<commit_before>/* eslint-disable no-fallthrough */
(function () {
  'use strict';

  const colors         = require('colors');
  const strip          = require('cli-color/strip');
  const fs             = require('fs');
  const path           = require('path');
  const prompt         = require('prompt-sync')({sigint: true});
  const child_process  = require('child_process');
  const pkg            = require('./package.json');
  let oldVersion       = pkg.version;
  const abortCmds      = ['git reset --hard', 'git checkout staging', 'rm abort push'];
  const pushCmds       = ['rm abort push'];
  const cleanupCmds    = [];
  const defaultOptions = { encoding: 'utf-8' };
  const origin         = 'git@github.com:angular/material.git';
  const lineWidth      = 80;
  const lastMajorVer   = JSON.parse(exec('curl https://material.angularjs.org/docs.json')).latest;
  let newVersion;

  try {
    child_process.execSync('gulp --version', defaultOptions);
  } catch (error) {
    throw new Error('Please install gulp globally via "npm i -g gulp@^3.9.1".');
  }
  header();
  const dryRun = prompt(`Is this a dry-run? [${"yes".cyan}/no] `, 'yes') !== 'no';

  if (dryRun) {
    oldVersion = prompt(`What would you like the old version to be? (default: ${oldVersion.cyan}) `, oldVersion);
    build();
  } else if (validate()) {
    build();
  }

  function build () {
    newVersion = getNewVersion();

    line();

    checkoutVersionBranch();
    updateVersion();
    createChangelog();
    commitChanges();
    tagRelease();
    cloneRepo('bower-material');
    updateBowerVersion();
    cloneRepo('code.material.angularjs.org');
    updateSite();
    updateMaster();
    writeScript('abort', abortCmds.concat(cleanupCmds));
    if (!dryRun) writeScript('push', pushCmds.concat(cleanupCmds));

    line();
    log('Your repo is ready to be pushed.');
    log(`Please look over ${"CHANGELOG.md".cyan} and make any changes.`);
    log(`When you are ready, please run "${"./push".cyan}" to finish the process.`);
    log('If you would like to cancel this release, please run "./abort"');
  }

  // utility methods

  /** confirms that you will be able to perform the release before attempting */
  function validate () {
    if (exec('npm whoami') !== 'angular') {
      err('You must be authenticated with npm as "angular" to perform a release.');
    } else if (exec('git rev-parse --abbrev-ref HEAD') !== 'staging') {
      err('Releases can only performed from "staging" at this time.');
    } else {
      return true;
    }
    function err (msg) {
      const str = 'Error: ' + msg;
      log(str.red);
    }
  }

  /** creates the version branch and adds abort steps */
  function checkoutVersionBranch () {
    exec(`git branch -q -D release/${newVersion}`);
    exec(`git checkout -q -b release/${newVersion}`);
    abortCmds.push('git checkout master');
    abortCmds.push(`git branch -D release/${newVersion}`);
  }

  /** writes the new version to package.json */
  function updateVersion () {
    start(`Updating ${"package.json".cyan} version from ${oldVersion.cyan} to ${newVersion.cyan}...`);
    pkg.version = newVersion;
    fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2));
    done();
    abortCmds.push('git checkout package.json');
    pushCmds.push('git add package.json');
  }

  /** generates the changelog from the commits since the last release */
  function createChangelog () {
    start(`Generating changelog from ${oldVersion.cyan} to ${newVersion.cyan}...`);

    exec(`git fetch --tags ${origin}`);
    exec(`git checkout CHANGELOG.md`);
    exec(`gulp changelog --sha=$(git merge-base v${lastMajorVer} HEAD)`);

    done();

    abortCmds.push('git checkout CHANGELOG.md');
    pushCmds.push('git add CHANGELOG.md');
  }

  /** utility method for clearing the terminal */
  function clear () {
    write("\u001b[2J\u001b[0;0H");
  }

  /** prompts the user for the new version */
  function getNewVersion () {
    header();
    const options = getVersionOptions(oldVersion);
    let key, version;
    log(`The current version is ${oldVersion.cyan}.`);
    log('');
    log('What should the next version be?');
    for (key in options) { log((+key + 1) + ') ' + options[ key ].cyan); }
    log('');
    const type = prompt('Please select a new version: ');

    if (options[ type - 1 ]) version = options[ type - 1 ];
    else if (type.match(/^\d+\.\d+\.\d+(-rc\.?\d+)?$/)) version = type;
    else throw new Error('Your entry was invalid.');

    log('');
    log('The new version will be ' + version.cyan + '.');
    return prompt(`Is this correct? [${"yes".cyan}/no] `, 'yes') === 'yes' ? version : getNewVersion();

    function getVersionOptions (version) {
      return version.match(/-rc\.?\d+$/)
        ? [increment(version, 'rc'), increment(version, 'minor')]
        : [increment(version, 'patch'), addRC(increment(version, 'minor'))];

      function increment (versionString, type) {
        const version = parseVersion(versionString);
        if (version.rc) {
          switch (type) {
            case 'minor': version.rc = 0; break;
            case 'rc': version.rc++; break;
          }
        } else {
          version[ type ]++;
          // reset any version numbers lower than the one changed
          switch (type) {
            case 'minor': version.patch = 0;
            case 'patch': version.rc = 0;
          }
        }
        return getVersionString(version);

        function parseVersion (version) {
          const parts = version.split(/-rc\.|\./g);
          return {
            string: version,
            major:  parts[ 0 ],
            minor:  parts[ 1 ],
            patch:  parts[ 2 ],
            rc:     parts[ 3 ] || 0
          };
        }

        function getVersionString (version) {
          let str = version.major + '.' + version.minor + '.' + version.patch;
          if (version.rc) str += '-rc.' + version.rc;
          return str;
        }
      }

      function addRC (str) {
        return str + '-rc.1';
      }
    }
  }

  /** adds git tag for release and pushes to github */
  function tagRelease () {
    pushCmds.push(
      `git tag v${newVersion} -f`,
      `git push ${origin} HEAD`,
      `git push --tags ${origin}`
    );
  }

  /** amends the commit to include local changes (ie. changelog) */
  function commitChanges () {
    start('Committing changes...');
    exec(`git commit -am "release: version ${newVersion}"`);
    done();
    pushCmds.push('git commit --amend --no-edit');
  }

  /** utility method for cloning github repos */
  function cloneRepo (repo) {
    start(`Cloning ${repo.cyan} from Github...`);
    exec(`rm -rf ${repo}`);
    exec(`git clone git@github.com:angular/${repo}.git --depth=1`);
    done();
    cleanupCmds.push(`rm -rf ${repo}`);
  }

  /** writes an array of commands to a bash script */
  function writeScript (name, cmds) {
    fs.writeFileSync(name, '#!/usr/bin/env bash\n\n' + cmds.join('\n'));
    exec('chmod +x ' + name);
  }

  /** updates the version for bower-material in package.json and bower.json */
  function updateBowerVersion () {
    start('Updating bower version...');
    const options = { cwd: './bower-material' };
    const bower   = require(options.cwd + '/bower.json'),
          pkg     = require(options.cwd + '/package.json');
    // update versions in config files
    bower.version = pkg.version = newVersion;
    fs.writeFileSync(options.cwd + '/package.json', JSON.stringify(pkg, null, 2));
    fs.writeFileSync(options.cwd + '/bower.json', JSON.stringify(bower, null, 2));
    done();
    start('Building bower files...');
    // build files for bower
    exec([
      'rm -rf dist',
      'gulp build',
      'gulp build-all-modules --mode=default',
      'gulp build-all-modules --mode=closure',
      'rm -rf dist/demos'
    ]);
    done();
    start('Copy files into bower repo...');
    // copy files over to bower repo
    exec([
      'cp -Rf ../dist/* ./',
      'git add -A',
      `git commit -m "release: version ${newVersion}"`,
      'rm -rf ../dist'
    ], options);
    done();
    // add steps to push script
    pushCmds.push(
      comment('push to bower (master and tag) and publish to npm'),
      'cd ' + options.cwd,
      'cp ../CHANGELOG.md .',
      'git add CHANGELOG.md',
      'git commit --amend --no-edit',
      `git tag -f v${newVersion}`,
      'git pull --rebase --strategy=ours',
      'git push',
      'git push --tags',
      'rm -rf .git/',
      'npm publish',
      'cd ..'
    );
  }

  /** builds the website for the new version */
  function updateSite () {
    start('Adding new version of the docs site...');
    const options = { cwd: './code.material.angularjs.org' };
    writeDocsJson();

    // build files for bower
    exec([
      'rm -rf dist',
      'gulp docs'
    ]);
    replaceFilePaths();

    // copy files over to site repo
    exec([
      `cp -Rf ../dist/docs ${newVersion}`,
      'rm -rf latest && cp -Rf ../dist/docs latest',
      'git add -A',
      `git commit -m "release: version ${newVersion}"`,
      'rm -rf ../dist'
    ], options);
    replaceBaseHref(newVersion);
    replaceBaseHref('latest');

    // update firebase.json file
    updateFirebaseJson();
    exec(['git commit --amend --no-edit -a'], options);
    done();

    // add steps to push script
    pushCmds.push(
      comment('push the site'),
      'cd ' + options.cwd,
      'git pull --rebase --strategy=ours',
      'git push',
      'cd ..'
    );

    function updateFirebaseJson () {
      fs.writeFileSync(options.cwd + '/firebase.json', getFirebaseJson());
      function getFirebaseJson () {
        const json = require(options.cwd + '/firebase.json');
        json.hosting.rewrites = json.hosting.rewrites || [];
        const rewrites = json.hosting.rewrites;

        switch (rewrites.length) {
          case 0:
            rewrites.push(getRewrite('HEAD'));
          case 1:
            rewrites.push(getRewrite('latest'));
          default:
            rewrites.push(getRewrite(newVersion));
        }
        return JSON.stringify(json, null, 2);
        function getRewrite (str) {
          return {
            source:      '/' + str + '/**/!(*.@(js|html|css|json|svg|png|jpg|jpeg))',
            destination: '/' + str + '/index.html'
          };
        }
      }
    }

    function writeDocsJson () {
      const config = require(options.cwd + '/docs.json');
      config.versions.unshift(newVersion);

      // only set to default if not a release candidate
      config.latest = newVersion;
      fs.writeFileSync(options.cwd + '/docs.json', JSON.stringify(config, null, 2));
    }
  }

  /** replaces localhost file paths with public URLs */
  function replaceFilePaths () {
    // handle docs.js
    const filePath = path.join(__dirname, '/dist/docs/docs.js');
    const file = fs.readFileSync(filePath);
    const contents = file.toString()
        .replace(/http:\/\/localhost:8080\/angular-material/g, 'https://gitcdn.xyz/cdn/angular/bower-material/v' + newVersion + '/angular-material')
        .replace(/http:\/\/localhost:8080\/docs.css/g, 'https://material.angularjs.org/' + newVersion + '/docs.css');
    fs.writeFileSync(filePath, contents);
  }

  /** replaces base href in index.html for new version as well as latest */
  function replaceBaseHref (folder) {
    // handle index.html
    const filePath = path.join(__dirname, '/code.material.angularjs.org/', folder, '/index.html');
    const file = fs.readFileSync(filePath);
    const contents = file.toString().replace(/base href="\//g, 'base href="/' + folder + '/');
    fs.writeFileSync(filePath, contents);
  }

  /** copies the changelog back over to master branch */
  function updateMaster () {
    pushCmds.push(
      comment('update package.json in master'),
      'git checkout master',
      `git pull --rebase ${origin} master --strategy=theirs`,
      `git checkout release/${newVersion} -- CHANGELOG.md`,
      `node -e "const newVersion = '${newVersion}'; ${stringifyFunction(buildCommand)}"`,
      'git add CHANGELOG.md',
      'git add package.json',
      `git commit -m "update version number in package.json to ${newVersion}"`,
      `git push ${origin} master`
    );

    function buildCommand () {
      require('fs').writeFileSync('package.json', JSON.stringify(getUpdatedJson(), null, 2));
      function getUpdatedJson () {
        const json = require('./package.json');
        json.version = newVersion;
        return json;
      }
    }

    function stringifyFunction (method) {
      return method
          .toString()
          .split('\n')
          .slice(1, -1)
          .map(function (line) { return line.trim(); })
          .join(' ')
          .replace(/"/g, '\\"');
    }
  }

  /** utility method to output header */
  function header () {
    clear();
    line();
    log(center('AngularJS Material Release'));
    line();
  }

  /** outputs a centered message in the terminal */
  function center (msg) {
    msg        = ' ' + msg.trim() + ' ';
    const length = msg.length;
    const spaces = Math.floor((lineWidth - length) / 2);
    return Array(spaces + 1).join('-') + msg.green + Array(lineWidth - msg.length - spaces + 1).join('-');
  }

  /** outputs done text when a task is completed */
  function done () {
    log('done'.green);
  }

  /**
   * utility method for executing terminal commands while ignoring stderr
   * @param {string|Array} cmd
   * @param {Object=} userOptions
   * @return
   */
  function exec (cmd, userOptions) {
    if (cmd instanceof Array) {
      return cmd.map(function (cmd) { return exec(cmd, userOptions); });
    }
    try {
      const options = Object.create(defaultOptions);
      for (const key in userOptions) options[ key ] = userOptions[ key ];
      return child_process.execSync(cmd + ' 2> /dev/null', options).toString().trim();
    } catch (err) {
      return err;
    }
  }

  /** returns a commented message for use in bash scripts */
  function comment (msg) {
    return '\n# ' + msg + '\n';
  }

  /**
   * prints the left side of a task while it is being performed
   */
  function start (msg) {
    const msgLength = strip(msg).length,
          diff      = lineWidth - 4 - msgLength;
    write(msg + Array(diff + 1).join(' '));
  }

  /** outputs to the terminal with string variable replacement */
  function log (msg) {
    msg = msg || '';
    console.log(msg);
  }

  /** writes a message without a newline */
  function write (msg) {
    process.stdout.write(msg);
  }

  /** prints a horizontal line to the terminal */
  function line () {
    log(Array(lineWidth + 1).join('-'));
  }
})();
<commit_msg>chore(release): support publishing to NPM with tags other than latest<commit_after>/* eslint-disable no-fallthrough */
(function () {
  'use strict';

  const colors         = require('colors');
  const strip          = require('cli-color/strip');
  const fs             = require('fs');
  const path           = require('path');
  const prompt         = require('prompt-sync')({sigint: true});
  const child_process  = require('child_process');
  const pkg            = require('./package.json');
  let oldVersion       = pkg.version;
  const abortCmds      = ['git reset --hard', 'git checkout staging', 'rm abort push'];
  const pushCmds       = ['rm abort push'];
  const cleanupCmds    = [];
  const defaultOptions = { encoding: 'utf-8' };
  const origin         = 'git@github.com:angular/material.git';
  const lineWidth      = 80;
  const lastMajorVer   = JSON.parse(exec('curl https://material.angularjs.org/docs.json')).latest;
  let newVersion;
  let npmTag = 'latest';

  try {
    child_process.execSync('gulp --version', defaultOptions);
  } catch (error) {
    throw new Error('Please install gulp globally via "npm i -g gulp@^3.9.1".');
  }
  header();
  const dryRun = prompt(`Is this a dry-run? [${"yes".cyan}/no] `, 'yes') !== 'no';
  npmTag = prompt(`What would you like the NPM tag to be? [${npmTag.cyan}/next] `, npmTag);

  if (dryRun) {
    oldVersion = prompt(`What would you like the old version to be? (default: ${oldVersion.cyan}) `, oldVersion);
    build();
  } else if (validate()) {
    build();
  }

  function build () {
    newVersion = getNewVersion();

    line();

    checkoutVersionBranch();
    updateVersion();
    createChangelog();
    commitChanges();
    tagRelease();
    cloneRepo('bower-material');
    updateBowerVersion();
    cloneRepo('code.material.angularjs.org');
    updateSite();
    updateMaster();
    writeScript('abort', abortCmds.concat(cleanupCmds));
    if (!dryRun) writeScript('push', pushCmds.concat(cleanupCmds));

    line();
    log('Your repo is ready to be pushed.');
    log(`Please look over ${"CHANGELOG.md".cyan} and make any changes.`);
    log(`When you are ready, please run "${"./push".cyan}" to finish the process.`);
    log('If you would like to cancel this release, please run "./abort"');
  }

  // utility methods

  /** confirms that you will be able to perform the release before attempting */
  function validate () {
    if (exec('npm whoami') !== 'angular') {
      err('You must be authenticated with npm as "angular" to perform a release.');
    } else if (exec('git rev-parse --abbrev-ref HEAD') !== 'staging') {
      err('Releases can only performed from "staging" at this time.');
    } else {
      return true;
    }
    function err (msg) {
      const str = 'Error: ' + msg;
      log(str.red);
    }
  }

  /** creates the version branch and adds abort steps */
  function checkoutVersionBranch () {
    exec(`git branch -q -D release/${newVersion}`);
    exec(`git checkout -q -b release/${newVersion}`);
    abortCmds.push('git checkout master');
    abortCmds.push(`git branch -D release/${newVersion}`);
  }

  /** writes the new version to package.json */
  function updateVersion () {
    start(`Updating ${"package.json".cyan} version from ${oldVersion.cyan} to ${newVersion.cyan}...`);
    pkg.version = newVersion;
    fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2));
    done();
    abortCmds.push('git checkout package.json');
    pushCmds.push('git add package.json');
  }

  /** generates the changelog from the commits since the last release */
  function createChangelog () {
    start(`Generating changelog from ${oldVersion.cyan} to ${newVersion.cyan}...`);

    exec(`git fetch --tags ${origin}`);
    exec(`git checkout CHANGELOG.md`);
    exec(`gulp changelog --sha=$(git merge-base v${lastMajorVer} HEAD)`);

    done();

    abortCmds.push('git checkout CHANGELOG.md');
    pushCmds.push('git add CHANGELOG.md');
  }

  /** utility method for clearing the terminal */
  function clear () {
    write("\u001b[2J\u001b[0;0H");
  }

  /** prompts the user for the new version */
  function getNewVersion () {
    header();
    const options = getVersionOptions(oldVersion);
    let key, version;
    log(`The current version is ${oldVersion.cyan}.`);
    log('');
    log('What should the next version be?');
    for (key in options) { log((+key + 1) + ') ' + options[ key ].cyan); }
    log('');
    const type = prompt('Please select a new version: ');

    if (options[ type - 1 ]) version = options[ type - 1 ];
    else if (type.match(/^\d+\.\d+\.\d+(-rc\.?\d+)?$/)) version = type;
    else throw new Error('Your entry was invalid.');

    log('');
    log('The new version will be ' + version.cyan + '.');
    return prompt(`Is this correct? [${"yes".cyan}/no] `, 'yes') === 'yes' ? version : getNewVersion();

    function getVersionOptions (version) {
      return version.match(/-rc\.?\d+$/)
        ? [increment(version, 'rc'), increment(version, 'minor')]
        : [increment(version, 'patch'), addRC(increment(version, 'minor'))];

      function increment (versionString, type) {
        const version = parseVersion(versionString);
        if (version.rc) {
          switch (type) {
            case 'minor': version.rc = 0; break;
            case 'rc': version.rc++; break;
          }
        } else {
          version[ type ]++;
          // reset any version numbers lower than the one changed
          switch (type) {
            case 'minor': version.patch = 0;
            case 'patch': version.rc = 0;
          }
        }
        return getVersionString(version);

        function parseVersion (version) {
          const parts = version.split(/-rc\.|\./g);
          return {
            string: version,
            major:  parts[ 0 ],
            minor:  parts[ 1 ],
            patch:  parts[ 2 ],
            rc:     parts[ 3 ] || 0
          };
        }

        function getVersionString (version) {
          let str = version.major + '.' + version.minor + '.' + version.patch;
          if (version.rc) str += '-rc.' + version.rc;
          return str;
        }
      }

      function addRC (str) {
        return str + '-rc.1';
      }
    }
  }

  /** adds git tag for release and pushes to github */
  function tagRelease () {
    pushCmds.push(
      `git tag v${newVersion} -f`,
      `git push ${origin} HEAD`,
      `git push --tags ${origin}`
    );
  }

  /** amends the commit to include local changes (ie. changelog) */
  function commitChanges () {
    start('Committing changes...');
    exec(`git commit -am "release: version ${newVersion}"`);
    done();
    pushCmds.push('git commit --amend --no-edit');
  }

  /** utility method for cloning github repos */
  function cloneRepo (repo) {
    start(`Cloning ${repo.cyan} from Github...`);
    exec(`rm -rf ${repo}`);
    exec(`git clone git@github.com:angular/${repo}.git --depth=1`);
    done();
    cleanupCmds.push(`rm -rf ${repo}`);
  }

  /** writes an array of commands to a bash script */
  function writeScript (name, cmds) {
    fs.writeFileSync(name, '#!/usr/bin/env bash\n\n' + cmds.join('\n'));
    exec('chmod +x ' + name);
  }

  /** updates the version for bower-material in package.json and bower.json */
  function updateBowerVersion () {
    start('Updating bower version...');
    const options = { cwd: './bower-material' };
    const bower   = require(options.cwd + '/bower.json'),
          pkg     = require(options.cwd + '/package.json');
    // update versions in config files
    bower.version = pkg.version = newVersion;
    fs.writeFileSync(options.cwd + '/package.json', JSON.stringify(pkg, null, 2));
    fs.writeFileSync(options.cwd + '/bower.json', JSON.stringify(bower, null, 2));
    done();
    start('Building bower files...');
    // build files for bower
    exec([
      'rm -rf dist',
      'gulp build',
      'gulp build-all-modules --mode=default',
      'gulp build-all-modules --mode=closure',
      'rm -rf dist/demos'
    ]);
    done();
    start('Copy files into bower repo...');
    // copy files over to bower repo
    exec([
      'cp -Rf ../dist/* ./',
      'git add -A',
      `git commit -m "release: version ${newVersion}"`,
      'rm -rf ../dist'
    ], options);
    done();
    // add steps to push script
    pushCmds.push(
      comment(`push to bower (master and tag) and publish to npm as '${npmTag}'`),
      'cd ' + options.cwd,
      'cp ../CHANGELOG.md .',
      'git add CHANGELOG.md',
      'git commit --amend --no-edit',
      `git tag -f v${newVersion}`,
      'git pull --rebase --strategy=ours',
      'git push',
      'git push --tags',
      'rm -rf .git/',
      `npm publish --tag ${npmTag}`,
      'cd ..'
    );
  }

  /** builds the website for the new version */
  function updateSite () {
    start('Adding new version of the docs site...');
    const options = { cwd: './code.material.angularjs.org' };
    writeDocsJson();

    // build files for bower
    exec([
      'rm -rf dist',
      'gulp docs'
    ]);
    replaceFilePaths();

    // copy files over to site repo
    exec([
      `cp -Rf ../dist/docs ${newVersion}`,
      'rm -rf latest && cp -Rf ../dist/docs latest',
      'git add -A',
      `git commit -m "release: version ${newVersion}"`,
      'rm -rf ../dist'
    ], options);
    replaceBaseHref(newVersion);
    replaceBaseHref('latest');

    // update firebase.json file
    updateFirebaseJson();
    exec(['git commit --amend --no-edit -a'], options);
    done();

    // add steps to push script
    pushCmds.push(
      comment('push the site'),
      'cd ' + options.cwd,
      'git pull --rebase --strategy=ours',
      'git push',
      'cd ..'
    );

    function updateFirebaseJson () {
      fs.writeFileSync(options.cwd + '/firebase.json', getFirebaseJson());
      function getFirebaseJson () {
        const json = require(options.cwd + '/firebase.json');
        json.hosting.rewrites = json.hosting.rewrites || [];
        const rewrites = json.hosting.rewrites;

        switch (rewrites.length) {
          case 0:
            rewrites.push(getRewrite('HEAD'));
          case 1:
            rewrites.push(getRewrite('latest'));
          default:
            rewrites.push(getRewrite(newVersion));
        }
        return JSON.stringify(json, null, 2);
        function getRewrite (str) {
          return {
            source:      '/' + str + '/**/!(*.@(js|html|css|json|svg|png|jpg|jpeg))',
            destination: '/' + str + '/index.html'
          };
        }
      }
    }

    function writeDocsJson () {
      const config = require(options.cwd + '/docs.json');
      config.versions.unshift(newVersion);

      // only set to default if not a release candidate
      config.latest = newVersion;
      fs.writeFileSync(options.cwd + '/docs.json', JSON.stringify(config, null, 2));
    }
  }

  /** replaces localhost file paths with public URLs */
  function replaceFilePaths () {
    // handle docs.js
    const filePath = path.join(__dirname, '/dist/docs/docs.js');
    const file = fs.readFileSync(filePath);
    const contents = file.toString()
        .replace(/http:\/\/localhost:8080\/angular-material/g, 'https://gitcdn.xyz/cdn/angular/bower-material/v' + newVersion + '/angular-material')
        .replace(/http:\/\/localhost:8080\/docs.css/g, 'https://material.angularjs.org/' + newVersion + '/docs.css');
    fs.writeFileSync(filePath, contents);
  }

  /** replaces base href in index.html for new version as well as latest */
  function replaceBaseHref (folder) {
    // handle index.html
    const filePath = path.join(__dirname, '/code.material.angularjs.org/', folder, '/index.html');
    const file = fs.readFileSync(filePath);
    const contents = file.toString().replace(/base href="\//g, 'base href="/' + folder + '/');
    fs.writeFileSync(filePath, contents);
  }

  /** copies the changelog back over to master branch */
  function updateMaster () {
    pushCmds.push(
      comment('update package.json in master'),
      'git checkout master',
      `git pull --rebase ${origin} master --strategy=theirs`,
      `git checkout release/${newVersion} -- CHANGELOG.md`,
      `node -e "const newVersion = '${newVersion}'; ${stringifyFunction(buildCommand)}"`,
      'git add CHANGELOG.md',
      'git add package.json',
      `git commit -m "update version number in package.json to ${newVersion}"`,
      `git push ${origin} master`
    );

    function buildCommand () {
      require('fs').writeFileSync('package.json', JSON.stringify(getUpdatedJson(), null, 2));
      function getUpdatedJson () {
        const json = require('./package.json');
        json.version = newVersion;
        return json;
      }
    }

    function stringifyFunction (method) {
      return method
          .toString()
          .split('\n')
          .slice(1, -1)
          .map(function (line) { return line.trim(); })
          .join(' ')
          .replace(/"/g, '\\"');
    }
  }

  /** utility method to output header */
  function header () {
    clear();
    line();
    log(center('AngularJS Material Release'));
    line();
  }

  /** outputs a centered message in the terminal */
  function center (msg) {
    msg        = ' ' + msg.trim() + ' ';
    const length = msg.length;
    const spaces = Math.floor((lineWidth - length) / 2);
    return Array(spaces + 1).join('-') + msg.green + Array(lineWidth - msg.length - spaces + 1).join('-');
  }

  /** outputs done text when a task is completed */
  function done () {
    log('done'.green);
  }

  /**
   * utility method for executing terminal commands while ignoring stderr
   * @param {string|Array} cmd
   * @param {Object=} userOptions
   * @return
   */
  function exec (cmd, userOptions) {
    if (cmd instanceof Array) {
      return cmd.map(function (cmd) { return exec(cmd, userOptions); });
    }
    try {
      const options = Object.create(defaultOptions);
      for (const key in userOptions) options[ key ] = userOptions[ key ];
      return child_process.execSync(cmd + ' 2> /dev/null', options).toString().trim();
    } catch (err) {
      return err;
    }
  }

  /** returns a commented message for use in bash scripts */
  function comment (msg) {
    return '\n# ' + msg + '\n';
  }

  /**
   * prints the left side of a task while it is being performed
   */
  function start (msg) {
    const msgLength = strip(msg).length,
          diff      = lineWidth - 4 - msgLength;
    write(msg + Array(diff + 1).join(' '));
  }

  /** outputs to the terminal with string variable replacement */
  function log (msg) {
    msg = msg || '';
    console.log(msg);
  }

  /** writes a message without a newline */
  function write (msg) {
    process.stdout.write(msg);
  }

  /** prints a horizontal line to the terminal */
  function line () {
    log(Array(lineWidth + 1).join('-'));
  }
})();
<|endoftext|>


<commit_before>module.exports = (markdown, metaData) => {
    console.log(markdown)
    return markdown
}<commit_msg>Trying to fix Cucumber in dependent swipe-up lib which don't like imports in browser-ui-state (patch)<commit_after>module.exports = (markdown, metaData) => {
    console.log(markdown);
    return markdown
}<|endoftext|>


<commit_before>var http = require('http'),
    querystring = require('querystring'),
    request = require('request'),
    helpers = require('./helpers');

/**
 * MailChimp Export API wrapper for the API version 1.0. This object should not
 * be instantiated directly but by using the version wrapper
 * {@link MailChimpExportAPI}.
 *
 * @param apiKey The API key to access the MailChimp Export API with
 * @param options Configuration options
 * @return Instance of {@link MailChimpExportAPI_v1_0}
 */
function MailChimpExportAPI_v1_0 (apiKey, options) {

	if (!options)
		var options = {};

	this.version     = '1.0';
	this.apiKey      = apiKey;
	this.secure      = options.secure || false;
	this.packageInfo = options.packageInfo;
	this.datacenter  = apiKey.split('-');
	this.datacenter  = this.datacenter[1];
	this.httpHost    = this.datacenter+'.api.mailchimp.com';
	this.httpUri     = (this.secure) ? 'https://'+this.httpHost+':443' : 'http://'+this.httpHost+':80';
	this.userAgent   = options.userAgent+' ' || '';

}

module.exports = MailChimpExportAPI_v1_0;

/**
 * Sends a given request as a JSON object to the MailChimp Export API and
 * finally calls the given callback function with the resulting JSON object.
 * This method should not be called directly but will be used internally by all
 * API methods defined.
 *
 * @param method MailChimp API method to call
 * @param availableParams Parameters available for the specified API method
 * @param givenParams Parameters to call the MailChimp API with
 * @param callback Callback function to call on success
 */
MailChimpExportAPI_v1_0.prototype.execute = function (method, availableParams, givenParams, callback) {

	var self = this;

	var finalParams = { apikey : this.apiKey };
	var currentParam;

	for (var i = 0; i < availableParams.length; i++) {
		currentParam = availableParams[i];
		if (typeof givenParams[currentParam] !== 'undefined')
			finalParams[currentParam] = givenParams[currentParam];
	}

	var query = querystring.stringify(finalParams);

	request({
		uri : this.httpUri+'/export/'+this.version+'/'+method+'/?'+query,
		headers : { 'User-Agent' : this.userAgent+'node-mailchimp/'+this.packageInfo['version'] }
	}, function (error, response, body) {
		if (error) {
			callback(new Error('Unable to connect to the MailChimp API endpoint.'));
		} else {
 			var processFunction = eval("self."+method+"Process");
			if (typeof processFunction == 'function') {
				processFunction(body, callback);
			} else {
				var parsedResponse;
				try {
					parsedResponse = JSON.parse(body);
				} catch (error) {
					callback(new Error('Error parsing JSON answer from MailChimp API.'));
					return;
				}
				callback(null, parsedResponse);
			}
		}
	});

}

/**
 * Exports/dumps members of a list and all of their associated details. This is
 * very similar to exporting via the web interface.
 *
 * @see http://apidocs.mailchimp.com/export/1.0/list.func.php
 */
MailChimpExportAPI_v1_0.prototype.list = function (params, callback) {
	if (typeof params == 'function') callback = params, params = {};
	this.execute('list', [
        'id',
        'status',
        'segment',
        'since',
	], params, callback);
}

/**
 * Process the response from the list API call and pass it to the callback
 * function.
 */
MailChimpExportAPI_v1_0.prototype.listProcess = function (data, callback) {

	var resultStrings = data.split("\n");
	var resultJSON    = [];

	for (current in resultStrings) {
		if (typeof resultStrings[current] == 'string' && resultStrings[current] !== "")
			resultJSON.push(JSON.parse(resultStrings[current]));
	}

	if (resultJSON[0] && resultJSON[0].error)
		callback(helpers.createMailChimpError(resultJSON[0].error, resultJSON[0].code));
	else
		callback(null, resultJSON);

}

/**
 * Exports/dumps all Subscriber Activity for the requested campaign.
 *
 * @see http://apidocs.mailchimp.com/export/1.0/campaignsubscriberactivity.func.php
 */
MailChimpExportAPI_v1_0.prototype.campaignSubscriberActivity = function (params, callback) {
	if (typeof params == 'function') callback = params, params = {};
	this.execute('campaignSubscriberActivity', [
        'id',
        'include_empty',
	], params, callback);
}

/**
 * Process the response from the campaignSubscriberActivity API call and pass
 * it to the callback function.
 */
MailChimpExportAPI_v1_0.prototype.campaignSubscriberActivityProcess = function (data, callback) {

	var resultStrings = data.split("\n");
	var resultJSON    = [];

	for (current in resultStrings) {
		if (typeof resultStrings[current] == 'string' && resultStrings[current] !== "")
			resultJSON.push(JSON.parse(resultStrings[current]));
	}

	if (resultJSON[0] && resultJSON[0].error)
		callback(helpers.createMailChimpError(resultJSON[0].error, resultJSON[0].code));
	else
		callback(null, resultJSON);

}<commit_msg>Fix for export api request for campaign subscriber activity and no activity returned.   In this case 'data.split' will fail as data is undefined.<commit_after>var http = require('http'),
    querystring = require('querystring'),
    request = require('request'),
    helpers = require('./helpers');

/**
 * MailChimp Export API wrapper for the API version 1.0. This object should not
 * be instantiated directly but by using the version wrapper
 * {@link MailChimpExportAPI}.
 *
 * @param apiKey The API key to access the MailChimp Export API with
 * @param options Configuration options
 * @return Instance of {@link MailChimpExportAPI_v1_0}
 */
function MailChimpExportAPI_v1_0 (apiKey, options) {

	if (!options)
		var options = {};

	this.version     = '1.0';
	this.apiKey      = apiKey;
	this.secure      = options.secure || false;
	this.packageInfo = options.packageInfo;
	this.datacenter  = apiKey.split('-');
	this.datacenter  = this.datacenter[1];
	this.httpHost    = this.datacenter+'.api.mailchimp.com';
	this.httpUri     = (this.secure) ? 'https://'+this.httpHost+':443' : 'http://'+this.httpHost+':80';
	this.userAgent   = options.userAgent+' ' || '';

}

module.exports = MailChimpExportAPI_v1_0;

/**
 * Sends a given request as a JSON object to the MailChimp Export API and
 * finally calls the given callback function with the resulting JSON object.
 * This method should not be called directly but will be used internally by all
 * API methods defined.
 *
 * @param method MailChimp API method to call
 * @param availableParams Parameters available for the specified API method
 * @param givenParams Parameters to call the MailChimp API with
 * @param callback Callback function to call on success
 */
MailChimpExportAPI_v1_0.prototype.execute = function (method, availableParams, givenParams, callback) {

	var self = this;

	var finalParams = { apikey : this.apiKey };
	var currentParam;

	for (var i = 0; i < availableParams.length; i++) {
		currentParam = availableParams[i];
		if (typeof givenParams[currentParam] !== 'undefined')
			finalParams[currentParam] = givenParams[currentParam];
	}

	var query = querystring.stringify(finalParams);

	request({
		uri : this.httpUri+'/export/'+this.version+'/'+method+'/?'+query,
		headers : { 'User-Agent' : this.userAgent+'node-mailchimp/'+this.packageInfo['version'] }
	}, function (error, response, body) {
		if (error) {
			callback(new Error('Unable to connect to the MailChimp API endpoint.'));
		} else {
 			var processFunction = eval("self."+method+"Process");
			if (typeof processFunction == 'function') {
				processFunction(body, callback);
			} else {
				var parsedResponse;
				try {
					parsedResponse = JSON.parse(body);
				} catch (error) {
					callback(new Error('Error parsing JSON answer from MailChimp API.'));
					return;
				}
				callback(null, parsedResponse);
			}
		}
	});

}

/**
 * Exports/dumps members of a list and all of their associated details. This is
 * very similar to exporting via the web interface.
 *
 * @see http://apidocs.mailchimp.com/export/1.0/list.func.php
 */
MailChimpExportAPI_v1_0.prototype.list = function (params, callback) {
	if (typeof params == 'function') callback = params, params = {};
	this.execute('list', [
        'id',
        'status',
        'segment',
        'since',
	], params, callback);
}

/**
 * Process the response from the list API call and pass it to the callback
 * function.
 */
MailChimpExportAPI_v1_0.prototype.listProcess = function (data, callback) {

	var resultStrings = data.split("\n");
	var resultJSON    = [];

	for (current in resultStrings) {
		if (typeof resultStrings[current] == 'string' && resultStrings[current] !== "")
			resultJSON.push(JSON.parse(resultStrings[current]));
	}

	if (resultJSON[0] && resultJSON[0].error)
		callback(helpers.createMailChimpError(resultJSON[0].error, resultJSON[0].code));
	else
		callback(null, resultJSON);

}

/**
 * Exports/dumps all Subscriber Activity for the requested campaign.
 *
 * @see http://apidocs.mailchimp.com/export/1.0/campaignsubscriberactivity.func.php
 */
MailChimpExportAPI_v1_0.prototype.campaignSubscriberActivity = function (params, callback) {
	if (typeof params == 'function') callback = params, params = {};
	this.execute('campaignSubscriberActivity', [
        'id',
        'include_empty',
	], params, callback);
}

/**
 * Process the response from the campaignSubscriberActivity API call and pass
 * it to the callback function.
 */
MailChimpExportAPI_v1_0.prototype.campaignSubscriberActivityProcess = function (data, callback) {

  // when api returns empty set data variable is undefined
  if(typeof data === 'undefined'){
    callback(null, []);
    return;
  }

	var resultStrings = data.split("\n");
	var resultJSON    = [];

	for (current in resultStrings) {
		if (typeof resultStrings[current] == 'string' && resultStrings[current] !== "")
			resultJSON.push(JSON.parse(resultStrings[current]));
	}

	if (resultJSON[0] && resultJSON[0].error)
		callback(helpers.createMailChimpError(resultJSON[0].error, resultJSON[0].code));
	else
		callback(null, resultJSON);

}<|endoftext|>


<commit_before>module.exports = {
    "name": "American Registry for Internet Numbers",
    "acronym":"ARIN",
    "logging": { level: 'debug'},
    "entityTypes": ['IPv4', 'IPv6'],
    //Custom CIDR Check; Should Match MM Check / Verify
	"customTypes":[
        {
            key: 'IPv4CIDR',
            regex: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/
        }
    ],
    "description": "ARIN Integration",
    "styles":[
        "./styles/arin.less"
    ],
    "block": {
        "component": {
            "file": "./component/arin.js"
        },
        "template": {
            "file": "./template/arin.hbs"
        }
    },
    "options":[
        {
            "key": "lookupIPv6",
            "name": "Lookup IPv6 Addresses",
            "description": "If checked, the integration will IPv6 addresses in addition to IPv4.",
            "default": true,
            "type": "boolean",
            "userCanEdit": true,
            "adminOnly": false
        },
        {
            "key"         : "blacklist",
            "name"        : "Blacklist IPs",
            "description" : "List of IPs that you never want sent to ARIN.",
            "default"     : "",
            "type"        : "text",
            "userCanEdit" : false,
            "adminOnly"    : false
        }

    ]
};<commit_msg>Change default logging to info<commit_after>module.exports = {
    "name": "American Registry for Internet Numbers",
    "acronym":"ARIN",
    "logging": { level: 'info'},
    "entityTypes": ['IPv4', 'IPv6'],
    //Custom CIDR Check; Should Match MM Check / Verify
	"customTypes":[
        {
            key: 'IPv4CIDR',
            regex: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/
        }
    ],
    "description": "ARIN Integration",
    "styles":[
        "./styles/arin.less"
    ],
    "block": {
        "component": {
            "file": "./component/arin.js"
        },
        "template": {
            "file": "./template/arin.hbs"
        }
    },
    "options":[
        {
            "key": "lookupIPv6",
            "name": "Lookup IPv6 Addresses",
            "description": "If checked, the integration will IPv6 addresses in addition to IPv4.",
            "default": true,
            "type": "boolean",
            "userCanEdit": true,
            "adminOnly": false
        },
        {
            "key"         : "blacklist",
            "name"        : "Blacklist IPs",
            "description" : "List of IPs that you never want sent to ARIN.",
            "default"     : "",
            "type"        : "text",
            "userCanEdit" : false,
            "adminOnly"    : false
        }

    ]
};<|endoftext|>


<commit_before>/* Magic Mirror Config Sample
 *
 * By Michael Teeuw http://michaelteeuw.nl
 * MIT Licensed.
 */

var config = {
	address: "0.0.0.0",
	port: 8080,
	ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1", "192.168.2.119", "192.168.2.149", "192.168.2.117"],

	language: 'de',
	timeFormat: 24,
	units: 'metric',

	modules: [
		{
			module: 'alert',
		},
		{
			module: "updatenotification",
			position: "top_bar"
		},
		{
			module: 'clock',
			position: 'top_left',
			config: {
				timezonelocation: 'Berlin',
			}
		},
		{
			module: 'clock',
			position: 'top_left',
			config: {
				timezonelocation: 'Denpasar, Bali',
				timezone: 'Asia/Jakarta',
			}
		},
		{
			module: 'currentweather',
			position: 'top_right',
			config: {
				location: 'Denpasar',
				locationID: '1645528',  //ID from http://www.openweathermap.org
				appid: 'd327541af26bdcda47432fced90c2db2',
				weatherlocation: 'Denpasar, Bali',
                showFeelsLike: false,
			}
		},
		{
			module: 'currentweather',
			position: 'top_right',
			config: {
				location: 'Görlitz',
				locationID: '2918987',  //ID from http://www.openweathermap.org
				appid: 'd327541af26bdcda47432fced90c2db2',
				weatherlocation: 'Görlitz',
                showFeelsLike: false,
			}
		},
		{
			module: 'weatherforecast',
			position: 'top_right',
			header: 'Wettervorhersage',
			config: {
				location: 'Görlitz',
				locationID: '2918987',  //ID from http://www.openweathermap.org
				appid: 'd327541af26bdcda47432fced90c2db2',
			}
		},
		{
			module: 'newsfeed',
			position: 'bottom_bar',
			config: {
				feeds: [
					{
						title: "Focus",
//						title: "tagesschau.de",
						url: "http://rss.focus.de/fol/XML/rss_folnews_eilmeldungen.xml"
//						url: "http://www.tagesschau.de/xml/rss2"
					}
				],
				showSourceTitle: true,
				showPublishDate: true
			}
		},
		{
    				module: 'MMM-DWD-WarnWeather',
   				position: 'top_right',
//				header: 'Wetterwarnungen',
    				config: {
        			region: 'Reichenbach/OL.',
        			changeColor: true,
        			interval: 10 * 60 * 1000, // every 10 minutes
        			loadingText: 'Warnungen werden geladen...',
        			noWarningText: 'Keine Warnungen'
    			}
		},
/*		{
					module: 'MMM-Globe',
					position: 'lower_third',
			config: {
					style: 'europeDiscNat',
					imageSize: 600,
					ownImagePath:'',
					updateInterval: 10*60*1000
				}
		},
*/		{
    			module: 'MMM-Remote-Control'
    		},
		{
  			module: "MMM-Remote-Control-Repository",
		},
/*		{

//			module: 'MMM-Nyan-Cat',
//			position: 'top_center',
//			config: {
//				gif: 'https://media.giphy.com/media/11StaZ9Lj74oCY/giphy.gif',
//				imageSize: 400,
//		}
//		},
/		{
			module: 'MMM-randomGIFs',
			position: 'top_center'
		},

	//	{
	//	module: 'helloworld',
	//	position: 'middle_center',	// This can be any of the regions.
	//	config: {
			// See 'Configuration options' for more information.
	//		text: 'I miss YOU!'
	//	}
//	}
*/	]

};

/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== 'undefined') {module.exports = config;}
<commit_msg>Edit config.js<commit_after>/* Magic Mirror Config Sample
 *
 * By Michael Teeuw http://michaelteeuw.nl
 * MIT Licensed.
 */

var config = {
	address: "0.0.0.0",
	port: 8080,
	ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1", "192.168.2.119", "192.168.2.149", "192.168.2.117"],

	language: 'de',
	timeFormat: 24,
	units: 'metric',

	modules: [
		{
			module: 'alert',
		},
		{
			module: "updatenotification",
			position: "top_bar"
		},
		{
			module: 'clock',
			position: 'top_left',
			config: {
				timezonelocation: 'Berlin',
			}
		},
		{
			module: 'clock',
			position: 'top_left',
			config: {
				timezonelocation: 'Denpasar, Bali',
				timezone: 'Asia/Jakarta',
			}
		},
		{
			module: 'currentweather',
			position: 'top_right',
            header: '',
			config: {
				location: 'Denpasar',
				locationID: '1645528',  //ID from http://www.openweathermap.org
				appid: 'd327541af26bdcda47432fced90c2db2',
				weatherlocation: 'Denpasar, Bali',
                showFeelsLike: false,
			}
		},
		{
			module: 'currentweather',
			position: 'top_right',
            header: '',
			config: {
				location: 'Görlitz',
				locationID: '2918987',  //ID from http://www.openweathermap.org
				appid: 'd327541af26bdcda47432fced90c2db2',
				weatherlocation: 'Görlitz',
                showFeelsLike: false,
			}
		},
		{
			module: 'weatherforecast',
			position: 'top_right',
			header: 'Wettervorhersage',
			config: {
				location: 'Görlitz',
				locationID: '2918987',  //ID from http://www.openweathermap.org
				appid: 'd327541af26bdcda47432fced90c2db2',
			}
		},
		{
			module: 'newsfeed',
			position: 'bottom_bar',
			config: {
				feeds: [
					{
						title: "Focus",
//						title: "tagesschau.de",
						url: "http://rss.focus.de/fol/XML/rss_folnews_eilmeldungen.xml"
//						url: "http://www.tagesschau.de/xml/rss2"
					}
				],
				showSourceTitle: true,
				showPublishDate: true
			}
		},
		{
    				module: 'MMM-DWD-WarnWeather',
   				position: 'top_right',
//				header: 'Wetterwarnungen',
    				config: {
        			region: 'Reichenbach/OL.',
        			changeColor: true,
        			interval: 10 * 60 * 1000, // every 10 minutes
        			loadingText: 'Warnungen werden geladen...',
        			noWarningText: 'Keine Warnungen'
    			}
		},
/*		{
					module: 'MMM-Globe',
					position: 'lower_third',
			config: {
					style: 'europeDiscNat',
					imageSize: 600,
					ownImagePath:'',
					updateInterval: 10*60*1000
				}
		},
*/		{
    			module: 'MMM-Remote-Control'
    		},
		{
  			module: "MMM-Remote-Control-Repository",
		},
/*		{

//			module: 'MMM-Nyan-Cat',
//			position: 'top_center',
//			config: {
//				gif: 'https://media.giphy.com/media/11StaZ9Lj74oCY/giphy.gif',
//				imageSize: 400,
//		}
//		},
/		{
			module: 'MMM-randomGIFs',
			position: 'top_center'
		},

	//	{
	//	module: 'helloworld',
	//	position: 'middle_center',	// This can be any of the regions.
	//	config: {
			// See 'Configuration options' for more information.
	//		text: 'I miss YOU!'
	//	}
//	}
*/	]

};

/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== 'undefined') {module.exports = config;}
<|endoftext|>


<commit_before>(function (d, c) {
    var activeClass = c || "active";
    function clearActive() {
        var actives = d.querySelectorAll("." + activeClass);
        for (var i = 0; i < actives.length; i++) {
            actives[i].classList.remove(activeClass);
        }
    }
    function setActive(e) {
        clearActive();
        if (e.target.tagName == "A") {
            e.target.classList.add(activeClass);
        }
    }
    d.body.addEventListener("touchstart", setActive, false);
    d.body.addEventListener("touchmove", clearActive, false);
})(document, "active");
<commit_msg>temporarily commenting out touchmove<commit_after>(function (d, c) {
    var activeClass = c || "active";
    function clearActive() {
        var actives = d.querySelectorAll("." + activeClass);
        for (var i = 0; i < actives.length; i++) {
            actives[i].classList.remove(activeClass);
        }
    }
    function setActive(e) {
        clearActive();
        if (e.target.tagName == "A") {
            e.target.classList.add(activeClass);
        }
    }
    d.body.addEventListener("touchstart", setActive, false);
    // d.body.addEventListener("touchmove", clearActive, false);
})(document, "active");
<|endoftext|>


<commit_before>'use strict';

var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
var scatterGeoAttrs = require('../scattergeo/attributes');
var scatterAttrs = require('../scatter/attributes');
var mapboxAttrs = require('../../plots/mapbox/layout_attributes');
var baseAttrs = require('../../plots/attributes');
var colorScaleAttrs = require('../../components/colorscale/attributes');

var extendFlat = require('../../lib/extend').extendFlat;
var overrideAll = require('../../plot_api/edit_types').overrideAll;
var mapboxLayoutAtributes = require('../../plots/mapbox/layout_attributes');

var lineAttrs = scatterGeoAttrs.line;
var markerAttrs = scatterGeoAttrs.marker;

module.exports = overrideAll({
    lon: scatterGeoAttrs.lon,
    lat: scatterGeoAttrs.lat,

    cluster: {
        enabled: {
            valType: 'boolean',
            dflt: false,
            description: 'Determines whether clustering is enabled or disabled.'
        },
        maxzoom: extendFlat({}, mapboxLayoutAtributes.layers.maxzoom, {
            description: [
                'Sets the maximum zoom level.',
                'At zoom levels equal to or greater than the maxzoom, the layer will be hidden.'
            ].join(' ')
        }),
        step: {
            valType: 'number',
            arrayOk: true,
            dflt: -1,
            min: -1,
            description: [
                'Sets the steps for each cluster.'
            ].join(' ')
        },
        size: {
            valType: 'number',
            arrayOk: true,
            dflt: 20,
            min: 0,
            description: [
                'Sets the size for each cluster step.'
            ].join(' ')
        },
        color: {
            valType: 'color',
            arrayOk: true,
            description: [
                'Sets the color for each cluster step.'
            ].join(' ')
        },
        opacity: extendFlat({}, markerAttrs.opacity, {
            dflt: 1
        })
    },

    // locations
    // locationmode

    mode: extendFlat({}, scatterAttrs.mode, {
        dflt: 'markers',
        description: [
            'Determines the drawing mode for this scatter trace.',
            'If the provided `mode` includes *text* then the `text` elements',
            'appear at the coordinates. Otherwise, the `text` elements',
            'appear on hover.'
        ].join(' ')
    }),

    text: extendFlat({}, scatterAttrs.text, {
        description: [
            'Sets text elements associated with each (lon,lat) pair',
            'If a single string, the same string appears over',
            'all the data points.',
            'If an array of string, the items are mapped in order to the',
            'this trace\'s (lon,lat) coordinates.',
            'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
            'these elements will be seen in the hover labels.'
        ].join(' ')
    }),
    texttemplate: texttemplateAttrs({editType: 'plot'}, {
        keys: ['lat', 'lon', 'text']
    }),
    hovertext: extendFlat({}, scatterAttrs.hovertext, {
        description: [
            'Sets hover text elements associated with each (lon,lat) pair',
            'If a single string, the same string appears over',
            'all the data points.',
            'If an array of string, the items are mapped in order to the',
            'this trace\'s (lon,lat) coordinates.',
            'To be seen, trace `hoverinfo` must contain a *text* flag.'
        ].join(' ')
    }),

    line: {
        color: lineAttrs.color,
        width: lineAttrs.width

        // TODO
        // dash: dash
    },

    connectgaps: scatterAttrs.connectgaps,

    marker: extendFlat({
        symbol: {
            valType: 'string',
            dflt: 'circle',
            arrayOk: true,
            description: [
                'Sets the marker symbol.',
                'Full list: https://www.mapbox.com/maki-icons/',
                'Note that the array `marker.color` and `marker.size`',
                'are only available for *circle* symbols.'
            ].join(' ')
        },
        angle: {
            valType: 'number',
            dflt: 'auto',
            arrayOk: true,
            description: [
                'Sets the marker orientation from true North, in degrees clockwise.',
                'When using the *auto* default, no rotation would be applied',
                'in perspective views which is different from using a zero angle.'
            ].join(' ')
        },
        allowoverlap: {
            valType: 'boolean',
            dflt: false,
            description: [
                'Flag to draw all symbols, even if they overlap.'
            ].join(' ')
        },
        opacity: markerAttrs.opacity,
        size: markerAttrs.size,
        sizeref: markerAttrs.sizeref,
        sizemin: markerAttrs.sizemin,
        sizemode: markerAttrs.sizemode
    },
        colorScaleAttrs('marker')
        // line
    ),

    fill: scatterGeoAttrs.fill,
    fillcolor: scatterAttrs.fillcolor,

    textfont: mapboxAttrs.layers.symbol.textfont,
    textposition: mapboxAttrs.layers.symbol.textposition,

    below: {
        valType: 'string',
        description: [
            'Determines if this scattermapbox trace\'s layers are to be inserted',
            'before the layer with the specified ID.',
            'By default, scattermapbox layers are inserted',
            'above all the base layers.',
            'To place the scattermapbox layers above every other layer, set `below` to *\'\'*.'
        ].join(' ')
    },

    selected: {
        marker: scatterAttrs.selected.marker
    },
    unselected: {
        marker: scatterAttrs.unselected.marker
    },

    hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
        flags: ['lon', 'lat', 'text', 'name']
    }),
    hovertemplate: hovertemplateAttrs(),
}, 'calc', 'nested');
<commit_msg>Update src/traces/scattermapbox/attributes.js<commit_after>'use strict';

var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs;
var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs;
var scatterGeoAttrs = require('../scattergeo/attributes');
var scatterAttrs = require('../scatter/attributes');
var mapboxAttrs = require('../../plots/mapbox/layout_attributes');
var baseAttrs = require('../../plots/attributes');
var colorScaleAttrs = require('../../components/colorscale/attributes');

var extendFlat = require('../../lib/extend').extendFlat;
var overrideAll = require('../../plot_api/edit_types').overrideAll;
var mapboxLayoutAtributes = require('../../plots/mapbox/layout_attributes');

var lineAttrs = scatterGeoAttrs.line;
var markerAttrs = scatterGeoAttrs.marker;

module.exports = overrideAll({
    lon: scatterGeoAttrs.lon,
    lat: scatterGeoAttrs.lat,

    cluster: {
        enabled: {
            valType: 'boolean',
            dflt: false,
            description: 'Determines whether clustering is enabled or disabled.'
        },
        maxzoom: extendFlat({}, mapboxLayoutAtributes.layers.maxzoom, {
            description: [
                'Sets the maximum zoom level.',
                'At zoom levels equal to or greater than this, points will never be clustered.'
            ].join(' ')
        }),
        step: {
            valType: 'number',
            arrayOk: true,
            dflt: -1,
            min: -1,
            description: [
                'Sets the steps for each cluster.'
            ].join(' ')
        },
        size: {
            valType: 'number',
            arrayOk: true,
            dflt: 20,
            min: 0,
            description: [
                'Sets the size for each cluster step.'
            ].join(' ')
        },
        color: {
            valType: 'color',
            arrayOk: true,
            description: [
                'Sets the color for each cluster step.'
            ].join(' ')
        },
        opacity: extendFlat({}, markerAttrs.opacity, {
            dflt: 1
        })
    },

    // locations
    // locationmode

    mode: extendFlat({}, scatterAttrs.mode, {
        dflt: 'markers',
        description: [
            'Determines the drawing mode for this scatter trace.',
            'If the provided `mode` includes *text* then the `text` elements',
            'appear at the coordinates. Otherwise, the `text` elements',
            'appear on hover.'
        ].join(' ')
    }),

    text: extendFlat({}, scatterAttrs.text, {
        description: [
            'Sets text elements associated with each (lon,lat) pair',
            'If a single string, the same string appears over',
            'all the data points.',
            'If an array of string, the items are mapped in order to the',
            'this trace\'s (lon,lat) coordinates.',
            'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
            'these elements will be seen in the hover labels.'
        ].join(' ')
    }),
    texttemplate: texttemplateAttrs({editType: 'plot'}, {
        keys: ['lat', 'lon', 'text']
    }),
    hovertext: extendFlat({}, scatterAttrs.hovertext, {
        description: [
            'Sets hover text elements associated with each (lon,lat) pair',
            'If a single string, the same string appears over',
            'all the data points.',
            'If an array of string, the items are mapped in order to the',
            'this trace\'s (lon,lat) coordinates.',
            'To be seen, trace `hoverinfo` must contain a *text* flag.'
        ].join(' ')
    }),

    line: {
        color: lineAttrs.color,
        width: lineAttrs.width

        // TODO
        // dash: dash
    },

    connectgaps: scatterAttrs.connectgaps,

    marker: extendFlat({
        symbol: {
            valType: 'string',
            dflt: 'circle',
            arrayOk: true,
            description: [
                'Sets the marker symbol.',
                'Full list: https://www.mapbox.com/maki-icons/',
                'Note that the array `marker.color` and `marker.size`',
                'are only available for *circle* symbols.'
            ].join(' ')
        },
        angle: {
            valType: 'number',
            dflt: 'auto',
            arrayOk: true,
            description: [
                'Sets the marker orientation from true North, in degrees clockwise.',
                'When using the *auto* default, no rotation would be applied',
                'in perspective views which is different from using a zero angle.'
            ].join(' ')
        },
        allowoverlap: {
            valType: 'boolean',
            dflt: false,
            description: [
                'Flag to draw all symbols, even if they overlap.'
            ].join(' ')
        },
        opacity: markerAttrs.opacity,
        size: markerAttrs.size,
        sizeref: markerAttrs.sizeref,
        sizemin: markerAttrs.sizemin,
        sizemode: markerAttrs.sizemode
    },
        colorScaleAttrs('marker')
        // line
    ),

    fill: scatterGeoAttrs.fill,
    fillcolor: scatterAttrs.fillcolor,

    textfont: mapboxAttrs.layers.symbol.textfont,
    textposition: mapboxAttrs.layers.symbol.textposition,

    below: {
        valType: 'string',
        description: [
            'Determines if this scattermapbox trace\'s layers are to be inserted',
            'before the layer with the specified ID.',
            'By default, scattermapbox layers are inserted',
            'above all the base layers.',
            'To place the scattermapbox layers above every other layer, set `below` to *\'\'*.'
        ].join(' ')
    },

    selected: {
        marker: scatterAttrs.selected.marker
    },
    unselected: {
        marker: scatterAttrs.unselected.marker
    },

    hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
        flags: ['lon', 'lat', 'text', 'name']
    }),
    hovertemplate: hovertemplateAttrs(),
}, 'calc', 'nested');
<|endoftext|>


<commit_before>

var ActionBroker = function()
{
  /*
    static constants
      ActionBroker.GLOBAL_HANDLER_ID = "global";

    static methods
      ActionBroker.get_instance
  */

  if (ActionBroker.instance)
    return ActionBroker.instance;

  ActionBroker.instance = this;

  /* interface */

  /**
    * To register an instance of class which implements
    * the ActionHandler interface.
    */
  this.register_handler = function(action_handler){};

  /**
    * To get a copy of the current shortcut map.
    */
  this.get_shortcuts = function(){};

  /**
    * To set a new shortcut map.
    * @param {Object} shortcuts
    * @param {String} handler_id
    * @param {Boolean} clear_setting. To reste to defaults
    */
  this.set_shortcuts = function(shortcuts, handler_id, clear_setting){};

  /**
    * To get a list of action handler ids.
    */
  this.get_handlers = function(){};

  /**
    * To propagate UI inputs, e.g. click or right click menu, as actions.
    */
  this.dispatch_action = function(view_id, action_id, event, target){};

  /**
    * To propagate key input as a shortcut action.
    */
  this.dispatch_key_input = function(key_id, event){};

  /**
    * To delay an action propagation,
    * e.g if a click could be followed by a double click.
    * @param {String} type, the event type
    * @param {String} handler_id
    * @param {String} action_id
    * @param {Event} event
    * @param {Element} target
    */
  this.delay_action = function(type, handler_id, action_id, event, target){};

  /**
    * To cancel delayed actions.
    * e.g. if a dbl click has followed a click.
    * @param {String} type, the event type
    */
  this.clear_delayed_actions = function(type){};

  /**
    * To get a list of all actions of a given action handler.
    * @param {String} handler_id
    */
  this.get_actions_with_handler_id = function(handler_id){};

  /**
    * To the label for a given mode.
    * @param {String} handler_id
    * @param {String} mode
    */
  this.get_label_with_handler_id_and_mode = function(handler_id, mode){};

  /**
    * To the global action handler.
    * Any action, which was not cancelled by the focused action handler,
    * gets passed to the global action handler.
    */
  this.get_global_handler = function(){};

  /**
    * To get a shortcut for a given handler and action.
    * @param {String} handler_id
    * @param {String} action
    */
  this.get_shortcut_with_handler_and_action = function(handler_id, action){};

  /* constants */

  const GLOBAL_HANDLER = ActionBroker.GLOBAL_HANDLER_ID;

  /* private */

  this._handlers = {};
  this._action_context = null;
  this._action_context_id = '';
  this._container = null;
  this._shortcuts = null;
  this._global_shortcuts = null;
  this._current_shortcuts = null;
  this._global_handler = new GlobalActionHandler(GLOBAL_HANDLER);
  this._delays = {};

  this._set_action_context_bound = (function(event)
  {
    if (!(this._action_context && this._action_context.onclick(event) === false))
    {
      var container = event.target;
      while (container && container.nodeType == 1 &&
             container.parentNode.nodeType == 1 &&
             !/^(?:top-)?(?:container|toolbar|tabs)$/i.test(container.nodeName))
        container = container.parentNode;

      switch (container && container.nodeName.toLowerCase() || '')
      {
        case 'container':
        {
          var ui_obj = UIBase.getUIById(container.getAttribute('ui-id'));
          if (ui_obj)
            this._set_current_handler(ui_obj.view_id, event, container);
          break;
        }
        // TODO set according key handler, e.g. toolbar, tab
        default:
        {
          this._set_current_handler(GLOBAL_HANDLER, event, container);
        }
      }
    }
  }).bind(this);

  this._set_current_handler = function(handler_id, event, container)
  {
    if (handler_id != this._action_context_id)
    {
      if (this._action_context)
        this._action_context.blur();
      if (this._container && this._container.hasClass('edit-mode'))
        this._container.removeClass('edit-mode');
      this._action_context = this._handlers[handler_id] || this._global_handler;
      this._action_context_id = this._action_context.id;
      this._current_shortcuts = this._shortcuts[this._action_context_id] || {};
      this._container = container || document.documentElement;
      this._action_context.focus(event, container);
    }
  }

  this._init = function()
  {
    this._key_identifier = new KeyIdentifier(this.dispatch_key_input.bind(this),
                                             window.ini.browser);
    this.register_handler(this._global_handler);
    window.app.addListener('services-created', function()
    {
      this._shortcuts = window.settings.general.get("shortcuts") ||
                        window.helpers.copy_object(window.ini.default_shortcuts);
      this._global_shortcuts = this._shortcuts.global;
      this._key_identifier.set_shortcuts(this._get_shortcut_keys());
      this._set_current_handler(this._global_handler);
      document.addEventListener('click', this._set_action_context_bound, true);
      window.messages.post('shortcuts-changed');
    }.bind(this));
  };

  /* implementation */

  this.register_handler = function(action_handler)
  {
    if (!(action_handler && action_handler.id))
      throw 'missing id on action_handler in ActionBroker.instance.register_handler';
    this._handlers[action_handler.id] = action_handler;
  }

  this.dispatch_action = function(action_handler_id, action_id, event, target)
  {
    this._handlers[action_handler_id].handle(action_id, event, target);
  }

  this.dispatch_key_input = function(key_id, event)
  {
    var shortcuts = this._current_shortcuts[this._action_context.mode];
    var action = shortcuts && shortcuts[key_id] || '';
    var propagate_event = true;
    if (action)
      propagate_event = this._action_context.handle(action,
                                                    event,
                                                    this._container);
    if (!(propagate_event === false) &&
         this._action_context != this._global_handler)
    {
      shortcuts = this._global_shortcuts[this._global_handler.mode];
      action = shortcuts && shortcuts[key_id] || '';
      if (action)
        propagate_event = this._global_handler.handle(action,
                                                      event,
                                                      this._container);
    }
    if (propagate_event === false)
    {
      event.stopPropagation();
      event.preventDefault();
    }
  }

  this.delay_action = function(type, handler_id, action_id, event, target)
  {
    if (!this._delays.hasOwnProperty(type))
    {
      this._delays[type] = new Timeouts();
    }
    var cb = this.dispatch_action.bind(this, handler_id, action_id, event, target);
    this._delays[type].set(cb, 300);
  }

  this.clear_delayed_actions = function(type)
  {
    if (this._delays[type])
      this._delays[type].clear();
  }

  this.get_shortcuts = function()
  {
    return window.helpers.copy_object(this._shortcuts);
  }

  this.set_shortcuts = function(shortcuts, handler_id, clear_setting)
  {
    shortcuts = window.helpers.copy_object(shortcuts);
    if (handler_id)
      this._shortcuts[handler_id] = shortcuts;
    else
      this._shortcuts = shortcuts;
    this._global_shortcuts = this._shortcuts.global;
    window.settings.general.set("shortcuts",
                                clear_setting == true ? null : this._shortcuts);
    this._key_identifier.set_shortcuts(this._get_shortcut_keys());
    window.messages.post('shortcuts-changed');
  };

  this.get_actions_with_handler_id = function(handler_id)
  {
    return (
    this._handlers[handler_id] && this._handlers[handler_id].get_action_list());
  };

  this._get_shortcut_keys = function()
  {
    var ret = [], name = '', handler = null, mode = '', key = '';
    for (name in this._shortcuts)
    {
      handler = this._shortcuts[name];
      for (mode in handler)
      {
        for (key in handler[mode])
        {
          if (ret.indexOf(key) == -1)
            ret.push(key);
        }
      }
    }
    return ret;
  };

  this.get_label_with_handler_id_and_mode = function(handler_id, mode)
  {
    return this._handlers[handler_id].mode_labels[mode];
  };

  this.get_global_handler = function()
  {
    return this._global_handler;
  };

  this.get_shortcut_with_handler_and_action = function(handler_id, action)
  {
    var
    shortcuts = this._shortcuts && this._shortcuts[handler_id],
    shortcuts_mode = null,
    mode = '',
    key = '';

    if (shortcuts)
      for (mode in shortcuts)
      {
        shortcuts_mode = shortcuts[mode];
        for (key in shortcuts_mode)
          if (shortcuts_mode[key] == action)
            return key;
      }
    return '';
  };

  if (document.readyState == "complete")
    this._init();
  else
    document.addEventListener('DOMContentLoaded', this._init.bind(this), false);

}

ActionBroker.get_instance = function()
{
  return this.instance || new ActionBroker();
}

ActionBroker.GLOBAL_HANDLER_ID = "global";
<commit_msg>Fixed bug with focus not being moved to a view in some cases. Fixes DFL-1472<commit_after>

var ActionBroker = function()
{
  /*
    static constants
      ActionBroker.GLOBAL_HANDLER_ID = "global";

    static methods
      ActionBroker.get_instance
  */

  if (ActionBroker.instance)
    return ActionBroker.instance;

  ActionBroker.instance = this;

  /* interface */

  /**
    * To register an instance of class which implements
    * the ActionHandler interface.
    */
  this.register_handler = function(action_handler){};

  /**
    * To get a copy of the current shortcut map.
    */
  this.get_shortcuts = function(){};

  /**
    * To set a new shortcut map.
    * @param {Object} shortcuts
    * @param {String} handler_id
    * @param {Boolean} clear_setting. To reste to defaults
    */
  this.set_shortcuts = function(shortcuts, handler_id, clear_setting){};

  /**
    * To get a list of action handler ids.
    */
  this.get_handlers = function(){};

  /**
    * To propagate UI inputs, e.g. click or right click menu, as actions.
    */
  this.dispatch_action = function(view_id, action_id, event, target){};

  /**
    * To propagate key input as a shortcut action.
    */
  this.dispatch_key_input = function(key_id, event){};

  /**
    * To delay an action propagation,
    * e.g if a click could be followed by a double click.
    * @param {String} type, the event type
    * @param {String} handler_id
    * @param {String} action_id
    * @param {Event} event
    * @param {Element} target
    */
  this.delay_action = function(type, handler_id, action_id, event, target){};

  /**
    * To cancel delayed actions.
    * e.g. if a dbl click has followed a click.
    * @param {String} type, the event type
    */
  this.clear_delayed_actions = function(type){};

  /**
    * To get a list of all actions of a given action handler.
    * @param {String} handler_id
    */
  this.get_actions_with_handler_id = function(handler_id){};

  /**
    * To the label for a given mode.
    * @param {String} handler_id
    * @param {String} mode
    */
  this.get_label_with_handler_id_and_mode = function(handler_id, mode){};

  /**
    * To the global action handler.
    * Any action, which was not cancelled by the focused action handler,
    * gets passed to the global action handler.
    */
  this.get_global_handler = function(){};

  /**
    * To get a shortcut for a given handler and action.
    * @param {String} handler_id
    * @param {String} action
    */
  this.get_shortcut_with_handler_and_action = function(handler_id, action){};

  /* constants */

  const GLOBAL_HANDLER = ActionBroker.GLOBAL_HANDLER_ID;

  /* private */

  this._handlers = {};
  this._action_context = null;
  this._action_context_id = '';
  this._container = null;
  this._shortcuts = null;
  this._global_shortcuts = null;
  this._current_shortcuts = null;
  this._global_handler = new GlobalActionHandler(GLOBAL_HANDLER);
  this._delays = {};

  this._set_action_context_bound = (function(event)
  {
    if (!(this._action_context && this._action_context.onclick(event) === false))
    {
      var container = event.target;
      while (container && container.nodeType == 1 &&
             container.parentNode.nodeType == 1 &&
             !/^(?:top-)?(?:container|toolbar|tabs)$/i.test(container.nodeName))
        container = container.parentNode;

      switch (container && container.nodeName.toLowerCase() || '')
      {
        case 'container':
        {
          var ui_obj = UIBase.getUIById(container.getAttribute('ui-id'));
          if (ui_obj)
            this._set_current_handler(ui_obj.view_id, event, container);
          break;
        }
        // TODO set according key handler, e.g. toolbar, tab
        default:
        {
          this._set_current_handler(GLOBAL_HANDLER, event, container);
        }
      }
    }
  }).bind(this);

  this._set_current_handler = function(handler_id, event, container)
  {
    if (handler_id != this._action_context_id)
    {
      if (this._action_context)
        this._action_context.blur();
      if (this._container && this._container.hasClass('edit-mode'))
        this._container.removeClass('edit-mode');
      this._action_context = this._handlers[handler_id] || this._global_handler;
      this._action_context_id = this._action_context.id;
      this._current_shortcuts = this._shortcuts[this._action_context_id] || {};
      this._container = container || document.documentElement;
      this._action_context.focus(event, container);
    }
  }

  this._init = function()
  {
    this._key_identifier = new KeyIdentifier(this.dispatch_key_input.bind(this),
                                             window.ini.browser);
    this.register_handler(this._global_handler);
    window.app.addListener('services-created', function()
    {
      this._shortcuts = window.settings.general.get("shortcuts") ||
                        window.helpers.copy_object(window.ini.default_shortcuts);
      this._global_shortcuts = this._shortcuts.global;
      this._key_identifier.set_shortcuts(this._get_shortcut_keys());
      this._set_current_handler(this._global_handler);
      document.addEventListener('click', this._set_action_context_bound, true);
      document.addEventListener('focus', this._set_action_context_bound, true);
      window.messages.post('shortcuts-changed');
    }.bind(this));
  };

  /* implementation */

  this.register_handler = function(action_handler)
  {
    if (!(action_handler && action_handler.id))
      throw 'missing id on action_handler in ActionBroker.instance.register_handler';
    this._handlers[action_handler.id] = action_handler;
  }

  this.dispatch_action = function(action_handler_id, action_id, event, target)
  {
    this._handlers[action_handler_id].handle(action_id, event, target);
  }

  this.dispatch_key_input = function(key_id, event)
  {
    var shortcuts = this._current_shortcuts[this._action_context.mode];
    var action = shortcuts && shortcuts[key_id] || '';
    var propagate_event = true;
    if (action)
    {
      propagate_event = this._action_context.handle(action,
                                                    event,
                                                    this._container);
    }

    if (!(propagate_event === false) &&
         this._action_context != this._global_handler)
    {
      shortcuts = this._global_shortcuts[this._global_handler.mode];
      action = shortcuts && shortcuts[key_id] || '';
      if (action)
        propagate_event = this._global_handler.handle(action,
                                                      event,
                                                      this._container);
    }

    if (propagate_event === false)
    {
      event.stopPropagation();
      event.preventDefault();
    }
  }

  this.delay_action = function(type, handler_id, action_id, event, target)
  {
    if (!this._delays.hasOwnProperty(type))
    {
      this._delays[type] = new Timeouts();
    }
    var cb = this.dispatch_action.bind(this, handler_id, action_id, event, target);
    this._delays[type].set(cb, 300);
  }

  this.clear_delayed_actions = function(type)
  {
    if (this._delays[type])
      this._delays[type].clear();
  }

  this.get_shortcuts = function()
  {
    return window.helpers.copy_object(this._shortcuts);
  }

  this.set_shortcuts = function(shortcuts, handler_id, clear_setting)
  {
    shortcuts = window.helpers.copy_object(shortcuts);
    if (handler_id)
      this._shortcuts[handler_id] = shortcuts;
    else
      this._shortcuts = shortcuts;
    this._global_shortcuts = this._shortcuts.global;
    window.settings.general.set("shortcuts",
                                clear_setting == true ? null : this._shortcuts);
    this._key_identifier.set_shortcuts(this._get_shortcut_keys());
    window.messages.post('shortcuts-changed');
  };

  this.get_actions_with_handler_id = function(handler_id)
  {
    return (
    this._handlers[handler_id] && this._handlers[handler_id].get_action_list());
  };

  this._get_shortcut_keys = function()
  {
    var ret = [], name = '', handler = null, mode = '', key = '';
    for (name in this._shortcuts)
    {
      handler = this._shortcuts[name];
      for (mode in handler)
      {
        for (key in handler[mode])
        {
          if (ret.indexOf(key) == -1)
            ret.push(key);
        }
      }
    }
    return ret;
  };

  this.get_label_with_handler_id_and_mode = function(handler_id, mode)
  {
    return this._handlers[handler_id].mode_labels[mode];
  };

  this.get_global_handler = function()
  {
    return this._global_handler;
  };

  this.get_shortcut_with_handler_and_action = function(handler_id, action)
  {
    var
    shortcuts = this._shortcuts && this._shortcuts[handler_id],
    shortcuts_mode = null,
    mode = '',
    key = '';

    if (shortcuts)
      for (mode in shortcuts)
      {
        shortcuts_mode = shortcuts[mode];
        for (key in shortcuts_mode)
          if (shortcuts_mode[key] == action)
            return key;
      }
    return '';
  };

  if (document.readyState == "complete")
    this._init();
  else
    document.addEventListener('DOMContentLoaded', this._init.bind(this), false);

}

ActionBroker.get_instance = function()
{
  return this.instance || new ActionBroker();
}

ActionBroker.GLOBAL_HANDLER_ID = "global";
<|endoftext|>


<commit_before>glimpse.elements = (function($) {
    var scope = $(document),
        holder, opener, pageSpacer, barHolder, panelHolder, tabHolder;

    return {
        scope: function () {
            return scope;
        },
        holder: function () {
            return holder || (holder = scope.find('.glimpse-holder'));
        },
        opener: function () {
            return opener || (opener = scope.find('.glimpse-open'));
        },
        pageSpacer: function () {
            return pageSpacer || (pageSpacer = scope.find('.glimpse-spacer'));
        },
        barHolder: function () {
            return barHolder || (barHolder = scope.find('.glimpse-bar'));
        },
        tabHolder: function() {
             return tabHolder || (tabHolder = scope.find('.glimpse-tabs ul'));
        },
        panelHolder: function() {
             return panelHolder || (panelHolder = scope.find('.glimpse-panel-holder'));
        },
        panel: function(key) {
             return this.panelHolder().find('.glimpse-panel[data-glimpseKey="' + key + '"]');
        },
        panels: function() {
             return this.panelHolder().find('.glimpse-panel');
        }
    };
})(jQueryGlimpse);<commit_msg>Added the ability to pull out a tab from the elements contract<commit_after>glimpse.elements = (function($) {
    var scope = $(document),
        holder, opener, pageSpacer, barHolder, panelHolder, tabHolder;

    return {
        scope: function () {
            return scope;
        },
        holder: function () {
            return holder || (holder = scope.find('.glimpse-holder'));
        },
        opener: function () {
            return opener || (opener = scope.find('.glimpse-open'));
        },
        pageSpacer: function () {
            return pageSpacer || (pageSpacer = scope.find('.glimpse-spacer'));
        },
        barHolder: function () {
            return barHolder || (barHolder = scope.find('.glimpse-bar'));
        },
        tabHolder: function() {
             return tabHolder || (tabHolder = scope.find('.glimpse-tabs ul'));
        },
        panelHolder: function() {
             return panelHolder || (panelHolder = scope.find('.glimpse-panel-holder'));
        },
        panel: function(key) {
             return this.panelHolder().find('.glimpse-panel[data-glimpseKey="' + key + '"]');
        },
        tab: function(key) {
             return this.tabHolder().find('.glimpse-tab[data-glimpseKey="' + key + '"]');
        },
        panels: function() {
             return this.panelHolder().find('.glimpse-panel');
        }
    };
})(jQueryGlimpse);<|endoftext|>


<commit_before>import { swalClasses } from '../../classes.js'
import * as dom from '../../dom/index.js'

export const renderImage = (instance, params) => {
  const image = dom.getImage()

  if (!params.imageUrl) {
    return dom.hide(image)
  }

  dom.show(image)

  // Src, alt
  image.setAttribute('src', params.imageUrl)
  image.setAttribute('alt', params.imageAlt)

  // Width, height
  dom.applyNumericalStyle(image, 'width', params.imageWidth)
  dom.applyNumericalStyle(image, 'height', params.imageHeight)

  // Class
  image.className = swalClasses.image
  dom.applyCustomClass(image, params, 'image')
}
<commit_msg>fix: do not set style="display: flex" on image (#1977)<commit_after>import { swalClasses } from '../../classes.js'
import * as dom from '../../dom/index.js'

export const renderImage = (instance, params) => {
  const image = dom.getImage()

  if (!params.imageUrl) {
    return dom.hide(image)
  }

  dom.show(image, '')

  // Src, alt
  image.setAttribute('src', params.imageUrl)
  image.setAttribute('alt', params.imageAlt)

  // Width, height
  dom.applyNumericalStyle(image, 'width', params.imageWidth)
  dom.applyNumericalStyle(image, 'height', params.imageHeight)

  // Class
  image.className = swalClasses.image
  dom.applyCustomClass(image, params, 'image')
}
<|endoftext|>


<commit_before>var ChildCompiler = require('../ChildCompiler');
var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
var sharedDataLoader = require('./loader');

var DocsPlugin = require('../../plugin');
var Plugin = require('../../plugins/Plugin');

var stringifyLoaderConfig = require('../../utils/loader/stringifyLoaderConfig');
var format = require('util').format;

/**
 * @param {Compilation} compilation
 * @param {ChildCompilerOptions} compilerOptions
 * @param {ExampleFile} file
 * @param {string} resourcePath
 * @constructor
 */
function ExampleFileCompiler(compilation, compilerOptions, file, resourcePath) {
  if (typeof file.source != 'string')
    throw new Error('File.source not defined');

  ChildCompiler.call(this, compilation, compilerOptions);

  var compiler = this._compiler;
  var parentCompilerPlugins = compilation.compiler.options.plugins;

  // Apply parent compiler plugins to this compiler
  parentCompilerPlugins
    .filter(function (plugin) {
      return !(plugin instanceof DocsPlugin) && !(plugin instanceof Plugin)
    })
    .forEach(function (plugin) {
      compiler.apply(plugin)
    });

  // Create loaders request
  var request = ExampleFileCompiler.createEntryRequest(file, compiler.options, resourcePath);

  // ExampleFile optionally may have `context` property for proper dependencies resolving
  var entry = new SingleEntryPlugin(file.context || compiler.context, request);

  // Add entry to compiler
  compiler.apply(entry);

  // Return file.source by shared data loader
  sharedDataLoader.plugInCompiler(compiler, file.source);
}

ExampleFileCompiler.prototype = Object.create(ChildCompiler.prototype);

/**
 * @param {ExampleFile} file
 * @param {WebpackConfig} config
 * @param {string} resourcePath
 * @returns {string}
 * @static
 */
ExampleFileCompiler.createEntryRequest = function (file, config, resourcePath) {
  var loaders = [];
  var exampleFilePath = '.' + file.type;

  if (config.module.preLoaders)
    loaders = loaders.concat(config.module.preLoaders);

  if (config.module.loaders)
    loaders = loaders.concat(config.module.loaders);

  if (config.module.postLoaders)
    loaders = loaders.concat(config.module.postLoaders);

  var matchedLoaders = loaders.filter(function (loaderConfig) {
    return loaderConfig.test.test(exampleFilePath);
  });

  matchedLoaders.push({
    loader: sharedDataLoader.CONTEXT_PROPERTY_NAME
  });

  var matchedLoadersString = matchedLoaders.map(stringifyLoaderConfig).join('!');

  return format('!!%s!%s', matchedLoadersString, resourcePath);
};

module.exports = ExampleFileCompiler;<commit_msg>Add example file compiler output filename options handling<commit_after>var ChildCompiler = require('../ChildCompiler');
var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
var sharedDataLoader = require('./loader');

var DocsPlugin = require('../../plugin');
var Plugin = require('../../plugins/Plugin');

var stringifyLoaderConfig = require('../../utils/loader/stringifyLoaderConfig');
var format = require('util').format;

/**
 * @param {Compilation} compilation
 * @param {ChildCompilerOptions} compilerOptions
 * @param {ExampleFile} file
 * @param {string} resourcePath
 * @constructor
 */
function ExampleFileCompiler(compilation, compilerOptions, file, resourcePath) {
  if (typeof file.source != 'string')
    throw new Error('File.source not defined');

  ChildCompiler.call(this, compilation, compilerOptions);

  var compiler = this._compiler;
  var compilerOutputOptions = compiler.options.output;
  var parentCompilerPlugins = compilation.compiler.options.plugins;

  // Apply parent compiler plugins to this compiler
  parentCompilerPlugins
    .filter(function (plugin) {
      return !(plugin instanceof DocsPlugin) && !(plugin instanceof Plugin)
    })
    .forEach(function (plugin) {
      compiler.apply(plugin)
    });

  // Create loaders request
  var request = ExampleFileCompiler.createEntryRequest(file, compiler.options, resourcePath);

  // ExampleFile optionally may have `context` property for proper dependencies resolving
  var entry = new SingleEntryPlugin(file.context || compiler.context, request, compilerOutputOptions.filename);

  // Add entry to compiler
  compiler.apply(entry);

  // Return file.source by shared data loader
  sharedDataLoader.plugInCompiler(compiler, file.source);
}

ExampleFileCompiler.prototype = Object.create(ChildCompiler.prototype);

/**
 * @param {ExampleFile} file
 * @param {WebpackConfig} config
 * @param {string} resourcePath
 * @returns {string}
 * @static
 */
ExampleFileCompiler.createEntryRequest = function (file, config, resourcePath) {
  var loaders = [];
  var exampleFilePath = '.' + file.type;

  if (config.module.preLoaders)
    loaders = loaders.concat(config.module.preLoaders);

  if (config.module.loaders)
    loaders = loaders.concat(config.module.loaders);

  if (config.module.postLoaders)
    loaders = loaders.concat(config.module.postLoaders);

  var matchedLoaders = loaders.filter(function (loaderConfig) {
    return loaderConfig.test.test(exampleFilePath);
  });

  matchedLoaders.push({
    loader: sharedDataLoader.CONTEXT_PROPERTY_NAME
  });

  var matchedLoadersString = matchedLoaders.map(stringifyLoaderConfig).join('!');

  return format('!!%s!%s', matchedLoadersString, resourcePath);
};

module.exports = ExampleFileCompiler;<|endoftext|>


<commit_before>'use strict';

var Node = require('../node');

var TYPE = 'aggregate-intersection';
var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    target: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    aggregate_function: Node.PARAM.ENUM('avg', 'count', 'max', 'min', 'sum'),
    aggregate_column: Node.PARAM.NULLABLE(Node.PARAM.STRING())
};

var AggregateIntersection = Node.create(TYPE, PARAMS, { cache: true, version: 3 });

module.exports = AggregateIntersection;

AggregateIntersection.prototype.sql = function() {
    var groupByColumns = setAliasPrefixToColumnNames(this.source.getColumns(), '_cdb_analysis_source');
    var columns = setAliasPrefixToColumnNames(this.source.getColumns(), '_cdb_analysis_source');
    var finalColumnName = this.aggregate_function;
    var qualifiedAggregateColumn = '_cdb_analysis_target.';
    if (this.aggregate_column === null) {
        qualifiedAggregateColumn += '*';
    } else {
        qualifiedAggregateColumn += this.aggregate_column;
        finalColumnName += '_' + this.aggregate_column;
    }

    var aggregateFunctionColumn = aggregateFunctionTemplate({
        aggregateFunction: this.aggregate_function,
        qualifiedAggregateColumn: qualifiedAggregateColumn,
        // TODO: we should adopt a common naming for new columns
        aggregateFinalColumnName: this.aggregate_function === 'count' ? 'count_vals' : finalColumnName
    });

    columns.push(aggregateFunctionColumn);

    if (this.aggregate_function === 'count') {
        var aggregateDensityColumn = densityQueryTemplate({
            aggregateFunction: this.aggregate_function,
            qualifiedAggregateColumn: qualifiedAggregateColumn,
            aggregateFinalColumnDensityName: 'count_vals_density'
        });

        columns.push(aggregateDensityColumn);
    }

    return queryAggregateTemplate({
        sourceQuery: this.source.getQuery(), // polygons
        targetQuery: this.target.getQuery(), // points
        columns: columns.join(', '),
        groupByColumns: groupByColumns.join(', ')
    });
};

function setAliasPrefixToColumnNames(columnNames, alias) {
    return columnNames.map(function (name) {
        return alias + '.' + name;
    });
}

var aggregateFunctionTemplate = Node.template(
    '{{=it.aggregateFunction}}({{=it.qualifiedAggregateColumn}}) as {{=it.aggregateFinalColumnName}}'
);

var densityQueryTemplate = Node.template([
    '{{=it.aggregateFunction}}({{=it.qualifiedAggregateColumn}})',
    '/',
    // use 2.6e-06 as minimum area (tile size at zoom level 31)
    'GREATEST(0.0000026, ST_Area((ST_Transform(_cdb_analysis_source.the_geom, 4326))::geography))',
    'as {{=it.aggregateFinalColumnDensityName}}',
].join(' '));

var queryAggregateTemplate = Node.template([
    'SELECT {{=it.columns}}',
    'FROM ({{=it.sourceQuery}}) _cdb_analysis_source, ({{=it.targetQuery}}) _cdb_analysis_target',
    'WHERE ST_Intersects(_cdb_analysis_source.the_geom, _cdb_analysis_target.the_geom)',
    'GROUP BY {{=it.groupByColumns}}'
].join('\n'));
<commit_msg>Compute requirements for aggregate-intersection anaylises<commit_after>'use strict';

var Node = require('../node');

var TYPE = 'aggregate-intersection';
var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    target: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    aggregate_function: Node.PARAM.ENUM('avg', 'count', 'max', 'min', 'sum'),
    aggregate_column: Node.PARAM.NULLABLE(Node.PARAM.STRING())
};

var AggregateIntersection = Node.create(TYPE, PARAMS, { cache: true, version: 3 });

module.exports = AggregateIntersection;

AggregateIntersection.prototype.sql = function() {
    var groupByColumns = setAliasPrefixToColumnNames(this.source.getColumns(), '_cdb_analysis_source');
    var columns = setAliasPrefixToColumnNames(this.source.getColumns(), '_cdb_analysis_source');
    var finalColumnName = this.aggregate_function;
    var qualifiedAggregateColumn = '_cdb_analysis_target.';
    if (this.aggregate_column === null) {
        qualifiedAggregateColumn += '*';
    } else {
        qualifiedAggregateColumn += this.aggregate_column;
        finalColumnName += '_' + this.aggregate_column;
    }

    var aggregateFunctionColumn = aggregateFunctionTemplate({
        aggregateFunction: this.aggregate_function,
        qualifiedAggregateColumn: qualifiedAggregateColumn,
        // TODO: we should adopt a common naming for new columns
        aggregateFinalColumnName: this.aggregate_function === 'count' ? 'count_vals' : finalColumnName
    });

    columns.push(aggregateFunctionColumn);

    if (this.aggregate_function === 'count') {
        var aggregateDensityColumn = densityQueryTemplate({
            aggregateFunction: this.aggregate_function,
            qualifiedAggregateColumn: qualifiedAggregateColumn,
            aggregateFinalColumnDensityName: 'count_vals_density'
        });

        columns.push(aggregateDensityColumn);
    }

    return queryAggregateTemplate({
        sourceQuery: this.source.getQuery(), // polygons
        targetQuery: this.target.getQuery(), // points
        columns: columns.join(', '),
        groupByColumns: groupByColumns.join(', ')
    });
};

function setAliasPrefixToColumnNames(columnNames, alias) {
    return columnNames.map(function (name) {
        return alias + '.' + name;
    });
}

var aggregateFunctionTemplate = Node.template(
    '{{=it.aggregateFunction}}({{=it.qualifiedAggregateColumn}}) as {{=it.aggregateFinalColumnName}}'
);

var densityQueryTemplate = Node.template([
    '{{=it.aggregateFunction}}({{=it.qualifiedAggregateColumn}})',
    '/',
    // use 2.6e-06 as minimum area (tile size at zoom level 31)
    'GREATEST(0.0000026, ST_Area((ST_Transform(_cdb_analysis_source.the_geom, 4326))::geography))',
    'as {{=it.aggregateFinalColumnDensityName}}',
].join(' '));

var queryAggregateTemplate = Node.template([
    'SELECT {{=it.columns}}',
    'FROM ({{=it.sourceQuery}}) _cdb_analysis_source, ({{=it.targetQuery}}) _cdb_analysis_target',
    'WHERE ST_Intersects(_cdb_analysis_source.the_geom, _cdb_analysis_target.the_geom)',
    'GROUP BY {{=it.groupByColumns}}'
].join('\n'));

AggregateIntersection.prototype.computeRequirements = function(databaseService, limits, callback) {
    // we estimate the maximum possible number of rows of the result
    var product = this.source.estimatedRequirements.numberOfRows *
                  this.target.estimatedRequirements.numberOfRows;
    this.estimatedRequirements = {
        numberOfRows: product
    };
    this.limits = {
        maximumNumberOfRows: Node.getNodeLimit(limits, TYPE, 'maximumNumberOfRows', 1000000)
    };
    return callback(null);
};
<|endoftext|>