<commit_before>// declare all vars
var loader        = document.getElementById('loader');
var scene         = new THREE.Scene();
var SCENE_FOV_MIN = 1;
var SCENE_FOV_MAX = 1000;
var SCREEN_WIDTH  = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var camera        = new THREE.PerspectiveCamera(45, SCREEN_WIDTH / SCREEN_HEIGHT, SCENE_FOV_MIN, SCENE_FOV_MAX);
var renderer      = new THREE.WebGLRenderer();
var plane_texture = new THREE.ImageUtils.loadTexture('cat.jpg');
var shader        = THREE.ShaderLib['normalmap'];
var displacement  = 25;
var uniforms      = THREE.UniformsUtils.clone(shader.uniforms);
var parameters    = {
    fragmentShader: shader.fragmentShader,
    vertexShader: shader.vertexShader,
    uniforms: uniforms,
    lights: true,
    wireframe: false
};
var shader        = new THREE.ShaderMaterial(parameters);
var geometry      = new THREE.PlaneGeometry(500, 281, 500, 281);
var plane         = new THREE.Mesh(geometry, shader);
var tween;

function init() {
    // first time init of WebGl business
    renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    document.body.appendChild(renderer.domElement);

    // set some defaults
    camera.position.z = -300;
    camera.position.y = -220;
    camera.lookAt(scene.position);

    // setup light
    ambientLight = new THREE.AmbientLight(0xFFFFFF);
    scene.add(ambientLight);

    // do the first time calculation
    calculateDisplacementMap();

    // make it easy to see the image by rotating to center canvas
    plane.rotation.y = Math.PI;
    scene.add(plane);
    return;
}

function calculateDisplacementMap() {
    // separete displacement map values into a
    // for isolated updates and computation
    uniforms['enableDisplacement'].value = true;
    uniforms['enableDiffuse'].value      = true;
    uniforms['tDisplacement'].value      = plane_texture;
    uniforms['tDiffuse'].value           = plane_texture;
    uniforms['uDisplacementScale'].value = displacement;
    geometry.computeTangents();
    return;
}

function animate() {
    // event loop
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
    return;
}

function initDOMControls() {
    // init image picker, reload map on click
    var pics = $('#pics');
    pics.on('click', 'a', function(e){
        globalLoader.load('Loading image map...');
        e.preventDefault();

        // re-init image map with new texture since points
        // need to be recalculated
        var img = $(this).find('img').attr('src');
        plane_texture = new THREE.ImageUtils.loadTexture(img);
        calculateDisplacementMap();
        globalLoader.unload();
    });
    return;
}

function demControls() {
    // create object for dat.gui reference
    this.message       = 'Adjust Displacement';
    this.scale         = displacement;
    this.camera_z      = -200;
    this.camera_x      = -220;
    this.camera_y      = -220;
    this.rotation      = 0;
    this.autoplay      = false;
    this.map_light     = '#ffffff';
    this.wire_border   = 2;
    this.use_wireframe = false;
    return;
}

function initControls() {
    // create controls for each reference to demControls
    var gui  = new dat.GUI();
    var controls = new demControls();
    var autoplay_interval;

    // dat.gui controllers
    var camera_rot_slider;
    var camera_z_slider;
    var camera_y_slider;
    var camera_x_slider;
    var displacement_slider;
    var autoplay;
    var toggle_wireframe;
    var wireframe_border;
    var map_light;

    // add the controls object
    gui.add(controls, 'message');

    // add individual toggles
    toggle_wireframe = gui.add(controls, 'use_wireframe');
    toggle_wireframe.onChange(function(value) {
        shader.wireframe = value;
    });
    wireframe_border = gui.add(controls, 'wire_border', 1, 100);
    wireframe_border.onChange(function(value) {
        uniforms['uDisplacementScale'].value = value;
    });
    map_light = gui.addColor(controls, 'map_light');
    map_light.onChange(function(value) {
        ambientLight.color.setHex('0x' + value.replace('#', ''));
    });
    autoplay = gui.add(controls, 'autoplay');
    autoplay.onChange(function(is_autoplay) {
        if(is_autoplay) {
            autoplay_interval = setInterval(function(){
                uniforms['uDisplacementScale'].value = rando(200);
                return;
            }, 1000);
        } else {
            clearInterval(autoplay_interval);
        }
    });
    displacement_slider = gui.add(controls, 'scale', -200, 200);
    displacement_slider.onChange(function(value) {
        uniforms['uDisplacementScale'].value = value;
    });
    camera_z_slider = gui.add(controls, 'camera_z', -300, 100);
    camera_z_slider.onChange(function(value) {
        camera.position.z = value;
    });
    camera_y_slider = gui.add(controls, 'camera_y', -320, 200);
    camera_y_slider.onChange(function(value) {
        camera.position.y = value;
    });
    camera_x_slider = gui.add(controls, 'camera_x', -320, 200);
    camera_x_slider.onChange(function(value) {
        camera.position.x = value;
    });
    camera_rot_slider = gui.add(controls, 'rotation', -360, 360);
    camera_rot_slider.onChange(function(value) {
        camera.rotation.z = value * 0.001;
        camera.updateProjectionMatrix();
    });
    return;
}

window.onload = function() {
    // load all the first time on windowload
    globalLoader.load('Loading image map...');

    // init all controls
    initDOMControls();
    initControls();
    init();

    // trigger event loop
    requestAnimationFrame(animate);
    globalLoader.unload();
    return;
};
<commit_msg>Fix image link<commit_after>// declare all vars
var loader        = document.getElementById('loader');
var scene         = new THREE.Scene();
var SCENE_FOV_MIN = 1;
var SCENE_FOV_MAX = 1000;
var SCREEN_WIDTH  = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var camera        = new THREE.PerspectiveCamera(45, SCREEN_WIDTH / SCREEN_HEIGHT, SCENE_FOV_MIN, SCENE_FOV_MAX);
var renderer      = new THREE.WebGLRenderer();
var plane_texture = new THREE.ImageUtils.loadTexture('imgs/cat.jpg');
var shader        = THREE.ShaderLib['normalmap'];
var displacement  = 25;
var uniforms      = THREE.UniformsUtils.clone(shader.uniforms);
var parameters    = {
    fragmentShader: shader.fragmentShader,
    vertexShader: shader.vertexShader,
    uniforms: uniforms,
    lights: true,
    wireframe: false
};
var shader        = new THREE.ShaderMaterial(parameters);
var geometry      = new THREE.PlaneGeometry(500, 281, 500, 281);
var plane         = new THREE.Mesh(geometry, shader);
var tween;

function init() {
    // first time init of WebGl business
    renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    document.body.appendChild(renderer.domElement);

    // set some defaults
    camera.position.z = -300;
    camera.position.y = -220;
    camera.lookAt(scene.position);

    // setup light
    ambientLight = new THREE.AmbientLight(0xFFFFFF);
    scene.add(ambientLight);

    // do the first time calculation
    calculateDisplacementMap();

    // make it easy to see the image by rotating to center canvas
    plane.rotation.y = Math.PI;
    scene.add(plane);
    return;
}

function calculateDisplacementMap() {
    // separete displacement map values into a
    // for isolated updates and computation
    uniforms['enableDisplacement'].value = true;
    uniforms['enableDiffuse'].value      = true;
    uniforms['tDisplacement'].value      = plane_texture;
    uniforms['tDiffuse'].value           = plane_texture;
    uniforms['uDisplacementScale'].value = displacement;
    geometry.computeTangents();
    return;
}

function animate() {
    // event loop
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
    return;
}

function initDOMControls() {
    // init image picker, reload map on click
    var pics = $('#pics');
    pics.on('click', 'a', function(e){
        globalLoader.load('Loading image map...');
        e.preventDefault();

        // re-init image map with new texture since points
        // need to be recalculated
        var img = $(this).find('img').attr('src');
        plane_texture = new THREE.ImageUtils.loadTexture(img);
        calculateDisplacementMap();
        globalLoader.unload();
    });
    return;
}

function demControls() {
    // create object for dat.gui reference
    this.message       = 'Adjust Displacement';
    this.scale         = displacement;
    this.camera_z      = -200;
    this.camera_x      = -220;
    this.camera_y      = -220;
    this.rotation      = 0;
    this.autoplay      = false;
    this.map_light     = '#ffffff';
    this.wire_border   = 2;
    this.use_wireframe = false;
    return;
}

function initControls() {
    // create controls for each reference to demControls
    var gui  = new dat.GUI();
    var controls = new demControls();
    var autoplay_interval;

    // dat.gui controllers
    var camera_rot_slider;
    var camera_z_slider;
    var camera_y_slider;
    var camera_x_slider;
    var displacement_slider;
    var autoplay;
    var toggle_wireframe;
    var wireframe_border;
    var map_light;

    // add the controls object
    gui.add(controls, 'message');

    // add individual toggles
    toggle_wireframe = gui.add(controls, 'use_wireframe');
    toggle_wireframe.onChange(function(value) {
        shader.wireframe = value;
    });
    wireframe_border = gui.add(controls, 'wire_border', 1, 100);
    wireframe_border.onChange(function(value) {
        uniforms['uDisplacementScale'].value = value;
    });
    map_light = gui.addColor(controls, 'map_light');
    map_light.onChange(function(value) {
        ambientLight.color.setHex('0x' + value.replace('#', ''));
    });
    autoplay = gui.add(controls, 'autoplay');
    autoplay.onChange(function(is_autoplay) {
        if(is_autoplay) {
            autoplay_interval = setInterval(function(){
                uniforms['uDisplacementScale'].value = rando(200);
                return;
            }, 1000);
        } else {
            clearInterval(autoplay_interval);
        }
    });
    displacement_slider = gui.add(controls, 'scale', -200, 200);
    displacement_slider.onChange(function(value) {
        uniforms['uDisplacementScale'].value = value;
    });
    camera_z_slider = gui.add(controls, 'camera_z', -300, 100);
    camera_z_slider.onChange(function(value) {
        camera.position.z = value;
    });
    camera_y_slider = gui.add(controls, 'camera_y', -320, 200);
    camera_y_slider.onChange(function(value) {
        camera.position.y = value;
    });
    camera_x_slider = gui.add(controls, 'camera_x', -320, 200);
    camera_x_slider.onChange(function(value) {
        camera.position.x = value;
    });
    camera_rot_slider = gui.add(controls, 'rotation', -360, 360);
    camera_rot_slider.onChange(function(value) {
        camera.rotation.z = value * 0.001;
        camera.updateProjectionMatrix();
    });
    return;
}

window.onload = function() {
    // load all the first time on windowload
    globalLoader.load('Loading image map...');

    // init all controls
    initDOMControls();
    initControls();
    init();

    // trigger event loop
    requestAnimationFrame(animate);
    globalLoader.unload();
    return;
};
<|endoftext|>


<commit_before>
/**
 * Panel to show Delivery info.
 */
Ext.define('devilry.extjshelpers.assignmentgroup.DeliveryInfo', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.deliveryinfo',
    cls: 'widget-deliveryinfo',
    html: '',
    requires: [
        'devilry.extjshelpers.assignmentgroup.FileMetaBrowserPanel'
    ],

    //width: 500,
    //style: {border: 'none'},

    config: {
        /**
         * @cfg
         * FileMeta ``Ext.data.Store``. (Required).
         * _Note_ that ``filemetastore.proxy.extraParams`` is changed by this
         * class.
         */
        filemetastore: undefined,

        /**
         * @cfg
         * A {@link devilry.extjshelpers.SingleRecordContainer} for Delivery.
         */
        delivery_recordcontainer: undefined,

        /**
         * @cfg
         * Delivery ``Ext.data.Model``.
         */
        deliverymodel: undefined,

        /**
         * @cfg
         * A {@link devilry.extjshelpers.SingleRecordContainer} for AssignmentGroup.
         */
        assignmentgroup_recordcontainer: undefined
    },

    tpl: Ext.create('Ext.XTemplate',
        '<tpl if="time_of_delivery">', // If time_of_delivery is false, the record is not loaded yet
        '
',
        '
Delivery number {number}
',
        '
This delivery was made {time_of_delivery:date}. Choose Browse files in the toolbar to download the delivered files.
',
        '
',
        '    <tpl if="time_of_delivery > deadline__deadline">',
        '
',
        '
After deadline
',
        '
This delivery was made after the deadline ({deadline__deadline:date}).
',
        '
',
        '    </tpl>',
        '</tpl>'
    ),

    initComponent: function() {
        this.toolbar = Ext.widget('toolbar', {
            xtype: 'toolbar',
            dock: 'top',
            items: []
        });

        Ext.apply(this, {
            hidden: true,
            dockedItems: [this.toolbar]
        });
        this.callParent(arguments);

        if(this.delivery_recordcontainer.record) {
            this.onLoadDelivery();
        }
        this.delivery_recordcontainer.addListener('setRecord', this.onLoadDelivery, this);
    },

    /**
     * @private
     */
    onLoadDelivery: function() {
        var delivery = this.delivery_recordcontainer.record.data;
        this.show();
        this.toolbar.removeAll();
        this.update(delivery);

        this.toolbar.add({
            xtype: 'button',
            text: 'Browse files',
            id: 'tooltip-browse-files',
            scale: 'large',
            menu: [], // To get an arrow
            enableToggle: true,
            listeners: {
                scope: this,
                click: this.showFileMetaBrowserWindow,
                render: function() {
                    Ext.create('devilry.extjshelpers.tooltips.assignmentgroup.BrowseFiles', {});
                }
            }
        });

        this.toolbar.add({
            xtype: 'button',
            menu: [], // To get an arrow
            id: 'tooltip-other-deliveries',
            text: 'Other deliveries',
            scale: 'large',
            enableToggle: true,
            listeners: {
                scope: this,
                click: this.onOtherDeliveries
            }
        });
    },

    /**
     * @private
     */
    onOtherDeliveries: function(button) {
        if(!this.deliveriesWindow) {
            this.deliveriesWindow = Ext.create('Ext.window.Window', {
                title: 'Deliveries by this group',
                height: 500,
                width: 400,
                modal: true,
                layout: 'fit',
                closeAction: 'hide',
                items: {
                    xtype: 'deliveriesonsinglegrouplisting',
                    assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                    delivery_recordcontainer: this.delivery_recordcontainer,
                    deliverymodel: this.deliverymodel,
                    deadlinemodel: this.deadlinemodel,
                    enableDeadlineCreation: this.canExamine
                },

                listeners: {
                    scope: this,
                    close: function() {
                        try {
                            button.toggle(false);
                        } catch(err) {
                            // This error occurrs because we clear the toolbar on selection.
                        }
                    }
                }
            });
        }
        this.deliveriesWindow.show();
        if(button) {
            this.deliveriesWindow.alignTo(button, 'bl', [0, 0]);
        }
    },

    /**
     * @private
     */
    showFileMetaBrowserWindow: function(button) {
        var fileBrowser = Ext.create('Ext.window.Window', {
            title: 'Files',
            height: 400,
            width: 500,
            modal: true,
            //animateTarget: button,
            layout: 'fit',
            items: [{
                xtype: 'filemetabrowserpanel',
                border: false,
                filemetastore: this.filemetastore,
                deliveryid: this.delivery_recordcontainer.record.data.id
            }],
            listeners: {
                scope: this,
                close: function() {
                    button.toggle(false);
                }
            }
        });
        fileBrowser.show();
        fileBrowser.alignTo(button, 'bl', [0, 0]);
    }
});
<commit_msg>apps.extjshelpers: Minor changes.<commit_after>
/**
 * Panel to show Delivery info.
 */
Ext.define('devilry.extjshelpers.assignmentgroup.DeliveryInfo', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.deliveryinfo',
    cls: 'widget-deliveryinfo',
    html: '',
    requires: [
        'devilry.extjshelpers.assignmentgroup.FileMetaBrowserPanel'
    ],

    //width: 500,
    //style: {border: 'none'},

    config: {
        /**
         * @cfg
         * FileMeta ``Ext.data.Store``. (Required).
         * _Note_ that ``filemetastore.proxy.extraParams`` is changed by this
         * class.
         */
        filemetastore: undefined,

        /**
         * @cfg
         * A {@link devilry.extjshelpers.SingleRecordContainer} for Delivery.
         */
        delivery_recordcontainer: undefined,

        /**
         * @cfg
         * Delivery ``Ext.data.Model``.
         */
        deliverymodel: undefined,

        /**
         * @cfg
         * A {@link devilry.extjshelpers.SingleRecordContainer} for AssignmentGroup.
         */
        assignmentgroup_recordcontainer: undefined
    },

    tpl: Ext.create('Ext.XTemplate',
        '<tpl if="time_of_delivery">', // If time_of_delivery is false, the record is not loaded yet
        '
',
        '
Delivery number {number}
',
        '
This delivery was made {time_of_delivery:date}. Choose Browse files in the toolbar to download the delivered files.
',
        '
',
        '    <tpl if="time_of_delivery > deadline__deadline">',
        '
',
        '
After deadline
',
        '
This delivery was made after the deadline ({deadline__deadline:date}).
',
        '
',
        '    </tpl>',
        '</tpl>'
    ),

    initComponent: function() {
        this.toolbar = Ext.widget('toolbar', {
            xtype: 'toolbar',
            dock: 'top',
            items: []
        });

        Ext.apply(this, {
            hidden: true,
            dockedItems: [this.toolbar]
        });
        this.callParent(arguments);

        if(this.delivery_recordcontainer.record) {
            this.onLoadDelivery();
        }
        this.delivery_recordcontainer.addListener('setRecord', this.onLoadDelivery, this);
    },

    /**
     * @private
     */
    onLoadDelivery: function() {
        var delivery = this.delivery_recordcontainer.record.data;
        this.show();
        this.toolbar.removeAll();
        this.update(delivery);

        this.toolbar.add({
            xtype: 'button',
            text: 'Browse files',
            id: 'tooltip-browse-files',
            scale: 'large',
            menu: [], // To get an arrow
            enableToggle: true,
            listeners: {
                scope: this,
                click: this.showFileMetaBrowserWindow,
                render: function() {
                    Ext.create('devilry.extjshelpers.tooltips.assignmentgroup.BrowseFiles', {});
                }
            }
        });

        this.toolbar.add({
            xtype: 'button',
            menu: [], // To get an arrow
            id: 'tooltip-other-deliveries',
            text: 'Other deliveries',
            scale: 'large',
            //enableToggle: true,
            listeners: {
                scope: this,
                click: this.onOtherDeliveries
            }
        });
    },

    /**
     * @private
     */
    onOtherDeliveries: function(button) {
        if(!this.deliveriesWindow) {
            this.deliveriesWindow = Ext.create('Ext.window.Window', {
                title: 'Deliveries by this group',
                height: 500,
                width: 400,
                modal: true,
                layout: 'fit',
                closeAction: 'hide',
                items: {
                    xtype: 'deliveriesonsinglegrouplisting',
                    assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                    delivery_recordcontainer: this.delivery_recordcontainer,
                    deliverymodel: this.deliverymodel,
                    deadlinemodel: this.deadlinemodel,
                    enableDeadlineCreation: this.canExamine
                },

                //listeners: {
                    //scope: this,
                    //close: function() {
                        //if(button) {
                            //button.toggle(false);
                        //}
                    //}
                //}
            });
        }
        this.deliveriesWindow.show();
        if(button) {
            this.deliveriesWindow.alignTo(button, 'bl', [0, 0]);
        }
    },

    /**
     * @private
     */
    showFileMetaBrowserWindow: function(button) {
        var fileBrowser = Ext.create('Ext.window.Window', {
            title: 'Files',
            height: 400,
            width: 500,
            modal: true,
            //animateTarget: button,
            layout: 'fit',
            items: [{
                xtype: 'filemetabrowserpanel',
                border: false,
                filemetastore: this.filemetastore,
                deliveryid: this.delivery_recordcontainer.record.data.id
            }],
            listeners: {
                scope: this,
                close: function() {
                    button.toggle(false);
                }
            }
        });
        fileBrowser.show();
        fileBrowser.alignTo(button, 'bl', [0, 0]);
    }
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict'

const _ = require('lodash/fp')
const co = require('co')
const fs = require('mz/fs')
const path = require('path')
const requireDir = require('require-dir')
const winston = require('winston')

const LibratoApi = require('./index').LibratoApi

const logger = new winston.Logger({
  level: process.env.LIBRATO_LOG_LEVEL || process.env.LOG_LEVEL || 'info',
  transports: [
    new winston.transports.Console({
      stderrLevels: _.keys(winston.levels),
      prettyPrint: true,
      align: true,
      colorize: true
    })
  ]
})
const libratoApi = new LibratoApi({ logger })

const getId = _.get('id')
const getNames = _.map('name')
const getIdAndNames = _.map(_.at(['id', 'name']))
const getNamesById = _.flow(getIdAndNames, _.fromPairs)
const getIdAndTitles = _.map(_.at(['id', 'title']))
const getTitlesById = _.flow(getIdAndTitles, _.fromPairs)

function * readJson (maybeSource) {
  const source = maybeSource || process.stdin.fd
  const buffer = yield fs.readFile(source)
  return JSON.parse(buffer.toString())
}

function * writeJson (maybeSink, data) {
  const jsonData = JSON.stringify(data, undefined, 2) + '\n'
  return (maybeSink === undefined)
    ? process.stdout.write(jsonData)
    : yield fs.writeFile(maybeSink, jsonData)
}

// does sync IO (requireDir)
function readConfigDir (configDir) {
  if (configDir === undefined) { throw new Error('missing config dir') }
  const absConfigDir = configDir.startsWith('/')
    ? configDir
    : path.join(process.cwd(), configDir)
  return requireDir(absConfigDir, { recurse: true })
}

// -- metric actions

function * listMetrics (maybeSink) {
  logger.verbose('listMetrics', { to: maybeSink })
  const metrics = yield libratoApi.getAllMetrics()
  yield writeJson(maybeSink, getNames(metrics))
}

function * getMetrics (maybeSink) {
  logger.verbose('getMetrics', { to: maybeSink })
  const metrics = yield libratoApi.getAllMetrics()
  yield writeJson(maybeSink, metrics)
}

function * getMetric (name, maybeSink) {
  logger.verbose('getMetric', { name, to: maybeSink })
  const metric = yield libratoApi.getMetric(name)
  yield writeJson(maybeSink, metric)
}

// -- space actions (with embedded charts)

function * listSpaces (maybeSink) {
  logger.verbose('listSpaces', { to: maybeSink })
  const spaces = yield libratoApi.getAllSpaces()
  yield writeJson(maybeSink, getNamesById(spaces))
}

function * dumpSpace (name, maybeSink) {
  logger.verbose('dumpSpace', { space: name, to: maybeSink })
  const space = yield libratoApi.dumpSpace(name)
  yield writeJson(maybeSink, space)
}

function * createOrUpdateSpace (maybeSource) {
  logger.verbose('createOrUpdateSpace', { from: maybeSource })
  const space = readJson(maybeSource)
  logger.debug('space definition', { space })
  yield libratoApi.createOrUpdateSpace(space)
}

function * deleteSpace (name) {
  logger.verbose('deleteSpace', { space: name })
  const space = yield libratoApi.findSpaceByName(name)
  yield libratoApi.deleteSpace(space.id)
}

// -- alert actions

function * listAlerts (maybeSink) {
  logger.verbose('listAlerts', { to: maybeSink })
  const alerts = yield libratoApi.getAllAlerts()
  yield writeJson(maybeSink, getNamesById(alerts))
}

function * getAlerts (maybeSink) {
  logger.verbose('getAlerts', { to: maybeSink })
  const alerts = yield libratoApi.getAllAlerts()
  yield writeJson(maybeSink, alerts)
}

function * getAlertsStatus (maybeSink) {
  logger.verbose('getAlertsStatus', { to: maybeSink })
  const status = yield libratoApi.getAlertsStatus()
  yield writeJson(maybeSink, status)
}

function * getAlert (idOrName, maybeSink) {
  logger.verbose('getAlert', { idOrName, to: maybeSink })
  const alert = yield libratoApi.getAlert(idOrName)
    .catch(_err => libratoApi.findAlertByName(idOrName))
  yield writeJson(maybeSink, alert)
}

// -- service actions

function * listServices (maybeSink) {
  logger.verbose('listServices', { to: maybeSink })
  const services = yield libratoApi.getAllServices()
  yield writeJson(maybeSink, getTitlesById(services))
}

function * getServices (maybeSink) {
  logger.verbose('getServices', { to: maybeSink })
  const services = yield libratoApi.getAllServices()
  yield writeJson(maybeSink, services)
}

function * getService (idOrTitle, maybeSink) {
  logger.verbose('getService', { idOrTitle, to: maybeSink })
  const service = yield libratoApi.getService(idOrTitle)
    .catch(_err => libratoApi.findServiceByTitle(idOrTitle))
  yield writeJson(maybeSink, service)
}

// -- source actions

function * listSources (maybeSink) {
  logger.verbose('listSources', { to: maybeSink })
  const sources = yield libratoApi.getAllSources()
  yield writeJson(maybeSink, getNames(sources))
}

function * getSources (maybeSink) {
  logger.verbose('getSources', { to: maybeSink })
  const sources = yield libratoApi.getAllSources()
  yield writeJson(maybeSink, sources)
}

function * getSource (name, maybeSink) {
  logger.verbose('getSource', { name, to: maybeSink })
  const source = yield libratoApi.getSource(name)
  yield writeJson(maybeSink, source)
}

// -- config dir actions

function * showConfigDir (configDir, maybeSink) {
  logger.verbose('showConfigDir', { configDir, to: maybeSink })
  const rawConfig = readConfigDir(configDir)
  const config = libratoApi._processRawConfig(rawConfig)
  yield writeJson(maybeSink, config)
}

function * showRawConfigDir (configDir, maybeSink) {
  logger.verbose('showRawConfigDir', { configDir, to: maybeSink })
  const rawConfig = readConfigDir(configDir)
  yield writeJson(maybeSink, rawConfig)
}

/**
 * @Note Some updates are silently ignored, e.g. trying to change a metric's
 * l2met_type or created_by_ua. This is just how the API works.
 *
 * @TODO move applying the config from here to LibratoAPI,
 *  collect errors like in createOrUpdateSpace, and provide tests.
 */
function * updateFromDir (configDir) {
  logger.verbose('updateFromDir', { configDir })
  const rawConfig = readConfigDir(configDir)
  const config = libratoApi._processRawConfig(rawConfig)

  var errorCount = 0
  const logOK = (what, id) => _result => {
    logger.verbose('%s %s', what, id)
  }
  const logAndCountError = (what, id) => err => {
    errorCount += 1
    logger.error('%s %s failed', what, id, {
      [what]: id,
      msg: err.toString(),
      errors: _.get('error.errors', err)
    })
  }
  const ignore404 = (what, id) => err => {
    if (err.statusCode === 404) {
      logger.verbose('%s %s (nothing there)', what, id)
    } else {
      throw err
    }
  }
  const withLogging = (what, id, action) =>
    action.then(logOK(what, id)).catch(logAndCountError(what, id))
  const withLoggingIgnore404 = (what, id, action) =>
    action.then(logOK(what, id), ignore404(what, id)).catch(logAndCountError(what, id))

  const deleteMetric = name =>
    withLoggingIgnore404('delete metric', name, libratoApi.deleteMetric(name))
  const deleteSpace = name =>
    withLoggingIgnore404(
      'delete space', name,
      libratoApi.findSpaceByName(name).then(getId).then(id => libratoApi.deleteSpace(id))
    )
  const deleteAlert = name =>
    withLoggingIgnore404(
      'delete alert', name,
      libratoApi.findAlertByName(name).then(getId).then(id => libratoApi.deleteAlert(id))
    )
  const deleteService = name =>
    withLoggingIgnore404(
      'delete service', name,
      libratoApi.findServiceByTitle(name).then(getId).then(id => libratoApi.deleteService(id))
    )
  const deleteSource = name =>
    withLoggingIgnore404('delete source', name, libratoApi.deleteSource(name))

  const updateMetric = metric =>
    withLogging('update metric', metric.name, libratoApi.putMetric(metric.name, metric))
  const updateSpace = space =>
    withLogging('update space', space.name, libratoApi.createOrUpdateSpace(space))
  const updateAlert = alert =>
    withLogging('update alert', alert.name, libratoApi.createOrUpdateAlert(alert))
  const updateService = service =>
    withLogging('update service', service.title, libratoApi.createOrUpdateService(service))
  const updateSource = source =>
    withLogging('update source', source.name, libratoApi.putSource(source.name, source))

  // deletes first
  yield {
    metrics: _.map(deleteMetric, config.outdated.metrics),
    spaces: _.map(deleteSpace, config.outdated.spaces),
    alerts: _.map(deleteAlert, config.outdated.alerts),
    services: _.map(deleteService, config.outdated.services),
    sources: _.map(deleteSource, config.outdated.sources)
  }
  // updates
  yield {
    metrics: _.map(updateMetric, config.metrics),
    services: _.map(updateService, config.services),
    sources: _.map(updateSource, config.sources)
  }
  // updates depending on metrics
  yield {
    spaces: _.map(updateSpace, config.spaces),
    alerts: _.map(updateAlert, config.alerts)
  }

  if (errorCount > 0) { throw new Error(`${errorCount} errors occured`) }
}

// -- main

function * help () {
  const getCmdList = _.flow(_.keys, _.reject(_.startsWith('_')), _.join(', '))
  process.stdout.write(`Commands: ${getCmdList(actions)}\n`)
}

const actions = {
  'list-metrics': listMetrics,
  'get-metrics': getMetrics,
  'get-metric': getMetric,
  'list-spaces': listSpaces,
  'dump-space': dumpSpace,
  'update-space': createOrUpdateSpace,
  'delete-space': deleteSpace,
  'list-alerts': listAlerts,
  'get-alerts': getAlerts,
  'get-alerts-status': getAlertsStatus,
  'get-alert': getAlert,
  'list-services': listServices,
  'get-services': getServices,
  'get-service': getService,
  'list-sources': listSources,
  'get-sources': getSources,
  'get-source': getSource,
  'show-config-dir': showConfigDir,
  'show-raw-config-dir': showRawConfigDir,
  'update-from-dir': updateFromDir,
  'help': help
}

/**
 * CLI tool to manage Librato backend configuration.
 *
 * @author Jürgen Strobel <juergen.strobel@emarsys.com>
 */
function * main (argv) {
  const cmd = argv[2]
  const args = _.drop(3, argv)
  function * unknownCommand () { throw new Error(`unknown command ${cmd}, use "help"`) }
  try {
    if (process.env.LIBRATO_USER === undefined || process.env.LIBRATO_TOKEN === undefined) {
      throw new Error('LIBRATO_USER and LIBRATO_TOKEN must be set in the environment')
    }
    // let's look at proper argv parsing and help sometime
    // https://www.npmjs.com/package/command-line-args
    // or https://github.com/75lb/command-line-commands
    const action = _.getOr(unknownCommand, cmd, actions)
    logger.debug('dispatching', { cmd, action, args })
    yield _.spread(action)(args)
    logger.debug('success')
  } catch (err) {
    process.exitCode = 1
    _.has('error', err)
      ? logger.error('%s: %s', err.name, err.message, err.error)
      : logger.error('%s: %s', err.name, err.message)
  }
}

module.exports = main
module.exports.actions = actions

// execute main only if required at top level
if (require.main === module) { co(main(process.argv)) }
<commit_msg>EDREI-32741 - Fixing update-space<commit_after>#!/usr/bin/env node
'use strict'

const _ = require('lodash/fp')
const co = require('co')
const fs = require('mz/fs')
const path = require('path')
const requireDir = require('require-dir')
const winston = require('winston')

const LibratoApi = require('./index').LibratoApi

const logger = new winston.Logger({
  level: process.env.LIBRATO_LOG_LEVEL || process.env.LOG_LEVEL || 'info',
  transports: [
    new winston.transports.Console({
      stderrLevels: _.keys(winston.levels),
      prettyPrint: true,
      align: true,
      colorize: true
    })
  ]
})
const libratoApi = new LibratoApi({ logger })

const getId = _.get('id')
const getNames = _.map('name')
const getIdAndNames = _.map(_.at(['id', 'name']))
const getNamesById = _.flow(getIdAndNames, _.fromPairs)
const getIdAndTitles = _.map(_.at(['id', 'title']))
const getTitlesById = _.flow(getIdAndTitles, _.fromPairs)

function * readJson (maybeSource) {
  const source = maybeSource || process.stdin.fd
  const buffer = yield fs.readFile(source)
  return JSON.parse(buffer.toString())
}

function * writeJson (maybeSink, data) {
  const jsonData = JSON.stringify(data, undefined, 2) + '\n'
  return (maybeSink === undefined)
    ? process.stdout.write(jsonData)
    : yield fs.writeFile(maybeSink, jsonData)
}

// does sync IO (requireDir)
function readConfigDir (configDir) {
  if (configDir === undefined) { throw new Error('missing config dir') }
  const absConfigDir = configDir.startsWith('/')
    ? configDir
    : path.join(process.cwd(), configDir)
  return requireDir(absConfigDir, { recurse: true })
}

// -- metric actions

function * listMetrics (maybeSink) {
  logger.verbose('listMetrics', { to: maybeSink })
  const metrics = yield libratoApi.getAllMetrics()
  yield writeJson(maybeSink, getNames(metrics))
}

function * getMetrics (maybeSink) {
  logger.verbose('getMetrics', { to: maybeSink })
  const metrics = yield libratoApi.getAllMetrics()
  yield writeJson(maybeSink, metrics)
}

function * getMetric (name, maybeSink) {
  logger.verbose('getMetric', { name, to: maybeSink })
  const metric = yield libratoApi.getMetric(name)
  yield writeJson(maybeSink, metric)
}

// -- space actions (with embedded charts)

function * listSpaces (maybeSink) {
  logger.verbose('listSpaces', { to: maybeSink })
  const spaces = yield libratoApi.getAllSpaces()
  yield writeJson(maybeSink, getNamesById(spaces))
}

function * dumpSpace (name, maybeSink) {
  logger.verbose('dumpSpace', { space: name, to: maybeSink })
  const space = yield libratoApi.dumpSpace(name)
  yield writeJson(maybeSink, space)
}

function * createOrUpdateSpace (maybeSource) {
  logger.verbose('createOrUpdateSpace', { from: maybeSource })
  const space = yield readJson(maybeSource)
  logger.debug('space definition', { space })
  yield libratoApi.createOrUpdateSpace(space)
}

function * deleteSpace (name) {
  logger.verbose('deleteSpace', { space: name })
  const space = yield libratoApi.findSpaceByName(name)
  yield libratoApi.deleteSpace(space.id)
}

// -- alert actions

function * listAlerts (maybeSink) {
  logger.verbose('listAlerts', { to: maybeSink })
  const alerts = yield libratoApi.getAllAlerts()
  yield writeJson(maybeSink, getNamesById(alerts))
}

function * getAlerts (maybeSink) {
  logger.verbose('getAlerts', { to: maybeSink })
  const alerts = yield libratoApi.getAllAlerts()
  yield writeJson(maybeSink, alerts)
}

function * getAlertsStatus (maybeSink) {
  logger.verbose('getAlertsStatus', { to: maybeSink })
  const status = yield libratoApi.getAlertsStatus()
  yield writeJson(maybeSink, status)
}

function * getAlert (idOrName, maybeSink) {
  logger.verbose('getAlert', { idOrName, to: maybeSink })
  const alert = yield libratoApi.getAlert(idOrName)
    .catch(_err => libratoApi.findAlertByName(idOrName))
  yield writeJson(maybeSink, alert)
}

// -- service actions

function * listServices (maybeSink) {
  logger.verbose('listServices', { to: maybeSink })
  const services = yield libratoApi.getAllServices()
  yield writeJson(maybeSink, getTitlesById(services))
}

function * getServices (maybeSink) {
  logger.verbose('getServices', { to: maybeSink })
  const services = yield libratoApi.getAllServices()
  yield writeJson(maybeSink, services)
}

function * getService (idOrTitle, maybeSink) {
  logger.verbose('getService', { idOrTitle, to: maybeSink })
  const service = yield libratoApi.getService(idOrTitle)
    .catch(_err => libratoApi.findServiceByTitle(idOrTitle))
  yield writeJson(maybeSink, service)
}

// -- source actions

function * listSources (maybeSink) {
  logger.verbose('listSources', { to: maybeSink })
  const sources = yield libratoApi.getAllSources()
  yield writeJson(maybeSink, getNames(sources))
}

function * getSources (maybeSink) {
  logger.verbose('getSources', { to: maybeSink })
  const sources = yield libratoApi.getAllSources()
  yield writeJson(maybeSink, sources)
}

function * getSource (name, maybeSink) {
  logger.verbose('getSource', { name, to: maybeSink })
  const source = yield libratoApi.getSource(name)
  yield writeJson(maybeSink, source)
}

// -- config dir actions

function * showConfigDir (configDir, maybeSink) {
  logger.verbose('showConfigDir', { configDir, to: maybeSink })
  const rawConfig = readConfigDir(configDir)
  const config = libratoApi._processRawConfig(rawConfig)
  yield writeJson(maybeSink, config)
}

function * showRawConfigDir (configDir, maybeSink) {
  logger.verbose('showRawConfigDir', { configDir, to: maybeSink })
  const rawConfig = readConfigDir(configDir)
  yield writeJson(maybeSink, rawConfig)
}

/**
 * @Note Some updates are silently ignored, e.g. trying to change a metric's
 * l2met_type or created_by_ua. This is just how the API works.
 *
 * @TODO move applying the config from here to LibratoAPI,
 *  collect errors like in createOrUpdateSpace, and provide tests.
 */
function * updateFromDir (configDir) {
  logger.verbose('updateFromDir', { configDir })
  const rawConfig = readConfigDir(configDir)
  const config = libratoApi._processRawConfig(rawConfig)

  var errorCount = 0
  const logOK = (what, id) => _result => {
    logger.verbose('%s %s', what, id)
  }
  const logAndCountError = (what, id) => err => {
    errorCount += 1
    logger.error('%s %s failed', what, id, {
      [what]: id,
      msg: err.toString(),
      errors: _.get('error.errors', err)
    })
  }
  const ignore404 = (what, id) => err => {
    if (err.statusCode === 404) {
      logger.verbose('%s %s (nothing there)', what, id)
    } else {
      throw err
    }
  }
  const withLogging = (what, id, action) =>
    action.then(logOK(what, id)).catch(logAndCountError(what, id))
  const withLoggingIgnore404 = (what, id, action) =>
    action.then(logOK(what, id), ignore404(what, id)).catch(logAndCountError(what, id))

  const deleteMetric = name =>
    withLoggingIgnore404('delete metric', name, libratoApi.deleteMetric(name))
  const deleteSpace = name =>
    withLoggingIgnore404(
      'delete space', name,
      libratoApi.findSpaceByName(name).then(getId).then(id => libratoApi.deleteSpace(id))
    )
  const deleteAlert = name =>
    withLoggingIgnore404(
      'delete alert', name,
      libratoApi.findAlertByName(name).then(getId).then(id => libratoApi.deleteAlert(id))
    )
  const deleteService = name =>
    withLoggingIgnore404(
      'delete service', name,
      libratoApi.findServiceByTitle(name).then(getId).then(id => libratoApi.deleteService(id))
    )
  const deleteSource = name =>
    withLoggingIgnore404('delete source', name, libratoApi.deleteSource(name))

  const updateMetric = metric =>
    withLogging('update metric', metric.name, libratoApi.putMetric(metric.name, metric))
  const updateSpace = space =>
    withLogging('update space', space.name, libratoApi.createOrUpdateSpace(space))
  const updateAlert = alert =>
    withLogging('update alert', alert.name, libratoApi.createOrUpdateAlert(alert))
  const updateService = service =>
    withLogging('update service', service.title, libratoApi.createOrUpdateService(service))
  const updateSource = source =>
    withLogging('update source', source.name, libratoApi.putSource(source.name, source))

  // deletes first
  yield {
    metrics: _.map(deleteMetric, config.outdated.metrics),
    spaces: _.map(deleteSpace, config.outdated.spaces),
    alerts: _.map(deleteAlert, config.outdated.alerts),
    services: _.map(deleteService, config.outdated.services),
    sources: _.map(deleteSource, config.outdated.sources)
  }
  // updates
  yield {
    metrics: _.map(updateMetric, config.metrics),
    services: _.map(updateService, config.services),
    sources: _.map(updateSource, config.sources)
  }
  // updates depending on metrics
  yield {
    spaces: _.map(updateSpace, config.spaces),
    alerts: _.map(updateAlert, config.alerts)
  }

  if (errorCount > 0) { throw new Error(`${errorCount} errors occured`) }
}

// -- main

function * help () {
  const getCmdList = _.flow(_.keys, _.reject(_.startsWith('_')), _.join(', '))
  process.stdout.write(`Commands: ${getCmdList(actions)}\n`)
}

const actions = {
  'list-metrics': listMetrics,
  'get-metrics': getMetrics,
  'get-metric': getMetric,
  'list-spaces': listSpaces,
  'dump-space': dumpSpace,
  'update-space': createOrUpdateSpace,
  'delete-space': deleteSpace,
  'list-alerts': listAlerts,
  'get-alerts': getAlerts,
  'get-alerts-status': getAlertsStatus,
  'get-alert': getAlert,
  'list-services': listServices,
  'get-services': getServices,
  'get-service': getService,
  'list-sources': listSources,
  'get-sources': getSources,
  'get-source': getSource,
  'show-config-dir': showConfigDir,
  'show-raw-config-dir': showRawConfigDir,
  'update-from-dir': updateFromDir,
  'help': help
}

/**
 * CLI tool to manage Librato backend configuration.
 *
 * @author Jürgen Strobel <juergen.strobel@emarsys.com>
 */
function * main (argv) {
  const cmd = argv[2]
  const args = _.drop(3, argv)
  function * unknownCommand () { throw new Error(`unknown command ${cmd}, use "help"`) }
  try {
    if (process.env.LIBRATO_USER === undefined || process.env.LIBRATO_TOKEN === undefined) {
      throw new Error('LIBRATO_USER and LIBRATO_TOKEN must be set in the environment')
    }
    // let's look at proper argv parsing and help sometime
    // https://www.npmjs.com/package/command-line-args
    // or https://github.com/75lb/command-line-commands
    const action = _.getOr(unknownCommand, cmd, actions)
    logger.debug('dispatching', { cmd, action, args })
    yield _.spread(action)(args)
    logger.debug('success')
  } catch (err) {
    process.exitCode = 1
    _.has('error', err)
      ? logger.error('%s: %s', err.name, err.message, err.error)
      : logger.error('%s: %s', err.name, err.message)
  }
}

module.exports = main
module.exports.actions = actions

// execute main only if required at top level
if (require.main === module) { co(main(process.argv)) }
<|endoftext|>


<commit_before>import { makeLogger, arrayify, mapObject } from './utils'
const { debug } = makeLogger('connect')

import instance from './instance'

/**
 * Higher-order function that creates a function that will execute `func` on all
 * `instances` with the given arguments.
 *
 * @param  {Function} func
 * @param  {Object|Array} instances
 * @return {Array}
 */
const execAll = (func, instances) => (...args) => {
  const mappingFn = (obj) => obj[func](...args)

  if (Array.isArray(instances)) return instances.map(mappingFn)
  else return mapObject(instances, mappingFn)
}

/**
 * Enhance instances container with `on`, `send` and `dispatch` functions
 *
 * @param {Object|Array} instances
 * @return {Object|Array}
 */
const enhanceInstances = (instances) => {
  // enhance `instances` container
  instances.on = execAll('on', instances)
  instances.send = execAll('send', instances)
  instances.dispatch = execAll('dispatch', instances)
  instances.filter = (fn) => enhanceInstances(Array.filter(instances, fn))
  instances.map = (fn) => enhanceInstances(Array.map(instances, fn))
  instances.reduce = (fn) => enhanceInstances(Array.reduce(instances, fn))
  return instances
}

/**
 * Create an instance container, which allows handling multiple networks on
 * various protocols.
 *
 * You can pass:
 *  - a single config object (will return an array with a single instance)
 *  - an array of config objects (will return an array with instances)
 *  - an object of config objects (will return an object of instances)
 *
 * @param  {Object|Array} rawConfig
 * @return {Object|Array}
 */
export default function connect (rawConfig) {
  debug('connect(' + JSON.stringify(rawConfig) + ')')

  let instances
  if (Array.isArray(rawConfig)) { // array of configs
    instances = rawConfig.map(instance)
  } else if (rawConfig.hasOwnProperty('protocol')) { // single config
    instances = arrayify(instance(rawConfig))
  } else { // object of configs
    instances = mapObject(rawConfig, instance)
  }

  if (
    (Array.isArray(instances) && instances.length === 0) ||
    (Object.keys(instances).length === 0)
  ) throw new Error('no config/s defined')

  return enhanceInstances(instances)
}
<commit_msg>don't break the unit tests<commit_after>import { makeLogger, arrayify, mapObject } from './utils'
const { debug } = makeLogger('connect')

import instance from './instance'

/**
 * Higher-order function that creates a function that will execute `func` on all
 * `instances` with the given arguments.
 *
 * @param  {Function} func
 * @param  {Object|Array} instances
 * @return {Array}
 */
const execAll = (func, instances) => (...args) => {
  const mappingFn = (obj) => obj && obj[func] && obj[func](...args)

  if (Array.isArray(instances)) return instances.map(mappingFn)
  else return mapObject(instances, mappingFn)
}

/**
 * Enhance instances container with `on`, `send` and `dispatch` functions
 *
 * @param {Object|Array} instances
 * @return {Object|Array}
 */
const enhanceInstances = (instances) => {
  // enhance `instances` container
  instances.on = execAll('on', instances)
  instances.send = execAll('send', instances)
  instances.dispatch = execAll('dispatch', instances)
  instances.filter = (fn) => enhanceInstances(Array.from(instances).filter(fn))
  instances.map = (fn) => enhanceInstances(Array.from(instances).map(fn))
  instances.reduce = (fn) => enhanceInstances(Array.from(instances).reduce(fn))
  return instances
}

/**
 * Create an instance container, which allows handling multiple networks on
 * various protocols.
 *
 * You can pass:
 *  - a single config object (will return an array with a single instance)
 *  - an array of config objects (will return an array with instances)
 *  - an object of config objects (will return an object of instances)
 *
 * @param  {Object|Array} rawConfig
 * @return {Object|Array}
 */
export default function connect (rawConfig) {
  debug('connect(' + JSON.stringify(rawConfig) + ')')

  let instances
  if (Array.isArray(rawConfig)) { // array of configs
    instances = rawConfig.map(instance)
  } else if (rawConfig.hasOwnProperty('protocol')) { // single config
    instances = arrayify(instance(rawConfig))
  } else { // object of configs
    instances = mapObject(rawConfig, instance)
  }

  if (
    (Array.isArray(instances) && instances.length === 0) ||
    (Object.keys(instances).length === 0)
  ) throw new Error('no config/s defined')

  return enhanceInstances(instances)
}
<|endoftext|>


<commit_before>task = (function(uuid){
    self = this;

    var task_api = "/api/v4/task?uuid=" + uuid;
    var taskresult_api = "/api/v4/taskresult/" + uuid;

    // Initial timeout in milliseconds. Will increase half a second for
    // every poll, with an upper limit of 3 seconds.
    var timeout = 200;

    /*
     * Po
     */
    function poll(timeout){
        $.ajax({
            url: task_api,
            dataType: 'json',
            success: poll_success,
            error: poll_error
        })
    }

    function poll_error(){
        $("#status").text("Polling failed. Refresh?");
    }

    function poll_success(data){
        self.timeout = (timeout >= 3000) ? timeout : timeout + 500;

        var task = data["results"][0];
        if (!task.ready && task.status === "INPROGRESS" && task.progress !== null){
            // Not yet ready, progress indication supplied
            window.setTimeout(poll, timeout);
        } else if (!task.ready){
            // Not yet ready, but no progress indiction supplied also
            window.setTimeout(poll, timeout);
        } else if (task.ready && task.status != "SUCCESS") {
            // Task ready, but failed.
            task_failed(task);
        } else {
            // Task ready and available for download
            task_success(task);
        }

        update_progress(task);
    }

    function update_progress(task){
        $("#status").text(task.status);

        if (task.progress !== null){
            $("#message").text(task.message);
            $("#progress").text(task.progress);
        }
    }

    function task_failed(task){
        console.log("failed")
    }

    function task_success(task){
        $(".hide-if-success").hide();
        $("#results").show();
    }

    poll();
});<commit_msg>Fixed scoping issue causing poll delay to stay at 200 ms.<commit_after>task = (function(uuid){
    self = this;

    var task_api = "/api/v4/task?uuid=" + uuid;
    var taskresult_api = "/api/v4/taskresult/" + uuid;

    // Initial timeout in milliseconds. Will increase half a second for
    // every poll, with an upper limit of 3 seconds.
    var timeout = 200;

    /*
     * Po
     */
    function poll(timeout){
        $.ajax({
            url: task_api,
            dataType: 'json',
            success: poll_success,
            error: poll_error
        })
    }

    function poll_error(){
        $("#status").text("Polling failed. Refresh?");
    }

    function poll_success(data){
        timeout = (timeout >= 3000) ? timeout : timeout + 500;

        var task = data["results"][0];
        if (!task.ready && task.status === "INPROGRESS" && task.progress !== null){
            // Not yet ready, progress indication supplied
            window.setTimeout(poll, timeout);
        } else if (!task.ready){
            // Not yet ready, but no progress indiction supplied also
            window.setTimeout(poll, timeout);
        } else if (task.ready && task.status != "SUCCESS") {
            // Task ready, but failed.
            task_failed(task);
        } else {
            // Task ready and available for download
            task_success(task);
        }

        update_progress(task);
    }

    function update_progress(task){
        $("#status").text(task.status);

        if (task.progress !== null){
            $("#message").text(task.message);
            $("#progress").text(task.progress);
        }
    }

    function task_failed(task){
        console.log("failed")
    }

    function task_success(task){
        $(".hide-if-success").hide();
        $("#results").show();
    }

    poll();
});<|endoftext|>


<commit_before>var prevTypes = {},
    origRepoTypes = [],
    powerPackTemplate = [
        '
', gettext('Power Pack Required'), '
',
        '
',
        gettext(' support is available with Power Pack, an extension which also offers powerful reports, document review, and more.'),
        '
'
    ].join('');

function updateFormDisplay(id, tools_info) {
    var type = $('#id_' + id).val(),
        oldInfo = tools_info[prevTypes[id]],
        newInfo = tools_info[type],
        text,
        field,
        i;

    for (i = 0; i < oldInfo.fields.length; i++) {
        $('#row-' + oldInfo.fields[i]).hide();
    }

    for (field in oldInfo.help_text) {
        $('#row-' + field).find('p.help')
            .remove();
    }

    for (i = 0; i < newInfo.fields.length; i++) {
        $('#row-' + newInfo.fields[i]).show();
    }

    for (field in newInfo.help_text) {
        if (newInfo.help_text.hasOwnProperty(field)) {
            text = newInfo.help_text[field];

            $('
')
                .text(text)
                .appendTo($('#row-' + field));
        }
    }

    prevTypes[id] = type;
}

function updatePlanEl($row, $plan, serviceType) {
    var planTypes = HOSTING_SERVICES[serviceType].plans,
        selectedPlan = $plan.val(),
        planType,
        opt,
        i;

    $plan.empty();

    if (planTypes.length === 1) {
        $row.hide();
    } else {
        for (i = 0; i < planTypes.length; i++) {
            planType = planTypes[i];
            opt = $('<option/>')
                .val(planType.type)
                .text(planType.label)
                .appendTo($plan);

            if (planType.type === selectedPlan) {
                opt.prop('selected', true);
            }
        }

        $row.show();
    }

    $plan.triggerHandler('change');
}

function updateHostingForm($hostingType, formPrefix, $plan, $forms) {
    var formID = formPrefix + '-' + $hostingType.val() + '-' +
                 ($plan.val() || 'default');

    $forms.hide();
    $('#' + formID).show();
}

function hideAllToolsFields() {
    var fields = TOOLS_INFO.none.fields,
        i;

    for (i = 0; i < fields.length; i++) {
        $('#row-' + fields[i]).hide();
    }
}

function updateRepositoryType() {
    var hostingType = $('#id_hosting_type').val(),
        newRepoTypes = (hostingType === 'custom'
                        ? []
                        : HOSTING_SERVICES[hostingType].scmtools),
        $repoTypes = $('#id_tool'),
        currentRepoType = $repoTypes.val();

    $repoTypes.empty();

    $(origRepoTypes).each(function (i) {
        var repoType = origRepoTypes[i];

        if (newRepoTypes.length === 0 ||
            newRepoTypes.indexOf(repoType.text) !== -1) {
            $('<option/>')
                .text(repoType.text)
                .val(repoType.value)
                .appendTo($repoTypes);

            if (repoType.value === currentRepoType) {
                $repoTypes.val(currentRepoType);
            }
        }
    });

    $repoTypes.triggerHandler('change');
}

$(document).ready(function() {
    var $hostingType = $('#id_hosting_type'),
        $hostingURLRow = $('#row-hosting_url'),
        $hostingURL = $('#id_hosting_url'),
        $hostingAccount = $('#id_hosting_account'),
        $hostingAccountRow = $('#row-hosting_account'),
        $hostingAccountUserRow = $('#row-hosting_account_username'),
        $hostingAccountPassRow = $('#row-hosting_account_password'),
        $hostingAccountTwoFactorAuthCodeRow =
            $('#row-hosting_account_two_factor_auth_code'),
        $hostingAccountRelink = $('
')
            .text(gettext('The authentication requirements for this account have changed. You will need to re-authenticate.'))
            .addClass('errornote')
            .hide()
            .appendTo($hostingAccountRow),
        $associateSshKeyFieldset =
            $('#row-associate_ssh_key').parents('fieldset'),
        $associateSshKey = $('#id_associate_ssh_key'),
        associateSshKeyDisabled = $associateSshKey.prop('disabled'),
        $bugTrackerUseHosting = $('#id_bug_tracker_use_hosting'),
        $bugTrackerType = $('#id_bug_tracker_type'),
        $bugTrackerHostingURLRow = $('#row-bug_tracker_hosting_url'),
        $bugTrackerTypeRow = $('#row-bug_tracker_type'),
        $bugTrackerPlan = $('#id_bug_tracker_plan'),
        $bugTrackerPlanRow = $('#row-bug_tracker_plan'),
        $bugTrackerURLRow = $('#row-bug_tracker'),
        $bugTrackerUsernameRow =
            $('#row-bug_tracker_hosting_account_username'),
        $repoPathRow = $('#row-path'),
        $repoMirrorPathRow = $('#row-mirror_path'),
        $repoPlanRow = $('#row-repository_plan'),
        $repoPlan = $('#id_repository_plan'),
        $publicAccess = $('#id_public'),
        $tool = $('#id_tool'),
        $toolRow = $('#row-tool'),
        $publicKeyPopup = $('#ssh-public-key-popup'),
        $repoForms = $('.repo-form'),
        $bugTrackerForms = $('.bug-tracker-form'),
        $submitButtons = $('input[type="submit"]'),
        $powerPackAdvert = $('
')
            .html(powerPackTemplate)
            .hide()
            .appendTo($hostingType.closest('fieldset'));

    prevTypes.bug_tracker_type = 'none';
    prevTypes.hosting_type = 'custom';
    prevTypes.tool = 'none';

    $tool.find('option').each(function() {
        var $repoType = $(this);

        origRepoTypes.push({
            value: $repoType.val(),
            text: $repoType.text()
        });
    });

    $bugTrackerUseHosting
        .change(function() {
            if (this.checked) {
                $bugTrackerTypeRow.hide();
                $bugTrackerPlanRow.hide();
                $bugTrackerUsernameRow.hide();
                $bugTrackerURLRow.hide();
                $bugTrackerForms.hide();
            } else {
                $bugTrackerTypeRow.show();
                $bugTrackerType.triggerHandler('change');
            }
        })
        .triggerHandler('change');

    $repoPlan.change(function() {
        updateHostingForm($hostingType, 'repo-form', $repoPlan, $repoForms);
    });

    $bugTrackerPlan.change(function() {
        var plan = $bugTrackerPlan.val() || 'default',
            bugTrackerType = $bugTrackerType.val(),
            planInfo = HOSTING_SERVICES[bugTrackerType].planInfo[plan];

        updateHostingForm($bugTrackerType, 'bug-tracker-form',
                          $bugTrackerPlan, $bugTrackerForms);

        $bugTrackerUsernameRow.setVisible(
            planInfo.bug_tracker_requires_username);
    });

    $hostingType
        .change(function() {
            var hostingType = $hostingType.val(),
                isCustom = (hostingType === 'custom'),
                isFake = (!isCustom &&
                          HOSTING_SERVICES[hostingType].fake === true);

            updateRepositoryType();

            if (isCustom) {
                $repoPlanRow.hide();
                $repoPathRow.show();
                $repoMirrorPathRow.show();
            } else {
                hideAllToolsFields();
                $repoPathRow.hide();
                $repoMirrorPathRow.hide();

                updatePlanEl($repoPlanRow, $repoPlan, hostingType);
            }

            $repoPlan.triggerHandler('change');

            if (isCustom ||
                !HOSTING_SERVICES[hostingType].supports_bug_trackers) {
                $bugTrackerUseHosting
                    .prop({
                        disabled: true,
                        checked: false
                    })
                    .triggerHandler('change');
            } else {
                $bugTrackerUseHosting.prop('disabled', false);
            }

            if (isCustom ||
                !HOSTING_SERVICES[hostingType].supports_ssh_key_association) {
                $associateSshKeyFieldset.hide();
                $associateSshKey.prop({
                    disabled: true,
                    checked: false
                });
            } else {
                /*
                 * Always use the original state of the checkbox (i.e. the
                 * state on page load)
                 */
                $associateSshKey.prop('disabled', associateSshKeyDisabled);
                $associateSshKeyFieldset.show();
            }

            $hostingURLRow.setVisible(
                !isCustom && HOSTING_SERVICES[hostingType].self_hosted);

            if (isFake) {
                $powerPackAdvert
                    .find('.power-pack-advert-hosting-type')
                    .text($hostingType.find(':selected').text());
            }

            $bugTrackerTypeRow.setVisible(!isFake);
            $repoPlanRow.setVisible(!isFake);
            $hostingAccountRow.setVisible(!isFake);
            $hostingAccountUserRow.setVisible(!isFake);
            $hostingAccountPassRow.setVisible(!isFake);
            $toolRow.setVisible(!isFake);

            $powerPackAdvert.setVisible(isFake);
            $submitButtons.prop('disabled', isFake);
        })
        .triggerHandler('change');

    $([$hostingType[0], $hostingURL[0]])
        .change(function() {
            var hostingType = $hostingType.val(),
                hostingInfo,
                accounts,
                foundSelected,
                selectedAccount,
                selectedURL,
                account,
                opt,
                i;

            if (hostingType !== 'custom') {
                hostingInfo = HOSTING_SERVICES[hostingType];
                accounts = hostingInfo.accounts;
                foundSelected = false;

                /* Rebuild the list of accounts. */
                selectedAccount = parseInt($hostingAccount.val(), 10);
                selectedURL = $hostingURL.val() || null;
                $hostingAccount.find('option[value!=""]').remove();

                if (hostingInfo.needs_two_factor_auth_code) {
                    /*
                     * The first one will be selected automatically, which
                     * we want. Don't select any below.
                     */
                    foundSelected = true;
                }

                for (i = 0; i < accounts.length; i++) {
                    account = accounts[i];

                    if (account.hosting_url === selectedURL) {
                        opt = $('<option/>')
                            .val(account.pk)
                            .text(account.username)
                            .data('account', account)
                            .appendTo($hostingAccount);

                        if (account.pk === selectedAccount || !foundSelected) {
                            opt.prop('selected', true);
                            foundSelected = true;
                            $hostingAccount.triggerHandler('change');
                        }
                    }
                }
            }
        });

    $([$hostingType[0], $hostingAccount[0]])
        .change(function() {
            var hostingType = $hostingType.val(),
                hostingInfo,
                selectedIndex,
                account,
                $selectedOption;

            $hostingAccountRelink.hide();
            $hostingAccountTwoFactorAuthCodeRow.hide();

            if (hostingType === 'custom') {
                $hostingAccountRow.hide();
                $hostingURLRow.hide();
                $repoPlanRow.hide();
                $hostingAccountUserRow.hide();
                $hostingAccountPassRow.hide();
            } else {
                hostingInfo = HOSTING_SERVICES[hostingType];

                if (hostingInfo.fake !== true) {
                    $hostingAccountRow.show();

                    if (hostingInfo.self_hosted) {
                        $hostingURLRow.show();
                    }

                    if ($hostingAccount.val() === '') {
                        $hostingAccountUserRow.show();

                        $hostingAccountPassRow.setVisible(
                            hostingInfo.needs_authorization);

                        if (hostingInfo.needs_two_factor_auth_code) {
                            $hostingAccountTwoFactorAuthCodeRow.show();
                        }
                    } else {
                        selectedIndex = $hostingAccount[0].selectedIndex;
                        $selectedOption = $($hostingAccount[0]
                            .options[selectedIndex]);
                        account = $selectedOption.data('account');

                        $hostingAccountUserRow.hide();

                        if (account.is_authorized) {
                            $hostingAccountPassRow.hide();
                        } else {
                            $hostingAccountPassRow.show();
                            $hostingAccountRelink.show();
                        }
                    }
                }
            }
        })
        .triggerHandler('change');

    $tool
        .change(function() {
            if ($hostingType.val() === 'custom') {
                updateFormDisplay('tool', TOOLS_INFO);
            } else {
                hideAllToolsFields();
            }
        })
        .triggerHandler('change');

    $bugTrackerType
        .change(function() {
            var bugTrackerType = $bugTrackerType.val();

            $bugTrackerForms.hide();

            if (bugTrackerType === 'custom' || bugTrackerType === 'none') {
                $bugTrackerHostingURLRow.hide();
                $bugTrackerPlanRow.hide();
                $bugTrackerUsernameRow.hide();
            }

            if (bugTrackerType === 'custom') {
                $bugTrackerURLRow.show();
            } else if (bugTrackerType === 'none') {
                $bugTrackerURLRow.hide();
            } else {
                $bugTrackerURLRow.hide();
                updatePlanEl($bugTrackerPlanRow, $bugTrackerPlan,
                             bugTrackerType);

                $bugTrackerHostingURLRow.setVisible(
                    HOSTING_SERVICES[bugTrackerType].self_hosted);
            }
        })
        .triggerHandler('change');

    $publicAccess
        .change(function() {
            var visible = !this.checked;
            $('#row-users').setVisible(visible);
            $('#row-review_groups').setVisible(visible);
        })
        .triggerHandler('change');

    $('#show-ssh-key-link').toggle(function() {
        $(this).text(gettext('Hide SSH Public Key'));
        $publicKeyPopup.show();
        return false;
    }, function() {
        $(this).text(gettext('Show SSH Public Key'));
        $publicKeyPopup.hide();
        return false;
    });

});
<commit_msg>Fix display of the "Repository Plan" field.<commit_after>var prevTypes = {},
    origRepoTypes = [],
    powerPackTemplate = [
        '
', gettext('Power Pack Required'), '
',
        '
',
        gettext(' support is available with Power Pack, an extension which also offers powerful reports, document review, and more.'),
        '
'
    ].join('');

function updateFormDisplay(id, tools_info) {
    var type = $('#id_' + id).val(),
        oldInfo = tools_info[prevTypes[id]],
        newInfo = tools_info[type],
        text,
        field,
        i;

    for (i = 0; i < oldInfo.fields.length; i++) {
        $('#row-' + oldInfo.fields[i]).hide();
    }

    for (field in oldInfo.help_text) {
        $('#row-' + field).find('p.help')
            .remove();
    }

    for (i = 0; i < newInfo.fields.length; i++) {
        $('#row-' + newInfo.fields[i]).show();
    }

    for (field in newInfo.help_text) {
        if (newInfo.help_text.hasOwnProperty(field)) {
            text = newInfo.help_text[field];

            $('
')
                .text(text)
                .appendTo($('#row-' + field));
        }
    }

    prevTypes[id] = type;
}

function updatePlanEl($row, $plan, serviceType, isFake) {
    var planTypes = HOSTING_SERVICES[serviceType].plans,
        selectedPlan = $plan.val(),
        planType,
        opt,
        i;

    $plan.empty();

    if (planTypes.length === 1 || isFake) {
        $row.hide();
    } else {
        for (i = 0; i < planTypes.length; i++) {
            planType = planTypes[i];
            opt = $('<option/>')
                .val(planType.type)
                .text(planType.label)
                .appendTo($plan);

            if (planType.type === selectedPlan) {
                opt.prop('selected', true);
            }
        }

        $row.show();
    }

    $plan.triggerHandler('change');
}

function updateHostingForm($hostingType, formPrefix, $plan, $forms) {
    var formID = formPrefix + '-' + $hostingType.val() + '-' +
                 ($plan.val() || 'default');

    $forms.hide();
    $('#' + formID).show();
}

function hideAllToolsFields() {
    var fields = TOOLS_INFO.none.fields,
        i;

    for (i = 0; i < fields.length; i++) {
        $('#row-' + fields[i]).hide();
    }
}

function updateRepositoryType() {
    var hostingType = $('#id_hosting_type').val(),
        newRepoTypes = (hostingType === 'custom'
                        ? []
                        : HOSTING_SERVICES[hostingType].scmtools),
        $repoTypes = $('#id_tool'),
        currentRepoType = $repoTypes.val();

    $repoTypes.empty();

    $(origRepoTypes).each(function (i) {
        var repoType = origRepoTypes[i];

        if (newRepoTypes.length === 0 ||
            newRepoTypes.indexOf(repoType.text) !== -1) {
            $('<option/>')
                .text(repoType.text)
                .val(repoType.value)
                .appendTo($repoTypes);

            if (repoType.value === currentRepoType) {
                $repoTypes.val(currentRepoType);
            }
        }
    });

    $repoTypes.triggerHandler('change');
}

$(document).ready(function() {
    var $hostingType = $('#id_hosting_type'),
        $hostingURLRow = $('#row-hosting_url'),
        $hostingURL = $('#id_hosting_url'),
        $hostingAccount = $('#id_hosting_account'),
        $hostingAccountRow = $('#row-hosting_account'),
        $hostingAccountUserRow = $('#row-hosting_account_username'),
        $hostingAccountPassRow = $('#row-hosting_account_password'),
        $hostingAccountTwoFactorAuthCodeRow =
            $('#row-hosting_account_two_factor_auth_code'),
        $hostingAccountRelink = $('
')
            .text(gettext('The authentication requirements for this account have changed. You will need to re-authenticate.'))
            .addClass('errornote')
            .hide()
            .appendTo($hostingAccountRow),
        $associateSshKeyFieldset =
            $('#row-associate_ssh_key').parents('fieldset'),
        $associateSshKey = $('#id_associate_ssh_key'),
        associateSshKeyDisabled = $associateSshKey.prop('disabled'),
        $bugTrackerUseHosting = $('#id_bug_tracker_use_hosting'),
        $bugTrackerType = $('#id_bug_tracker_type'),
        $bugTrackerHostingURLRow = $('#row-bug_tracker_hosting_url'),
        $bugTrackerTypeRow = $('#row-bug_tracker_type'),
        $bugTrackerPlan = $('#id_bug_tracker_plan'),
        $bugTrackerPlanRow = $('#row-bug_tracker_plan'),
        $bugTrackerURLRow = $('#row-bug_tracker'),
        $bugTrackerUsernameRow =
            $('#row-bug_tracker_hosting_account_username'),
        $repoPathRow = $('#row-path'),
        $repoMirrorPathRow = $('#row-mirror_path'),
        $repoPlanRow = $('#row-repository_plan'),
        $repoPlan = $('#id_repository_plan'),
        $publicAccess = $('#id_public'),
        $tool = $('#id_tool'),
        $toolRow = $('#row-tool'),
        $publicKeyPopup = $('#ssh-public-key-popup'),
        $repoForms = $('.repo-form'),
        $bugTrackerForms = $('.bug-tracker-form'),
        $submitButtons = $('input[type="submit"]'),
        $powerPackAdvert = $('
')
            .html(powerPackTemplate)
            .hide()
            .appendTo($hostingType.closest('fieldset'));

    prevTypes.bug_tracker_type = 'none';
    prevTypes.hosting_type = 'custom';
    prevTypes.tool = 'none';

    $tool.find('option').each(function() {
        var $repoType = $(this);

        origRepoTypes.push({
            value: $repoType.val(),
            text: $repoType.text()
        });
    });

    $bugTrackerUseHosting
        .change(function() {
            if (this.checked) {
                $bugTrackerTypeRow.hide();
                $bugTrackerPlanRow.hide();
                $bugTrackerUsernameRow.hide();
                $bugTrackerURLRow.hide();
                $bugTrackerForms.hide();
            } else {
                $bugTrackerTypeRow.show();
                $bugTrackerType.triggerHandler('change');
            }
        })
        .triggerHandler('change');

    $repoPlan.change(function() {
        updateHostingForm($hostingType, 'repo-form', $repoPlan, $repoForms);
    });

    $bugTrackerPlan.change(function() {
        var plan = $bugTrackerPlan.val() || 'default',
            bugTrackerType = $bugTrackerType.val(),
            planInfo = HOSTING_SERVICES[bugTrackerType].planInfo[plan];

        updateHostingForm($bugTrackerType, 'bug-tracker-form',
                          $bugTrackerPlan, $bugTrackerForms);

        $bugTrackerUsernameRow.setVisible(
            planInfo.bug_tracker_requires_username);
    });

    $hostingType
        .change(function() {
            var hostingType = $hostingType.val(),
                isCustom = (hostingType === 'custom'),
                isFake = (!isCustom &&
                          HOSTING_SERVICES[hostingType].fake === true);

            updateRepositoryType();

            if (isCustom) {
                $repoPlanRow.hide();
                $repoPathRow.show();
                $repoMirrorPathRow.show();
            } else {
                hideAllToolsFields();
                $repoPathRow.hide();
                $repoMirrorPathRow.hide();

                updatePlanEl($repoPlanRow, $repoPlan, hostingType, isFake);
            }

            $repoPlan.triggerHandler('change');

            if (isCustom ||
                !HOSTING_SERVICES[hostingType].supports_bug_trackers) {
                $bugTrackerUseHosting
                    .prop({
                        disabled: true,
                        checked: false
                    })
                    .triggerHandler('change');
            } else {
                $bugTrackerUseHosting.prop('disabled', false);
            }

            if (isCustom ||
                !HOSTING_SERVICES[hostingType].supports_ssh_key_association) {
                $associateSshKeyFieldset.hide();
                $associateSshKey.prop({
                    disabled: true,
                    checked: false
                });
            } else {
                /*
                 * Always use the original state of the checkbox (i.e. the
                 * state on page load)
                 */
                $associateSshKey.prop('disabled', associateSshKeyDisabled);
                $associateSshKeyFieldset.show();
            }

            $hostingURLRow.setVisible(
                !isCustom && HOSTING_SERVICES[hostingType].self_hosted);

            if (isFake) {
                $powerPackAdvert
                    .find('.power-pack-advert-hosting-type')
                    .text($hostingType.find(':selected').text());
            }

            $bugTrackerTypeRow.setVisible(!isFake);
            $hostingAccountRow.setVisible(!isFake);
            $hostingAccountUserRow.setVisible(!isFake);
            $hostingAccountPassRow.setVisible(!isFake);
            $toolRow.setVisible(!isFake);

            $powerPackAdvert.setVisible(isFake);
            $submitButtons.prop('disabled', isFake);
        })
        .triggerHandler('change');

    $([$hostingType[0], $hostingURL[0]])
        .change(function() {
            var hostingType = $hostingType.val(),
                hostingInfo,
                accounts,
                foundSelected,
                selectedAccount,
                selectedURL,
                account,
                opt,
                i;

            if (hostingType !== 'custom') {
                hostingInfo = HOSTING_SERVICES[hostingType];
                accounts = hostingInfo.accounts;
                foundSelected = false;

                /* Rebuild the list of accounts. */
                selectedAccount = parseInt($hostingAccount.val(), 10);
                selectedURL = $hostingURL.val() || null;
                $hostingAccount.find('option[value!=""]').remove();

                if (hostingInfo.needs_two_factor_auth_code) {
                    /*
                     * The first one will be selected automatically, which
                     * we want. Don't select any below.
                     */
                    foundSelected = true;
                }

                for (i = 0; i < accounts.length; i++) {
                    account = accounts[i];

                    if (account.hosting_url === selectedURL) {
                        opt = $('<option/>')
                            .val(account.pk)
                            .text(account.username)
                            .data('account', account)
                            .appendTo($hostingAccount);

                        if (account.pk === selectedAccount || !foundSelected) {
                            opt.prop('selected', true);
                            foundSelected = true;
                            $hostingAccount.triggerHandler('change');
                        }
                    }
                }
            }
        });

    $([$hostingType[0], $hostingAccount[0]])
        .change(function() {
            var hostingType = $hostingType.val(),
                hostingInfo,
                selectedIndex,
                account,
                $selectedOption;

            $hostingAccountRelink.hide();
            $hostingAccountTwoFactorAuthCodeRow.hide();

            if (hostingType === 'custom') {
                $hostingAccountRow.hide();
                $hostingURLRow.hide();
                $repoPlanRow.hide();
                $hostingAccountUserRow.hide();
                $hostingAccountPassRow.hide();
            } else {
                hostingInfo = HOSTING_SERVICES[hostingType];

                if (hostingInfo.fake !== true) {
                    $hostingAccountRow.show();

                    if (hostingInfo.self_hosted) {
                        $hostingURLRow.show();
                    }

                    if ($hostingAccount.val() === '') {
                        $hostingAccountUserRow.show();

                        $hostingAccountPassRow.setVisible(
                            hostingInfo.needs_authorization);

                        if (hostingInfo.needs_two_factor_auth_code) {
                            $hostingAccountTwoFactorAuthCodeRow.show();
                        }
                    } else {
                        selectedIndex = $hostingAccount[0].selectedIndex;
                        $selectedOption = $($hostingAccount[0]
                            .options[selectedIndex]);
                        account = $selectedOption.data('account');

                        $hostingAccountUserRow.hide();

                        if (account.is_authorized) {
                            $hostingAccountPassRow.hide();
                        } else {
                            $hostingAccountPassRow.show();
                            $hostingAccountRelink.show();
                        }
                    }
                }
            }
        })
        .triggerHandler('change');

    $tool
        .change(function() {
            if ($hostingType.val() === 'custom') {
                updateFormDisplay('tool', TOOLS_INFO);
            } else {
                hideAllToolsFields();
            }
        })
        .triggerHandler('change');

    $bugTrackerType
        .change(function() {
            var bugTrackerType = $bugTrackerType.val();

            $bugTrackerForms.hide();

            if (bugTrackerType === 'custom' || bugTrackerType === 'none') {
                $bugTrackerHostingURLRow.hide();
                $bugTrackerPlanRow.hide();
                $bugTrackerUsernameRow.hide();
            }

            if (bugTrackerType === 'custom') {
                $bugTrackerURLRow.show();
            } else if (bugTrackerType === 'none') {
                $bugTrackerURLRow.hide();
            } else {
                $bugTrackerURLRow.hide();
                updatePlanEl($bugTrackerPlanRow, $bugTrackerPlan,
                             bugTrackerType, false);

                $bugTrackerHostingURLRow.setVisible(
                    HOSTING_SERVICES[bugTrackerType].self_hosted);
            }
        })
        .triggerHandler('change');

    $publicAccess
        .change(function() {
            var visible = !this.checked;
            $('#row-users').setVisible(visible);
            $('#row-review_groups').setVisible(visible);
        })
        .triggerHandler('change');

    $('#show-ssh-key-link').toggle(function() {
        $(this).text(gettext('Hide SSH Public Key'));
        $publicKeyPopup.show();
        return false;
    }, function() {
        $(this).text(gettext('Show SSH Public Key'));
        $publicKeyPopup.hide();
        return false;
    });

});
<|endoftext|>


<commit_before>const { Base, Client } = require("eris");
const eris = Client;
const s = require("snekfetch");
const ErisEndpoints = require("eris/lib/rest/Endpoints");
const ModLog = require("./modlog/index");
const WorkerManager = require("./util/worker");
const resolveInvite = require("./util/resolveInvite");
const i18n = require("./i18n");
class LibWUtil extends eris {
    constructor(token, options) {
        super(token, options);
        this.modLog = new ModLog();
        this.workers = new WorkerManager();
        this.i18n = new i18n(this);
        global.i18n = this.i18n;
    }

    async canUseCommand(user, command) {
        if (command.category == 4 && this.isAdmin(user)) return true;
        if (command.category == 3 && (await this.isModerator(user))) return true;
        if (command.category == 2 && isO({ author: user })) return true;
        if (command.category == 1) return true;
        return false;
    }

    async _doPost(key = "", url = "", pld = { server_count: this.guilds.size }) {
        if (!key || !url || !pld) return;
        let data;
        try {
            data = await s.post(url)
                .set("Authorization", key)
                .send(pld);
        } catch (err) {
            throw {
                message: "Can't post, access text or body property for more info.",
                text: err.response.text,
                body: err.response.body
            };
        }
        if (data.status <= 200 && data.status < 300) throw {
            message: "Can't post, access text or body property for more info.",
            text: data.text,
            body: data.body
        };
        return;
    }
    passesRoleHierarchy(member1, member2) {
        if (member1.guild != member2.guild) throw new TypeError("Members aren't in the same guild");
        if (member1.guild.ownerID == member1.id) return true;
        if (member1.roles.length == 0) return false;
        if (member2.roles.length == 0) return true;
        let member1Roles = member1.roles.map(r => member1.guild.roles.get(r));
        let member2Roles = member2.roles.map(r => member2.guild.roles.get(r));
        member1Roles = member1Roles.sort((a, b) => b.position - a.position);
        member2Roles = member2Roles.sort((a, b) => b.position - a.position);
        return member1Roles[0].position > member2Roles[0].position;
    }
    async postStats() {
        if (!config.dbotskey || config.dbotskey == "") return;
        try {
            return await this._doPost(config.dbotskey, `https://bots.discord.pw/api/bots/${this.user.id}/stats`);
        } catch (err) {
            throw err;
        }

    }
    async postStats2() {
        if (!config.dbots2key || config.dbots2key == "") return;
        try {
            return await this._doPost(config.dbots2key, `https://discordbots.org/api/bots/${this.user.id}/stats`);
        } catch (err) {
            throw err;
        }
    }
    async isModerator(member, botOwnerIsMod = true) {
        if (this.isAdmin(member, botOwnerIsMod)) return true;
        let serverHasModRole = false;
        let modRole = null;
        let server = await db.table("configs").get(member.guild.id).run();
        if (server) {
            let role = member.guild.roles.find(r => r.name.toLowerCase() === server.modRole.toLowerCase());
            if (role) { serverHasModRole = true; modRole = role; }
        } else {
            let role = member.guild.roles.find(r => r.name.toLowerCase() === "tt.bot mod");
            if (role) { serverHasModRole = true; modRole = role; }
        }
        if (serverHasModRole) return member.roles.includes(modRole.id);
    }

    isAdmin(member, botOwnerIsAdmin = true) {
        if (botOwnerIsAdmin && isO({ author: member.user })) return true;
        if (member.permission.has("manageGuild")) return true;
        if (member.guild.ownerID == member.id) return true;
    }
    listBotColls() {
        return this.guilds.filter(g => ((g.members.filter(fn => fn.bot).length) / g.memberCount * 100) >= 75);
    }
    // eslint disable no-useless-escape
    escapeMarkdown(string) {
        let replacedItallicsAndBold = string.replace(/\*/g, "\\*");
        let replacedBackticks = replacedItallicsAndBold.replace(/\`/g, "\\`");
        let replacedUnderscores = replacedBackticks.replace(/\_/g, "\\_");
        let replacedBrackets = replacedUnderscores.replace(/\[/g, "\\[").replace(/\(/, "\\(").replace(/\]/g, "\\]").replace(/\)/g, "\\)");
        return replacedBrackets;
    }
    //actually Client.getRESTUser, but bypasses the need of options.restMode
    getUserWithoutRESTMode(userID) {
        return this.requestHandler.request("GET", ErisEndpoints.USER(userID), true).then((user) => new ErisO.User(user, this));
    }
    getBaseObject(id) {
        return new Base(id);
    }
    getTag(user) {
        return `${user.username}#${user.discriminator}`;
    }

    embedToText(embed) {
        let txt = [];
        if (embed.title) txt.push(`----------${embed.title} ${embed.url ? `- ${embed.url}` : ""}----------`);
        if (embed.author) txt.push(`${embed.title ? "(" : ""}${embed.author.name || "noname"} - ${embed.author.icon_url || "noiconuri"} - ${embed.author.url || "nouri"}${embed.title ? ")" : ""}`);
        if (embed.description) txt.push(embed.description);
        if (embed.fields) embed.fields.forEach(f => {
            txt.push("--------------------");
            txt.push(f.name);
            txt.push("");
            txt.push(f.value);
            txt.push("--------------------");
        });
        if (embed.thumbnail) txt.push("THUMB: " + embed.thumbnail.url);
        if (embed.image) txt.push(`IMAGE: ${embed.image.url}`);
        if (embed.video) txt.push(`VIDEO: ${embed.video.url}`);
        if (embed.provider) txt.push(`PROVIDER: ${embed.provider.name} ${embed.provider.url}`);
        if (embed.footer) txt.push(`----------${embed.footer.text || "notext"} - ${embed.footer.icon_url || "noiconuri"}----------`);
        return txt.join("\n");
    }
    parseMsg(string, m, g) {
        const replacers = {
            "{g.name}": g.name,
            "{g.id}": g.id,
            "{g.channels}": g.channels.size,
            "{g.members}": g.members.size,
            "{u.mention}": `<@!${m.user.id}>`,
            "{u.name}": m.username,
            "{u.discrim}": m.discriminator,
            "{u.id}": m.user.id,
            "{u.tag}": bot.getTag(m),
        };
        const regex = new RegExp(Object.keys(replacers).map(t => t.replace(/\./g, "\\.")).join("|"), "gi");
        return string.replace(regex, m => replacers[m]);
    }

    waitForEvent(event, timeout, check) {
        //eslint-disable-next-line no-unused-vars
        let t;
        if (!check || typeof check !== "function") check = () => true;
        return new Promise((rs, rj) => {
            const listener = (...args) => {
                if (check && typeof check == "function" && check(...args) === true) {
                    dispose();
                    rs([...args]);
                    return;
                }
            };
            const dispose = () => {
                this.removeListener(event, listener);
            };

            if (timeout) t = setTimeout(() => {
                dispose();
                rj("timeout");
            }, timeout);
            this.on(event, listener);
        });
    }

    getInvite(inviteID, withCounts) {
        const parsed = resolveInvite(inviteID);
        return super.getInvite(parsed, withCounts);
    }
}
module.exports = LibWUtil;<commit_msg>A somewhat important commit Past this commit, you cannot ban an owner with a lower role than you<commit_after>const { Base, Client } = require("eris");
const eris = Client;
const s = require("snekfetch");
const ErisEndpoints = require("eris/lib/rest/Endpoints");
const ModLog = require("./modlog/index");
const WorkerManager = require("./util/worker");
const resolveInvite = require("./util/resolveInvite");
const i18n = require("./i18n");
class LibWUtil extends eris {
    constructor(token, options) {
        super(token, options);
        this.modLog = new ModLog();
        this.workers = new WorkerManager();
        this.i18n = new i18n(this);
        global.i18n = this.i18n;
    }

    async canUseCommand(user, command) {
        if (command.category == 4 && this.isAdmin(user)) return true;
        if (command.category == 3 && (await this.isModerator(user))) return true;
        if (command.category == 2 && isO({ author: user })) return true;
        if (command.category == 1) return true;
        return false;
    }

    async _doPost(key = "", url = "", pld = { server_count: this.guilds.size }) {
        if (!key || !url || !pld) return;
        let data;
        try {
            data = await s.post(url)
                .set("Authorization", key)
                .send(pld);
        } catch (err) {
            throw {
                message: "Can't post, access text or body property for more info.",
                text: err.response.text,
                body: err.response.body
            };
        }
        if (data.status <= 200 && data.status < 300) throw {
            message: "Can't post, access text or body property for more info.",
            text: data.text,
            body: data.body
        };
        return;
    }
    passesRoleHierarchy(member1, member2) {
        if (member1.guild != member2.guild) throw new TypeError("Members aren't in the same guild");
        if (member1.guild.ownerID == member1.id) return true;
        if (member1.guild.ownerID == member2.id) return false;
        if (member1.roles.length == 0) return false;
        if (member2.roles.length == 0) return true;
        let member1Roles = member1.roles.map(r => member1.guild.roles.get(r));
        let member2Roles = member2.roles.map(r => member2.guild.roles.get(r));
        member1Roles = member1Roles.sort((a, b) => b.position - a.position);
        member2Roles = member2Roles.sort((a, b) => b.position - a.position);
        return member1Roles[0].position > member2Roles[0].position;
    }
    async postStats() {
        if (!config.dbotskey || config.dbotskey == "") return;
        try {
            return await this._doPost(config.dbotskey, `https://bots.discord.pw/api/bots/${this.user.id}/stats`);
        } catch (err) {
            throw err;
        }

    }
    async postStats2() {
        if (!config.dbots2key || config.dbots2key == "") return;
        try {
            return await this._doPost(config.dbots2key, `https://discordbots.org/api/bots/${this.user.id}/stats`);
        } catch (err) {
            throw err;
        }
    }
    async isModerator(member, botOwnerIsMod = true) {
        if (this.isAdmin(member, botOwnerIsMod)) return true;
        let serverHasModRole = false;
        let modRole = null;
        let server = await db.table("configs").get(member.guild.id).run();
        if (server) {
            let role = member.guild.roles.find(r => r.name.toLowerCase() === server.modRole.toLowerCase());
            if (role) { serverHasModRole = true; modRole = role; }
        } else {
            let role = member.guild.roles.find(r => r.name.toLowerCase() === "tt.bot mod");
            if (role) { serverHasModRole = true; modRole = role; }
        }
        if (serverHasModRole) return member.roles.includes(modRole.id);
    }

    isAdmin(member, botOwnerIsAdmin = true) {
        if (botOwnerIsAdmin && isO({ author: member.user })) return true;
        if (member.permission.has("manageGuild")) return true;
        if (member.guild.ownerID == member.id) return true;
    }
    listBotColls() {
        return this.guilds.filter(g => ((g.members.filter(fn => fn.bot).length) / g.memberCount * 100) >= 75);
    }
    // eslint disable no-useless-escape
    escapeMarkdown(string) {
        let replacedItallicsAndBold = string.replace(/\*/g, "\\*");
        let replacedBackticks = replacedItallicsAndBold.replace(/\`/g, "\\`");
        let replacedUnderscores = replacedBackticks.replace(/\_/g, "\\_");
        let replacedBrackets = replacedUnderscores.replace(/\[/g, "\\[").replace(/\(/, "\\(").replace(/\]/g, "\\]").replace(/\)/g, "\\)");
        return replacedBrackets;
    }
    //actually Client.getRESTUser, but bypasses the need of options.restMode
    getUserWithoutRESTMode(userID) {
        return this.requestHandler.request("GET", ErisEndpoints.USER(userID), true).then((user) => new ErisO.User(user, this));
    }
    getBaseObject(id) {
        return new Base(id);
    }
    getTag(user) {
        return `${user.username}#${user.discriminator}`;
    }

    embedToText(embed) {
        let txt = [];
        if (embed.title) txt.push(`----------${embed.title} ${embed.url ? `- ${embed.url}` : ""}----------`);
        if (embed.author) txt.push(`${embed.title ? "(" : ""}${embed.author.name || "noname"} - ${embed.author.icon_url || "noiconuri"} - ${embed.author.url || "nouri"}${embed.title ? ")" : ""}`);
        if (embed.description) txt.push(embed.description);
        if (embed.fields) embed.fields.forEach(f => {
            txt.push("--------------------");
            txt.push(f.name);
            txt.push("");
            txt.push(f.value);
            txt.push("--------------------");
        });
        if (embed.thumbnail) txt.push("THUMB: " + embed.thumbnail.url);
        if (embed.image) txt.push(`IMAGE: ${embed.image.url}`);
        if (embed.video) txt.push(`VIDEO: ${embed.video.url}`);
        if (embed.provider) txt.push(`PROVIDER: ${embed.provider.name} ${embed.provider.url}`);
        if (embed.footer) txt.push(`----------${embed.footer.text || "notext"} - ${embed.footer.icon_url || "noiconuri"}----------`);
        return txt.join("\n");
    }
    parseMsg(string, m, g) {
        const replacers = {
            "{g.name}": g.name,
            "{g.id}": g.id,
            "{g.channels}": g.channels.size,
            "{g.members}": g.members.size,
            "{u.mention}": `<@!${m.user.id}>`,
            "{u.name}": m.username,
            "{u.discrim}": m.discriminator,
            "{u.id}": m.user.id,
            "{u.tag}": bot.getTag(m),
        };
        const regex = new RegExp(Object.keys(replacers).map(t => t.replace(/\./g, "\\.")).join("|"), "gi");
        return string.replace(regex, m => replacers[m]);
    }

    waitForEvent(event, timeout, check) {
        //eslint-disable-next-line no-unused-vars
        let t;
        if (!check || typeof check !== "function") check = () => true;
        return new Promise((rs, rj) => {
            const listener = (...args) => {
                if (check && typeof check == "function" && check(...args) === true) {
                    dispose();
                    rs([...args]);
                    return;
                }
            };
            const dispose = () => {
                this.removeListener(event, listener);
            };

            if (timeout) t = setTimeout(() => {
                dispose();
                rj("timeout");
            }, timeout);
            this.on(event, listener);
        });
    }

    getInvite(inviteID, withCounts) {
        const parsed = resolveInvite(inviteID);
        return super.getInvite(parsed, withCounts);
    }
}
module.exports = LibWUtil;<|endoftext|>