<commit_before>var fs   = require('fs'),
    _    = require('lodash'),
    path = require('path'),
    Events = require('events');

require('colors');

function DependencyError(message, modules) {
    this.name = 'DependencyError';
    this.message = message;
    this.modules = modules;
    this.stack = new Error(message).stack;
}
DependencyError.prototype = Error.prototype;

function Acqua(config) {
    config = config || {};

    this.log = config.log || function() {};
    this.err = config.err || function() {};
    this.emitter = config.emitter || new Events.EventEmitter();

    // namespaces {
    this.name = config.name || undefined;
    this.parent = config.parent || undefined;
    this.namespaces = [];
    // }

    this.dependencies = config.dependencies || [];

    this.context = {
        'acqua' : this
    };

    this.hotswap = config.hotswap;
}

Acqua.prototype.getFromNamespace = function (namespace, name) {
    var dependency = this.get(name),
        acquaDependency,
        i;

    for (i = 0; i < this.dependencies.length && dependency === undefined; i += 1) {
        acquaDependency = this.dependencies[i];
        if (acquaDependency.namespace(namespace) !== undefined) {
            dependency = acquaDependency.namespace(namespace).get(name);
        } else {
            dependency = acquaDependency.get(name);
        }
    }

    return dependency;
};

Acqua.prototype.get = function (name) {
    var dependency = this.context[name],
        i;

    if (dependency === undefined) {
        if (this.name !== undefined && this.parent !== undefined) {
            dependency = this.parent.getFromNamespace(this.name, name);
        }

        for (i = 0; i < this.dependencies.length && dependency === undefined; i += 1) {
            dependency = this.dependencies[i].get(name);
        }
    }

    return dependency;
};

Acqua.prototype.add = function (name, $module) {
    if (this.context[name] !== undefined) {
        this.log(`Module with name: '${name}' already exists, overriding`.red);
    }
    this.context[name] = $module;
};

Acqua.prototype.getParamNames = function (func) {
    if (func.$inject) {
        return func.$inject;
    }

    var fnStr = func.toString().replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, ''),
        result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(/([^\s,]+)/g);

    // single argument arrow function support
    if (/^[A-Za-z][A-Za-z0-9]* ?=> ?/.test(fnStr)) {
        result = [/^([A-Za-z][A-Za-z0-9]*) ?=> ?/.exec(fnStr)[1]];
    } else if (result === null) {
        result = [];
    }
    return result;
};

Acqua.prototype.getFunctionName = function (func) {
    var array = /^function\s+([\w\$]+)\(/.exec(func.toString());
    return array === null ? null : array[1];
};

Acqua.prototype.getDependencies = function (fn) {
    var params = this.getParamNames(fn),
        dependencies = [],
        self = this;

    _.forEach(params, param => {
        var dependency = self.get(param);
        if (dependency === undefined) {
            throw new DependencyError('Dependency module does not exist: ' + param);
        }
        dependencies.push(dependency);
    });

    return dependencies;
};

Acqua.prototype.exec = function (fn) {
    var dependencies = this.getDependencies(fn);
    return fn.apply({}, dependencies);
};

Acqua.prototype.execModule = function ($module, modulePath, silent) {
    var dependencies = this.getDependencies($module, modulePath);
    if (_.isString(modulePath) && !silent) {
        this.log('Importing module: '.green + modulePath);
    }
    return $module.apply({}, dependencies);
};

Acqua.prototype.importModule = function (modulePath, reload) {
    var result,
        $module = modulePath,
        name;

    if (_.isString($module)) {
        if (reload) {
            this.log('CHANGED: '.yellow + modulePath);
            delete require.cache[require.resolve($module)];
        }
        $module = require($module);
    }

    if (_.isFunction($module)) {
        name = this.getFunctionName($module);
        result = this.execModule($module, modulePath, reload);

        if (name === null) {
            this.log('└─ Not a named function, just executing the function, this module will not be added to the context'.yellow);
        } else if (!reload) {
            this.add(name, result);
        }
    } else {
        this.err('Module is not a function, ignoring');
    }

    return result;
};

Acqua.prototype.loadDir = function (dir, importFunction) {
    var self = this,
        pendentModules = [],
        newPendentModules;

    this.internalLoadDir(dir, importFunction, pendentModules);

    do {
        newPendentModules = [];
        _.forEach(pendentModules, pendentModule => {
            self.internalLoadFile(pendentModule.directory, pendentModule.file, undefined, newPendentModules);
        });

        if (newPendentModules.length === pendentModules.length && newPendentModules.length > 0) {
            throw new DependencyError('Dependency Error on the Following Modules: (Might be a circular dependency) '
                    + JSON.stringify(newPendentModules, null, 4), newPendentModules);
        }
        pendentModules = newPendentModules;
    } while (pendentModules.length > 0);
};

Acqua.prototype.internalLoadDir = function (dir, importFunction, pendentModules) {
    var self = this;

    fs.readdirSync(dir).filter(file => {
        return (file.indexOf('.') !== 0) && (file !== 'index.js');
    }).forEach(file => {
        self.internalLoadFile(dir, file, importFunction, pendentModules);
    });
};

Acqua.prototype.loadFile = function (dir, file, importFunction) {
    this.internalLoadFile(dir, file, importFunction);
};

Acqua.prototype.internalLoadFile = function (dir, file, importFunction, pendentModules) {
    var location = path.join(dir, file);
    if (file.indexOf('.js') < 0) {
        this.internalLoadDir(location, importFunction, pendentModules);
    } else {
        if (importFunction !== undefined && _.isFunction(importFunction)) {
            importFunction(location, this);
        } else {
            try {
                var fileModule = this.importModule(location);
                if (this.hotswap) {
                    fs.watchFile(location, { persistent : true, interval : 100 }, () => {
                        this.fileChanged(location, fileModule);
                    });
                }
            } catch (err) {
                if (err instanceof DependencyError && pendentModules !== undefined) {
                    pendentModules.push({ directory: dir, file: file, error: err.message });
                } else {
                    throw err;
                }
            }
        }
    }
};

Acqua.prototype.fileChanged = function (filepath, fileModule) {
    try {
        var newFileModule = this.importModule(filepath, true);
        _.assign(fileModule, newFileModule);
        this.emitter.emit('change', {
            filepath : filepath,
            module : fileModule
        });
    } catch (err) {
        this.err(err);
        this.emitter.emit('changeerror', err);
    }
};

/*
 * Acqua Namespace
 */
Acqua.prototype.createNamespace = function (name) {
    var newNamespace;

    newNamespace = new Acqua({
        name : name,
        parent : this,
        log : this.log,
        err : this.err,
        hotswap : this.hotswap,
        emitter : this.emitter
    });

    this.namespaces[name] = newNamespace;

    return newNamespace;
};

Acqua.prototype.namespace = function (name) {
    return this.namespaces[name];
};

Acqua.prototype.on = function (event, handler) {
   this.emitter.on(event, handler);
};

module.exports = Acqua;
<commit_msg>creating $init and $refresh<commit_after>var fs   = require('fs'),
    _    = require('lodash'),
    path = require('path'),
    Events = require('events');

require('colors');

function DependencyError(message, modules) {
    this.name = 'DependencyError';
    this.message = message;
    this.modules = modules;
    this.stack = new Error(message).stack;
}
DependencyError.prototype = Error.prototype;

function Acqua(config) {
    config = config || {};

    this.log = config.log || function() {};
    this.err = config.err || function() {};
    this.emitter = config.emitter || new Events.EventEmitter();

    // namespaces {
    this.name = config.name || undefined;
    this.parent = config.parent || undefined;
    this.namespaces = [];
    // }

    this.dependencies = config.dependencies || [];

    this.context = {
        'acqua' : this
    };

    this.hotswap = config.hotswap;
}

Acqua.prototype.getFromNamespace = function (namespace, name) {
    var dependency = this.get(name),
        acquaDependency,
        i;

    for (i = 0; i < this.dependencies.length && dependency === undefined; i += 1) {
        acquaDependency = this.dependencies[i];
        if (acquaDependency.namespace(namespace) !== undefined) {
            dependency = acquaDependency.namespace(namespace).get(name);
        } else {
            dependency = acquaDependency.get(name);
        }
    }

    return dependency;
};

Acqua.prototype.get = function (name) {
    var dependency = this.context[name],
        i;

    if (dependency === undefined) {
        if (this.name !== undefined && this.parent !== undefined) {
            dependency = this.parent.getFromNamespace(this.name, name);
        }

        for (i = 0; i < this.dependencies.length && dependency === undefined; i += 1) {
            dependency = this.dependencies[i].get(name);
        }
    }

    return dependency;
};

Acqua.prototype.add = function (name, $module) {
    if (this.context[name] !== undefined) {
        this.log(`Module with name: '${name}' already exists, overriding`.red);
    }
    this.context[name] = $module;
};

Acqua.prototype.getParamNames = function (func) {
    if (func.$inject) {
        return func.$inject;
    }

    var fnStr = func.toString().replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, ''),
        result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(/([^\s,]+)/g);

    // single argument arrow function support
    if (/^[A-Za-z][A-Za-z0-9]* ?=> ?/.test(fnStr)) {
        result = [/^([A-Za-z][A-Za-z0-9]*) ?=> ?/.exec(fnStr)[1]];
    } else if (result === null) {
        result = [];
    }
    return result;
};

Acqua.prototype.getFunctionName = function (func) {
    var array = /^function\s+([\w\$]+)\(/.exec(func.toString());
    return array === null ? null : array[1];
};

Acqua.prototype.getDependencies = function (fn) {
    var params = this.getParamNames(fn),
        dependencies = [],
        self = this;

    _.forEach(params, param => {
        var dependency = self.get(param);
        if (dependency === undefined) {
            throw new DependencyError('Dependency module does not exist: ' + param);
        }
        dependencies.push(dependency);
    });

    return dependencies;
};

Acqua.prototype.exec = function (fn) {
    var dependencies = this.getDependencies(fn);
    return fn.apply({}, dependencies);
};

Acqua.prototype.execModule = function ($module, modulePath, silent) {
    var dependencies = this.getDependencies($module, modulePath);
    if (_.isString(modulePath) && !silent) {
        this.log('Importing module: '.green + modulePath);
    }
    return $module.apply({}, dependencies);
};

Acqua.prototype.importModule = function (modulePath, reload) {
    var result,
        $module = modulePath,
        name;

    if (_.isString($module)) {
        if (reload) {
            this.log('CHANGED: '.yellow + modulePath);
            delete require.cache[require.resolve($module)];
        }
        $module = require($module);
    }

    if (_.isFunction($module)) {
        name = this.getFunctionName($module);
        result = this.execModule($module, modulePath, reload);

        if (result && result.$init) {
            result.$init();
        }

        if (name === null) {
            this.log('└─ Not a named function, just executing the function, this module will not be added to the context'.yellow);
        } else if (!reload) {
            this.add(name, result);
        }
    } else {
        this.err('Module is not a function, ignoring');
    }

    return result;
};

Acqua.prototype.loadDir = function (dir, importFunction) {
    var self = this,
        pendentModules = [],
        newPendentModules;

    this.internalLoadDir(dir, importFunction, pendentModules);

    do {
        newPendentModules = [];
        _.forEach(pendentModules, pendentModule => {
            self.internalLoadFile(pendentModule.directory, pendentModule.file, undefined, newPendentModules);
        });

        if (newPendentModules.length === pendentModules.length && newPendentModules.length > 0) {
            throw new DependencyError('Dependency Error on the Following Modules: (Might be a circular dependency) '
                    + JSON.stringify(newPendentModules, null, 4), newPendentModules);
        }
        pendentModules = newPendentModules;
    } while (pendentModules.length > 0);
};

Acqua.prototype.internalLoadDir = function (dir, importFunction, pendentModules) {
    var self = this;

    fs.readdirSync(dir).filter(file => {
        return (file.indexOf('.') !== 0) && (file !== 'index.js');
    }).forEach(file => {
        self.internalLoadFile(dir, file, importFunction, pendentModules);
    });
};

Acqua.prototype.loadFile = function (dir, file, importFunction) {
    this.internalLoadFile(dir, file, importFunction);
};

Acqua.prototype.internalLoadFile = function (dir, file, importFunction, pendentModules) {
    var location = path.join(dir, file);
    if (file.indexOf('.js') < 0) {
        this.internalLoadDir(location, importFunction, pendentModules);
    } else {
        if (importFunction !== undefined && _.isFunction(importFunction)) {
            importFunction(location, this);
        } else {
            try {
                var fileModule = this.importModule(location);
                if (this.hotswap) {
                    fs.watchFile(location, { persistent : true, interval : 100 }, () => {
                        this.fileChanged(location, fileModule);
                    });
                }
            } catch (err) {
                if (err instanceof DependencyError && pendentModules !== undefined) {
                    pendentModules.push({ directory: dir, file: file, error: err.message });
                } else {
                    throw err;
                }
            }
        }
    }
};

Acqua.prototype.fileChanged = function (filepath, fileModule) {
    try {
        var newFileModule = this.importModule(filepath, true);

        // Will execute the function passing the old instance
        if (fileModule.$refresh) {
            newFileModule.$refresh(fileModule);
        }

        _.assign(fileModule, newFileModule);
        this.emitter.emit('change', {
            filepath : filepath,
            module : fileModule
        });
    } catch (err) {
        this.err(err);
        this.emitter.emit('changeerror', err);
    }
};

/*
 * Acqua Namespace
 */
Acqua.prototype.createNamespace = function (name) {
    var newNamespace;

    newNamespace = new Acqua({
        name : name,
        parent : this,
        log : this.log,
        err : this.err,
        hotswap : this.hotswap,
        emitter : this.emitter
    });

    this.namespaces[name] = newNamespace;

    return newNamespace;
};

Acqua.prototype.namespace = function (name) {
    return this.namespaces[name];
};

Acqua.prototype.on = function (event, handler) {
   this.emitter.on(event, handler);
};

module.exports = Acqua;
<|endoftext|>


<commit_before>import $ from 'dom7';
import Utils from '../../utils/utils';

const Accordion = {
  toggleClicked($clickedEl) {
    const app = this;
    let $accordionItemEl = $clickedEl.closest('.accordion-item').eq(0);
    if (!$accordionItemEl.length) $accordionItemEl = $clickedEl.parents('li').eq(0);
    app.accordion.toggle($accordionItemEl);
  },
  open(el) {
    const app = this;
    const $el = $(el);
    const $list = $el.parents('.accordion-list').eq(0);
    let $contentEl = $el.children('.accordion-item-content');
    if ($contentEl.length === 0) $contentEl = $el.find('.accordion-item-content');
    if ($contentEl.length === 0) return;
    const $openedItem = $list.length > 0 && $el.parent().children('.accordion-item-opened');
    if ($openedItem.length > 0) {
      app.accordion.close($openedItem);
    }
    $contentEl.transitionEnd(() => {
      if ($el.hasClass('accordion-item-opened')) {
        $contentEl.css('height', '');
        $contentEl.transition('');
        $el.trigger('accordion:opened');
        app.emit('accordionOpened', $el[0]);
      } else {
        $contentEl.css('height', '');
        $el.trigger('accordion:closed');
        app.emit('accordionClosed', $el[0]);
      }
    });
    $contentEl.css('height', `${$contentEl[0].scrollHeight}px`);
    $el.trigger('accordion:open');
    $el.addClass('accordion-item-opened');
    app.emit('accordionOpen', $el[0]);
  },
  close(el) {
    const app = this;
    const $el = $(el);
    let $contentEl = $el.children('.accordion-item-content');
    if ($contentEl.length === 0) $contentEl = $el.find('.accordion-item-content');
    $el.removeClass('accordion-item-opened');
    $contentEl.transition(0);
    $contentEl.css('height', `${$contentEl[0].scrollHeight}px`);
    // Close
    $contentEl.transitionEnd(() => {
      if ($el.hasClass('accordion-item-opened')) {
        $contentEl.css('height', '');
        $contentEl.transition('');
        $el.trigger('accordion:opened');
        app.emit('accordionOpened', $el[0]);
      } else {
        $contentEl.css('height', '');
        $el.trigger('accordion:closed');
        app.emit('accordionClosed', $el[0]);
      }
    });
    Utils.nextFrame(() => {
      $contentEl.transition('');
      $contentEl.css('height', '');
      $el.trigger('accordion:close');
      app.emit('accordionClose');
    });
  },
  toggle(el) {
    const app = this;
    const $el = $(el);
    if ($el.length === 0) return;
    if ($el.hasClass('accordion-item-opened')) app.accordion.close(el);
    else app.accordion.open(el);
  },
};

export default {
  name: 'accordion',
  create() {
    const app = this;
    Utils.extend(app, {
      accordion: {
        open: Accordion.open.bind(app),
        close: Accordion.close.bind(app),
        toggle: Accordion.toggle.bind(app),
      },
    });
  },
  clicks: {
    '.accordion-item .item-link, .accordion-item-toggle, .links-list.accordion-list > ul > li > a': function open($clickedEl) {
      const app = this;
      Accordion.toggleClicked.call(app, $clickedEl);
    },
  },
};
<commit_msg>Fix Accordion on iOS 9<commit_after>import $ from 'dom7';
import Utils from '../../utils/utils';

const Accordion = {
  toggleClicked($clickedEl) {
    const app = this;
    let $accordionItemEl = $clickedEl.closest('.accordion-item').eq(0);
    if (!$accordionItemEl.length) $accordionItemEl = $clickedEl.parents('li').eq(0);
    app.accordion.toggle($accordionItemEl);
  },
  open(el) {
    const app = this;
    const $el = $(el);
    const $list = $el.parents('.accordion-list').eq(0);
    let $contentEl = $el.children('.accordion-item-content');
    if ($contentEl.length === 0) $contentEl = $el.find('.accordion-item-content');
    if ($contentEl.length === 0) return;
    const $openedItem = $list.length > 0 && $el.parent().children('.accordion-item-opened');
    if ($openedItem.length > 0) {
      app.accordion.close($openedItem);
    }
    $contentEl.transitionEnd(() => {
      if ($el.hasClass('accordion-item-opened')) {
        $contentEl.transition(0);
        $contentEl.css('height', 'auto');
        let clientLeft = $contentEl[0].clientLeft;
        $contentEl.transition('');
        $el.trigger('accordion:opened');
        app.emit('accordionOpened', $el[0]);
      } else {
        $contentEl.css('height', '');
        $el.trigger('accordion:closed');
        app.emit('accordionClosed', $el[0]);
      }
    });
    $contentEl.css('height', `${$contentEl[0].scrollHeight}px`);
    $el.trigger('accordion:open');
    $el.addClass('accordion-item-opened');
    app.emit('accordionOpen', $el[0]);
  },
  close(el) {
    const app = this;
    const $el = $(el);
    let $contentEl = $el.children('.accordion-item-content');
    if ($contentEl.length === 0) $contentEl = $el.find('.accordion-item-content');
    $el.removeClass('accordion-item-opened');
    $contentEl.transition(0);
    $contentEl.css('height', `${$contentEl[0].scrollHeight}px`);
    let clientLeft = $contentEl[0].clientLeft;
    $contentEl.transition('');
    // Close
    $contentEl.transitionEnd(() => {
      if ($el.hasClass('accordion-item-opened')) {
        $contentEl.transition(0);
        $contentEl.css('height', 'auto');
        let clientLeft = $contentEl[0].clientLeft;
        $contentEl.transition('');
        $el.trigger('accordion:opened');
        app.emit('accordionOpened', $el[0]);
      } else {
        $contentEl.css('height', '');
        $el.trigger('accordion:closed');
        app.emit('accordionClosed', $el[0]);
      }
    });
    Utils.nextFrame(() => {
      $contentEl.transition('');
      $contentEl.css('height', '');
      $el.trigger('accordion:close');
      app.emit('accordionClose');
    });
  },
  toggle(el) {
    const app = this;
    const $el = $(el);
    if ($el.length === 0) return;
    if ($el.hasClass('accordion-item-opened')) app.accordion.close(el);
    else app.accordion.open(el);
  },
};

export default {
  name: 'accordion',
  create() {
    const app = this;
    Utils.extend(app, {
      accordion: {
        open: Accordion.open.bind(app),
        close: Accordion.close.bind(app),
        toggle: Accordion.toggle.bind(app),
      },
    });
  },
  clicks: {
    '.accordion-item .item-link, .accordion-item-toggle, .links-list.accordion-list > ul > li > a': function open($clickedEl) {
      const app = this;
      Accordion.toggleClicked.call(app, $clickedEl);
    },
  },
};
<|endoftext|>


<commit_before>import Events from 'base/events.js'
import HLS from 'playbacks/hls'
import HLSJS from 'hls.js'

describe('HLS playback', () => {
  it('should be able to identify it can play resources independently of the file extension case', function() {

    // FIXME: why is this not working in Firefox?
    if (window.navigator.userAgent.match(/Firefox\//))
      return

    // FIXME: this should actually use a mock of HlsJs
    //        we are not testing Hls.js or browser capabilities here
    //        but the logic inside HLS-Playback

    expect(HLS.canPlay('/relative/video.m3u8')).to.be.true
    expect(HLS.canPlay('/relative/VIDEO.M3U8')).to.be.true
    expect(HLS.canPlay('/relative/video.m3u8?foobarQuery=1234#somefragment')).to.be.true
    expect(HLS.canPlay('whatever_no_extension?foobarQuery=1234#somefragment', 'application/x-mpegURL' )).to.be.true
    expect(HLS.canPlay('//whatever_no_extension?foobarQuery=1234#somefragment', 'application/x-mpegURL' )).to.be.true
  })

  it('should ensure it does not create an audio tag if audioOnly is not set', function() {
    let options = { src: 'http://clappr.io/video.m3u8' },
      playback = new HLS(options)
    expect(playback.tagName).to.be.equal('video')
    options = { src: 'http://clappr.io/video.m3u8', mimeType: 'application/x-mpegurl' }
    playback = new HLS(options)
    expect(playback.tagName).to.be.equal('video')
  })

  it('should play on an audio tag if audioOnly is set', function() {
    let options = { src: 'http://clappr.io/video.m3u8', playback: { audioOnly: true } },
      playback = new HLS(options)
    expect(playback.tagName).to.be.equal('audio')
  })

  describe('options backwards compatibility', function() {
    // backwards compatibility (TODO: remove on 0.3.0)
    it('should set options.playback as a reference to options if options.playback not set', function() {
      let options = { src: 'http://clappr.io/video.m3u8' },
        hls = new HLS(options)
      expect(hls.options.playback).to.be.equal(hls.options)
      options = { src: 'http://clappr.io/video.m3u8', playback: { test: true } }
      hls = new HLS(options)
      expect(hls.options.playback.test).to.be.equal(true)
    })
  })

  describe('hls.js configuration', function() {
    it('should use hlsjsConfig from playback options', function() {
      const options = {
        src: 'http://clappr.io/video.m3u8',
        playback: {
          hlsMinimumDvrSize: 1,
          hlsjsConfig: {
            someHlsjsOption: 'value'
          }
        }
      }
      const playback = new HLS(options)
      playback._setup()
      expect(playback._hls.config.someHlsjsOption).to.be.equal('value')
      expect(playback._hls.config).not.to.include.keys('hlsMinimumDvrSize')
    })

    it('should use hlsjsConfig from player options as fallback', function() {
      const options = {
        src: 'http://clappr.io/video.m3u8',
        hlsMinimumDvrSize: 1,
        hlsjsConfig: {
          someHlsjsOption: 'value'
        }
      }
      const playback = new HLS(options)
      playback._setup()
      expect(playback._hls.config.someHlsjsOption).to.be.equal('value')
      expect(playback._hls.config).not.to.include.keys('hlsMinimumDvrSize')
    })
  })

  it('should trigger a playback error if source load failed', function(done) {
    this.timeout(5000)
    let options = { src: 'http://clappr.io/notfound.m3u8' }
    const playback = new HLS(options)
    playback.on(Events.PLAYBACK_ERROR, (e) => {
      expect(e.raw.type).to.be.equal(HLSJS.ErrorTypes.NETWORK_ERROR)
      expect(e.raw.details).to.be.equal(HLSJS.ErrorDetails.MANIFEST_LOAD_ERROR)
      done()
    })
    playback.play()
  })

  xit('levels', function() {
    let playback
    beforeEach(() => {
      const options = { src: 'http://clappr.io/foo.m3u8' }
      playback = new HLS(options)
      playback.setupHls()
      // NOTE: rather than trying to call playback.setupHls, we'll punch a new one in place
      playback.hls = {
        levels: []
      }
      playback.fillLevels()
    })

    it('supports specifying the level', () => {
      // AUTO by default (-1)
      expect(playback.currentLevel).to.equal(-1)

      // Supports other level specification. Should keep track of it
      // on itself and by proxy on the HLS.js object.
      playback.currentLevel = 0
      expect(playback.currentLevel).to.equal(0)
      expect(playback.hls.currentLevel).to.equal(0)
      playback.currentLevel = 1
      expect(playback.currentLevel).to.equal(1)
      expect(playback.hls.currentLevel).to.equal(1)
    })
  })
})
<commit_msg>test(hls): use promise instead of done fix error message when test fails<commit_after>import Events from 'base/events.js'
import HLS from 'playbacks/hls'
import HLSJS from 'hls.js'

describe('HLS playback', () => {
  it('should be able to identify it can play resources independently of the file extension case', function() {

    // FIXME: why is this not working in Firefox?
    if (window.navigator.userAgent.match(/Firefox\//))
      return

    // FIXME: this should actually use a mock of HlsJs
    //        we are not testing Hls.js or browser capabilities here
    //        but the logic inside HLS-Playback

    expect(HLS.canPlay('/relative/video.m3u8')).to.be.true
    expect(HLS.canPlay('/relative/VIDEO.M3U8')).to.be.true
    expect(HLS.canPlay('/relative/video.m3u8?foobarQuery=1234#somefragment')).to.be.true
    expect(HLS.canPlay('whatever_no_extension?foobarQuery=1234#somefragment', 'application/x-mpegURL' )).to.be.true
    expect(HLS.canPlay('//whatever_no_extension?foobarQuery=1234#somefragment', 'application/x-mpegURL' )).to.be.true
  })

  it('should ensure it does not create an audio tag if audioOnly is not set', function() {
    let options = { src: 'http://clappr.io/video.m3u8' },
      playback = new HLS(options)
    expect(playback.tagName).to.be.equal('video')
    options = { src: 'http://clappr.io/video.m3u8', mimeType: 'application/x-mpegurl' }
    playback = new HLS(options)
    expect(playback.tagName).to.be.equal('video')
  })

  it('should play on an audio tag if audioOnly is set', function() {
    let options = { src: 'http://clappr.io/video.m3u8', playback: { audioOnly: true } },
      playback = new HLS(options)
    expect(playback.tagName).to.be.equal('audio')
  })

  describe('options backwards compatibility', function() {
    // backwards compatibility (TODO: remove on 0.3.0)
    it('should set options.playback as a reference to options if options.playback not set', function() {
      let options = { src: 'http://clappr.io/video.m3u8' },
        hls = new HLS(options)
      expect(hls.options.playback).to.be.equal(hls.options)
      options = { src: 'http://clappr.io/video.m3u8', playback: { test: true } }
      hls = new HLS(options)
      expect(hls.options.playback.test).to.be.equal(true)
    })
  })

  describe('hls.js configuration', function() {
    it('should use hlsjsConfig from playback options', function() {
      const options = {
        src: 'http://clappr.io/video.m3u8',
        playback: {
          hlsMinimumDvrSize: 1,
          hlsjsConfig: {
            someHlsjsOption: 'value'
          }
        }
      }
      const playback = new HLS(options)
      playback._setup()
      expect(playback._hls.config.someHlsjsOption).to.be.equal('value')
      expect(playback._hls.config).not.to.include.keys('hlsMinimumDvrSize')
    })

    it('should use hlsjsConfig from player options as fallback', function() {
      const options = {
        src: 'http://clappr.io/video.m3u8',
        hlsMinimumDvrSize: 1,
        hlsjsConfig: {
          someHlsjsOption: 'value'
        }
      }
      const playback = new HLS(options)
      playback._setup()
      expect(playback._hls.config.someHlsjsOption).to.be.equal('value')
      expect(playback._hls.config).not.to.include.keys('hlsMinimumDvrSize')
    })
  })

  it('should trigger a playback error if source load failed', function() {
    let resolveFn = undefined, rejectFn = undefined
    const promise = new Promise((resolve, reject) => {
      resolveFn = resolve
      rejectFn = reject
    })
    let options = { src: 'http://clappr.io/notfound.m3u8' }
    const playback = new HLS(options)
    playback.on(Events.PLAYBACK_ERROR, (e) => {
      resolveFn(e)
    })
    playback.play()

    return promise.then((e) => {
      expect(e.raw.type).to.be.equal(HLSJS.ErrorTypes.NETWORK_ERROR)
      expect(e.raw.details).to.be.equal(HLSJS.ErrorDetails.MANIFEST_LOAD_ERROR)
    })
  })

  xit('levels', function() {
    let playback
    beforeEach(() => {
      const options = { src: 'http://clappr.io/foo.m3u8' }
      playback = new HLS(options)
      playback.setupHls()
      // NOTE: rather than trying to call playback.setupHls, we'll punch a new one in place
      playback.hls = {
        levels: []
      }
      playback.fillLevels()
    })

    it('supports specifying the level', () => {
      // AUTO by default (-1)
      expect(playback.currentLevel).to.equal(-1)

      // Supports other level specification. Should keep track of it
      // on itself and by proxy on the HLS.js object.
      playback.currentLevel = 0
      expect(playback.currentLevel).to.equal(0)
      expect(playback.hls.currentLevel).to.equal(0)
      playback.currentLevel = 1
      expect(playback.currentLevel).to.equal(1)
      expect(playback.hls.currentLevel).to.equal(1)
    })
  })
})
<|endoftext|>


<commit_before>'use strict'

var http = require('http')
var util = require('util')
var events = require('events')
var uuid = require('node-uuid')
var OpbeatHttpClient = require('opbeat-http-client')
var ReleaseTracker = require('opbeat-release-tracker')
var debug = require('debug')('opbeat')
var config = require('./config')
var logger = require('./logger')
var parsers = require('./parsers')
var request = require('./request')
var connect = require('./middleware/connect')
var Instrumentation = require('./instrumentation')

var version = require('../package').version
var userAgent = 'opbeat-nodejs/' + version

module.exports = Agent

function Agent () {
  events.EventEmitter.call(this)

  var boundConnect = connect.bind(this)
  this.middleware = { connect: boundConnect, express: boundConnect }

  var ins = new Instrumentation(this)
  this._instrumentation = ins
  this.startTransaction = ins.startTransaction.bind(ins)
  this.endTransaction = ins.endTransaction.bind(ins)
  this.setTransactionName = ins.setTransactionName.bind(ins)
  this.buildTrace = ins.buildTrace.bind(ins)

  // configure the agent with default values
  this._init()
}

util.inherits(Agent, events.EventEmitter)

Agent.prototype._init = function (opts) {
  opts = config(opts)

  logger.init({ level: opts.logLevel })

  this.appId = opts.appId
  this.organizationId = opts.organizationId
  this.secretToken = opts.secretToken
  this.active = opts.active
  this.logLevel = opts.logLevel
  this.hostname = opts.hostname
  this.stackTraceLimit = opts.stackTraceLimit
  this.captureExceptions = opts.captureExceptions
  this.exceptionLogLevel = opts.exceptionLogLevel
  this.instrument = opts.instrument
  this.filter = opts.filter
  this._apiHost = opts._apiHost
  this._ff_captureFrame = opts._ff_captureFrame
}

Agent.prototype.start = function (opts) {
  if (global.__opbeat_initialized) throw new Error('Do not call opbeat.start() more than once')
  global.__opbeat_initialized = true

  this._init(opts)

  if (!this.active) {
    logger.info('Opbeat agent is inactive due to configuration')
    return this
  } else if (!this.appId || !this.organizationId || !this.secretToken) {
    logger.error('Opbeat isn\'t correctly configured: Missing organizationId, appId or secretToken')
    this.active = false
    return this
  } else {
    debug('agent configured correctly %o', { node: process.version, agent: version, org: this.organizationId, app: this.appId, instrument: this.instrument })
  }

  this._instrumentation.start()

  this._httpClient = OpbeatHttpClient({
    appId: this.appId,
    organizationId: this.organizationId,
    secretToken: this.secretToken,
    userAgent: userAgent,
    _apiHost: this._apiHost
  })

  Error.stackTraceLimit = this.stackTraceLimit
  if (this.captureExceptions) this.handleUncaughtExceptions()

  this.on('error', errorLogger)
  this.on('logged', function (url, uuid) {
    logger.info('Opbeat logged error successfully at %s', url, { uuid: uuid })
  })

  return this
}

Agent.prototype.captureError = function (err, data, cb) {
  var agent = this
  var captureTime = new Date()

  if (typeof data === 'function') {
    cb = data
    data = {}
  } else if (!data) {
    data = {}
  } else if (data.request instanceof http.IncomingMessage) {
    data.http = parsers.parseRequest(data.request)
  }
  delete data.request

  var trace = this._instrumentation.currentTrace
  if (!data.http && trace && trace.transaction.req) data.http = parsers.parseRequest(trace.transaction.req)

  var errUUID = data.extra && data.extra.uuid || uuid.v4()

  if (!util.isError(err)) {
    var isMessage = true
    var customCulprit = 'culprit' in data
    parsers.parseMessage(err, data)
    logger.error(data.message, { uuid: errUUID })
    err = new Error(data.message)
  } else if (this._ff_captureFrame && !err.uncaught) {
    var captureFrameError = new Error()
  }

  if (!isMessage) {
    logger.error('logging error with Opbeat:', { uuid: errUUID })
    logger.error(err.stack)
  }

  parsers.parseError(err, data, function (data) {
    if (isMessage) {
      // Messages shouldn't have an exception and the algorithm for finding the
      // culprit might show the Opbeat agent and we don't want that
      delete data.exception
      if (!customCulprit) delete data.culprit
      if (data.stacktrace) data.stacktrace.frames.shift()
    }

    var done = function () {
      if (data.stacktrace) data.stacktrace.frames.reverse() // opbeat expects frames in reverse order
      data.machine = { hostname: agent.hostname }
      data.extra = data.extra || {}
      data.extra.node = process.version
      if (!data.extra.uuid) data.extra.uuid = errUUID
      data.timestamp = captureTime.toISOString()

      if (agent.filter) data = agent.filter(err, data)
      if (agent.active) request.error(agent, data, cb)
      // In v3.x, the captureError callback will only be called if the agent is
      // active. This is scheduled to change in v4.x. When using the middleware
      // we want to call the next function even if the agent is inactive, so
      // until we release v4.x we need a way to tell the captureError function
      // that the callback should be called even if the agent is inactive. This
      // is done by naming the callback `_opbeat_middleware`.
      // TODO: Undo this hack in v4.x
      else if (cb && cb.name === '_opbeat_middleware') cb()
    }

    if (captureFrameError && (!data.stacktrace || !data.stacktrace.frames.some(function (frame) { return frame.in_app }))) {
      // prepare to add a top frame to the stack trace specifying the location
      // where captureError was called from. This can make it easier to debug
      // async stack traces.
      parsers.parseError(captureFrameError, {}, function (result) {
        // ignore the first frame as it will be the opbeat module
        if (result.stacktrace) var frame = result.stacktrace.frames[1]
        if (data.stacktrace) data.stacktrace.frames.unshift(frame)
        else if (frame) data.stacktrace = { frames: [frame] }
        done()
      })
    } else {
      done()
    }
  })
}

// The optional callback will be called with the error object after the
// error have been logged to Opbeat. If no callback have been provided
// we will automatically terminate the process, so if you provide a
// callback you must remember to terminate the process manually.
Agent.prototype.handleUncaughtExceptions = function (cb) {
  var agent = this

  if (this._uncaughtExceptionListener) process.removeListener('uncaughtException', this._uncaughtExceptionListener)

  this._uncaughtExceptionListener = function (err) {
    var data = {
      extra: { uuid: uuid.v4() },
      level: agent.exceptionLogLevel
    }

    debug('Opbeat caught unhandled exception %o', { uuid: data.extra.uuid })

    // Since we exit the node-process we cannot guarantee that the
    // listeners will be called, so to ensure a uniform result,
    // we'll remove all event listeners if an uncaught exception is
    // found
    agent.removeAllListeners()
    // But make sure emitted errors doesn't cause yet another uncaught
    // exception
    agent.on('error', errorLogger)

    err.uncaught = true

    agent.captureError(err, data, function (opbeatErr, url) {
      if (opbeatErr) {
        logger.error('Could not notify Opbeat', { uuid: data.extra.uuid })
        logger.error(opbeatErr.stack)
      } else {
        logger.info('Opbeat logged error successfully at %s', url, { uuid: data.extra.uuid })
      }
      cb ? cb(err, url) : process.exit(1)
    })
  }

  process.on('uncaughtException', this._uncaughtExceptionListener)
}

Agent.prototype.trackRelease = function (data, cb) {
  var agent = this
  if (!this._releaseTracker) this._releaseTracker = ReleaseTracker(this._httpClient)
  this._releaseTracker(data, function (err) {
    if (cb) cb(err)
    if (err) agent.emit('error', err)
  })
}

function errorLogger (err, uuid) {
  logger.error('Could not notify Opbeat', { uuid: uuid })
  logger.error(err.stack)
}
<commit_msg>Don't emit error if error occurs during trackRelease<commit_after>'use strict'

var http = require('http')
var util = require('util')
var events = require('events')
var uuid = require('node-uuid')
var OpbeatHttpClient = require('opbeat-http-client')
var ReleaseTracker = require('opbeat-release-tracker')
var debug = require('debug')('opbeat')
var config = require('./config')
var logger = require('./logger')
var parsers = require('./parsers')
var request = require('./request')
var connect = require('./middleware/connect')
var Instrumentation = require('./instrumentation')

var version = require('../package').version
var userAgent = 'opbeat-nodejs/' + version

var noop = function () {}

module.exports = Agent

function Agent () {
  events.EventEmitter.call(this)

  var boundConnect = connect.bind(this)
  this.middleware = { connect: boundConnect, express: boundConnect }

  var ins = new Instrumentation(this)
  this._instrumentation = ins
  this.startTransaction = ins.startTransaction.bind(ins)
  this.endTransaction = ins.endTransaction.bind(ins)
  this.setTransactionName = ins.setTransactionName.bind(ins)
  this.buildTrace = ins.buildTrace.bind(ins)

  // configure the agent with default values
  this._init()
}

util.inherits(Agent, events.EventEmitter)

Agent.prototype._init = function (opts) {
  opts = config(opts)

  logger.init({ level: opts.logLevel })

  this.appId = opts.appId
  this.organizationId = opts.organizationId
  this.secretToken = opts.secretToken
  this.active = opts.active
  this.logLevel = opts.logLevel
  this.hostname = opts.hostname
  this.stackTraceLimit = opts.stackTraceLimit
  this.captureExceptions = opts.captureExceptions
  this.exceptionLogLevel = opts.exceptionLogLevel
  this.instrument = opts.instrument
  this.filter = opts.filter
  this._apiHost = opts._apiHost
  this._ff_captureFrame = opts._ff_captureFrame
}

Agent.prototype.start = function (opts) {
  if (global.__opbeat_initialized) throw new Error('Do not call opbeat.start() more than once')
  global.__opbeat_initialized = true

  this._init(opts)

  if (!this.active) {
    logger.info('Opbeat agent is inactive due to configuration')
    return this
  } else if (!this.appId || !this.organizationId || !this.secretToken) {
    logger.error('Opbeat isn\'t correctly configured: Missing organizationId, appId or secretToken')
    this.active = false
    return this
  } else {
    debug('agent configured correctly %o', { node: process.version, agent: version, org: this.organizationId, app: this.appId, instrument: this.instrument })
  }

  this._instrumentation.start()

  this._httpClient = OpbeatHttpClient({
    appId: this.appId,
    organizationId: this.organizationId,
    secretToken: this.secretToken,
    userAgent: userAgent,
    _apiHost: this._apiHost
  })

  Error.stackTraceLimit = this.stackTraceLimit
  if (this.captureExceptions) this.handleUncaughtExceptions()

  this.on('error', errorLogger)
  this.on('logged', function (url, uuid) {
    logger.info('Opbeat logged error successfully at %s', url, { uuid: uuid })
  })

  return this
}

Agent.prototype.captureError = function (err, data, cb) {
  var agent = this
  var captureTime = new Date()

  if (typeof data === 'function') {
    cb = data
    data = {}
  } else if (!data) {
    data = {}
  } else if (data.request instanceof http.IncomingMessage) {
    data.http = parsers.parseRequest(data.request)
  }
  delete data.request

  var trace = this._instrumentation.currentTrace
  if (!data.http && trace && trace.transaction.req) data.http = parsers.parseRequest(trace.transaction.req)

  var errUUID = data.extra && data.extra.uuid || uuid.v4()

  if (!util.isError(err)) {
    var isMessage = true
    var customCulprit = 'culprit' in data
    parsers.parseMessage(err, data)
    logger.error(data.message, { uuid: errUUID })
    err = new Error(data.message)
  } else if (this._ff_captureFrame && !err.uncaught) {
    var captureFrameError = new Error()
  }

  if (!isMessage) {
    logger.error('logging error with Opbeat:', { uuid: errUUID })
    logger.error(err.stack)
  }

  parsers.parseError(err, data, function (data) {
    if (isMessage) {
      // Messages shouldn't have an exception and the algorithm for finding the
      // culprit might show the Opbeat agent and we don't want that
      delete data.exception
      if (!customCulprit) delete data.culprit
      if (data.stacktrace) data.stacktrace.frames.shift()
    }

    var done = function () {
      if (data.stacktrace) data.stacktrace.frames.reverse() // opbeat expects frames in reverse order
      data.machine = { hostname: agent.hostname }
      data.extra = data.extra || {}
      data.extra.node = process.version
      if (!data.extra.uuid) data.extra.uuid = errUUID
      data.timestamp = captureTime.toISOString()

      if (agent.filter) data = agent.filter(err, data)
      if (agent.active) request.error(agent, data, cb)
      // In v3.x, the captureError callback will only be called if the agent is
      // active. This is scheduled to change in v4.x. When using the middleware
      // we want to call the next function even if the agent is inactive, so
      // until we release v4.x we need a way to tell the captureError function
      // that the callback should be called even if the agent is inactive. This
      // is done by naming the callback `_opbeat_middleware`.
      // TODO: Undo this hack in v4.x
      else if (cb && cb.name === '_opbeat_middleware') cb()
    }

    if (captureFrameError && (!data.stacktrace || !data.stacktrace.frames.some(function (frame) { return frame.in_app }))) {
      // prepare to add a top frame to the stack trace specifying the location
      // where captureError was called from. This can make it easier to debug
      // async stack traces.
      parsers.parseError(captureFrameError, {}, function (result) {
        // ignore the first frame as it will be the opbeat module
        if (result.stacktrace) var frame = result.stacktrace.frames[1]
        if (data.stacktrace) data.stacktrace.frames.unshift(frame)
        else if (frame) data.stacktrace = { frames: [frame] }
        done()
      })
    } else {
      done()
    }
  })
}

// The optional callback will be called with the error object after the
// error have been logged to Opbeat. If no callback have been provided
// we will automatically terminate the process, so if you provide a
// callback you must remember to terminate the process manually.
Agent.prototype.handleUncaughtExceptions = function (cb) {
  var agent = this

  if (this._uncaughtExceptionListener) process.removeListener('uncaughtException', this._uncaughtExceptionListener)

  this._uncaughtExceptionListener = function (err) {
    var data = {
      extra: { uuid: uuid.v4() },
      level: agent.exceptionLogLevel
    }

    debug('Opbeat caught unhandled exception %o', { uuid: data.extra.uuid })

    // Since we exit the node-process we cannot guarantee that the
    // listeners will be called, so to ensure a uniform result,
    // we'll remove all event listeners if an uncaught exception is
    // found
    agent.removeAllListeners()
    // But make sure emitted errors doesn't cause yet another uncaught
    // exception
    agent.on('error', errorLogger)

    err.uncaught = true

    agent.captureError(err, data, function (opbeatErr, url) {
      if (opbeatErr) {
        logger.error('Could not notify Opbeat', { uuid: data.extra.uuid })
        logger.error(opbeatErr.stack)
      } else {
        logger.info('Opbeat logged error successfully at %s', url, { uuid: data.extra.uuid })
      }
      cb ? cb(err, url) : process.exit(1)
    })
  }

  process.on('uncaughtException', this._uncaughtExceptionListener)
}

Agent.prototype.trackRelease = function (data, cb) {
  if (!this._releaseTracker) this._releaseTracker = ReleaseTracker(this._httpClient)
  this._releaseTracker(data, cb || noop)
}

function errorLogger (err, uuid) {
  logger.error('Could not notify Opbeat', { uuid: uuid })
  logger.error(err.stack)
}
<|endoftext|>


<commit_before>'use strict';

var axesAttrs = require('../../plots/cartesian/layout_attributes');
var fontAttrs = require('../../plots/font_attributes');
var extendFlat = require('../../lib/extend').extendFlat;
var overrideAll = require('../../plot_api/edit_types').overrideAll;

module.exports = overrideAll({
    orientation: {
        valType: 'enumerated',
        values: ['h', 'v'],
        dflt: 'v',
        description: 'Sets the orientation of the colorbar.'
    },
    thicknessmode: {
        valType: 'enumerated',
        values: ['fraction', 'pixels'],
        dflt: 'pixels',
        description: [
            'Determines whether this color bar\'s thickness',
            '(i.e. the measure in the constant color direction)',
            'is set in units of plot *fraction* or in *pixels*.',
            'Use `thickness` to set the value.'
        ].join(' ')
    },
    thickness: {
        valType: 'number',
        min: 0,
        dflt: 30,
        description: [
            'Sets the thickness of the color bar',
            'This measure excludes the size of the padding, ticks and labels.'
        ].join(' ')
    },
    lenmode: {
        valType: 'enumerated',
        values: ['fraction', 'pixels'],
        dflt: 'fraction',
        description: [
            'Determines whether this color bar\'s length',
            '(i.e. the measure in the color variation direction)',
            'is set in units of plot *fraction* or in *pixels.',
            'Use `len` to set the value.'
        ].join(' ')
    },
    len: {
        valType: 'number',
        min: 0,
        dflt: 1,
        description: [
            'Sets the length of the color bar',
            'This measure excludes the padding of both ends.',
            'That is, the color bar length is this length minus the',
            'padding on both ends.'
        ].join(' ')
    },
    x: {
        valType: 'number',
        min: -2,
        max: 3,
        description: [
            'Sets the x position of the color bar (in plot fraction).',
            'Defaults to 1.02 when `orientation` if *v* and ',
            'defaults to 0.5 when `orientation` if *h*.'
        ].join(' ')
    },
    xanchor: {
        valType: 'enumerated',
        values: ['left', 'center', 'right'],
        description: [
            'Sets this color bar\'s horizontal position anchor.',
            'This anchor binds the `x` position to the *left*, *center*',
            'or *right* of the color bar.',
            'Defaults to *left* when `orientation` if *v* and ',
            'defaults to *center* when `orientation` if *h*.'
        ].join(' ')
    },
    xpad: {
        valType: 'number',
        min: 0,
        dflt: 10,
        description: 'Sets the amount of padding (in px) along the x direction.'
    },
    y: {
        valType: 'number',
        min: -2,
        max: 3,
        description: [
            'Sets the y position of the color bar (in plot fraction).',
            'Defaults to 0.5 when `orientation` is *v* and',
            '1.02 when `orientation` is *h*.'
        ].join(' ')
    },
    yanchor: {
        valType: 'enumerated',
        values: ['top', 'middle', 'bottom'],
        description: [
            'Sets this color bar\'s vertical position anchor',
            'This anchor binds the `y` position to the *top*, *middle*',
            'or *bottom* of the color bar.',
            'Defaults to *middle* when `orientation` is *v* and',
            '*bottom* when `orientation` is *h*.'
        ].join(' ')
    },
    ypad: {
        valType: 'number',
        min: 0,
        dflt: 10,
        description: 'Sets the amount of padding (in px) along the y direction.'
    },
    // a possible line around the bar itself
    outlinecolor: axesAttrs.linecolor,
    outlinewidth: axesAttrs.linewidth,
    // Should outlinewidth have {dflt: 0} ?
    // another possible line outside the padding and tick labels
    bordercolor: axesAttrs.linecolor,
    borderwidth: {
        valType: 'number',
        min: 0,
        dflt: 0,
        description: [
            'Sets the width (in px) or the border enclosing this color bar.'
        ].join(' ')
    },
    bgcolor: {
        valType: 'color',
        dflt: 'rgba(0,0,0,0)',
        description: 'Sets the color of padded area.'
    },
    // tick and title properties named and function exactly as in axes
    tickmode: axesAttrs.tickmode,
    nticks: axesAttrs.nticks,
    tick0: axesAttrs.tick0,
    dtick: axesAttrs.dtick,
    tickvals: axesAttrs.tickvals,
    ticktext: axesAttrs.ticktext,
    ticks: extendFlat({}, axesAttrs.ticks, {dflt: ''}),
    ticklabeloverflow: extendFlat({}, axesAttrs.ticklabeloverflow, {
        description: [
            'Determines how we handle tick labels that would overflow either the graph div or the domain of the axis.',
            'The default value for inside tick labels is *hide past domain*.',
            'In other cases the default is *hide past div*.'
        ].join(' ')
    }),

    // ticklabelposition: not used directly, as values depend on orientation
    // left/right options are for x axes, and top/bottom options are for y axes
    ticklabelposition: {
        valType: 'enumerated',
        values: [
            'outside', 'inside',
            'outside top', 'inside top',
            'outside left', 'inside left',
            'outside right', 'inside right',
            'outside bottom', 'inside bottom'
        ],
        dflt: 'outside',
        description: [
            'Determines where tick labels are drawn relative to the ticks.',
            'Left and right options are used when `orientation` is *h*,',
            'top and bottom when `orientation` is *v*.'
        ].join(' ')
    },

    ticklen: axesAttrs.ticklen,
    tickwidth: axesAttrs.tickwidth,
    tickcolor: axesAttrs.tickcolor,
    showticklabels: axesAttrs.showticklabels,
    tickfont: fontAttrs({
        description: 'Sets the color bar\'s tick label font'
    }),
    tickangle: axesAttrs.tickangle,
    tickformat: axesAttrs.tickformat,
    tickformatstops: axesAttrs.tickformatstops,
    tickprefix: axesAttrs.tickprefix,
    showtickprefix: axesAttrs.showtickprefix,
    ticksuffix: axesAttrs.ticksuffix,
    showticksuffix: axesAttrs.showticksuffix,
    separatethousands: axesAttrs.separatethousands,
    exponentformat: axesAttrs.exponentformat,
    minexponent: axesAttrs.minexponent,
    showexponent: axesAttrs.showexponent,
    title: {
        text: {
            valType: 'string',
            description: [
                'Sets the title of the color bar.',
                'Note that before the existence of `title.text`, the title\'s',
                'contents used to be defined as the `title` attribute itself.',
                'This behavior has been deprecated.'
            ].join(' ')
        },
        font: fontAttrs({
            description: [
                'Sets this color bar\'s title font.',
                'Note that the title\'s font used to be set',
                'by the now deprecated `titlefont` attribute.'
            ].join(' ')
        }),
        side: {
            valType: 'enumerated',
            values: ['right', 'top', 'bottom'],
            description: [
                'Determines the location of color bar\'s title',
                'with respect to the color bar.',
                'Defaults to *top* when `orientation` if *v* and ',
                'defaults to *right* when `orientation` if *h*.',
                'Note that the title\'s location used to be set',
                'by the now deprecated `titleside` attribute.'
            ].join(' ')
        }
    },

    _deprecated: {
        title: {
            valType: 'string',
            description: [
                'Deprecated in favor of color bar\'s `title.text`.',
                'Note that value of color bar\'s `title` is no longer a simple',
                '*string* but a set of sub-attributes.'
            ].join(' ')
        },
        titlefont: fontAttrs({
            description: 'Deprecated in favor of color bar\'s `title.font`.'
        }),
        titleside: {
            valType: 'enumerated',
            values: ['right', 'top', 'bottom'],
            dflt: 'top',
            description: 'Deprecated in favor of color bar\'s `title.side`.'
        }
    }
}, 'colorbars', 'from-root');
<commit_msg>Update src/components/colorbar/attributes.js<commit_after>'use strict';

var axesAttrs = require('../../plots/cartesian/layout_attributes');
var fontAttrs = require('../../plots/font_attributes');
var extendFlat = require('../../lib/extend').extendFlat;
var overrideAll = require('../../plot_api/edit_types').overrideAll;

module.exports = overrideAll({
    orientation: {
        valType: 'enumerated',
        values: ['h', 'v'],
        dflt: 'v',
        description: 'Sets the orientation of the colorbar.'
    },
    thicknessmode: {
        valType: 'enumerated',
        values: ['fraction', 'pixels'],
        dflt: 'pixels',
        description: [
            'Determines whether this color bar\'s thickness',
            '(i.e. the measure in the constant color direction)',
            'is set in units of plot *fraction* or in *pixels*.',
            'Use `thickness` to set the value.'
        ].join(' ')
    },
    thickness: {
        valType: 'number',
        min: 0,
        dflt: 30,
        description: [
            'Sets the thickness of the color bar',
            'This measure excludes the size of the padding, ticks and labels.'
        ].join(' ')
    },
    lenmode: {
        valType: 'enumerated',
        values: ['fraction', 'pixels'],
        dflt: 'fraction',
        description: [
            'Determines whether this color bar\'s length',
            '(i.e. the measure in the color variation direction)',
            'is set in units of plot *fraction* or in *pixels.',
            'Use `len` to set the value.'
        ].join(' ')
    },
    len: {
        valType: 'number',
        min: 0,
        dflt: 1,
        description: [
            'Sets the length of the color bar',
            'This measure excludes the padding of both ends.',
            'That is, the color bar length is this length minus the',
            'padding on both ends.'
        ].join(' ')
    },
    x: {
        valType: 'number',
        min: -2,
        max: 3,
        description: [
            'Sets the x position of the color bar (in plot fraction).',
            'Defaults to 1.02 when `orientation` is *v* and',
            '0.5 when `orientation` is *h*.'
        ].join(' ')
    },
    xanchor: {
        valType: 'enumerated',
        values: ['left', 'center', 'right'],
        description: [
            'Sets this color bar\'s horizontal position anchor.',
            'This anchor binds the `x` position to the *left*, *center*',
            'or *right* of the color bar.',
            'Defaults to *left* when `orientation` if *v* and ',
            'defaults to *center* when `orientation` if *h*.'
        ].join(' ')
    },
    xpad: {
        valType: 'number',
        min: 0,
        dflt: 10,
        description: 'Sets the amount of padding (in px) along the x direction.'
    },
    y: {
        valType: 'number',
        min: -2,
        max: 3,
        description: [
            'Sets the y position of the color bar (in plot fraction).',
            'Defaults to 0.5 when `orientation` is *v* and',
            '1.02 when `orientation` is *h*.'
        ].join(' ')
    },
    yanchor: {
        valType: 'enumerated',
        values: ['top', 'middle', 'bottom'],
        description: [
            'Sets this color bar\'s vertical position anchor',
            'This anchor binds the `y` position to the *top*, *middle*',
            'or *bottom* of the color bar.',
            'Defaults to *middle* when `orientation` is *v* and',
            '*bottom* when `orientation` is *h*.'
        ].join(' ')
    },
    ypad: {
        valType: 'number',
        min: 0,
        dflt: 10,
        description: 'Sets the amount of padding (in px) along the y direction.'
    },
    // a possible line around the bar itself
    outlinecolor: axesAttrs.linecolor,
    outlinewidth: axesAttrs.linewidth,
    // Should outlinewidth have {dflt: 0} ?
    // another possible line outside the padding and tick labels
    bordercolor: axesAttrs.linecolor,
    borderwidth: {
        valType: 'number',
        min: 0,
        dflt: 0,
        description: [
            'Sets the width (in px) or the border enclosing this color bar.'
        ].join(' ')
    },
    bgcolor: {
        valType: 'color',
        dflt: 'rgba(0,0,0,0)',
        description: 'Sets the color of padded area.'
    },
    // tick and title properties named and function exactly as in axes
    tickmode: axesAttrs.tickmode,
    nticks: axesAttrs.nticks,
    tick0: axesAttrs.tick0,
    dtick: axesAttrs.dtick,
    tickvals: axesAttrs.tickvals,
    ticktext: axesAttrs.ticktext,
    ticks: extendFlat({}, axesAttrs.ticks, {dflt: ''}),
    ticklabeloverflow: extendFlat({}, axesAttrs.ticklabeloverflow, {
        description: [
            'Determines how we handle tick labels that would overflow either the graph div or the domain of the axis.',
            'The default value for inside tick labels is *hide past domain*.',
            'In other cases the default is *hide past div*.'
        ].join(' ')
    }),

    // ticklabelposition: not used directly, as values depend on orientation
    // left/right options are for x axes, and top/bottom options are for y axes
    ticklabelposition: {
        valType: 'enumerated',
        values: [
            'outside', 'inside',
            'outside top', 'inside top',
            'outside left', 'inside left',
            'outside right', 'inside right',
            'outside bottom', 'inside bottom'
        ],
        dflt: 'outside',
        description: [
            'Determines where tick labels are drawn relative to the ticks.',
            'Left and right options are used when `orientation` is *h*,',
            'top and bottom when `orientation` is *v*.'
        ].join(' ')
    },

    ticklen: axesAttrs.ticklen,
    tickwidth: axesAttrs.tickwidth,
    tickcolor: axesAttrs.tickcolor,
    showticklabels: axesAttrs.showticklabels,
    tickfont: fontAttrs({
        description: 'Sets the color bar\'s tick label font'
    }),
    tickangle: axesAttrs.tickangle,
    tickformat: axesAttrs.tickformat,
    tickformatstops: axesAttrs.tickformatstops,
    tickprefix: axesAttrs.tickprefix,
    showtickprefix: axesAttrs.showtickprefix,
    ticksuffix: axesAttrs.ticksuffix,
    showticksuffix: axesAttrs.showticksuffix,
    separatethousands: axesAttrs.separatethousands,
    exponentformat: axesAttrs.exponentformat,
    minexponent: axesAttrs.minexponent,
    showexponent: axesAttrs.showexponent,
    title: {
        text: {
            valType: 'string',
            description: [
                'Sets the title of the color bar.',
                'Note that before the existence of `title.text`, the title\'s',
                'contents used to be defined as the `title` attribute itself.',
                'This behavior has been deprecated.'
            ].join(' ')
        },
        font: fontAttrs({
            description: [
                'Sets this color bar\'s title font.',
                'Note that the title\'s font used to be set',
                'by the now deprecated `titlefont` attribute.'
            ].join(' ')
        }),
        side: {
            valType: 'enumerated',
            values: ['right', 'top', 'bottom'],
            description: [
                'Determines the location of color bar\'s title',
                'with respect to the color bar.',
                'Defaults to *top* when `orientation` if *v* and ',
                'defaults to *right* when `orientation` if *h*.',
                'Note that the title\'s location used to be set',
                'by the now deprecated `titleside` attribute.'
            ].join(' ')
        }
    },

    _deprecated: {
        title: {
            valType: 'string',
            description: [
                'Deprecated in favor of color bar\'s `title.text`.',
                'Note that value of color bar\'s `title` is no longer a simple',
                '*string* but a set of sub-attributes.'
            ].join(' ')
        },
        titlefont: fontAttrs({
            description: 'Deprecated in favor of color bar\'s `title.font`.'
        }),
        titleside: {
            valType: 'enumerated',
            values: ['right', 'top', 'bottom'],
            dflt: 'top',
            description: 'Deprecated in favor of color bar\'s `title.side`.'
        }
    }
}, 'colorbars', 'from-root');
<|endoftext|>


<commit_before>import { hasStatusLoading } from "./lazyload.data";
import { decreaseLoadingCount } from "./lazyload.event";
import { resetSourcesImg } from "./lazyload.setSources";
import { safeCallback } from "./lazyload.callback";

export const cancelIfLoading = (element, entry, settings, instance) => {
    if (!settings.cancel_on_exit) return;
    if (!hasStatusLoading(element)) return;
    if (element.tagName !== "IMG") return;
    resetSourcesImg(element, settings, instance);
    decreaseLoadingCount(instance);
    safeCallback(settings.callback_cancel, element, entry, instance);
    // setTimeout is needed because the "callback_cancel" implementation
    // could be out of the main thread, e.g. `img.setAttribute("src", "")`
    setTimeout(() => {
        instance.resetElementStatus(element, instance);
    }, 0);
};
<commit_msg>cancelIfLoading: Removing event listeners before resetting sources<commit_after>import { hasStatusLoading } from "./lazyload.data";
import { decreaseLoadingCount, removeEventListeners } from "./lazyload.event";
import { resetSourcesImg } from "./lazyload.setSources";
import { safeCallback } from "./lazyload.callback";

export const cancelIfLoading = (element, entry, settings, instance) => {
    if (!settings.cancel_on_exit) return;
    if (!hasStatusLoading(element)) return;
    if (element.tagName !== "IMG") return;
    removeEventListeners(element);
    resetSourcesImg(element, settings, instance);
    decreaseLoadingCount(instance);
    safeCallback(settings.callback_cancel, element, entry, instance);
    // setTimeout is needed because the "callback_cancel" implementation
    // could be out of the main thread, e.g. `img.setAttribute("src", "")`
    setTimeout(() => {
        instance.resetElementStatus(element, instance);
    }, 0);
};
<|endoftext|>


<commit_before>import {
  GraphQLObjectType
} from 'graphql'
import {
  mrType,
  mrArgs,
  mrResolve
} from '../../../src'
import Starship from './starship'
import StarshipModel from '../../models/starship'
import Product from './product'
import ProductModel from '../../models/product'
import foodTypes from '../../data/foodTypes.json'

const RootQuery = new GraphQLObjectType({
  name: 'RootQuery',
  fields: {
    allStarships: {
      type: mrType('Starships', Starship),
      args: mrArgs,
      resolve (parentValue, args) {
        const opts = {
          cursorField: 'starshipClass'
        }
        return mrResolve(args, StarshipModel, {}, opts)
      }
    },
    allFoodProducts: {
      type: mrType('FoodProduct', Product),
      args: mrArgs,
      resolve (parentValue, args) {
        const query = {
          type: { $in: foodTypes }
        }
        const opts = {
          cursorField: 'price',
          direction: -1
        }
        return mrResolve(args, ProductModel, query, opts)
      }
    }
  }
})

export default RootQuery
<commit_msg>:sparkles: add query: allNonFoodProducts with mapNode options<commit_after>import {
  GraphQLObjectType
} from 'graphql'
import {
  mrType,
  mrArgs,
  mrResolve
} from '../../../src'
import Starship from './starship'
import StarshipModel from '../../models/starship'
import {
  Product,
  ProductPrice
} from './product'
import ProductModel from '../../models/product'
import foodTypes from '../../data/foodTypes.json'

const RootQuery = new GraphQLObjectType({
  name: 'RootQuery',
  fields: {
    allStarships: {
      type: mrType('Starships', Starship),
      args: mrArgs,
      resolve (parentValue, args) {
        const opts = {
          cursorField: 'starshipClass'
        }
        return mrResolve(args, StarshipModel, {}, opts)
      }
    },
    allFoodProducts: {
      type: mrType('FoodProduct', Product),
      args: mrArgs,
      resolve (parentValue, args) {
        const query = {
          type: { $in: foodTypes }
        }
        const opts = {
          cursorField: 'price',
          direction: -1
        }
        return mrResolve(args, ProductModel, query, opts)
      }
    },
    allNonFoodProducts: {
      type: mrType('NonFoodProduct', ProductPrice),
      args: mrArgs,
      resolve (parentValue, args) {
        const query = {
          type: { $nin: foodTypes }
        }
        const format = p => +p.toFixed(2)
        const opts = {
          cursorField: 'price',
          direction: -1,
          mapNode: x => {
            return {
              name: x.name,
              type: x.type,
              usd: format(x.price / 7.78),
              euro: format(x.price / 8.71),
              yen: format(x.price * 14.36)
            }
          }
        }
        return mrResolve(args, ProductModel, query, opts)
      }
    }
  }
})

export default RootQuery
<|endoftext|>


<commit_before>import retry from 'async-retry';
import dns from 'dns';
import Now from '../lib';
import toHost from './to-host';
import chalk from 'chalk';
import table from 'text-table';
import ms from 'ms';

export default class Alias extends Now {

  async ls (deployment) {
    if (deployment) {
      const target = await this.findDeployment(deployment);
      if (!target) {
        const err = new Error(`Aliases not found by "${deployment}". Run ${chalk.dim('`now alias ls`')} to see your aliases.`);
        err.userError = true;
        throw err;
      }

      return this.retry(async (bail, attempt) => {
        const res = await this._fetch(`/now/deployments/${target.uid}/aliases`);
        const body = await res.json();
        return body.aliases;
      });
    }

    return this.retry(async (bail, attempt) => {
      const res = await this._fetch('/now/aliases');
      const body = await res.json();
      return body.aliases;
    });
  }

  async rm (alias) {
    const _alias = await this.findAlias(alias);
    if (!_alias) {
      const err = new Error(`Alias not found by "${alias}". Run ${chalk.dim('`now alias ls`')} to see your aliases.`);
      err.userError = true;
      throw err;
    }

    if (await readConfirmation(_alias)) {
      return this.retry(async (bail, attempt) => {
        const res = await this._fetch(`/now/aliases/${_alias.uid}`, {
          method: 'DELETE'
        });

        if (403 === res.status) {
          return bail(new Error('Unauthorized'));
        }

        if (res.status !== 200) {
          const err = new Error('Deletion failed. Try again later.');
          throw err;
        }

        console.log(`${chalk.cyan('> Success!')} The alias has been removed.`);
      });
    } else {
      console.log('> Aborted');
    }
  }

  async findAlias (alias) {
    const list = await this.ls();

    let key, val;
    if (/\./.test(alias)) {
      val = toHost(alias);
      key = 'alias';
    } else {
      val = alias;
      key = 'uid';
    }

    const _alias = list.find((d) => {
      if (d[key] === val) {
        if (this._debug) console.log(`> [debug] matched alias ${d.uid} by ${key} ${val}`);
        return true;
      }

      // match prefix
      if (`${val}.now.sh` === d.alias) {
        if (this._debug) console.log(`> [debug] matched alias ${d.uid} by url ${d.host}`);
        return true;
      }

      return false;
    });

    return _alias;
  }

  async findDeployment (deployment) {
    const list = await this.list();
    let key, val;
    if (/\./.test(deployment)) {
      val = toHost(deployment);
      key = 'url';
    } else {
      val = deployment;
      key = 'uid';
    }

    const depl = list.find((d) => {
      if (d[key] === val) {
        if (this._debug) console.log(`> [debug] matched deployment ${d.uid} by ${key} ${val}`);
        return true;
      }

      // match prefix
      if (`${val}.now.sh` === d.url) {
        if (this._debug) console.log(`> [debug] matched deployment ${d.uid} by url ${d.url}`);
        return true;
      }

      return false;
    });

    return depl;
  }

  async set (deployment, alias) {
    alias = alias.toLowerCase();

    const depl = await this.findDeployment(deployment);
    if (!depl) {
      const err = new Error(`Deployment not found by "${deployment}". Run ${chalk.dim('`now ls`')} to see your deployments.`);
      err.userError = true;
      throw err;
    }

    // evaluate the alias
    if (!/\./.test(alias)) {
      if (this._debug) console.log(`> [debug] suffixing \`.now.sh\` to alias ${alias}`);
      alias = `${alias}.now.sh`;
    } else {
      alias = toHost(alias);
    }

    if (!/\.now\.sh$/.test(alias)) {
      console.log(`> ${chalk.bold(chalk.underline(alias))} is a custom domain.`);
      console.log(`> Verifying that ${chalk.bold(chalk.underline(alias))} has a ${chalk.cyan('`CNAME`')} or ${chalk.cyan('`ALIAS`')} record pointing to ${chalk.bold(chalk.underline('alias.zeit.co'))}.`);
      await this.verifyOwnership(alias);
    }

    await this.createAlias(depl, alias);
    console.log(`${chalk.cyan('> Success!')} Deployment ${chalk.bold(`https://${depl.url}`)} ${chalk.dim(`(${depl.uid})`)} now points to ${chalk.bold(chalk.underline(`https://${alias}`))}`);
  }

  createAlias (depl, alias) {
    return this.retry(async (bail, attempt) => {
      if (this._debug) console.time(`> [debug] /now/deployments/${depl.uid}/aliases #${attempt}`);
      const res = await this._fetch(`/now/deployments/${depl.uid}/aliases`, {
        method: 'POST',
        body: { alias }
      });

      if (304 === res.status) return;

      const body = await res.json();
      if (this._debug) console.timeEnd(`> [debug] /now/deployments/${depl.uid}/aliases #${attempt}`);

      // no retry on authorization problems
      if (403 === res.status) {
        const code = body.error.code;

        if ('custom_domain_needs_upgrade' === code) {
          const err = new Error(`Custom domains are only enabled for premium accounts. Please upgrade at ${chalk.underline('https://zeit.co/account')}.`);
          err.userError = true;
          return bail(err);
        }

        if ('alias_in_use' === code) {
          const err = new Error(`The alias you are trying to configure (${chalk.underline(chalk.bold(alias))}) is already in use by a different account.`);
          err.userError = true;
          return bail(err);
        }

        return bail(new Error('Authorization error'));
      }

      // all other errors
      if (body.error) {
        const code = body.error.code;

        if ('deployment_not_found' === code) {
          return bail(new Error('Deployment not found'));
        }

        if ('cert_missing' === code) {
          console.log(`> Provisioning certificate for ${chalk.underline(chalk.cyan(alias))}`);

          await this.createCert();

          // try again, but now having provisioned the certificate
          return this.createAlias(depl, alias);
        }

        return bail(new Error(body.error.message));
      }

      // the two expected succesful cods are 200 and 304
      if (200 !== res.status && 304 !== res.status) {
        throw new Error('Unhandled error');
      }
    });
  }

  verifyOwnership (domain) {
    return this.retry(async (bail, attempt) => {
      const targets = await resolve4('alias.zeit.co');

      if (!targets.length) {
        return bail(new Error('Unable to resolve alias.zeit.co'));
      }

      const ips = await resolve4(domain);
      if (!ips.length) {
        const err = new Error('The domain ${domain} A record in the DNS configuration is not returning any IPs.');
        err.userError = true;
        return bail(err);
      }

      for (const ip of ips) {
        if (!~targets.indexOf(ip)) {
          const err = new Error(`The domain ${domain} has an A record ${chalk.bold(ip)} that doesn\'t resolve to ${chalk.bold(chalk.underline('alias.zeit.co'))}. Please check your DNS settings.`);
          err.userError = true;
          return bail(err);
        }
      }
    });
  }

  createCert (domain) {
    return this.retry(async (bail, attempt) => {
      if (this._debug) console.time(`> [debug] /certs #${attempt}`);
      const res = await this._fetch('/certs', {
        method: 'POST',
        body: {
          domains: [domain]
        }
      });

      const body = await res.json();
      if (this._debug) console.timeEnd(`> [debug] /certs #${attempt}`);

      if (body.error) {
        const { code } = body.error;

        if ('verification_failed' === code) {
          const err = new Error(`We couldn't verify ownership of the domain ${domain}. Make sure the appropriate \`ALIAS\` or \`CNAME\` records are configured and pointing to ${chalk.bold('alias.zeit.co')}.`);
          err.userError = true;
          return bail(err);
        }

        throw new Error(body.message);
      }

      if (200 !== res.status && 304 !== res.status) {
        throw new Error('Unhandled error');
      }
    });
  }

  retry (fn) {
    return retry(fn, { retries: 5, randomize: true, onRetry: this._onRetry });
  }

}

function resolve4 (host) {
  return new Promise((resolve, reject) => {
    return dns.resolve4(host, (err, answer) => {
      if (err) return reject(err);
      resolve(answer);
    });
  });
}

function readConfirmation (alias) {
  return new Promise((resolve, reject) => {
    const time = chalk.gray(ms(new Date() - new Date(alias.created)) + ' ago');
    const tbl = table(
      [[alias.uid, `https://${alias.alias}`, time]],
      { align: ['l', 'r', 'l'], hsep: ' '.repeat(3) }
    );

    process.stdout.write('> The following alias will be removed permanently\n');
    process.stdout.write('  ' + tbl + '\n');
    process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`);

    process.stdin.on('data', (d) => {
      process.stdin.pause();
      process.stdin.write('\n');
      resolve('y' === d.toString().trim());
    }).resume();
  });
}
<commit_msg>alias: handle 409<commit_after>import retry from 'async-retry';
import dns from 'dns';
import Now from '../lib';
import toHost from './to-host';
import chalk from 'chalk';
import table from 'text-table';
import ms from 'ms';

export default class Alias extends Now {

  async ls (deployment) {
    if (deployment) {
      const target = await this.findDeployment(deployment);
      if (!target) {
        const err = new Error(`Aliases not found by "${deployment}". Run ${chalk.dim('`now alias ls`')} to see your aliases.`);
        err.userError = true;
        throw err;
      }

      return this.retry(async (bail, attempt) => {
        const res = await this._fetch(`/now/deployments/${target.uid}/aliases`);
        const body = await res.json();
        return body.aliases;
      });
    }

    return this.retry(async (bail, attempt) => {
      const res = await this._fetch('/now/aliases');
      const body = await res.json();
      return body.aliases;
    });
  }

  async rm (alias) {
    const _alias = await this.findAlias(alias);
    if (!_alias) {
      const err = new Error(`Alias not found by "${alias}". Run ${chalk.dim('`now alias ls`')} to see your aliases.`);
      err.userError = true;
      throw err;
    }

    if (await readConfirmation(_alias)) {
      return this.retry(async (bail, attempt) => {
        const res = await this._fetch(`/now/aliases/${_alias.uid}`, {
          method: 'DELETE'
        });

        if (403 === res.status) {
          return bail(new Error('Unauthorized'));
        }

        if (res.status !== 200) {
          const err = new Error('Deletion failed. Try again later.');
          throw err;
        }

        console.log(`${chalk.cyan('> Success!')} The alias has been removed.`);
      });
    } else {
      console.log('> Aborted');
    }
  }

  async findAlias (alias) {
    const list = await this.ls();

    let key, val;
    if (/\./.test(alias)) {
      val = toHost(alias);
      key = 'alias';
    } else {
      val = alias;
      key = 'uid';
    }

    const _alias = list.find((d) => {
      if (d[key] === val) {
        if (this._debug) console.log(`> [debug] matched alias ${d.uid} by ${key} ${val}`);
        return true;
      }

      // match prefix
      if (`${val}.now.sh` === d.alias) {
        if (this._debug) console.log(`> [debug] matched alias ${d.uid} by url ${d.host}`);
        return true;
      }

      return false;
    });

    return _alias;
  }

  async findDeployment (deployment) {
    const list = await this.list();
    let key, val;
    if (/\./.test(deployment)) {
      val = toHost(deployment);
      key = 'url';
    } else {
      val = deployment;
      key = 'uid';
    }

    const depl = list.find((d) => {
      if (d[key] === val) {
        if (this._debug) console.log(`> [debug] matched deployment ${d.uid} by ${key} ${val}`);
        return true;
      }

      // match prefix
      if (`${val}.now.sh` === d.url) {
        if (this._debug) console.log(`> [debug] matched deployment ${d.uid} by url ${d.url}`);
        return true;
      }

      return false;
    });

    return depl;
  }

  async set (deployment, alias) {
    alias = alias.toLowerCase();

    const depl = await this.findDeployment(deployment);
    if (!depl) {
      const err = new Error(`Deployment not found by "${deployment}". Run ${chalk.dim('`now ls`')} to see your deployments.`);
      err.userError = true;
      throw err;
    }

    // evaluate the alias
    if (!/\./.test(alias)) {
      if (this._debug) console.log(`> [debug] suffixing \`.now.sh\` to alias ${alias}`);
      alias = `${alias}.now.sh`;
    } else {
      alias = toHost(alias);
    }

    if (!/\.now\.sh$/.test(alias)) {
      console.log(`> ${chalk.bold(chalk.underline(alias))} is a custom domain.`);
      console.log(`> Verifying that ${chalk.bold(chalk.underline(alias))} has a ${chalk.cyan('`CNAME`')} or ${chalk.cyan('`ALIAS`')} record pointing to ${chalk.bold(chalk.underline('alias.zeit.co'))}.`);
      await this.verifyOwnership(alias);
    }

    const { created, uid } = await this.createAlias(depl, alias);
    if (created) {
      console.log(`${chalk.cyan('> Success!')} Alias created ${chalk.dim(`(${uid})`)}: ${chalk.bold(`https://${depl.url}`)} ${chalk.dim(`(${depl.uid})`)} now points to ${chalk.bold(chalk.underline(`https://${alias}`))}`);
    } else {
      console.log(`${chalk.cyan('> Success!')} Alias already exists ${chalk.dim(`(${uid})`)}.`);
    }
  }

  createAlias (depl, alias) {
    return this.retry(async (bail, attempt) => {
      if (this._debug) console.time(`> [debug] /now/deployments/${depl.uid}/aliases #${attempt}`);
      const res = await this._fetch(`/now/deployments/${depl.uid}/aliases`, {
        method: 'POST',
        body: { alias }
      });

      const body = await res.json();
      if (this._debug) console.timeEnd(`> [debug] /now/deployments/${depl.uid}/aliases #${attempt}`);

      // 409 conflict is returned if it already exists
      if (409 === res.status) return { uid: body.error.uid };

      // no retry on authorization problems
      if (403 === res.status) {
        const code = body.error.code;

        if ('custom_domain_needs_upgrade' === code) {
          const err = new Error(`Custom domains are only enabled for premium accounts. Please upgrade at ${chalk.underline('https://zeit.co/account')}.`);
          err.userError = true;
          return bail(err);
        }

        if ('alias_in_use' === code) {
          const err = new Error(`The alias you are trying to configure (${chalk.underline(chalk.bold(alias))}) is already in use by a different account.`);
          err.userError = true;
          return bail(err);
        }

        return bail(new Error('Authorization error'));
      }

      // all other errors
      if (body.error) {
        const code = body.error.code;

        if ('deployment_not_found' === code) {
          return bail(new Error('Deployment not found'));
        }

        if ('cert_missing' === code) {
          console.log(`> Provisioning certificate for ${chalk.underline(chalk.cyan(alias))}`);

          await this.createCert();

          // try again, but now having provisioned the certificate
          return this.createAlias(depl, alias);
        }

        return bail(new Error(body.error.message));
      }

      // the two expected succesful cods are 200 and 304
      if (200 !== res.status && 304 !== res.status) {
        throw new Error('Unhandled error');
      }

      return body;
    });
  }

  verifyOwnership (domain) {
    return this.retry(async (bail, attempt) => {
      const targets = await resolve4('alias.zeit.co');

      if (!targets.length) {
        return bail(new Error('Unable to resolve alias.zeit.co'));
      }

      const ips = await resolve4(domain);
      if (!ips.length) {
        const err = new Error('The domain ${domain} A record in the DNS configuration is not returning any IPs.');
        err.userError = true;
        return bail(err);
      }

      for (const ip of ips) {
        if (!~targets.indexOf(ip)) {
          const err = new Error(`The domain ${domain} has an A record ${chalk.bold(ip)} that doesn\'t resolve to ${chalk.bold(chalk.underline('alias.zeit.co'))}. Please check your DNS settings.`);
          err.userError = true;
          return bail(err);
        }
      }
    });
  }

  createCert (domain) {
    return this.retry(async (bail, attempt) => {
      if (this._debug) console.time(`> [debug] /certs #${attempt}`);
      const res = await this._fetch('/certs', {
        method: 'POST',
        body: {
          domains: [domain]
        }
      });

      const body = await res.json();
      if (this._debug) console.timeEnd(`> [debug] /certs #${attempt}`);

      if (body.error) {
        const { code } = body.error;

        if ('verification_failed' === code) {
          const err = new Error(`We couldn't verify ownership of the domain ${domain}. Make sure the appropriate \`ALIAS\` or \`CNAME\` records are configured and pointing to ${chalk.bold('alias.zeit.co')}.`);
          err.userError = true;
          return bail(err);
        }

        throw new Error(body.message);
      }

      if (200 !== res.status && 304 !== res.status) {
        throw new Error('Unhandled error');
      }
    });
  }

  retry (fn) {
    return retry(fn, { retries: 5, randomize: true, onRetry: this._onRetry });
  }

}

function resolve4 (host) {
  return new Promise((resolve, reject) => {
    return dns.resolve4(host, (err, answer) => {
      if (err) return reject(err);
      resolve(answer);
    });
  });
}

function readConfirmation (alias) {
  return new Promise((resolve, reject) => {
    const time = chalk.gray(ms(new Date() - new Date(alias.created)) + ' ago');
    const tbl = table(
      [[alias.uid, `https://${alias.alias}`, time]],
      { align: ['l', 'r', 'l'], hsep: ' '.repeat(3) }
    );

    process.stdout.write('> The following alias will be removed permanently\n');
    process.stdout.write('  ' + tbl + '\n');
    process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`);

    process.stdin.on('data', (d) => {
      process.stdin.pause();
      process.stdin.write('\n');
      resolve('y' === d.toString().trim());
    }).resume();
  });
}
<|endoftext|>


<commit_before>/**
 * A text field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define([
    'react',
    'build/Components/Panels/Page/Form/label.react',
    'jquery.fileupload'
], function (React, Label) {
    return React.createClass({
        componentDidMount: function () {
            //Dynamically add the element since we don't want to have React to bind its events to it
            var node = $(this.refs.file.getDOMNode()).append(
                $('<input type="file" />')
            );

            node.fileupload({
                url: this.props.item.getTarget()
            });
        },
        render: function () {
            return (

            );
        }
    });

});<commit_msg>Removed name<commit_after>/**
 * A text field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define([
    'react',
    'build/Components/Panels/Page/Form/label.react',
    'jquery.fileupload'
], function (React, Label) {
    return React.createClass({
        componentDidMount: function () {
            //Dynamically add the element since we don't want to have React to bind its events to it
            var node = $(this.refs.file.getDOMNode()).append(
                $('<input type="file" name="file" data-name="file" />')
            );

            node.fileupload({
                url: this.props.item.getTarget(),

                //Transfer the reference we got from the upload response
                done: function (e, data) {
                    var ref = '';
                    for (var i in data.result.files) {
                        ref = data.result.files[0].ref;
                    }
                    $(this.refs.hidden.getDOMNode()).val(ref);
                }.bind(this)
            });
        },
        render: function () {
            return (

                    <input type="text" name={this.props.item.getName()} ref="hidden" />

            );
        }
    });

});<|endoftext|>