<commit_before>'use strict';
const Base = require('yeoman-generator').Base;
const chalk = require('chalk');
const fs = require('fs-extra');
const path = require('path');
const yeoman = require('yeoman-environment');
const {toHTTPRepoUrl, toSSHRepoUrl, simplifyRepoUrl} = require('../../utils/repo');

function toBaseName(name) {
  if (name.includes('/')) {
    return name;
  }
  return `Caleydo/${name}`;
}

function failed(spawnResult) {
  return spawnResult.status !== 0;
}

function toCWD(basename) {
  let match = basename.match(/.*\/(.*)/)[1];
  if (match.endsWith('_product')) {
    match = match.slice(0, -8);
  }
  return match;
}

function findDefaultApp(product) {
  if (!product) {
    return null;
  }
  for (let p of product) {
    if (p.type === 'web') {
      return p.repo.slice(p.repo.lastIndexOf('/') + 1).replace('.git', '');
    }
  }
  return null;
}

function downloadFileImpl(url, dest) {
  const http = require(url.startsWith('https') ? 'https' : 'http');
  console.log(chalk.blue('download file', url));
  return new Promise((resolve, reject) => {
    const file = fs.createWriteStream(dest);
    http.get(url, (response) => {
      response.pipe(file);
      file.on('finish', () => {
        file.close(resolve);
      });
    }).on('error', reject);
  });
}

function downloadDataUrl(url, dest) {
  if (!url.startsWith('http')) {
    url = `https://s3.eu-central-1.amazonaws.com/phovea-data-packages/${url}`;
  }
  return downloadFileImpl(url, dest);
}

function downloadBackupUrl(url, dest) {
  if (!url.startsWith('http')) {
    url = `https://s3.eu-central-1.amazonaws.com/phovea-volume-backups/${url}`;
  }
  return downloadFileImpl(url, dest);
}

function toDownloadName(url) {
  if (!url.startsWith('http')) {
    return url;
  }
  return url.substring(url.lastIndexOf('/') + 1);
}

class Generator extends Base {

  constructor(args, options) {
    super(args, options);

    this.option('ssh', {
      alias: 's',
      defaults: false,
      type: Boolean
    });

    this.option('branch', {
      alias: 'b',
      defaults: 'master',
      type: String
    });

    this.option('skip', {
      defaults: '',
      type: String
    });

    this.argument('product', {
      required: true
    });
  }

  prompting() {
    return this.prompt([{
      type: 'input',
      name: 'productName',
      message: 'Product',
      default: this.args.length > 0 ? this.args[0] : undefined,
      when: this.args.length === 0,
      validate: (d) => d.length > 0
    }, {
      type: 'confirm',
      name: 'cloneSSH',
      message: 'SSH clone',
      store: true,
      default: this.options.ssh,
      when: !this.options.ssh
    }]).then((props) => {
      this.productName = toBaseName(props.productName || this.args[0]);
      this.cwd = toCWD(this.productName);
      this.cloneSSH = props.cloneSSH || this.options.ssh;
    });
  }

  _yo(generator, options) {
    // call yo internally
    const env = yeoman.createEnv([], {
      cwd: this.cwd
    }, this.env.adapter);
    env.register(require.resolve('../' + generator), 'phovea:' + generator);
    return new Promise((resolve, reject) => {
      try {
        this.log('running yo phovea:' + generator);
        env.run('phovea:' + generator, options || {}, () => {
          // wait a second after running yo to commit the files correctly
          setTimeout(() => resolve(), 500);
        });
      } catch (e) {
        console.error('error', e, e.stack);
        reject(e);
      }
    });
  }

  _abort(msg) {
    return Promise.reject(msg ? msg : 'Step Failed: Aborting');
  }

  _spawn(cmd, argline, cwd) {
    const options = cwd === false ? {} : Object.assign({cwd: this.cwd}, cwd || {});
    return this.spawnCommandSync(cmd, Array.isArray(argline) ? argline : argline.split(' '), options);
  }

  _spawnOrAbort(cmd, argline, cwd) {
    const r = this._spawn(cmd, argline, cwd);
    if (failed(r)) {
      this.log(r);
      return this._abort(`failed: "${cmd} ${argline.join(' ')}" - status code: ${r.status}`);
    }
    return Promise.resolve(cmd);
  }

  _cloneRepo(repo, branch, extras) {
    const repoUrl = this.cloneSSH ? toSSHRepoUrl(repo) : toHTTPRepoUrl(repo);
    if (!/^[0-9a-f]+$/gi.test(branch)) {
      // regular branch
      const line = `clone -b ${branch}${extras || ''} ${repoUrl}`;
      this.log(chalk.blue(`clone repository:`), `git ${line}`);
      return this._spawnOrAbort('git', line.split(/ +/));
    }
    // clone a specific commit
    const line = `clone ${extras || ''} ${repoUrl}`;
    this.log(chalk.blue(`clone repository:`), `git ${line}`);
    return this._spawnOrAbort('git', line.split(/ +/)).then(() => {
      const line = `checkout ${branch}`;
      this.log(chalk.blue(`checkout commit:`), `git ${line}`);
      let repoName = simplifyRepoUrl(repo);
      repoName = repoName.slice(repoName.lastIndexOf('/') + 1);
      return this._spawnOrAbort('git', line.split(/ +/), {cwd: `${this.cwd}/${repoName}`});
    });
  }

  _getProduct() {
    return this._cloneRepo(this.productName, this.options.branch || 'master', ' --depth 1')
      .then(() => {
        const name = this.productName.slice(this.productName.lastIndexOf('/') + 1);
        this.product = fs.readJSONSync(`${this.cwd}/${name}/phovea_product.json`);

        // pass through the docker overrides
        for (const file of ['docker-compose-patch.yaml', 'docker-compose-patch.yml']) {
          if (fs.existsSync(`${this.cwd}/${name}/${file}`)) {
            fs.copySync(`${this.cwd}/${name}/${file}`, this.destinationPath(`${this.cwd}/${file}`));
          }
        }
        if (fs.existsSync(`${this.cwd}/${name}/docker_script.sh`)) {
          fs.copySync(`${this.cwd}/${name}/docker_script.sh`, this.destinationPath(`${this.cwd}/docker_script_patch.sh`));
        }
        // generic copy helper
        if (fs.existsSync(`${this.cwd}/${name}/ws`)) {
          fs.copySync(`${this.cwd}/${name}/ws`, this.destinationPath(`${this.cwd}`));
        }

        const defaultApp = this.product.find((v) => v.type === 'web');
        if (defaultApp) {
          const baseRepo = simplifyRepoUrl(defaultApp.repo);
          const defaultAppName = baseRepo.slice(baseRepo.lastIndexOf('/') + 1);
          this.defaultApp = defaultAppName;
          fs.writeJsonSync(this.destinationPath(`${this.cwd}/.yo-rc-workspace.json`), {
            modules: [],
            defaultApp: defaultAppName
          });
        }

        return this.product;
      }).then((product) => {
        const name = this.productName.slice(this.productName.lastIndexOf('/') + 1);
        // clean up again
        fs.removeSync(`${this.cwd}/${name}`);
        return product;
      });
  }

  _mkdir(dir) {
    dir = dir || this.cwd;
    this.log('create directory: ' + dir);
    return new Promise((resolve) => fs.ensureDir(dir, resolve));
  }

  _customizeWorkspace() {
    const defaultApp = findDefaultApp(this.product);
    if (defaultApp) {
      this.fs.copyTpl(this.templatePath('start_defaultapp.tmpl.xml'), this.destinationPath(`${this.cwd}/.idea/runConfigurations/start_${defaultApp}.xml`), {
        defaultApp: defaultApp
      });
      this.fs.copyTpl(this.templatePath('lint_defaultapp.tmpl.xml'), this.destinationPath(`${this.cwd}/.idea/runConfigurations/lint_${defaultApp}.xml`), {
        defaultApp: defaultApp
      });
    }
  }

  _downloadDataFile(desc, destDir) {
    if (typeof desc === 'string') {
      desc = {
        type: 'url',
        url: desc
      };
    }
    switch (desc.type) {
      case 'url':
        return downloadDataUrl(desc.url, path.join(destDir, toDownloadName(desc.url)));
      default:
        this.log(chalk.red('cannot handle data type:', desc.type));
        return null;
    }
  }

  _downloadBackupFile(desc, destDir) {
    if (typeof desc === 'string') {
      desc = {
        type: 'url',
        url: desc
      };
    }
    switch (desc.type) {
      case 'url':
        return downloadBackupUrl(desc.url, path.join(destDir, toDownloadName(desc.url)));
      default:
        this.log(chalk.red('cannot handle data type:', desc.type));
        return null;
    }
  }

  _downloadDataFiles() {
    const data = [];
    this.product.forEach((p) => {
      if (p.data) {
        data.push(...p.data);
      }
    });
    if (data.length === 0) {
      return Promise.resolve(null);
    }
    return this._mkdir(this.cwd + '/_data')
      .then(() => Promise.all(data.map((d) => this._downloadDataFile(d, this.cwd + '/_data'))));
  }

  _downloadBackupFiles() {
    const data = [];
    this.product.forEach((p) => {
      if (p.backup) {
        data.push(...p.backup);
      }
    });
    if (data.length === 0) {
      return Promise.resolve(null);
    }
    return this._mkdir(this.cwd + '/_backup')
      .then(() => Promise.all(data.map((d) => this._downloadBackupFile(d, this.cwd + '/_backup'))))
      .then(this._ifExecutable.bind(this, 'docker-compose', this._spawnOrAbort.bind(this, './docker-backup', 'restore'), 'please execute: "./docker-backup restore" manually'));
  }

  _ifExecutable(cmd, ifExists, extraMessage = '') {
    const paths = process.env.PATH.split(path.delimiter);
    const pathExt = (process.env.PATHEXT || '').split(path.delimiter);

    const findIt = () => {
      for (const p of paths) {
        for (const ext of pathExt) {
          const fullPath = `${p}${path.sep}${cmd}${ext}`;
          if (fs.existsSync(fullPath)) {
            this.log(`found ${cmd} at ${fullPath}`);
            return true;
          }
        }
      }
      return false;
    };

    if (!findIt()) {
      this.log(chalk.red(`Error: ${cmd} not found${extraMessage}`));
      return Promise.resolve(null);
    }
    return ifExists();
  }

  writing() {
    return Promise.resolve(1)
      .then(this._mkdir.bind(this, null))
      .then(this._getProduct.bind(this))
      .then((product) => {
        const names = new Set();
        const repos = [];
        product.forEach((p) => {
          const repo = p.repo || 'phovea/' + p.name;
          if (!names.has(repo)) {
            names.add(repo);
            repos.push({
              repo,
              branch: p.branch || 'master'
            });
          }
          (p.additional || []).forEach((pi) => {
            const repo = pi.repo || 'phovea/' + pi.name;
            if (!names.has(repo)) {
              names.add(repo);
              repos.push({
                repo,
                branch: pi.branch || 'master'
              });
            }
          });
        });
        return repos;
      })
      .then((repos) => Promise.all(repos.map((r) => this._cloneRepo(r.repo, r.branch))))
      .then(this._yo.bind(this, 'workspace', {defaultApp: findDefaultApp()}))
      .then(this._customizeWorkspace.bind(this))
      .then(this._downloadDataFiles.bind(this))
      .then(() => this.options.skip.includes('install') ? null : this._spawnOrAbort('npm', 'install'))
      .then(this._downloadBackupFiles.bind(this))
      .then(() => {
        const l = this.fs.read(this.destinationPath(`${this.cwd}/docker-compose.yml`), {defaults: ''});
        if (l.trim().length > 0 && !this.options.skip.includes('build')) {
          return this._ifExecutable('docker-compose', this._spawnOrAbort.bind(this, 'docker-compose', 'build'), ' please run "docker-compose build" manually"');
        }
        return null;
      })
      .catch((msg) => {
        this.log(chalk.red(`Error: ${msg}`));
        return Promise.reject(msg);
      });
  }

  end() {
    this.log('\n\nnext steps: ');
    this.log(chalk.green('1. switch to the created directory: '), chalk.yellow(`cd ${this.cwd}`));
    this.log(chalk.green('2. Open IDE (PyCharm or Visual Studio Code, Atom) and select:'), this.destinationPath(this.cwd));
    this.log(chalk.green('   in case of Visual Studio Code, the following should also work: '), chalk.yellow('code .'));
    this.log(chalk.green('3. start server docker container in the background (-d): '), chalk.yellow('docker-compose up -d'));
    this.log(chalk.green('4. start client application in the foreground: '), chalk.yellow('npm start'));
    this.log(chalk.green('5. open web browser and access: '), chalk.yellow('http://localhost:8080'));

    this.log(chalk.green('X. look at last 50 server log messages (-f ... auto update): '), chalk.yellow('docker-compose logs -f --tail=50 api'));
  }
}

module.exports = Generator;
<commit_msg>Add version range for branches to setup-workspace<commit_after>'use strict';
const Base = require('yeoman-generator').Base;
const chalk = require('chalk');
const fs = require('fs-extra');
const path = require('path');
const yeoman = require('yeoman-environment');
const {
  toHTTPRepoUrl,
  toSSHRepoUrl,
  simplifyRepoUrl
} = require('../../utils/repo');
const version = require('../../utils/version');

function toBaseName(name) {
  if (name.includes('/')) {
    return name;
  }
  return `Caleydo/${name}`;
}

function failed(spawnResult) {
  return spawnResult.status !== 0;
}

function toCWD(basename) {
  let match = basename.match(/.*\/(.*)/)[1];
  if (match.endsWith('_product')) {
    match = match.slice(0, -8);
  }
  return match;
}

function findDefaultApp(product) {
  if (!product) {
    return null;
  }
  for (let p of product) {
    if (p.type === 'web') {
      return p.repo.slice(p.repo.lastIndexOf('/') + 1).replace('.git', '');
    }
  }
  return null;
}

function downloadFileImpl(url, dest) {
  const http = require(url.startsWith('https') ? 'https' : 'http');
  console.log(chalk.blue('download file', url));
  return new Promise((resolve, reject) => {
    const file = fs.createWriteStream(dest);
    http.get(url, (response) => {
      response.pipe(file);
      file.on('finish', () => {
        file.close(resolve);
      });
    }).on('error', reject);
  });
}

function downloadDataUrl(url, dest) {
  if (!url.startsWith('http')) {
    url = `https://s3.eu-central-1.amazonaws.com/phovea-data-packages/${url}`;
  }
  return downloadFileImpl(url, dest);
}

function downloadBackupUrl(url, dest) {
  if (!url.startsWith('http')) {
    url = `https://s3.eu-central-1.amazonaws.com/phovea-volume-backups/${url}`;
  }
  return downloadFileImpl(url, dest);
}

function toDownloadName(url) {
  if (!url.startsWith('http')) {
    return url;
  }
  return url.substring(url.lastIndexOf('/') + 1);
}

class Generator extends Base {

  constructor(args, options) {
    super(args, options);

    this.option('ssh', {
      alias: 's',
      defaults: false,
      type: Boolean
    });

    this.option('branch', {
      alias: 'b',
      defaults: 'master',
      type: String
    });

    this.option('skip', {
      defaults: '',
      type: String
    });

    this.argument('product', {
      required: true
    });
  }

  prompting() {
    return this.prompt([{
      type: 'input',
      name: 'productName',
      message: 'Product',
      default: this.args.length > 0 ? this.args[0] : undefined,
      when: this.args.length === 0,
      validate: (d) => d.length > 0
    }, {
      type: 'confirm',
      name: 'cloneSSH',
      message: 'SSH clone',
      store: true,
      default: this.options.ssh,
      when: !this.options.ssh
    }]).then((props) => {
      this.productName = toBaseName(props.productName || this.args[0]);
      this.cwd = toCWD(this.productName);
      this.cloneSSH = props.cloneSSH || this.options.ssh;
    });
  }

  _yo(generator, options) {
    // call yo internally
    const env = yeoman.createEnv([], {
      cwd: this.cwd
    }, this.env.adapter);
    env.register(require.resolve('../' + generator), 'phovea:' + generator);
    return new Promise((resolve, reject) => {
      try {
        this.log('running yo phovea:' + generator);
        env.run('phovea:' + generator, options || {}, () => {
          // wait a second after running yo to commit the files correctly
          setTimeout(() => resolve(), 500);
        });
      } catch (e) {
        console.error('error', e, e.stack);
        reject(e);
      }
    });
  }

  _abort(msg) {
    return Promise.reject(msg ? msg : 'Step Failed: Aborting');
  }

  _spawn(cmd, argline, cwd) {
    const options = cwd === false ? {} : Object.assign({
      cwd: this.cwd,
      stdio: ['inherit', 'pipe', 'pipe'] // pipe `stdout` and `stderr` to host process
    }, cwd || {});
    return this.spawnCommandSync(cmd, Array.isArray(argline) ? argline : argline.split(' '), options);
  }

  _spawnOrAbort(cmd, argline, cwd) {
    const r = this._spawn(cmd, argline, cwd);
    if (failed(r)) {
      this.log(r.stderr.toString());
      return this._abort(`failed: "${cmd} ${Array.isArray(argline) ? argline.join(' ') : argline}" - status code: ${r.status}`);
    }
    return Promise.resolve(cmd);
  }

  _cloneRepo(repo, branch, extras) {
    const repoUrl = this.cloneSSH ? toSSHRepoUrl(repo) : toHTTPRepoUrl(repo);
    if (!version.isGitCommit(branch)) {
      // modify branch name, if it is an advance version tag
      // otherwise just use the branch name as it is
      if (version.isAdvancedVersionTag(branch)) {
        this.log(chalk.white(`found branch with version range`), chalk.green(branch), chalk.white(`for`), chalk.green(repoUrl));

        const line = `ls-remote --tags ${repoUrl}`;
        this.log(chalk.white(`fetching possible version tags:`), `git ${line}`);
        const r = this._spawn('git', line.split(/ +/));

        if (failed(r)) {
          this.log(chalk.red(`failed to fetch list of tags from git repository`), `status code: ${r.status}`);
          this.log(r.stderr.toString());
          return this._abort(`failed to fetch list of tags from git repository - status code: ${r.status}`);
        }

        const gitLog = r.stdout.toString();
        const gitVersions = version.extractVersionsFromGitLog(gitLog);
        this.log(chalk.white(`found the following version tags: `), gitVersions);

        const highestVersion = version.findHighestVersion(gitVersions, branch);
        if (!highestVersion) {
          this.log(chalk.red(`failed to find git version tag for given version range`));
          return this._abort(`failed to find git version tag for given version range`);
        }

        this.log(chalk.white(`use version tag`), chalk.green(highestVersion), chalk.white(`as branch name`));
        branch = highestVersion;
      }

      const line = `clone -b ${branch}${extras || ''} ${repoUrl}`;
      this.log(chalk.white(`clone repository:`), `git ${line}`);
      return this._spawnOrAbort('git', line.split(/ +/));
    }
    // clone a specific commit
    const line = `clone ${extras || ''} ${repoUrl}`;
    this.log(chalk.white(`clone repository:`), `git ${line}`);
    return this._spawnOrAbort('git', line.split(/ +/)).then(() => {
      const line = `checkout ${branch}`;
      this.log(chalk.white(`checkout commit:`), `git ${line}`);
      let repoName = simplifyRepoUrl(repo);
      repoName = repoName.slice(repoName.lastIndexOf('/') + 1);
      return this._spawnOrAbort('git', line.split(/ +/), {
        cwd: `${this.cwd}/${repoName}`
      });
    });
  }

  _getProduct() {
    return this._cloneRepo(this.productName, this.options.branch || 'master', ' --depth 1')
      .then(() => {
        const name = this.productName.slice(this.productName.lastIndexOf('/') + 1);
        this.product = fs.readJSONSync(`${this.cwd}/${name}/phovea_product.json`);

        // pass through the docker overrides
        for (const file of ['docker-compose-patch.yaml', 'docker-compose-patch.yml']) {
          if (fs.existsSync(`${this.cwd}/${name}/${file}`)) {
            fs.copySync(`${this.cwd}/${name}/${file}`, this.destinationPath(`${this.cwd}/${file}`));
          }
        }
        if (fs.existsSync(`${this.cwd}/${name}/docker_script.sh`)) {
          fs.copySync(`${this.cwd}/${name}/docker_script.sh`, this.destinationPath(`${this.cwd}/docker_script_patch.sh`));
        }
        // generic copy helper
        if (fs.existsSync(`${this.cwd}/${name}/ws`)) {
          fs.copySync(`${this.cwd}/${name}/ws`, this.destinationPath(`${this.cwd}`));
        }

        const defaultApp = this.product.find((v) => v.type === 'web');
        if (defaultApp) {
          const baseRepo = simplifyRepoUrl(defaultApp.repo);
          const defaultAppName = baseRepo.slice(baseRepo.lastIndexOf('/') + 1);
          this.defaultApp = defaultAppName;
          fs.writeJsonSync(this.destinationPath(`${this.cwd}/.yo-rc-workspace.json`), {
            modules: [],
            defaultApp: defaultAppName
          });
        }

        return this.product;
      }).then((product) => {
        const name = this.productName.slice(this.productName.lastIndexOf('/') + 1);
        // clean up again
        fs.removeSync(`${this.cwd}/${name}`);
        return product;
      });
  }

  _mkdir(dir) {
    dir = dir || this.cwd;
    this.log('create directory: ' + dir);
    return new Promise((resolve) => fs.ensureDir(dir, resolve));
  }

  _customizeWorkspace() {
    const defaultApp = findDefaultApp(this.product);
    if (defaultApp) {
      this.fs.copyTpl(this.templatePath('start_defaultapp.tmpl.xml'), this.destinationPath(`${this.cwd}/.idea/runConfigurations/start_${defaultApp}.xml`), {
        defaultApp: defaultApp
      });
      this.fs.copyTpl(this.templatePath('lint_defaultapp.tmpl.xml'), this.destinationPath(`${this.cwd}/.idea/runConfigurations/lint_${defaultApp}.xml`), {
        defaultApp: defaultApp
      });
    }
  }

  _downloadDataFile(desc, destDir) {
    if (typeof desc === 'string') {
      desc = {
        type: 'url',
        url: desc
      };
    }
    switch (desc.type) {
      case 'url':
        return downloadDataUrl(desc.url, path.join(destDir, toDownloadName(desc.url)));
      default:
        this.log(chalk.red('cannot handle data type:', desc.type));
        return null;
    }
  }

  _downloadBackupFile(desc, destDir) {
    if (typeof desc === 'string') {
      desc = {
        type: 'url',
        url: desc
      };
    }
    switch (desc.type) {
      case 'url':
        return downloadBackupUrl(desc.url, path.join(destDir, toDownloadName(desc.url)));
      default:
        this.log(chalk.red('cannot handle data type:', desc.type));
        return null;
    }
  }

  _downloadDataFiles() {
    const data = [];
    this.product.forEach((p) => {
      if (p.data) {
        data.push(...p.data);
      }
    });
    if (data.length === 0) {
      return Promise.resolve(null);
    }
    return this._mkdir(this.cwd + '/_data')
      .then(() => Promise.all(data.map((d) => this._downloadDataFile(d, this.cwd + '/_data'))));
  }

  _downloadBackupFiles() {
    const data = [];
    this.product.forEach((p) => {
      if (p.backup) {
        data.push(...p.backup);
      }
    });
    if (data.length === 0) {
      return Promise.resolve(null);
    }
    return this._mkdir(this.cwd + '/_backup')
      .then(() => Promise.all(data.map((d) => this._downloadBackupFile(d, this.cwd + '/_backup'))))
      .then(this._ifExecutable.bind(this, 'docker-compose', this._spawnOrAbort.bind(this, './docker-backup', 'restore'), 'please execute: "./docker-backup restore" manually'));
  }

  _ifExecutable(cmd, ifExists, extraMessage = '') {
    const paths = process.env.PATH.split(path.delimiter);
    const pathExt = (process.env.PATHEXT || '').split(path.delimiter);

    const findIt = () => {
      for (const p of paths) {
        for (const ext of pathExt) {
          const fullPath = `${p}${path.sep}${cmd}${ext}`;
          if (fs.existsSync(fullPath)) {
            this.log(`found ${cmd} at ${fullPath}`);
            return true;
          }
        }
      }
      return false;
    };

    if (!findIt()) {
      this.log(chalk.red(`Error: ${cmd} not found${extraMessage}`));
      return Promise.resolve(null);
    }
    return ifExists();
  }

  writing() {
    return Promise.resolve(1)
      .then(this._mkdir.bind(this, null))
      .then(this._getProduct.bind(this))
      .then((product) => {
        const names = new Set();
        const repos = [];
        product.forEach((p) => {
          const repo = p.repo || 'phovea/' + p.name;
          if (!names.has(repo)) {
            names.add(repo);
            repos.push({
              repo,
              branch: p.branch || 'master'
            });
          }
          (p.additional || []).forEach((pi) => {
            const repo = pi.repo || 'phovea/' + pi.name;
            if (!names.has(repo)) {
              names.add(repo);
              repos.push({
                repo,
                branch: pi.branch || 'master'
              });
            }
          });
        });
        return repos;
      })
      .then((repos) => Promise.all(repos.map((r) => this._cloneRepo(r.repo, r.branch))))
      .then(this._yo.bind(this, 'workspace', {
        defaultApp: findDefaultApp()
      }))
      .then(this._customizeWorkspace.bind(this))
      .then(this._downloadDataFiles.bind(this))
      .then(() => this.options.skip.includes('install') ? null : this._spawnOrAbort('npm', 'install'))
      .then(this._downloadBackupFiles.bind(this))
      .then(() => {
        const l = this.fs.read(this.destinationPath(`${this.cwd}/docker-compose.yml`), {
          defaults: ''
        });
        if (l.trim().length > 0 && !this.options.skip.includes('build')) {
          return this._ifExecutable('docker-compose', this._spawnOrAbort.bind(this, 'docker-compose', 'build'), ' please run "docker-compose build" manually"');
        }
        return null;
      })
      .catch((msg) => {
        this.log(chalk.red(`Error: ${msg}`));
        return Promise.reject(msg);
      });
  }

  end() {
    this.log('\n\nnext steps: ');
    this.log(chalk.green('1. switch to the created directory: '), chalk.yellow(`cd ${this.cwd}`));
    this.log(chalk.green('2. Open IDE (PyCharm or Visual Studio Code, Atom) and select:'), this.destinationPath(this.cwd));
    this.log(chalk.green('   in case of Visual Studio Code, the following should also work: '), chalk.yellow('code .'));
    this.log(chalk.green('3. start server docker container in the background (-d): '), chalk.yellow('docker-compose up -d'));
    this.log(chalk.green('4. start client application in the foreground: '), chalk.yellow('npm start'));
    this.log(chalk.green('5. open web browser and access: '), chalk.yellow('http://localhost:8080'));

    this.log(chalk.green('X. look at last 50 server log messages (-f ... auto update): '), chalk.yellow('docker-compose logs -f --tail=50 api'));
  }
}

module.exports = Generator;
<|endoftext|>


<commit_before>import React from 'react';

import SuggestionsTab from 'Main/SuggestionsTab';

import MainCombatLogParser from 'Parser/Core/CombatLogParser';
import DamageDone from 'Parser/Core/Modules/DamageDone';

import Haste from './Modules/Core/Haste';

import CastEfficiency from './Modules/Features/CastEfficiency';
import AlwaysBeCasting from './Modules/Features/AlwaysBeCasting';

import Moonfire from './Modules/Spells/Moonfire';
import Sunfire from './Modules/Spells/Sunfire';
import NewMoon from './Modules/Spells/NewMoon';
import HalfMoon from './Modules/Spells/HalfMoon';
import FullMoon from './Modules/Spells/FullMoon';
// import SolarUnemp from './Modules/Spells/Empowerments/SolarUnemp';
// import LunarUnemp from './Modules/Spells/Empowerments/LunarUnemp';
import LEmpowerment from './Modules/Features/LunarEmpowerment';
import SEmpowerment from './Modules/Features/SolarEmpowerment';
import AstralPower from './Modules/Features/AstralPower';
import UnempoweredLs from './Modules/Spells/UnempoweredLs';
//Items
import EmeraldDreamcatcher from './Modules/Items/EmeraldDreamcatcher';

class CombatLogParser extends MainCombatLogParser {
  static specModules = {
    haste: Haste,
      // Features
    damageDone: [DamageDone, { showStatistic: true }],
    castEfficiency: CastEfficiency,
    alwaysBeCasting: AlwaysBeCasting,
      // Modules made but not loaded in the first PR
    moonfire: Moonfire,
    sunfire: Sunfire,
    newmoon: NewMoon,
    halfmoon: HalfMoon,
    fullmoon: FullMoon,
      // solarunemp: SolarUnemp,
      // lunarumep: LunarUnemp,
    lsempowerment: LEmpowerment,
    swempowerment: SEmpowerment,
    astralpower: AstralPower,
    unempoweredLS: UnempoweredLs,
    //Items
    emeraldDreamcatcher: EmeraldDreamcatcher,
  };

  generateResults() {
    const results = super.generateResults();

    results.tabs = [
      {
        title: 'Suggestions',
        url: 'suggestions',
        render: () => (
          <SuggestionsTab issues={results.issues} />
          ),
      },
      ...results.tabs,
    ];

    return results;
  }
}

export default CombatLogParser;
<commit_msg>Reorganize and clean up Parser<commit_after>import React from 'react';

import SuggestionsTab from 'Main/SuggestionsTab';

import MainCombatLogParser from 'Parser/Core/CombatLogParser';
import DamageDone from 'Parser/Core/Modules/DamageDone';

import Haste from './Modules/Core/Haste';

//Features
import AlwaysBeCasting from './Modules/Features/AlwaysBeCasting';
import AstralPower from './Modules/Features/AstralPower';
import CastEfficiency from './Modules/Features/CastEfficiency';
import LEmpowerment from './Modules/Features/LunarEmpowerment';
import SEmpowerment from './Modules/Features/SolarEmpowerment';

//Spells
import FullMoon from './Modules/Spells/FullMoon';
import HalfMoon from './Modules/Spells/HalfMoon';
import Moonfire from './Modules/Spells/Moonfire';
import NewMoon from './Modules/Spells/NewMoon';
import Sunfire from './Modules/Spells/Sunfire';
import UnempoweredLs from './Modules/Spells/UnempoweredLs';

//Items
import EmeraldDreamcatcher from './Modules/Items/EmeraldDreamcatcher';

class CombatLogParser extends MainCombatLogParser {
  static specModules = {
    haste: Haste,
    damageDone: [DamageDone, { showStatistic: true }],
    // Features
    alwaysBeCasting: AlwaysBeCasting,
    astralpower: AstralPower,
    castEfficiency: CastEfficiency,
    lsempowerment: LEmpowerment,
    swempowerment: SEmpowerment,
    //Spells
    fullmoon: FullMoon,
    halfmoon: HalfMoon,
    moonfire: Moonfire,
    newmoon: NewMoon,
    sunfire: Sunfire,
    unempoweredLS: UnempoweredLs,
    //Items
    emeraldDreamcatcher: EmeraldDreamcatcher,
  };

  generateResults() {
    const results = super.generateResults();

    results.tabs = [
      {
        title: 'Suggestions',
        url: 'suggestions',
        render: () => (
          <SuggestionsTab issues={results.issues} />
          ),
      },
      ...results.tabs,
    ];

    return results;
  }
}

export default CombatLogParser;
<|endoftext|>


<commit_before>/*
 * I.js, simple helper to manage localized strings.
 * https://github.com/RobertoPrevato/jQuery-DataEntry
 *
 * Copyright 2015, Roberto Prevato
 * http://ugrose.com
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */
var I = {

	//default locale
	locale: 'en',

	current: function () {
		return this.regional[this.locale];
	},

	setLocale: function (locale) {
		this.locale = locale;
		//add to body
		for (var x in this.regional)
			$('body').removeClass(x.toLowerCase());
		$('body').addClass(locale.toLowerCase());
	},

	regional: {},

	//function to return localized strings
	t: function (key, options) {
		options = options || {};
		if (!this.regional[this.locale]) return ['Missing regional for: ', this.locale].join('');
		var w = '', o = this.regional[this.locale], parts = key.split(/\./g);
		while (w = parts.shift()) {
			if (!o) return ['Missing translation for: ', key].join('');
			o = o[w];
		}
		if (o) {
			if (typeof o == 'object') return o;
			return o;
		}
		return ['Missing translation for: ', this.locale, '.', key].join('');
		this.regional[this.locale][key] || '';
	},

	lookup: function (key) {
		//returns true if the
		if (!this.regional[this.locale]) return ['Missing regional for: ', this.locale].join('');
		var w = '', o = this.regional[this.locale], parts = key.split(/\./g);
		while (w = parts.shift()) {
      if (!o) return false;
      o = o[w];
    }
		return typeof o != "undefined";
	},

  tryGet: function (key) {
    return this.lookup(key) ? this.t(key) : null;
  }

};<commit_msg>Fixes indentations in file.<commit_after>/*
 * I.js, simple helper to manage localized strings.
 * https://github.com/RobertoPrevato/jQuery-DataEntry
 *
 * Copyright 2015, Roberto Prevato
 * http://ugrose.com
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */
var I = {

  //default locale
  locale: "en",

  current: function () {
    return this.regional[this.locale];
  },

  setLocale: function (locale) {
    this.locale = locale;
    //add to body
    for (var x in this.regional)
      $("body").removeClass(x.toLowerCase());
    $("body").addClass(locale.toLowerCase());
  },

  regional: {},

  //function to return localized strings
  t: function (key, options) {
    options = options || {};
    if (!this.regional[this.locale]) return ["Missing regional for: ", this.locale].join("");
    var w = "", o = this.regional[this.locale], parts = key.split(/\./g);
    while (w = parts.shift()) {
      if (!o) return ["Missing translation for: ", key].join("");
      o = o[w];
    }
    if (o) {
      if (typeof o == "object") return o;
      return o;
    }
    return ["Missing translation for: ", this.locale, ".", key].join("");
  },

  lookup: function (key) {
    //returns true if the
    if (!this.regional[this.locale]) return ["Missing regional for: ", this.locale].join("");
    var w = "", o = this.regional[this.locale], parts = key.split(/\./g);
    while (w = parts.shift()) {
      if (!o) return false;
      o = o[w];
    }
    return typeof o != "undefined";
  },

  tryGet: function (key) {
    return this.lookup(key) ? this.t(key) : null;
  }

};<|endoftext|>


<commit_before>(function ($) {
	$(document).on('change', '.preference :checkbox', function () {
		var childBlock = $(this).data('tiki-admin-child-block')
			, childMode = $(this).data('tiki-admin-child-mode')
			, checked = $(this).is(':checked')
			, disabled = $(this).prop('disabled')
			;

		if (childMode === 'invert') {
			checked = ! checked;
		}

		if (disabled || ! checked) {
			$(childBlock).hide('fast');
		} else {
			$(childBlock).show('fast');
		}
	});

	$(document).on('click', '.pref-reset-wrapper a', function () {
		var box = $(this).closest('span').find(':checkbox');
		box.click();
		var $i = $(this).find("img");
		if ($i.attr("src").indexOf("undo") > -1) {
			$i.attr({
				"src": $i.attr("src").replace("undo", "redo"),
				"title": "Restore current value",
				"alt": "Restore current value"
			});
		} else {
			$i.attr({
				"src": $i.attr("src").replace("redo", "undo"),
				"title": "Reset to default",
				"alt": "Reset to default"
			});
		}
		return false;
	});

	$(document).on('click', '.pref-reset', function() {
		var c = $(this).prop('checked');
		var $el = $(this).closest('.adminoptionbox').find('input:not(:hidden),select,textarea')
			.not('.system').attr( 'disabled', c )
			.css("opacity", c ? .6 : 1 );
		var defval = $(this).data('preference-default');

		if ($el.is(':checkbox')) {
			$(this).data('preference-default', $el.prop('checked') ? 'y' : 'n');
			$el.prop('checked', defval === "y");
		} else {
			$(this).data('preference-default', $el.val());
			$el.val(defval);
		}
		$el.change();
		if (jqueryTiki.chosen) {
			$el.trigger("chosen:updated");
		}
	});

	$(document).on('change', '.preference select', function () {
		var childBlock = $(this).data('tiki-admin-child-block')
			, selected = $(this).val()
			;

		$(childBlock).hide();

		if (selected && /^[\w-]+$/.test(selected)) {
			$(childBlock).filter('.' + selected).show();
		}
	});

	$(document).on('change', '.preference :radio', function () {
		var childBlock = $(this).data('tiki-admin-child-block')

		if ($(this).prop('checked')) {
			$(childBlock).show('fast');
			$(this).closest('.preference').find(':radio').not(this).change();
		} else {
			$(childBlock).hide();
		}
	});

	$(function () {
		$('.preference :checkbox, .preference select, .preference :radio').change();

		$('.pref-reset')
			.wrap('')
			.closest('span')
			.append('')
			;
	});
})(jQuery);
<commit_msg>[FIX] Forced enable should display child container<commit_after>(function ($) {
	$(document).on('change', '.preference :checkbox', function () {
		var childBlock = $(this).data('tiki-admin-child-block')
			, childMode = $(this).data('tiki-admin-child-mode')
			, checked = $(this).is(':checked')
			, disabled = $(this).prop('disabled')
			;

		if (childMode === 'invert') {
			checked = ! checked;
		}

		if (disabled && checked) {
			$(childBlock).show('fast');
		} else if (disabled || ! checked) {
			$(childBlock).hide('fast');
		} else {
			$(childBlock).show('fast');
		}
	});

	$(document).on('click', '.pref-reset-wrapper a', function () {
		var box = $(this).closest('span').find(':checkbox');
		box.click();
		var $i = $(this).find("img");
		if ($i.attr("src").indexOf("undo") > -1) {
			$i.attr({
				"src": $i.attr("src").replace("undo", "redo"),
				"title": "Restore current value",
				"alt": "Restore current value"
			});
		} else {
			$i.attr({
				"src": $i.attr("src").replace("redo", "undo"),
				"title": "Reset to default",
				"alt": "Reset to default"
			});
		}
		return false;
	});

	$(document).on('click', '.pref-reset', function() {
		var c = $(this).prop('checked');
		var $el = $(this).closest('.adminoptionbox').find('input:not(:hidden),select,textarea')
			.not('.system').attr( 'disabled', c )
			.css("opacity", c ? .6 : 1 );
		var defval = $(this).data('preference-default');

		if ($el.is(':checkbox')) {
			$(this).data('preference-default', $el.prop('checked') ? 'y' : 'n');
			$el.prop('checked', defval === "y");
		} else {
			$(this).data('preference-default', $el.val());
			$el.val(defval);
		}
		$el.change();
		if (jqueryTiki.chosen) {
			$el.trigger("chosen:updated");
		}
	});

	$(document).on('change', '.preference select', function () {
		var childBlock = $(this).data('tiki-admin-child-block')
			, selected = $(this).val()
			;

		$(childBlock).hide();

		if (selected && /^[\w-]+$/.test(selected)) {
			$(childBlock).filter('.' + selected).show();
		}
	});

	$(document).on('change', '.preference :radio', function () {
		var childBlock = $(this).data('tiki-admin-child-block')

		if ($(this).prop('checked')) {
			$(childBlock).show('fast');
			$(this).closest('.preference').find(':radio').not(this).change();
		} else {
			$(childBlock).hide();
		}
	});

	$(function () {
		$('.preference :checkbox, .preference select, .preference :radio').change();

		$('.pref-reset')
			.wrap('')
			.closest('span')
			.append('')
			;
	});
})(jQuery);
<|endoftext|>


<commit_before>'use strict';
var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
var mountFolder = function (connect, dir) {
    return connect.static(require('path').resolve(dir));
};

module.exports = function (grunt) {
    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    // configurable paths
    var yeomanConfig = {
        app: 'app',
        dist: 'dist'
    };

    grunt.initConfig({
        yeoman: yeomanConfig,
        watch: {
            coffee: {
                files: ['<%%= yeoman.app %>/scripts/*.coffee'],
                tasks: ['coffee:dist']
            },
            coffeeTest: {
                files: ['test/spec/*.coffee'],
                tasks: ['coffee:test']
            },
            compass: {
                files: ['<%%= yeoman.app %>/styles/*.{scss,sass}'],
                tasks: ['compass']
            },
            livereload: {
                files: [
                    '<%%= yeoman.app %>/*.html',
                    '{.tmp,<%%= yeoman.app %>}/styles/*.css',
                    '{.tmp,<%%= yeoman.app %>}/scripts/*.js',
                    '<%%= yeoman.app %>/images/*.{png,jpg,jpeg}'
                ],
                tasks: ['livereload']
            }
        },
        connect: {
            options: {
                port: 9000,
                // Change this to '0.0.0.0' to access the server from outside.
                hostname: 'localhost'
            },
            livereload: {
                options: {
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            mountFolder(connect, '.tmp'),
                            mountFolder(connect, 'app')
                        ];
                    }
                }
            },
            test: {
                options: {
                    middleware: function (connect) {
                        return [
                            mountFolder(connect, '.tmp'),
                            mountFolder(connect, 'test')
                        ];
                    }
                }
            },
            dist: {
                options: {
                    middleware: function (connect) {
                        return [
                            mountFolder(connect, 'dist')
                        ];
                    }
                }
            }
        },
        open: {
            server: {
                url: 'http://localhost:<%%= connect.options.port %>'
            }
        },
        clean: {
            dist: ['.tmp', '<%%= yeoman.dist %>/*'],
            server: '.tmp'
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            all: [
                'Gruntfile.js',
                '<%%= yeoman.app %>/scripts/*.js',
                'test/spec/*.js'
            ]
        },
        mocha: {
            all: {
                options: {
                    run: true,
                    urls: ['http://localhost:<%%= connect.options.port %>/index.html']
                }
            }
        },
        coffee: {
            dist: {
                files: {
                    '.tmp/scripts/coffee.js': '<%%= yeoman.app %>/scripts/*.coffee'
                }
            },
            test: {
                files: [{
                    expand: true,
                    cwd: '.tmp/spec',
                    src: '*.coffee',
                    dest: 'test/spec'
                }]
            }
        },
        compass: {
            options: {
                sassDir: '<%%= yeoman.app %>/styles',
                cssDir: '.tmp/styles',
                imagesDir: '<%%= yeoman.app %>/images',
                javascriptsDir: '<%%= yeoman.app %>/scripts',
                fontsDir: '<%%= yeoman.app %>/styles/fonts',
                importPath: 'app/components',
                relativeAssets: true
            },
            dist: {},
            server: {
                options: {
                    debugInfo: true
                }
            }
        },
        // not used since Uglify task does concat,
        // but still available if needed
        /*concat: {
            dist: {}
        },*/
        <% if (includeRequireJS) { %>requirejs: {
            dist: {
                // Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
                options: {
                    // `name` and `out` is set by grunt-usemin
                    baseUrl: 'app/scripts',
                    optimize: 'none',
                    // TODO: Figure out how to make sourcemaps work with grunt-usemin
                    // https://github.com/yeoman/grunt-usemin/issues/30
                    //generateSourceMaps: true,
                    // required to support SourceMaps
                    // http://requirejs.org/docs/errors.html#sourcemapcomments
                    preserveLicenseComments: false,
                    useStrict: true,
                    wrap: true,
                    //uglify2: {} // https://github.com/mishoo/UglifyJS2
                    mainConfigFile: 'app/scripts/main.js'
                }
            }
        },<% } else { %>
        uglify: {
            dist: {
                files: {
                    '<%%= yeoman.dist %>/scripts/main.js': [
                        '.tmp/scripts/*.js',
                        '<%%= yeoman.app %>/scripts/*.js'
                    ],
                }
            }
        },<% } %>
        useminPrepare: {
            html: '<%%= yeoman.app %>/index.html',
            options: {
                dest: '<%%= yeoman.dist %>'
            }
        },
        usemin: {
            html: ['<%%= yeoman.dist %>/*.html'],
            css: ['<%%= yeoman.dist %>/styles/*.css'],
            options: {
                dirs: ['<%%= yeoman.dist %>']
            }
        },
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/images',
                    src: '*.{png,jpg,jpeg}',
                    dest: '<%%= yeoman.dist %>/images'
                }]
            }
        },
        cssmin: {
            dist: {
                files: {
                    '<%%= yeoman.dist %>/styles/main.css': [
                        '.tmp/styles/*.css',
                        '<%%= yeoman.app %>/styles/*.css'
                    ]
                }
            }
        },
        htmlmin: {
            dist: {
                options: {
                    /*removeCommentsFromCDATA: true,
                    // https://github.com/yeoman/grunt-usemin/issues/44
                    //collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    removeAttributeQuotes: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true*/
                },
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>',
                    src: '*.html',
                    dest: '<%%= yeoman.dist %>'
                }]
            }
        },
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%%= yeoman.app %>',
                    dest: '<%%= yeoman.dist %>',
                    src: [
                        '*.{ico,txt}',
                        '.htaccess'
                    ]
                }]
            }
        },
        bower: {
            rjsConfig: 'app/scripts/main.js',
            indent: '    '
        }
    });

    grunt.renameTask('regarde', 'watch');

    grunt.registerTask('server', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['open', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'coffee:dist',
            'compass:server',
            'livereload-start',
            'connect:livereload',
            'open',
            'watch'
        ]);
    });

    grunt.registerTask('test', [
        'clean:server',
        'coffee',
        'compass',
        'connect:test',
        'mocha'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'jshint',
        'test',
        'coffee',
        'compass:dist',
        'useminPrepare',<% if (includeRequireJS) { %>
        'requirejs',<% } %>
        'imagemin',
        'cssmin',
        'htmlmin',
        'concat',
        'uglify',
        'copy',
        'usemin'
    ]);

    grunt.registerTask('default', ['build']);
};
<commit_msg>Remove no longer needed config, since usemin now sets it<commit_after>'use strict';
var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
var mountFolder = function (connect, dir) {
    return connect.static(require('path').resolve(dir));
};

module.exports = function (grunt) {
    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    // configurable paths
    var yeomanConfig = {
        app: 'app',
        dist: 'dist'
    };

    grunt.initConfig({
        yeoman: yeomanConfig,
        watch: {
            coffee: {
                files: ['<%%= yeoman.app %>/scripts/*.coffee'],
                tasks: ['coffee:dist']
            },
            coffeeTest: {
                files: ['test/spec/*.coffee'],
                tasks: ['coffee:test']
            },
            compass: {
                files: ['<%%= yeoman.app %>/styles/*.{scss,sass}'],
                tasks: ['compass']
            },
            livereload: {
                files: [
                    '<%%= yeoman.app %>/*.html',
                    '{.tmp,<%%= yeoman.app %>}/styles/*.css',
                    '{.tmp,<%%= yeoman.app %>}/scripts/*.js',
                    '<%%= yeoman.app %>/images/*.{png,jpg,jpeg}'
                ],
                tasks: ['livereload']
            }
        },
        connect: {
            options: {
                port: 9000,
                // Change this to '0.0.0.0' to access the server from outside.
                hostname: 'localhost'
            },
            livereload: {
                options: {
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            mountFolder(connect, '.tmp'),
                            mountFolder(connect, 'app')
                        ];
                    }
                }
            },
            test: {
                options: {
                    middleware: function (connect) {
                        return [
                            mountFolder(connect, '.tmp'),
                            mountFolder(connect, 'test')
                        ];
                    }
                }
            },
            dist: {
                options: {
                    middleware: function (connect) {
                        return [
                            mountFolder(connect, 'dist')
                        ];
                    }
                }
            }
        },
        open: {
            server: {
                url: 'http://localhost:<%%= connect.options.port %>'
            }
        },
        clean: {
            dist: ['.tmp', '<%%= yeoman.dist %>/*'],
            server: '.tmp'
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            all: [
                'Gruntfile.js',
                '<%%= yeoman.app %>/scripts/*.js',
                'test/spec/*.js'
            ]
        },
        mocha: {
            all: {
                options: {
                    run: true,
                    urls: ['http://localhost:<%%= connect.options.port %>/index.html']
                }
            }
        },
        coffee: {
            dist: {
                files: {
                    '.tmp/scripts/coffee.js': '<%%= yeoman.app %>/scripts/*.coffee'
                }
            },
            test: {
                files: [{
                    expand: true,
                    cwd: '.tmp/spec',
                    src: '*.coffee',
                    dest: 'test/spec'
                }]
            }
        },
        compass: {
            options: {
                sassDir: '<%%= yeoman.app %>/styles',
                cssDir: '.tmp/styles',
                imagesDir: '<%%= yeoman.app %>/images',
                javascriptsDir: '<%%= yeoman.app %>/scripts',
                fontsDir: '<%%= yeoman.app %>/styles/fonts',
                importPath: 'app/components',
                relativeAssets: true
            },
            dist: {},
            server: {
                options: {
                    debugInfo: true
                }
            }
        },
        // not used since Uglify task does concat,
        // but still available if needed
        /*concat: {
            dist: {}
        },*/
        <% if (includeRequireJS) { %>requirejs: {
            dist: {
                // Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
                options: {
                    // `name` and `out` is set by grunt-usemin
                    baseUrl: 'app/scripts',
                    optimize: 'none',
                    // TODO: Figure out how to make sourcemaps work with grunt-usemin
                    // https://github.com/yeoman/grunt-usemin/issues/30
                    //generateSourceMaps: true,
                    // required to support SourceMaps
                    // http://requirejs.org/docs/errors.html#sourcemapcomments
                    preserveLicenseComments: false,
                    useStrict: true,
                    wrap: true,
                    //uglify2: {} // https://github.com/mishoo/UglifyJS2
                }
            }
        },<% } else { %>
        uglify: {
            dist: {
                files: {
                    '<%%= yeoman.dist %>/scripts/main.js': [
                        '.tmp/scripts/*.js',
                        '<%%= yeoman.app %>/scripts/*.js'
                    ],
                }
            }
        },<% } %>
        useminPrepare: {
            html: '<%%= yeoman.app %>/index.html',
            options: {
                dest: '<%%= yeoman.dist %>'
            }
        },
        usemin: {
            html: ['<%%= yeoman.dist %>/*.html'],
            css: ['<%%= yeoman.dist %>/styles/*.css'],
            options: {
                dirs: ['<%%= yeoman.dist %>']
            }
        },
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/images',
                    src: '*.{png,jpg,jpeg}',
                    dest: '<%%= yeoman.dist %>/images'
                }]
            }
        },
        cssmin: {
            dist: {
                files: {
                    '<%%= yeoman.dist %>/styles/main.css': [
                        '.tmp/styles/*.css',
                        '<%%= yeoman.app %>/styles/*.css'
                    ]
                }
            }
        },
        htmlmin: {
            dist: {
                options: {
                    /*removeCommentsFromCDATA: true,
                    // https://github.com/yeoman/grunt-usemin/issues/44
                    //collapseWhitespace: true,
                    collapseBooleanAttributes: true,
                    removeAttributeQuotes: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true*/
                },
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>',
                    src: '*.html',
                    dest: '<%%= yeoman.dist %>'
                }]
            }
        },
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%%= yeoman.app %>',
                    dest: '<%%= yeoman.dist %>',
                    src: [
                        '*.{ico,txt}',
                        '.htaccess'
                    ]
                }]
            }
        },
        bower: {
            rjsConfig: 'app/scripts/main.js',
            indent: '    '
        }
    });

    grunt.renameTask('regarde', 'watch');

    grunt.registerTask('server', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['open', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'coffee:dist',
            'compass:server',
            'livereload-start',
            'connect:livereload',
            'open',
            'watch'
        ]);
    });

    grunt.registerTask('test', [
        'clean:server',
        'coffee',
        'compass',
        'connect:test',
        'mocha'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'jshint',
        'test',
        'coffee',
        'compass:dist',
        'useminPrepare',<% if (includeRequireJS) { %>
        'requirejs',<% } %>
        'imagemin',
        'cssmin',
        'htmlmin',
        'concat',
        'uglify',
        'copy',
        'usemin'
    ]);

    grunt.registerTask('default', ['build']);
};
<|endoftext|>


<commit_before>import React from 'react';

import { Anomoly, Versaya, aryu, Zerotorescue, hatra344, niseko } from 'CONTRIBUTORS';
import ITEMS from 'common/ITEMS';
import SPELLS from 'common/SPELLS';
import ItemLink from 'common/ItemLink';
import SpellLink from 'common/SpellLink';

export default [
  {
    date: new Date('2018-05-26'),
    changes: <React.Fragment>The <SpellLink id={SPELLS.CLOUDBURST_TOTEM_TALENT.id} /> buff is now displayed in the timeline.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-05-20'),
    changes: <React.Fragment>Added support for <SpellLink id={SPELLS.DELUGE_TALENT.id} /> and <ItemLink id={ITEMS.ELEMENTAL_REBALANCERS.id}/>.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-05-02'),
    changes: <React.Fragment>Inneficient <SpellLink id={SPELLS.HEALING_WAVE.id} /> casts will now be highlighted in the timeline with a red border.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-04-13'),
    changes: <React.Fragment>Added statistics showing the healing impact of each talent, with support for all talents that directly impact HPS apart from <SpellLink id={SPELLS.CRASHING_WAVES_TALENT.id} />, <SpellLink id={SPELLS.DELUGE_TALENT.id} /> and <SpellLink id={SPELLS.ECHO_OF_THE_ELEMENTS_TALENT.id} />.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-04-13'),
    changes: <React.Fragment>Added a module breaking down your <SpellLink id={SPELLS.UNLEASH_LIFE_TALENT.id} /> usage by spell.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-04-11'),
    changes: 'Implemented Stat Values for Restoration Shaman.',
    contributors: [niseko],
  },
  {
    date: new Date('2018-03-28'),
    changes: <React.Fragment>Added a Tab detailing the <SpellLink id={SPELLS.DEEP_HEALING.id} /> effectiveness per player.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-03-24'),
    changes: <React.Fragment>Reworked the <SpellLink id={SPELLS.TIDAL_WAVES_BUFF.id} /> statistics, making them easier to read.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-03-16'),
    changes: <React.Fragment>Added a <SpellLink id={SPELLS.RESURGENCE.id} /> module, detailing how much each spell contributed to your mana pool.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-03-15'),
    changes: <React.Fragment>Added support for DPS spells, <SpellLink id={SPELLS.CHAIN_HEAL.id} />, <SpellLink id={SPELLS.UNLEASH_LIFE_TALENT.id} /> and <SpellLink id={SPELLS.WELLSPRING_TALENT.id} /> to the timeline. Added talents to the Checklist.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-01-16'),
    changes: 'Added support for purify spirit to timeline.',
    contributors: [hatra344],
  },
  {
    date: new Date('2017-12-24'),
    changes: 'Implemented the checklist.',
    contributors: [hatra344],
  },
  {
    date: new Date('2017-11-29'),
    changes: <React.Fragment>Added in T21 2 set and 4 set healing contribution values.</React.Fragment>,
    contributors: [Anomoly],
  },
  {
    date: new Date('2017-11-16'),
    changes: <React.Fragment>Fix crash when using <ItemLink id={ITEMS.FOCUSER_OF_JONAT.id} />.</React.Fragment>,
    contributors: [Zerotorescue],
  },
  {
    date: new Date('2017-11-16'),
    changes: 'Refactored Restoration Shaman spec to be in line with current spec module implementations.',
    contributors: [Anomoly],
  },
  {
    date: new Date('2017-08-20'),
    changes: 'Added Ancestral Vigor metric.',
    contributors: [aryu],
  },
  {
    date: new Date('2017-07-06'),
    changes: 'Fix crash when CBT, AG or Ascendance was cast before pull.',
    contributors: [Versaya],
  },
  {
    date: new Date('2017-05-29'),
    changes: 'Added overhealing in Cast Efficiency tab for some resto shaman spells. Fixed Uncertain Reminder in case of pre-lust. Added GotQ target efficiency. Don\'t allow CBT healing to feed into CBT.',
    contributors: [Versaya],
  },
  {
    date: new Date('2017-05-28'),
    changes: 'Added the initial support.',
    contributors: [Versaya],
  },
];
<commit_msg>fix eslint complaints<commit_after>import React from 'react';

import { Anomoly, Versaya, aryu, Zerotorescue, hatra344, niseko } from 'CONTRIBUTORS';
import ITEMS from 'common/ITEMS';
import SPELLS from 'common/SPELLS';
import ItemLink from 'common/ItemLink';
import SpellLink from 'common/SpellLink';

export default [
  {
    date: new Date('2018-05-26'),
    changes: <React.Fragment>The <SpellLink id={SPELLS.CLOUDBURST_TOTEM_TALENT.id} /> buff is now displayed in the timeline.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-05-20'),
    changes: <React.Fragment>Added support for <SpellLink id={SPELLS.DELUGE_TALENT.id} /> and <ItemLink id={ITEMS.ELEMENTAL_REBALANCERS.id} />.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-05-02'),
    changes: <React.Fragment>Inneficient <SpellLink id={SPELLS.HEALING_WAVE.id} /> casts will now be highlighted in the timeline with a red border.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-04-13'),
    changes: <React.Fragment>Added statistics showing the healing impact of each talent, with support for all talents that directly impact HPS apart from <SpellLink id={SPELLS.CRASHING_WAVES_TALENT.id} />, <SpellLink id={SPELLS.DELUGE_TALENT.id} /> and <SpellLink id={SPELLS.ECHO_OF_THE_ELEMENTS_TALENT.id} />.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-04-13'),
    changes: <React.Fragment>Added a module breaking down your <SpellLink id={SPELLS.UNLEASH_LIFE_TALENT.id} /> usage by spell.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-04-11'),
    changes: 'Implemented Stat Values for Restoration Shaman.',
    contributors: [niseko],
  },
  {
    date: new Date('2018-03-28'),
    changes: <React.Fragment>Added a Tab detailing the <SpellLink id={SPELLS.DEEP_HEALING.id} /> effectiveness per player.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-03-24'),
    changes: <React.Fragment>Reworked the <SpellLink id={SPELLS.TIDAL_WAVES_BUFF.id} /> statistics, making them easier to read.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-03-16'),
    changes: <React.Fragment>Added a <SpellLink id={SPELLS.RESURGENCE.id} /> module, detailing how much each spell contributed to your mana pool.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-03-15'),
    changes: <React.Fragment>Added support for DPS spells, <SpellLink id={SPELLS.CHAIN_HEAL.id} />, <SpellLink id={SPELLS.UNLEASH_LIFE_TALENT.id} /> and <SpellLink id={SPELLS.WELLSPRING_TALENT.id} /> to the timeline. Added talents to the Checklist.</React.Fragment>,
    contributors: [niseko],
  },
  {
    date: new Date('2018-01-16'),
    changes: 'Added support for purify spirit to timeline.',
    contributors: [hatra344],
  },
  {
    date: new Date('2017-12-24'),
    changes: 'Implemented the checklist.',
    contributors: [hatra344],
  },
  {
    date: new Date('2017-11-29'),
    changes: <React.Fragment>Added in T21 2 set and 4 set healing contribution values.</React.Fragment>,
    contributors: [Anomoly],
  },
  {
    date: new Date('2017-11-16'),
    changes: <React.Fragment>Fix crash when using <ItemLink id={ITEMS.FOCUSER_OF_JONAT.id} />.</React.Fragment>,
    contributors: [Zerotorescue],
  },
  {
    date: new Date('2017-11-16'),
    changes: 'Refactored Restoration Shaman spec to be in line with current spec module implementations.',
    contributors: [Anomoly],
  },
  {
    date: new Date('2017-08-20'),
    changes: 'Added Ancestral Vigor metric.',
    contributors: [aryu],
  },
  {
    date: new Date('2017-07-06'),
    changes: 'Fix crash when CBT, AG or Ascendance was cast before pull.',
    contributors: [Versaya],
  },
  {
    date: new Date('2017-05-29'),
    changes: 'Added overhealing in Cast Efficiency tab for some resto shaman spells. Fixed Uncertain Reminder in case of pre-lust. Added GotQ target efficiency. Don\'t allow CBT healing to feed into CBT.',
    contributors: [Versaya],
  },
  {
    date: new Date('2017-05-28'),
    changes: 'Added the initial support.',
    contributors: [Versaya],
  },
];
<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {

	grunt.initConfig({
		watch: {
			css: {
				files: [<% if (includeLESS) { %>
					'app/wp-content/themes/<%= themeName %>/assets/less/*.less',
					'app/wp-content/themes/<%= themeName %>/assets/less/site/*.less'<% } if (includeSASS) { %>
					'app/wp-content/themes/<%= themeName %>/assets/sass/*.scss',
					'app/wp-content/themes/<%= themeName %>/assets/sass/site/*.scss'<% } %>
				],
				tasks: [<% if (includeLESS) { %>
					'less:development'<% } if (includeSASS) { %>
					'sass:development'<% } %>
				],
				options: {
					livereload: true
				}
			},
			js: {
				files: [
					'app/wp-content/themes/<%= themeName %>/assets/js/*.js',
					'Gruntfile.js'
				],
				tasks: ['jshint'],
				options: {
					livereload: true,
				}
			}
		},
		browser_sync: {
			files: {
				src : [
					'app/wp-content/themes/<%= themeName %>/*.css',
					'app/wp-content/themes/<%= themeName %>/assets/img/*',
					'app/wp-content/themes/<%= themeName %>/assets/js/*.js',
					'app/wp-content/themes/<%= themeName %>/{,*/}*.php'
				],
			},
			options: {
				watchTask: true
			}
		},
		<% if (includeLESS) { %>
		less: {
			development: {
				options: {
					paths: 'app/wp-content/themes/<%= themeName %>/'
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/less/style.less'
				}
			},
			production: {
				options: {
					paths: 'app/wp-content/themes/<%= themeName %>/',
					cleancss: true
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/less/style.less'
				}
			}
		},<% } if (includeSASS) { %>
		sass: {
			development: {
				files: {
					'app/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/sass/style.scss'
				}
			},
			production: {
				options: {
					style: 'compressed'
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/sass/style.scss'
				}
			}
		},<% } %>
		clean: {
			dist: {
				files: [{
					dot: true,
					src: [
						'dist/*',
						'dist/.git*'
					]
				}]
			}
		},
		jshint: {
			options: {
				jshintrc: '.jshintrc'
			},
			all: [
				'Gruntfile.js',
				'app/wp-content/themes/<%= themeName %>/assets/js/{,*/}*.js'
			]
		},<% if (includeSASS) { %>
		// Configuration needs to be completed
		compass: {
			options: {
				sassDir: 'app/wp-content/themes/<%= themeName %>',
				cssDir: 'app/wp-content/themes/<%= themeName %>',
				generatedImagesDir: 'app/wp-content/themes/<%= themeName %>/img',
				imagesDir: 'app/wp-content/themes/<%= themeName %>/img',
				javascriptsDir: 'app/wp-content/themes/<%= themeName %>/js',
				fontsDir: 'app/wp-content/themes/<%= themeName %>/css/fonts',
				httpImagesPath: 'app/wp-content/themes/<%= themeName %>/img',
				httpGeneratedImagesPath: 'app/wp-content/themes/<%= themeName %>/img',
				httpFontsPath: 'app/wp-content/themes/<%= themeName %>/fonts',
				relativeAssets: false
			},
			dist: {
				options: {
					generatedImagesDir: 'dist/wp-content/themes/<%= themeName %>/img/generated'
				}
			}
		},<% } if (includeRequireJS) { %>
		requirejs: {
			dist: {
				// Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
				options: {
					// `name` and `out` is set by grunt-usemin
					baseUrl: 'app/wp-content/themes/<%= themeName %>/assets/js',
					mainConfigFile: 'app/wp-content/themes/<%= themeName %>/assets/js/main.js',
					paths: {
						jquery: 'empty:',
						underscore: 'empty:',
						app: 'app'
					},
					dir: 'dist/wp-content/themes/<%= themeName %>/assets/js',
					shim: {
						underscore: {
							deps: ['jquery'],
							exports: '_'
						},
						app: {
							deps: ['jquery', 'underscore']
						}
					}
				}
			}
		},<% } %>
		imagemin: {
			dist: {
				files: [{
					expand: true,
					cwd: 'app/wp-content/themes/<%= themeName %>/assets/img',
					src: '{,*/}*.{png,jpg,jpeg}',
					dest: 'dist/wp-content/themes/<%= themeName %>/assets/img'
				}]
			}
		},
		svgmin: {
			dist: {
				files: [{
					expand: true,
					cwd: 'wp-content/themes/<%= themeName %>/assets/img',
					src: '{,*/}*.svg',
					dest: 'dist/wp-content/themes/<%= themeName %>/assets/img'
				}]
			}
		},
		// Put files not handled in other tasks here
		copy: {
			dist: {
				files: [{
					expand: true,
					dot: true,
					cwd: 'app',
					dest: 'dist',
					src: [
						'*.{ico,png,txt,php}',
						'.htaccess',
						'wp-admin/*',
						'wp-includes/*',
						'wp-content/plugins/*',
						'wp-content/themes/<%= themeName %>/*.{php,md,png,css}',
						'wp-content/themes/<%= themeName %>/templates/*',
						'wp-content/themes/<%= themeName %>/lib/*',
						'wp-content/themes/<%= themeName %>/lang/*',
						'wp-content/themes/<%= themeName %>/assets/fonts/{,*/}*.*'
					]
				}]
			}
		},
		concurrent: {
			dist: [
				<% if (includeSASS) { %>
				'compass',
				<% } %>
				'imagemin',
				'svgmin'
			]
		}
	});

	// Load the Grunt plugins.
	<% if (includeLESS) { %>
	grunt.loadNpmTasks('grunt-contrib-less');
	<% } if (includeSASS) { %>
	grunt.loadNpmTasks('grunt-contrib-sass');
	<% } %>
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-browser-sync');
	grunt.loadNpmTasks('grunt-contrib-requirejs');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-svgmin');
	grunt.loadNpmTasks('grunt-concurrent');

	grunt.registerTask('build', [
		'clean:dist',
		'concurrent:dist',
		'requirejs',
		'copy:dist'
	]);

	grunt.registerTask('default', [
		'browser_sync',
		'watch',
		'jshint',
		'build'
	]);
};
<commit_msg>update to grunfile<commit_after>'use strict';

module.exports = function(grunt) {
	var app = 'app/wp-content/themes/<%= themeName %>/';
	var dist = 'dist/wp-content/themes/<%= themeName %>/';

	grunt.initConfig({
		watch: {
			css: {
				files: [<% if (includeLESS) { %>
					app + '/assets/less/*.less',
					app + '/assets/less/site/*.less'<% } if (includeSASS) { %>
					app + '/assets/sass/*.scss',
					app + '/assets/sass/site/*.scss'<% } %>
				],
				tasks: [<% if (includeLESS) { %>
					'less:development'<% } if (includeSASS) { %>
					'sass:development'<% } %>
				],
				options: {
					livereload: true
				}
			},
			js: {
				files: [
					app + '/assets/js/*.js',
					'Gruntfile.js'
				],
				tasks: ['jshint'],
				options: {
					livereload: true,
				}
			}
		},
		browser_sync: {
			files: {
				src : [
					app + '*.css',
					app + 'assets/img/*',
					app + 'assets/js/*.js',
					app + '{,*/}*.php'
				],
			},
			options: {
				watchTask: true
				host: '<%= themeName %>',
				port: 8888
			}
		}, <% if (includeLESS) { %>
		less: {
			development: {
				options: {
					sourceMap: true,
					sourceMapFilename: app + '/style.css.map',
					sourceMapURL: '/wp-content/themes/<%= themeName %> /style.css.map',
					sourceMapBasepath: 'public',
					sourceMapRootpath: '/'
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/less/style.less'
				}
			},
			dist: {
				options: {
					paths: app,
					sourceMap: false,
					cleancss: true,
					compress: true
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/less/style.less'
				}
			}
		},<% } if (includeSASS) { %>
		sass: {
			development: {
				options: {
					sourceMap: true,
					sourceMapFilename: app + 'style.css.map',
					sourceMapURL: app + 'style.css.map',
					sourceMapBasepath: 'public',
					sourceMapRootpath: '/'
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/sass/style.scss'
				}
			},
			dist: {
				options: {
					style: 'compressed',
					sourceMap: false
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/sass/style.scss'
				}
			}
		},<% } %>
		clean: {
			dist: {
				files: [{
					dot: true,
					src: [
						'dist/*',
						'dist/.git*'
					]
				}]
			}
		},
		jshint: {
			options: {
				jshintrc: '.jshintrc'
			},
			all: [
				'Gruntfile.js',
				app + 'assets/js/{,*/}*.js'
			]
		},<% if (includeSASS) { %>
		// Configuration needs to be completed
		compass: {
			options: {
				sassDir: app,
				cssDir: app,
				generatedImagesDir: app + 'img',
				imagesDir: app + 'img',
				javascriptsDir: app + 'js',
				fontsDir: app + 'css/fonts',
				httpImagesPath: app + 'img',
				httpGeneratedImagesPath: app + 'img',
				httpFontsPath: app + 'fonts',
				relativeAssets: false
			},
			dist: {
				options: {
					generatedImagesDir: app + 'img/generated'
				}
			}
		},<% } if (includeRequireJS) { %>
		requirejs: {
			dist: {
				// Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
				options: {
					// `name` and `out` is set by grunt-usemin
					baseUrl: app + 'assets/js',
					mainConfigFile: app + 'assets/js/main.js',
					paths: {
						jquery: 'empty:',
						underscore: 'empty:',
						app: 'app'
					},
					dir: dist + 'assets/js',
					shim: {
						underscore: {
							deps: ['jquery'],
							exports: '_'
						},
						app: {
							deps: ['jquery', 'underscore']
						}
					}
				}
			}
		},<% } %>
		imagemin: {
			dist: {
				files: [{
					expand: true,
					cwd: app + 'assets/images',
					src: '**/*.{png,jpg,jpeg}',
					dest: dist + 'assets/images'
				}],
				options: {
					cache: false
				}
			}
		},
		svgmin: {
			dist: {
				files: [{
					expand: true,
					cwd: app + 'assets/images',
					src: '**/*.svg',
					dest: dist + 'assets/images'
				}]
			}
		},
		preprocess: {
			dev: {
				options: {
					context: {
						NODE_ENV: 'DEVELOPMENT'
					},
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/base.php': 'app/wp-content/themes/<%= themeName %>/base-template.html'
				},
			},
			dist: {
				options: {
					context: {
						NODE_ENV: 'PRODUCTION'
					},
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/base.php': 'app/wp-content/themes/<%= themeName %>/base-template.html'
				},
			},
		},
		// Put files not handled in other tasks here
		copy: {
			dist: {
				files: [{
					expand: true,
					dot: true,
					cwd: 'app',
					dest: 'dist',
					src: [
						'*.{ico,png,txt,php}',
						'.htaccess',
						'wp-admin/*',
						'wp-includes/*',
						'wp-content/plugins/*',
						'wp-content/themes/<%= themeName %>/*.{php,md,png,css}',
						'wp-content/themes/<%= themeName %>/templates/*',
						'wp-content/themes/<%= themeName %>/lib/*',
						'wp-content/themes/<%= themeName %>/lang/*',
						'wp-content/themes/<%= themeName %>/assets/fonts/{,*/}*.*'
					]
				}]
			}
		},
		hashres: {
			options: {
				encoding: 'utf8',
				fileNameFormat: '${name}.${ext}?${hash}',
				renameFiles: false
			},
			css: {
				src: [
					dist + 'style.css'
				],
				dest: dist + 'templates/head.php',
			}
		},
		concurrent: {
			dev: ['clean:dist', 'preprocess:dev'],
			build1: ['imagemin:dist', 'copy:dist', 'less:dist'],
			build2: ['preprocess:dist', 'svgmin:dist']

			dist: [	<% if (includeSASS) { %>
				'compass', <% } %>
				'imagemin',
				'svgmin'
			]
		}
	});

	// Load the Grunt plugins.
	<% if (includeLESS) { %>
	grunt.loadNpmTasks('grunt-contrib-less');<% } if (includeSASS) { %>
	grunt.loadNpmTasks('grunt-contrib-sass');<% } %>
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-browser-sync');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-svgmin');
	grunt.loadNpmTasks('grunt-preprocess');
	grunt.loadNpmTasks('grunt-concurrent');
	grunt.loadNpmTasks('grunt-hashres'); <% if (includeRequireJS) { %>
	grunt.loadNpmTasks('grunt-contrib-requirejs'); <% } %>

	grunt.registerTask('build', [
		'clean:dist',
		'concurrent:build1',
		'concurrent:build2',
		'requirejs',
		'hashres'
	]);

	grunt.registerTask('dev', [
		'concurrent:dev',
		'browser_sync',
		'watch'
	]);
};
<|endoftext|>


<commit_before>pref("extensions.{e4a8a97b-f2ed-450b-b12d-ee082ba24781}.description", "chrome://greasemonkey/locale/greasemonkey.properties");
pref("greasemonkey.fileIsGreaseable", false);
pref("greasemonkey.globalExcludes", '[]');
pref("greasemonkey.installDelay", 5);
pref("greasemonkey.unmhtIsGreaseable", false);
pref("greasemonkey.enableScriptRefreshing", true);
pref("greasemonkey.uninstallPreferences", true);
pref("greasemonkey.enableUpdateChecking", false);
pref("greasemonkey.minDaysBetweenUpdateChecks", 7);
pref("greasemonkey.autoInstallUpdates", true);
pref("greasemonkey.requireSecureUpdates", true);
pref("greasemonkey.haveInsertedToolbarbutton", false);
pref("greasemonkey.logChrome", false);
<commit_msg>Script update checking on by default.<commit_after>pref("extensions.{e4a8a97b-f2ed-450b-b12d-ee082ba24781}.description", "chrome://greasemonkey/locale/greasemonkey.properties");
pref("greasemonkey.fileIsGreaseable", false);
pref("greasemonkey.globalExcludes", '[]');
pref("greasemonkey.installDelay", 5);
pref("greasemonkey.unmhtIsGreaseable", false);
pref("greasemonkey.enableScriptRefreshing", true);
pref("greasemonkey.uninstallPreferences", true);
pref("greasemonkey.enableUpdateChecking", true);
pref("greasemonkey.minDaysBetweenUpdateChecks", 7);
pref("greasemonkey.autoInstallUpdates", true);
pref("greasemonkey.requireSecureUpdates", true);
pref("greasemonkey.haveInsertedToolbarbutton", false);
pref("greasemonkey.logChrome", false);
<|endoftext|>