<commit_before>'use babel'
/** @jsx vanilla.jsx */
import vanilla from 'vanilla-jsx'
import {CompositeDisposable} from 'atom'
import {createMessage} from './helpers'

export class Panel {
  constructor(visible) {
    this.subscriptions = new CompositeDisposable()
    this.element = this.createElement()

    this.configVisibility = visible
    this.paneVisibility = true
    this.subscriptions.add(atom.workspace.onDidChangeActivePaneItem(paneItem => {
      this.paneVisibility = paneItem && typeof paneItem.getText === 'function'
      this.updateVisibility()
      this.updateEditorElements()
    }))
    this.subscriptions.add(atom.config.onDidChange('linter-ui-default.showIssuesFromAllFiles', () => {
      this.updateEditorElements()
    }))

    this.panel = atom.workspace.addBottomPanel({
      item: this.element,
      visible: this.visibility,
      priority: 500
    })

    this.editorMessages = new WeakMap()
    this.editorElements = new Map()
    this.countElements = new Map()

    this.getEditorElement(null)
    // ^- Initialize element for no-file-path messages
    this.getCountElement('Error')
    this.getCountElement('Warning')
    // ^- Make sure these tabs are first of all
  }

  getCountElement(name) {
    if (this.countElements.has(name)) {
      return this.countElements.get(name)
    }
    const el = document.createElement('span')
    el.textContent = `${name}s: 0`
    el.setCount = function(count) {
      this.textContent = `${name}s: ${count}`
    }
    this.element.refs.counts.appendChild(el)
    this.countElements.set(name, el)
    return el
  }
  getEditorElement(path) {
    if (this.editorElements.has(path)) {
      return this.editorElements.get(path)
    }
    const el = document.createElement('div')
    el.setAttribute('hidden', true)
    el.countMap = {}
    this.element.refs.content.appendChild(el)
    this.editorElements.set(path, el)
    return el
  }
  updateEditorElements() {

    const showAll = atom.config.get('linter-ui-default.showIssuesFromAllFiles')
    const activeEditor = atom.workspace.getActiveTextEditor()
    const activePath = activeEditor ? activeEditor.getPath() || NaN : NaN
    const countMap = {}

    let showContent = false
    this.editorElements.forEach((element, key) => {
      if (key !== null) {
        if (!element.children.length) {
          element.remove()
          this.editorElements.delete(key)
        } else {
          if (showAll || key === activePath) {
            showContent = true
            element.removeAttribute('hidden')
            for (let type in element.countMap) {
              if (countMap[type]) {
                countMap[type] += element.countMap[type]
              } else countMap[type] = element.countMap[type]
            }
          } else {
            element.setAttribute('hidden', true)
          }
        }
      }
    })
    if (showContent || this.editorElements.get(null).children.length) {
      this.element.refs.content.classList.remove('hide')
    } else {
      this.element.refs.content.classList.add('hide')
    }

    for (let type in countMap) {
      this.getCountElement(type).setCount(countMap[type])
    }
    this.countElements.forEach((element, type) => {
      if (!countMap[type]) {
        if (type !== 'Error' && type !== 'Warning' ) {
          this.countElements.delete(type)
          element.remove()
        } else {
          this.countElements.get(type).setCount(0)
        }
      }
    })
  }

  update({added, removed}) {
    if (added.length)
    added.forEach(message => {
      const messageElement = createMessage(message)
      const editorElement = this.getEditorElement(message.filePath)
      this.editorMessages.set(message, messageElement)
      editorElement.appendChild(messageElement)

      if (editorElement.countMap[message.type]) {
        editorElement.countMap[message.type]++
      } else {
        editorElement.countMap[message.type] = 1
      }
    })

    if(removed.length)
    removed.forEach(message => {
      const messageElement = this.editorMessages.get(message)
      messageElement.parentNode.countMap[message.type]--
      messageElement.remove()
    })

    this.updateEditorElements()
  }

  createElement() {
    const icons = {
      MIN: '🗕',
      MAX: '🗖'
    }
    let content

    const hidePanel = () => this.panel.hide()
    const toggleContent = function() {
      if (content.classList.contains('hidden')) {
        this.textContent = icons.MIN
        content.classList.remove('hidden')
      } else {
        this.textContent = icons.MAX
        content.classList.add('hidden')
      }
    }

    const el = <linter-new-panel tabindex="-1">

            Linter

            {icons.MIN}
            ✖

    </linter-new-panel>

    el.refs = {}
    content = el.refs.content = el.querySelector('.panel-body')
    el.refs.counts = el.querySelector('.heading-counts')

    return el
  }

  get visibility() {
    return this.configVisibility && this.paneVisibility
  }

  set visibility(visibility) {
    this.configVisibility = visibility
    this.updateVisibility()
  }

  updateVisibility() {
    if (this.visibility) {
      this.panel.show()
    } else {
      this.panel.hide()
    }
  }

  dispose() {
    this.subscriptions.dispose()
  }
}
<commit_msg>:new: Make ctrl-c work on bottom panel<commit_after>'use babel'
/** @jsx vanilla.jsx */
import vanilla from 'vanilla-jsx'
import {CompositeDisposable} from 'atom'
import {createMessage} from './helpers'
import Clipboard from 'clipboard'
// TODO: ^- when atom updates to a never version of Electron, change this to `require('electron').Clipboard`

export class Panel {
  constructor(visible) {
    this.subscriptions = new CompositeDisposable()
    this.element = this.createElement()

    this.configVisibility = visible
    this.paneVisibility = true
    this.subscriptions.add(atom.workspace.onDidChangeActivePaneItem(paneItem => {
      this.paneVisibility = paneItem && typeof paneItem.getText === 'function'
      this.updateVisibility()
      this.updateEditorElements()
    }))
    this.subscriptions.add(atom.config.onDidChange('linter-ui-default.showIssuesFromAllFiles', () => {
      this.updateEditorElements()
    }))

    this.panel = atom.workspace.addBottomPanel({
      item: this.element,
      visible: this.visibility,
      priority: 500
    })

    this.editorMessages = new WeakMap()
    this.editorElements = new Map()
    this.countElements = new Map()

    this.getEditorElement(null)
    // ^- Initialize element for no-file-path messages
    this.getCountElement('Error')
    this.getCountElement('Warning')
    // ^- Make sure these tabs are first of all
  }

  getCountElement(name) {
    if (this.countElements.has(name)) {
      return this.countElements.get(name)
    }
    const el = document.createElement('span')
    el.textContent = `${name}s: 0`
    el.setCount = function(count) {
      this.textContent = `${name}s: ${count}`
    }
    this.element.refs.counts.appendChild(el)
    this.countElements.set(name, el)
    return el
  }
  getEditorElement(path) {
    if (this.editorElements.has(path)) {
      return this.editorElements.get(path)
    }
    const el = document.createElement('div')
    el.setAttribute('hidden', true)
    el.countMap = {}
    this.element.refs.content.appendChild(el)
    this.editorElements.set(path, el)
    return el
  }
  updateEditorElements() {

    const showAll = atom.config.get('linter-ui-default.showIssuesFromAllFiles')
    const activeEditor = atom.workspace.getActiveTextEditor()
    const activePath = activeEditor ? activeEditor.getPath() || NaN : NaN
    const countMap = {}

    let showContent = false
    this.editorElements.forEach((element, key) => {
      if (key !== null) {
        if (!element.children.length) {
          element.remove()
          this.editorElements.delete(key)
        } else {
          if (showAll || key === activePath) {
            showContent = true
            element.removeAttribute('hidden')
            for (let type in element.countMap) {
              if (countMap[type]) {
                countMap[type] += element.countMap[type]
              } else countMap[type] = element.countMap[type]
            }
          } else {
            element.setAttribute('hidden', true)
          }
        }
      }
    })
    if (showContent || this.editorElements.get(null).children.length) {
      this.element.refs.content.classList.remove('hide')
    } else {
      this.element.refs.content.classList.add('hide')
    }

    for (let type in countMap) {
      this.getCountElement(type).setCount(countMap[type])
    }
    this.countElements.forEach((element, type) => {
      if (!countMap[type]) {
        if (type !== 'Error' && type !== 'Warning' ) {
          this.countElements.delete(type)
          element.remove()
        } else {
          this.countElements.get(type).setCount(0)
        }
      }
    })
  }

  update({added, removed}) {
    if (added.length)
    added.forEach(message => {
      const messageElement = createMessage(message)
      const editorElement = this.getEditorElement(message.filePath)
      this.editorMessages.set(message, messageElement)
      editorElement.appendChild(messageElement)

      if (editorElement.countMap[message.type]) {
        editorElement.countMap[message.type]++
      } else {
        editorElement.countMap[message.type] = 1
      }
    })

    if(removed.length)
    removed.forEach(message => {
      const messageElement = this.editorMessages.get(message)
      messageElement.parentNode.countMap[message.type]--
      messageElement.remove()
    })

    this.updateEditorElements()
  }

  createElement() {
    const icons = {
      MIN: '🗕',
      MAX: '🗖'
    }
    let content

    const hidePanel = () => this.panel.hide()
    const toggleContent = function() {
      if (content.classList.contains('hidden')) {
        this.textContent = icons.MIN
        content.classList.remove('hidden')
      } else {
        this.textContent = icons.MAX
        content.classList.add('hidden')
      }
    }

    const el = <linter-new-panel tabindex="-1">

            Linter

            {icons.MIN}
            ✖

    </linter-new-panel>

    el.refs = {}
    content = el.refs.content = el.querySelector('.panel-body')
    el.refs.counts = el.querySelector('.heading-counts')

    el.addEventListener('keydown', function(e) {
      if (e.which == 67 && e.ctrlKey) {
        Clipboard.writeText(getSelection().toString())
      }
    })

    return el
  }

  get visibility() {
    return this.configVisibility && this.paneVisibility
  }

  set visibility(visibility) {
    this.configVisibility = visibility
    this.updateVisibility()
  }

  updateVisibility() {
    if (this.visibility) {
      this.panel.show()
    } else {
      this.panel.hide()
    }
  }

  dispose() {
    this.subscriptions.dispose()
  }
}
<|endoftext|>


<commit_before>/**
 * skipper-better-s3
 *
 * @author     Robert Rossmann <rr.rossmann@me.com>
 * @copyright  2015 Robert Rossmann
 * @license    http://choosealicense.com/licenses/bsd-3-clause  BSD-3-Clause License
 */

'use strict'

const WritableStream = require('stream').Writable
    , path = require('path')
    , AWS = require('aws-sdk')
    , mime = require('mime')
    , merge = require('semantic-merge')
    , uuid = require('node-uuid')
    , local = require('local-scope')()
    , Hasher = require('./hasher')

module.exports = class Uploader extends WritableStream {

  constructor (opts) {

    // Initialise this writable stream in object mode
    super({ objectMode: true })

    const scope = local(this)

    // Save configuration options and the S3 client to local scope
    scope.opts = opts
    scope.client = new AWS.S3(opts.service)
  }

  _write (inStream, encoding, done) {

    // If there is a path property, this is an fs read stream
    // If not, this is probably a standard http upload stream
    // If even the fd property is missing, fall back to a generated name
    // (Both path and fd could be missing if we upload i.e. a zlib or crypto stream and the
    // originator did not read the documentation about having to provide this property 😀)
    const name = inStream.path ? path.parse(inStream.path).base
                               : inStream.fd || uuid.v4()
        , type = mime.lookup(name)
        , scope = local(this)
        , fd = scope.opts.dirname ? `${scope.opts.dirname}/${name}`
                                  : name
        , outStream = new Hasher()
        , params = merge({ Key: fd
                         , Body: outStream
                         , ContentType: type
                        })
                   .and(scope.opts.request)
                   .excluding('onProgress')
                   .into({})

        , request = scope.client.upload(params, scope.opts.options, (err, data) => {
          // If there has been an error with the upload, return immediately, otherwise the extra
          // object used below will be undefined and we will throw a completely unrelated error
          if (err)
            return done(err)

          // Attach the response data to the stream - Skipper packages this in its response to the
          // caller for further reuse
          inStream.extra = data
          // The ETag returned in the response is enclosed in double-quotes - I find this quite
          // irritating since I usually only care about the actual value - let's fix that once and
          // for all, for everyone!
          inStream.extra.ETag = inStream.extra.ETag.replace(/"/g, '')
          // Get the md5 hash we computed for this file stream and export it in the extras
          inStream.extra.md5 = outStream.md5('hex')
          // For non-http uploads, the fd and content-type are not available anywhere, so let's put
          // them to the extra as well, for convenience
          inStream.extra.fd = fd
          inStream.extra.ContentType = type

          return done(null, data)
        })

    // Fix the content type header on the request in case it was incorrectly detected
    // Wrong detection can happen when uploading via curl, for example.
    // Note that headers will only be provided for http uploads, not for fs read streams etc.
    if (inStream.headers instanceof Object)
      inStream.headers['content-type'] = type

    // Calculate md5 of the data being uploaded
    // We use this because the original assumption about the ETag being an md5 hash is only true
    // while doing single-part uploads of files smaller than 5GB. If it's larger or if the upload
    // is a multipart upload, the ETag is computed differently.
    inStream.pipe(outStream)

    // Attach progress handler, if provided
    if (typeof scope.opts.request.onProgress === 'function')
      this.trackProgress(request, scope.opts.request.onProgress)
  }

  trackProgress (request, handler) {

    // If there's no handler provided, do not attach any listeners
    if (typeof handler !== 'function')
      return

    // Generate a per-request unique ID
    const id = uuid.v4()

    request.on('httpUploadProgress', progress => {
      // Prepare Skipper-specific progress structure
      const written = progress.loaded
      // S3 docs say that progress.total may not always be present, so let's have some fallback
          , total = progress.total || request.body.byteCount || null
          , data =
            { id: id
            , fd: request.body.fd
            , name: request.body.name
            , written: written
            , total: total
            // If total is null, performing bitwise-or will change the result to 0
            // It also rounds down to an integer, which is kinda nice
            , percent: written / total * 100 | 0
            }

      handler(data)
    })
  }
}
<commit_msg>Fix dirname being added twice for generic streams<commit_after>/**
 * skipper-better-s3
 *
 * @author     Robert Rossmann <rr.rossmann@me.com>
 * @copyright  2015 Robert Rossmann
 * @license    http://choosealicense.com/licenses/bsd-3-clause  BSD-3-Clause License
 */

'use strict'

const WritableStream = require('stream').Writable
    , path = require('path')
    , AWS = require('aws-sdk')
    , mime = require('mime')
    , merge = require('semantic-merge')
    , uuid = require('node-uuid')
    , local = require('local-scope')()
    , Hasher = require('./hasher')

module.exports = class Uploader extends WritableStream {

  constructor (opts) {

    // Initialise this writable stream in object mode
    super({ objectMode: true })

    const scope = local(this)

    // Save configuration options and the S3 client to local scope
    scope.opts = opts
    scope.client = new AWS.S3(opts.service)
  }

  _write (inStream, encoding, done) {

    const scope = local(this)
    // If there is a path property, this is an fs read stream
    // If there is no path, but fd, this is a standard http upload stream
    // If even the fd property is missing, fall back to a generated name
    // (Both path and fd could be missing if we upload i.e. a zlib or crypto stream and the
    // originator did not read the documentation about having to provide this property 😀)
        , name = inStream.path ? path.parse(inStream.path).base
                               : inStream.fd || uuid.v4()
        , parts = path.parse(name)

    // If we got a dirname in config options, and it is not already in the fd, add it
    // Skipper adds dirname for regular uploads, but for generic streams, we need to take care of
    // this ourselves
    if (scope.opts.dirname && parts.dir !== scope.opts.dirname)
      parts.dir = scope.opts.dirname

    const fd = path.format(parts)     // eslint-disable-line one-var
        , type = mime.lookup(name)
        , outStream = new Hasher()
        , params = merge({ Key: fd
                         , Body: outStream
                         , ContentType: type
                        })
                   .and(scope.opts.request)
                   .excluding('onProgress')
                   .into({})

        , request = scope.client.upload(params, scope.opts.options, (err, data) => {
          // If there has been an error with the upload, return immediately, otherwise the extra
          // object used below will be undefined and we will throw a completely unrelated error
          if (err)
            return done(err)

          // Attach the response data to the stream - Skipper packages this in its response to the
          // caller for further reuse
          inStream.extra = data
          // The ETag returned in the response is enclosed in double-quotes - I find this quite
          // irritating since I usually only care about the actual value - let's fix that once and
          // for all, for everyone!
          inStream.extra.ETag = inStream.extra.ETag.replace(/"/g, '')
          // Get the md5 hash we computed for this file stream and export it in the extras
          inStream.extra.md5 = outStream.md5('hex')
          // For non-http uploads, the fd and content-type are not available anywhere, so let's put
          // them to the extra as well, for convenience
          inStream.extra.fd = fd
          inStream.extra.ContentType = type

          return done(null, data)
        })

    // Fix the content type header on the request in case it was incorrectly detected
    // Wrong detection can happen when uploading via curl, for example.
    // Note that headers will only be provided for http uploads, not for fs read streams etc.
    if (inStream.headers instanceof Object)
      inStream.headers['content-type'] = type

    // Calculate md5 of the data being uploaded
    // We use this because the original assumption about the ETag being an md5 hash is only true
    // while doing single-part uploads of files smaller than 5GB. If it's larger or if the upload
    // is a multipart upload, the ETag is computed differently.
    inStream.pipe(outStream)

    // Attach progress handler, if provided
    if (typeof scope.opts.request.onProgress === 'function')
      this.trackProgress(request, scope.opts.request.onProgress)
  }

  trackProgress (request, handler) {

    // If there's no handler provided, do not attach any listeners
    if (typeof handler !== 'function')
      return

    // Generate a per-request unique ID
    const id = uuid.v4()

    request.on('httpUploadProgress', progress => {
      // Prepare Skipper-specific progress structure
      const written = progress.loaded
      // S3 docs say that progress.total may not always be present, so let's have some fallback
          , total = progress.total || request.body.byteCount || null
          , data =
            { id: id
            , fd: request.body.fd
            , name: request.body.name
            , written: written
            , total: total
            // If total is null, performing bitwise-or will change the result to 0
            // It also rounds down to an integer, which is kinda nice
            , percent: written / total * 100 | 0
            }

      handler(data)
    })
  }
}
<|endoftext|>


<commit_before>var path = require('path');
var _ = require('lodash');
var Iterator = require('./iterator');

var DEFAULT_OPTIONS = {
    required: false,
    args: 0
};

function CLI() {
    this.options = [];
}

CLI.prototype.option = function (flag, alias, desc, required, args, def) {
    var option;
    if (_.isPlainObject(flag)) {
        option = _.defaults(flag, DEFAULT_OPTIONS);
    } else {
        option = {
            flag: flag,
            alias: alias,
            desc: desc,
            required: required || false,
            args: args || 0,
            def: def
        };
    }
    this.options.push(option);
    return this;
};

CLI.prototype.parse = function () {
    var it = new Iterator(getOpts());
    var argv = {
        '*': []
    };

    this.option({
        alias: 'help',
        desc: 'display this help and exit'
    });

    while (it.hasNext()) {
        var opt = it.next();
        if (_.startsWith(opt, '--')) {
            this.parseOpt(it, opt, opt.slice(2), true, argv);
        } else if (_.startsWith(opt, '-')) {
            this.parseOpt(it, opt, opt.slice(1), false, argv);
        } else {
            argv['*'].push(opt);
        }
    }

    if (argv.help) {
        this.usage();
    }

    return this.validate(argv);
};

/**
 * @private
 */
CLI.prototype.parseOpt = function (it, arg, name, alias, argv) {
    var option = _.find(this.options, function (opt) {
        return alias ? (opt.alias === name) : (opt.flag === name);
    });

    if (option === undefined) {
        unknownOption(arg);
    }

    var name = getName(option);
    if (option.args === 0) {
        argv[name] = true;
        return;
    }

    if (it.hasNext()) {
        var value = it.next();
        if (_.startsWith(value, '-')) {
            missingOptionArgument(arg);
        }

        if (option.args === 1) {
            argv[name] = value;
        } else {
            argv[name] = argv[name] || [];
            argv[name].push(value);
        }
        return;
    }

    missingOptionArgument(arg);
};

/**
 * @private
 */
CLI.prototype.validate = function (argv) {
    this.options.forEach(function (option) {
        var name = getName(option);
        if (argv[name] === undefined) {
            if (option.required) {
                missingRequiredOption(option);
                return false;
            }
            if (option.def !== undefined) {
                argv[name] = option.def;
            }
        }
    });
    return argv;
};

CLI.prototype.usage = function () {
    var script = path.basename(process.argv[1]);
    console.log('Usage: node %s [options] ...', script);
    console.log();
    console.log('Options:');

    this.options.forEach(function (option) {
        var str = '  ';

        str += option.flag ? ('-' + option.flag) : '  ';
        if (option.alias) {
            str += option.flag ? ',' : ' ';
            str += ' --' + option.alias;
        }
        if (option.args > 0) {
            str += ' [args]';
        }

        str = _.padRight(str, 32, ' ');
        str += option.desc;
        if (option.def) {
            str += ' (default: ' + option.def + ')';
        }
        console.log(str);
    });
    console.log();

    process.exit(0);
};

function getOpts() {
    var it = new Iterator(process.argv.slice(2));
    var argv = [];
    while (it.hasNext()) {
        var opt = it.next();
        if (_.startsWith(opt, '--')) {
            var pos = opt.indexOf('=');
            if (pos === -1) {
                argv.push(opt);
            } else {
                argv.push(opt.slice(0, pos));
                argv.push(opt.slice(pos + 1));
            }
        } else if (_.startsWith(opt, '-')) {
            for (var i = 1; i < opt.length; i++) {
                argv.push('-' + opt.charAt(i));
            }
        } else {
            argv.push(opt);
        }
    }
    return argv;
}

function getName(option) {
    if (option.alias) {
        return _.camelCase(option.alias);
    }
    return option.flag;
}

function unknownOption(name) {
    console.error();
    console.error("  error: unknown option '%s'", name);
    console.error();
    process.exit(1);
}

function missingRequiredOption(option) {
    var name = '';
    if (option.flag) {
        name = '-' + option.flag;
    }
    if (option.alias) {
        if (name.length > 0) {
            name += ', ';
        }
        name += '--' + option.alias;
    }
    console.error();
    console.error("  error: option '%s' missing", name);
    console.error();
    process.exit(1);
}

function missingOptionArgument(name) {
    console.error();
    console.error("  error: option '%s' argument missing", name);
    console.error();
    process.exit(1);
}

module.exports = new CLI();
<commit_msg>Update cli.js<commit_after>var path = require('path');
var _ = require('lodash');
var Iterator = require('./iterator');

var DEFAULT_OPTIONS = {
    required: false,
    args: 0
};

/**
 var argv = cli
    .option('h', 'host', 'target hostname/ip', true, 1)
    .option('', 'port', 'target port', false, 1, "22")
    .option('u', 'username', 'username for authentication', false, 1, 'admin')
    .option('p', 'password', 'password for authentication', false, 1, 'default')
    .option('f', 'file-list', 'file list to synchronize', false, 1, 'filelist.json')
    .parse();
 */

function CLI() {
    this.options = [];
}

CLI.prototype.option = function (flag, alias, desc, required, args, def) {
    var option;
    if (_.isPlainObject(flag)) {
        option = _.defaults(flag, DEFAULT_OPTIONS);
    } else {
        option = {
            flag: flag,
            alias: alias,
            desc: desc,
            required: required || false,
            args: args || 0,
            def: def
        };
    }
    this.options.push(option);
    return this;
};

CLI.prototype.parse = function () {
    var it = new Iterator(getOpts());
    var argv = {
        '*': []
    };

    this.option({
        alias: 'help',
        desc: 'display this help and exit'
    });

    while (it.hasNext()) {
        var opt = it.next();
        if (_.startsWith(opt, '--')) {
            this.parseOpt(it, opt, opt.slice(2), true, argv);
        } else if (_.startsWith(opt, '-')) {
            this.parseOpt(it, opt, opt.slice(1), false, argv);
        } else {
            argv['*'].push(opt);
        }
    }

    if (argv.help) {
        this.usage();
    }

    return this.validate(argv);
};

/**
 * @private
 */
CLI.prototype.parseOpt = function (it, arg, name, alias, argv) {
    var option = _.find(this.options, function (opt) {
        return alias ? (opt.alias === name) : (opt.flag === name);
    });

    if (option === undefined) {
        unknownOption(arg);
    }

    var name = getName(option);
    if (option.args === 0) {
        argv[name] = true;
        return;
    }

    if (it.hasNext()) {
        var value = it.next();
        if (_.startsWith(value, '-')) {
            missingOptionArgument(arg);
        }

        if (option.args === 1) {
            argv[name] = value;
        } else {
            argv[name] = argv[name] || [];
            argv[name].push(value);
        }
        return;
    }

    missingOptionArgument(arg);
};

/**
 * @private
 */
CLI.prototype.validate = function (argv) {
    this.options.forEach(function (option) {
        var name = getName(option);
        if (argv[name] === undefined) {
            if (option.required) {
                missingRequiredOption(option);
                return false;
            }
            if (option.def !== undefined) {
                argv[name] = option.def;
            }
        }
    });
    return argv;
};

CLI.prototype.usage = function () {
    var script = path.basename(process.argv[1]);
    console.log('Usage: node %s [options] ...', script);
    console.log();
    console.log('Options:');

    this.options.forEach(function (option) {
        var str = '  ';

        str += option.flag ? ('-' + option.flag) : '  ';
        if (option.alias) {
            str += option.flag ? ',' : ' ';
            str += ' --' + option.alias;
        }
        if (option.args > 0) {
            str += ' [args]';
        }

        str = _.padRight(str, 32, ' ');
        str += option.desc;
        if (option.def) {
            str += ' (default: ' + option.def + ')';
        }
        console.log(str);
    });
    console.log();

    process.exit(0);
};

function getOpts() {
    var it = new Iterator(process.argv.slice(2));
    var argv = [];
    while (it.hasNext()) {
        var opt = it.next();
        if (_.startsWith(opt, '--')) {
            var pos = opt.indexOf('=');
            if (pos === -1) {
                argv.push(opt);
            } else {
                argv.push(opt.slice(0, pos));
                argv.push(opt.slice(pos + 1));
            }
        } else if (_.startsWith(opt, '-')) {
            for (var i = 1; i < opt.length; i++) {
                argv.push('-' + opt.charAt(i));
            }
        } else {
            argv.push(opt);
        }
    }
    return argv;
}

function getName(option) {
    if (option.alias) {
        return _.camelCase(option.alias);
    }
    return option.flag;
}

function unknownOption(name) {
    console.error();
    console.error("  error: unknown option '%s'", name);
    console.error();
    process.exit(1);
}

function missingRequiredOption(option) {
    var name = '';
    if (option.flag) {
        name = '-' + option.flag;
    }
    if (option.alias) {
        if (name.length > 0) {
            name += ', ';
        }
        name += '--' + option.alias;
    }
    console.error();
    console.error("  error: option '%s' missing", name);
    console.error();
    process.exit(1);
}

function missingOptionArgument(name) {
    console.error();
    console.error("  error: option '%s' argument missing", name);
    console.error();
    process.exit(1);
}

module.exports = new CLI();
<|endoftext|>


<commit_before>/**
 * Created by dm on 2/6/16.
 */
'use strict';
const _ = require('underscore');

class Validate {
    /**
     * Main Validator requires Validation Rules Table, and Object to validate
     * @param validationMap
     * @param objectToValidate
     */
    run(validationMap, objectToValidate) {
        var errors = null;
        // Ensure arguments are objects - Critical error
        if (!_.isObject(validationMap)) {
            return ['Critical: validationMap is not an object'];
        }
        if (!_.isObject(objectToValidate)) {
            return ['Critical: objectToValidate is not an object'];
        }

        return (function () {
            // Iterate over validation rules and invoke 'validate'
            _.each(validationMap, function (elem) {
                // Tokenize the key key = person.name etc
                var tokens = elem.key.split('.');
                var dynamicKey = ['objectToValidate'];
                var index = 0;
                // Create Dynamic Keys for JSON lookup
                _.each(tokens, function () {
                    dynamicKey.push('[tokens[' + index + ']]');
                    index++;
                });
                // Dynamically Create function to retrieve value from objectToValidate
                const lookup = new Function('objectToValidate', 'tokens', 'return ' + dynamicKey.join('') + '');
                const value = lookup(objectToValidate, tokens);
                // validate is a function reference described on the validationMap
                if (!elem.validate(value)) {
                    errors = errors === null ? errors = [] : errors;
                    errors.push(elem.error);
                }
            });
            errors = errors === null ? errors = [] : errors;
            return errors;
        })();
    }

    /**
     * Helper Function
     * @param email
     * @returns {boolean}
     */
    isEmail(email) {
        const regexp = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        return regexp.test(email);
    }

    /**
     * Helper Function - first class function - prime the pump with PRECISION
     * @param PRECISION
     * @returns {boolean}
     */
    isDecimal(PRECISION) {
        return function _isDecimal(number) {
            const newR = new RegExp('^(\\d+)?([.]?\\d{' + PRECISION + ',' + PRECISION + '})?$', 'g');
            return newR.test(number);
        };
    }

    /**
     * Helper Function - first class function - prime the pump with FROM TO
     * @param FROM
     * @param TO
     * @returns {Function}
     */
    range(FROM, TO) {
        return function _range(number) {
            return (number >= FROM) && (number <= TO);
        };
    }

    /**
     * Helper Function - first class function - prime the pump with GROUP
     * @param GROUP initializer
     * @returns {Function}
     */
    inGroup(GROUP) {
        return function _inGroup(value) {
            return _.indexOf(GROUP, value) >= 0;
        };
    }
}

module.exports = Validate;

<commit_msg>remove eval<commit_after>/**
 * Created by dm on 2/6/16.
 */
'use strict';
const _ = require('underscore');

class Validate {

    constructor() {};
    /**
     * Main Validator requires Validation Rules Table, and Object to validate
     * @param validationMap
     * @param objectToValidate
     */
    run(validationMap, objectToValidate) {
        var errors = null;
        // Ensure arguments are objects - Critical error
        if (!_.isObject(validationMap)) {
            return ['Critical: validationMap is not an object'];
        }
        if (!_.isObject(objectToValidate)) {
            return ['Critical: objectToValidate is not an object'];
        }
        /**
         * Returns a self invoking function () closure
         */
        return (function () {
            // Iterate over validation rules and invoke 'validate'
            _.each(validationMap, function (elem) {
                // Tokenize the key key = person.name etc and Lookup the value
                const tokens = elem.key.split('.');
                const value = lookupValue(objectToValidate,tokens);
                // validate is a function reference described on the validationMap
                if (!elem.validate(value)) {
                    errors = errors === null ? errors = [] : errors;
                    errors.push(elem.error);
                }
            });
            errors = errors === null ? errors = [] : errors;
            return errors;
        })();
    }

    /**
     * Helper Function
     * @param email
     * @returns {boolean}
     */
    isEmail(email) {
        const regexp = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
        return regexp.test(email);
    }

    /**
     * Helper Function - first class function - prime the pump with PRECISION
     * @param PRECISION
     * @returns {boolean}
     */
    isDecimal(PRECISION) {
        return function _isDecimal(number) {
            const newR = new RegExp('^(\\d+)?([.]?\\d{' + PRECISION + ',' + PRECISION + '})?$', 'g');
            return newR.test(number);
        };
    }

    /**
     * Helper Function - first class function - prime the pump with FROM TO
     * @param FROM
     * @param TO
     * @returns {Function}
     */
    range(FROM, TO) {
        return function _range(number) {
            return (number >= FROM) && (number <= TO);
        };
    }

    /**
     * Helper Function - first class function - prime the pump with GROUP
     * @param GROUP initializer
     * @returns {Function}
     */
    inGroup(GROUP) {
        return function _inGroup(value) {
            return _.indexOf(GROUP, value) >= 0;
        };
    }
}

/**
 * Module specific embeded function
 * Constraint Return 5 level deep - Constraint
 * @param objectToValidate
 * @param names
 * @returns {*}
 */
var lookupValue = function(objectToValidate, names) {

    var lookupIndex = null;
    var i = names.length-1;
    switch (i) {
        case 0:
            lookupIndex = objectToValidate[names[i]];
            break;
        case 1:
            lookupIndex = objectToValidate[names[i-1]][names[i]];
            break;
        case 2:
            lookupIndex = objectToValidate[names[i-2]][names[i-1]][names[i]];
            break;
        case 3:
            lookupIndex = objectToValidate[names[i-3]][names[i-2]][names[i-1]][names[i]];
            break;
        case 4:
            lookupIndex = objectToValidate[names[i-4]][names[i-3]][names[i-2]][names[i-1]][names[i]];
            break;
    }

    return lookupIndex;
};

module.exports = Validate;

<|endoftext|>


<commit_before>var gulp = require('gulp');
var filter = require('gulp-filter');
var cleancss = require('gulp-clean-css');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var confirm = require('gulp-prompt').confirm;
var rsync = require('gulp-rsync');
var replace = require('gulp-replace');
var octophant = require('octophant');
var sequence = require('run-sequence');
var inquirer = require('inquirer');
var exec = require('child_process').execSync;
var plumber = require('gulp-plumber');

var CONFIG = require('../config.js');
var CURRENT_VERSION = require('../../package.json').version;
var NEXT_VERSION;

gulp.task('deploy', function(cb) {
  sequence('deploy:prompt', 'deploy:version', 'deploy:dist', 'deploy:plugins', 'deploy:settings', 'deploy:commit', 'deploy:templates', cb);
});

gulp.task('deploy:prep', function(cb) {
  sequence('deploy:prompt', 'deploy:version', 'deploy:dist', 'deploy:plugins', 'deploy:settings', cb);
});

gulp.task('deploy:prompt', function(cb) {
  inquirer.prompt([{
    type: 'input',
    name: 'version',
    message: 'What version are we moving to? (Current version is ' + CURRENT_VERSION + ')'
  }])
  .then(function(res) {
    NEXT_VERSION = res.version;
    cb();
  });
});

// Bumps the version number in any file that has one
gulp.task('deploy:version', function() {
  return gulp.src(CONFIG.VERSIONED_FILES, { base: process.cwd() })
    .pipe(replace(CURRENT_VERSION, NEXT_VERSION))
    .pipe(gulp.dest('.'));
});

// Generates compiled CSS and JS files and puts them in the dist/ folder
gulp.task('deploy:dist', ['sass:foundation', 'javascript:foundation'], function() {
  var cssFilter = filter(['**/*.css'], { restore: true });
  var jsFilter  = filter(['**/*.js'], { restore: true });
  var cssSourcemapFilter = filter(['**/*.css.map'], { restore: true });
  var jsSourcemapFilter = filter(['**/*.js.map'], { restore: true });

  console.log(CONFIG.DIST_FILES)
  return gulp.src(CONFIG.DIST_FILES)
    .pipe(plumber())
    .pipe(cssFilter)
      .pipe(gulp.dest('./dist/css'))
      .pipe(cleancss({ compatibility: 'ie9' }))
      .pipe(rename({ suffix: '.min' }))
      .pipe(gulp.dest('./dist/css'))
    .pipe(cssFilter.restore)
    .pipe(cssSourcemapFilter)
      .pipe(gulp.dest('./dist/css'))
    .pipe(cssSourcemapFilter.restore)
    .pipe(jsFilter)
      .pipe(gulp.dest('./dist/js'))
      .pipe(uglify())
      .pipe(rename({ suffix: '.min' }))
    .pipe(gulp.dest('./dist/js'))
    .pipe(jsSourcemapFilter)
      .pipe(gulp.dest('./dist/js'))
    .pipe(jsSourcemapFilter.restore);
});

// Copies standalone JavaScript plugins to dist/ folder
gulp.task('deploy:plugins', function() {
  gulp.src('_build/assets/js/plugins/*.js')
    .pipe(gulp.dest('dist/js/plugins'))
    .pipe(uglify())
    .pipe(rename({ suffix: '.min' }))
    .pipe(gulp.dest('dist/js/plugins'));
});

// Generates a settings file
gulp.task('deploy:settings', function(cb) {
  var options = {
    title: 'Foundation for Sites Settings',
    output: './scss/settings/_settings.scss',
    groups: {
      'grid': 'The Grid',
      'off-canvas': 'Off-canvas',
      'typography-base': 'Base Typography'
    },
    sort: [
      'global',
      'breakpoints',
      'grid',
      'typography-base',
      'typography-helpers'
    ],
    imports: ['util/util'],
    _foundationShim: true
  }

  octophant('./scss', options, cb);
});

// Writes a commit with the changes to the version numbers
gulp.task('deploy:commit', function(cb) {
  exec('git commit -am "Bump to version "' + NEXT_VERSION);
  exec('git tag v' + NEXT_VERSION);
  exec('git push origin develop --follow-tags');
  cb();
});

// Uploads the documentation to the live server
gulp.task('deploy:docs', ['build'], function() {
  return gulp.src('./_build/**')
    .pipe(confirm('Make sure everything looks right before you deploy.'))
    .pipe(rsync({
      root: './_build',
      hostname: 'deployer@72.32.134.77',
      destination: '/home/deployer/sites/foundation-sites-6-docs'
    }));
  });

// Uploads the documentation to the live server in beta env
gulp.task('deploy:beta', ['build'], function() {
  return gulp.src('./_build/**')
    .pipe(confirm('Make sure everything looks right before you deploy.'))
    .pipe(rsync({
      root: './_build',
      hostname: 'deployer@72.32.134.77',
      destination: '/home/deployer/sites/scalingsexiness/foundation-sites-6-docs'
    }));
});

// This part of the deploy process hasn't been tested! It should be done manually for now
gulp.task('deploy:templates', function(done) {
  // exec('git clone https://github.com/zurb/foundation-sites-template');
  // exec('cp scss/settings/_settings.scss foundation-sites-template/scss/_settings.scss');
  // exec('cd foundation-sites-template');
  // exec('git commit -am "Update settings file to match Foundation "' + NEXT_VERSION);
  // exec('git push origin master');
  // exec('cd ..');
  // exec('rm -rf foundation-sites-template');
  //
  // exec('git clone https://github.com/zurb/foundation-zurb-template');
  // exec('cp scss/settings/_settings.scss foundation-zurb-template/src/assets/scss/_settings.scss');
  // exec('cd foundation-zurb-template');
  // exec('git commit -am "Update settings file to match Foundation "' + NEXT_VERSION);
  // exec('git push origin master');
  // exec('cd ..');
  // exec('rm -rf foundation-zurb-template');
  done();
});

// The Customizer runs this function to generate files it needs
gulp.task('deploy:custom', ['sass:foundation', 'javascript:foundation'], function() {
  gulp.src('./_build/assets/css/foundation.css')
      .pipe(cleancss({ compatibility: 'ie9' }))
      .pipe(rename('foundation.min.css'))
      .pipe(gulp.dest('./_build/assets/css'));

  return gulp.src('_build/assets/js/foundation.js')
      .pipe(uglify())
      .pipe(rename('foundation.min.js'))
      .pipe(gulp.dest('./_build/assets/js'));
});
<commit_msg>chore: add sourcemaps for minified files<commit_after>var gulp = require('gulp');
var filter = require('gulp-filter');
var cleancss = require('gulp-clean-css');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var confirm = require('gulp-prompt').confirm;
var rsync = require('gulp-rsync');
var replace = require('gulp-replace');
var octophant = require('octophant');
var sequence = require('run-sequence');
var inquirer = require('inquirer');
var exec = require('child_process').execSync;
var plumber = require('gulp-plumber');
var sourcemaps = require('gulp-sourcemaps');

var CONFIG = require('../config.js');
var CURRENT_VERSION = require('../../package.json').version;
var NEXT_VERSION;

gulp.task('deploy', function(cb) {
  sequence('deploy:prompt', 'deploy:version', 'deploy:dist', 'deploy:plugins', 'deploy:settings', 'deploy:commit', 'deploy:templates', cb);
});

gulp.task('deploy:prep', function(cb) {
  sequence('deploy:prompt', 'deploy:version', 'deploy:dist', 'deploy:plugins', 'deploy:settings', cb);
});

gulp.task('deploy:prompt', function(cb) {
  inquirer.prompt([{
    type: 'input',
    name: 'version',
    message: 'What version are we moving to? (Current version is ' + CURRENT_VERSION + ')'
  }])
  .then(function(res) {
    NEXT_VERSION = res.version;
    cb();
  });
});

// Bumps the version number in any file that has one
gulp.task('deploy:version', function() {
  return gulp.src(CONFIG.VERSIONED_FILES, { base: process.cwd() })
    .pipe(replace(CURRENT_VERSION, NEXT_VERSION))
    .pipe(gulp.dest('.'));
});

// Generates compiled CSS and JS files and puts them in the dist/ folder
gulp.task('deploy:dist', ['sass:foundation', 'javascript:foundation'], function() {
  var cssFilter = filter(['**/*.css'], { restore: true });
  var jsFilter  = filter(['**/*.js'], { restore: true });
  var cssSourcemapFilter = filter(['**/*.css.map'], { restore: true });
  var jsSourcemapFilter = filter(['**/*.js.map'], { restore: true });

  console.log(CONFIG.DIST_FILES)
  return gulp.src(CONFIG.DIST_FILES)
    .pipe(plumber())
    .pipe(cssSourcemapFilter)
      .pipe(gulp.dest('./dist/css'))
      .pipe(cssSourcemapFilter.restore)
    .pipe(jsSourcemapFilter)
      .pipe(gulp.dest('./dist/js'))
      .pipe(jsSourcemapFilter.restore)
    .pipe(cssFilter)
      .pipe(gulp.dest('./dist/css'))
      .pipe(sourcemaps.init({ loadMaps: true }))
      .pipe(rename({ suffix: '.min' }))
      .pipe(cleancss({ compatibility: 'ie9' }))
      .pipe(sourcemaps.write('.', {
        mapFile: function(path) { return path.replace('.css.map', '.min.css.map'); }
      }))
      .pipe(gulp.dest('./dist/css'))
      .pipe(cssFilter.restore)

    .pipe(jsFilter)
      .pipe(gulp.dest('./dist/js'))
      .pipe(sourcemaps.init({ loadMaps: true }))
      .pipe(rename({ suffix: '.min' }))
      .pipe(uglify())
      .pipe(sourcemaps.write('.', {
        mapFile: function(path) { return path.replace('.js.map', '.min.js.map'); }
      }))
      .pipe(gulp.dest('./dist/js'));
});

// Copies standalone JavaScript plugins to dist/ folder
gulp.task('deploy:plugins', function() {
  gulp.src('_build/assets/js/plugins/*.js')
    .pipe(gulp.dest('dist/js/plugins'))
    .pipe(uglify())
    .pipe(rename({ suffix: '.min' }))
    .pipe(gulp.dest('dist/js/plugins'));
});

// Generates a settings file
gulp.task('deploy:settings', function(cb) {
  var options = {
    title: 'Foundation for Sites Settings',
    output: './scss/settings/_settings.scss',
    groups: {
      'grid': 'The Grid',
      'off-canvas': 'Off-canvas',
      'typography-base': 'Base Typography'
    },
    sort: [
      'global',
      'breakpoints',
      'grid',
      'typography-base',
      'typography-helpers'
    ],
    imports: ['util/util'],
    _foundationShim: true
  }

  octophant('./scss', options, cb);
});

// Writes a commit with the changes to the version numbers
gulp.task('deploy:commit', function(cb) {
  exec('git commit -am "Bump to version "' + NEXT_VERSION);
  exec('git tag v' + NEXT_VERSION);
  exec('git push origin develop --follow-tags');
  cb();
});

// Uploads the documentation to the live server
gulp.task('deploy:docs', ['build'], function() {
  return gulp.src('./_build/**')
    .pipe(confirm('Make sure everything looks right before you deploy.'))
    .pipe(rsync({
      root: './_build',
      hostname: 'deployer@72.32.134.77',
      destination: '/home/deployer/sites/foundation-sites-6-docs'
    }));
  });

// Uploads the documentation to the live server in beta env
gulp.task('deploy:beta', ['build'], function() {
  return gulp.src('./_build/**')
    .pipe(confirm('Make sure everything looks right before you deploy.'))
    .pipe(rsync({
      root: './_build',
      hostname: 'deployer@72.32.134.77',
      destination: '/home/deployer/sites/scalingsexiness/foundation-sites-6-docs'
    }));
});

// This part of the deploy process hasn't been tested! It should be done manually for now
gulp.task('deploy:templates', function(done) {
  // exec('git clone https://github.com/zurb/foundation-sites-template');
  // exec('cp scss/settings/_settings.scss foundation-sites-template/scss/_settings.scss');
  // exec('cd foundation-sites-template');
  // exec('git commit -am "Update settings file to match Foundation "' + NEXT_VERSION);
  // exec('git push origin master');
  // exec('cd ..');
  // exec('rm -rf foundation-sites-template');
  //
  // exec('git clone https://github.com/zurb/foundation-zurb-template');
  // exec('cp scss/settings/_settings.scss foundation-zurb-template/src/assets/scss/_settings.scss');
  // exec('cd foundation-zurb-template');
  // exec('git commit -am "Update settings file to match Foundation "' + NEXT_VERSION);
  // exec('git push origin master');
  // exec('cd ..');
  // exec('rm -rf foundation-zurb-template');
  done();
});

// The Customizer runs this function to generate files it needs
gulp.task('deploy:custom', ['sass:foundation', 'javascript:foundation'], function() {
  gulp.src('./_build/assets/css/foundation.css')
      .pipe(cleancss({ compatibility: 'ie9' }))
      .pipe(rename('foundation.min.css'))
      .pipe(gulp.dest('./_build/assets/css'));

  return gulp.src('_build/assets/js/foundation.js')
      .pipe(uglify())
      .pipe(rename('foundation.min.js'))
      .pipe(gulp.dest('./_build/assets/js'));
});
<|endoftext|>


<commit_before>var gulp = require('gulp');
var autoprefixer = require('autoprefixer');
var browserSync = require('browser-sync').create();
var cleanCss = require('gulp-clean-css');
var concat = require('gulp-concat');
var mmq = require('gulp-merge-media-queries');
var plumber = require('gulp-plumber');
var postCss = require('gulp-postcss');
var runSequence = require('run-sequence');
var sass = require('gulp-sass');
var sassLint = require('gulp-sass-lint');

var log = require('../log/log.js');
var notifyError = require('../notify/error.js');

module.exports = function(config, log, error, success) {
  gulp.task('styles:lint', function() {
    return gulp.src(config.styles.lint.src)
      .pipe(plumber({
        errorHandler: error
      }))
      .pipe(sassLint({
        rules: {
          'single-line-per-selector': 0,
          'property-sort-order': 0,
          'force-pseudo-nesting': 0
        }
      }))
      .pipe(sassLint.format())
      .pipe(sassLint.failOnError())
      .pipe(plumber.stop());
  });

  gulp.task('styles:build', function() {
    return gulp.src(config.styles.build.src)
      .pipe(plumber({
        errorHandler: error
      }))
      .pipe(sass({
        noCache: true
      }).on('error', error))
      .pipe(mmq({
        log: true
      }))
      .pipe(postCss([autoprefixer({
        browsers: ['last 2 version']
      })]))
      .pipe(concat('main.min.css'))
      .pipe(cleanCss({
        level: 0
      }))
      .pipe(gulp.dest(config.styles.build.dest))
      .pipe(browserSync.stream())
      .pipe(plumber.stop());
  });

  gulp.task('styles', function(callback) {
    runSequence('styles:lint', 'styles:build', callback);
  });
};
<commit_msg>remove css lint colors literals<commit_after>var gulp = require('gulp');
var autoprefixer = require('autoprefixer');
var browserSync = require('browser-sync').create();
var cleanCss = require('gulp-clean-css');
var concat = require('gulp-concat');
var mmq = require('gulp-merge-media-queries');
var plumber = require('gulp-plumber');
var postCss = require('gulp-postcss');
var runSequence = require('run-sequence');
var sass = require('gulp-sass');
var sassLint = require('gulp-sass-lint');

var log = require('../log/log.js');
var notifyError = require('../notify/error.js');

module.exports = function(config, log, error, success) {
  gulp.task('styles:lint', function() {
    return gulp.src(config.styles.lint.src)
      .pipe(plumber({
        errorHandler: error
      }))
      .pipe(sassLint({
        rules: {
          'single-line-per-selector': 0,
          'property-sort-order': 0,
          'force-pseudo-nesting': 0,
          'no-color-keywords': 0,
          'no-color-literals': 0
        }
      }))
      .pipe(sassLint.format())
      .pipe(sassLint.failOnError())
      .pipe(plumber.stop());
  });

  gulp.task('styles:build', function() {
    return gulp.src(config.styles.build.src)
      .pipe(plumber({
        errorHandler: error
      }))
      .pipe(sass({
        noCache: true
      }).on('error', error))
      .pipe(mmq({
        log: true
      }))
      .pipe(postCss([autoprefixer({
        browsers: ['last 2 version']
      })]))
      .pipe(concat('main.min.css'))
      .pipe(cleanCss({
        level: 0
      }))
      .pipe(gulp.dest(config.styles.build.dest))
      .pipe(browserSync.stream())
      .pipe(plumber.stop());
  });

  gulp.task('styles', function(callback) {
    runSequence('styles:lint', 'styles:build', callback);
  });
};
<|endoftext|>


<commit_before>/**
 * @file  The file used to draw themeRiver view
 * @author  Deqing Li(annong035@gmail.com)
 */
define(function (require) {

    var poly = require('../line/poly');
    var graphic = require('../../util/graphic');
    var zrUtil = require('zrender/core/util');
    var DataDiffer = require('../../data/DataDiffer');

    return require('../../echarts').extendChartView({

        type: 'themeRiver',

        init: function () {
            this._layers = [];
        },

        render: function (seriesModel, ecModel, api) {
            var data = seriesModel.getData();
            var rawData = seriesModel.getRawData();

            if (!data.count()) {
                return;
            }

            var group = this.group;

            var layerSeries = seriesModel.getLayerSeries();

            var layoutInfo = data.getLayout('layoutInfo');
            var rect = layoutInfo.rect;
            var boundaryGap = layoutInfo.boundaryGap;

            group.attr('position', [0, rect.y + boundaryGap[0]]);

            function keyGetter(item) {
                return item.name;
            }
            var dataDiffer = new DataDiffer(
                this._layersSeries || [], layerSeries,
                keyGetter, keyGetter
            );

            var newLayersGroups = {};

            dataDiffer.add(zrUtil.bind(zrUtil.curry(process, 'add'), this))
                .update(zrUtil.bind(zrUtil.curry(process, 'update'), this))
                .remove(zrUtil.bind(zrUtil.curry(process, 'remove'), this))
                .execute();

            function process(status, idx, oldIdx) {
                var oldLayersGroups = this._layers;
                if (status === 'remove') {
                    group.remove(oldLayersGroups[idx]);
                    return;
                }
                var points0 = [];
                var points1 = [];
                var color;
                var indices = layerSeries[idx].indices;
                for (var j = 0; j < indices.length; j++) {
                    var layout = data.getItemLayout(indices[j]);
                    var x = layout.x;
                    var y0 = layout.y0;
                    var y = layout.y;

                    points0.push([x, y0]);
                    points1.push([x, y0 + y]);

                    color = rawData.getItemVisual(
                        data.getRawIndex(indices[j]), 'color'
                    );
                }

                var polygon;
                var text;
                var textLayout = data.getItemLayout(indices[0]);
                var itemModel = data.getItemModel(indices[j - 1]);
                var labelModel = itemModel.getModel('label.normal');
                var margin = labelModel.get('margin');
                if (status === 'add') {
                    var layerGroup = newLayersGroups[idx] = new graphic.Group();
                    polygon = new poly.Polygon({
                        shape: {
                            points: points0,
                            stackedOnPoints: points1,
                            smooth: 0.4,
                            stackedOnSmooth: 0.4,
                            smoothConstraint: false
                        },
                        z2: 0
                    });
                    text = new graphic.Text({
                        style: {
                            x: textLayout.x - margin,
                            y: textLayout.y0 + textLayout.y / 2
                        }
                    });
                    layerGroup.add(polygon);
                    layerGroup.add(text);
                    group.add(layerGroup);

                    polygon.setClipPath(createGridClipShape(polygon.getBoundingRect(), seriesModel, function () {
                        polygon.removeClipPath();
                    }));
                }
                else {
                    var layerGroup = oldLayersGroups[oldIdx];
                    polygon = layerGroup.childAt(0);
                    text = layerGroup.childAt(1);
                    group.add(layerGroup);

                    newLayersGroups[idx] = layerGroup;

                    graphic.updateProps(polygon, {
                        shape: {
                            points: points0,
                            stackedOnPoints: points1
                        }
                    }, seriesModel);

                    graphic.updateProps(text, {
                        style: {
                            x: textLayout.x - margin,
                            y: textLayout.y0 + textLayout.y / 2
                        }
                    }, seriesModel);
                }

                var hoverItemStyleModel = itemModel.getModel('itemStyle.emphasis');
                var itemStyleModel = itemModel.getModel('itemStyle.nomral');
                var textStyleModel = labelModel.getModel('textStyle');

                text.setStyle({
                    text: labelModel.get('show')
                        ? seriesModel.getFormattedLabel(indices[j - 1], 'normal')
                            || data.getName(indices[j - 1])
                        : '',
                    textFont: textStyleModel.getFont(),
                    textAlign: labelModel.get('textAlign'),
                    textVerticalAlign: 'middle'
                });

                polygon.setStyle(zrUtil.extend({
                    fill: color
                }, itemStyleModel.getItemStyle(['color'])));

                graphic.setHoverStyle(polygon, hoverItemStyleModel.getItemStyle());
            }

            this._layersSeries = layerSeries;
            this._layers = newLayersGroups;
        },

        dispose: function () {}
    });

    // add animation to the view
    function createGridClipShape(rect, seriesModel, cb) {
        var rectEl = new graphic.Rect({
            shape: {
                x: rect.x - 10,
                y: rect.y - 10,
                width: 0,
                height: rect.height + 20
            }
        });
        graphic.initProps(rectEl, {
            shape: {
                width: rect.width + 20,
                height: rect.height + 20
            }
        }, seriesModel, cb);

        return rectEl;
    }

});
<commit_msg>Fix typo in ThemeRiverView.js<commit_after>/**
 * @file  The file used to draw themeRiver view
 * @author  Deqing Li(annong035@gmail.com)
 */
define(function (require) {

    var poly = require('../line/poly');
    var graphic = require('../../util/graphic');
    var zrUtil = require('zrender/core/util');
    var DataDiffer = require('../../data/DataDiffer');

    return require('../../echarts').extendChartView({

        type: 'themeRiver',

        init: function () {
            this._layers = [];
        },

        render: function (seriesModel, ecModel, api) {
            var data = seriesModel.getData();
            var rawData = seriesModel.getRawData();

            if (!data.count()) {
                return;
            }

            var group = this.group;

            var layerSeries = seriesModel.getLayerSeries();

            var layoutInfo = data.getLayout('layoutInfo');
            var rect = layoutInfo.rect;
            var boundaryGap = layoutInfo.boundaryGap;

            group.attr('position', [0, rect.y + boundaryGap[0]]);

            function keyGetter(item) {
                return item.name;
            }
            var dataDiffer = new DataDiffer(
                this._layersSeries || [], layerSeries,
                keyGetter, keyGetter
            );

            var newLayersGroups = {};

            dataDiffer.add(zrUtil.bind(zrUtil.curry(process, 'add'), this))
                .update(zrUtil.bind(zrUtil.curry(process, 'update'), this))
                .remove(zrUtil.bind(zrUtil.curry(process, 'remove'), this))
                .execute();

            function process(status, idx, oldIdx) {
                var oldLayersGroups = this._layers;
                if (status === 'remove') {
                    group.remove(oldLayersGroups[idx]);
                    return;
                }
                var points0 = [];
                var points1 = [];
                var color;
                var indices = layerSeries[idx].indices;
                for (var j = 0; j < indices.length; j++) {
                    var layout = data.getItemLayout(indices[j]);
                    var x = layout.x;
                    var y0 = layout.y0;
                    var y = layout.y;

                    points0.push([x, y0]);
                    points1.push([x, y0 + y]);

                    color = rawData.getItemVisual(
                        data.getRawIndex(indices[j]), 'color'
                    );
                }

                var polygon;
                var text;
                var textLayout = data.getItemLayout(indices[0]);
                var itemModel = data.getItemModel(indices[j - 1]);
                var labelModel = itemModel.getModel('label.normal');
                var margin = labelModel.get('margin');
                if (status === 'add') {
                    var layerGroup = newLayersGroups[idx] = new graphic.Group();
                    polygon = new poly.Polygon({
                        shape: {
                            points: points0,
                            stackedOnPoints: points1,
                            smooth: 0.4,
                            stackedOnSmooth: 0.4,
                            smoothConstraint: false
                        },
                        z2: 0
                    });
                    text = new graphic.Text({
                        style: {
                            x: textLayout.x - margin,
                            y: textLayout.y0 + textLayout.y / 2
                        }
                    });
                    layerGroup.add(polygon);
                    layerGroup.add(text);
                    group.add(layerGroup);

                    polygon.setClipPath(createGridClipShape(polygon.getBoundingRect(), seriesModel, function () {
                        polygon.removeClipPath();
                    }));
                }
                else {
                    var layerGroup = oldLayersGroups[oldIdx];
                    polygon = layerGroup.childAt(0);
                    text = layerGroup.childAt(1);
                    group.add(layerGroup);

                    newLayersGroups[idx] = layerGroup;

                    graphic.updateProps(polygon, {
                        shape: {
                            points: points0,
                            stackedOnPoints: points1
                        }
                    }, seriesModel);

                    graphic.updateProps(text, {
                        style: {
                            x: textLayout.x - margin,
                            y: textLayout.y0 + textLayout.y / 2
                        }
                    }, seriesModel);
                }

                var hoverItemStyleModel = itemModel.getModel('itemStyle.emphasis');
                var itemStyleModel = itemModel.getModel('itemStyle.normal');
                var textStyleModel = labelModel.getModel('textStyle');

                text.setStyle({
                    text: labelModel.get('show')
                        ? seriesModel.getFormattedLabel(indices[j - 1], 'normal')
                            || data.getName(indices[j - 1])
                        : '',
                    textFont: textStyleModel.getFont(),
                    textAlign: labelModel.get('textAlign'),
                    textVerticalAlign: 'middle'
                });

                polygon.setStyle(zrUtil.extend({
                    fill: color
                }, itemStyleModel.getItemStyle(['color'])));

                graphic.setHoverStyle(polygon, hoverItemStyleModel.getItemStyle());
            }

            this._layersSeries = layerSeries;
            this._layers = newLayersGroups;
        },

        dispose: function () {}
    });

    // add animation to the view
    function createGridClipShape(rect, seriesModel, cb) {
        var rectEl = new graphic.Rect({
            shape: {
                x: rect.x - 10,
                y: rect.y - 10,
                width: 0,
                height: rect.height + 20
            }
        });
        graphic.initProps(rectEl, {
            shape: {
                width: rect.width + 20,
                height: rect.height + 20
            }
        }, seriesModel, cb);

        return rectEl;
    }

});
<|endoftext|>


<commit_before>// go.components.views
// ===================
// Generic, re-usable views for Go

(function(exports) {
  var utils = go.utils,
      functor = utils.functor,
      maybeByName = utils.maybeByName;

  var structures = go.components.structures,
      Extendable = structures.Extendable,
      ViewCollection = structures.ViewCollection;

  // A view that can be uniquely identified by its `uuid` property.
  var UniqueView = Backbone.View.extend({
    constructor: function(options) {
      options = options || {};
      Backbone.View.prototype.constructor.call(this, options);

      this.uuid = options.uuid || this.uuid || uuid.v4();

      // We need a way to uniquely identify a view (and its element) without
      // using its `id`, since this maps to the html id attribute. This causes
      // problems when set the id attribute to a uuid value which isn't a valid
      // html id attribute (for example, if it begins with a digit).
      this.$el.attr('data-uuid', _(this).result('uuid'));
    }
  });

  var MessageTextView = Backbone.View.extend({
    SMS_MAX_CHARS: 160,
    events: {
      'keyup': 'render'
    },
    initialize: function() {
      // we call render to output "0 characters used, 0 smses."
      this.render();
    },
    render: function() {
      var $p = this.$el.next();
      if (!$p.hasClass('textarea-char-count')) {
          $p = $('
');
          this.$el.after($p);
      }
      this.totalChars = this.$el.val().length;
      this.totalSMS = Math.ceil(this.totalChars / this.SMS_MAX_CHARS);
      $p.html(this.totalChars + ' characters used
' + this.totalSMS + ' smses');

      return this;
    }
  });

  var ConfirmView = Backbone.View.extend({
    className: 'modal hide fade in',

    template: 'JST.components_confirm',

    events: {
      'click .ok': 'onOk',
      'click .cancel': 'onCancel'
    },

    optional: false,
    animated: true,

    initialize: function(options) {
      options = _(options || {}).defaults({
        optional: this.optional,
        animate: this.animated,
        content: ''
      });

      this.dontShow = false;
      this.content = options.content;
      this.optional = options.optional;
      this.animate(options.animate);

      this.resetActionHandlers();
    },

    resetActionHandlers: function() {
      this.off('ok');
      this.off('cancel');

      this.on('ok', this.resetActionHandlers, this);
      this.on('cancel', this.resetActionHandlers, this);
    },

    animate: function(animated) {
      if (animated) { this.$el.addClass('fade in'); }
      else { this.$el.removeClass('fade in'); }
    },

    onOk: function() {
      if (this.optional) {
        this.dontShow = this.$('.dont-show').is(':checked');
      }

      this.trigger('ok');
      this.hide();
    },

    onCancel: function() {
      this.trigger('cancel');
      this.hide();
    },

    show: function() {
      if (this.dontShow) { this.trigger('ok'); }
      else { this.render(); }
      return this;
    },

    hide: function() {
      this.$el.modal('hide');
      return this;
    },

    render: function() {
      this.$el
        .appendTo($('body'))
        .html(maybeByName(this.template)({self: this}))
        .modal('show');

      return this;
    }
  });

  var PopoverView = Backbone.View.extend({
    target: null,

    popoverOptions: {},

    initialize: function(options) {
      if (options.target) { this.target = options.target; }
      if (options.popover) { this.popoverOptions = options.popover; }

      this.popover = null;
      this.hidden = true;
    },

    remove: function() {
      PopoverView.__super__.remove.apply(this, arguments);
      if (this.popover) { this.popover.destroy(); }
    },

    show: function() {
      this.render();

      if (!this.popover) {
        this.popover = _(this)
          .result('target')
          .popover(
            _({content: this.$el, html: true}).defaults(
            _(this).result('popoverOptions')))
          .data('popover');
      }

      this.popover.show();
      this.hidden = false;
      this.trigger('show');
      return this;
    },

    hide: function() {
      if (this.popover) {
        this.popover.hide();
        this.hidden = true;
      }

      this.trigger('hide');
      return this;
    },

    toggle: function() {
      return this.hidden
        ? this.show()
        : this.hide();
    }
  });

  var Partials = Extendable.extend({
    constructor: function(items) {
      this.items = {};
      _(items).each(this.add, this);
    },

    _ensureArray: function(obj) {
      if (obj instanceof ViewCollection) { return obj.values(); }

      return _.isArray(obj)
        ? obj
        : [obj];
    },

    add: function(partial, name) {
      this.items[name] = this._ensureArray(partial);
      return this;
    },

    toPlaceholders: function() {
      var placeholders = {};

      _(this.items).each(function(partial, name) {
        var placeholder = placeholders[name] = [];

        return partial.forEach(function(p, i) {
          placeholder.push('

");
        });
      });

      return placeholders;
    },

    applyPartial: function(p, $at, data) {
      if (p instanceof Backbone.View) {
        p.render();
        $at.replaceWith(p.$el);
        p.delegateEvents();
      } else {
        p = $(maybeByName(p)(data));
        $at.replaceWith(p);
      }

      return this;
    },

    applyTo: function(target, data) {
      var self = this;
      data = data || {};

      _(this.items).each(function(partial, name) {
        target.find('[data-partial="' + name + '"]').each(function() {
          var $at = $(this),
              i = $at.attr('data-partial-index');

          self.applyPartial(partial[i], $at, data);
        });
      });

      return this;
    }
  });

  var TemplateView = Backbone.View.extend({
    jst: null,

    partials: {},

    data: {},

    initialize: function(options) {
      if (options.data) { this.data = options.data; }
      if (options.jst) { this.jst = options.jst; }
      this.partials = _({}).extend(this.partials, options.partials || {});
    },

    render: function() {
      var partials = new Partials(this.partials),
          data = _(this).result('data');

      data.partials = partials.toPlaceholders();
      this.$el.html(maybeByName(this.jst)(data));

      partials.applyTo(this.$el, data);
      return this;
    }
  });

  _.extend(exports, {
    UniqueView: UniqueView,
    ConfirmView: ConfirmView,
    PopoverView: PopoverView,
    Partials: Partials,
    TemplateView: TemplateView,
    MessageTextView: MessageTextView
  });
})(go.components.views = {});
<commit_msg>Create a new boostrap popover each Popover.prototype.show() for cases where the target isn't always the same (this happens when a TemplateView is re-rendered, since .html() is used). Fixes the dialogue state multiple popover positioning bug.<commit_after>// go.components.views
// ===================
// Generic, re-usable views for Go

(function(exports) {
  var utils = go.utils,
      functor = utils.functor,
      maybeByName = utils.maybeByName;

  var structures = go.components.structures,
      Extendable = structures.Extendable,
      ViewCollection = structures.ViewCollection;

  // A view that can be uniquely identified by its `uuid` property.
  var UniqueView = Backbone.View.extend({
    constructor: function(options) {
      options = options || {};
      Backbone.View.prototype.constructor.call(this, options);

      this.uuid = options.uuid || this.uuid || uuid.v4();

      // We need a way to uniquely identify a view (and its element) without
      // using its `id`, since this maps to the html id attribute. This causes
      // problems when set the id attribute to a uuid value which isn't a valid
      // html id attribute (for example, if it begins with a digit).
      this.$el.attr('data-uuid', _(this).result('uuid'));
    }
  });

  var MessageTextView = Backbone.View.extend({
    SMS_MAX_CHARS: 160,
    events: {
      'keyup': 'render'
    },
    initialize: function() {
      // we call render to output "0 characters used, 0 smses."
      this.render();
    },
    render: function() {
      var $p = this.$el.next();
      if (!$p.hasClass('textarea-char-count')) {
          $p = $('
');
          this.$el.after($p);
      }
      this.totalChars = this.$el.val().length;
      this.totalSMS = Math.ceil(this.totalChars / this.SMS_MAX_CHARS);
      $p.html(this.totalChars + ' characters used
' + this.totalSMS + ' smses');

      return this;
    }
  });

  var ConfirmView = Backbone.View.extend({
    className: 'modal hide fade in',

    template: 'JST.components_confirm',

    events: {
      'click .ok': 'onOk',
      'click .cancel': 'onCancel'
    },

    optional: false,
    animated: true,

    initialize: function(options) {
      options = _(options || {}).defaults({
        optional: this.optional,
        animate: this.animated,
        content: ''
      });

      this.dontShow = false;
      this.content = options.content;
      this.optional = options.optional;
      this.animate(options.animate);

      this.resetActionHandlers();
    },

    resetActionHandlers: function() {
      this.off('ok');
      this.off('cancel');

      this.on('ok', this.resetActionHandlers, this);
      this.on('cancel', this.resetActionHandlers, this);
    },

    animate: function(animated) {
      if (animated) { this.$el.addClass('fade in'); }
      else { this.$el.removeClass('fade in'); }
    },

    onOk: function() {
      if (this.optional) {
        this.dontShow = this.$('.dont-show').is(':checked');
      }

      this.trigger('ok');
      this.hide();
    },

    onCancel: function() {
      this.trigger('cancel');
      this.hide();
    },

    show: function() {
      if (this.dontShow) { this.trigger('ok'); }
      else { this.render(); }
      return this;
    },

    hide: function() {
      this.$el.modal('hide');
      return this;
    },

    render: function() {
      this.$el
        .appendTo($('body'))
        .html(maybeByName(this.template)({self: this}))
        .modal('show');

      return this;
    }
  });

  var PopoverView = Backbone.View.extend({
    target: null,

    popoverOptions: {},

    initialize: function(options) {
      if (options.target) { this.target = options.target; }
      if (options.popover) { this.popoverOptions = options.popover; }

      this.popover = null;
      this.hidden = true;
    },

    remove: function() {
      PopoverView.__super__.remove.apply(this, arguments);
      if (this.popover) { this.popover.destroy(); }
    },

    show: function() {
      this.render();

      this.popover = _(this)
        .result('target')
        .popover(
          _({content: this.$el, html: true}).defaults(
          _(this).result('popoverOptions')))
        .data('popover');

      this.popover.show();
      this.hidden = false;
      this.trigger('show');
      return this;
    },

    hide: function() {
      if (this.popover) {
        this.popover.hide();
        this.hidden = true;
      }

      this.trigger('hide');
      return this;
    },

    toggle: function() {
      return this.hidden
        ? this.show()
        : this.hide();
    }
  });

  var Partials = Extendable.extend({
    constructor: function(items) {
      this.items = {};
      _(items).each(this.add, this);
    },

    _ensureArray: function(obj) {
      if (obj instanceof ViewCollection) { return obj.values(); }

      return _.isArray(obj)
        ? obj
        : [obj];
    },

    add: function(partial, name) {
      this.items[name] = this._ensureArray(partial);
      return this;
    },

    toPlaceholders: function() {
      var placeholders = {};

      _(this.items).each(function(partial, name) {
        var placeholder = placeholders[name] = [];

        return partial.forEach(function(p, i) {
          placeholder.push('

");
        });
      });

      return placeholders;
    },

    applyPartial: function(p, $at, data) {
      if (p instanceof Backbone.View) {
        p.render();
        $at.replaceWith(p.$el);
        p.delegateEvents();
      } else {
        p = $(maybeByName(p)(data));
        $at.replaceWith(p);
      }

      return this;
    },

    applyTo: function(target, data) {
      var self = this;
      data = data || {};

      _(this.items).each(function(partial, name) {
        target.find('[data-partial="' + name + '"]').each(function() {
          var $at = $(this),
              i = $at.attr('data-partial-index');

          self.applyPartial(partial[i], $at, data);
        });
      });

      return this;
    }
  });

  var TemplateView = Backbone.View.extend({
    jst: null,

    partials: {},

    data: {},

    initialize: function(options) {
      if (options.data) { this.data = options.data; }
      if (options.jst) { this.jst = options.jst; }
      this.partials = _({}).extend(this.partials, options.partials || {});
    },

    render: function() {
      var partials = new Partials(this.partials),
          data = _(this).result('data');

      data.partials = partials.toPlaceholders();
      this.$el.html(maybeByName(this.jst)(data));

      partials.applyTo(this.$el, data);
      return this;
    }
  });

  _.extend(exports, {
    UniqueView: UniqueView,
    ConfirmView: ConfirmView,
    PopoverView: PopoverView,
    Partials: Partials,
    TemplateView: TemplateView,
    MessageTextView: MessageTextView
  });
})(go.components.views = {});
<|endoftext|>


<commit_before>'use strict';
import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import url from 'url';
import { content_views } from './globals';
import { Auth0, HistoryAndTriggers } from './mixins';
import { NavbarMixin, Nav, Navbar, NavItem } from '../libs/bootstrap/navigation';
import jsonScriptEscape from '../libs/jsonScriptEscape';
import { RestMixin } from './rest';
import AffiliationModal from './affiliation/modal';
const AffiliationsList = require('./affiliation/affiliations.json');

var routes = {
    'curator': require('./curator').Curator
};

// Site information, including navigation
var portal = {
    portal_title: 'ClinGen',
    navUser: [
        {id: 'help', title: 'Help', url: '#'}, // dropdown Help menu button to both gene and variant help docs
        {id: 'variant', title: 'New Variant Curation', url: '/select-variant/'}, // link to VCI page /select-variant/
        {id: 'gene', title: 'New Gene Curation', url: '/create-gene-disease/'}, // link to GCI page /create-gene-disease/
        {id: 'space', title: 'space'}, // white space between
        {id: 'dashboard', title: 'Dashboard', icon: 'icon-home', url: '/dashboard/'},
        {id: 'demo', title: 'Demo Login'},
        {id: 'loginout', title: 'Login'}
        //{id: 'account', title: 'Account', url: '/account/'},
    ]
};

// Renders HTML common to all pages.
var App = module.exports = createReactClass({
    mixins: [Auth0, HistoryAndTriggers, RestMixin],

    triggers: {
        demo: 'triggerAutoLogin',
        login: 'triggerLogin',
        logout: 'triggerLogout'
    },

    // Note on context. state.context set from initial props. Navigating to other pages sets this state.
    // This state gets passed as a property to ContentView, so it should be referenced as props.context
    // from there.
    getInitialState: function() {
        var demoWarning = false;
        var productionWarning = false;
        if (/production.clinicalgenome.org/.test(url.parse(this.props.href).hostname)) {
            // check if production URL. Enable productionWarning if it is.
            productionWarning = true;
        } else if (!/^(www\.)?curation.clinicalgenome.org/.test(url.parse(this.props.href).hostname)) {
            // if neither production nor curation URL, enable demoWarning.
            demoWarning = true;
        }
        return {
            context: this.props.context, // Close to anti-pattern, but puts *initial* context into state
            slow: this.props.slow,
            href: this.props.href,
            errors: [],
            portal: portal,
            demoWarning: demoWarning,
            productionWarning: productionWarning,
            tempAffiliation: null, // Placeholder when user selects an option in the affiliation dropdown
            affiliation: {}, // Confirmed affiliation when user selects to continue in the modal
            affiliationModalButtonDisabled: true,
            isAffiliationModalOpen: false
        };
    },

    currentAction: function() {
        var href_url = url.parse(this.state.href);
        var hash = href_url.hash || '';
        var name;
        if (hash.slice(0, 2) === '#!') {
            name = hash.slice(2);
        }
        return name;
    },

    /**
     * Method to set states when the affiliation selection is changed
     * @param {event} e - Selection change event
     */
    handleOnChange(e) {
        this.setState({
            tempAffiliation: e.target.value !== 'Individual' ? JSON.parse(e.target.value) : {},
            affiliationModalButtonDisabled: false
        });
    },

    createCookie(name, value, days) {
        let expires = "";
        if (days) {
            let date = new Date();
            date.setTime(date.getTime() + (days*24*60*60*1000));
            expires = "; expires=" + date.toUTCString();
        }
        document.cookie = name + "=" + value + expires + "; path=/";
    },

    toggleAffiliationModal() {
        this.setState({
            affiliation: this.state.tempAffiliation,
            isAffiliationModalOpen: !this.state.isAffiliationModalOpen
        }, () => {
            this.createCookie('affiliation', JSON.stringify(this.state.affiliation));
            this.setState({tempAffiliation: null});
        });
    },

    /**
     * Method to trim affiliation URIs and return an array of IDs
     * @param {array} affiliations - List of affiliation URIs
     */
    getAffiliationIds(affiliations) {
        let idArray = [];
        affiliations.forEach(item => {
            let id = item.substr(14, 5);
            idArray.push(id);
        });
        return idArray;
    },

    getUserAffiliations(affiliations, staticAffiliations) {
        let affiliationArray = [];
        if (affiliations.length) {
            affiliations.forEach(id=> {
                for (let affiliation of staticAffiliations) {
                    if (affiliation.affiliation_id === id) {
                        affiliationArray.push(affiliation);
                    }
                }
            });
        }
        return affiliationArray;
    },

    renderAffiliationModal(affiliations) {
        // let affiliationIds = this.getAffiliationIds(affiliations);
        let userAffiliations = this.getUserAffiliations(affiliations, AffiliationsList);
        return (
            <AffiliationModal show={this.state.isAffiliationModalOpen} onClose={this.toggleAffiliationModal}
                buttonDisabled={this.state.affiliationModalButtonDisabled}>

Continue as an individual or as a member of an affiliation.

                    <select className="form-control" defaultValue="none" onChange={this.handleOnChange}>
                        <option value="none" disabled="disabled">Select</option>
                        <option value="" disabled="disabled"></option>
                        <option value="Individual">Individual</option>
                        {userAffiliations.map((affiliation, i) => {
                            return <option key={i} value={JSON.stringify(affiliation)}>{affiliation.affiliation_abbreviation}</option>;
                        })}
                    </select>

            </AffiliationModal>
        );
    },

    showAffiliationModal(affiliation) {
        this.setState({isAffiliationModalOpen: true}, () => {
            this.renderAffiliationModal(affiliation);
        });
    },

    render: function() {
        var content;
        var context = this.state.context;
        let session = this.state.session;
        let user_properties = session && session.user_properties;
        var href_url = url.parse(this.state.href);
        // Switching between collections may leave component in place
        var key = context && context['@id'];
        var current_action = this.currentAction();
        if (!current_action && context.default_page) {
            context = context.default_page;
        }
        if (context) {
            var ContentView = content_views.lookup(context, current_action);
            content = <ContentView {...this.props} context={context} href={this.state.href}
                loadingComplete={this.state.loadingComplete} session={session}
                portal={this.state.portal} navigate={this.navigate} href_url={href_url}
                demoVersion={this.state.demoWarning} affiliation={this.state.affiliation} />;
        }
        var errors = this.state.errors.map(function (error) {
            return

;
        });

        var appClass = 'done';
        if (this.state.slow) {
            appClass = 'communicating';
        }

        var title = context.title || context.name || context.accession || context['@id'];
        if (title && title != 'Home') {
            title = title + ' – ' + portal.portal_title;
        } else {
            title = portal.portal_title;
        }

        var canonical = this.props.href;
        if (context.canonical_uri) {
            if (href_url.host) {
                canonical = (href_url.protocol || '') + '//' + href_url.host + context.canonical_uri;
            } else {
                canonical = context.canonical_uri;
            }
        }

        let affiliation_cookie = this.state.affiliation_cookie;

        return (

                    <meta charSet="utf-8" />
                    <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
                    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                    <title>ClinGen</title>
                    <link rel="canonical" href={canonical} />

                    <link rel="stylesheet" href="@@cssFile" />

                        {this.state.demoWarning ?
                            <Notice noticeType='demo' noticeMessage={Note: This is a demo version of the site. Any data you enter will not be permanently saved.} />
                            : null}
                        {this.state.productionWarning ?
                            <Notice noticeType='production' noticeMessage={Do not use this URL for entering data. Please use curation.clinicalgenome.org instead.} />
                            : null}
                        {user_properties && user_properties.affiliation && this.state.affiliation && Object.keys(this.state.affiliation).length ?

                                    Affiliation: {this.state.affiliation.affiliation_fullname}

                                        <button type="button" className="btn btn-default btn-sm" onClick={this.showAffiliationModal.bind(null, user_properties.affiliation)}>Change Affiliation</button>

                            : null}
                        {user_properties && user_properties.affiliation && user_properties.affiliation.length && !affiliation_cookie ?
                            this.renderAffiliationModal(user_properties.affiliation)
                            : null}
                        {content}

        );
    },

    statics: {
        // Get data to display from page

                    <link rel="stylesheet" href="@@cssFile" />

                        {this.state.demoWarning ?
                            <Notice noticeType='demo' noticeMessage={Note: This is a demo version of the site. Any data you enter will not be permanently saved.} />
                            : null}
                        {this.state.productionWarning ?
                            <Notice noticeType='production' noticeMessage={Do not use this URL for entering data. Please use curation.clinicalgenome.org instead.} />
                            : null}
                        {user_properties && user_properties.affiliation && this.state.affiliation && Object.keys(this.state.affiliation).length ?

                                    Affiliation: {this.state.affiliation.affiliation_fullname}

                                        <button type="button" className="btn btn-default btn-sm" onClick={this.showAffiliationModal.bind(null, user_properties.affiliation)}>Change Affiliation</button>

                            : null}
                        {user_properties && user_properties.affiliation && user_properties.affiliation.length && !affiliation_cookie ?
                            this.renderAffiliationModal(user_properties.affiliation)
                            : null}
                        {content}

        );
    },

    statics: {
        // Get data to display from page