<commit_before>'use strict';

var fs = require('fs'),
    path = require('path');

var grayMatter = require('gray-matter'),
    gUtil = require('gulp-util'),
    jade = require('jade'),
    marked = require('marked'),
    merge = require('merge'),
    highlightjs = require('highlight.js'),
    slug = require('slug'),
    through = require('through2');

var chalk = gUtil.colors,
    log = gUtil.log,
    logFlag = chalk.gray('[') + chalk.magenta('SSG') + chalk.gray(']'),
    PluginError = gUtil.PluginError;

/**
 * static site generator gulp plugin
 * @param  {options} options custom options (see readme)
 * @return {object}          destroyable transform object
 */
function staticSiteGenerator(options) {

  var buffer = {},
      layoutCache = {},
      templateCache = {},
      markedRenderer = new marked.Renderer();

  options = merge.recursive({
    basePath: '/',
    data: {},
    defaultLayout: false,
    jade: jade,
    jadeOptions: {
      basedir: path.join(process.cwd(), 'src')
    },
    layoutPath: 'layouts',
    marked: marked,
    markedOptions: {
      renderer: markedRenderer
    },
    passThrough: true,
    prettyUrls: true,
    regexpHtml: /\.html$/i,
    regexpMarkdown: /\.(md|markdown)$/i,
    regexpTemplate: /\.jade$/i,
    renderCode: renderCode,
    renderTemplate: renderTemplate,
    renderMarkdown: renderMarkdown,
    slugify: true,
    slugOptions: {
      mode: 'rfc3986',
      remove: /^\./g
    }
  }, options || {});

  options.markedOptions.renderer.code = options.renderCode;
  options.marked.setOptions(options.markedOptions);
  options.jade.filters.markdown = options.renderMarkdown;

  return through.obj(transformChunk);

  /**
   * transforms a stream chunk
   * @param  {object}   chunk    chunk object
   * @param  {string}   encoding file encoding
   * @param  {Function} done     callback
   * @return {undefined}
   */
  function transformChunk(chunk, encoding, done) {
    if (chunk.isNull()) return done();
    if (chunk.isStream()) return this.emit('error', new PluginError(logFlag, 'Streaming not supported'));
    if (
      !(chunk.isMarkdown = options.regexpMarkdown.test(chunk.relative)) &&
      !(chunk.isTemplate = options.regexpTemplate.test(chunk.relative)) &&
      !(chunk.isHtml = options.regexpHtml.test(chunk.relative))
    ) {
      return options.passThrough ? done(null, chunk) : done();
    }
    transformChunkData(chunk);
    if (chunk.data.draft && process.env.NODE_ENV !== 'development') return done();
    if (buffer.hasOwnProperty(chunk.relative)) {
      logDuplicate(chunk);
      return done();
    }
    transformChunkContents.call(this, chunk);
    buffer[chunk.relative] = chunk;
    done(null, chunk);
  }

  /**
   * merge site data, options data, frontmatter data into chunk data
   * @param  {object} chunk stream chunk object
   * @return {object}       chunk with transformed data
   */
  function transformChunkData(chunk) {
    var matter = grayMatter(String(chunk.contents)),
        relPath = chunk.hasOwnProperty('data') && chunk.data.relativePath ?
          chunk.data.relativePath : getRelativePath(chunk.relative),
        absPath = path.normalize(path.join(options.basePath, relPath));
    chunk.data = merge.recursive({},
      options.data,
      {
        basePath: options.basePath,
        relativePath: relPath,
        path: absPath,
        urlPath: options.prettyUrls ? path.dirname(absPath) + '/' : absPath,
        srcBasePath: chunk.base,
        srcRelativePath: chunk.relative,
        srcPath: chunk.path,
        contents: '',
        draft: false,
        layout: options.defaultLayout
      },
      chunk.data || {},
      matter.data
    );
    chunk.contents = new Buffer(matter.content);
    chunk.path = path.join(chunk.base, relPath);
    return chunk;
  }

  /**
   * render chunk contents with markdown renderer, wrap layout, render template
   * @param  {object} chunk stream chunk object
   * @return {object}       chunk with transformed contents
   */
  function transformChunkContents(chunk) {
    var contents = String(chunk.contents);
    try {
      if (chunk.isMarkdown) {
        contents = options.renderMarkdown(contents);
      }
      if (chunk.isTemplate) {
        contents = options.renderTemplate(contents, chunk.data, chunk.data.srcPath);
      }
      chunk.contents = new Buffer(contents);
      if (chunk.data.layout) applyLayout(chunk);
    } catch (err) {
      this.emit('error', new PluginError(logFlag, err.stack || err));
    }
    return chunk;
  }

  /**
   * render a template string with optional data
   * @param  {string} contents template
   * @param  {object} data     optional template data
   * @param  {object} filename optional template path for importing/mergeing
   * @return {string}          rendered template
   */
  function renderTemplate(contents, data, filename) {
    if (!templateCache.hasOwnProperty(contents)) {
      var jadeOptions = merge.recursive({}, options.jadeOptions, {filename: filename});
      templateCache[contents] = options.jade.compile(contents, jadeOptions);
    }
    var locals = merge.recursive({}, data, {locals: locals});
    return templateCache[contents](data);
  }

  /**
   * render a markdown string to html
   * @param  {string} contents markdown
   * @return {string}          html
   */
  function renderMarkdown(contents) {
    return options.marked(contents).trim();
  }

  /**
   * render string of code to highlighted code html structure
   * @param {string}  code source code string
   * @param {string}  lang source code language string
   * @return {string}      html
   */
  function renderCode(code, lang) {
    lang = typeof lang === 'string' && highlightjs.getLanguage(lang) ? lang : false;
    code = lang ? highlightjs.highlight(lang, code).value : highlightjs.highlightAuto(code).value;
    return '
' + code + '
';
  }

  /**
   * set chunk contents as template data property and render it with a layout
   * @param  {object} chunk stream chunk object
   * @return {object}       chunk with applied layout
   */
  function applyLayout(chunk) {
    chunk.data.contents = String(chunk.contents);
    var layout = getLayout(chunk.data.layout),
        contents = options.renderTemplate(layout.contents, chunk.data, layout.path);
    chunk.contents = new Buffer(contents);
    return chunk;
  }

  /**
   * transform a src file path into an relative url path
   * @param  {string} filePath file path
   * @return {string}          url
   */
  function getRelativePath(filePath) {
    var urlPath = path.join(
      path.dirname(filePath),
      path.basename(filePath, path.extname(filePath))
    );
    if (options.slugify) {
      urlPath = urlPath.split('/').map(function(part) {
        return slug(part, options.slugOptions);
      }).join('/');
    }
    urlPath += !options.prettyUrls || (/(^|\/)index$/i).test(urlPath) ?
      '.html' : '/index.html';
    return urlPath;
  }

  /**
   * read a layout file from given path; store it in cache object for further
   * usage; return object with layout contents and absolute path
   * @param  {string}   layout path to layout
   * @return {object}          layout contents and path
   */
  function getLayout(layout) {
    if (!layoutCache.hasOwnProperty(layout)) {
      var layoutContents = false,
          layoutPath = path.join(
        path.isAbsolute(options.layoutPath) ?
          options.layoutPath : path.join(process.cwd(), options.layoutPath),
        layout
      );
      try {
        layoutContents = fs.readFileSync(layoutPath, 'utf8');
      } catch (err) {
        throw new PluginError(logFlag, 'Could not read layout: \'' + layoutPath + '\'\n');
      }
      layoutCache[layout] = {
        contents: layoutContents,
        path: layoutPath
      };
    }
    return layoutCache[layout];
  }

  /**
   * log possible output overwrite to console
   * @param  {object} chunk stream chunk object
   * @return {undefined}
   */
  function logDuplicate(chunk) {
    log(logFlag,
      chalk.red('WARNING: ') +
      chalk.yellow(chunk.data.relativeFilename) +
      ' outputs to same url as ' +
      chalk.yellow(buffer[chunk.relative].data.relativeFilename) +
      '. ' + chalk.red('Skipping...')
    );
  }

}

module.exports = staticSiteGenerator;
<commit_msg>customize warning message for duplicate path<commit_after>'use strict';

var fs = require('fs'),
    path = require('path');

var grayMatter = require('gray-matter'),
    gUtil = require('gulp-util'),
    jade = require('jade'),
    marked = require('marked'),
    merge = require('merge'),
    highlightjs = require('highlight.js'),
    slug = require('slug'),
    through = require('through2');

var chalk = gUtil.colors,
    log = gUtil.log,
    logFlag = chalk.gray('[') + chalk.magenta('SSG') + chalk.gray(']'),
    PluginError = gUtil.PluginError;

/**
 * static site generator gulp plugin
 * @param  {options} options custom options (see readme)
 * @return {object}          destroyable transform object
 */
function staticSiteGenerator(options) {

  var buffer = {},
      layoutCache = {},
      templateCache = {},
      markedRenderer = new marked.Renderer();

  options = merge.recursive({
    basePath: '/',
    data: {},
    defaultLayout: false,
    jade: jade,
    jadeOptions: {
      basedir: path.join(process.cwd(), 'src')
    },
    layoutPath: 'layouts',
    marked: marked,
    markedOptions: {
      renderer: markedRenderer
    },
    passThrough: true,
    prettyUrls: true,
    regexpHtml: /\.html$/i,
    regexpMarkdown: /\.(md|markdown)$/i,
    regexpTemplate: /\.jade$/i,
    renderCode: renderCode,
    renderTemplate: renderTemplate,
    renderMarkdown: renderMarkdown,
    slugify: true,
    slugOptions: {
      mode: 'rfc3986',
      remove: /^\./g
    }
  }, options || {});

  options.markedOptions.renderer.code = options.renderCode;
  options.marked.setOptions(options.markedOptions);
  options.jade.filters.markdown = options.renderMarkdown;

  return through.obj(transformChunk);

  /**
   * transforms a stream chunk
   * @param  {object}   chunk    chunk object
   * @param  {string}   encoding file encoding
   * @param  {Function} done     callback
   * @return {undefined}
   */
  function transformChunk(chunk, encoding, done) {
    if (chunk.isNull()) return done();
    if (chunk.isStream()) return this.emit('error', new PluginError(logFlag, 'Streaming not supported'));
    if (
      !(chunk.isMarkdown = options.regexpMarkdown.test(chunk.relative)) &&
      !(chunk.isTemplate = options.regexpTemplate.test(chunk.relative)) &&
      !(chunk.isHtml = options.regexpHtml.test(chunk.relative))
    ) {
      return options.passThrough ? done(null, chunk) : done();
    }
    transformChunkData(chunk);
    if (chunk.data.draft && process.env.NODE_ENV !== 'development') return done();
    if (buffer.hasOwnProperty(chunk.relative)) {
      logDuplicate(chunk);
      return done();
    }
    transformChunkContents.call(this, chunk);
    buffer[chunk.relative] = chunk;
    done(null, chunk);
  }

  /**
   * merge site data, options data, frontmatter data into chunk data
   * @param  {object} chunk stream chunk object
   * @return {object}       chunk with transformed data
   */
  function transformChunkData(chunk) {
    var matter = grayMatter(String(chunk.contents)),
        relPath = chunk.hasOwnProperty('data') && chunk.data.relativePath ?
          chunk.data.relativePath : getRelativePath(chunk.relative),
        absPath = path.normalize(path.join(options.basePath, relPath));
    chunk.data = merge.recursive({},
      options.data,
      {
        basePath: options.basePath,
        relativePath: relPath,
        path: absPath,
        urlPath: options.prettyUrls ? path.dirname(absPath) + '/' : absPath,
        srcBasePath: chunk.base,
        srcRelativePath: chunk.relative,
        srcPath: chunk.path,
        contents: '',
        draft: false,
        layout: options.defaultLayout
      },
      chunk.data || {},
      matter.data
    );
    chunk.contents = new Buffer(matter.content);
    chunk.path = path.join(chunk.base, relPath);
    return chunk;
  }

  /**
   * render chunk contents with markdown renderer, wrap layout, render template
   * @param  {object} chunk stream chunk object
   * @return {object}       chunk with transformed contents
   */
  function transformChunkContents(chunk) {
    var contents = String(chunk.contents);
    try {
      if (chunk.isMarkdown) {
        contents = options.renderMarkdown(contents);
      }
      if (chunk.isTemplate) {
        contents = options.renderTemplate(contents, chunk.data, chunk.data.srcPath);
      }
      chunk.contents = new Buffer(contents);
      if (chunk.data.layout) applyLayout(chunk);
    } catch (err) {
      this.emit('error', new PluginError(logFlag, err.stack || err));
    }
    return chunk;
  }

  /**
   * render a template string with optional data
   * @param  {string} contents template
   * @param  {object} data     optional template data
   * @param  {object} filename optional template path for importing/mergeing
   * @return {string}          rendered template
   */
  function renderTemplate(contents, data, filename) {
    if (!templateCache.hasOwnProperty(contents)) {
      var jadeOptions = merge.recursive({}, options.jadeOptions, {filename: filename});
      templateCache[contents] = options.jade.compile(contents, jadeOptions);
    }
    var locals = merge.recursive({}, data, {locals: locals});
    return templateCache[contents](data);
  }

  /**
   * render a markdown string to html
   * @param  {string} contents markdown
   * @return {string}          html
   */
  function renderMarkdown(contents) {
    return options.marked(contents).trim();
  }

  /**
   * render string of code to highlighted code html structure
   * @param {string}  code source code string
   * @param {string}  lang source code language string
   * @return {string}      html
   */
  function renderCode(code, lang) {
    lang = typeof lang === 'string' && highlightjs.getLanguage(lang) ? lang : false;
    code = lang ? highlightjs.highlight(lang, code).value : highlightjs.highlightAuto(code).value;
    return '
' + code + '
';
  }

  /**
   * set chunk contents as template data property and render it with a layout
   * @param  {object} chunk stream chunk object
   * @return {object}       chunk with applied layout
   */
  function applyLayout(chunk) {
    chunk.data.contents = String(chunk.contents);
    var layout = getLayout(chunk.data.layout),
        contents = options.renderTemplate(layout.contents, chunk.data, layout.path);
    chunk.contents = new Buffer(contents);
    return chunk;
  }

  /**
   * transform a src file path into an relative url path
   * @param  {string} filePath file path
   * @return {string}          url
   */
  function getRelativePath(filePath) {
    var urlPath = path.join(
      path.dirname(filePath),
      path.basename(filePath, path.extname(filePath))
    );
    if (options.slugify) {
      urlPath = urlPath.split('/').map(function(part) {
        return slug(part, options.slugOptions);
      }).join('/');
    }
    urlPath += !options.prettyUrls || (/(^|\/)index$/i).test(urlPath) ?
      '.html' : '/index.html';
    return urlPath;
  }

  /**
   * read a layout file from given path; store it in cache object for further
   * usage; return object with layout contents and absolute path
   * @param  {string}   layout path to layout
   * @return {object}          layout contents and path
   */
  function getLayout(layout) {
    if (!layoutCache.hasOwnProperty(layout)) {
      var layoutContents = false,
          layoutPath = path.join(
        path.isAbsolute(options.layoutPath) ?
          options.layoutPath : path.join(process.cwd(), options.layoutPath),
        layout
      );
      try {
        layoutContents = fs.readFileSync(layoutPath, 'utf8');
      } catch (err) {
        throw new PluginError(logFlag, 'Could not read layout: \'' + layoutPath + '\'\n');
      }
      layoutCache[layout] = {
        contents: layoutContents,
        path: layoutPath
      };
    }
    return layoutCache[layout];
  }

  /**
   * log possible output overwrite to console
   * @param  {object} chunk stream chunk object
   * @return {undefined}
   */
  function logDuplicate(chunk) {
    log(logFlag,
      chalk.black.bgYellow('WARNING') + ' skipping ' +
      chalk.magenta(chunk.data.srcRelativePath) +
      ' as it would output to same path as ' +
      chalk.magenta(buffer[chunk.relative].data.srcRelativePath)
    );
  }

}

module.exports = staticSiteGenerator;
<|endoftext|>


<commit_before>import { get, set, computed } from '@ember/object';
import { inject as service } from '@ember/service';
import Resource from '@rancher/ember-api-store/models/resource';
import { hasMany } from '@rancher/ember-api-store/utils/denormalize';
import ResourceUsage from 'shared/mixins/resource-usage';
import Grafana from 'shared/mixins/grafana';
import { equal, alias } from '@ember/object/computed';
import { resolve } from 'rsvp';
import C from 'ui/utils/constants';
import { isEmpty } from '@ember/utils';

export default Resource.extend(Grafana, ResourceUsage, {
  globalStore: service(),
  growl:       service(),
  scope:       service(),
  router:      service(),
  intl:        service(),

  namespaces:                  hasMany('id', 'namespace', 'clusterId'),
  projects:                    hasMany('id', 'project', 'clusterId'),
  nodes:                       hasMany('id', 'node', 'clusterId'),
  nodePools:                   hasMany('id', 'nodePool', 'clusterId'),
  clusterRoleTemplateBindings: hasMany('id', 'clusterRoleTemplateBinding', 'clusterId'),
  etcdbackups:                 hasMany('id', 'etcdbackup', 'clusterId'),
  grafanaDashboardName:        'Cluster',
  machines:                    alias('nodes'),
  roleTemplateBindings:        alias('clusterRoleTemplateBindings'),
  isGKE:                       equal('driver', 'googleKubernetesEngine'),
  isAKS:                       equal('driver', 'azureKubernetesService'),

  getAltActionDelete: computed('action.remove', function() { // eslint-disable-line
    return get(this, 'canBulkRemove') ? 'delete' : null;
  }),

  hasSessionToken: computed('annotations', function() {
    const sessionTokenLabel = `${ (get(this, 'annotations') || {})[C.LABEL.EKS_SESSION_TOKEN]  }`;
    let hasSessionToken      = false;

    if (sessionTokenLabel === 'undefined' || sessionTokenLabel === 'false') {
      hasSessionToken = false;
    } else {
      hasSessionToken = true;
    }

    return hasSessionToken;
  }),

  canBulkRemove: computed('action.remove', function() { // eslint-disable-line
    return get(this, 'hasSessionToken') ? false : true;
  }),

  configName: computed(function() {
    const keys = this.allKeys().filter((x) => x.endsWith('Config'));

    for ( let key, i = 0 ; i < keys.length ; i++ ) {
      key = keys[i];
      if ( get(this, key) ) {
        return key;
      }
    }

    return null;
  }),

  isMonitoringReady: computed('monitoringStatus.@each.conditions', function() {
    if ( !get(this, 'enableClusterMonitoring') ) {
      return false;
    }
    const conditions = get(this, 'monitoringStatus.conditions') || [];

    if ( get(conditions, 'length') > 0 ) {
      const ready = conditions.filterBy('status', 'True') || [] ;

      return get(ready, 'length') === get(conditions, 'length');
    }

    return false;
  }),

  isReady: computed('conditions.@each.status', function() {
    return this.hasCondition('Ready');
  }),

  isRKE: computed('configName', function() {
    return get(this, 'configName') === 'rancherKubernetesEngineConfig';
  }),

  provider: computed('configName', 'nodePools.@each.nodeTemplateId', function() {
    const pools = get(this, 'nodePools') || [];
    const firstTemplate = get(pools, 'firstObject.nodeTemplate');

    switch ( get(this, 'configName') ) {
    case 'amazonElasticContainerServiceConfig':
      return 'amazoneks';
    case 'azureKubernetesServiceConfig':
      return 'azureaks';
    case 'googleKubernetesEngineConfig':
      return 'googlegke';
    case 'tencentEngineConfig':
      return 'tencenttke';
    case 'aliyunEngineConfig':
      return 'aliyunkcs';
    case 'huaweiEngineConfig':
      return 'huaweicce';
    case 'rancherKubernetesEngineConfig':
      if ( pools.length > 0 ) {
        if ( firstTemplate ) {
          return get(firstTemplate, 'driver');
        } else {
          return null;
        }
      } else {
        return 'custom';
      }
    default:
      if (get(this, 'driver') && get(this, 'configName')) {
        return get(this, 'driver');
      } else {
        return 'import';
      }
    }
  }),

  displayProvider: computed('configName', 'nodePools.@each.displayProvider', 'intl.locale', function() {
    const intl = get(this, 'intl');
    const pools = get(this, 'nodePools');
    const firstPool = (pools || []).objectAt(0);

    switch ( get(this, 'configName') ) {
    case 'amazonElasticContainerServiceConfig':
      return intl.t('clusterNew.amazoneks.shortLabel');
    case 'azureKubernetesServiceConfig':
      return intl.t('clusterNew.azureaks.shortLabel');
    case 'googleKubernetesEngineConfig':
      return intl.t('clusterNew.googlegke.shortLabel');
    case 'tencentEngineConfig':
      return intl.t('clusterNew.tencenttke.shortLabel');
    case 'aliyunEngineConfig':
      return intl.t('clusterNew.aliyunkcs.shortLabel');
    case 'huaweiEngineConfig':
      return intl.t('clusterNew.huaweicce.shortLabel');
    case 'rancherKubernetesEngineConfig':
      if ( !!pools ) {
        if ( firstPool ) {
          return get(firstPool, 'displayProvider');
        } else {
          return intl.t('clusterNew.rke.shortLabel');
        }
      } else {
        return intl.t('clusterNew.custom.shortLabel');
      }
    default:
      if (get(this, 'driver') && get(this, 'configName')) {
        return get(this, 'driver').capitalize();
      } else {
        return intl.t('clusterNew.import.shortLabel');
      }
    }
  }),

  systemProject: computed('projects.@each.isSystemProject', function() {
    let projects = (get(this, 'projects') || []).filterBy('isSystemProject', true);

    return get(projects, 'firstObject');
  }),

  defaultProject: computed('projects.@each.{name,clusterOwner}', function() {
    let projects = get(this, 'projects');

    let out = projects.findBy('isDefault');

    if ( out ) {
      return out;
    }

    out = projects.findBy('clusterOwner', true);
    if ( out ) {
      return out;
    }

    out = projects.objectAt(0);

    return out;
  }),

  availableActions: computed('actionLinks.{rotateCertificates}', function() {
    const a = get(this, 'actionLinks') || {};

    return [
      {
        label:     'action.rotate',
        icon:      'icon icon-history',
        action:    'rotateCertificates',
        enabled:   !!a.rotateCertificates,
      },
      {
        label:     'action.backupEtcd',
        icon:      'icon icon-history',
        action:    'backupEtcd',
        enabled:   !!a.backupEtcd,
      },
      {
        label:     'action.restoreFromEtcdBackup',
        icon:      'icon icon-history',
        action:    'restoreFromEtcdBackup',
        enabled:   !!a.restoreFromEtcdBackup,
      },
    ];
  }),

  actions: {
    backupEtcd() {
      const getBackupType = () => {
        let services = get(this, 'rancherKubernetesEngineConfig.services.etcd');

        if (get(services, 'backupConfig')) {
          if (isEmpty(services.s3BackupConfig)) {
            return 'local';
          } else if (!isEmpty(services.s3BackupConfig)) {
            return 's3';
          }
        }
      }

      const backupType     = getBackupType();
      const successTitle   = this.intl.t('action.backupEtcdMessage.success.title');
      const successMessage = this.intl.t('action.backupEtcdMessage.success.message', {
        clusterId: this.displayName || this.id,
        backupType
      });

      this.doAction('backupEtcd')
        .then(() => this.growl.success(successTitle, successMessage))
        .catch((err) => this.growl.fromError(err));
    },

    restoreFromEtcdBackup() {
      get(this, 'modalService').toggleModal('modal-restore-backup', { cluster: this, });
    },

    promptDelete() {
      const hasSessionToken = get(this, 'canBulkRemove') ? false : true; // canBulkRemove returns true of the session token is set false

      if (hasSessionToken) {
        set(this, `${ get(this, 'configName') }.accessKey`, null);
        get(this, 'modalService').toggleModal('modal-delete-eks-cluster', { model: this, });
      } else {
        get(this, 'modalService').toggleModal('confirm-delete', {
          escToClose: true,
          resources:  [this]
        });
      }
    },

    edit() {
      get(this, 'router').transitionTo('authenticated.cluster.edit', get(this, 'id'), { queryParams: { provider: get(this, 'driver') } });
    },

    scaleDownPool(id) {
      const pool = (get(this, 'nodePools') || []).findBy('id', id);

      if ( pool ) {
        pool.incrementQuantity(-1);
      }
    },

    scaleUpPool(id) {
      const pool = (get(this, 'nodePools') || []).findBy('id', id);

      if ( pool ) {
        pool.incrementQuantity(1);
      }
    },

    rotateCertificates() {
      const model = this;

      get(this, 'modalService').toggleModal('modal-rotate-certificates', {
        model,
        serviceDefaults: get(this, 'globalStore').getById('schema', 'rotatecertificateinput').optionsFor('services'),
      });
    },

  },

  clearProvidersExcept(keep) {
    const keys = this.allKeys().filter((x) => x.endsWith('Config'));

    for ( let key, i = 0 ; i < keys.length ; i++ ) {
      key = keys[i];
      if ( key !== keep && get(this, key) ) {
        set(this, key, null);
      }
    }
  },

  delete(/* arguments*/) {
    const promise = this._super.apply(this, arguments);

    return promise.then((/* resp */) => {
      if (get(this, 'scope.currentCluster.id') === get(this, 'id')) {
        get(this, 'router').transitionTo('global-admin.clusters');
      }
    });
  },

  getOrCreateToken() {
    const globalStore = get(this, 'globalStore');
    const id = get(this, 'id');

    return globalStore.findAll('clusterRegistrationToken', { forceReload: true }).then((tokens) => {
      let token = tokens.filterBy('clusterId', id)[0];

      if ( token ) {
        return resolve(token);
      } else {
        token = get(this, 'globalStore').createRecord({
          type:      'clusterRegistrationToken',
          clusterId: id
        });

        return token.save();
      }
    });
  },
});
<commit_msg>update cluster model prodiver to watch provider key<commit_after>import { get, set, computed } from '@ember/object';
import { inject as service } from '@ember/service';
import Resource from '@rancher/ember-api-store/models/resource';
import { hasMany } from '@rancher/ember-api-store/utils/denormalize';
import ResourceUsage from 'shared/mixins/resource-usage';
import Grafana from 'shared/mixins/grafana';
import { equal, alias } from '@ember/object/computed';
import { resolve } from 'rsvp';
import C from 'ui/utils/constants';
import { isEmpty } from '@ember/utils';

export default Resource.extend(Grafana, ResourceUsage, {
  globalStore: service(),
  growl:       service(),
  scope:       service(),
  router:      service(),
  intl:        service(),

  namespaces:                  hasMany('id', 'namespace', 'clusterId'),
  projects:                    hasMany('id', 'project', 'clusterId'),
  nodes:                       hasMany('id', 'node', 'clusterId'),
  nodePools:                   hasMany('id', 'nodePool', 'clusterId'),
  clusterRoleTemplateBindings: hasMany('id', 'clusterRoleTemplateBinding', 'clusterId'),
  etcdbackups:                 hasMany('id', 'etcdbackup', 'clusterId'),
  grafanaDashboardName:        'Cluster',
  machines:                    alias('nodes'),
  roleTemplateBindings:        alias('clusterRoleTemplateBindings'),
  isGKE:                       equal('driver', 'googleKubernetesEngine'),
  isAKS:                       equal('driver', 'azureKubernetesService'),

  getAltActionDelete: computed('action.remove', function() { // eslint-disable-line
    return get(this, 'canBulkRemove') ? 'delete' : null;
  }),

  hasSessionToken: computed('annotations', function() {
    const sessionTokenLabel = `${ (get(this, 'annotations') || {})[C.LABEL.EKS_SESSION_TOKEN]  }`;
    let hasSessionToken      = false;

    if (sessionTokenLabel === 'undefined' || sessionTokenLabel === 'false') {
      hasSessionToken = false;
    } else {
      hasSessionToken = true;
    }

    return hasSessionToken;
  }),

  canBulkRemove: computed('action.remove', function() { // eslint-disable-line
    return get(this, 'hasSessionToken') ? false : true;
  }),

  configName: computed(function() {
    const keys = this.allKeys().filter((x) => x.endsWith('Config'));

    for ( let key, i = 0 ; i < keys.length ; i++ ) {
      key = keys[i];
      if ( get(this, key) ) {
        return key;
      }
    }

    return null;
  }),

  isMonitoringReady: computed('monitoringStatus.@each.conditions', function() {
    if ( !get(this, 'enableClusterMonitoring') ) {
      return false;
    }
    const conditions = get(this, 'monitoringStatus.conditions') || [];

    if ( get(conditions, 'length') > 0 ) {
      const ready = conditions.filterBy('status', 'True') || [] ;

      return get(ready, 'length') === get(conditions, 'length');
    }

    return false;
  }),

  isReady: computed('conditions.@each.status', function() {
    return this.hasCondition('Ready');
  }),

  isRKE: computed('configName', function() {
    return get(this, 'configName') === 'rancherKubernetesEngineConfig';
  }),

  provider: computed('configName', 'nodePools.@each.nodeTemplateId', 'driver', function() {
    const pools = get(this, 'nodePools') || [];
    const firstTemplate = get(pools, 'firstObject.nodeTemplate');

    switch ( get(this, 'configName') ) {
    case 'amazonElasticContainerServiceConfig':
      return 'amazoneks';
    case 'azureKubernetesServiceConfig':
      return 'azureaks';
    case 'googleKubernetesEngineConfig':
      return 'googlegke';
    case 'tencentEngineConfig':
      return 'tencenttke';
    case 'aliyunEngineConfig':
      return 'aliyunkcs';
    case 'huaweiEngineConfig':
      return 'huaweicce';
    case 'rancherKubernetesEngineConfig':
      if ( pools.length > 0 ) {
        if ( firstTemplate ) {
          return get(firstTemplate, 'driver');
        } else {
          return null;
        }
      } else {
        return 'custom';
      }
    default:
      if (get(this, 'driver') && get(this, 'configName')) {
        return get(this, 'driver');
      } else {
        return 'import';
      }
    }
  }),

  displayProvider: computed('configName', 'nodePools.@each.displayProvider', 'intl.locale', 'driver', function() {
    const intl = get(this, 'intl');
    const pools = get(this, 'nodePools');
    const firstPool = (pools || []).objectAt(0);

    switch ( get(this, 'configName') ) {
    case 'amazonElasticContainerServiceConfig':
      return intl.t('clusterNew.amazoneks.shortLabel');
    case 'azureKubernetesServiceConfig':
      return intl.t('clusterNew.azureaks.shortLabel');
    case 'googleKubernetesEngineConfig':
      return intl.t('clusterNew.googlegke.shortLabel');
    case 'tencentEngineConfig':
      return intl.t('clusterNew.tencenttke.shortLabel');
    case 'aliyunEngineConfig':
      return intl.t('clusterNew.aliyunkcs.shortLabel');
    case 'huaweiEngineConfig':
      return intl.t('clusterNew.huaweicce.shortLabel');
    case 'rancherKubernetesEngineConfig':
      if ( !!pools ) {
        if ( firstPool ) {
          return get(firstPool, 'displayProvider');
        } else {
          return intl.t('clusterNew.rke.shortLabel');
        }
      } else {
        return intl.t('clusterNew.custom.shortLabel');
      }
    default:
      if (get(this, 'driver') && get(this, 'configName')) {
        return get(this, 'driver').capitalize();
      } else {
        return intl.t('clusterNew.import.shortLabel');
      }
    }
  }),

  systemProject: computed('projects.@each.isSystemProject', function() {
    let projects = (get(this, 'projects') || []).filterBy('isSystemProject', true);

    return get(projects, 'firstObject');
  }),

  defaultProject: computed('projects.@each.{name,clusterOwner}', function() {
    let projects = get(this, 'projects');

    let out = projects.findBy('isDefault');

    if ( out ) {
      return out;
    }

    out = projects.findBy('clusterOwner', true);
    if ( out ) {
      return out;
    }

    out = projects.objectAt(0);

    return out;
  }),

  availableActions: computed('actionLinks.{rotateCertificates}', function() {
    const a = get(this, 'actionLinks') || {};

    return [
      {
        label:     'action.rotate',
        icon:      'icon icon-history',
        action:    'rotateCertificates',
        enabled:   !!a.rotateCertificates,
      },
      {
        label:     'action.backupEtcd',
        icon:      'icon icon-history',
        action:    'backupEtcd',
        enabled:   !!a.backupEtcd,
      },
      {
        label:     'action.restoreFromEtcdBackup',
        icon:      'icon icon-history',
        action:    'restoreFromEtcdBackup',
        enabled:   !!a.restoreFromEtcdBackup,
      },
    ];
  }),

  actions: {
    backupEtcd() {
      const getBackupType = () => {
        let services = get(this, 'rancherKubernetesEngineConfig.services.etcd');

        if (get(services, 'backupConfig')) {
          if (isEmpty(services.s3BackupConfig)) {
            return 'local';
          } else if (!isEmpty(services.s3BackupConfig)) {
            return 's3';
          }
        }
      }

      const backupType     = getBackupType();
      const successTitle   = this.intl.t('action.backupEtcdMessage.success.title');
      const successMessage = this.intl.t('action.backupEtcdMessage.success.message', {
        clusterId: this.displayName || this.id,
        backupType
      });

      this.doAction('backupEtcd')
        .then(() => this.growl.success(successTitle, successMessage))
        .catch((err) => this.growl.fromError(err));
    },

    restoreFromEtcdBackup() {
      get(this, 'modalService').toggleModal('modal-restore-backup', { cluster: this, });
    },

    promptDelete() {
      const hasSessionToken = get(this, 'canBulkRemove') ? false : true; // canBulkRemove returns true of the session token is set false

      if (hasSessionToken) {
        set(this, `${ get(this, 'configName') }.accessKey`, null);
        get(this, 'modalService').toggleModal('modal-delete-eks-cluster', { model: this, });
      } else {
        get(this, 'modalService').toggleModal('confirm-delete', {
          escToClose: true,
          resources:  [this]
        });
      }
    },

    edit() {
      get(this, 'router').transitionTo('authenticated.cluster.edit', get(this, 'id'), { queryParams: { provider: get(this, 'driver') } });
    },

    scaleDownPool(id) {
      const pool = (get(this, 'nodePools') || []).findBy('id', id);

      if ( pool ) {
        pool.incrementQuantity(-1);
      }
    },

    scaleUpPool(id) {
      const pool = (get(this, 'nodePools') || []).findBy('id', id);

      if ( pool ) {
        pool.incrementQuantity(1);
      }
    },

    rotateCertificates() {
      const model = this;

      get(this, 'modalService').toggleModal('modal-rotate-certificates', {
        model,
        serviceDefaults: get(this, 'globalStore').getById('schema', 'rotatecertificateinput').optionsFor('services'),
      });
    },

  },

  clearProvidersExcept(keep) {
    const keys = this.allKeys().filter((x) => x.endsWith('Config'));

    for ( let key, i = 0 ; i < keys.length ; i++ ) {
      key = keys[i];
      if ( key !== keep && get(this, key) ) {
        set(this, key, null);
      }
    }
  },

  delete(/* arguments*/) {
    const promise = this._super.apply(this, arguments);

    return promise.then((/* resp */) => {
      if (get(this, 'scope.currentCluster.id') === get(this, 'id')) {
        get(this, 'router').transitionTo('global-admin.clusters');
      }
    });
  },

  getOrCreateToken() {
    const globalStore = get(this, 'globalStore');
    const id = get(this, 'id');

    return globalStore.findAll('clusterRegistrationToken', { forceReload: true }).then((tokens) => {
      let token = tokens.filterBy('clusterId', id)[0];

      if ( token ) {
        return resolve(token);
      } else {
        token = get(this, 'globalStore').createRecord({
          type:      'clusterRegistrationToken',
          clusterId: id
        });

        return token.save();
      }
    });
  },
});
<|endoftext|>


<commit_before>// @flow
/**
 * Compute an isoline as a GeoJSON feature from a regular grid
 * Uses the Marching Squares algorithm, with code ported from
 * https://github.com/conveyal/r5/blob/master/src/main/java/com/conveyal/r5/analyst/IsochroneFeature.java
 * @author mattwigway
 */

import {point} from '@turf/helpers'
import inside from '@turf/inside'
import dbg from 'debug'

type Coordinate = [number, number]

const debug = dbg('jsolines')

/**
 * Create a JSON isoline. Surface is a (possibly typed) array, width and height
 * are its width and height, and cutoff is the cutoff. It is possible to disable
 * linear interpolation for debug purposes by passing interpolation: false
 */
export default function jsolines ({
  surface,
  width,
  height,
  cutoff,
  project,
  interpolation = true
}: {
  surface: Uint8Array,
  width: number,
  height: number,
  cutoff: number,
  project: (Coordinate) => Coordinate,
  interpolation: boolean
}) {
  // first, create the contour grid
  const contour = getContour({surface, width, height, cutoff})
  const cWidth = width - 1

  // javascript does not have boolean arrays. lame.
  const found = new Uint8Array((width - 1) * (height - 1))

  // DEBUG, comment out to save memory
  const indices = []

  // we'll sort out what shell goes with what hole in a bit
  const shells = []
  const holes = []

  // find a cell that has a line in it, then follow that line, keeping filled area to your
  // left. This lets us use winding direction to determine holes.
  for (let origy = 0; origy < height - 1; origy++) {
    for (let origx = 0; origx < width - 1; origx++) {
      if (found[origy * cWidth + origx] === 1) {
        continue
      }

      let idx = contour[origy * cWidth + origx]
      // continue if there is no line here or if it's a saddle, as we don't know which way the saddle goes
      if (idx === 0 || idx === 5 || idx === 10 || idx === 15) continue

      // huzzah! we have found a line, now follow it, keeping the filled area to our left,
      // which allows us to use the winding direction to determine what should be a shell and
      // what should be a hole
      let x = origx
      let y = origy

      let prevx = -1
      let prevy = -1
      let startx = -1
      let starty = -1

      // track winding direction
      let direction = 0

      const coords = []

      while (true) {
        // make sure we're not traveling in circles
        // NB using index from _previous_ cell, we have not yet set an index for this cell
        if (found[y * cWidth + x] === 1) {
          debug(`Ring crosses other ring (or possibly self) at ${x}, ${y} coming from case ${idx}`)
          debug(`Last few indices: ${indices.slice(Math.max(0, indices.length - 10)).join(',')}`)
          break
        }

        prevx = startx
        prevy = starty
        startx = x
        starty = y
        idx = contour[y * cWidth + x]

        indices.push(idx)

        // only mark as found if it's not a saddle because we expect to reach saddles twice.
        if (idx !== 5 && idx !== 10) {
          found[y * cWidth + x] = 1
        }

        if (idx === 0 || idx === 15) {
          debug('Ran off outside of ring')
          break
        }

        // follow the loop
        // we keep track of which contour cell we're in, and we always keep the filled area to our left.
        // thus we always indicate only which direction we exit the cell.
        switch (idx) {
          case 1:
            x--
            break
          // NB: +y is down
          case 2:
            y++
            break
          case 3:
            x--
            break
          case 4:
            x++
            break
          case 5:
            // assume that saddle has // orientation (as opposed to \\). It doesn't
            // really matter if we're wrong, we'll just have two disjoint pieces where we should have
            // one, or vice versa
            if (prevy > y) {
              // came from bottom
              x++
            } else if (prevy < y) {
              // came from top
              x--
            } else {
              debug('Entered case 5 saddle point from wrong direction!')
            }
            break
          case 6:
            y++
            break
          case 7:
            x--
            break
          case 8:
            y--
            break
          case 9:
            y--
            break
          case 10: // hex a
            if (prevx < x) {
              // came from left
              y++
            } else if (prevx > x) {
              // came from right
              y--
            } else {
              debug('Entered case 10 saddle point from wrong direction.')
            }
            break
          case 11: // b
            y--
            break
          case 12: // c
            x++
            break
          case 13: // d
            x++
            break
          case 14: // e
            y++
            break
        }

        // keep track of winding direction
        direction += (x - startx) * (y + starty)

        const index = y * width + x
        const topLeft = surface[index]
        const topRight = surface[index + 1]
        const botLeft = surface[index + width]
        const botRight = surface[index + width + 1]

        // do linear interpolation
        let coord
        if (startx < x) {
          // came from left
          let frac = interpolation ? (cutoff - topLeft) / (botLeft - topLeft) : 0.5

          if (frac === Infinity) {
            debug(`segment fraction from left is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x, y + frac]
        } else if (startx > x) {
          // came from right
          let frac = interpolation ? (cutoff - topRight) / (botRight - topRight) : 0.5

          if (frac === Infinity) {
            debug(`segment fraction from right is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x + 1, y + frac]
        } else if (starty > y) {
          // came from bottom
          let frac = interpolation ? (cutoff - botLeft) / (botRight - botLeft) : 0.5

          if (frac === Infinity) {
            debug(`segment fraction from bottom is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x + frac, y + 1]
        } else if (starty < y) {
          // came from top
          let frac = interpolation ? (cutoff - topLeft) / (topRight - topLeft) : 0.5

          if (frac === Infinity) {
            debug(`segment fraction from top is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
            frac = 0.5
          }

          coord = [x + frac, y]
        } else {
          debug(`Unexpected coordinate shift from ${startx}, ${starty} to ${x}, ${y}, discarding ring`)
          break
        }

        coords.push(project(coord))

        if (coords.length > 10000) {
          debug('More than 10000 coordinates found in ring, skipping this ring')
          break
        }

        // we're back at the start of the ring
        if (x === origx && y === origy) {
          coords.push(coords[0]) // close the ring

          // make it a fully-fledged GeoJSON object
          const geom = {
            type: 'Feature',
            geometry: {
              type: 'Polygon',
              coordinates: [coords]
            }
          }

          // check winding direction
          // positive means counter clockwise, see http://stackoverflow.com/questions/1165647
          // NB +y is down so the signs are reversed from what would normally be expected
          if (direction > 0) shells.push(geom)
          else holes.push(geom)
          break
        }
      }
    }
  }

  // shell game time.
  // sort out shells and holes
  holes.forEach((hole) => {
    // NB this is checking whether the first coordinate of the hole is inside the shell.
    // This is sufficient as shells don't overlap, and holes are guaranteed to be completely
    // contained by a single shell.
    const holePoint = point(hole.geometry.coordinates[0][0])
    const containingShell = shells.find((shell) => inside(holePoint, shell))

    if (containingShell) {
      containingShell.geometry.coordinates.push(hole.geometry.coordinates[0])
    } else {
      debug('Did not find fitting shell for hole')
    }
  })

  return {
    type: 'Feature',
    geometry: {
      type: 'MultiPolygon',
      coordinates: shells.map(s => s.geometry.coordinates)
    }
  }
}

/**
 * Get a contouring grid. Exported for debug purposes, not generally used
 * outside jsolines testing
 */
export function getContour ({
  surface,
  width,
  height,
  cutoff
}: {
  cutoff: number,
  height: number,
  width: number,
  surface: Uint8Array
}): Uint8Array {
  const contour = new Uint8Array((width - 1) * (height - 1))

  // compute contour values for each cell
  for (let x = 0; x < width - 1; x++) {
    for (let y = 0; y < height - 1; y++) {
      const index = y * width + x
      let topLeft = surface[index] < cutoff
      let topRight = surface[index + 1] < cutoff
      let botLeft = surface[index + width] < cutoff
      let botRight = surface[index + width + 1] < cutoff

      // if we're at the edge of the area, set the outer sides to false, so that
      // isochrones always close even when they actually extend beyond the edges
      // of the surface
      if (x === 0) topLeft = botLeft = false
      if (x === width - 2) topRight = botRight = false
      if (y === 0) topLeft = topRight = false
      if (y === height - 2) botRight = botLeft = false

      let idx = 0

      if (topLeft) idx |= 1 << 3
      if (topRight) idx |= 1 << 2
      if (botRight) idx |= 1 << 1
      if (botLeft) idx |= 1

      contour[y * (width - 1) + x] = idx
    }
  }

  return contour
}
<commit_msg>refactor(flow): Fix flow errors<commit_after>// @flow
/**
 * Compute an isoline as a GeoJSON feature from a regular grid
 * Uses the Marching Squares algorithm, with code ported from
 * https://github.com/conveyal/r5/blob/master/src/main/java/com/conveyal/r5/analyst/IsochroneFeature.java
 * @author mattwigway
 */

import {point} from '@turf/helpers'
import inside from '@turf/inside'
import dbg from 'debug'

type Coordinate = [number, number]

const debug = dbg('jsolines')

/**
 * Create a JSON isoline. Surface is a (possibly typed) array, width and height
 * are its width and height, and cutoff is the cutoff. It is possible to disable
 * linear interpolation for debug purposes by passing interpolation: false
 */
export default function jsolines ({
  surface,
  width,
  height,
  cutoff,
  project,
  interpolation = true
}: {
  surface: Uint8Array,
  width: number,
  height: number,
  cutoff: number,
  project: (Coordinate) => Coordinate,
  interpolation: boolean
}) {
  // first, create the contour grid
  const contour = getContour({surface, width, height, cutoff})
  const cWidth = width - 1

  // javascript does not have boolean arrays. lame.
  const found = new Uint8Array((width - 1) * (height - 1))

  // DEBUG, comment out to save memory
  const indices = []

  // we'll sort out what shell goes with what hole in a bit
  const shells = []
  const holes = []

  // find a cell that has a line in it, then follow that line, keeping filled area to your
  // left. This lets us use winding direction to determine holes.
  for (let origy = 0; origy < height - 1; origy++) {
    for (let origx = 0; origx < width - 1; origx++) {
      if (found[origy * cWidth + origx] === 1) {
        continue
      }

      let idx = contour[origy * cWidth + origx]
      // continue if there is no line here or if it's a saddle, as we don't know which way the saddle goes
      if (idx === 0 || idx === 5 || idx === 10 || idx === 15) continue

      // huzzah! we have found a line, now follow it, keeping the filled area to our left,
      // which allows us to use the winding direction to determine what should be a shell and
      // what should be a hole
      let x = origx
      let y = origy

      let prevx = -1
      let prevy = -1
      let startx = -1
      let starty = -1

      // track winding direction
      let direction = 0

      const coords = []

      while (true) {
        // make sure we're not traveling in circles
        // NB using index from _previous_ cell, we have not yet set an index for this cell
        if (found[y * cWidth + x] === 1) {
          debug(`Ring crosses other ring (or possibly self) at ${x}, ${y} coming from case ${idx}`)
          debug(`Last few indices: ${indices.slice(Math.max(0, indices.length - 10)).join(',')}`)
          break
        }

        prevx = startx
        prevy = starty
        startx = x
        starty = y
        idx = contour[y * cWidth + x]

        indices.push(idx)

        // only mark as found if it's not a saddle because we expect to reach saddles twice.
        if (idx !== 5 && idx !== 10) {
          found[y * cWidth + x] = 1
        }

        if (idx === 0 || idx === 15) {
          debug('Ran off outside of ring')
          break
        }

        // follow the loop
        // we keep track of which contour cell we're in, and we always keep the filled area to our left.
        // thus we always indicate only which direction we exit the cell.
        switch (idx) {
          case 1:
            x--
            break
          // NB: +y is down
          case 2:
            y++
            break
          case 3:
            x--
            break
          case 4:
            x++
            break
          case 5:
            // assume that saddle has // orientation (as opposed to \\). It doesn't
            // really matter if we're wrong, we'll just have two disjoint pieces where we should have
            // one, or vice versa
            if (prevy > y) {
              // came from bottom
              x++
            } else if (prevy < y) {
              // came from top
              x--
            } else {
              debug('Entered case 5 saddle point from wrong direction!')
            }
            break
          case 6:
            y++
            break
          case 7:
            x--
            break
          case 8:
            y--
            break
          case 9:
            y--
            break
          case 10: // hex a
            if (prevx < x) {
              // came from left
              y++
            } else if (prevx > x) {
              // came from right
              y--
            } else {
              debug('Entered case 10 saddle point from wrong direction.')
            }
            break
          case 11: // b
            y--
            break
          case 12: // c
            x++
            break
          case 13: // d
            x++
            break
          case 14: // e
            y++
            break
        }

        // keep track of winding direction
        direction += (x - startx) * (y + starty)

        const coord = interpolate({
          coord: [x, y],
          cutoff,
          interpolation,
          startx,
          starty,
          surface,
          width
        })
        if (!coord) break

        coords.push(project(coord))

        if (coords.length > 10000) {
          debug('More than 10000 coordinates found in ring, skipping this ring')
          break
        }

        // we're back at the start of the ring
        if (x === origx && y === origy) {
          coords.push(coords[0]) // close the ring

          // make it a fully-fledged GeoJSON object
          const geom = {
            type: 'Feature',
            geometry: {
              type: 'Polygon',
              coordinates: [coords]
            }
          }

          // check winding direction
          // positive means counter clockwise, see http://stackoverflow.com/questions/1165647
          // NB +y is down so the signs are reversed from what would normally be expected
          if (direction > 0) shells.push(geom)
          else holes.push(geom)
          break
        }
      }
    }
  }

  // shell game time.
  // sort out shells and holes
  holes.forEach((hole) => {
    // NB this is checking whether the first coordinate of the hole is inside the shell.
    // This is sufficient as shells don't overlap, and holes are guaranteed to be completely
    // contained by a single shell.
    const holePoint = point(hole.geometry.coordinates[0][0])
    const containingShell = shells.find((shell) => inside(holePoint, shell))

    if (containingShell) {
      containingShell.geometry.coordinates.push(hole.geometry.coordinates[0])
    } else {
      debug('Did not find fitting shell for hole')
    }
  })

  return {
    type: 'Feature',
    geometry: {
      type: 'MultiPolygon',
      coordinates: shells.map(s => s.geometry.coordinates)
    }
  }
}

function interpolate ({
  coord,
  cutoff,
  interpolation,
  startx,
  starty,
  surface,
  width
}: {
  coord: Coordinate,
  cutoff: number,
  interpolation: boolean,
  startx: number,
  starty: number,
  surface: Uint8Array,
  width: number
}): (Coordinate | void) {
  const [x, y] = coord
  const index = y * width + x
  const topLeft = surface[index]
  const topRight = surface[index + 1]
  const botLeft = surface[index + width]
  const botRight = surface[index + width + 1]

  // do linear interpolation
  if (startx < x) {
    // came from left
    let frac = interpolation ? (cutoff - topLeft) / (botLeft - topLeft) : 0.5

    if (frac === Infinity) {
      debug(`segment fraction from left is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
      frac = 0.5
    }

    return [x, y + frac]
  } else if (startx > x) {
    // came from right
    let frac = interpolation ? (cutoff - topRight) / (botRight - topRight) : 0.5

    if (frac === Infinity) {
      debug(`segment fraction from right is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
      frac = 0.5
    }

    return [x + 1, y + frac]
  } else if (starty > y) {
    // came from bottom
    let frac = interpolation ? (cutoff - botLeft) / (botRight - botLeft) : 0.5

    if (frac === Infinity) {
      debug(`segment fraction from bottom is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
      frac = 0.5
    }

    return [x + frac, y + 1]
  } else if (starty < y) {
    // came from top
    let frac = interpolation ? (cutoff - topLeft) / (topRight - topLeft) : 0.5

    if (frac === Infinity) {
      debug(`segment fraction from top is Infinity at ${x}, ${y}; if this is at the edge of the query this is not totally unexpected.`)
      frac = 0.5
    }

    return [x + frac, y]
  } else {
    debug(`Unexpected coordinate shift from ${startx}, ${starty} to ${x}, ${y}, discarding ring`)
  }
}

/**
 * Get a contouring grid. Exported for debug purposes, not generally used
 * outside jsolines testing
 */
export function getContour ({
  surface,
  width,
  height,
  cutoff
}: {
  cutoff: number,
  height: number,
  width: number,
  surface: Uint8Array
}): Uint8Array {
  const contour = new Uint8Array((width - 1) * (height - 1))

  // compute contour values for each cell
  for (let x = 0; x < width - 1; x++) {
    for (let y = 0; y < height - 1; y++) {
      const index = y * width + x
      let topLeft = surface[index] < cutoff
      let topRight = surface[index + 1] < cutoff
      let botLeft = surface[index + width] < cutoff
      let botRight = surface[index + width + 1] < cutoff

      // if we're at the edge of the area, set the outer sides to false, so that
      // isochrones always close even when they actually extend beyond the edges
      // of the surface
      if (x === 0) topLeft = botLeft = false
      if (x === width - 2) topRight = botRight = false
      if (y === 0) topLeft = topRight = false
      if (y === height - 2) botRight = botLeft = false

      let idx = 0

      if (topLeft) idx |= 1 << 3
      if (topRight) idx |= 1 << 2
      if (botRight) idx |= 1 << 1
      if (botLeft) idx |= 1

      contour[y * (width - 1) + x] = idx
    }
  }

  return contour
}
<|endoftext|>


<commit_before>var jsdom = require("jsdom");
var request = require('request');
var fs = require("fs");
var jquery = fs.readFileSync("./lib/jquery.js", "utf-8");

var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('mame.db');

var args = process.argv.slice(2);

var romDir = args[0];
var gameList = [];
var doneCounter = 0;

var starttime;

if(!romDir)
	throw Error("No path secified. Use path to roms as argument");

db.serialize(function() {
	db.run("CREATE TABLE IF NOT EXISTS arcadegames (id INTEGER PRIMARY KEY NOT NULL, master_id INTEGER, shortname TEXT, name TEXT, ignore BOOLEAN DEFAULT false)");

	if(args[1] == "truncate") {
		db.run("DELETE FROM arcadegames");
		console.log("Truncated table");
	}

	console.log("Database set up");

	readDirectory();
});

function readDirectory() {
	fs.readdir(romDir, function(err, files) {

		console.log("Found %d files", files.length);

		files.map(handleFile);

		console.log("Found %d possible games", gameList.length);
		console.log("Starting crawl");
		starttime = Date.now();
		gameList.map(fetchGameData);
	});
}

function handleFile(filename) {
	var fileParts = filename.match(new RegExp(/(.*)\.zip$/i));
	if(!fileParts) return;

	gameList.push(fileParts[1]);
}

function fetchGameData(gamename) {
	request('http://www.mamedb.com/game/' + gamename, function (err, response, body) {
		if (!err && response.statusCode == 200) {
			jsdom.env(
				{
					html: body,
					src: [jquery],
					done: function(err, window) {parseMamedb(err, window, gamename)}
				}
			);
		}else{
			console.log("%s NOT FOUND: %s", logLine(), gamename);
		}

		doneCounter++;
	});
}

function logLine() {
	var timelapsed = (Date.now() - starttime) / 1000;
	var crawlTime = timelapsed / doneCounter;
	var remainingSeconds = Math.round((gameList.length - doneCounter) * crawlTime);

	var remaining = remainingSeconds + 's';
	if(remainingSeconds > 300)
		remaining = Math.round(remainingSeconds / 60) + 'min';

	if(remainingSeconds > 3600){
		var hours = Math.floor(remainingSeconds / 3600);
		var minutes = Math.round(remainingSeconds % (hours * 3600) / 60);

		remaining = hours + 'h ' + minutes + 'min';
	}

	return '[' + (doneCounter) + '/' + gameList.length + '] [' + remaining + '] -';
}

function parseMamedb(err, window, gamename) {
	if(err) {
		console.log("%s Error parsing page on game: %s",logLine(), gamename);
		return;
	}

	var $ = window.$;
	var nameRegex = new RegExp(/<h1>(.+) \(MAME version \d\.\d+\)/);

	var game_id = $('input[name="game_id"]').val();
	var master_game_id = $('input[name="master_game_id"]').val();
	var formattedName = $('body').html().match(nameRegex);

	if(!formattedName){
		console.log("ERROR name not parsed: %s", gamename);
		return;
	}

	db.run("INSERT INTO arcadegames (id, master_id, shortname, name) VALUES (?,?,?,?)", game_id, master_game_id, gamename, formattedName[1]);

	console.log('%s %s: %s/%s - %s', logLine(), gamename, game_id, master_game_id, formattedName[1]);
}<commit_msg>move regex out of function<commit_after>var jsdom = require("jsdom");
var request = require('request');
var fs = require("fs");
var jquery = fs.readFileSync("./lib/jquery.js", "utf-8");

var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('mame.db');

var args = process.argv.slice(2);

var romDir = args[0];
var gameList = [];
var doneCounter = 0;
var nameRegex = new RegExp(/<h1>(.+) \(MAME version \d\.\d+\)/);

var starttime;

if(!romDir)
	throw Error("No path secified. Use path to roms as argument");

db.serialize(function() {
	db.run("CREATE TABLE IF NOT EXISTS arcadegames (id INTEGER PRIMARY KEY NOT NULL, master_id INTEGER, shortname TEXT, name TEXT, ignore BOOLEAN DEFAULT false)");

	if(args[1] == "truncate") {
		db.run("DELETE FROM arcadegames");
		console.log("Truncated table");
	}

	console.log("Database set up");

	readDirectory();
});

function readDirectory() {
	fs.readdir(romDir, function(err, files) {

		console.log("Found %d files", files.length);

		files.map(handleFile);

		console.log("Found %d possible games", gameList.length);
		console.log("Starting crawl");
		starttime = Date.now();
		gameList.map(fetchGameData);
	});
}

function handleFile(filename) {
	var fileParts = filename.match(new RegExp(/(.*)\.zip$/i));
	if(!fileParts) return;

	gameList.push(fileParts[1]);
}

function fetchGameData(gamename) {
	request('http://www.mamedb.com/game/' + gamename, function (err, response, body) {
		if (!err && response.statusCode == 200) {
			jsdom.env(
				{
					html: body,
					src: [jquery],
					done: function(err, window) {parseMamedb(err, window, gamename)}
				}
			);
		}else{
			console.log("%s NOT FOUND: %s", logLine(), gamename);
		}

		doneCounter++;
	});
}

function logLine() {
	var timelapsed = (Date.now() - starttime) / 1000;
	var crawlTime = timelapsed / doneCounter;
	var remainingSeconds = Math.round((gameList.length - doneCounter) * crawlTime);

	var remaining = remainingSeconds + 's';
	if(remainingSeconds > 300)
		remaining = Math.round(remainingSeconds / 60) + 'min';

	if(remainingSeconds > 3600){
		var hours = Math.floor(remainingSeconds / 3600);
		var minutes = Math.round(remainingSeconds % (hours * 3600) / 60);

		remaining = hours + 'h ' + minutes + 'min';
	}

	return '[' + (doneCounter) + '/' + gameList.length + '] [' + remaining + '] -';
}

function parseMamedb(err, window, gamename) {
	if(err) {
		console.log("%s Error parsing page on game: %s",logLine(), gamename);
		return;
	}

	var $ = window.$;

	var game_id = $('input[name="game_id"]').val();
	var master_game_id = $('input[name="master_game_id"]').val();
	var formattedName = $('body').html().match(nameRegex);

	if(!formattedName){
		console.log("ERROR name not parsed: %s", gamename);
		return;
	}

	db.run("INSERT INTO arcadegames (id, master_id, shortname, name) VALUES (?,?,?,?)", game_id, master_game_id, gamename, formattedName[1]);

	console.log('%s %s: %s/%s - %s', logLine(), gamename, game_id, master_game_id, formattedName[1]);
}<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var MongoClient = require('mongodb').MongoClient
, assert = require('assert');

var db = MongoClient.connect("penn_db");
//get random from 1 to 100000
//return "num : {x,y}" from mongo

var num;
var url = 'mongodb://ec2-54-211-134-229.compute-1.amazonaws.com/penn_db';
var Message;
var collection;
app.get('/read', function (req, res) {
    num = (Math.floor(Math.random() * (100000 - 1001 + 1)) + 1001).toString()
    MongoClient.connect(url, function(err, db) {
        assert.equal(null, err);
        console.log("Connection successful");
        var findDocuments = function(db, callback) {
    	// Get the documents collection
    	collection = db.collection('bal1');
    	collection.find({'_id': num}).toArray(function(err, docs) {
    	    assert.equal(err, null);
    	    console.log("Found the following records");
    	    console.log(req.params.time);
            Message = docs;
    	    callback(docs);
            //res.send("helloder");
            res.send((req.params.time).toString());
    	});
        }
        findDocuments(db,function(){
    	   db.close();
        });
    });
})

//get random from 1 to 100000
//get value of x and y from mongo
//hash the values and update mongo
//return new values without a read to mongo
// app.get('/update', function(req, res) {
//     num = (Math.floor(Math.random() * (100000 - 1001 + 1)) + 1001).toString()
//     MongoClient.connect(url, function(err, db) {
//         assert.equal(null, err);
//         console.log("Connection successful");
//         var updateDocuments = function(db, callback) {
//         // Get the documents collection
//             collection = db.collection('bal1');
//             collection.update({'_id': num}, { $set: {'_id' : (Math.floor(Math.random() * (100000 - 1001 + 1)) + 1001).toString(function(err, docs){
//                 assert.equal(err, null);
//                 assert.equal(1, results.result.n);
//                 console.log("Found the following records");
//                 console.log(docs);
//                 Message = docs;
//                 callback(docs);
//             });
//             )}}
//         }
//         updateDocuments(db,function(){
//         db.close();
//         });
//     });
//   callback.send(Message);
// })

var server = app.listen(8081, function (err) {
    assert.equal(err,null);
    var host = server.address().address
    var port = server.address().port
    //console.log("Example app listening at http://%s:%s", host, port)
})
<commit_msg>stfff<commit_after>var express = require('express');
var app = express();
var MongoClient = require('mongodb').MongoClient
, assert = require('assert');

var db = MongoClient.connect("penn_db");
//get random from 1 to 100000
//return "num : {x,y}" from mongo

var num;
var url = 'mongodb://ec2-54-211-134-229.compute-1.amazonaws.com/penn_db';
var Message;
var collection;
app.get('/read', function (req, res) {
    num = (Math.floor(Math.random() * (100000 - 1001 + 1)) + 1001).toString()
    MongoClient.connect(url, function(err, db) {
        assert.equal(null, err);
        console.log("Connection successful");
        var findDocuments = function(db, callback) {
    	// Get the documents collection
    	collection = db.collection('bal1');
    	collection.find({'_id': num}).toArray(function(err, docs) {
    	    assert.equal(err, null);
    	    console.log("Found the following records");
    	    console.log(req.params.tagId);
            Message = docs;
    	    callback(docs);
            //res.send("helloder");
            res.send((req.params.tagId).toString());
    	});
        }
        findDocuments(db,function(){
    	   db.close();
        });
    });
})

//get random from 1 to 100000
//get value of x and y from mongo
//hash the values and update mongo
//return new values without a read to mongo
// app.get('/update', function(req, res) {
//     num = (Math.floor(Math.random() * (100000 - 1001 + 1)) + 1001).toString()
//     MongoClient.connect(url, function(err, db) {
//         assert.equal(null, err);
//         console.log("Connection successful");
//         var updateDocuments = function(db, callback) {
//         // Get the documents collection
//             collection = db.collection('bal1');
//             collection.update({'_id': num}, { $set: {'_id' : (Math.floor(Math.random() * (100000 - 1001 + 1)) + 1001).toString(function(err, docs){
//                 assert.equal(err, null);
//                 assert.equal(1, results.result.n);
//                 console.log("Found the following records");
//                 console.log(docs);
//                 Message = docs;
//                 callback(docs);
//             });
//             )}}
//         }
//         updateDocuments(db,function(){
//         db.close();
//         });
//     });
//   callback.send(Message);
// })

var server = app.listen(8081, function (err) {
    assert.equal(err,null);
    var host = server.address().address
    var port = server.address().port
    //console.log("Example app listening at http://%s:%s", host, port)
})
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Link } from 'react-router';
import moment from '../../../assets/moment.min.js';
//Import Actions
import { submitFile, getRecentSubmission} from './AssignmentActions'
// Import Style
import styles from './Assignment.css';

import Feedback from './components/Feedback/Feedback';
// Import Material UI Components
import {
  Card,
  CardActions,
  CardHeader,
  CardMedia,
  CardTitle,
  CardText
} from 'material-ui/Card';
import RaisedButton from 'material-ui/RaisedButton';
import {
  Table,
  TableBody,
  TableHeader,
  TableHeaderColumn,
  TableRow,
  TableRowColumn,
} from 'material-ui/Table';
import TextField from 'material-ui/TextField';

export class Assignment extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isMounted: false,
      feedbackVisible: false,
      score: 0,
      fileChosen: false,
      submitted: false,
    };
    this.intervalID = setInterval(() => this.checkFeedback(), 5000);
  }

  componentDidMount() {
    this.setState({ isMounted: true });
  }

  componentWillReceiveProps(NextProps) {
    var courseNum = NextProps.params.course;
    var assignmentNum = NextProps.assignmentData[NextProps.params.assignment].assignment_num;
    var userEmail = NextProps.user.email;
    this.props.getRecentSubmission(courseNum, assignmentNum, userEmail);
  }

  render() {
    var assignmentData = this.props.assignmentData[this.props.params.assignment];
    if (assignmentData == null) { return null; }
    // console.log(assignmentData);
    var due_date = moment(assignmentData.due_date).format('LLL');
    var end_date = moment(assignmentData.end_date).format('LLL');
    var asst_desc = assignmentData.description;
    console.log(this.props.score.toString());
    var problemsArray = assignmentData.problems;
    //Determine maxScore
    var maxScore = 0;
    for(var i = 0; i < problemsArray.length; i++){
      maxScore = maxScore + problemsArray[i].score;
    }
    return (
      <Card>
        <CardTitle title={this.props.params.assignment} subtitle={asst_desc} />
        <CardMedia>

            <TableBody displayRowCheckbox={false}>
              <TableRow selectable={false}>
                <TableRowColumn>Due date: </TableRowColumn>
                <TableRowColumn>{due_date}</TableRowColumn>
              </TableRow>
              <TableRow selectable={false}>
                <TableRowColumn>Last day to hand in: </TableRowColumn>
                <TableRowColumn>{end_date}</TableRowColumn>
              </TableRow>
              <TableRow selectable={false}>
                <TableRowColumn>Most recent score: </TableRowColumn>
                <TableRowColumn>{(typeof this.props.score === 'number') ? (this.props.score.toString() + "/" + maxScore.toString()) : this.props.score}</TableRowColumn>
              </TableRow>
            </TableBody>

        </CardMedia>
        <CardText>
          {
            this.state.feedbackVisible
              ? <Feedback rawFeedback={this.props.feedback} />
              : null
          }
          {
            (this.state.fileChosen && !this.state.submitted)
            ?

            : null
          }
          {
            this.state.submitted
              ?
Your submission has been submitted for review.

              : null
          }
          {
            (this.state.fileChosen || this.state.submitted)
            ? null
            :
Please choose a file to submit.

          }
        </CardText>
        <CardActions>
          <RaisedButton
            primary={true}
            label='Choose File'
            containerElement='label'>
            <input id="submission" type="file" style={{ display: 'none' }} onChange={() => this.fileEntered()}/>
          </RaisedButton>
          <RaisedButton disabled={!this.state.fileChosen} label="submit" primary={true} onClick={() => this.sendFile()} />
          <RaisedButton onClick={() => this.hideShowFeedback()} primary={true}
            label={
              this.state.feedbackVisible ? 'Hide Feedback' : 'Show Feedback'
            }
          />
        </CardActions>
      </Card>
    );
  }

  fileEntered() {
    var file = document.getElementById("submission").files[0];
    if(typeof file != undefined) {
      this.setState({
        fileChosen: true,
        submitted: false,
      });
    }
  }

  hideShowFeedback() {
    this.setState({ feedbackVisible: !this.state.feedbackVisible });
  }

  sendFile() {
    var file = document.getElementById("submission").files[0];
    if (typeof file == undefined) {
      this.setState({fileChosen: false});
      return;
    }
    var courseNum = this.props.params.course;
    var assignmentNum = this.props.assignmentData[this.props.params.assignment].assignment_num;
    this.props.submitFile(courseNum, assignmentNum, file);
    this.setState({
      fileChosen: false,
      submitted: true,
    });
    document.getElementById("submission").value="";
  }

  checkFeedback() {
    if(!this.state.isMounted) {
      return;
    }
    var courseNum = this.props.params.course;
    var assignmentNum = this.props.assignmentData[this.props.params.assignment].assignment_num;
    var userEmail = this.props.user.email;
    this.props.getRecentSubmission(courseNum, assignmentNum, userEmail);
  }
}
// Retrieve data from store as props
function mapStateToProps(state) {
  return {
    user: state.app.user,
    score: state.assignment.score,
    maxScore: state.assignment.maxScore,
    feedback: state.assignment.feedback,
    assignmentData: state.assignments.assignmentsMap,
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({
    submitFile: submitFile,
    getRecentSubmission: getRecentSubmission,
  }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Assignment);

<commit_msg>Display name now appears on assignment page<commit_after>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Link } from 'react-router';
import moment from '../../../assets/moment.min.js';
//Import Actions
import { submitFile, getRecentSubmission} from './AssignmentActions'
// Import Style
import styles from './Assignment.css';

import Feedback from './components/Feedback/Feedback';
// Import Material UI Components
import {
  Card,
  CardActions,
  CardHeader,
  CardMedia,
  CardTitle,
  CardText
} from 'material-ui/Card';
import RaisedButton from 'material-ui/RaisedButton';
import {
  Table,
  TableBody,
  TableHeader,
  TableHeaderColumn,
  TableRow,
  TableRowColumn,
} from 'material-ui/Table';
import TextField from 'material-ui/TextField';

export class Assignment extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isMounted: false,
      feedbackVisible: false,
      score: 0,
      fileChosen: false,
      submitted: false,
    };
    this.intervalID = setInterval(() => this.checkFeedback(), 5000);
  }

  componentDidMount() {
    this.setState({ isMounted: true });
  }

  componentWillReceiveProps(NextProps) {
    var courseNum = NextProps.params.course;
    var assignmentNum = NextProps.assignmentData[NextProps.params.assignment].assignment_num;
    var userEmail = NextProps.user.email;
    this.props.getRecentSubmission(courseNum, assignmentNum, userEmail);
  }

  render() {
    var assignmentData = this.props.assignmentData[this.props.params.assignment];
    if (assignmentData == null) { return null; }
    // console.log(assignmentData);
    var due_date = moment(assignmentData.due_date).format('LLL');
    var end_date = moment(assignmentData.end_date).format('LLL');
    var asst_desc = assignmentData.description;
    console.log(this.props.score.toString());
    var problemsArray = assignmentData.problems;
    //Determine maxScore
    var maxScore = 0;
    for(var i = 0; i < problemsArray.length; i++){
      maxScore = maxScore + problemsArray[i].score;
    }
    var displayName = this.props.assignmentData[this.props.params.assignment].name;
    return (
      <Card>
        <CardTitle title={displayName} subtitle={asst_desc} />
        <CardMedia>

            <TableBody displayRowCheckbox={false}>
              <TableRow selectable={false}>
                <TableRowColumn>Due date: </TableRowColumn>
                <TableRowColumn>{due_date}</TableRowColumn>
              </TableRow>
              <TableRow selectable={false}>
                <TableRowColumn>Last day to hand in: </TableRowColumn>
                <TableRowColumn>{end_date}</TableRowColumn>
              </TableRow>
              <TableRow selectable={false}>
                <TableRowColumn>Most recent score: </TableRowColumn>
                <TableRowColumn>{(typeof this.props.score === 'number') ? (this.props.score.toString() + "/" + maxScore.toString()) : this.props.score}</TableRowColumn>
              </TableRow>
            </TableBody>

        </CardMedia>
        <CardText>
          {
            this.state.feedbackVisible
              ? <Feedback rawFeedback={this.props.feedback} />
              : null
          }
          {
            (this.state.fileChosen && !this.state.submitted)
            ?

            : null
          }
          {
            this.state.submitted
              ?
Your submission has been submitted for review.

              : null
          }
          {
            (this.state.fileChosen || this.state.submitted)
            ? null
            :
Please choose a file to submit.

          }
        </CardText>
        <CardActions>
          <RaisedButton
            primary={true}
            label='Choose File'
            containerElement='label'>
            <input id="submission" type="file" style={{ display: 'none' }} onChange={() => this.fileEntered()}/>
          </RaisedButton>
          <RaisedButton disabled={!this.state.fileChosen} label="submit" primary={true} onClick={() => this.sendFile()} />
          <RaisedButton onClick={() => this.hideShowFeedback()} primary={true}
            label={
              this.state.feedbackVisible ? 'Hide Feedback' : 'Show Feedback'
            }
          />
        </CardActions>
      </Card>
    );
  }

  fileEntered() {
    var file = document.getElementById("submission").files[0];
    if(typeof file != undefined) {
      this.setState({
        fileChosen: true,
        submitted: false,
      });
    }
  }

  hideShowFeedback() {
    this.setState({ feedbackVisible: !this.state.feedbackVisible });
  }

  sendFile() {
    var file = document.getElementById("submission").files[0];
    if (typeof file == undefined) {
      this.setState({fileChosen: false});
      return;
    }
    var courseNum = this.props.params.course;
    var assignmentNum = this.props.assignmentData[this.props.params.assignment].assignment_num;
    this.props.submitFile(courseNum, assignmentNum, file);
    this.setState({
      fileChosen: false,
      submitted: true,
    });
    document.getElementById("submission").value="";
  }

  checkFeedback() {
    if(!this.state.isMounted) {
      return;
    }
    var courseNum = this.props.params.course;
    var assignmentNum = this.props.assignmentData[this.props.params.assignment].assignment_num;
    var userEmail = this.props.user.email;
    this.props.getRecentSubmission(courseNum, assignmentNum, userEmail);
  }
}
// Retrieve data from store as props
function mapStateToProps(state) {
  return {
    user: state.app.user,
    score: state.assignment.score,
    maxScore: state.assignment.maxScore,
    feedback: state.assignment.feedback,
    assignmentData: state.assignments.assignmentsMap,
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({
    submitFile: submitFile,
    getRecentSubmission: getRecentSubmission,
  }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Assignment);

<|endoftext|>


<commit_before>var Server = require('./socketServer/server.js'),
    MongoClient = require('mongodb').MongoClient,
    ProtoBuf = require("protobufjs"),
    app = require('./app'),
    clc = require('cli-color'),
    events = require('events');

var builder = ProtoBuf.loadJsonFile("./rpc.json");
global.rpc = builder.build('rpc');

var TransUnit = rpc.TransUnit,
    command = rpc.Command;

global.dbReady = new events.EventEmitter();
global.async = require('async');

global.db = require('./db');

dbReady.once('dbReady', function(){
    var server = new Server({
        port: 9001
    }, handleServerMessage);
    console.log(clc.green('游戏服务器启动成功'));
});

function handleServerMessage(data){
    var self = this;
    console.log('receive', data);
    var request;
    try{
        request = TransUnit.decode(data);
    }catch(e){
        throw new Error('无法解析请求,即将断开客户端连接');
        self.end();
        return;
    }
    console.log(JSON.stringify(request));
    var cmd = "";
    for(var key in command){
        if(command[key] === request['cmd']){
            cmd = key;
            break;
        }
    }
    if(!cmd){
        console.log('no valid cmd', cmd);
        return;
    }
    for(key in rpc){
        if(rpc.hasOwnProperty(key) && key.toUpperCase() === cmd.replace(/_/g,"")){
            console.log('action is ', key);
            var tData;
            try{
                tData = rpc[key].decode(request.data);
            }catch(e){
                throw new Error('无法解析请求,即将断开客户端连接');
                self.end();
                return;
            }
            console.log(tData);
            if(app && app[key]){
                app[key].call(self, tData);
            }
            break;
        }
    }
}<commit_msg>修改服务器端口<commit_after>var Server = require('./socketServer/server.js'),
    MongoClient = require('mongodb').MongoClient,
    ProtoBuf = require("protobufjs"),
    app = require('./app'),
    clc = require('cli-color'),
    events = require('events');

var builder = ProtoBuf.loadJsonFile("./rpc.json");
global.rpc = builder.build('rpc');

var TransUnit = rpc.TransUnit,
    command = rpc.Command;

global.dbReady = new events.EventEmitter();
global.async = require('async');

global.db = require('./db');

dbReady.once('dbReady', function(){
    var server = new Server({
        port: 7707
    }, handleServerMessage);
    console.log(clc.green('游戏服务器启动成功'));
});

function handleServerMessage(data){
    var self = this;
    console.log('receive', data);
    var request;
    try{
        request = TransUnit.decode(data);
    }catch(e){
        throw new Error('无法解析请求,即将断开客户端连接');
        self.end();
        return;
    }
    console.log(JSON.stringify(request));
    var cmd = "";
    for(var key in command){
        if(command[key] === request['cmd']){
            cmd = key;
            break;
        }
    }
    if(!cmd){
        console.log('no valid cmd', cmd);
        return;
    }
    for(key in rpc){
        if(rpc.hasOwnProperty(key) && key.toUpperCase() === cmd.replace(/_/g,"")){
            console.log('action is ', key);
            var tData;
            try{
                tData = rpc[key].decode(request.data);
            }catch(e){
                throw new Error('无法解析请求,即将断开客户端连接');
                self.end();
                return;
            }
            console.log(tData);
            if(app && app[key]){
                app[key].call(self, tData);
            }
            break;
        }
    }
}
<|endoftext|>


<commit_before>import chai from "chai";
import chaiAsPromised from "chai-as-promised";
import UserApp from "../UserApp";

chai.use(chaiAsPromised);
const { expect, assert } = chai;

describe("Router", async function() {
  const { router, context } = await UserApp();
  it("/login", async () => {
    // console.log("CONTEXT ", context);
    const route = await router.instance.resolve("/user/auth/login");
    assert(route);
    assert.equal(route.title, "Login");
  });
  it("/app/profile not authenticated", async () => {
    expect(router.instance.resolve("/profile")).to.be.rejectedWith(Error);
  });
  it.skip("/app/profile authenticated", async () => {
    context.parts.auth.stores().auth.authenticated = true;
    const route = await router.instance.resolve("/profile");
    assert.equal(route.title, "My Profile");
  });
});
<commit_msg>fix unit test<commit_after>import chai from "chai";
import chaiAsPromised from "chai-as-promised";
import UserApp from "../UserApp";

chai.use(chaiAsPromised);
const { expect, assert } = chai;

describe("Router", async function() {
  const { router, context } = await UserApp();
  it("/login", async () => {
    const route = await router.instance.resolve("/auth/login");
    assert(route);
    assert(route.component)
    assert.equal(route.title, "Login");
  });
  it("/app/profile not authenticated", async () => {
    expect(router.instance.resolve("/profile")).to.be.rejectedWith(Error);
  });
});
<|endoftext|>


<commit_before>var cookie = require('cookie');

var _rawCookie = {};
var _res = undefined;

function load(name, doNotParse) {
  var cookies = (typeof document === 'undefined') ? _rawCookie : cookie.parse(document.cookie);
  var cookieVal = cookies && cookies[name];

  if (!doNotParse) {
    try {
      cookieVal = JSON.parse(cookieVal);
    } catch(e) {
      // Not serialized object
    }
  }

  return cookieVal;
}

function save(name, val, opt) {
  _rawCookie[name] = val;

  // allow you to work with cookies as objects.
  if (typeof val === 'object') {
    _rawCookie[name] = JSON.stringify(val);
  }

  // Cookies only work in the browser
  if (typeof document !== 'undefined') {
    document.cookie = cookie.serialize(name, _rawCookie[name], opt);
  }

  if (_res && _res.cookie) {
    _res.cookie(name, val, opt);
  }
}

function remove(name, opt) {
  delete _rawCookie[name];

  if (typeof opt === 'undefined') {
    opt = {};
  } else if (typeof opt === 'string') {
    // Will be deprecated in future versions
    opt = { path: opt };
  }

  if (typeof document !== 'undefined') {
    opt.expires = new Date(1970, 1, 1, 0, 0, 1);
    document.cookie = cookie.serialize(name, '', opt);
  }

  if (_res && _res.clearCookie) {
    _res.clearCookie(name, opt);
  }
}

function setRawCookie(rawCookie) {
  if (rawCookie) {
    _rawCookie = cookie.parse(rawCookie);
  } else {
    _rawCookie = {};
  }
}

function plugToRequest(req, res) {
  if (req.cookie) {
    _rawCookie = req.cookie;
  } else if (req.headers && req.headers.cookie) {
    setRawCookie(req.headers.cookie);
  } else {
    _rawCookie = {};
  }

  _res = res;
}

var reactCookie = {
  load: load,
  save: save,
  remove: remove,
  setRawCookie: setRawCookie,
  plugToRequest: plugToRequest
};

if (typeof window !== 'undefined') {
  window['reactCookie'] = reactCookie;
}

module.exports = reactCookie;
<commit_msg>Fix cookie-parser populates req.cookies (plural)<commit_after>var cookie = require('cookie');

var _rawCookie = {};
var _res = undefined;

function load(name, doNotParse) {
  var cookies = (typeof document === 'undefined') ? _rawCookie : cookie.parse(document.cookie);
  var cookieVal = cookies && cookies[name];

  if (!doNotParse) {
    try {
      cookieVal = JSON.parse(cookieVal);
    } catch(e) {
      // Not serialized object
    }
  }

  return cookieVal;
}

function save(name, val, opt) {
  _rawCookie[name] = val;

  // allow you to work with cookies as objects.
  if (typeof val === 'object') {
    _rawCookie[name] = JSON.stringify(val);
  }

  // Cookies only work in the browser
  if (typeof document !== 'undefined') {
    document.cookie = cookie.serialize(name, _rawCookie[name], opt);
  }

  if (_res && _res.cookie) {
    _res.cookie(name, val, opt);
  }
}

function remove(name, opt) {
  delete _rawCookie[name];

  if (typeof opt === 'undefined') {
    opt = {};
  } else if (typeof opt === 'string') {
    // Will be deprecated in future versions
    opt = { path: opt };
  }

  if (typeof document !== 'undefined') {
    opt.expires = new Date(1970, 1, 1, 0, 0, 1);
    document.cookie = cookie.serialize(name, '', opt);
  }

  if (_res && _res.clearCookie) {
    _res.clearCookie(name, opt);
  }
}

function setRawCookie(rawCookie) {
  if (rawCookie) {
    _rawCookie = cookie.parse(rawCookie);
  } else {
    _rawCookie = {};
  }
}

function plugToRequest(req, res) {
  if (req.cookie) {
    _rawCookie = req.cookie;
  } else if (req.cookies) {
    _rawCookie = req.cookies;
  } else if (req.headers && req.headers.cookie) {
    setRawCookie(req.headers.cookie);
  } else {
    _rawCookie = {};
  }

  _res = res;
}

var reactCookie = {
  load: load,
  save: save,
  remove: remove,
  setRawCookie: setRawCookie,
  plugToRequest: plugToRequest
};

if (typeof window !== 'undefined') {
  window['reactCookie'] = reactCookie;
}

module.exports = reactCookie;
<|endoftext|>


<commit_before>'use strict'

const debug = require('debug')('qool')

class Qool {
	constructor(db) {
		this._db = db
		this._data = db.sublevel('data')
		this._meta = db.sublevel('meta')
		this._batchSize = 1000
		this._counter = 0

		setInterval(() => {
			debug('reset key counter')
			this._counter = 0
		}, 1000)

		this._initLog()
		this._loop()
	}

	enqueue(data, cb) {
		debug('enqueue()', data)
		let key = [Date.now(), this._counter++]
		this._pushToBatch(new EnqueueOp(key, data, cb))
	}

	dequeue(timeout, cb) {
		debug('dequeue()')
		if (typeof(timeout) === 'function') {
			cb = timeout
			timeout = -1
		}

		this._pushToBatch(new DequeueOp(timeout, cb))
	}

	_pushToBatch(op) {
		let batch = this._log[this._log.length - 1]
		if (!batch || (batch.ops.length > this._batchSize)) {
			batch = new UnifiedBatch(this._batchSize)
			this._log.push(batch)
		}

		batch.push(op)
	}

	_loop() {
		if (this._log.length === 0) {
			return setImmediate(() => {
				this._loop()
			})
		}

		let log = this._log.reverse()
		this._initLog()

		let exec = () => {

			if (log.length === 0) {
				return this._loop()
			}

			log.pop().execute(this._data, this._meta, exec)
		}

		exec()
	}

	_initLog() {
		this._log = [] //new Array(10000)
	}
}

/**
 *
 */
class UnifiedBatch {
	constructor(maxBatchSize) {
		// since we're initializing these arrays we need to keep track of the actual
		// length to avoid processing undefined members
		this.ops = new Array(maxBatchSize)
		this.length = 0
		this.currentIndex = 0

		this.enqueueIndex = new Array(maxBatchSize)
		this.enqueueIndexLength = 0
		this.currentEnqueueIndex = 0

		this.batch = new Array(maxBatchSize)
		this.batchLength = 0

		this.bookmark = undefined
		this.start = undefined
	}

	execute(data, meta, cb) {
		debug('execute() %d ops from %d', this.ops.length, this.currentIndex)

		let executeOp = (op) => {
			return op.execute(this, data, (err, bookmark) => {
				if (err) {
					// break the batch
					return this.done(err, data, cb)
				}

				// update the bookmark
				if (bookmark) {
					this.bookmark = bookmark
				}

				if (op.batchOp) {
					this.batch[this.batchLength++] = op.batchOp
				}

				this.currentIndex++
				this.execute(data, meta, cb)
			})
		}

		for (;this.currentIndex < this.length; this.currentIndex++) {
			let op = this.ops[this.currentIndex]

			let proceed = executeOp(op)

			if (!proceed) {
				return
			}

			this.batch[this.batchLength++] = op.batchOp
		}

		this.done(null, data, cb)
	}

	push(op) {
		debug('UnifiedBatch: push()')
		this.ops[this.length++] = op
		if (op instanceof EnqueueOp) {
			this.enqueueIndex[this.enqueueIndexLength++] = op
		}
	}

	done(err, data, cb) {
		debug('UnifiedBatch: done()')
		if (err) {
			for (let i =  0; i < this.currentIndex; i++) {
				this.ops[i].done(err)
			}

			cb(err)
			return
		}

		debug('UnifiedBatch: done() 0 => %d', this.currentIndex)

		// we;re done so call all the cbs after batch
		data.batch(this.batch.slice(0, this.batchLength), (err) => {

			for (let i =  0; i < this.currentIndex; i++) {
				this.ops[i].done(err)
			}

			cb(err)
		})
	}

	getLastPut() {
		let lastPut = this.enqueueIndex[this.currentEnqueueIndex]
		if (lastPut) {
			this.currentEnqueueIndex++
		}

		return lastPut
	}
}

class DequeueOp {
	constructor(timeout, userCb) {
		this.batchOp = undefined
		this.timeout = timeout // not operational yet
		this.userCb = userCb
		this.value = undefined
		this.error = undefined
		this.bookmark = undefined
	}

	execute(batch, data, cb) {
		debug('DequeueOp: execute()')
		let lastPut = batch.getLastPut()

		if (lastPut) {
			this.batchOp = new DelOp(lastPut.batchOp.key)
			this.value = lastPut.batchOp.value
			return true
		}

		this._getHead(batch.bookmark, data, cb)
	}

	done(err) {
		if (this.userCb) {
			debug('DequeueOp: done()')
			this.userCb(err || this.error, this.value)
		}
	}

	_getHead(bookmark, data, cb) {
		debug('_getHead(%s)', bookmark)
		let entry, error
		let opts = {
			limit: 1,
			gt: bookmark
		}

		data.createReadStream(opts)
			.once('data', (_entry) => {
				this.value = _entry.value
				this.bookmark = _entry.key
			})
			.once('error', (err) => {
				err = error
			})
			.once('close', () => {
				if (error) {
					this[ERROR] = error
					return cb(error)
				}

				if (this.bookmark) {
					this.batchOp = new DelOp(this.bookmark)
				}

				cb(null, this.bookmark)
			})
	}
}

class EnqueueOp {
	constructor(key, value, userCb) {
		this.batchOp = new PutOp(key, value)
		this.userCb = userCb
		this.claimed = false
		this.error = undefined
	}

	execute(batch, data, cb) {
		debug('EnqueueOp: execute()')
		return true
	}

	isClaimed() {
		debug('EnqueueOp: isClaimed()')
		return this.claimed
	}

	claim() {
		debug('EnqueueOp: claim()')
		this.claimed = true
	}

	done(err) {
		if (this.userCb) {
			debug('EnqueueOp: done()')
			this.userCb(err || this.error)
		}
	}
}

class DelOp {
	constructor(key) {
		this.type = 'del'
		this.key = key
	}
}

class PutOp {
	constructor(key, value) {
		this.type = 'put'
		this.key = key
		this.value = value
	}
}

module.exports = Qool
<commit_msg>remove unused code<commit_after>'use strict'

const debug = require('debug')('qool')

class Qool {
	constructor(db) {
		this._db = db
		this._data = db.sublevel('data')
		this._meta = db.sublevel('meta')
		this._batchSize = 1000
		this._counter = 0

		setInterval(() => {
			debug('reset key counter')
			this._counter = 0
		}, 1000)

		this._initLog()
		this._loop()
	}

	enqueue(data, cb) {
		debug('enqueue()', data)
		let key = [Date.now(), this._counter++]
		this._pushToBatch(new EnqueueOp(key, data, cb))
	}

	dequeue(timeout, cb) {
		debug('dequeue()')
		if (typeof(timeout) === 'function') {
			cb = timeout
			timeout = -1
		}

		this._pushToBatch(new DequeueOp(timeout, cb))
	}

	_pushToBatch(op) {
		let batch = this._log[this._log.length - 1]
		if (!batch || (batch.ops.length > this._batchSize)) {
			batch = new UnifiedBatch(this._batchSize)
			this._log.push(batch)
		}

		batch.push(op)
	}

	_loop() {
		if (this._log.length === 0) {
			return setImmediate(() => {
				this._loop()
			})
		}

		let log = this._log.reverse()
		this._initLog()

		let exec = () => {

			if (log.length === 0) {
				return this._loop()
			}

			log.pop().execute(this._data, this._meta, exec)
		}

		exec()
	}

	_initLog() {
		this._log = [] //new Array(10000)
	}
}

/**
 *
 */
class UnifiedBatch {
	constructor(maxBatchSize) {
		// since we're initializing these arrays we need to keep track of the actual
		// length to avoid processing undefined members
		this.ops = new Array(maxBatchSize)
		this.length = 0
		this.currentIndex = 0

		this.enqueueIndex = new Array(maxBatchSize)
		this.enqueueIndexLength = 0
		this.currentEnqueueIndex = 0

		this.batch = new Array(maxBatchSize)
		this.batchLength = 0

		this.bookmark = undefined
		this.start = undefined
	}

	execute(data, meta, cb) {
		debug('execute() %d ops from %d', this.ops.length, this.currentIndex)

		let executeOp = (op) => {
			return op.execute(this, data, (err, bookmark) => {
				if (err) {
					// break the batch
					return this.done(err, data, cb)
				}

				// update the bookmark
				if (bookmark) {
					this.bookmark = bookmark
				}

				if (op.batchOp) {
					this.batch[this.batchLength++] = op.batchOp
				}

				this.currentIndex++
				this.execute(data, meta, cb)
			})
		}

		for (;this.currentIndex < this.length; this.currentIndex++) {
			let op = this.ops[this.currentIndex]

			let proceed = executeOp(op)

			if (!proceed) {
				return
			}

			this.batch[this.batchLength++] = op.batchOp
		}

		this.done(null, data, cb)
	}

	push(op) {
		debug('UnifiedBatch: push()')
		this.ops[this.length++] = op
		if (op instanceof EnqueueOp) {
			this.enqueueIndex[this.enqueueIndexLength++] = op
		}
	}

	done(err, data, cb) {
		debug('UnifiedBatch: done()')
		if (err) {
			for (let i =  0; i < this.currentIndex; i++) {
				this.ops[i].done(err)
			}

			cb(err)
			return
		}

		debug('UnifiedBatch: done() 0 => %d', this.currentIndex)

		// we;re done so call all the cbs after batch
		data.batch(this.batch.slice(0, this.batchLength), (err) => {

			for (let i =  0; i < this.currentIndex; i++) {
				this.ops[i].done(err)
			}

			cb(err)
		})
	}

	getLastPut() {
		let lastPut = this.enqueueIndex[this.currentEnqueueIndex]
		if (lastPut) {
			this.currentEnqueueIndex++
		}

		return lastPut
	}
}

class DequeueOp {
	constructor(timeout, userCb) {
		this.batchOp = undefined
		this.timeout = timeout // not operational yet
		this.userCb = userCb
		this.value = undefined
		this.error = undefined
		this.bookmark = undefined
	}

	execute(batch, data, cb) {
		debug('DequeueOp: execute()')
		let lastPut = batch.getLastPut()

		if (lastPut) {
			this.batchOp = new DelOp(lastPut.batchOp.key)
			this.value = lastPut.batchOp.value
			return true
		}

		this._getHead(batch.bookmark, data, cb)
	}

	done(err) {
		if (this.userCb) {
			debug('DequeueOp: done()')
			this.userCb(err || this.error, this.value)
		}
	}

	_getHead(bookmark, data, cb) {
		debug('_getHead(%s)', bookmark)
		let entry, error
		let opts = {
			limit: 1,
			gt: bookmark
		}

		data.createReadStream(opts)
			.once('data', (_entry) => {
				this.value = _entry.value
				this.bookmark = _entry.key
			})
			.once('error', (err) => {
				err = error
			})
			.once('close', () => {
				if (error) {
					this[ERROR] = error
					return cb(error)
				}

				if (this.bookmark) {
					this.batchOp = new DelOp(this.bookmark)
				}

				cb(null, this.bookmark)
			})
	}
}

class EnqueueOp {
	constructor(key, value, userCb) {
		this.batchOp = new PutOp(key, value)
		this.userCb = userCb
		this.error = undefined
	}

	execute(batch, data, cb) {
		debug('EnqueueOp: execute()')
		return true
	}

	done(err) {
		if (this.userCb) {
			debug('EnqueueOp: done()')
			this.userCb(err || this.error)
		}
	}
}

class DelOp {
	constructor(key) {
		this.type = 'del'
		this.key = key
	}
}

class PutOp {
	constructor(key, value) {
		this.type = 'put'
		this.key = key
		this.value = value
	}
}

module.exports = Qool
<|endoftext|>