<commit_before>(function(scope) {
    'use strict';

    var Scope = scope.window ? window : global;

    if (typeof module === 'object' && module.exports)
        module.exports = new UtilProto();
    else if (!Scope.Util)
        Scope.Util = new UtilProto();

    function UtilProto() {
        var Util = this;

        /**
         * function do save exec of function
         * @param pCallBack
         * @param pArg1
         * ...
         * @param pArgN
         */
        this.exec                       = function(callback) {
            var ret,
                args    = Util.slice(arguments, 1);

            if (Util.isFunction(callback))
                ret     = callback.apply(null, args);

            return ret;
        };

        this.type                   = new TypeProto();

        function TypeProto() {
            /**
             * get type of variable
             *
             * @param variable
             */
            function type(variable) {
                var regExp      = new RegExp('\\s([a-zA-Z]+)'),
                    str         = {}.toString.call(variable),
                    typeBig     = str.match(regExp)[1],
                    result      = typeBig.toLowerCase();

                return result;
            }

            /**
             * functions check is variable is array
             * @param variable
             */
            type.array          = function(variable) {
                var result;

                if (Array.isArray)
                    result = Array.isArray(variable) ;
                else
                    result = type(variable) === 'array';

                return result;
            };

            /**
             * functions check is variable is arrayBuffer
             * @param variable
             */
            type.arrayBuffer    = function(variable) {
                return type(variable) === 'arraybuffer';
            };

            /**
             * functions check is variable is boolean
             * @param variable
             */
            type.boolean               = function(variable) {
                return typeof variable === 'boolean';
            };

            /**
             * functions check is variable is function
             * @param variable
             */
            type.function               = function(variable) {
                return typeof variable === 'function';
            };

            /**
             * functions check is variable is number
             * @param variable
             */
            type.number               = function(variable) {
                return typeof variable === 'number';
            };

            /**
             * functions check is variable is object
             * @param variable
             */
            type.object               = function(variable) {
                var type    = Util.type(variable),
                    is      = type === 'object';

                return is;
            };

            /**
             * functions check is variable is string
             * @param variable
             */
            type.string               = function(variable) {
                return typeof variable === 'string';
            };

            /**
             * functions check is variable is string
             * @param variable
             */
            type.undefined            = function(variable) {
                return typeof variable === 'undefined';
            };

            /**
             * functions check is variable is File
             * @param variable
             */
            type.file                 = function(variable) {
                var FILE = '[object File]',
                    name, is;

                name    = Util.exec.ifExist(variable, 'toString');

                is      = name === FILE;

                return is;
            };

            return type;
        }

        /**
         * function makes new array based on first
         *
         * @param array
         */
        this.slice                  = function(array, count) {
            var ret;

            if (array)
                ret = [].slice.call(array, count);

            return ret;
        };

        /**
         * function render template with view
         * @templ
         * @view
         */
        this.render                  = function(templ, view) {
            var ret,
                NOT_ESCAPE  = true,
                SPACES      = '\\s*',
                symbols     = ['{{' + SPACES, SPACES + '}}'];

            ret = Util.ownRender(templ, view, symbols, NOT_ESCAPE);

            return ret;
        };

        /**
         * function render template with view and own symbols
         * @templ
         * @view
         * @symbols
         */
        this.ownRender                  = function(templ, view, symbols, notEscape) {
            var str, param, expr,
                ret         = templ,
                firstChar,
                secondChar;

            firstChar   = symbols[0];
            secondChar  = symbols[1]  || firstChar;

            for (param in view) {
                str     = view[param];
                str     = Util.exec(str) || str;
                expr    = firstChar + param + secondChar;
                ret     = Util.replaceStr(ret, expr, str, notEscape);
            }

            expr        = firstChar + '.*' + secondChar;
            ret         = Util.replaceStr(ret, expr, '', notEscape);

            return ret;
        };

        /**
         * function replase pFrom to pTo in pStr
         * @param str
         * @param from
         * @param to
         * @param notEscape
         */
        this.replaceStr             = function(str, from, to, notEscape) {
            var regExp,
                isStr   = Util.isString(str);

            if (isStr && from) {
                if (!notEscape)
                    from = Util.escapeRegExp(from);

                regExp  = new RegExp(from, 'g');
                str     = str.replace(regExp, to);
            }

           return str;
        };

        /**
         * function remove substring from string
         * @param str
         * @param substr
         */
        this.rmStr                  = function(str, substr, isOnce) {
            var replace,
                strArray    = [],
                isString    = Util.isString(str),
                isArray     = Util.isArray(substr),
                replaceStr  = function(str, strItem) {
                    var ret = str.replace(strItem, '');

                    return ret;
                };

            replace         = isOnce ? replaceStr : Util.replaceStr;

            if (isString && substr)  {
                if (isArray)
                    strArray = substr;
                else
                    strArray.push(substr);

                strArray.forEach(function(strItem) {
                    str = replace(str, strItem, '');
                });
            }

            return str;
        };

        this.escapeRegExp = function(pStr) {
            var lRet    = pStr,
                isStr   = Util.isString(pStr);

            if (isStr)
                lRet = pStr.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');

            return lRet;
        };

        /**
         * function convert name: rm: '(, ), -, " "'
         *
         * @name
         * convert
         */
        this.convertName            = function(name) {
            var conv = name && name.toLowerCase();

            conv    = Util.rmStr(conv, ['(', ')']);
            conv    = Util.replaceStr(conv, ' ', '-');

            return conv;
        };
    }
})(this);
<commit_msg>fix(util) Util.isString -> Util.type.string<commit_after>(function(scope) {
    'use strict';

    var Scope = scope.window ? window : global;

    if (typeof module === 'object' && module.exports)
        module.exports = new UtilProto();
    else if (!Scope.Util)
        Scope.Util = new UtilProto();

    function UtilProto() {
        var Util = this;

        /**
         * function do save exec of function
         * @param pCallBack
         * @param pArg1
         * ...
         * @param pArgN
         */
        this.exec                       = function(callback) {
            var ret,
                args    = Util.slice(arguments, 1);

            if (Util.type.function(callback))
                ret     = callback.apply(null, args);

            return ret;
        };

        this.type                   = new TypeProto();

        function TypeProto() {
            /**
             * get type of variable
             *
             * @param variable
             */
            function type(variable) {
                var regExp      = new RegExp('\\s([a-zA-Z]+)'),
                    str         = {}.toString.call(variable),
                    typeBig     = str.match(regExp)[1],
                    result      = typeBig.toLowerCase();

                return result;
            }

            /**
             * functions check is variable is array
             * @param variable
             */
            type.array          = function(variable) {
                var result;

                if (Array.isArray)
                    result = Array.isArray(variable) ;
                else
                    result = type(variable) === 'array';

                return result;
            };

            /**
             * functions check is variable is arrayBuffer
             * @param variable
             */
            type.arrayBuffer    = function(variable) {
                return type(variable) === 'arraybuffer';
            };

            /**
             * functions check is variable is boolean
             * @param variable
             */
            type.boolean               = function(variable) {
                return typeof variable === 'boolean';
            };

            /**
             * functions check is variable is function
             * @param variable
             */
            type.function               = function(variable) {
                return typeof variable === 'function';
            };

            /**
             * functions check is variable is number
             * @param variable
             */
            type.number               = function(variable) {
                return typeof variable === 'number';
            };

            /**
             * functions check is variable is object
             * @param variable
             */
            type.object               = function(variable) {
                var type    = Util.type(variable),
                    is      = type === 'object';

                return is;
            };

            /**
             * functions check is variable is string
             * @param variable
             */
            type.string               = function(variable) {
                return typeof variable === 'string';
            };

            /**
             * functions check is variable is string
             * @param variable
             */
            type.undefined            = function(variable) {
                return typeof variable === 'undefined';
            };

            /**
             * functions check is variable is File
             * @param variable
             */
            type.file                 = function(variable) {
                var FILE = '[object File]',
                    name, is;

                name    = Util.exec.ifExist(variable, 'toString');

                is      = name === FILE;

                return is;
            };

            return type;
        }

        /**
         * function makes new array based on first
         *
         * @param array
         */
        this.slice                  = function(array, count) {
            var ret;

            if (array)
                ret = [].slice.call(array, count);

            return ret;
        };

        /**
         * function render template with view
         * @templ
         * @view
         */
        this.render                  = function(templ, view) {
            var ret,
                NOT_ESCAPE  = true,
                SPACES      = '\\s*',
                symbols     = ['{{' + SPACES, SPACES + '}}'];

            ret = Util.ownRender(templ, view, symbols, NOT_ESCAPE);

            return ret;
        };

        /**
         * function render template with view and own symbols
         * @templ
         * @view
         * @symbols
         */
        this.ownRender                  = function(templ, view, symbols, notEscape) {
            var str, param, expr,
                ret         = templ,
                firstChar,
                secondChar;

            firstChar   = symbols[0];
            secondChar  = symbols[1]  || firstChar;

            for (param in view) {
                str     = view[param];
                str     = Util.exec(str) || str;
                expr    = firstChar + param + secondChar;
                ret     = Util.replaceStr(ret, expr, str, notEscape);
            }

            expr        = firstChar + '.*' + secondChar;
            ret         = Util.replaceStr(ret, expr, '', notEscape);

            return ret;
        };

        /**
         * function replase pFrom to pTo in pStr
         * @param str
         * @param from
         * @param to
         * @param notEscape
         */
        this.replaceStr             = function(str, from, to, notEscape) {
            var regExp,
                isStr   = Util.type.string(str);

            if (isStr && from) {
                if (!notEscape)
                    from = Util.escapeRegExp(from);

                regExp  = new RegExp(from, 'g');
                str     = str.replace(regExp, to);
            }

           return str;
        };

        /**
         * function remove substring from string
         * @param str
         * @param substr
         */
        this.rmStr                  = function(str, substr, isOnce) {
            var replace,
                strArray    = [],
                isString    = Util.type.string(str),
                isArray     = Util.type.array(substr),
                replaceStr  = function(str, strItem) {
                    var ret = str.replace(strItem, '');

                    return ret;
                };

            replace         = isOnce ? replaceStr : Util.replaceStr;

            if (isString && substr)  {
                if (isArray)
                    strArray = substr;
                else
                    strArray.push(substr);

                strArray.forEach(function(strItem) {
                    str = replace(str, strItem, '');
                });
            }

            return str;
        };

        this.escapeRegExp = function(pStr) {
            var lRet    = pStr,
                isStr   = Util.type.string(pStr);

            if (isStr)
                lRet = pStr.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');

            return lRet;
        };

        /**
         * function convert name: rm: '(, ), -, " "'
         *
         * @name
         * convert
         */
        this.convertName            = function(name) {
            var conv = name && name.toLowerCase();

            conv    = Util.rmStr(conv, ['(', ')']);
            conv    = Util.replaceStr(conv, ' ', '-');

            return conv;
        };
    }
})(this);
<|endoftext|>


<commit_before>/* eslint no-console: 0 */
/* eslint no-confusing-arrow: 0 */
const ran = true; // set to true to exclude migration
const name = 'Add privacy access rights for users.';

const database = require('../src/utils/database');

const RoleModel = require('../src/services/role/model');
const { ConsentVersionModel } = require('../src/services/consent/model');

const run = async () => {
	database.connect();

	const userRoles = await RoleModel.find({ name: { $in: ['user', 'demo'] } }).exec();
	const addPermissions = ['PRIVACY_VIEW'];

	const chain = [];

	// update user roles/permissions
	chain.push(userRoles.map(userRole => Promise.all(addPermissions.map((permission) => {
		if (!userRole.permissions.includes(permission)) {
			console.log(`add permission ${permission} for userrole ${userRole.name}`);
			return RoleModel
				.findByIdAndUpdate(userRole._id,
					{ $push: { permissions: permission } })
				.exec();
		}
		console.log(`${permission} already exists for userRole ${userRole.name}`);
		return Promise.resolve();
	}))));

	// add chat information to consentversions
	const publishedAt = new Date('2019-05-13').getUTCDate();
	// use static id to not add this entry again on possible second run
	const exist = await ConsentVersionModel
		.findOne({ publishedAt, consentTypes: 'privacy' }).exec();
	if (!exist) {
		console.log('add sample consent version');
		chain.push(new ConsentVersionModel({
			title: 'Neue Chatfunktion',
			consentTypes: ['privacy'],
			consentText:
				`Die neue Funktion „Teams“ ist verfügbar.
Innerhalb der Teams könnt ihr zusätzlich zum Dateiaustausch,
Gruppenterminen und Gruppennews einen Chat hinzufügen und so teamweite Nachrichten versenden,
sofern der Admin deiner Schule die Nutzung der Chatfunktion grundsätzlich freigeschaltet hat.

Der Chat ist direkt am HPI gehostet, was bedeutet,
dass deine Daten jederzeit auf unseren Servern liegen und zu
keinem Zeitpunkt an Dritte weitergegeben werden.
Außerdem besteht eine verschlüsselte Netzverbindung zwischen dem
Server am HPI und dem Client (SSL-Verschlüsselung).

Bei Rückfragen kannst du dich jederzeit an Deine Schule oder an
info@schul-cloud.org wenden.
Weitere Hinweise zur Datenverarbeitung  findest
Du in der oben verlinkten Datenschutzerklärung deiner Schule.`,
			publishedAt,
		}).save());
	} else {
		console.log('consent version already added');
	}

	return Promise.all(chain);
};

module.exports = {
	ran,
	name,
	run,
};
<commit_msg>fix migrations script privacy<commit_after>/* eslint no-console: 0 */
/* eslint no-confusing-arrow: 0 */
const ran = true; // set to true to exclude migration
const name = 'Add privacy access rights for users.';

const database = require('../src/utils/database');

const RoleModel = require('../src/services/role/model');
const { ConsentVersionModel } = require('../src/services/consent/model');

const run = async () => {
	database.connect();

	const userRoles = await RoleModel.find({ name: { $in: ['user', 'demo'] } }).exec();
	const addPermissions = ['PRIVACY_VIEW'];

	const chain = [];

	// update user roles/permissions
	chain.push(userRoles.map(userRole => Promise.all(addPermissions.map((permission) => {
		if (!userRole.permissions.includes(permission)) {
			console.log(`add permission ${permission} for userrole ${userRole.name}`);
			return RoleModel
				.findByIdAndUpdate(userRole._id,
					{ $push: { permissions: permission } })
				.exec();
		}
		console.log(`${permission} already exists for userRole ${userRole.name}`);
		return Promise.resolve();
	}))));

	// add chat information to consentversions
	const publishedAt = new Date('2019-05-13');
	// use static id to not add this entry again on possible second run
	const exist = await ConsentVersionModel
		.findOne({ publishedAt, consentTypes: 'privacy' }).exec();
	if (!exist) {
		console.log('add consent version for chat');
		chain.push(new ConsentVersionModel({
			title: 'Neue Chatfunktion',
			consentTypes: ['privacy'],
			consentText:
				`Die neue Funktion „Teams“ ist verfügbar.
Innerhalb der Teams könnt ihr zusätzlich zum Dateiaustausch,
Gruppenterminen und Gruppennews einen Chat hinzufügen und so teamweite Nachrichten versenden,
sofern der Admin deiner Schule die Nutzung der Chatfunktion grundsätzlich freigeschaltet hat.

Der Chat ist direkt am HPI gehostet, was bedeutet,
dass deine Daten jederzeit auf unseren Servern liegen und zu
keinem Zeitpunkt an Dritte weitergegeben werden.
Außerdem besteht eine verschlüsselte Netzverbindung zwischen dem
Server am HPI und dem Client (SSL-Verschlüsselung).

Bei Rückfragen kannst du dich jederzeit an Deine Schule oder an
info@schul-cloud.org wenden.
Weitere Hinweise zur Datenverarbeitung  findest
Du in der oben verlinkten Datenschutzerklärung deiner Schule.`,
			publishedAt,
		}).save());
	} else {
		console.log('consent version already added');
	}

	return Promise.all(chain);
};

module.exports = {
	ran,
	name,
	run,
};
<|endoftext|>


<commit_before>define(['jquery','jquery-trap-input'], function ($) {
    // @ngInject
    var PinfDialog = function ($templateCache, $http, $q, $controller, $compile) {
        var currentDialog, focusedElement, closeDeffered = null;
        var self = this;

        function getDialogTemplate(templateUrl) {
            var dialogTemplate = $templateCache.get(templateUrl);

            if (!dialogTemplate) {
                return $http
                    .get(templateUrl)
                    .then(function (response) {
                        var templateResponse = response.data;
                        $templateCache.put(templateUrl, templateResponse);
                        return templateResponse;
                    })
            }
            else {
                var deferred = $q.defer();
                deferred.resolve(dialogTemplate);
                return deferred.promise;
            }
        }

        function documentKeyUp(e){
            if (e.keyCode == 27) {
                self.close();
            }
        }

        function createAndShowDialog(template) {
            var dialog = $(template);
            $('body').append(dialog);
            dialog.attr('aria-hidden', 'false');
            return dialog;
        }

        function bindHandlers(dialog) {
            dialog.find('button.dialog-close').click(close);
            dialog.click(close);
            dialog.find('.dialog-holder').click(function (e) {
                e.stopPropagation();
            })
            var doc = $(document);
            doc.bind('keyup', documentKeyUp);
        }

        /**
         * Opens new dialog.
         * @param scope
         * Scope of controller spawning dialog. This is important because dialog will have scope which is a child
         * of provided scope.
         *
         * @param settings
         * Setting object
         * controller : Function | String - controller that is going to be used in dialog. OPTIONAL
         * templateUrl : String - url to dialogs template
         * injectClose : Boolean - if this is true close() method will be injected to dialogs scope. OPTIONAL
         */
        this.open = function (scope, settings) {
            focusedElement = $(':focus');

            closeDeffered = $q.defer()

            getDialogTemplate(settings.templateUrl)
                .then(function (template) {
                    var dialog = createAndShowDialog(template);

                    dialog.find('.dialog-content').focus().attr('tabindex', '-1');
                    dialog.trap();

                    bindHandlers(dialog);
                    currentDialog = dialog;

                    var childScope = scope.$new(false);

                    if(settings.injectClose){
                        childScope.close = close
                    }

                    var controller = $controller(settings.controller || function() {}, {
                        $scope : childScope
                    });

                    $compile(dialog)(childScope)

                });

            return closeDeffered.promise;
        }

        /**
         * Closes currently opened dialog
         */
        this.close = function(result){
            var doc = $(document);

            currentDialog.untrap();
            currentDialog.attr('aria-hidden','true');

            closeDeffered.resolve(result);
            closeDeffered = null;

            currentDialog.remove();
            doc.unbind('keyup', documentKeyUp);
            currentDialog = null;

            focusedElement.focus();

        }

        var close = self.close.bind(self);
    }

    return PinfDialog;
});<commit_msg>Removing auto-close<commit_after>define(['jquery','jquery-trap-input'], function ($) {
    // @ngInject
    var PinfDialog = function ($templateCache, $http, $q, $controller, $compile) {
        var currentDialog, focusedElement, closeDeffered = null;
        var self = this;

        function getDialogTemplate(templateUrl) {
            var dialogTemplate = $templateCache.get(templateUrl);

            if (!dialogTemplate) {
                return $http
                    .get(templateUrl)
                    .then(function (response) {
                        var templateResponse = response.data;
                        $templateCache.put(templateUrl, templateResponse);
                        return templateResponse;
                    })
            }
            else {
                var deferred = $q.defer();
                deferred.resolve(dialogTemplate);
                return deferred.promise;
            }
        }

        function documentKeyUp(e){
            if (e.keyCode == 27) {
                self.close();
            }
        }

        function createAndShowDialog(template) {
            var dialog = $(template);
            $('body').append(dialog);
            dialog.attr('aria-hidden', 'false');
            return dialog;
        }

        function bindHandlers(dialog) {
            dialog.click(close);
            dialog.find('.dialog-holder').click(function (e) {
                e.stopPropagation();
            })
            var doc = $(document);
            doc.bind('keyup', documentKeyUp);
        }

        /**
         * Opens new dialog.
         * @param scope
         * Scope of controller spawning dialog. This is important because dialog will have scope which is a child
         * of provided scope.
         *
         * @param settings
         * Setting object
         * controller : Function | String - controller that is going to be used in dialog. OPTIONAL
         * templateUrl : String - url to dialogs template
         * injectClose : Boolean - if this is true close() method will be injected to dialogs scope. OPTIONAL
         */
        this.open = function (scope, settings) {
            focusedElement = $(':focus');

            closeDeffered = $q.defer()

            getDialogTemplate(settings.templateUrl)
                .then(function (template) {
                    var dialog = createAndShowDialog(template);

                    dialog.find('.dialog-content').focus().attr('tabindex', '-1');
                    dialog.trap();

                    bindHandlers(dialog);
                    currentDialog = dialog;

                    var childScope = scope.$new(false);

                    if(settings.injectClose){
                        childScope.close = close
                    }

                    var controller = $controller(settings.controller || function() {}, {
                        $scope : childScope
                    });

                    $compile(dialog)(childScope)

                });

            return closeDeffered.promise;
        }

        /**
         * Closes currently opened dialog
         */
        this.close = function(result){
            var doc = $(document);

            currentDialog.untrap();
            currentDialog.attr('aria-hidden','true');

            closeDeffered.resolve(result);
            closeDeffered = null;

            currentDialog.remove();
            doc.unbind('keyup', documentKeyUp);
            currentDialog = null;

            focusedElement.focus();

        }

        var close = self.close.bind(self);
    }

    return PinfDialog;
});<|endoftext|>


<commit_before>require('proof')(7, require('cadence')(prove))

function prove (async, assert) {
    var bin = require('../../reconfigure.bin'), io
    var http = require('http')
    var Semblance = require('semblance')
    var semblance = new Semblance
    var server = http.createServer(semblance.dispatch())
    var exec = require('child_process').exec
    var ip
    if (process.env.DOCKER_HOST) {
        ip = /^[^\d]+([\d.]+)/.exec(process.env.DOCKER_HOST)[1]
    } else {
        console.log(require('os').networkInterfaces())
        ip = require('os').networkInterfaces().eth0.filter(function (iface) {
            return iface.family == 'IPv4'
        })[0].address
    }

    async([function () {
        async(function () {
            exec('docker kill reconfigure-etcd', async())
        }, function () {
            exec('docker rm reconfigure-etcd', async())
        })
    }], function () {
        exec('docker run -d -p 4001:4001 -p 2380:2380 -p 2379:2379 \
             --name reconfigure-etcd quay.io/coreos/etcd \
             -name reconfigure-etcd \
             -advertise-client-urls http://' + ip + ':2379,http://' + ip + ':4001 \
             -listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 \
             -initial-advertise-peer-urls http://' + ip + ':2380 \
             -listen-peer-urls http://0.0.0.0:2380 \
             -initial-cluster-token etcd-cluster-1 \
             -initial-cluster reconfigure-etcd=http://' + ip + ':2380 \
             -initial-cluster-state new', async())
    }, function () {
        server.listen(4077, '127.0.0.1', async())
    }, function () {
        io = bin({}, ['serve', '--port=2390', '--etcdaddr=' + ip + ':2379'], {}, async())
    }, function () {
        assert(true, 'running')
        bin({}, ['register', '127.0.0.1:2390', 'http://127.0.0.1:4077'], {}, async())
    }, function (ret) {
        assert(ret.success, true, 'registered')
        bin({}, ['set', '127.0.0.1:2390', 'greeting', 'Hello World!'], {}, async())
    }, function () {
        bin({}, ['set', '127.0.0.1:2390', 'greeting2', 'Hello World!'], {}, async())
    }, function () {
        assert(semblance.shift().body.properties, { greeting: 'Hello World!'},
        'listener updated')
        bin({}, ['list', '127.0.0.1:2390'], {}, async())
    }, function (values) {
        assert((values.indexOf('greeting\tHello World!\n') != -1) &&
        (values.indexOf('greeting2\tHello World!\n') != -1), true, 'key set and retrieved')
       bin({}, ['register', '127.0.0.1:2390', 'blah:4001'], {}, async())
    }, function () {
       bin({}, ['register', '127.0.0.1:2390', 'blah:4001'], {}, async())
    }, function (ret) {
        assert(ret.extant, true, 'duplicant registry')
        bin({}, ['deregister', '127.0.0.1:2390', 'blah:4001'], {}, async())
    }, function (ret) {
        assert(ret.success, true, 'deregistered')
        bin({}, ['registered', '127.0.0.1:2390'], {}, async())
    }, function (ret) {
        assert(ret, 'http://127.0.0.1:4077', 'registry listed')
        io.events.emit('SIGINT')
        server.close()
    })
}
<commit_msg>Move cleanup to function.<commit_after>require('proof')(7, require('cadence')(prove))

function prove (async, assert) {
    var cadence = require('cadence')
    var bin = require('../../reconfigure.bin'), io
    var http = require('http')
    var Semblance = require('semblance')
    var semblance = new Semblance
    var server = http.createServer(semblance.dispatch())
    var exec = require('child_process').exec
    var ip
    if (process.env.DOCKER_HOST) {
        ip = /^[^\d]+([\d.]+)/.exec(process.env.DOCKER_HOST)[1]
    } else {
        console.log(require('os').networkInterfaces())
        ip = require('os').networkInterfaces().eth0.filter(function (iface) {
            return iface.family == 'IPv4'
        })[0].address
    }

    var dock = cadence(function (async) {
        async([function () {
            exec('docker kill reconfigure-etcd', async())
        }, /kill/, function (error) {
            console.log('errorrrrr')
        }], [function () {
            exec('docker rm reconfigure-etcd', async())
        }, /running/, function (error) {
            console.log('errorrrrr')
        }])
    })

    async([function () {
        dock(async())
    }], function () {
            exec('docker run -d -p 4001:4001 -p 2380:2380 -p 2379:2379 \
                 --name reconfigure-etcd quay.io/coreos/etcd \
                 -name reconfigure-etcd \
                 -advertise-client-urls http://' + ip + ':2379,http://' + ip + ':4001 \
                 -listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 \
                 -initial-advertise-peer-urls http://' + ip + ':2380 \
                 -listen-peer-urls http://0.0.0.0:2380 \
                 -initial-cluster-token etcd-cluster-1 \
                 -initial-cluster reconfigure-etcd=http://' + ip + ':2380 \
                 -initial-cluster-state new', async())
    }, function () {
        server.listen(4077, '127.0.0.1', async())
    }, function () {
        io = bin({}, ['serve', '--port=2390', '--etcdaddr=' + ip + ':2379'], {}, async())
    }, function () {
        assert(true, 'running')
        bin({}, ['register', '127.0.0.1:2390', 'http://127.0.0.1:4077'], {}, async())
    }, function (ret) {
        assert(ret.success, true, 'registered')
        bin({}, ['set', '127.0.0.1:2390', 'greeting', 'Hello World!'], {}, async())
    }, function () {
        bin({}, ['set', '127.0.0.1:2390', 'greeting2', 'Hello World!'], {}, async())
    }, function () {
        assert(semblance.shift().body.properties, { greeting: 'Hello World!'},
        'listener updated')
        bin({}, ['list', '127.0.0.1:2390'], {}, async())
    }, function (values) {
        assert((values.indexOf('greeting\tHello World!\n') != -1) &&
        (values.indexOf('greeting2\tHello World!\n') != -1), true, 'key set and retrieved')
       bin({}, ['register', '127.0.0.1:2390', 'blah:4001'], {}, async())
    }, function () {
       bin({}, ['register', '127.0.0.1:2390', 'blah:4001'], {}, async())
    }, function (ret) {
        assert(ret.extant, true, 'duplicant registry')
        bin({}, ['deregister', '127.0.0.1:2390', 'blah:4001'], {}, async())
    }, function (ret) {
        assert(ret.success, true, 'deregistered')
        bin({}, ['registered', '127.0.0.1:2390'], {}, async())
    }, function (ret) {
        assert(ret, 'http://127.0.0.1:4077', 'registry listed')
        io.events.emit('SIGINT')
        server.close()
    })
}
<|endoftext|>


<commit_before>// Task

var Task = Backbone.Model.extend({
	defaults: {
		text: "",
	},
}, {
	timeScales: [
		{ id: "this-week",  label: "kinda soon", range: 7 * 24 * 60 * 60 * 1000 },
		{ id: "today",      label: "REALLY soon", range: 24 * 60 * 60 * 1000 },
	],
});

var TaskCollection = Backbone.Collection.extend({
	model: Task,

	constructor: function (store) {
		store.applyToCollection(this);
		Backbone.Collection.apply(this, Array.prototype.slice.call(arguments, 1));
	},
});

// Comparison

var Comparison = Backbone.Model.extend({
	defaults: {
		greaterTaskId: "",
		lesserTaskId: "",
		invalidated: false,
	},

	comparator: "createdAt",

	initialize: function () {
		if (!this.has("createdAt")) {
			this.set("createdAt", new Date);
		}
	},

	invalidate: function () {
		this.save({
			invalidated: true,
			invalidatedAt: new Date,
		});
	},
});

var ComparisonCollection = Backbone.Collection.extend({
	model: Comparison,

	constructor: function (store) {
		store.applyToCollection(this);
		Backbone.Collection.apply(this, Array.prototype.slice.call(arguments, 1));
	},
});

// TaskForest

function TaskForest(tasks, comparisons) {
	this.taskComparator = _.bind(this.taskComparator, this);

	this.tasks = tasks;
	this.comparisons = comparisons;

	this.potentialNextTasks = new Backbone.Collection();
	this.nextTasks = new Backbone.Collection();
	this.restTasks = new Backbone.Collection();
	this.wfTasks = new Backbone.Collection();
	this.potentialNextTasks.pile = this.nextTasks.pile = this.restTasks.pile = this.wfTasks.pile = this;

	this._recalculate();

	this.listenTo(tasks, "add remove reset change:waitingFor", atBatchEnd(this._recalculate, this));
	this.listenTo(comparisons, "add remove reset sort change:invalidated", atBatchEnd(this._recalculate, this));

	// this.listenTo(this, "recalculate", this._debug);
}
_.extend(TaskForest.prototype, Backbone.Events, {
	randomComparisonTaskPair: function () {
		if (this.potentialNextTasks.length <= 2) {
			return this.potentialNextTasks.slice(0, 2);
		}

		var self = this;

		return this.potentialNextTasks.chain().map(function (task) {
			return {
				task: task,
				weight: Math.random() / self._size[task.cid],
			};
		}).sortBy("weight").reverse().pluck("task").value().slice(0, 2);
	},

	taskComparator: function (task1, task2) {
		var level1 = this._level(task1.cid);
		var level2 = this._level(task2.cid);

		if (level1 === undefined && level2 === undefined) {
			return 0;
		} else if (level1 === undefined) {
			return 1;
		} else if (level2 === undefined) {
			return -1;
		}
		return level1 - level2;
	},

	_updateCollections: function () {
		var potentialNexts, nexts = {}, rests = {}, wfs = {}; // { cid: task, ... }
		var byLevel = []; // [{ cid: task, ... }, ...]
		var taskLevel = {}; // { cid: level, ... }

		function setLevel(task, level) {
			if (!(task.cid in taskLevel) || taskLevel[task.cid] < level) {
				if ((task.cid in taskLevel) && taskLevel[task.cid] < level) {
					var oldLevel = taskLevel[task.cid];
					delete byLevel[oldLevel][task.cid];
				}
				taskLevel[task.cid] = level;
				byLevel[level] || (byLevel[level] = {});
				byLevel[level][task.cid] = task;
			}
		}

		this._walk(null, function (task, level) {
			if (task.has("waitingFor")) {
				wfs[task.cid] = task;
				return level;
			} else {
				setLevel(task, level);
				return level + 1;
			}
		}, 0);

		potentialNexts = byLevel[0] || {};

		for (var level = 0, next = true; byLevel[level]; level++) {
			var tasks = _.values(byLevel[level]);
			if (next && tasks.length === 1) {
				nexts[tasks[0].cid] = tasks[0];
				next = false; // limit to 1 next task for now
			} else {
				next = false;
				_.each(tasks, function (task) {
					rests[task.cid] = task;
				}, this);
			}
		}

		this.potentialNextTasks.reset(_.chain(potentialNexts).values().sortBy(this.taskComparator).value());
		this.nextTasks.reset(_.chain(nexts).values().sortBy(this.taskComparator).value());
		this.restTasks.reset(_.chain(rests).values().sortBy(this.taskComparator).value());
		this.wfTasks.reset(_.chain(wfs).values().sortBy(this.taskComparator).value());
	},

	_addTask: function (task) {
		this._children[task.cid] = [];
		this._parents[task.cid] = [];
		this._size[task.cid] = 1;
		this._roots.push(task.cid);
	},

	_addComparison: function (comparison) {
		if (comparison.get("invalidated")) {
			return;
		}

		var greaterTask = this.tasks.get(comparison.get("greaterTaskId"));
		var lesserTask = this.tasks.get(comparison.get("lesserTaskId"));
		if (!greaterTask || !lesserTask) {
			return;
		}

		if (_.contains(this._allParents(greaterTask.cid), lesserTask.cid)) {
			console.log("ignoring comparison that would create a cycle", greaterTask.get("text"), ">", lesserTask.get("text"));
			return;
		}

		this._addChild(greaterTask.cid, lesserTask.cid);
		removeFromSet(this._roots, lesserTask.cid);
	},

	_recalculate: function () {
		this._children = {}; // cid -> [cid, ...]
		this._parents = {}; // cid -> [cid, ...]
		this._size = {}; // cid -> int
		this._roots = []; // [cid, ...]

		this.tasks.each(this._addTask, this);
		this.comparisons.each(this._addComparison, this);

		this._updateCollections();

		this.trigger("recalculate");
	},

	_debug: function () {
		console.group();
		this._walk(null, _.bind(function (task, indent) {
			console.log(indent + task.get("text") + (task.has("waitingFor") ? " wf" : ""));
			return indent + "  ";
		}, this), "");
		console.groupEnd();
	},

	_addChild: function (parentCid, childCid) {
		addToSet(this._children[parentCid], childCid);
		addToSet(this._parents[childCid], parentCid);

		// XXX: not accurate because may have already been a child
		this._size[parentCid] += this._size[childCid];
		var parentParents = this._allParents(parentCid);
		_.each(parentParents, function (cid) {
			this._size[cid] += this._size[childCid];
		}, this);
	},

	_allParents: function (cid) {
		var self = this, all = [];
		walk(cid);
		return all;

		function walk(currentCid) {
			var parentCids = self._parents[currentCid] || [];
			all.push.apply(all, parentCids);
			_.each(parentCids, walk);
		}
	},

	// find the longest path to the root & return that depth
	_level: function (cid) {
		var self = this;
		return getLevel(cid);

		function getLevel(currentCid) {
			var parentCids = self._parents[currentCid] || [];
			if (parentCids.length === 0) {
				return 0;
			}

			return _.max(parentCids.map(getLevel)) + 1;
		}
	},

	_walk: function (task, iter, data, filter) {
		// get the list of children in case it's mutated
		var children;
		if (task) {
			if (!this._children[task.cid]) {
				console.error("during walk, children of task weren't found", task);
				return;
			}
			children = this._children[task.cid];
		} else {
			children = this._roots;
		}

		// invoke the iterator
		if (task && (!filter || filter(task))) {
			data = iter(task, data);
		}

		// recurse
		_.each(children, function (childCid) {
			var child = this.tasks.get(childCid);
			if (child) {
				this._walk(child, iter, data, filter);
			} else {
				console.error("during walk, task wasn't found", childCid);
			}
		}, this);
	},
});

// Pile

var Pile = Backbone.Model.extend({
	defaults: {
		name: "",
	},

	initialize: function () {
		if (this.has("id")) {
			this._makeCollections();
		} else {
			this.listenToOnce(this, "change:id", this._makeCollections);
		}
	},

	_makeCollections: function () {
		this.tasks = new TaskCollection(this.collection.store.makeStore("piles-" + this.id + "-tasks"));
		this.comparisons = new ComparisonCollection(this.collection.store.makeStore("piles-" + this.id + "-comparisons"));
		this.taskForest = new TaskForest(this.tasks, this.comparisons);

		this.tasks.pile = this.comparisons.pile = this;
	},

	toJSON: function () {
		var o = Backbone.Model.prototype.toJSON.apply(this, arguments);
		o.tasks = this.tasks.toJSON();
		o.comparisons = this.comparisons.toJSON();
		return o;
	},
});

var PileCollection = Backbone.Collection.extend({
	model: Pile,

	constructor: function (store) {
		store.applyToCollection(this);
		Backbone.Collection.apply(this, Array.prototype.slice.call(arguments, 1));
	},

	// per Backbone.js convention, that's an object, not a string
	clonePileFromJSON: function (json) {
		var d = new $.Deferred;

		var taskJSONs = json.tasks, comparisonJSONs = json.comparisons;
		var oldIds = _.pluck(taskJSONs, "id");
		delete json.id;
		delete json.tasks;
		delete json.comparisons;

		var pile = this.add(json);
		pile.save().then(saveTasks, bail("Could not save pile"));

		function saveTasks() {
			pile.tasks.reset(_.map(taskJSONs, function (taskJSON) {
				delete taskJSON.id;
				return taskJSON;
			}));
			$.when.apply($, pile.tasks.invoke("save"))
				.then(saveComparisons, bail("failed to save all the tasks"));
		}

		function saveComparisons() {
			var newIds = pile.tasks.pluck("id");
			var idMap = _.object(oldIds, newIds);

			pile.comparisons.reset(_.reduce(comparisonJSONs, function (jsons, comparisonJSON) {
				delete comparisonJSON.id;
				comparisonJSON.lesserTaskId = idMap[comparisonJSON.lesserTaskId];
				comparisonJSON.greaterTaskId = idMap[comparisonJSON.greaterTaskId];
				if (comparisonJSON.lesserTaskId && comparisonJSON.greaterTaskId) {
					jsons.push(comparisonJSON);
				}
				return jsons;
			}, []));
			console.log("[import] pruned " + (comparisonJSONs.length - pile.comparisons.length) + " of " + comparisonJSONs.length + " comparisons");
			$.when.apply($, pile.comparisons.invoke("save"))
				.then(done, bail("failed to save all the comparisons"));
		}

		function done() {
			d.resolve(pile);
		}

		function bail(reason) {
			return function () {
				d.reject(reason);
			};
		}

		return d.promise();
	},
});
<commit_msg>break sort ties with # children<commit_after>// Task

var Task = Backbone.Model.extend({
	defaults: {
		text: "",
	},
}, {
	timeScales: [
		{ id: "this-week",  label: "kinda soon", range: 7 * 24 * 60 * 60 * 1000 },
		{ id: "today",      label: "REALLY soon", range: 24 * 60 * 60 * 1000 },
	],
});

var TaskCollection = Backbone.Collection.extend({
	model: Task,

	constructor: function (store) {
		store.applyToCollection(this);
		Backbone.Collection.apply(this, Array.prototype.slice.call(arguments, 1));
	},
});

// Comparison

var Comparison = Backbone.Model.extend({
	defaults: {
		greaterTaskId: "",
		lesserTaskId: "",
		invalidated: false,
	},

	comparator: "createdAt",

	initialize: function () {
		if (!this.has("createdAt")) {
			this.set("createdAt", new Date);
		}
	},

	invalidate: function () {
		this.save({
			invalidated: true,
			invalidatedAt: new Date,
		});
	},
});

var ComparisonCollection = Backbone.Collection.extend({
	model: Comparison,

	constructor: function (store) {
		store.applyToCollection(this);
		Backbone.Collection.apply(this, Array.prototype.slice.call(arguments, 1));
	},
});

// TaskForest

function TaskForest(tasks, comparisons) {
	this.taskComparator = _.bind(this.taskComparator, this);

	this.tasks = tasks;
	this.comparisons = comparisons;

	this.potentialNextTasks = new Backbone.Collection();
	this.nextTasks = new Backbone.Collection();
	this.restTasks = new Backbone.Collection();
	this.wfTasks = new Backbone.Collection();
	this.potentialNextTasks.pile = this.nextTasks.pile = this.restTasks.pile = this.wfTasks.pile = this;

	this._recalculate();

	this.listenTo(tasks, "add remove reset change:waitingFor", atBatchEnd(this._recalculate, this));
	this.listenTo(comparisons, "add remove reset sort change:invalidated", atBatchEnd(this._recalculate, this));

	// this.listenTo(this, "recalculate", this._debug);
}
_.extend(TaskForest.prototype, Backbone.Events, {
	randomComparisonTaskPair: function () {
		if (this.potentialNextTasks.length <= 2) {
			return this.potentialNextTasks.slice(0, 2);
		}

		var self = this;

		return this.potentialNextTasks.chain().map(function (task) {
			return {
				task: task,
				weight: Math.random() / self._size[task.cid],
			};
		}).sortBy("weight").reverse().pluck("task").value().slice(0, 2);
	},

	taskComparator: function (task1, task2) {
		var level1 = this._level(task1.cid);
		var level2 = this._level(task2.cid);

		if (level1 === undefined && level2 === undefined) {
			return 0;
		} else if (level1 === undefined) {
			return 1;
		} else if (level2 === undefined) {
			return -1;
		}

		if (level1 === level2) {
			return this._size[task2.cid] - this._size[task1.cid];
		}
		return level1 - level2;
	},

	_updateCollections: function () {
		var potentialNexts, nexts = {}, rests = {}, wfs = {}; // { cid: task, ... }
		var byLevel = []; // [{ cid: task, ... }, ...]
		var taskLevel = {}; // { cid: level, ... }

		function setLevel(task, level) {
			if (!(task.cid in taskLevel) || taskLevel[task.cid] < level) {
				if ((task.cid in taskLevel) && taskLevel[task.cid] < level) {
					var oldLevel = taskLevel[task.cid];
					delete byLevel[oldLevel][task.cid];
				}
				taskLevel[task.cid] = level;
				byLevel[level] || (byLevel[level] = {});
				byLevel[level][task.cid] = task;
			}
		}

		this._walk(null, function (task, level) {
			if (task.has("waitingFor")) {
				wfs[task.cid] = task;
				return level;
			} else {
				setLevel(task, level);
				return level + 1;
			}
		}, 0);

		potentialNexts = byLevel[0] || {};

		for (var level = 0, next = true; byLevel[level]; level++) {
			var tasks = _.values(byLevel[level]);
			if (next && tasks.length === 1) {
				nexts[tasks[0].cid] = tasks[0];
				next = false; // limit to 1 next task for now
			} else {
				next = false;
				_.each(tasks, function (task) {
					rests[task.cid] = task;
				}, this);
			}
		}

		this.potentialNextTasks.reset(_.chain(potentialNexts).values().sortBy(this.taskComparator).value());
		this.nextTasks.reset(_.chain(nexts).values().sortBy(this.taskComparator).value());
		this.restTasks.reset(_.chain(rests).values().sortBy(this.taskComparator).value());
		this.wfTasks.reset(_.chain(wfs).values().sortBy(this.taskComparator).value());
	},

	_addTask: function (task) {
		this._children[task.cid] = [];
		this._parents[task.cid] = [];
		this._size[task.cid] = 1;
		this._roots.push(task.cid);
	},

	_addComparison: function (comparison) {
		if (comparison.get("invalidated")) {
			return;
		}

		var greaterTask = this.tasks.get(comparison.get("greaterTaskId"));
		var lesserTask = this.tasks.get(comparison.get("lesserTaskId"));
		if (!greaterTask || !lesserTask) {
			return;
		}

		if (_.contains(this._allParents(greaterTask.cid), lesserTask.cid)) {
			console.log("ignoring comparison that would create a cycle", greaterTask.get("text"), ">", lesserTask.get("text"));
			return;
		}

		this._addChild(greaterTask.cid, lesserTask.cid);
		removeFromSet(this._roots, lesserTask.cid);
	},

	_recalculate: function () {
		this._children = {}; // cid -> [cid, ...]
		this._parents = {}; // cid -> [cid, ...]
		this._size = {}; // cid -> int
		this._roots = []; // [cid, ...]

		this.tasks.each(this._addTask, this);
		this.comparisons.each(this._addComparison, this);

		this._updateCollections();

		this.trigger("recalculate");
	},

	_debug: function () {
		console.group();
		this._walk(null, _.bind(function (task, indent) {
			console.log(indent + task.get("text") + (task.has("waitingFor") ? " wf" : ""));
			return indent + "  ";
		}, this), "");
		console.groupEnd();
	},

	_addChild: function (parentCid, childCid) {
		addToSet(this._children[parentCid], childCid);
		addToSet(this._parents[childCid], parentCid);

		// XXX: not accurate because may have already been a child
		this._size[parentCid] += this._size[childCid];
		var parentParents = this._allParents(parentCid);
		_.each(parentParents, function (cid) {
			this._size[cid] += this._size[childCid];
		}, this);
	},

	_allParents: function (cid) {
		var self = this, all = [];
		walk(cid);
		return all;

		function walk(currentCid) {
			var parentCids = self._parents[currentCid] || [];
			all.push.apply(all, parentCids);
			_.each(parentCids, walk);
		}
	},

	// find the longest path to the root & return that depth
	_level: function (cid) {
		var self = this;
		return getLevel(cid);

		function getLevel(currentCid) {
			var parentCids = self._parents[currentCid] || [];
			if (parentCids.length === 0) {
				return 0;
			}

			return _.max(parentCids.map(getLevel)) + 1;
		}
	},

	_walk: function (task, iter, data, filter) {
		// get the list of children in case it's mutated
		var children;
		if (task) {
			if (!this._children[task.cid]) {
				console.error("during walk, children of task weren't found", task);
				return;
			}
			children = this._children[task.cid];
		} else {
			children = this._roots;
		}

		// invoke the iterator
		if (task && (!filter || filter(task))) {
			data = iter(task, data);
		}

		// recurse
		_.each(children, function (childCid) {
			var child = this.tasks.get(childCid);
			if (child) {
				this._walk(child, iter, data, filter);
			} else {
				console.error("during walk, task wasn't found", childCid);
			}
		}, this);
	},
});

// Pile

var Pile = Backbone.Model.extend({
	defaults: {
		name: "",
	},

	initialize: function () {
		if (this.has("id")) {
			this._makeCollections();
		} else {
			this.listenToOnce(this, "change:id", this._makeCollections);
		}
	},

	_makeCollections: function () {
		this.tasks = new TaskCollection(this.collection.store.makeStore("piles-" + this.id + "-tasks"));
		this.comparisons = new ComparisonCollection(this.collection.store.makeStore("piles-" + this.id + "-comparisons"));
		this.taskForest = new TaskForest(this.tasks, this.comparisons);

		this.tasks.pile = this.comparisons.pile = this;
	},

	toJSON: function () {
		var o = Backbone.Model.prototype.toJSON.apply(this, arguments);
		o.tasks = this.tasks.toJSON();
		o.comparisons = this.comparisons.toJSON();
		return o;
	},
});

var PileCollection = Backbone.Collection.extend({
	model: Pile,

	constructor: function (store) {
		store.applyToCollection(this);
		Backbone.Collection.apply(this, Array.prototype.slice.call(arguments, 1));
	},

	// per Backbone.js convention, that's an object, not a string
	clonePileFromJSON: function (json) {
		var d = new $.Deferred;

		var taskJSONs = json.tasks, comparisonJSONs = json.comparisons;
		var oldIds = _.pluck(taskJSONs, "id");
		delete json.id;
		delete json.tasks;
		delete json.comparisons;

		var pile = this.add(json);
		pile.save().then(saveTasks, bail("Could not save pile"));

		function saveTasks() {
			pile.tasks.reset(_.map(taskJSONs, function (taskJSON) {
				delete taskJSON.id;
				return taskJSON;
			}));
			$.when.apply($, pile.tasks.invoke("save"))
				.then(saveComparisons, bail("failed to save all the tasks"));
		}

		function saveComparisons() {
			var newIds = pile.tasks.pluck("id");
			var idMap = _.object(oldIds, newIds);

			pile.comparisons.reset(_.reduce(comparisonJSONs, function (jsons, comparisonJSON) {
				delete comparisonJSON.id;
				comparisonJSON.lesserTaskId = idMap[comparisonJSON.lesserTaskId];
				comparisonJSON.greaterTaskId = idMap[comparisonJSON.greaterTaskId];
				if (comparisonJSON.lesserTaskId && comparisonJSON.greaterTaskId) {
					jsons.push(comparisonJSON);
				}
				return jsons;
			}, []));
			console.log("[import] pruned " + (comparisonJSONs.length - pile.comparisons.length) + " of " + comparisonJSONs.length + " comparisons");
			$.when.apply($, pile.comparisons.invoke("save"))
				.then(done, bail("failed to save all the comparisons"));
		}

		function done() {
			d.resolve(pile);
		}

		function bail(reason) {
			return function () {
				d.reject(reason);
			};
		}

		return d.promise();
	},
});
<|endoftext|>


<commit_before>const _get = require('lodash/get');
const _isEqual = require('lodash/isEqual');
const _isNumber = require('lodash/isNumber');
const _merge = require('lodash/merge');
const _throttle = require('lodash/throttle');
const _uniqueId = require('lodash/uniqueId');
const keycode = require('keycode');
const PropTypes = require('prop-types');
const React = require('react');
const Velocity = require('velocity-animate');
const { StyleRoot } = require('radium');

import { withTheme } from './Theme';
const Button = require('../components/Button');
const MXFocusTrap = require('../components/MXFocusTrap');

const { themeShape } = require('../constants/App');

const StyleUtils = require('../utils/Style');
const { deprecatePrimaryColor } = require('../utils/Deprecation');

class Drawer extends React.Component {
  static propTypes = {
    'aria-describedby': PropTypes.string,
    'aria-labelledby': PropTypes.string,
    animateLeftDistance: PropTypes.number,
    beforeClose: PropTypes.func,
    breakPoints: PropTypes.shape({
      large: PropTypes.number,
      medium: PropTypes.number
    }),
    buttonPrimaryColor: PropTypes.string,
    closeOnScrimClick: PropTypes.bool,
    contentStyle: PropTypes.oneOfType([
      PropTypes.array,
      PropTypes.object
    ]),
    duration: PropTypes.number,
    easing: PropTypes.array,
    focusOnLoad: PropTypes.bool,
    focusTrapProps: PropTypes.object,
    headerMenu: PropTypes.oneOfType([
      PropTypes.element,
      PropTypes.func
    ]),
    headerStyle: PropTypes.oneOfType([
      PropTypes.array,
      PropTypes.object
    ]),
    maxWidth: PropTypes.number,
    navConfig: PropTypes.shape({
      label: PropTypes.string.isRequired,
      onNextClick: PropTypes.func.isRequired,
      onPreviousClick: PropTypes.func.isRequired
    }),
    onClose: PropTypes.func.isRequired,
    onKeyUp: PropTypes.func,
    onOpen: PropTypes.func,
    role: PropTypes.string,
    showCloseButton: PropTypes.bool,
    showScrim: PropTypes.bool,
    styles: PropTypes.object,
    theme: themeShape,
    title: PropTypes.string
  };

  static defaultProps = {
    beforeClose: () => {},
    closeOnScrimClick: true,
    duration: 500,
    easing: [0.28, 0.14, 0.34, 1.04],
    focusOnLoad: true,
    focusTrapProps: {},
    maxWidth: 960,
    onOpen: () => {},
    role: 'dialog',
    showCloseButton: true,
    showScrim: true,
    title: ''
  };

  constructor (props) {
    super(props);

    const theme = StyleUtils.mergeTheme(props.theme, props.buttonPrimaryColor);
    const breakPoints = props.breakPoints || theme.BreakPoints;

    this.state = { breakPoints, theme };
  }

  componentWillMount () {
    this._resizeThrottled = _throttle(this._resize, 100);
  }

  componentDidMount () {
    deprecatePrimaryColor(this.props, 'buttonPrimaryColor');
    this.open();
    window.addEventListener('resize', this._resizeThrottled);

    if (this.props.focusOnLoad) {
      this._component.focus();
    }
  }

  componentWillReceiveProps (newProps) {
    if (!_isEqual(newProps.breakPoints, this.props.breakPoints)) {
      this.setState({
        breakPoints: this.props.breakPoints
      });
    }
  }

  componentWillUnmount () {
    window.removeEventListener('resize', this._resizeThrottled);
  }

  _getAnimationDistance = () => {
    if (_isNumber(this.props.animateLeftDistance)) {
      return this.props.animateLeftDistance + '%';
    }

    const windowWidth = window.innerWidth;

    if (windowWidth >= this.state.breakPoints.large) {
      //Resolution - maxWidth
      return windowWidth - this.props.maxWidth;
    } else if (windowWidth <= this.state.breakPoints.medium) {
      //All the way over to the left
      return 0;
    } else {
      //20% from the left
      const newLeft = windowWidth * 0.2;

      return Math.max(newLeft, windowWidth - this.props.maxWidth);
    }
  };

  _getExposedDrawerFunctions = () => {
    return { close: this.close };
  };

  /**
   * Figure out the height of the header. This can come from either:
   *
   * this.props.headerStyle.height
   * this.props.header.height
   *
   * If neither are set, default to 50px
   */
  _getHeaderHeight = () => {
    return _get(this.props, ['headerStyle', 'height'],
                _get(this.props,
                     ['styles', 'header', 'height'],
                     '50px'));
  };

  /**
   * Animate the Drawer closed and then call the onClose callback.
   *
   * @returns {Promise} that is resolved when the animation finishes
   */
  close = () => {
    this.props.beforeClose();
    return this._animateComponent({ left: '100%' })
      .then(() => {
        this.props.onClose();
      });
  };

  open = () => {
    return this._animateComponent({ left: this._getAnimationDistance() })
      .then(() => {
        this.props.onOpen();
      });
  };

  _animateComponent = (transition, extraOptions) => {
    const el = this._component;
    const options = Object.assign({
      duration: this.props.duration,
      easing: this.props.easing
    }, extraOptions);

    return Velocity(el, transition, options);
  };

  _handleKeyUp = e => {
    e.preventDefault();
    e.stopPropagation();

    if (keycode(e) === 'esc') this.close();
  };

  _resize = () => {
    this._animateComponent({ left: this._getAnimationDistance() }, { duration: 0 });
  };

  _renderNav = (navConfig, styles, theme) => {
    return (

        <Button
          icon='caret-left'
          onClick={navConfig.onPreviousClick}
          theme={theme}
          type='base'
        />

          {navConfig.label}

        <Button
          icon='caret-right'
          onClick={navConfig.onNextClick}
          theme={theme}
          type='base'
        />

    );
  };

  render () {
    const { theme } = this.state;
    const styles = this.styles(theme);
    const { headerMenu, focusTrapProps, navConfig } = this.props;
    const mergedFocusTrapProps = {
      focusTrapOptions: {
        clickOutsideDeactivates: true
      },
      paused: false,
      ...focusTrapProps
    };

    let menu = null;

    // If headerMenu is a function then we want to pass the Drawer's
    // exposed functions to the call.
    if (typeof headerMenu === 'function') {
      menu = headerMenu(this._getExposedDrawerFunctions());
    // If headerMenu is a normal node/element then use directly.
    } else if (headerMenu) {
      menu = headerMenu;
    // If no headerMenu and navConfig passed then use Drawer's
    // _renderNav function to generate the menu.
    } else if (navConfig) {
      menu = this._renderNav(navConfig, styles, theme);
    }
    const titleUniqueId = _uniqueId('mx-drawer-title-');

    return (


<commit_before>const mongoose = require('mongoose');
// eslint-disable-next-line no-unused-vars
const { info, error } = require('../src/logger');

const { connect, close } = require('../src/utils/database');

const defaultFeatures = [];
const USER_FEATURES = {
	EDTR: 'edtr',
};

// use your own name for your model, otherwise other migrations may fail.
// The third parameter is the actually relevent one for what collection to write to.
const User = mongoose.model('addEDTRFeatureToKlaraFall', new mongoose.Schema({
	email: { type: String, required: true, lowercase: true },
	features: {
		type: [String],
		default: defaultFeatures,
		enum: Object.values(USER_FEATURES),
	},
}, {
	timestamps: true,
}), 'users');

// How to use more than one schema per collection on mongodb
// https://stackoverflow.com/questions/14453864/use-more-than-one-schema-per-collection-on-mongodb

// TODO npm run migration-persist and remove this line
// TODO update seed data and remove this line

module.exports = {
	up: async function up() {
		await connect();
		// ////////////////////////////////////////////////////
		// Make changes to the database here.
		// Hint: Access models via this('modelName'), not an imported model to have
		// access to the correct database connection. Otherwise Mongoose calls never return.
		console.log(await User.find({
			email: 'klara.fall@schul-cloud.org',
		}).lean().exec());
		await User.update({
			email: 'klara.fall@schul-cloud.org',
		}, {
			$push: { features: 'edtr' },
		}).lean().exec();
		// ////////////////////////////////////////////////////
		await close();
	},

	down: async function down() {
		await connect();
		// ////////////////////////////////////////////////////
		// Implement the necessary steps to roll back the migration here.
		await User.update({
			email: 'klara.fall@schul-cloud.org',
		}, {
			$pull: { features: 'edtr' },
		}).lean().exec();
		// ////////////////////////////////////////////////////
		await close();
	},
};
<commit_msg>remove log<commit_after>const mongoose = require('mongoose');
// eslint-disable-next-line no-unused-vars
const { info, error } = require('../src/logger');

const { connect, close } = require('../src/utils/database');

const defaultFeatures = [];
const USER_FEATURES = {
	EDTR: 'edtr',
};

// use your own name for your model, otherwise other migrations may fail.
// The third parameter is the actually relevent one for what collection to write to.
const User = mongoose.model('addEDTRFeatureToKlaraFall', new mongoose.Schema({
	email: { type: String, required: true, lowercase: true },
	features: {
		type: [String],
		default: defaultFeatures,
		enum: Object.values(USER_FEATURES),
	},
}, {
	timestamps: true,
}), 'users');

// How to use more than one schema per collection on mongodb
// https://stackoverflow.com/questions/14453864/use-more-than-one-schema-per-collection-on-mongodb

// TODO npm run migration-persist and remove this line
// TODO update seed data and remove this line

module.exports = {
	up: async function up() {
		await connect();
		// ////////////////////////////////////////////////////
		// Make changes to the database here.
		// Hint: Access models via this('modelName'), not an imported model to have
		// access to the correct database connection. Otherwise Mongoose calls never return.
		await User.update({
			email: 'klara.fall@schul-cloud.org',
		}, {
			$push: { features: 'edtr' },
		}).lean().exec();
		// ////////////////////////////////////////////////////
		await close();
	},

	down: async function down() {
		await connect();
		// ////////////////////////////////////////////////////
		// Implement the necessary steps to roll back the migration here.
		await User.update({
			email: 'klara.fall@schul-cloud.org',
		}, {
			$pull: { features: 'edtr' },
		}).lean().exec();
		// ////////////////////////////////////////////////////
		await close();
	},
};
<|endoftext|>


<commit_before>/**
 初始化vue 对象
 @param vc vue component对象
 @param vmOptions Vue参数
 **/
(function (vc, vmOptions) {
    console.log("vmOptions:", vmOptions);
    vc.component = new Vue(vmOptions);
})(window.vc, window.vc.vmOptions);

/**
 vc监听事件
 **/
(function (vc) {
    /**
     事件监听
     **/
    vc.on = function (_componentName, _value, _callback) {

        vc.component.$on(_componentName + '_' + _value,
            function (param) {
                if (vc.debug) {
                    console.log("监听ON事件", _componentName, _value, param);
                }
                _callback(param);
            }
        );
    };

    /**
     事件触发
     **/
    vc.emit = function (_componentName, _value, _param) {
        if (vc.debug) {
            console.log("监听emit事件", _componentName, _value, _param);
        }
        vc.component.$emit(_componentName + '_' + _value, _param);
    };

    /**
     事件监听
     **/
    vc.on = function (_namespace, _componentName, _value, _callback) {

        vc.component.$on(_namespace + "_" + _componentName + '_' + _value,
            function (param) {
                if (vc.debug) {
                    console.log("监听ON事件", _namespace, _componentName, _value, param);
                }
                _callback(param);
            }
        );
    };

    /**
     事件触发
     **/
    vc.emit = function (_namespace, _componentName, _value, _param) {
        if (vc.debug) {
            console.log("监听emit事件", _namespace, _componentName, _value, _param);
        }
        vc.component.$emit(_namespace + "_" + _componentName + '_' + _value, _param);
    };

})(window.vc);

/**
 * vue对象 执行初始化方法
 */
(function (vc) {
    vc.initEvent.forEach(function (eventMethod) {
        eventMethod();
    });
    vc.initMethod.forEach(function (callback) {
        callback();
    });
    vc.namespace.forEach(function (_param) {
        vc[_param.namespace] = vc.component[_param.namespace];
    });
})(window.vc);

<commit_msg>优化vc.on<commit_after>/**
 初始化vue 对象
 @param vc vue component对象
 @param vmOptions Vue参数
 **/
(function (vc, vmOptions) {
    console.log("vmOptions:", vmOptions);
    vc.component = new Vue(vmOptions);
})(window.vc, window.vc.vmOptions);

/**
 vc监听事件
 **/
(function (vc) {
    /**
     事件监听
     **/
    vc.on = function () {
        var _namespace = "";
        var _componentName = "";
        var _value = "";
        var _callback = undefined;
        if (arguments.length == 4) {
            _namespace = arguments[0];
            _componentName = arguments[1];
            _value = arguments[2];
            _callback = arguments[3];
        }else if(arguments.length == 3){
            _componentName = arguments[0];
            _value = arguments[1];
            _callback = arguments[2];
        }else{
            console.error("执行on 异常，vc.on 参数只能是3个 或4个");
            return;
        }
        if (vc.notNull(_namespace)) {
            vc.component.$on(_namespace + "_" + _componentName + '_' + _value,
                function (param) {
                    if (vc.debug) {
                        console.log("监听ON事件", _namespace, _componentName, _value, param);
                    }
                    _callback(param);
                }
            );
            return;
        }

        vc.component.$on(_componentName + '_' + _value,
            function (param) {
                if (vc.debug) {
                    console.log("监听ON事件", _componentName, _value, param);
                }
                _callback(param);
            }
        );
    };

    /**
     事件触发
     **/
    vc.emit = function () {
        var _namespace = "";
        var _componentName = "";
        var _value = "";
        var _callback = undefined;
        if (arguments.length == 4) {
            _namespace = arguments[0];
            _componentName = arguments[1];
            _value = arguments[2];
            _callback = arguments[3];
        }else if(arguments.length == 3){
            _componentName = arguments[0];
            _value = arguments[1];
            _callback = arguments[2];
        }else{
            console.error("执行on 异常，vc.on 参数只能是3个 或4个");
            return;
        }
        if (vc.debug) {
            console.log("监听emit事件", _componentName, _value, _param);
        }
        if (vc.notNull(_namespace)) {
            vc.component.$emit(_namespace + "_" + _componentName + '_' + _value, _param);
            return;
        }
        vc.component.$emit(_componentName + '_' + _value, _param);
    };

})(window.vc);

/**
 * vue对象 执行初始化方法
 */
(function (vc) {
    vc.initEvent.forEach(function (eventMethod) {
        eventMethod();
    });
    vc.initMethod.forEach(function (callback) {
        callback();
    });
    vc.namespace.forEach(function (_param) {
        vc[_param.namespace] = vc.component[_param.namespace];
    });
})(window.vc);

<|endoftext|>


<commit_before>import React from 'react'
import _map from 'lodash.map'
import FitText from '../vendor/react-fittext'

class HeaderColumn extends React.Component {
  render () {
    const self = this

    return (

{ self.props.children }

    )
  }
}

HeaderColumn.defaultProps = {
  heading: '',
  headingClassName: '',
  className: '',
  lang: 'ja'
}

class Header extends React.Component {
  render () {
    const self = this
    const data = self.props.data

    var typefaceList = _map(Object.keys(data.fonts), function (index) {
      var font = data.fonts[index]
      var fontWeight =  400

      // TODO
      // Nikukyu = only second glyph
      // Ones with Kanji = add 安

      if (font.published !== false && font.designer) {
        return (

                <FitText compressor={0.33} minFontSize={24}>

あア

                </FitText>

                { font.name.ja } { font.name.en !== font.name.ja ? font.name.en : '' }
                { font.designer.name.ja } { font.designer.name.en !== font.designer.name.ja ? font.designer.name.en : '' }

        )
      }
    })

    return (

Google Fonts + Japanese Early Access

          <FitText compressor={ 0.9 }>

            Google Fonts
             + 日本語 早期アクセス

          </FitText>

            <HeaderColumn>

Google Fonts は、デザイナー ウェブフォントを直感的にご利用いただける、安定したオープンソース ディレクトリです。Google Fonts 早期アクセスでは、現時点で完全にはサポートしていないフォントを試験的に提供しています。

膨大な数の文字のデザインに要する時間や、大容量のフォント ファイルをウェブフォントとして提供する際に必要な技術的インフラストラクチャなど、日本語の書体デザインやフォント開発にはさまざまな課題が立ちふさがります。そこで、規格や技術の開発を進めると同時に、Google Fonts 早期アクセスを通じてデザイナーやデベロッパーの皆様に日本語のウェブフォントをお試しいただけるようにしました。

            </HeaderColumn>
            <HeaderColumn lang="en">

Google Fonts provides an intuitive and robust directory of open source, designer web fonts. Our Early Access program serves as an experimental playground for fonts that aren’t yet fully supported.

The rich typography of Japan presents many interesting challenges, from the lengthy process needed to design thousands of characters to the technical infrastructure required to serve large font files as web fonts. As Google makes progress on supporting Japanese web typography, we invite designers and developers to experiment with these Japanese web fonts now available from Google Fonts Early Access.

            </HeaderColumn>

{ typefaceList }

    )
  }
}

export default Header
<commit_msg>Adds different content to header nav based on character support<commit_after>import React from 'react'
import _map from 'lodash.map'
import FitText from '../vendor/react-fittext'

class HeaderColumn extends React.Component {
  render () {
    const self = this

    return (

{ self.props.children }

    )
  }
}

HeaderColumn.defaultProps = {
  heading: '',
  headingClassName: '',
  className: '',
  lang: 'ja'
}

class Header extends React.Component {
  render () {
    const self = this
    const data = self.props.data

    var typefaceList = _map(Object.keys(data.fonts), function (index) {
      var font = data.fonts[index]
      var fontWeight =  400
      var fontString = 'アあ '

      if (font.published !== false && font.designer) {
        if (font.hiragana === false) {
          fontString = 'ア  '
        }
        if (font.kanji === true) {
          fontString = 'アあ安'
        }

        return (

                <FitText compressor={0.33} minFontSize={24}>

{ fontString }

                </FitText>

                { font.name.ja } { font.name.en !== font.name.ja ? font.name.en : '' }
                { font.designer.name.ja } { font.designer.name.en !== font.designer.name.ja ? font.designer.name.en : '' }

        )
      }
    })

    return (

Google Fonts + Japanese Early Access

          <FitText compressor={ 0.9 }>

            Google Fonts
             + 日本語 早期アクセス

          </FitText>

            <HeaderColumn>

Google Fonts は、デザイナー ウェブフォントを直感的にご利用いただける、安定したオープンソース ディレクトリです。Google Fonts 早期アクセスでは、現時点で完全にはサポートしていないフォントを試験的に提供しています。

膨大な数の文字のデザインに要する時間や、大容量のフォント ファイルをウェブフォントとして提供する際に必要な技術的インフラストラクチャなど、日本語の書体デザインやフォント開発にはさまざまな課題が立ちふさがります。そこで、規格や技術の開発を進めると同時に、Google Fonts 早期アクセスを通じてデザイナーやデベロッパーの皆様に日本語のウェブフォントをお試しいただけるようにしました。

            </HeaderColumn>
            <HeaderColumn lang="en">

Google Fonts provides an intuitive and robust directory of open source, designer web fonts. Our Early Access program serves as an experimental playground for fonts that aren’t yet fully supported.

The rich typography of Japan presents many interesting challenges, from the lengthy process needed to design thousands of characters to the technical infrastructure required to serve large font files as web fonts. As Google makes progress on supporting Japanese web typography, we invite designers and developers to experiment with these Japanese web fonts now available from Google Fonts Early Access.

            </HeaderColumn>

{ typefaceList }

    )
  }
}

export default Header
<|endoftext|>


<commit_before>$.get("/get/username", function(data) {
    parsedData = JSON.parse(data);
    $("#loggedIn").attr("uid", parsedData.username);
    $("#loggedIn").html("" + parsedData.username + "");
    //$("#logout").html("<form method=\"post\" action=\"/logout\"><button type=\"submit\">Logout</button></form>");
    $("#login").hide();
    $("#signup").hide();
    $("#loggedIn").show();
});

window.onload = function() {

  // Get references to elements on the page.
  var form = document.getElementById('message-form');
  var messageField = document.getElementById('message');
  var messagesList = document.getElementById('messages');
  //var socketStatus = document.getElementById('status');

  // Create a new WebSocket.
  var socket = new WebSocket('ws://ipp.chtr.us');

  // // Handle any errors that occur.
  // socket.onerror = function(error) {
  //   console.log('WebSocket Error: ' + error);
  // };

  // // Show a connected message when the WebSocket is opened.
  // socket.onopen = function(event) {
  //   socketStatus.innerHTML = 'Connected to: ws://ipp.chtr.us';
  //   socketStatus.className = 'open';
  // };

  // Handle messages sent by the server.
  socket.onmessage = function(event) {
    var value = JSON.parse(event.data);
    messagesList.innerHTML += '

' +
                               value.message + '
'+value.username+'| 23rd June at 5:00pm

';
  };

  // // Show a disconnected message when the WebSocket is closed.
  // socket.onclose = function(event) {
  //   socketStatus.innerHTML = 'Disconnected from WebSocket.';
  //   socketStatus.className = 'closed';
  // };

  // Send a message when the form is submitted.
  form.onsubmit = function(e) {
    e.preventDefault();

    // Retrieve the message from the textarea.
    var json = {
        "message": messageField.value,
        "username": document.getElementById('loggedIn').getAttribute('uid')
    };
    var message = JSON.stringify(json);

    // Send the message through the WebSocket.
    socket.send(message);

    // Add the message to the messages list.
    //messagesList.innerHTML += '
Sent:' + message +
                              //'
';

    // Clear out the message field.
    messageField.value = '';

    return false;
  };

};
<commit_msg>Online users<commit_after>$.get("/get/username", function(data) {
    parsedData = JSON.parse(data);
    $("#loggedIn").attr("uid", parsedData.username);
    $("#loggedIn").html("" + parsedData.username + "");
    //$("#logout").html("<form method=\"post\" action=\"/logout\"><button type=\"submit\">Logout</button></form>");
    $("#login").hide();
    $("#signup").hide();
    $("#loggedIn").show();
});

window.onload = function() {

  // Get references to elements on the page.
  var form = document.getElementById('message-form');
  var messageField = document.getElementById('message');
  var messagesList = document.getElementById('messages');
  //var socketStatus = document.getElementById('status');

  // Create a new WebSocket.
  var socket = new WebSocket('ws://ipp.chtr.us');

  // // Handle any errors that occur.
  // socket.onerror = function(error) {
  //   console.log('WebSocket Error: ' + error);
  // };

  // // Show a connected message when the WebSocket is opened.
  // socket.onopen = function(event) {
  //   socketStatus.innerHTML = 'Connected to: ws://ipp.chtr.us';
  //   socketStatus.className = 'open';
  // };

  // Handle messages sent by the server.
  socket.onmessage = function(event) {
    var value = JSON.parse(event.data);
    messagesList.innerHTML += '

' +
                               value.message + '
'+value.username+'| 23rd June at 5:00pm

';
  };

  // // Show a disconnected message when the WebSocket is closed.
  // socket.onclose = function(event) {
  //   socketStatus.innerHTML = 'Disconnected from WebSocket.';
  //   socketStatus.className = 'closed';
  // };

  // Send a message when the form is submitted.
  form.onsubmit = function(e) {
    e.preventDefault();

    // Retrieve the message from the textarea.
    var json = {
        "message": messageField.value,
        "username": document.getElementById('loggedIn').getAttribute('uid')
        "type": messageField.value
    };
    var message = JSON.stringify(json);

    // Send the message through the WebSocket.
    socket.send(message);

    // Add the message to the messages list.
    //messagesList.innerHTML += '
Sent:' + message +
                              //'
';

    // Clear out the message field.
    messageField.value = '';

    return false;
  };

};
<|endoftext|>


<commit_before>isic.App = girder.App.extend({

    initialize: function (settings) {
        // Call the parent "initialize", but don't let that call "start()",
        // since we want to pass custom parameters
        girder.App.prototype.initialize.call(this, {
            start: false
        });

        // Start the app (and fetch the user)
        this.start({
            // Don't render automatically, to ensure currentUser is updated
            // before the first rendering
            render: false,
            // Don't start the history, to delay starting navigation until
            // rendering has occurred
            history: false
        }).done(_.bind(function () {
            // Then update currentUser if necessary
            this._updateCurrentUser();
            // Do the things that would normally be done within "start()"
            this.render();
            Backbone.history.start({
                pushState: false
            });
        }, this));
    },

    bindGirderEvents: function () {
        girder.App.prototype.bindGirderEvents.call(this);

        // It would be better to listen for "g:login.success", as it's triggered
        // before "g:login", but "g:login.success" isn't triggered after a new
        // user registers (which is probably a bug)

        // "currentUser" must be updated before all rendering, so unbind the
        // default binding of "g:login" to "this.login", and ensure that
        // updating "currentUser" is the event bound to "g:login"; however,
        // it's an undocumented property of Backbone that events get called in
        // the order they were bound, so this isn't a great solution
        girder.events.off('g:login', this.login);
        girder.events.on('g:login', this._updateCurrentUser(), this);
        // "g:login-changed" is triggered when users change passwords
        girder.events.on('g:login-changed', this._updateCurrentUser(), this);
        girder.events.on('g:login', this.login, this);
    },

    _updateCurrentUser: function () {
        // Replace the girder.currentUser object with its subclass, which
        // exposes additional methods
        if (girder.currentUser) {
            girder.currentUser =
                new isic.models.UserModel(girder.currentUser.attributes);
        }
    },

    render: function () {
        this.$el.html(isic.templates.layout());

        new isic.views.LayoutHeaderView({ // eslint-disable-line no-new
            el: this.$('#isic-app-header-container'),
            parentView: this
        });

        new isic.views.LayoutFooterView({ // eslint-disable-line no-new
            el: this.$('#isic-app-footer-container'),
            parentView: this
        });

        return this;
    },

    navigateTo: function () {
        this.$('#g-app-body-container').removeClass('isic-body-nopad');
        return girder.App.prototype.navigateTo.apply(this, arguments);
    },

    /**
     * On login we re-render the current body view; whereas on
     * logout, we redirect to the front page.
     */
    login: function () {
        var route = girder.dialogs.splitRoute(Backbone.history.fragment).base;
        Backbone.history.fragment = null;
        girder.eventStream.close();

        if (girder.currentUser) {
            girder.eventStream.open();
            isic.router.navigate(route, {trigger: true});
        } else {
            isic.router.navigate('/', {trigger: true});
        }
    }
});
<commit_msg>Fix a typo in event binding<commit_after>isic.App = girder.App.extend({

    initialize: function (settings) {
        // Call the parent "initialize", but don't let that call "start()",
        // since we want to pass custom parameters
        girder.App.prototype.initialize.call(this, {
            start: false
        });

        // Start the app (and fetch the user)
        this.start({
            // Don't render automatically, to ensure currentUser is updated
            // before the first rendering
            render: false,
            // Don't start the history, to delay starting navigation until
            // rendering has occurred
            history: false
        }).done(_.bind(function () {
            // Then update currentUser if necessary
            this._updateCurrentUser();
            // Do the things that would normally be done within "start()"
            this.render();
            Backbone.history.start({
                pushState: false
            });
        }, this));
    },

    bindGirderEvents: function () {
        girder.App.prototype.bindGirderEvents.call(this);

        // It would be better to listen for "g:login.success", as it's triggered
        // before "g:login", but "g:login.success" isn't triggered after a new
        // user registers (which is probably a bug)

        // "currentUser" must be updated before all rendering, so unbind the
        // default binding of "g:login" to "this.login", and ensure that
        // updating "currentUser" is the event bound to "g:login"; however,
        // it's an undocumented property of Backbone that events get called in
        // the order they were bound, so this isn't a great solution
        girder.events.off('g:login', this.login);
        girder.events.on('g:login', this._updateCurrentUser, this);
        // "g:login-changed" is triggered when users change passwords
        girder.events.on('g:login-changed', this._updateCurrentUser, this);
        girder.events.on('g:login', this.login, this);
    },

    _updateCurrentUser: function () {
        // Replace the girder.currentUser object with its subclass, which
        // exposes additional methods
        if (girder.currentUser) {
            girder.currentUser =
                new isic.models.UserModel(girder.currentUser.attributes);
        }
    },

    render: function () {
        this.$el.html(isic.templates.layout());

        new isic.views.LayoutHeaderView({ // eslint-disable-line no-new
            el: this.$('#isic-app-header-container'),
            parentView: this
        });

        new isic.views.LayoutFooterView({ // eslint-disable-line no-new
            el: this.$('#isic-app-footer-container'),
            parentView: this
        });

        return this;
    },

    navigateTo: function () {
        this.$('#g-app-body-container').removeClass('isic-body-nopad');
        return girder.App.prototype.navigateTo.apply(this, arguments);
    },

    /**
     * On login we re-render the current body view; whereas on
     * logout, we redirect to the front page.
     */
    login: function () {
        var route = girder.dialogs.splitRoute(Backbone.history.fragment).base;
        Backbone.history.fragment = null;
        girder.eventStream.close();

        if (girder.currentUser) {
            girder.eventStream.open();
            isic.router.navigate(route, {trigger: true});
        } else {
            isic.router.navigate('/', {trigger: true});
        }
    }
});
<|endoftext|>


<commit_before>/**
 * Created by Hendrik Strobelt (hendrik.strobelt.com) on 1/28/15.
 */

/*
 *
 * ======================================================
 * We follow the vis template of init - wrangle - update
 * ======================================================
 *
 * */

/**
 * CountVis object for HW3 of CS171
 * @param _parentElement -- the HTML or SVG element (D3 node) to which to attach the vis
 * @param _data -- the data array
 * @param _metaData -- the meta-data / data description object
 * @param _eventHandler -- the Eventhandling Object to emit data to (see Task 4)
 * @constructor
 */
CountVis = function(_parentElement, _data, _metaData, _eventHandler){
    this.parentElement = _parentElement;
    this.data = _data;
    this.metaData = _metaData;
    this.eventHandler = _eventHandler;
    this.displayData = [];

    // TODO: define all "constants" here

    this.initVis();
}

/**
 * Method that sets up the SVG and the variables
 */
CountVis.prototype.initVis = function(){

    var that = this; // read about the this

    //TODO: implement here all things that don't change
    //TODO: implement here all things that need an initial status
    // Examples are:
    // - construct SVG layout
    // - create axis
    // -  implement brushing !!
    // --- ONLY FOR BONUS ---  implement zooming

    // TODO: modify this to append an svg element, not modify the current placeholder SVG element
    this.svg = this.parentElement.select("svg");

    //TODO: implement the slider -- see example at http://bl.ocks.org/mbostock/6452972
    this.addSlider(this.svg)

    // filter, aggregate, modify data
    this.wrangleData();

    // call the update method
    this.updateVis();
}

/**
 * Method to wrangle the data. In this case it takes an options object
  */
CountVis.prototype.wrangleData= function(){

    // displayData should hold the data which is visualized
    // pretty simple in this case -- no modifications needed
    this.displayData = this.data;

}

/**
 * the drawing function - should use the D3 selection, enter, exit
 * @param _options -- only needed if different kinds of updates are needed
 */
CountVis.prototype.updateVis = function(){

    // TODO: implement update graphs (D3: update, enter, exit)

}

/**
 * Gets called by event handler and should create new aggregated data
 * aggregation is done by the function "aggregate(filter)". Filter has to
 * be defined here.
 * @param selection
 */
CountVis.prototype.onSelectionChange= function (selectionStart, selectionEnd){

    // TODO: call wrangle function

    // do nothing -- no update when brushing

}

/*
 *
 * ==================================
 * From here on only HELPER functions
 * ==================================
 *
 * */

/**
 * creates the y axis slider
 * @param svg -- the svg element
 */
CountVis.prototype.addSlider = function(svg){
    var that = this;

    // TODO: Think of what is domain and what is range for the y axis slider !!
    var sliderScale = d3.scale.linear().domain([0,200]).range([0,200])

    var sliderDragged = function(){
        var value = Math.max(0, Math.min(200,d3.event.y));

        var sliderValue = sliderScale.invert(value);

        // TODO: do something here to deform the y scale
        console.log("Y Axis Slider value: ", sliderValue);

        d3.select(this)
            .attr("y", function () {
                return sliderScale(sliderValue);
            })

        that.updateVis({});
    }
    var sliderDragBehaviour = d3.behavior.drag()
        .on("drag", sliderDragged)

    var sliderGroup = svg.append("g").attr({
        class:"sliderGroup",
        "transform":"translate("+0+","+30+")"
    })

    sliderGroup.append("rect").attr({
        class:"sliderBg",
        x:5,
        width:10,
        height:200
    }).style({
        fill:"lightgray"
    })

    sliderGroup.append("rect").attr({
        "class":"sliderHandle",
        y:0,
        width:20,
        height:10,
        rx:2,
        ry:2
    }).style({
        fill:"#333333"
    }).call(sliderDragBehaviour)

}

<commit_msg>countvis.js is not working at all<commit_after>/**
 * Created by Hendrik Strobelt (hendrik.strobelt.com) on 1/28/15.
 */

/*
 *
 * ======================================================
 * We follow the vis template of init - wrangle - update
 * ======================================================
 *
 * */

/**
 * CountVis object for HW3 of CS171
 * @param _parentElement -- the HTML or SVG element (D3 node) to which to attach the vis
 * @param _data -- the data array
 * @param _metaData -- the meta-data / data description object
 * @param _eventHandler -- the Eventhandling Object to emit data to (see Task 4)
 * @constructor
 */
CountVis = function(_parentElement, _data, _metaData, _eventHandler){
    this.parentElement = _parentElement;
    this.data = _data;
    this.metaData = _metaData;
    this.eventHandler = _eventHandler;
    this.displayData = [];

    // TODO: define all "constants" here

    this.initVis();
}

/**
 * Method that sets up the SVG and the variables
 */
CountVis.prototype.initVis = function(){

    var that = this; // read about the this

    //TODO: implement here all things that don't change
    //TODO: implements here all things that need an initial status
    // Examples are:
    // - construct SVG layout
    // - create axis
    // -  implement brushing !!
    // --- ONLY FOR BONUS ---  implement zooming

    // TODO: modify this to append an svg element, not modify the current placeholder SVG element
    this.svg = this.parentElement.select("svg");

    //TODO: implement the slider -- see example at http://bl.ocks.org/mbostock/6452972
    this.addSlider(this.svg)

    // filter, aggregate, modify data
    this.wrangleData();

    // call the update method
    this.updateVis();
}

/**
 * Method to wrangle the data. In this case it takes an options object
  */
CountVis.prototype.wrangleData= function(){

    // displayData should hold the data which is visualized
    // pretty simple in this case -- no modifications needed
    this.displayData = this.data;

}

/**
 * the drawing function - should use the D3 selection, enter, exit
 * @param _options -- only needed if different kinds of updates are needed
 */
CountVis.prototype.updateVis = function(){

    // TODO: implement update graphs (D3: update, enter, exit)

}

/**
 * Gets called by event handler and should create new aggregated data
 * aggregation is done by the function "aggregate(filter)". Filter has to
 * be defined here.
 * @param selection
 */
CountVis.prototype.onSelectionChange= function (selectionStart, selectionEnd){

    // TODO: call wrangle function

    // do nothing -- no update when brushing

}

/*
 *
 * ==================================
 * From here on only HELPER functions
 * ==================================
 *
 * */

/**
 * creates the y axis slider
 * @param svg -- the svg element
 */
CountVis.prototype.addSlider = function(svg){
    var that = this;

    // TODO: Think of what is domain and what is range for the y axis slider !!
    var sliderScale = d3.scale.linear().domain([0,200]).range([0,200])

    var sliderDragged = function(){
        var value = Math.max(0, Math.min(200,d3.event.y));

        var sliderValue = sliderScale.invert(value);

        // TODO: do something here to deform the y scale
        console.log("Y Axis Slider value: ", sliderValue);

        d3.select(this)
            .attr("y", function () {
                return sliderScale(sliderValue);
            })

        that.updateVis({});
    }
    var sliderDragBehaviour = d3.behavior.drag()
        .on("drag", sliderDragged)

    var sliderGroup = svg.append("g").attr({
        class:"sliderGroup",
        "transform":"translate("+0+","+30+")"
    })

    sliderGroup.append("rect").attr({
        class:"sliderBg",
        x:5,
        width:10,
        height:200
    }).style({
        fill:"lightgray"
    })

    sliderGroup.append("rect").attr({
        "class":"sliderHandle",
        y:0,
        width:20,
        height:10,
        rx:2,
        ry:2
    }).style({
        fill:"#333333"
    }).call(sliderDragBehaviour)

}<|endoftext|>