<commit_before>var fs = require('fs')
var path = require('path')
var normalize = require('normalize-path')
var findParentDir = require('find-parent-dir')
var hooks = require('./hooks.json')
var pkg = require('../package.json')

function write (filename, data) {
  fs.writeFileSync(filename, data)
  fs.chmodSync(filename, parseInt('0755', 8))
}

function isHusky (filename) {
  var data = fs.readFileSync(filename, 'utf-8')
  return data.indexOf('#husky') !== -1
}

function isGhooks (filename) {
  var data = fs.readFileSync(filename, 'utf-8')
  return data.indexOf('// Generated by ghooks. Do not edit this file.') !== -1
}

function findHooksDir (dirname) {
  var dir = findParentDir.sync(dirname, '.git')

  if (dir) {
    var gitDir = path.join(dir, '.git')
    var stats = fs.lstatSync(gitDir)

    if (stats.isFile()) {
      // Expect following format
      // git: pathToGit
      gitDir = fs
        .readFileSync(gitDir, 'utf-8')
        .split(':')[1]
        .trim()

      return path.join(dir, gitDir, 'hooks')
    }

    return path.join(gitDir, 'hooks')
  }
}

function getHookScript (hookName, relativePath, cmd) {
    // On Windows normalize path (i.e. convert \ to /)
  var normalizedPath = normalize(relativePath)

  // Hook script
  var arr = [
    '#!/bin/sh',
    '#husky ' + pkg.version,
    '',
    'command_exists () {',
    '  command -v "$1" >/dev/null 2>&1',
    '}',
    '',

    'load_nvm () {',
    '  export $1=$2',
    '  [ -s "$1/nvm.sh" ] && . $1/nvm.sh',
    '  exists nvm && [ -f .nvmrc ] && nvm use',
    '}',
    '',

    // https://github.com/typicode/husky/issues/76
    'has_hook_script () {',
    '  [ -f package.json ] && cat package.json | grep -q "\\"$1\\"[[:space:]]*:"',
    '}',
    ''
  ]

  arr = arr.concat([
    'cd ' + normalizedPath,
    '',
    // Fix for issue #16 #24
    // If script is not defined in package.json then exit
    'has_hook_script ' + cmd + ' || exit 0',
    ''
  ])

  // On OS X and Linux, try to use nvm if it's installed
  if (process.platform !== 'win32') {
    // ~ is unavaible, so $HOME is used
    var home = process.env.HOME

    if (process.platform === 'darwin') {
      // Add
      // Brew standard installation path /use/local/bin
      // Node standard installation path /usr/local
      // for GUI apps
      // https://github.com/typicode/husky/issues/49
      arr = arr.concat([
        'export PATH=$PATH:/usr/local/bin:/usr/local'
      ])
    }

    if (process.platform === 'darwin') {
      arr = arr.concat([
        'command_exists npm || load_nvm BREW_NVM_DIR /usr/local/opt/nvm',
        ''
      ])
    }

    arr = arr.concat([
      'command_exists npm || load_nvm NVM_DIR ' + home + '/.nvm',
      ''
    ])
  } else {
    // Add
    // Node standard installation path /c/Program Files/nodejs
    // for GUI apps
    // https://github.com/typicode/husky/issues/49
    arr = arr.concat([
      'export PATH="$PATH:/c/Program Files/nodejs"'
    ])
  }

  // Can't find npm message
  var npmNotFound = '> husky - Can\'t find npm in PATH. Skipping ' + cmd + ' script in package.json'

  arr = arr.concat([
    // Test if npm is in PATH
    'command_exists npm || {',
    '  echo >&2 "' + npmNotFound + '"',
    '  exit 0',
    '}',
    '',

    // Run script
    'echo',
    'echo "> husky - npm run -s ' + cmd + '"',
    'echo',
    '',

    'export GIT_PARAMS="$*"',
    'npm run -s ' + cmd + ' || {',
    '  echo',
    '  echo "> husky - ' + hookName + ' hook failed (add --no-verify to bypass)"',
    '  echo "> husky - to debug, use \'npm run precommit\'"',
    '  exit 1',
    '}',
    ''
  ])

  return arr.join('\n')
}

function createHook (huskyDir, hooksDir, hookName, cmd) {
  var filename = path.join(hooksDir, hookName)

  // Assuming that this file is in node_modules/husky
  var packageDir = path.join(huskyDir, '..', '..')

  // Get project directory
  // When used in submodule, the project dir is the first .git that is found
  var projectDir = findParentDir.sync(huskyDir, '.git')

  // In order to support projects with package.json in a different directory
  // than .git, find relative path from project directory to package.json
  var relativePath = path.join('.', path.relative(projectDir, packageDir))

  var hookScript = getHookScript(hookName, relativePath, cmd)

  // Create hooks directory if needed
  if (!fs.existsSync(hooksDir)) fs.mkdirSync(hooksDir)

  if (!fs.existsSync(filename)) {
    return write(filename, hookScript)
  }

  if (isGhooks(filename)) {
    console.log('migrating ghooks ' + hookName + ' script')
    return write(filename, hookScript)
  }

  if (isHusky(filename)) {
    return write(filename, hookScript)
  }

  console.log('skipping ' + hookName + ' hook (existing user hook)')
}

function removeHook (dir, name) {
  var filename = dir + '/' + name

  if (fs.existsSync(filename) && isHusky(filename)) {
    fs.unlinkSync(dir + '/' + name)
  }
}

function installFrom (huskyDir) {
  try {
    var isInSubNodeModule = (huskyDir.match(/node_modules/g) || []).length > 1
    if (isInSubNodeModule) {
      return console.log(
        'Trying to install from sub \'node_module\' directory,',
        'skipping Git hooks installation'
      )
    }

    var hooksDir = findHooksDir(huskyDir)

    if (hooksDir) {
      hooks.forEach(function (hookName) {
        var npmScriptName = hookName.replace(/-/g, '')
        createHook(huskyDir, hooksDir, hookName, npmScriptName)
      })
      console.log('done\n')
    } else {
      console.log('Can\'t find .git directory, skipping Git hooks installation')
    }
  } catch (e) {
    console.error(e)
  }
}

function uninstallFrom (huskyDir) {
  try {
    var hooksDir = findHooksDir(huskyDir)

    hooks.forEach(function (hookName) {
      removeHook(hooksDir, hookName)
    })
    console.log('done\n')
  } catch (e) {
    console.error(e)
  }
}

module.exports = {
  installFrom: installFrom,
  uninstallFrom: uninstallFrom
}
<commit_msg>Fix checking for `nvm` (#101)<commit_after>var fs = require('fs')
var path = require('path')
var normalize = require('normalize-path')
var findParentDir = require('find-parent-dir')
var hooks = require('./hooks.json')
var pkg = require('../package.json')

function write (filename, data) {
  fs.writeFileSync(filename, data)
  fs.chmodSync(filename, parseInt('0755', 8))
}

function isHusky (filename) {
  var data = fs.readFileSync(filename, 'utf-8')
  return data.indexOf('#husky') !== -1
}

function isGhooks (filename) {
  var data = fs.readFileSync(filename, 'utf-8')
  return data.indexOf('// Generated by ghooks. Do not edit this file.') !== -1
}

function findHooksDir (dirname) {
  var dir = findParentDir.sync(dirname, '.git')

  if (dir) {
    var gitDir = path.join(dir, '.git')
    var stats = fs.lstatSync(gitDir)

    if (stats.isFile()) {
      // Expect following format
      // git: pathToGit
      gitDir = fs
        .readFileSync(gitDir, 'utf-8')
        .split(':')[1]
        .trim()

      return path.join(dir, gitDir, 'hooks')
    }

    return path.join(gitDir, 'hooks')
  }
}

function getHookScript (hookName, relativePath, cmd) {
    // On Windows normalize path (i.e. convert \ to /)
  var normalizedPath = normalize(relativePath)

  // Hook script
  var arr = [
    '#!/bin/sh',
    '#husky ' + pkg.version,
    '',
    'command_exists () {',
    '  command -v "$1" >/dev/null 2>&1',
    '}',
    '',

    'load_nvm () {',
    '  export $1=$2',
    '  [ -s "$2/nvm.sh" ] && . $2/nvm.sh',
    '  command_exists nvm && [ -f .nvmrc ] && nvm use',
    '}',
    '',

    // https://github.com/typicode/husky/issues/76
    'has_hook_script () {',
    '  [ -f package.json ] && cat package.json | grep -q "\\"$1\\"[[:space:]]*:"',
    '}',
    ''
  ]

  arr = arr.concat([
    'cd ' + normalizedPath,
    '',
    // Fix for issue #16 #24
    // If script is not defined in package.json then exit
    'has_hook_script ' + cmd + ' || exit 0',
    ''
  ])

  // On OS X and Linux, try to use nvm if it's installed
  if (process.platform !== 'win32') {
    // ~ is unavaible, so $HOME is used
    var home = process.env.HOME

    if (process.platform === 'darwin') {
      // Add
      // Brew standard installation path /use/local/bin
      // Node standard installation path /usr/local
      // for GUI apps
      // https://github.com/typicode/husky/issues/49
      arr = arr.concat([
        'export PATH=$PATH:/usr/local/bin:/usr/local'
      ])
    }

    if (process.platform === 'darwin') {
      arr = arr.concat([
        'command_exists npm || load_nvm BREW_NVM_DIR /usr/local/opt/nvm',
        ''
      ])
    }

    arr = arr.concat([
      'command_exists npm || load_nvm NVM_DIR ' + home + '/.nvm',
      ''
    ])
  } else {
    // Add
    // Node standard installation path /c/Program Files/nodejs
    // for GUI apps
    // https://github.com/typicode/husky/issues/49
    arr = arr.concat([
      'export PATH="$PATH:/c/Program Files/nodejs"'
    ])
  }

  // Can't find npm message
  var npmNotFound = '> husky - Can\'t find npm in PATH. Skipping ' + cmd + ' script in package.json'

  arr = arr.concat([
    // Test if npm is in PATH
    'command_exists npm || {',
    '  echo >&2 "' + npmNotFound + '"',
    '  exit 0',
    '}',
    '',

    // Run script
    'echo',
    'echo "> husky - npm run -s ' + cmd + '"',
    'echo',
    '',

    'export GIT_PARAMS="$*"',
    'npm run -s ' + cmd + ' || {',
    '  echo',
    '  echo "> husky - ' + hookName + ' hook failed (add --no-verify to bypass)"',
    '  echo "> husky - to debug, use \'npm run precommit\'"',
    '  exit 1',
    '}',
    ''
  ])

  return arr.join('\n')
}

function createHook (huskyDir, hooksDir, hookName, cmd) {
  var filename = path.join(hooksDir, hookName)

  // Assuming that this file is in node_modules/husky
  var packageDir = path.join(huskyDir, '..', '..')

  // Get project directory
  // When used in submodule, the project dir is the first .git that is found
  var projectDir = findParentDir.sync(huskyDir, '.git')

  // In order to support projects with package.json in a different directory
  // than .git, find relative path from project directory to package.json
  var relativePath = path.join('.', path.relative(projectDir, packageDir))

  var hookScript = getHookScript(hookName, relativePath, cmd)

  // Create hooks directory if needed
  if (!fs.existsSync(hooksDir)) fs.mkdirSync(hooksDir)

  if (!fs.existsSync(filename)) {
    return write(filename, hookScript)
  }

  if (isGhooks(filename)) {
    console.log('migrating ghooks ' + hookName + ' script')
    return write(filename, hookScript)
  }

  if (isHusky(filename)) {
    return write(filename, hookScript)
  }

  console.log('skipping ' + hookName + ' hook (existing user hook)')
}

function removeHook (dir, name) {
  var filename = dir + '/' + name

  if (fs.existsSync(filename) && isHusky(filename)) {
    fs.unlinkSync(dir + '/' + name)
  }
}

function installFrom (huskyDir) {
  try {
    var isInSubNodeModule = (huskyDir.match(/node_modules/g) || []).length > 1
    if (isInSubNodeModule) {
      return console.log(
        'Trying to install from sub \'node_module\' directory,',
        'skipping Git hooks installation'
      )
    }

    var hooksDir = findHooksDir(huskyDir)

    if (hooksDir) {
      hooks.forEach(function (hookName) {
        var npmScriptName = hookName.replace(/-/g, '')
        createHook(huskyDir, hooksDir, hookName, npmScriptName)
      })
      console.log('done\n')
    } else {
      console.log('Can\'t find .git directory, skipping Git hooks installation')
    }
  } catch (e) {
    console.error(e)
  }
}

function uninstallFrom (huskyDir) {
  try {
    var hooksDir = findHooksDir(huskyDir)

    hooks.forEach(function (hookName) {
      removeHook(hooksDir, hookName)
    })
    console.log('done\n')
  } catch (e) {
    console.error(e)
  }
}

module.exports = {
  installFrom: installFrom,
  uninstallFrom: uninstallFrom
}
<|endoftext|>


<commit_before>const initApi = require('./api/index.js');
const initDom = require('./dom/index.js');

/**
 * @constructor
 */
function AcLib () {
  // 无法直接获取信息。选择不封装
  // Object.assign(this, {
  //   /**
  //    * aclib版本号
  //    * @member {string}
  //    * @example 2.0.0
  //    */
  //   get acVersion() {
  //     return '2.0.0'
  //   },
  //   /**
  //    * 应用ID
  //    * @type {string}
  //    * @example A6980386445546
  //    */
  //   get appId() {
  //     return api.appId
  //   },
  //   /**
  //    * 应用在桌面显示名称
  //    * @type {string}
  //    * @example AppLoader
  //    */
  //   get appName() {
  //     return api.appName
  //   },
  //   /**
  //    * 应用版本号
  //    * @type {string}
  //    * @example 1.0.0
  //    */
  //   get appVersion() {
  //     return api.appVersion
  //   },
  //   /**
  //    * 系统类型，可以返回ios|android|win|wp
  //    * @type {string}
  //    * @example ios
  //    */
  //   get systemType() {
  //     return api.systemType
  //   },
  //   /**
  //    * 手机平台的系统版本
  //    * @type {string}
  //    * @example 8.0
  //    */
  //   get systemVersion() {
  //     return api.systemVersion
  //   },
  //   /**
  //    * 引擎版本信息
  //    * @type {string}
  //    * @example 1.0.0
  //    */
  //   get version() {
  //     return api.version
  //   },
  //   /**
  //    * 设备唯一标识
  //    * @type {string}
  //    * @example FC408F8B-9598-48B6-A740-B9037ADCXXXE
  //    */
  //   get deviceId() {
  //     return api.deviceId
  //   },
  //   /**
  //    * iOS中用于推送的Token，若未从系统获取到则返回空字符串
  //    * @type {string}
  //    * @example a22241adab6c68b3687a9f0f086c540341f4b3f010546d4af4834ada32281615
  //    */
  //   get deviceToken() {
  //     return api.deviceToken
  //   },
  //   /**
  //    * 设备型号
  //    * @type {string}
  //    * @example iPhone 5
  //    */
  //   get deviceModel() {
  //     return api.deviceModel
  //   },
  //   /**
  //    * 设备名称
  //    * @type {string}
  //    * @example “柚子”的 iPhone
  //    */
  //   get deviceName() {
  //     return api.deviceName
  //   },
  //   /**
  //    * 设备类型，可以返回pad|phone|tv|car|desk|watch
  //    * @type {string}
  //    * @example phone
  //    */
  //   get uiMode() {
  //     return api.uiMode
  //   },
  //   /**
  //    * 运营商名称，若未获取到则返回none
  //    * @type {string}
  //    * @example 中国移动
  //    */
  //   get operator() {
  //     return api.operator
  //   },
  //   /**
  //    * 当前网络连接类型，如 2g、3g、4g、wifi 等
  //    * @type {string}
  //    * @example wifi
  //    */
  //   get connectionType() {
  //     return api.connectionType
  //   },
  //   /**
  //    * 应用是否全屏,只支持iOS
  //    * @type {boolean}
  //    * @example true
  //    */
  //   get fullScreen() {
  //     return api.fullScreen
  //   },
  //   /**
  //    * 屏幕分辨率宽
  //    * @type {number}
  //    * @example 640
  //    */
  //   get screenWidth() {
  //     return api.screenWidth
  //   },
  //   /**
  //    * 屏幕分辨率高
  //    * @type {number}
  //    * @example 960
  //    */
  //   get screenHeight() {
  //     return api.screenHeight
  //   },
  //   /**
  //    * 当前 window 名称
  //    * 该属性值为 openWin() 时传递的 name 参数值，注意首页的名称为 root
  //    * @type {string}
  //    * @example root
  //    */
  //   get winName() {
  //     return api.winName
  //   },
  //   /**
  //    * 当前 window 宽度
  //    * 此属性值不同于屏幕的分辨率，比如 iPhone 5 的分辨率为 640*1136，但是其 winWidth 为 320，因此前端需根据 winWidth 和 winHeight 来进行布局
  //    * @type {number}
  //    * @example 320
  //    */
  //   get winWidth() {
  //     return api.winWidth
  //   },
  //   /**
  //    * 当前 window 高度
  //    * 此属性值不同于屏幕的分辨率，比如 iPhone 5 的分辨率为 640*1136，但是其 winHeight 为 568（若不使用iOS7风格则为 548），因此前端需根据 winWidth 和 winHeight 来进行布局
  //    * @type {number}
  //    * @example 568
  //    */
  //   get winHeight() {
  //     return api.winHeight
  //   },
  //   /**
  //    * frame 名称
  //    * 若当前环境为 window 中，则该属性值为空字符串
  //    * @type {string}
  //    * @example trans-con
  //    */
  //   get frameName() {
  //     return api.frameName
  //   },
  //   /**
  //    * frame 宽度
  //    * @type {number}
  //    * @example 若当前环境为 window 中，则值和 winWidth 相同
  //    */
  //   get frameWidth() {
  //     return api.frameWidth
  //   },
  //   /**
  //    * frame 高度
  //    * 若当前环境为 window 中，则值和 winHeight 相同
  //    * @type {number}
  //    * @example 1.0.0
  //    */
  //   get frameHeight() {
  //     return api.frameHeight
  //   },
  //   /**
  //    * 页面不被其它内容（如状态栏）遮住的区域

  //    * 通过safeArea能够知道当前页面哪些地方被遮住，从而做出相应的调整，保证页面重要元素不被遮挡住。

  //    * 比如应对顶部header被状态栏遮住一部分，可以为header增加一个paddingTop，如：

  //    * header.style.paddingTop = api.safeArea.top + 'px';

  //    * 在比如在iPhone X上面，底部的导航菜单会被虚拟Home键遮住一部分，可以为footer增加一个paddingBottom，如：

  //    * footer.style.paddingBottom = api.safeArea.bottom + 'px';
  //    * @type {object}
  //    * @example {top:20, left:0, bottom:0, right:0}
  //    */
  //   get safeArea() {
  //     return api.safeArea
  //   },
  //   /**
  //    * 页面参数

  //    * 用于获取页面间传递的参数值，为 openWin()、openFrame() 等方法中的 pageParam 参数对应值
  //    * @type {object}
  //    * @example {"name" : "tans-con"}
  //    */
  //   get pageParam() {
  //     return api.pageParam
  //   },
  //   /**
  //    * widget 参数

  //    * 用于获取 widget 间传递的参数值，为 openWidget() 方法中的 wgtParam 参数对应值
  //    * @type {object}
  //    * @example {"name": "API Demo"}
  //    */
  //   get wgtParam() {
  //     return api.wgtParam
  //   },
  //   /**
  //    * 当应用被第三方应用打开时，传递过来的参数，字符串类型

  //    * 建议通过appintent事件监听应用被第三方应用调起，并在事件回调里面获取参数进行处理。
  //    * @type {object}
  //    * @example {"name": "API Demo"}
  //    */
  //   get appParam() {
  //     return api.appParam
  //   },
  //   /**
  //    * 当前应用状态栏是否支持沉浸式效果
  //    * @type {boolean}
  //    * @example true
  //    */
  //   get statusBarAppearance() {
  //     return api.statusBarAppearance
  //   },
  //   /**
  //    * widget: //协议对应的真实目录，即 widget 网页包的根目录

  //    * 注意该目录为只读，不要往该目录下面写文件
  //    * @type {string}
  //    * @example /private/var/mobile/Containers/Bundle/Application/56218B5B-1B59-48CD-8080-DAC54DB46446/UZApp.app/widget
  //    */
  //   get wgtRootDir() {
  //     return api.wgtRootDir
  //   },
  //   /**
  //    * fs: //协议对应地真实目录
  //    * @type {string}
  //    * @example /var/mobile/Containers/Data/Application/4E376FDE-D595-4E08-B0A4-A06561B31000/Documents/uzfs/A123456789
  //    */
  //   get fsDir() {
  //     return api.fsDir
  //   },
  //   /**
  //    * cache://协议对应的真实目录

  //    * iOS 平台下载的文件一般存放于该目录下，否则提交 AppStore 审核时可能会不通过，且此目录下的内容在手机备份时不会被备份
  //    * @type {string}
  //    * @example /var/mobile/Containers/Data/Application/4E376FDE-D595-4E08-B0A4-A06561B31000/Library/Caches/APICloud/Cache/XXXXXX
  //    */
  //   get cacheDir() {
  //     return api.cacheDir
  //   },
  //   /**
  //    * box://协议对应的真实目录

  //    * iOS上面在应用Documents下，安卓上面在系统为app分配的沙箱下，root或者越狱的手机可看到。
  //    * @type {string}
  //    * @example /var/mobile/Containers/Data/Application/4E376FDE-D595-4E08-B0A4-A06561B31000/Documents/uzfs/box
  //    */
  //   get boxDir() {
  //     return api.boxDir
  //   },
  //   /**
  //    * 获取config.xml配置的debug字段的值。
  //    * @type {string}
  //    * @example /var/mobile/Containers/Data/Application/4E376FDE-D595-4E08-B0A4-A06561B31000/Documents/uzfs/box
  //    */
  //   get debug() {
  //     return api.debug
  //   },
  //   /**
  //    * 渠道号
  //    * @type {string}
  //    * @example Apple App Store
  //    */
  //   get channel() {
  //     return api.channel
  //   },
  //   /**
  //    * 设备是否越狱
  //    * @type {boolean}
  //    * @example false
  //    */
  //   get jailbreak() {
  //     return api.jailbreak
  //   },
  // })
}

/**
 * api对象准备完毕
 * @example ac.ready(function() {...});
 */
AcLib.prototype.ready = (func) => {
  apiready = () => {
    func();
  }
}

initApi.call(AcLib);
initDom.call(AcLib);

module.exports = AcLib;
window.ac = new AcLib();
<commit_msg>修复apiready的bug<commit_after>const initApi = require('./api/index.js');
const initDom = require('./dom/index.js');

/**
 * @constructor
 */
function AcLib () {
  // 无法直接获取信息。选择不封装
  // Object.assign(this, {
  //   /**
  //    * aclib版本号
  //    * @member {string}
  //    * @example 2.0.0
  //    */
  //   get acVersion() {
  //     return '2.0.0'
  //   },
  //   /**
  //    * 应用ID
  //    * @type {string}
  //    * @example A6980386445546
  //    */
  //   get appId() {
  //     return api.appId
  //   },
  //   /**
  //    * 应用在桌面显示名称
  //    * @type {string}
  //    * @example AppLoader
  //    */
  //   get appName() {
  //     return api.appName
  //   },
  //   /**
  //    * 应用版本号
  //    * @type {string}
  //    * @example 1.0.0
  //    */
  //   get appVersion() {
  //     return api.appVersion
  //   },
  //   /**
  //    * 系统类型，可以返回ios|android|win|wp
  //    * @type {string}
  //    * @example ios
  //    */
  //   get systemType() {
  //     return api.systemType
  //   },
  //   /**
  //    * 手机平台的系统版本
  //    * @type {string}
  //    * @example 8.0
  //    */
  //   get systemVersion() {
  //     return api.systemVersion
  //   },
  //   /**
  //    * 引擎版本信息
  //    * @type {string}
  //    * @example 1.0.0
  //    */
  //   get version() {
  //     return api.version
  //   },
  //   /**
  //    * 设备唯一标识
  //    * @type {string}
  //    * @example FC408F8B-9598-48B6-A740-B9037ADCXXXE
  //    */
  //   get deviceId() {
  //     return api.deviceId
  //   },
  //   /**
  //    * iOS中用于推送的Token，若未从系统获取到则返回空字符串
  //    * @type {string}
  //    * @example a22241adab6c68b3687a9f0f086c540341f4b3f010546d4af4834ada32281615
  //    */
  //   get deviceToken() {
  //     return api.deviceToken
  //   },
  //   /**
  //    * 设备型号
  //    * @type {string}
  //    * @example iPhone 5
  //    */
  //   get deviceModel() {
  //     return api.deviceModel
  //   },
  //   /**
  //    * 设备名称
  //    * @type {string}
  //    * @example “柚子”的 iPhone
  //    */
  //   get deviceName() {
  //     return api.deviceName
  //   },
  //   /**
  //    * 设备类型，可以返回pad|phone|tv|car|desk|watch
  //    * @type {string}
  //    * @example phone
  //    */
  //   get uiMode() {
  //     return api.uiMode
  //   },
  //   /**
  //    * 运营商名称，若未获取到则返回none
  //    * @type {string}
  //    * @example 中国移动
  //    */
  //   get operator() {
  //     return api.operator
  //   },
  //   /**
  //    * 当前网络连接类型，如 2g、3g、4g、wifi 等
  //    * @type {string}
  //    * @example wifi
  //    */
  //   get connectionType() {
  //     return api.connectionType
  //   },
  //   /**
  //    * 应用是否全屏,只支持iOS
  //    * @type {boolean}
  //    * @example true
  //    */
  //   get fullScreen() {
  //     return api.fullScreen
  //   },
  //   /**
  //    * 屏幕分辨率宽
  //    * @type {number}
  //    * @example 640
  //    */
  //   get screenWidth() {
  //     return api.screenWidth
  //   },
  //   /**
  //    * 屏幕分辨率高
  //    * @type {number}
  //    * @example 960
  //    */
  //   get screenHeight() {
  //     return api.screenHeight
  //   },
  //   /**
  //    * 当前 window 名称
  //    * 该属性值为 openWin() 时传递的 name 参数值，注意首页的名称为 root
  //    * @type {string}
  //    * @example root
  //    */
  //   get winName() {
  //     return api.winName
  //   },
  //   /**
  //    * 当前 window 宽度
  //    * 此属性值不同于屏幕的分辨率，比如 iPhone 5 的分辨率为 640*1136，但是其 winWidth 为 320，因此前端需根据 winWidth 和 winHeight 来进行布局
  //    * @type {number}
  //    * @example 320
  //    */
  //   get winWidth() {
  //     return api.winWidth
  //   },
  //   /**
  //    * 当前 window 高度
  //    * 此属性值不同于屏幕的分辨率，比如 iPhone 5 的分辨率为 640*1136，但是其 winHeight 为 568（若不使用iOS7风格则为 548），因此前端需根据 winWidth 和 winHeight 来进行布局
  //    * @type {number}
  //    * @example 568
  //    */
  //   get winHeight() {
  //     return api.winHeight
  //   },
  //   /**
  //    * frame 名称
  //    * 若当前环境为 window 中，则该属性值为空字符串
  //    * @type {string}
  //    * @example trans-con
  //    */
  //   get frameName() {
  //     return api.frameName
  //   },
  //   /**
  //    * frame 宽度
  //    * @type {number}
  //    * @example 若当前环境为 window 中，则值和 winWidth 相同
  //    */
  //   get frameWidth() {
  //     return api.frameWidth
  //   },
  //   /**
  //    * frame 高度
  //    * 若当前环境为 window 中，则值和 winHeight 相同
  //    * @type {number}
  //    * @example 1.0.0
  //    */
  //   get frameHeight() {
  //     return api.frameHeight
  //   },
  //   /**
  //    * 页面不被其它内容（如状态栏）遮住的区域

  //    * 通过safeArea能够知道当前页面哪些地方被遮住，从而做出相应的调整，保证页面重要元素不被遮挡住。

  //    * 比如应对顶部header被状态栏遮住一部分，可以为header增加一个paddingTop，如：

  //    * header.style.paddingTop = api.safeArea.top + 'px';

  //    * 在比如在iPhone X上面，底部的导航菜单会被虚拟Home键遮住一部分，可以为footer增加一个paddingBottom，如：

  //    * footer.style.paddingBottom = api.safeArea.bottom + 'px';
  //    * @type {object}
  //    * @example {top:20, left:0, bottom:0, right:0}
  //    */
  //   get safeArea() {
  //     return api.safeArea
  //   },
  //   /**
  //    * 页面参数

  //    * 用于获取页面间传递的参数值，为 openWin()、openFrame() 等方法中的 pageParam 参数对应值
  //    * @type {object}
  //    * @example {"name" : "tans-con"}
  //    */
  //   get pageParam() {
  //     return api.pageParam
  //   },
  //   /**
  //    * widget 参数

  //    * 用于获取 widget 间传递的参数值，为 openWidget() 方法中的 wgtParam 参数对应值
  //    * @type {object}
  //    * @example {"name": "API Demo"}
  //    */
  //   get wgtParam() {
  //     return api.wgtParam
  //   },
  //   /**
  //    * 当应用被第三方应用打开时，传递过来的参数，字符串类型

  //    * 建议通过appintent事件监听应用被第三方应用调起，并在事件回调里面获取参数进行处理。
  //    * @type {object}
  //    * @example {"name": "API Demo"}
  //    */
  //   get appParam() {
  //     return api.appParam
  //   },
  //   /**
  //    * 当前应用状态栏是否支持沉浸式效果
  //    * @type {boolean}
  //    * @example true
  //    */
  //   get statusBarAppearance() {
  //     return api.statusBarAppearance
  //   },
  //   /**
  //    * widget: //协议对应的真实目录，即 widget 网页包的根目录

  //    * 注意该目录为只读，不要往该目录下面写文件
  //    * @type {string}
  //    * @example /private/var/mobile/Containers/Bundle/Application/56218B5B-1B59-48CD-8080-DAC54DB46446/UZApp.app/widget
  //    */
  //   get wgtRootDir() {
  //     return api.wgtRootDir
  //   },
  //   /**
  //    * fs: //协议对应地真实目录
  //    * @type {string}
  //    * @example /var/mobile/Containers/Data/Application/4E376FDE-D595-4E08-B0A4-A06561B31000/Documents/uzfs/A123456789
  //    */
  //   get fsDir() {
  //     return api.fsDir
  //   },
  //   /**
  //    * cache://协议对应的真实目录

  //    * iOS 平台下载的文件一般存放于该目录下，否则提交 AppStore 审核时可能会不通过，且此目录下的内容在手机备份时不会被备份
  //    * @type {string}
  //    * @example /var/mobile/Containers/Data/Application/4E376FDE-D595-4E08-B0A4-A06561B31000/Library/Caches/APICloud/Cache/XXXXXX
  //    */
  //   get cacheDir() {
  //     return api.cacheDir
  //   },
  //   /**
  //    * box://协议对应的真实目录

  //    * iOS上面在应用Documents下，安卓上面在系统为app分配的沙箱下，root或者越狱的手机可看到。
  //    * @type {string}
  //    * @example /var/mobile/Containers/Data/Application/4E376FDE-D595-4E08-B0A4-A06561B31000/Documents/uzfs/box
  //    */
  //   get boxDir() {
  //     return api.boxDir
  //   },
  //   /**
  //    * 获取config.xml配置的debug字段的值。
  //    * @type {string}
  //    * @example /var/mobile/Containers/Data/Application/4E376FDE-D595-4E08-B0A4-A06561B31000/Documents/uzfs/box
  //    */
  //   get debug() {
  //     return api.debug
  //   },
  //   /**
  //    * 渠道号
  //    * @type {string}
  //    * @example Apple App Store
  //    */
  //   get channel() {
  //     return api.channel
  //   },
  //   /**
  //    * 设备是否越狱
  //    * @type {boolean}
  //    * @example false
  //    */
  //   get jailbreak() {
  //     return api.jailbreak
  //   },
  // })
}

/**
 * api对象准备完毕
 * @example ac.ready(function() {...});
 */
AcLib.prototype.ready = (func) => {
  window.apiready = () => {
    func();
  }
}

initApi.call(AcLib);
initDom.call(AcLib);

module.exports = AcLib;
window.ac = new AcLib();
<|endoftext|>


<commit_before>'use strict';

import core from './core';
import array from './array/array';
import async from './async/async';
import Disposable from './disposable/Disposable';
import object from './object/object';
import string from './string/string';

export { core };
export { array };
export { async };
export { Disposable };
export { object };
export { string };
<commit_msg>Exports core as the default module<commit_after>'use strict';

import core from './core';
import array from './array/array';
import async from './async/async';
import Disposable from './disposable/Disposable';
import object from './object/object';
import string from './string/string';

export default core;
export { core, array, async, Disposable, object, string };
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
  Dimensions,
  Modal,
  DeviceEventEmitter,
  TouchableWithoutFeedback,
  KeyboardAvoidingView,
} from 'react-native';
import PropTypes from 'prop-types';
import {
  View,
  initializeRegistryWithDefinitions,
  registerAnimation,
  createAnimation,
} from 'react-native-animatable';
import * as ANIMATION_DEFINITIONS from './animations';

import styles from './index.style.js';

// Override default animations
initializeRegistryWithDefinitions(ANIMATION_DEFINITIONS);

// Utility for creating custom animations
const makeAnimation = (name, obj) => {
  registerAnimation(name, createAnimation(obj));
};

const isObject = obj => {
  return obj !== null && typeof obj === 'object';
};

export class ReactNativeModal extends Component {
  static propTypes = {
    animationIn: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationInTiming: PropTypes.number,
    animationOut: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationOutTiming: PropTypes.number,
    avoidKeyboard: PropTypes.bool,
    backdropColor: PropTypes.string,
    backdropOpacity: PropTypes.number,
    backdropTransitionInTiming: PropTypes.number,
    backdropTransitionOutTiming: PropTypes.number,
    children: PropTypes.node.isRequired,
    isVisible: PropTypes.bool.isRequired,
    onModalShow: PropTypes.func,
    onModalHide: PropTypes.func,
    onBackButtonPress: PropTypes.func,
    onBackdropPress: PropTypes.func,
    useNativeDriver: PropTypes.bool,
    style: PropTypes.any,
  };

  static defaultProps = {
    animationIn: 'slideInUp',
    animationInTiming: 300,
    animationOut: 'slideOutDown',
    animationOutTiming: 300,
    avoidKeyboard: false,
    backdropColor: 'black',
    backdropOpacity: 0.7,
    backdropTransitionInTiming: 300,
    backdropTransitionOutTiming: 300,
    onModalShow: () => null,
    onModalHide: () => null,
    isVisible: false,
    onBackdropPress: () => null,
    onBackButtonPress: () => null,
    useNativeDriver: false,
  };

  // We use an internal state for keeping track of the modal visibility: this allows us to keep
  // the modal visibile during the exit animation, even if the user has already change the
  // isVisible prop to false.
  // We also store in the state the device width and height so that we can update the modal on
  // device rotation.
  state = {
    isVisible: false,
    deviceWidth: Dimensions.get('window').width,
    deviceHeight: Dimensions.get('window').height,
  };

  transitionLock = null;

  constructor(props) {
    super(props);
    this._buildAnimations(props);
  }

  componentWillReceiveProps(nextProps) {
    if (!this.state.isVisible && nextProps.isVisible) {
      this.setState({ isVisible: true });
    }
    if (
      this.props.animationIn !== nextProps.animationIn ||
      this.props.animationOut !== nextProps.animationOut
    ) {
      this._buildAnimations(nextProps);
    }
  }

  componentWillMount() {
    if (this.props.isVisible) {
      this.setState({ isVisible: true });
    }
  }

  componentDidMount() {
    if (this.state.isVisible) {
      this._open();
    }
    DeviceEventEmitter.addListener('didUpdateDimensions', this._handleDimensionsUpdate);
  }

  componentWillUnmount() {
    DeviceEventEmitter.removeListener('didUpdateDimensions', this._handleDimensionsUpdate);
  }

  componentDidUpdate(prevProps, prevState) {
    // On modal open request, we slide the view up and fade in the backdrop
    if (this.props.isVisible && !prevProps.isVisible) {
      this._open();
    }
    // On modal close request, we slide the view down and fade out the backdrop
    else if (!this.props.isVisible && prevProps.isVisible) {
      this._close();
    }
  }

  // User can define custom react-native-animatable animations, see PR #72
  _buildAnimations = props => {
    let animationIn = props.animationIn;
    let animationOut = props.animationOut;

    if (isObject(animationIn)) {
      makeAnimation('animationIn', animationIn);
      animationIn = 'animationIn';
    }

    if (isObject(animationOut)) {
      makeAnimation('animationOut', animationOut);
      animationOut = 'animationOut';
    }

    this.animationIn = animationIn;
    this.animationOut = animationOut;
  };

  _handleDimensionsUpdate = dimensionsUpdate => {
    // Here we update the device dimensions in the state if the layout changed (triggering a render)
    const deviceWidth = Dimensions.get('window').width;
    const deviceHeight = Dimensions.get('window').height;
    if (deviceWidth !== this.state.deviceWidth || deviceHeight !== this.state.deviceHeight) {
      this.setState({ deviceWidth, deviceHeight });
    }
  };

  _open = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    this.backdropRef.transitionTo(
      { opacity: this.props.backdropOpacity },
      this.props.backdropTransitionInTiming,
    );
    this.contentRef[this.animationIn](this.props.animationInTiming).then(() => {
      this.transitionLock = false;
      if (!this.props.isVisible) {
        this._close();
      }
      else {
        this.props.onModalShow();
      }
    });
  };

  _close = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    this.backdropRef.transitionTo({ opacity: 0 }, this.props.backdropTransitionOutTiming);
    this.contentRef[this.animationOut](this.props.animationOutTiming).then(() => {
      this.transitionLock = false;
      if (this.props.isVisible) {
        this._open();
      }
      else {
        this.setState({ isVisible: false });
        this.props.onModalHide();
      }
    });
  };

  render() {
    const {
      animationIn,
      animationInTiming,
      animationOut,
      animationOutTiming,
      avoidKeyboard,
      backdropColor,
      backdropOpacity,
      backdropTransitionInTiming,
      backdropTransitionOutTiming,
      children,
      isVisible,
      onModalShow,
      onBackdropPress,
      onBackButtonPress,
      useNativeDriver,
      style,
      ...otherProps
    } = this.props;
    const { deviceWidth, deviceHeight } = this.state;

    const computedStyle = [
      { margin: deviceWidth * 0.05, transform: [{ translateY: 0 }] },
      styles.content,
      style,
    ];

    const containerView = (
      <View
        ref={ref => (this.contentRef = ref)}
        style={computedStyle}
        pointerEvents={'box-none'}
        useNativeDriver={useNativeDriver}
        {...otherProps}
      >
        {children}
      </View>
    );

    return (
      <Modal
        transparent={true}
        animationType={'none'}
        visible={this.state.isVisible}
        onRequestClose={onBackButtonPress}
        {...otherProps}
      >
        <TouchableWithoutFeedback onPress={onBackdropPress}>
          <View
            ref={ref => (this.backdropRef = ref)}
            useNativeDriver={useNativeDriver}
            style={[
              styles.backdrop,
              {
                backgroundColor: backdropColor,
                width: deviceWidth,
                height: deviceHeight,
              },
            ]}
          />
        </TouchableWithoutFeedback>

        {avoidKeyboard && (
          <KeyboardAvoidingView
            behavior={'padding'}
            pointerEvents={'box-none'}
            style={computedStyle.concat([{ margin: 0 }])}
          >
            {containerView}
          </KeyboardAvoidingView>
        )}

        {!avoidKeyboard && containerView}
      </Modal>
    );
  }
}

export default ReactNativeModal;
<commit_msg>Allow Backdrop Opacity Updates<commit_after>import React, { Component } from 'react';
import {
  Dimensions,
  Modal,
  DeviceEventEmitter,
  TouchableWithoutFeedback,
  KeyboardAvoidingView,
} from 'react-native';
import PropTypes from 'prop-types';
import {
  View,
  initializeRegistryWithDefinitions,
  registerAnimation,
  createAnimation,
} from 'react-native-animatable';
import * as ANIMATION_DEFINITIONS from './animations';

import styles from './index.style.js';

// Override default animations
initializeRegistryWithDefinitions(ANIMATION_DEFINITIONS);

// Utility for creating custom animations
const makeAnimation = (name, obj) => {
  registerAnimation(name, createAnimation(obj));
};

const isObject = obj => {
  return obj !== null && typeof obj === 'object';
};

export class ReactNativeModal extends Component {
  static propTypes = {
    animationIn: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationInTiming: PropTypes.number,
    animationOut: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationOutTiming: PropTypes.number,
    avoidKeyboard: PropTypes.bool,
    backdropColor: PropTypes.string,
    backdropOpacity: PropTypes.number,
    backdropTransitionInTiming: PropTypes.number,
    backdropTransitionOutTiming: PropTypes.number,
    children: PropTypes.node.isRequired,
    isVisible: PropTypes.bool.isRequired,
    onModalShow: PropTypes.func,
    onModalHide: PropTypes.func,
    onBackButtonPress: PropTypes.func,
    onBackdropPress: PropTypes.func,
    useNativeDriver: PropTypes.bool,
    style: PropTypes.any,
  };

  static defaultProps = {
    animationIn: 'slideInUp',
    animationInTiming: 300,
    animationOut: 'slideOutDown',
    animationOutTiming: 300,
    avoidKeyboard: false,
    backdropColor: 'black',
    backdropOpacity: 0.7,
    backdropTransitionInTiming: 300,
    backdropTransitionOutTiming: 300,
    onModalShow: () => null,
    onModalHide: () => null,
    isVisible: false,
    onBackdropPress: () => null,
    onBackButtonPress: () => null,
    useNativeDriver: false,
  };

  // We use an internal state for keeping track of the modal visibility: this allows us to keep
  // the modal visibile during the exit animation, even if the user has already change the
  // isVisible prop to false.
  // We also store in the state the device width and height so that we can update the modal on
  // device rotation.
  state = {
    isVisible: false,
    deviceWidth: Dimensions.get('window').width,
    deviceHeight: Dimensions.get('window').height,
  };

  transitionLock = null;

  constructor(props) {
    super(props);
    this._buildAnimations(props);
  }

  componentWillReceiveProps(nextProps) {
    if (!this.state.isVisible && nextProps.isVisible) {
      this.setState({ isVisible: true });
    }
    if (
      this.props.animationIn !== nextProps.animationIn ||
      this.props.animationOut !== nextProps.animationOut
    ) {
      this._buildAnimations(nextProps);
    }
    if (this.props.backdropOpacity !== nextProps.backdropOpacity && this.backdropRef) {
      this.backdropRef.transitionTo(
        { opacity: nextProps.backdropOpacity },
        this.props.backdropTransitionInTiming
      );
    }
  }

  componentWillMount() {
    if (this.props.isVisible) {
      this.setState({ isVisible: true });
    }
  }

  componentDidMount() {
    if (this.state.isVisible) {
      this._open();
    }
    DeviceEventEmitter.addListener('didUpdateDimensions', this._handleDimensionsUpdate);
  }

  componentWillUnmount() {
    DeviceEventEmitter.removeListener('didUpdateDimensions', this._handleDimensionsUpdate);
  }

  componentDidUpdate(prevProps, prevState) {
    // On modal open request, we slide the view up and fade in the backdrop
    if (this.props.isVisible && !prevProps.isVisible) {
      this._open();
    }
    // On modal close request, we slide the view down and fade out the backdrop
    else if (!this.props.isVisible && prevProps.isVisible) {
      this._close();
    }
  }

  // User can define custom react-native-animatable animations, see PR #72
  _buildAnimations = props => {
    let animationIn = props.animationIn;
    let animationOut = props.animationOut;

    if (isObject(animationIn)) {
      makeAnimation('animationIn', animationIn);
      animationIn = 'animationIn';
    }

    if (isObject(animationOut)) {
      makeAnimation('animationOut', animationOut);
      animationOut = 'animationOut';
    }

    this.animationIn = animationIn;
    this.animationOut = animationOut;
  };

  _handleDimensionsUpdate = dimensionsUpdate => {
    // Here we update the device dimensions in the state if the layout changed (triggering a render)
    const deviceWidth = Dimensions.get('window').width;
    const deviceHeight = Dimensions.get('window').height;
    if (deviceWidth !== this.state.deviceWidth || deviceHeight !== this.state.deviceHeight) {
      this.setState({ deviceWidth, deviceHeight });
    }
  };

  _open = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    this.backdropRef.transitionTo(
      { opacity: this.props.backdropOpacity },
      this.props.backdropTransitionInTiming,
    );
    this.contentRef[this.animationIn](this.props.animationInTiming).then(() => {
      this.transitionLock = false;
      if (!this.props.isVisible) {
        this._close();
      }
      else {
        this.props.onModalShow();
      }
    });
  };

  _close = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    this.backdropRef.transitionTo({ opacity: 0 }, this.props.backdropTransitionOutTiming);
    this.contentRef[this.animationOut](this.props.animationOutTiming).then(() => {
      this.transitionLock = false;
      if (this.props.isVisible) {
        this._open();
      }
      else {
        this.setState({ isVisible: false });
        this.props.onModalHide();
      }
    });
  };

  render() {
    const {
      animationIn,
      animationInTiming,
      animationOut,
      animationOutTiming,
      avoidKeyboard,
      backdropColor,
      backdropOpacity,
      backdropTransitionInTiming,
      backdropTransitionOutTiming,
      children,
      isVisible,
      onModalShow,
      onBackdropPress,
      onBackButtonPress,
      useNativeDriver,
      style,
      ...otherProps
    } = this.props;
    const { deviceWidth, deviceHeight } = this.state;

    const computedStyle = [
      { margin: deviceWidth * 0.05, transform: [{ translateY: 0 }] },
      styles.content,
      style,
    ];

    const containerView = (
      <View
        ref={ref => (this.contentRef = ref)}
        style={computedStyle}
        pointerEvents={'box-none'}
        useNativeDriver={useNativeDriver}
        {...otherProps}
      >
        {children}
      </View>
    );

    return (
      <Modal
        transparent={true}
        animationType={'none'}
        visible={this.state.isVisible}
        onRequestClose={onBackButtonPress}
        {...otherProps}
      >
        <TouchableWithoutFeedback onPress={onBackdropPress}>
          <View
            ref={ref => (this.backdropRef = ref)}
            useNativeDriver={useNativeDriver}
            style={[
              styles.backdrop,
              {
                backgroundColor: backdropColor,
                width: deviceWidth,
                height: deviceHeight,
              },
            ]}
          />
        </TouchableWithoutFeedback>

        {avoidKeyboard && (
          <KeyboardAvoidingView
            behavior={'padding'}
            pointerEvents={'box-none'}
            style={computedStyle.concat([{ margin: 0 }])}
          >
            {containerView}
          </KeyboardAvoidingView>
        )}

        {!avoidKeyboard && containerView}
      </Modal>
    );
  }
}

export default ReactNativeModal;
<|endoftext|>


<commit_before>'use strict';

var events = require("events");
var util = require("util");
var $ = require("jquery");
var Queue = require("./queue");
var _ = require("underscore");
var attributes = require("attributes");
var Errors = require("./errors");

module.exports = Uploader;

var adapters = {
    flash : require("./adapter/flash"),
    ajax : require("./adapter/ajax")
};

function Uploader(element,config){
    var theme = config.theme || require("./theme/default");
    var self = this;

    this.type = config.type || this._getType();

    this.set('autoUpload',config.autoUpload);
    this.set('queueTarget',config.queueTarget || "#queue");
    this.set('multipleLen',config.multipleLen || -1 );
    this.set('beforeUpload',config.beforeUpload);
    this.set('data',config.data);

    var adapter = new adapters[this.type](element,config);
    // 初始化上传队列

    this._initQueue();

    adapter.on("load",function(){
        self.emit("load");
    });

    adapter.on("select",function(e){
        var queue = self.get('queue'),
            curId = self.get('currentId'),
            files = e.files;

        files = self._processExceedMultiple(files);
        self.emit("select",{files:files});

        _.forEach(files,function(file){
            queue.add(file);
        });
        if (!curId && self.get('autoUpload')) {
            self.upload();
        }
    });

    adapter.on('start',function(e){
        self.emit("start",e);
        self.set('currentId',e.file.id);
    });

    adapter.on("progress",function(e){
        var queue = self.get("queue");
        queue.updateFileStatus(e.file,"progress");
        self.emit("progress",e);
    });

    adapter.on("success",function(e){
        self.emit("success",e);
    });

    adapter.on("error",function(e){
        self.emit("error",e);
    });

    self.on("success",function(e){
        var queue = self.get("queue");
        queue.updateFileStatus(e.file,"success");
        self.emit("complete",e);
    });

    self.on("error",function(e){
        var queue = self.get("queue");
        queue.updateFileStatus(e.file,"error");
        self.emit("complete",e);
    });

    self.on("complete",function(e){
        var queue = self.get("queue");
        var file = e.file;
        self._continue();
    });

    self.on("enable",function(){
        adapter.setDisabled(false);
    });

    self.on("disable",function(){
        adapter.setDisabled(true);
    });

    this.set("adapter",adapter);

    this._auth(config);
    this._theme(theme);
}

util.inherits(Uploader,events);
attributes.patch(Uploader,{
    queueTarget:{
        setter: function(selector){
            return $(selector);
        }
    },
    beforeUpload:{value:function(){}},
    theme:{value:{}},
    data:{value:{}},
    /**
     * 是否自动上传
     * @type Boolean
     * @default true
     */
    autoUpload:{
        value:true,
        setter:function(v){
            if(v===undefined){
                return true
            }
        }
    },
    /**
     * Queue队列的实例
     * @type Queue
     * @default {}
     */
    queue:{value:{}},
    /**
     * 上传方式实例
     * @type UploaderType
     * @default {}
     */
    adapter:{value:{}},
    /**
     * 用于限制多选文件个数，值为负时不设置多选限制
     * @type Number
     * @default -1
     */
    multipleLen:{value:-1},
    maxItems:{value:-1},
    /**
     *  当前上传的文件对应的在数组内的Id，如果没有文件正在上传，值为空
     *  @type Number
     *  @default ""
     */
    currentId:{value:''},
    isAllowUpload:{value:true},
    isSuccess:{value:function(){return true;}}
});

Uploader.prototype.upload = function(file){
    var self = this;
    var beforeUpload = this.get('beforeUpload');

    if(!file){
        this._continue();
    }else{
        file.ext = "." + _.chain(file.name.split(".")).reverse().value()[0];
        if(beforeUpload){
            beforeUpload.call(self, file, _.bind(this._upload,this,file));
        }else{
            this._upload(file);
        }
    }
}

Uploader.prototype._upload = function(file){
    var adapter = this.get("adapter");
    this.get("data") && adapter.setData(this.get("data"));
    adapter.upload(file);
}

Uploader.prototype.remove = function(file){
    this.get("queue").remove(file);
}

Uploader.prototype._convertSizeUnit = function(size){
    var match = size.match(/(\d+)(\w)/);
    var count = match[1];
    var unit = match[2];
    var units = ["K","M","G"];
    return count * Math.pow(1024, units.indexOf(unit) + 1);
}

Uploader.prototype._auth = function(config){
    var self = this;
    var maxItems = config.maxItems;
    var allowExtensions = config.allowExtensions;
    var maxSize = config.maxSize || -1;
    var adapter = this.get("adapter");

    maxItems && self.set("maxItems",maxItems);

    allowExtensions
    && self.on("load",function(){
        self.get("adapter").setFileTypes(allowExtensions);
    });

    this.on('add', function(e){
        var file = e.file;
        if(maxSize > 0 && self._convertSizeUnit(maxSize) < file.size){
            return self.emit("error",{
                file:file,
                code: Errors.UPLOAD_FAILED,
                message: "UPLOAD_FAILED"
            });
        }
    });

    this.on('success', function(){
        if(self.reachMax()){
            self.emit("disable");
        }
    });

    this.on("remove", function(){
        if(!self.reachMax()){
            self.emit("enable");
        }
    });
    return this;
}

Uploader.prototype._initQueue = function () {
    var self = this, queue = new Queue();
    //将上传组件实例传给队列，方便队列内部执行取消、重新上传的操作
    queue.set('uploader', self);

    queue.on('add',function(ev){
        self.emit("add",ev);
    });

    //监听队列的删除事件
    queue.on('remove', function (ev) {
        self.emit("remove",ev);
    });
    self.set('queue', queue);
    return queue;
};

Uploader.prototype._createItem = function (event) {
  var self = this;
  var container = this.get('queueTarget');
  var file = event.file;
  var item = $(_.template(this.get('theme').template, file));
  item.attr('id', 'J_upload_item_' + file.id);
  item.appendTo(container);

  item.find(".J_upload_remove").on("click", function () {
    self.remove(file);
  });
};

Uploader.prototype._theme = function(theme){
    var self = this;
    this.set('theme',theme);
    self.on('add',function(file){
        self._createItem(file);
    });

    _.forEach(['load','add','remove','start','progress','success','error','complete'],function(ev){
        self.on(ev,function(e){
            var func = theme[ev];
            if(e && _.isObject(e) && e.file){
                e.elem = $("#J_upload_item_" + e.file.id);
            }
            func && func.call(self,e);
        });
    });
}

Uploader.prototype._successCount = function(){
    return this.get("queue").getFilesByStatus("success").length;
}

Uploader.prototype.reachMax = function(){
    var maxItems = this.get("maxItems");
    return maxItems <= this._successCount();
}

/**
 * 超过最大多选数予以截断
 */
Uploader.prototype._processExceedMultiple = function (files) {
    // var filesArr = [];
    var self = this,
        multipleLen = self.get('multipleLen'),
        maxItems = self.get("maxItems"),
        succeeded = self._successCount();

    if ( (multipleLen < 0 && maxItems < 0 ) || !files.length) return files;
    return _.filter(files, function (file, index) {
        if(maxItems < 0){
            return index < multipleLen;
        }

        if(multipleLen < 0){
            return index < maxItems - succeeded;
        }

        return index < multipleLen && index < maxItems - succeeded;
    });
};

Uploader.prototype._continue = function(){
    var queue = this.get("queue");
    var file = queue.getFilesByStatus("waiting")[0];
    if(file){
        this.upload(file);
    }else{
        this.set('currentId',null);
    }
}

Uploader.prototype._getType = function(){
    if (new XMLHttpRequest().upload) {
        return "ajax";
    } else {
        return "flash";
    }
}

<commit_msg>reachMax should return false if maxItems is not set  fixes #4<commit_after>'use strict';

var events = require("events");
var util = require("util");
var $ = require("jquery");
var Queue = require("./queue");
var _ = require("underscore");
var attributes = require("attributes");
var Errors = require("./errors");

module.exports = Uploader;

var adapters = {
    flash : require("./adapter/flash"),
    ajax : require("./adapter/ajax")
};

function Uploader(element,config){
    var theme = config.theme || require("./theme/default");
    var self = this;

    this.type = config.type || this._getType();

    this.set('autoUpload',config.autoUpload);
    this.set('queueTarget',config.queueTarget || "#queue");
    this.set('multipleLen',config.multipleLen || -1 );
    this.set('beforeUpload',config.beforeUpload);
    this.set('data',config.data);

    var adapter = new adapters[this.type](element,config);
    // 初始化上传队列

    this._initQueue();

    adapter.on("load",function(){
        self.emit("load");
    });

    adapter.on("select",function(e){
        var queue = self.get('queue'),
            curId = self.get('currentId'),
            files = e.files;

        files = self._processExceedMultiple(files);
        self.emit("select",{files:files});

        _.forEach(files,function(file){
            queue.add(file);
        });
        if (!curId && self.get('autoUpload')) {
            self.upload();
        }
    });

    adapter.on('start',function(e){
        self.emit("start",e);
        self.set('currentId',e.file.id);
    });

    adapter.on("progress",function(e){
        var queue = self.get("queue");
        queue.updateFileStatus(e.file,"progress");
        self.emit("progress",e);
    });

    adapter.on("success",function(e){
        self.emit("success",e);
    });

    adapter.on("error",function(e){
        self.emit("error",e);
    });

    self.on("success",function(e){
        var queue = self.get("queue");
        queue.updateFileStatus(e.file,"success");
        self.emit("complete",e);
    });

    self.on("error",function(e){
        var queue = self.get("queue");
        queue.updateFileStatus(e.file,"error");
        self.emit("complete",e);
    });

    self.on("complete",function(e){
        var queue = self.get("queue");
        var file = e.file;
        self._continue();
    });

    self.on("enable",function(){
        adapter.setDisabled(false);
    });

    self.on("disable",function(){
        adapter.setDisabled(true);
    });

    this.set("adapter",adapter);

    this._auth(config);
    this._theme(theme);
}

util.inherits(Uploader,events);
attributes.patch(Uploader,{
    queueTarget:{
        setter: function(selector){
            return $(selector);
        }
    },
    beforeUpload:{value:function(){}},
    theme:{value:{}},
    data:{value:{}},
    /**
     * 是否自动上传
     * @type Boolean
     * @default true
     */
    autoUpload:{
        value:true,
        setter:function(v){
            if(v===undefined){
                return true
            }
        }
    },
    /**
     * Queue队列的实例
     * @type Queue
     * @default {}
     */
    queue:{value:{}},
    /**
     * 上传方式实例
     * @type UploaderType
     * @default {}
     */
    adapter:{value:{}},
    /**
     * 用于限制多选文件个数，值为负时不设置多选限制
     * @type Number
     * @default -1
     */
    multipleLen:{value:-1},
    maxItems:{value:-1},
    /**
     *  当前上传的文件对应的在数组内的Id，如果没有文件正在上传，值为空
     *  @type Number
     *  @default ""
     */
    currentId:{value:''},
    isAllowUpload:{value:true},
    isSuccess:{value:function(){return true;}}
});

Uploader.prototype.upload = function(file){
    var self = this;
    var beforeUpload = this.get('beforeUpload');

    if(!file){
        this._continue();
    }else{
        file.ext = "." + _.chain(file.name.split(".")).reverse().value()[0];
        if(beforeUpload){
            beforeUpload.call(self, file, _.bind(this._upload,this,file));
        }else{
            this._upload(file);
        }
    }
}

Uploader.prototype._upload = function(file){
    var adapter = this.get("adapter");
    this.get("data") && adapter.setData(this.get("data"));
    adapter.upload(file);
}

Uploader.prototype.remove = function(file){
    this.get("queue").remove(file);
}

Uploader.prototype._convertSizeUnit = function(size){
    var match = size.match(/(\d+)(\w)/);
    var count = match[1];
    var unit = match[2];
    var units = ["K","M","G"];
    return count * Math.pow(1024, units.indexOf(unit) + 1);
}

Uploader.prototype._auth = function(config){
    var self = this;
    var maxItems = config.maxItems;
    var allowExtensions = config.allowExtensions;
    var maxSize = config.maxSize || -1;
    var adapter = this.get("adapter");

    maxItems && self.set("maxItems",maxItems);

    allowExtensions
    && self.on("load",function(){
        self.get("adapter").setFileTypes(allowExtensions);
    });

    this.on('add', function(e){
        var file = e.file;
        if(maxSize > 0 && self._convertSizeUnit(maxSize) < file.size){
            return self.emit("error",{
                file:file,
                code: Errors.UPLOAD_FAILED,
                message: "UPLOAD_FAILED"
            });
        }
    });

    this.on('success', function(){
        if(self.reachMax()){
            self.emit("disable");
        }
    });

    this.on("remove", function(){
        if(!self.reachMax()){
            self.emit("enable");
        }
    });
    return this;
}

Uploader.prototype._initQueue = function () {
    var self = this, queue = new Queue();
    //将上传组件实例传给队列，方便队列内部执行取消、重新上传的操作
    queue.set('uploader', self);

    queue.on('add',function(ev){
        self.emit("add",ev);
    });

    //监听队列的删除事件
    queue.on('remove', function (ev) {
        self.emit("remove",ev);
    });
    self.set('queue', queue);
    return queue;
};

Uploader.prototype._createItem = function (event) {
  var self = this;
  var container = this.get('queueTarget');
  var file = event.file;
  var item = $(_.template(this.get('theme').template, file));
  item.attr('id', 'J_upload_item_' + file.id);
  item.appendTo(container);

  item.find(".J_upload_remove").on("click", function () {
    self.remove(file);
  });
};

Uploader.prototype._theme = function(theme){
    var self = this;
    this.set('theme',theme);
    self.on('add',function(file){
        self._createItem(file);
    });

    _.forEach(['load','add','remove','start','progress','success','error','complete'],function(ev){
        self.on(ev,function(e){
            var func = theme[ev];
            if(e && _.isObject(e) && e.file){
                e.elem = $("#J_upload_item_" + e.file.id);
            }
            func && func.call(self,e);
        });
    });
}

Uploader.prototype._successCount = function(){
    return this.get("queue").getFilesByStatus("success").length;
}

Uploader.prototype.reachMax = function(){
    var maxItems = this.get("maxItems");
    return maxItems > 0 && maxItems <= this._successCount();
}

/**
 * 超过最大多选数予以截断
 */
Uploader.prototype._processExceedMultiple = function (files) {
    // var filesArr = [];
    var self = this,
        multipleLen = self.get('multipleLen'),
        maxItems = self.get("maxItems"),
        succeeded = self._successCount();

    if ( (multipleLen < 0 && maxItems < 0 ) || !files.length) return files;
    return _.filter(files, function (file, index) {
        if(maxItems < 0){
            return index < multipleLen;
        }

        if(multipleLen < 0){
            return index < maxItems - succeeded;
        }

        return index < multipleLen && index < maxItems - succeeded;
    });
};

Uploader.prototype._continue = function(){
    var queue = this.get("queue");
    var file = queue.getFilesByStatus("waiting")[0];
    if(file){
        this.upload(file);
    }else{
        this.set('currentId',null);
    }
}

Uploader.prototype._getType = function(){
    if (new XMLHttpRequest().upload) {
        return "ajax";
    } else {
        return "flash";
    }
}

<|endoftext|>


<commit_before>import {Origin} from 'aurelia-metadata';
import {Loader} from 'aurelia-loader';
import {DOM, PLATFORM} from 'aurelia-pal';

/**
* An implementation of the TemplateLoader interface implemented with text-based loading.
*/
export class TextTemplateLoader {
  /**
  * Loads a template.
  * @param loader The loader that is requesting the template load.
  * @param entry The TemplateRegistryEntry to load and populate with a template.
  * @return A promise which resolves when the TemplateRegistryEntry is loaded with a template.
  */
  loadTemplate(loader, entry) {
    return loader.loadText(entry.address).then(text => {
      entry.template = DOM.createTemplateFromMarkup(text);
    });
  }
}

function ensureOriginOnExports(executed, name) {
  let target = executed;
  let key;
  let exportedValue;

  if (target.__useDefault) {
    target = target.default;
  }

  Origin.set(target, new Origin(name, 'default'));

  for (key in target) {
    exportedValue = target[key];

    if (typeof exportedValue === 'function') {
      Origin.set(exportedValue, new Origin(name, key));
    }
  }

  return executed;
}

/**
* A default implementation of the Loader abstraction which works with webpack (extended common-js style).
*/
export class WebpackLoader extends Loader {
  constructor() {
    super();

    this.moduleRegistry = Object.create(null);
    this.loaderPlugins = Object.create(null);
    this.useTemplateLoader(new TextTemplateLoader());

    let that = this;

    this.addPlugin('template-registry-entry', {
      'fetch': function(address) {
        let entry = that.getOrCreateTemplateRegistryEntry(address);
        return entry.templateIsLoaded ? entry : that.templateLoader.loadTemplate(that, entry).then(x => entry);
      }
    });

    PLATFORM.eachModule = callback => {
      let registry = this.moduleRegistry;

      for (let key in registry) {
        try {
          if (callback(key, registry[key])) return;
        } catch (e) {}
      }
    };
  }

  _import(moduleId) {
    const moduleIdParts = moduleId.split('!');
    const path = moduleIdParts.splice(moduleIdParts.length - 1, 1)[0];
    const loaderPlugin = moduleIdParts.length === 1 ? moduleIdParts[0] : null;

    return new Promise((resolve, reject) => {
      try {
        if (loaderPlugin) {
          resolve(this.loaderPlugins[loaderPlugin].fetch(path));
        } else {
          require.ensure([], function(require) {
            const result = require('aurelia-loader-context/' + path);
            if (typeof(result) === 'function') { // because of async loading when the bundle loader is active
              result(res => resolve(res));
            } else {
              resolve(result);
            }
          });
        }
      } catch (e) {
        reject(e);
      }
    });
  }

  /**
  * Maps a module id to a source.
  * @param id The module id.
  * @param source The source to map the module to.
  */
  map(id, source) {

  }

  /**
  * Normalizes a module id.
  * @param moduleId The module id to normalize.
  * @param relativeTo What the module id should be normalized relative to.
  * @return The normalized module id.
  */
  normalizeSync(moduleId, relativeTo) {
    return moduleId;
  }

  /**
  * Normalizes a module id.
  * @param moduleId The module id to normalize.
  * @param relativeTo What the module id should be normalized relative to.
  * @return The normalized module id.
  */
  normalize(moduleId, relativeTo) {
    return Promise.resolve(moduleId);
  }

  /**
  * Instructs the loader to use a specific TemplateLoader instance for loading templates
  * @param templateLoader The instance of TemplateLoader to use for loading templates.
  */
  useTemplateLoader(templateLoader) {
    this.templateLoader = templateLoader;
  }

  /**
  * Loads a collection of modules.
  * @param ids The set of module ids to load.
  * @return A Promise for an array of loaded modules.
  */
  loadAllModules(ids) {
    let loads = [];

    for (let i = 0, ii = ids.length; i < ii; ++i) {
      loads.push(this.loadModule(ids[i]));
    }

    return Promise.all(loads);
  }

  /**
  * Loads a module.
  * @param id The module id to normalize.
  * @return A Promise for the loaded module.
  */
  loadModule(id) {
    let existing = this.moduleRegistry[id];
    if (existing) {
      return Promise.resolve(existing);
    }

    return new Promise((resolve, reject) => {
      try {
        this._import(id).then(m => {
          this.moduleRegistry[id] = m;
          resolve(ensureOriginOnExports(m, id));
        });
      } catch (e) {
        reject(e);
      }
    });
  }

  /**
  * Loads a template.
  * @param url The url of the template to load.
  * @return A Promise for a TemplateRegistryEntry containing the template.
  */
  loadTemplate(url) {
    return this._import(this.applyPluginToUrl(url, 'template-registry-entry'));
  }

  /**
  * Loads a text-based resource.
  * @param url The url of the text file to load.
  * @return A Promise for text content.
  */
  loadText(url) {
    return this._import(url);
  }

  /**
  * Alters a module id so that it includes a plugin loader.
  * @param url The url of the module to load.
  * @param pluginName The plugin to apply to the module id.
  * @return The plugin-based module id.
  */
  applyPluginToUrl(url, pluginName) {
    return `${pluginName}!${url}`;
  }

  /**
  * Registers a plugin with the loader.
  * @param pluginName The name of the plugin.
  * @param implementation The plugin implementation.
  */
  addPlugin(pluginName, implementation) {
    this.loaderPlugins[pluginName] = implementation;
  }
}

PLATFORM.Loader = WebpackLoader;
<commit_msg>feat(index): use a named chunk<commit_after>import {Origin} from 'aurelia-metadata';
import {Loader} from 'aurelia-loader';
import {DOM, PLATFORM} from 'aurelia-pal';

/**
* An implementation of the TemplateLoader interface implemented with text-based loading.
*/
export class TextTemplateLoader {
  /**
  * Loads a template.
  * @param loader The loader that is requesting the template load.
  * @param entry The TemplateRegistryEntry to load and populate with a template.
  * @return A promise which resolves when the TemplateRegistryEntry is loaded with a template.
  */
  loadTemplate(loader, entry) {
    return loader.loadText(entry.address).then(text => {
      entry.template = DOM.createTemplateFromMarkup(text);
    });
  }
}

function ensureOriginOnExports(executed, name) {
  let target = executed;
  let key;
  let exportedValue;

  if (target.__useDefault) {
    target = target.default;
  }

  Origin.set(target, new Origin(name, 'default'));

  for (key in target) {
    exportedValue = target[key];

    if (typeof exportedValue === 'function') {
      Origin.set(exportedValue, new Origin(name, key));
    }
  }

  return executed;
}

/**
* A default implementation of the Loader abstraction which works with webpack (extended common-js style).
*/
export class WebpackLoader extends Loader {
  constructor() {
    super();

    this.moduleRegistry = Object.create(null);
    this.loaderPlugins = Object.create(null);
    this.useTemplateLoader(new TextTemplateLoader());

    let that = this;

    this.addPlugin('template-registry-entry', {
      'fetch': function(address) {
        let entry = that.getOrCreateTemplateRegistryEntry(address);
        return entry.templateIsLoaded ? entry : that.templateLoader.loadTemplate(that, entry).then(x => entry);
      }
    });

    PLATFORM.eachModule = callback => {
      let registry = this.moduleRegistry;

      for (let key in registry) {
        try {
          if (callback(key, registry[key])) return;
        } catch (e) {}
      }
    };
  }

  _import(moduleId) {
    const moduleIdParts = moduleId.split('!');
    const path = moduleIdParts.splice(moduleIdParts.length - 1, 1)[0];
    const loaderPlugin = moduleIdParts.length === 1 ? moduleIdParts[0] : null;

    return new Promise((resolve, reject) => {
      try {
        if (loaderPlugin) {
          resolve(this.loaderPlugins[loaderPlugin].fetch(path));
        } else {
          require.ensure([], function(require) {
            const result = require('aurelia-loader-context/' + path);
            if (typeof(result) === 'function') { // because of async loading when the bundle loader is active
              result(res => resolve(res));
            } else {
              resolve(result);
            }
          }, 'app');
        }
      } catch (e) {
        reject(e);
      }
    });
  }

  /**
  * Maps a module id to a source.
  * @param id The module id.
  * @param source The source to map the module to.
  */
  map(id, source) {

  }

  /**
  * Normalizes a module id.
  * @param moduleId The module id to normalize.
  * @param relativeTo What the module id should be normalized relative to.
  * @return The normalized module id.
  */
  normalizeSync(moduleId, relativeTo) {
    return moduleId;
  }

  /**
  * Normalizes a module id.
  * @param moduleId The module id to normalize.
  * @param relativeTo What the module id should be normalized relative to.
  * @return The normalized module id.
  */
  normalize(moduleId, relativeTo) {
    return Promise.resolve(moduleId);
  }

  /**
  * Instructs the loader to use a specific TemplateLoader instance for loading templates
  * @param templateLoader The instance of TemplateLoader to use for loading templates.
  */
  useTemplateLoader(templateLoader) {
    this.templateLoader = templateLoader;
  }

  /**
  * Loads a collection of modules.
  * @param ids The set of module ids to load.
  * @return A Promise for an array of loaded modules.
  */
  loadAllModules(ids) {
    let loads = [];

    for (let i = 0, ii = ids.length; i < ii; ++i) {
      loads.push(this.loadModule(ids[i]));
    }

    return Promise.all(loads);
  }

  /**
  * Loads a module.
  * @param id The module id to normalize.
  * @return A Promise for the loaded module.
  */
  loadModule(id) {
    let existing = this.moduleRegistry[id];
    if (existing) {
      return Promise.resolve(existing);
    }

    return new Promise((resolve, reject) => {
      try {
        this._import(id).then(m => {
          this.moduleRegistry[id] = m;
          resolve(ensureOriginOnExports(m, id));
        });
      } catch (e) {
        reject(e);
      }
    });
  }

  /**
  * Loads a template.
  * @param url The url of the template to load.
  * @return A Promise for a TemplateRegistryEntry containing the template.
  */
  loadTemplate(url) {
    return this._import(this.applyPluginToUrl(url, 'template-registry-entry'));
  }

  /**
  * Loads a text-based resource.
  * @param url The url of the text file to load.
  * @return A Promise for text content.
  */
  loadText(url) {
    return this._import(url);
  }

  /**
  * Alters a module id so that it includes a plugin loader.
  * @param url The url of the module to load.
  * @param pluginName The plugin to apply to the module id.
  * @return The plugin-based module id.
  */
  applyPluginToUrl(url, pluginName) {
    return `${pluginName}!${url}`;
  }

  /**
  * Registers a plugin with the loader.
  * @param pluginName The name of the plugin.
  * @param implementation The plugin implementation.
  */
  addPlugin(pluginName, implementation) {
    this.loaderPlugins[pluginName] = implementation;
  }
}

PLATFORM.Loader = WebpackLoader;
<|endoftext|>


<commit_before>HummingbirdTracker = {};

HummingbirdTracker.track = function(env) {
  delete env.trackingServer;
  delete env.trackingServerSecure;
  env.u = document.location.href;
  env.bw = window.innerWidth;
  env.bh = window.innerHeight;
  env.guid = document.cookie.match(/guid=([^\_]*)_([^;]*)/)[2];
  env.gen = document.cookie.match(/gender=([^;]*);/)[1];
  env.uid = document.cookie.match(/user_id=([^\_]*)_([^;]*)/)[2];

  $('body').append('');
};
<commit_msg>Adding referrer to tracking pixel<commit_after>HummingbirdTracker = {};

HummingbirdTracker.track = function(env) {
  delete env.trackingServer;
  delete env.trackingServerSecure;
  env.u = document.location.href;
  env.bw = window.innerWidth;
  env.bh = window.innerHeight;
  env.guid = document.cookie.match(/guid=([^\_]*)_([^;]*)/)[2];
  env.gen = document.cookie.match(/gender=([^;]*);/)[1];
  env.uid = document.cookie.match(/user_id=([^\_]*)_([^;]*)/)[2];

  if(document.referrer && document.referrer != "") {
    env.ref = document.referrer;
  }

  $('body').append('');
};
<|endoftext|>


<commit_before>import { css } from 'styled-components';
import { pxToEm, pxToRem } from './convertors';

export {
  pxToEm,
  pxToRem
};

/**
 * Default media breakpoints
 * @type {Object}
 */
export const defaultBreakpoints = {
  huge: '1440px',
  large: '1170px',
  medium: '768px',
  small: '450px',
};

function getSizeFromBreakpoint(breakpointValue: number | string, breakpoints = {}) {
  if (breakpoints[breakpointValue]) {
    return breakpoints[breakpointValue];
  } else if (parseInt(breakpointValue)) {
    return breakpointValue;
  } else {
    console.error('styled-media-query: No valid breakpoint or size specified for media.');
    return '0';
  }
}

/**
 * Media query generator
 * @param {Object} [defaultBreakpoints] breakpoints - Map labels to breakpoint sizes
 * @return {Object} - Media generators for each breakpoint
 */
export function generateMedia(breakpoints = defaultBreakpoints) {
  const lessThan = (breakpoint) => (...args) => css`
    @media (max-width: ${getSizeFromBreakpoint(breakpoint, breakpoints)}) {
      ${css(...args)}
    }
  `;

  const greaterThan = (breakpoint) => (...args) => css`
    @media (min-width: ${getSizeFromBreakpoint(breakpoint, breakpoints)}) {
      ${css(...args)}
    }
  `;

  const between = (firstBreakpoint, secondBreakpoint) => (...args) => css`
    @media (min-width: ${getSizeFromBreakpoint(firstBreakpoint, breakpoints)}) and
      (max-width: ${getSizeFromBreakpoint(secondBreakpoint, breakpoints)}) {
      ${css(...args)}
    }
  `;

  const oldStyle = Object
    .keys(breakpoints)
    .reduce((acc, label) => {
      const size = breakpoints[label];

      acc.to[label] = (...args) => {
        console.warn(`styled-media-query: Use media.lessThan('${label}') instead of old media.${label} (Probably we'll deprecate it)`);
        return css`
          @media (max-width: ${size}) {
            ${css(...args)}
          }
        `;
      };

      acc.from[label] = (...args) => {
        console.warn(`styled-media-query: Use media.lessThan('${label}') instead of old media.${label} (Probably we'll deprecate it)`);
        return css`
          @media (min-width: ${size}) {
            ${css(...args)}
          }
        `;
      };

      return acc;
    },
    { to: {}, from: {} }
  );

  return Object.assign(
    {
      lessThan,
      greaterThan,
      between,
    },
    oldStyle,
  );
}

/**
 * Media object with default breakpoints
 * @return {object} - Media generators for each size
 */
export default generateMedia();

/**
 * Usage: styled.div` ${media.from.medium`background: #000;`} `;
 * With this code, background for small and medium sizes will be `default` and for more than medium, will be `#000`
 */
<commit_msg>fix: Correct warning message<commit_after>import { css } from 'styled-components';
import { pxToEm, pxToRem } from './convertors';

export {
  pxToEm,
  pxToRem
};

/**
 * Default media breakpoints
 * @type {Object}
 */
export const defaultBreakpoints = {
  huge: '1440px',
  large: '1170px',
  medium: '768px',
  small: '450px',
};

function getSizeFromBreakpoint(breakpointValue: number | string, breakpoints = {}) {
  if (breakpoints[breakpointValue]) {
    return breakpoints[breakpointValue];
  } else if (parseInt(breakpointValue)) {
    return breakpointValue;
  } else {
    console.error('styled-media-query: No valid breakpoint or size specified for media.');
    return '0';
  }
}

/**
 * Media query generator
 * @param {Object} [defaultBreakpoints] breakpoints - Map labels to breakpoint sizes
 * @return {Object} - Media generators for each breakpoint
 */
export function generateMedia(breakpoints = defaultBreakpoints) {
  const lessThan = (breakpoint) => (...args) => css`
    @media (max-width: ${getSizeFromBreakpoint(breakpoint, breakpoints)}) {
      ${css(...args)}
    }
  `;

  const greaterThan = (breakpoint) => (...args) => css`
    @media (min-width: ${getSizeFromBreakpoint(breakpoint, breakpoints)}) {
      ${css(...args)}
    }
  `;

  const between = (firstBreakpoint, secondBreakpoint) => (...args) => css`
    @media (min-width: ${getSizeFromBreakpoint(firstBreakpoint, breakpoints)}) and
      (max-width: ${getSizeFromBreakpoint(secondBreakpoint, breakpoints)}) {
      ${css(...args)}
    }
  `;

  const oldStyle = Object
    .keys(breakpoints)
    .reduce((acc, label) => {
      const size = breakpoints[label];

      acc.to[label] = (...args) => {
        console.warn(`styled-media-query: Use media.lessThan('${label}') instead of old media.to.${label} (Probably we'll deprecate it)`);
        return css`
          @media (max-width: ${size}) {
            ${css(...args)}
          }
        `;
      };

      acc.from[label] = (...args) => {
        console.warn(`styled-media-query: Use media.greaterThan('${label}') instead of old media.from.${label} (Probably we'll deprecate it)`);
        return css`
          @media (min-width: ${size}) {
            ${css(...args)}
          }
        `;
      };

      return acc;
    },
    { to: {}, from: {} }
  );

  return Object.assign(
    {
      lessThan,
      greaterThan,
      between,
    },
    oldStyle,
  );
}

/**
 * Media object with default breakpoints
 * @return {object} - Media generators for each size
 */
export default generateMedia();

/**
 * Usage: styled.div` ${media.from.medium`background: #000;`} `;
 * With this code, background for small and medium sizes will be `default` and for more than medium, will be `#000`
 */
<|endoftext|>


<commit_before>let getUserMedia = navigator.getUserMedia ||
    navigator.webkitGetUserMedia ||
    navigator.mozGetUserMedia ||
    navigator.msGetUserMedia
if (getUserMedia) {
  getUserMedia = getUserMedia.bind(navigator)
}

const supportsSourceSelection = !!window.MediaStreamTrack.getSources

function equalsNormalizedFacing(desired, check) {
  let normalized = check
  switch (check) {
    case 'user':
      normalized = 'front'
      break
    case 'environment':
      normalized = 'rear'
      break
  }

  return desired === normalized
}

class StreamResult {
  constructor(video, stream, url, hasFrontAndRear, facing) {
    this.video = video
    this.stream = stream
    this.url = url
    this.hasFrontAndRear = hasFrontAndRear
    this.facing = facing
    this.stopped = false
  }

  stop() {
    if (this.stopped) return

    if (this.url && this.video.src === this.url) {
      this.video.pause()
      this.video.removeAttribute('src')
      window.URL.revokeObjectURL(this.url)
      this.url = null
    } else if (this.video.mozSrcObject && this.video.mozSrcObject === this.stream) {
      this.video.pause()
      this.video.removeAttribute('src')
    }

    this.stream.stop()
    this.video = null
    this.stream = null
    this.stopped = true
  }
}

function initWebrtc(video, width, height, facing, cb) {
  if (!getUserMedia) {
    return cb(new Error('Browser doesn\'t support WebRTC'))
  }

  const constraints = {
    optional: [
      { minWidth: width },
      { minHeight: height },
      { minAspectRatio: width / height },
    ],
  }
  let hasFrontAndRear = false
  let requestedFacing = false

  if (!facing || !supportsSourceSelection) {
    return getMedia()
  }

  window.MediaStreamTrack.getSources(infos => {
    let found = false
    let hasFront = false
    let hasRear = false

    for (const info of infos) {
      if (info.kind !== 'video') continue

      if (equalsNormalizedFacing(facing, info.facing) && !found) {
        found = true
        requestedFacing = true
        constraints.optional.push({ sourceId: info.id })
      }

      if (equalsNormalizedFacing('front', info.facing)) {
        hasFront = true
      } else if (equalsNormalizedFacing('rear', info.facing)) {
        hasRear = true
      }
    }

    hasFrontAndRear = hasFront && hasRear
    getMedia()
  })

  function getMedia() {
    getUserMedia({
      audio: false,
      video: constraints,
    }, success, failure)
  }

  function success(stream) {
    let url
    video.autoplay = true
    if (video.mozSrcObject) {
      video.mozSrcObject = stream
    } else {
      url = window.URL.createObjectURL(stream)
      video.src = url
    }

    video.addEventListener('loadeddata', dataLoaded)

    function dataLoaded() {
      video.removeEventListener('loadeddata', dataLoaded)
      cb(null,
          new StreamResult(video, stream, url, hasFrontAndRear, requestedFacing ? facing : null))
    }
  }

  function failure(err) {
    cb(err)
  }
}

initWebrtc.supportsSourceSelection = supportsSourceSelection
export default initWebrtc
<commit_msg>Stop MediaStream correcly.<commit_after>let getUserMedia = navigator.getUserMedia ||
    navigator.webkitGetUserMedia ||
    navigator.mozGetUserMedia ||
    navigator.msGetUserMedia
if (getUserMedia) {
  getUserMedia = getUserMedia.bind(navigator)
}

const supportsSourceSelection = !!window.MediaStreamTrack.getSources

function equalsNormalizedFacing(desired, check) {
  let normalized = check
  switch (check) {
    case 'user':
      normalized = 'front'
      break
    case 'environment':
      normalized = 'rear'
      break
  }

  return desired === normalized
}

class StreamResult {
  constructor(video, stream, url, hasFrontAndRear, facing) {
    this.video = video
    this.stream = stream
    this.url = url
    this.hasFrontAndRear = hasFrontAndRear
    this.facing = facing
    this.stopped = false
  }

  stop() {
    if (this.stopped) return

    if (this.url && this.video.src === this.url) {
      this.video.pause()
      this.video.removeAttribute('src')
      window.URL.revokeObjectURL(this.url)
      this.url = null
    } else if (this.video.mozSrcObject && this.video.mozSrcObject === this.stream) {
      this.video.pause()
      this.video.removeAttribute('src')
    }

    for (const track of this.stream.getTracks()) {
      track.stop()
    }
    this.video = null
    this.stream = null
    this.stopped = true
  }
}

function initWebrtc(video, width, height, facing, cb) {
  if (!getUserMedia) {
    return cb(new Error('Browser doesn\'t support WebRTC'))
  }

  const constraints = {
    optional: [
      { minWidth: width },
      { minHeight: height },
      { minAspectRatio: width / height },
    ],
  }
  let hasFrontAndRear = false
  let requestedFacing = false

  if (!facing || !supportsSourceSelection) {
    return getMedia()
  }

  window.MediaStreamTrack.getSources(infos => {
    let found = false
    let hasFront = false
    let hasRear = false

    for (const info of infos) {
      if (info.kind !== 'video') continue

      if (equalsNormalizedFacing(facing, info.facing) && !found) {
        found = true
        requestedFacing = true
        constraints.optional.push({ sourceId: info.id })
      }

      if (equalsNormalizedFacing('front', info.facing)) {
        hasFront = true
      } else if (equalsNormalizedFacing('rear', info.facing)) {
        hasRear = true
      }
    }

    hasFrontAndRear = hasFront && hasRear
    getMedia()
  })

  function getMedia() {
    getUserMedia({
      audio: false,
      video: constraints,
    }, success, failure)
  }

  function success(stream) {
    let url
    video.autoplay = true
    if (video.mozSrcObject) {
      video.mozSrcObject = stream
    } else {
      url = window.URL.createObjectURL(stream)
      video.src = url
    }

    video.addEventListener('loadeddata', dataLoaded)

    function dataLoaded() {
      video.removeEventListener('loadeddata', dataLoaded)
      cb(null,
          new StreamResult(video, stream, url, hasFrontAndRear, requestedFacing ? facing : null))
    }
  }

  function failure(err) {
    cb(err)
  }
}

initWebrtc.supportsSourceSelection = supportsSourceSelection
export default initWebrtc
<|endoftext|>


<commit_before>var reader = require('text2token')

module.exports = Translator

function Translator () {
  this.foreignWords = []
  this.foreignLines = []
  this.nativeWords = []
  this.nativeLines = []
  this.devWords = []
  this.sentencePairs = []

  this.probs = {}
  this.transmissions = {} // this is t(e|f)
  this.countef = {} // this countef
  this.totalf = {}
  this.totals = {}
}

Translator.prototype.train = function (nativeText, foreignText) {
  if (nativeText == undefined || foreignText == undefined) {
    throw new Error('Native and Foreign Texts are both required!')
  }

  var convertedData = reader.text2token(nativeText)
  this.nativeLines = convertedData.lines
  this.nativeWords = convertedData.tokens

  var convertedForeignData = reader.text2token(foreignText)
  this.foreignLines = convertedForeignData.lines
  this.foreignWords = convertedForeignData.tokens

  this.sentencePairs = []
  for (var i = 0; i < this.nativeLines.length; i++) {
    var pair = [ this.nativeLines[i], this.foreignLines[i]]
    this.sentencePairs.push(pair)
  }

  this._initTransmissions()
  this._iterateEM(10)
}

Translator.prototype._initTransmissions = function () {
  var probs = {},
    transmissions = {}

  for (var i = 0; i < this.nativeWords.length; i++) {
    var word = this.nativeWords[i]
    var word_poss = []

    // if word is in sentence then...
    for (var j = 0; j < this.nativeLines.length; j++) {
      var sentence = this.nativeLines[j]

      if (sentence.indexOf(word) > -1) {
        var matching = this.foreignLines[this.nativeLines.indexOf(sentence)]
        var matches = matching.split(' ')
        for (var index = 0; index < matches.length; index++) {
          word_poss.push(matches[index])
        }
      }
    }

    // remove duplicates
    word_poss = word_poss.unique()

    // add probable matches
    probs[word] = word_poss
  }

  this.probs = probs

  for (var i = 0; i < this.nativeWords.length; i++) {
    var word = this.nativeWords[i]
    var word_probs = this.probs[word]

    var uniform_prob = 1.0 / word_probs.length

    var prob_set = {}

    for (var k = 0; k < word_probs.length; k++) {
      var w = word_probs[k]
      prob_set[w] = uniform_prob
    }

    transmissions[word] = prob_set
  }
  this.transmissions = transmissions
}

Translator.prototype._iterateEM = function (count) {
  for (var i = 0; i < count; i++) {
    var totalf = {},
      countef = {}

    for (var j = 0; j < this.nativeWords.length; j++) {
      var word = this.nativeWords[j]

      if (!this.probs.word)
        continue
      /* istanbul ignore next */
      var word_probs = this.probs[word]
      /* istanbul ignore next */
      var prob_set = {}
      /* istanbul ignore next */
      for (var k = 0; k < word_probs.length; k++) {
        var w = word_probs[k]
        prob_set[w] = 0
      }
      /* istanbul ignore next */
      countef[word] = count
      /* istanbul ignore next */
      totalf[word] = 0
    }

    this.countef = countef
    this.totalf = totalf

    // iterate over each sentence pair
    for (var k = 0; k < this.sentencePairs.length; k++) {
      var sentence = this.sentencePairs[k]
      var nativeTokens = sentence[0].split('')
      var foreignTokens = sentence[1].split('')

      for (var f = 0; f < foreignTokens.length; f++) {
        this.totals[f] = 0
        for (var n = 0; n < nativeTokens.length; n++) {
          if (!this.transmissions.n)
            continue
          /* istanbul ignore next */
          if (!this.transmissions.n.f)
            continue
          /* istanbul ignore next */
          this.countef[n][f] += this.transmissions[n][f] / this.totals[f]
          /* istanbul ignore next */
          this.totalf[n] += this.transmissions[n][f] / this.totals[f]
        }

      }

      for (var n = 0; n < nativeTokens.length; n++) {
        if (!this.probs.n)
          continue
        /* istanbul ignore next */
        var n_prob = self.probs[n]
        /* istanbul ignore next */
        for (var f = 0; f < n_prob.length; n++) {
          this.transmissions[n][f] = this.countef[n][f] / this.totalf[n]
        }
      }
    }
  }
}

Translator.prototype.translate = function (nativeWord) {
  if (!this.transmissions[nativeWord] || nativeWord === undefined) {
    throw new Error('No match found!')
  }
  return this.transmissions[nativeWord]
}

Array.prototype.contains = function (v) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] === v) return true
  }
  return false
}

Array.prototype.unique = function () {
  var arr = []
  for (var i = 0; i < this.length; i++) {
    if (!arr.contains(this[i])) {
      arr.push(this[i])
    }
  }
  return arr
}
<commit_msg>Added some basic JSDoc descriptions<commit_after>/**
 * Translator module. Uses statistical machine translation to
 * translate between two different languages. Loosely based on
 * the IBM model 1 algorithm.
 */
var reader = require('text2token')

module.exports = Translator

function Translator () {
  this.foreignWords = []
  this.foreignLines = []
  this.nativeWords = []
  this.nativeLines = []
  this.devWords = []
  this.sentencePairs = []

  this.probs = {}
  this.transmissions = {} // this is t(e|f)
  this.countef = {} // this countef
  this.totalf = {}
  this.totals = {}
}

/** Throw error if native text or foreign text is not provided. */
Translator.prototype.train = function (nativeText, foreignText) {
  if (nativeText == undefined || foreignText == undefined) {
    throw new Error('Native and Foreign Texts are both required!')
  }

  var convertedData = reader.text2token(nativeText)
  this.nativeLines = convertedData.lines
  this.nativeWords = convertedData.tokens

  var convertedForeignData = reader.text2token(foreignText)
  this.foreignLines = convertedForeignData.lines
  this.foreignWords = convertedForeignData.tokens

  this.sentencePairs = []
  for (var i = 0; i < this.nativeLines.length; i++) {
    var pair = [ this.nativeLines[i], this.foreignLines[i]]
    this.sentencePairs.push(pair)
  }

  this._initTransmissions()
  this._iterateEM(10)
}

Translator.prototype._initTransmissions = function () {
  var probs = {},
    transmissions = {}

  for (var i = 0; i < this.nativeWords.length; i++) {
    var word = this.nativeWords[i]
    var word_poss = []

    // if word is in sentence then...
    for (var j = 0; j < this.nativeLines.length; j++) {
      var sentence = this.nativeLines[j]

      if (sentence.indexOf(word) > -1) {
        var matching = this.foreignLines[this.nativeLines.indexOf(sentence)]
        var matches = matching.split(' ')
        for (var index = 0; index < matches.length; index++) {
          word_poss.push(matches[index])
        }
      }
    }

   /** Remove duplicates. */
    word_poss = word_poss.unique()

    /** Add probable matches. */
    probs[word] = word_poss
  }

  this.probs = probs

  for (var i = 0; i < this.nativeWords.length; i++) {
    var word = this.nativeWords[i]
    var word_probs = this.probs[word]

    var uniform_prob = 1.0 / word_probs.length

    var prob_set = {}

    for (var k = 0; k < word_probs.length; k++) {
      var w = word_probs[k]
      prob_set[w] = uniform_prob
    }

    transmissions[word] = prob_set
  }
  this.transmissions = transmissions
}

Translator.prototype._iterateEM = function (count) {
  for (var i = 0; i < count; i++) {
    var totalf = {},
      countef = {}

    for (var j = 0; j < this.nativeWords.length; j++) {
      var word = this.nativeWords[j]

      if (!this.probs.word)
        continue
      /* istanbul ignore next */
      var word_probs = this.probs[word]
      /* istanbul ignore next */
      var prob_set = {}
      /* istanbul ignore next */
      for (var k = 0; k < word_probs.length; k++) {
        var w = word_probs[k]
        prob_set[w] = 0
      }
      /* istanbul ignore next */
      countef[word] = count
      /* istanbul ignore next */
      totalf[word] = 0
    }

    this.countef = countef
    this.totalf = totalf

    /** Iterate over each sentence pair. */
    for (var k = 0; k < this.sentencePairs.length; k++) {
      var sentence = this.sentencePairs[k]
      var nativeTokens = sentence[0].split('')
      var foreignTokens = sentence[1].split('')

      for (var f = 0; f < foreignTokens.length; f++) {
        this.totals[f] = 0
        for (var n = 0; n < nativeTokens.length; n++) {
          if (!this.transmissions.n)
            continue
          /* istanbul ignore next */
          if (!this.transmissions.n.f)
            continue
          /* istanbul ignore next */
          this.countef[n][f] += this.transmissions[n][f] / this.totals[f]
          /* istanbul ignore next */
          this.totalf[n] += this.transmissions[n][f] / this.totals[f]
        }

      }

      for (var n = 0; n < nativeTokens.length; n++) {
        if (!this.probs.n)
          continue
        /* istanbul ignore next */
        var n_prob = self.probs[n]
        /* istanbul ignore next */
        for (var f = 0; f < n_prob.length; n++) {
          this.transmissions[n][f] = this.countef[n][f] / this.totalf[n]
        }
      }
    }
  }
}

/** Throw error if no match is found. */
Translator.prototype.translate = function (nativeWord) {
  if (!this.transmissions[nativeWord] || nativeWord === undefined) {
    throw new Error('No match found!')
  }
  return this.transmissions[nativeWord]
}

Array.prototype.contains = function (v) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] === v) return true
  }
  return false
}

Array.prototype.unique = function () {
  var arr = []
  for (var i = 0; i < this.length; i++) {
    if (!arr.contains(this[i])) {
      arr.push(this[i])
    }
  }
  return arr
}
<|endoftext|>