<commit_before>var helper = require('./helpers/promise')
  , db = require('ezseed-database').db
  , logger = require('ezseed-logger')('useradd')
  , config = require('../lib/config.js')
  , async = require('async')
  , p = require('path')
  , i18n = require('i18n')
  , Promise = require('bluebird')

module.exports = function(opts) {

  require('./inquirer/useradd.js')(opts)
  .then(function(opts) {
    //require config + client installed?

    async.waterfall([
      function(done) {
        return db.user.create(opts, function() {
          return done() //forcing no arguments to prevent async.waterfall to add those
        })
      },
      function(done) {
        //adds the ezseed user
        db.paths.save(
          p.join(config.home, opts.username, 'downloads'),
          {
            username: opts.username,
            default: true
          },
          function(err) {
            if(err) {
              logger.warn(err)
            }

            return done()
          }
        )
      }, function(done) {

        if(opts.client !== 'transmission') {
          return done()
        }

        require('local-port').findOpen(9002, function(err, open_port) {
          if(err) {
            logger.error('We could not find any open port')
            done(err)
          } else {
            opts.transmission_port = open_port
            done()
          }
        })
      }
    ], function(err) {
      if(err) {
        helper.exit(err)(1)
      }

      //adds the system user
      return require('./commands/user')
      .create(opts.username, opts.password)
      .catch(helper.exit(i18n.__('Creating system user')))
      .then(function() {

          //adds the client user (transmission or rtorrent)
        return require('./commands/user')
          .client(opts.client)('useradd', opts.username, opts.password, opts.transmission_port)
      })
      .catch(helper.exit(i18n.__('Creating %s client', opts.client)))
      .then(function() {
        return new Promise(function(resolve, reject) {
          db.user.update(opts.username, {port: opts.transmission_port}, function(err) {
            if(err) {
              return reject(err)
            } else {
              resolve(0)
            }
          })
        })
      })
      .then(helper.exit(i18n.__('Creating %s', opts.username)))
      .catch(helper.exit(i18n.__('Creating %s', opts.username)))

    })

  })
}
<commit_msg>fix(useradd): Port update with no port<commit_after>var helper = require('./helpers/promise')
  , db = require('ezseed-database').db
  , logger = require('ezseed-logger')('useradd')
  , config = require('../lib/config.js')
  , async = require('async')
  , p = require('path')
  , i18n = require('i18n')
  , Promise = require('bluebird')

module.exports = function(opts) {

  require('./inquirer/useradd.js')(opts)
  .then(function(opts) {
    //require config + client installed?

    async.waterfall([
      function(done) {
        return db.user.create(opts, function(err) {
          if(err) {
            logger.error(err)
          }

          return done() //forcing no arguments to prevent async.waterfall to add those
        })
      },
      function(done) {
        //adds the ezseed user
        db.paths.save(
          p.join(config.home, opts.username, 'downloads'),
          {
            username: opts.username,
            default: true
          },
          function(err) {
            if(err) {
              logger.warn(err)
            }

            return done()
          }
        )
      }, function(done) {

        if(opts.client !== 'transmission') {
          return done()
        }

        require('local-port').findOpen(9002, function(err, open_port) {
          if(err) {
            logger.error('We could not find any open port')
            done(err)
          } else {
            opts.transmission_port = open_port
            done()
          }
        })
      }
    ], function(err) {
      if(err) {
        helper.exit(err)(1)
      }

      //adds the system user
      return require('./commands/user')
      .create(opts.username, opts.password)
      .catch(helper.exit(i18n.__('Creating system user')))
      .then(function() {

          //adds the client user (transmission or rtorrent)
        return require('./commands/user')
          .client(opts.client)('useradd', opts.username, opts.password, opts.transmission_port)
      })
      .catch(helper.exit(i18n.__('Creating %s client', opts.client)))
      .then(function() {
        return helper.condition(opts.client == 'transmission', function() {
          return new Promise(function(resolve, reject) {
            db.user.update(opts.username, {port: opts.transmission_port}, function(err) {
              if(err) {
                return reject(err)
              } else {
                resolve(0)
              }
            })
          })
        })
      })
      .then(helper.exit(i18n.__('Creating %s', opts.username)))
      .catch(helper.exit(i18n.__('Creating %s', opts.username)))

    })

  })
}
<|endoftext|>


<commit_before>(function () {

'use strict';

// The core module used for the OpenSlides site and the projector
angular.module('OpenSlidesApp.core', [
    'js-data',
    'gettext',
    'ngAnimate',
    'ngSanitize',  // TODO: only use this in functions that need it.
    'ui.bootstrap',
    'ui.tree',
    'pdf'
])

.config([
    'DSProvider',
    'DSHttpAdapterProvider',
    function(DSProvider, DSHttpAdapterProvider) {
        // Reloads everything after 5 minutes.
        // TODO: * find a way only to reload things that are still needed
        DSProvider.defaults.maxAge = 5 * 60 * 1000;  // 5 minutes
        DSProvider.defaults.reapAction = 'none';
        DSProvider.defaults.basePath = '/rest';
        DSProvider.defaults.afterReap = function(model, items) {
            if (items.length > 5) {
                model.findAll({}, {bypassCache: true});
            } else {
                _.forEach(items, function (item) {
                    model.refresh(item[model.idAttribute]);
                });
            }
        };
        DSHttpAdapterProvider.defaults.forceTrailingSlash = true;
    }
])

.factory('autoupdate', [
    'DS',
    '$rootScope',
    function (DS, $rootScope) {
        var url = location.origin + "/sockjs";
        var socket;
        var Autoupdate = {
            socket: null,
            message_receivers: [],
            connect: function () {
                var autoupdate = this;
                socket = this.socket = new SockJS(url);

                this.socket.onmessage = function (event) {
                    _.forEach(autoupdate.message_receivers, function (receiver) {
                        receiver(event.data);
                    });
                };

                this.socket.onopen = function () {
                    $rootScope.connected = true;
                };

                this.socket.onclose = function () {
                    $rootScope.connected = false;
                    autoupdate.connect()

                };
            },
            on_message: function (receiver) {
                this.message_receivers.push(receiver);
            },
            reconnect: function () {
                socket.close();
                Autoupdate.connect();
            }
        };
        $rootScope.connected = false;
        Autoupdate.connect();
        return Autoupdate;
    }
])

// gets all in OpenSlides available languages
.factory('Languages', [
    'gettext',
    'gettextCatalog',
    function (gettext, gettextCatalog) {
        return {
            // get all available languages
            getLanguages: function () {
                var current = gettextCatalog.getCurrentLanguage();
                // Define here new languages...
                var languages = [
                    { code: 'en', name: gettext('English') },
                    { code: 'de', name: gettext('German') },
                    { code: 'fr', name: gettext('French') },
                    { code: 'es', name: gettext('Spanish') },
                    { code: 'pt', name: gettext('Portuguese') },
                    { code: 'cs', name: gettext('Czech') },
                ];
                angular.forEach(languages, function (language) {
                    if (language.code == current)
                        language.selected = true;
                });
                return languages
            },
            // get detected browser language code
            getBrowserLanguage: function () {
                var lang = navigator.language || navigator.userLanguage;
                if (lang.indexOf('-') !== -1)
                    lang = lang.split('-')[0];
                if (lang.indexOf('_') !== -1)
                    lang = lang.split('_')[0];
                return lang;
            },
            // set current language and return updated languages object array
            setCurrentLanguage: function (lang) {
                var languages = this.getLanguages();
                angular.forEach(languages, function (language) {
                    language.selected = false;
                    if (language.code == lang) {
                        language.selected = true;
                        gettextCatalog.setCurrentLanguage(lang);
                        if (lang != 'en') {
                            gettextCatalog.loadRemote("static/i18n/" + lang + ".json");
                        }
                    }
                });
                return languages;
            }
        }
    }
])

// set browser language as default language for OpenSlides
.run([
    'gettextCatalog',
    'Languages',
    function(gettextCatalog, Languages) {
        // set detected browser language as default language (fallback: 'en')
        Languages.setCurrentLanguage(Languages.getBrowserLanguage());

        // Set this to true for debug. Helps to find untranslated strings by
        // adding "[MISSING]:".
        gettextCatalog.debug = false;
    }
])

.factory('dsEject', [
    'DS',
    function (DS) {
        return function (collection, instance) {
            var Resource = DS.definitions[collection];
            if (Resource.relationList) {
                Resource.relationList.forEach(function (relationDef) {
                    if (relationDef.foreignKey) {
                        var query = {};
                        query[relationDef.foreignKey] = instance[Resource.idAttribute];
                        Resource.getResource(relationDef.relation).ejectAll(query);
                    }
                });
            }
        }
    }
])

.run([
    'DS',
    'autoupdate',
    'dsEject',
    function (DS, autoupdate, dsEject) {
        autoupdate.on_message(function(data) {
            // TODO: when MODEL.find() is called after this
            //       a new request is fired. This could be a bug in DS

            // TODO: Do not send the status code to the client, but make the decission
            //       on the server side. It is an implementation detail, that tornado
            //       sends request to wsgi, which should not concern the client.
            console.log("Received object: " + data.collection + ", " + data.id);
            var instance = DS.get(data.collection, data.id);
            if (data.status_code == 200) {
                if (instance) {
                    // The instance is in the local db
                    dsEject(data.collection, instance);
                }
                DS.inject(data.collection, data.data);
            } else if (data.status_code == 404) {
                if (instance) {
                    // The instance is in the local db
                    dsEject(data.collection, instance);
                }
                DS.eject(data.collection, data.id);
            }
            // TODO: handle other statuscodes
        });
    }
])

.factory('loadGlobalData', [
    '$rootScope',
    '$http',
    'ChatMessage',
    'Config',
    'Projector',
    function ($rootScope, $http, ChatMessage, Config, Projector) {
        return function () {
            // Puts the config object into each scope.
            Config.findAll().then(function() {
                $rootScope.config = function(key) {
                    try {
                        return Config.get(key).value;
                    }
                    catch(err) {
                        console.log("Unkown config key: " + key);
                        return '';
                    }
                };
            });

            // Loads all projector data
            Projector.findAll();

            // Loads all chat messages data and their user_ids
            // TODO: add permission check if user has required chat permission
            // error if include 'operator' here:
            // "Circular dependency found: loadGlobalData <- operator <- loadGlobalData"
            //if (operator.hasPerms("core.can_use_chat")) {
                ChatMessage.findAll().then( function(chatmessages) {
                    angular.forEach(chatmessages, function (chatmessage) {
                        ChatMessage.loadRelations(chatmessage, 'user');
                    });
                });
            //}

            // Loads server time and calculates server offset
            $http.get('/core/servertime/').then(function(data) {
                $rootScope.serverOffset = Math.floor( Date.now() / 1000 - data.data );
            });
        };
    }
])

// Load the global data on startup
.run([
    'loadGlobalData',
    function(loadGlobalData) {
        loadGlobalData();
    }
])

.factory('jsDataModel', [
    '$http',
    'Projector',
    function($http, Projector) {
        var BaseModel = function() {};
        BaseModel.prototype.project = function() {
            return $http.post(
                '/rest/core/projector/1/prune_elements/',
                [{name: this.getResourceName(), id: this.id}]
            );
        };
        BaseModel.prototype.isProjected = function() {
            // Returns true if there is a projector element with the same
            // name and the same id.
            var projector = Projector.get(1);
            if (typeof projector === 'undefined') return false;
            var self = this;
            var predicate = function (element) {
                return element.name == self.getResourceName() &&
                       typeof element.id !== 'undefined' &&
                       element.id == self.id;
            };
            return typeof _.findKey(projector.elements, predicate) === 'string';
        };
        return BaseModel;
    }
])

.factory('Customslide', [
    'DS',
    'jsDataModel',
    'gettext',
    function(DS, jsDataModel, gettext) {
        var name = 'core/customslide';
        return DS.defineResource({
            name: name,
            useClass: jsDataModel,
            verboseName: gettext('Agenda item'),
            methods: {
                getResourceName: function () {
                    return name;
                },
                getAgendaTitle: function () {
                    return this.title;
                },
                // link name which is shown in search result
                getSearchResultName: function () {
                    return this.getAgendaTitle();
                },
                // subtitle of search result
                getSearchResultSubtitle: function () {
                    return "Agenda item";
                },
            },
            relations: {
                belongsTo: {
                    'agenda/item': {
                        localKey: 'agenda_item_id',
                        localField: 'agenda_item',
                    }
                },
                hasMany: {
                    'mediafiles/mediafile': {
                        localField: 'attachments',
                        localKeys: 'attachments_id',
                    }
                }
            }
        });
    }
])

.factory('Tag', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/tag',
        });
    }
])

.factory('Config', [
    '$http',
    'DS',
    function($http, DS) {
        var configOptions;
        return DS.defineResource({
            name: 'core/config',
            idAttribute: 'key',
            configOptions: configOptions,
            getConfigOptions: function () {
                if (!this.configOptions) {
                    this.configOptions = $http({ 'method': 'OPTIONS', 'url': '/rest/core/config/' });
                }
                return this.configOptions;
            },
        });
    }
])

.factory('ChatMessage', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/chatmessage',
            relations: {
                belongsTo: {
                    'users/user': {
                        localField: 'user',
                        localKey: 'user_id',
                    }
                }
            }
        });
    }
])

/* Model for a projector.
 *
 * At the moment we use only one projector, so there will be only one object
 * in this model. It has the id 1. For later releases there will be multiple
 * projector objects.
 *
 * This model uses onConfilict: 'replace' instead of 'merge'. This is necessary
 * because the keys of the projector objects can change and old keys have to
 * be removed. See http://www.js-data.io/docs/dsdefaults#onconflict for
 * more information.
 */
.factory('Projector', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/projector',
            onConflict: 'replace',
        });
    }
])

/* Converts number of seconds into string "hh:mm:ss" or "mm:ss" */
.filter('osSecondsToTime', [
    function () {
        return function (totalseconds) {
            var time;
            // floor returns the largest integer of the absolut value of totalseconds
            var total = Math.floor(Math.abs(totalseconds));
            var hh = Math.floor(total / 3600);
            var mm = Math.floor(total % 3600 / 60);
            var ss = Math.floor(total % 60);
            var zero = "0";
            // Add leading "0" for double digit values
            hh = (zero+hh).slice(-2);
            mm = (zero+mm).slice(-2);
            ss = (zero+ss).slice(-2);
            if (hh == "00")
                time =  mm + ':' + ss;
            else
                time = hh + ":" + mm + ":" + ss;
            if (totalseconds < 0)
                time = "-"+time;
            return time;
        };
    }
])

.filter('osFilter', [
    '$filter',
    function ($filter) {
        return function (array, string, getFilterString) {
            if (!string) {
                return array;
            }
            return Array.prototype.filter.call(array, function (item) {
                return getFilterString(item).toLowerCase().indexOf(string.toLowerCase()) > -1;
            });
        }
    }
])

/* Options for CKEditor used in various create and edit views. */
.value('CKEditorOptions', {
    allowedContent:
        'h1 h2 h3 p pre b i u strike strong em blockquote;' +
        'a[!href];' +
        'img[!src,alt]{width,height,float};' +
        'table tr th td caption;' +
        'li ol ul{list-style};' +
        'span{color,background-color};',
    extraPlugins: 'colorbutton',
    toolbarGroups: [
        { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
        { name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] },
        { name: 'forms', groups: [ 'forms' ] },
        { name: 'tools', groups: [ 'tools' ] },
        { name: 'about', groups: [ 'about' ] },
        { name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
        { name: 'others', groups: [ 'others' ] },
        '/',
        { name: 'styles', groups: [ 'styles' ] },
        { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
        { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi', 'paragraph' ] },
        { name: 'links', groups: [ 'links' ] },
        { name: 'insert', groups: [ 'insert' ] },
        { name: 'colors', groups: [ 'colors' ] }
    ],
    removeButtons: 'Anchor,SpecialChar,Subscript,Superscript,Styles,RemoveFormat,HorizontalRule'
})

// Make sure that the DS factories are loaded by making them a dependency
.run([
    'ChatMessage',
    'Config',
    'Customslide',
    'Projector',
    'Tag',
    function (ChatMessage, Config, Customslide, Projector, Tag) {}
]);

}());
<commit_msg>Refactor reconnect function of autoupdate.<commit_after>(function () {

'use strict';

// The core module used for the OpenSlides site and the projector
angular.module('OpenSlidesApp.core', [
    'js-data',
    'gettext',
    'ngAnimate',
    'ngSanitize',  // TODO: only use this in functions that need it.
    'ui.bootstrap',
    'ui.tree',
    'pdf'
])

.config([
    'DSProvider',
    'DSHttpAdapterProvider',
    function(DSProvider, DSHttpAdapterProvider) {
        // Reloads everything after 5 minutes.
        // TODO: * find a way only to reload things that are still needed
        DSProvider.defaults.maxAge = 5 * 60 * 1000;  // 5 minutes
        DSProvider.defaults.reapAction = 'none';
        DSProvider.defaults.basePath = '/rest';
        DSProvider.defaults.afterReap = function(model, items) {
            if (items.length > 5) {
                model.findAll({}, {bypassCache: true});
            } else {
                _.forEach(items, function (item) {
                    model.refresh(item[model.idAttribute]);
                });
            }
        };
        DSHttpAdapterProvider.defaults.forceTrailingSlash = true;
    }
])

.factory('autoupdate', [
    'DS',
    '$rootScope',
    function (DS, $rootScope) {
        var socket = null;
        var recInterval = null;
        $rootScope.connected = true;

        var newConnect = function () {
            socket = new SockJS(location.origin + "/sockjs");
            clearInterval(recInterval);
            socket.onopen = function () {
                $rootScope.connected = true;
            };
            socket.onclose = function () {
                $rootScope.connected = false;
                socket = null;
                recInterval = setInterval(function () {
                    newConnect();
                }, 1000);
            };
        };
        var Autoupdate = {
            messageReceivers: [],
            connect: function () {
                socket.onmessage = function (event) {
                    _.forEach(Autoupdate.messageReceivers, function (receiver) {
                        receiver(event.data);
                    });
                };
            },
            on_message: function (receiver) {
                this.messageReceivers.push(receiver);
            },
            reconnect: function () {
                socket.close();
            }
        };
        newConnect();
        Autoupdate.connect();
        return Autoupdate;
    }
])

// gets all in OpenSlides available languages
.factory('Languages', [
    'gettext',
    'gettextCatalog',
    function (gettext, gettextCatalog) {
        return {
            // get all available languages
            getLanguages: function () {
                var current = gettextCatalog.getCurrentLanguage();
                // Define here new languages...
                var languages = [
                    { code: 'en', name: gettext('English') },
                    { code: 'de', name: gettext('German') },
                    { code: 'fr', name: gettext('French') },
                    { code: 'es', name: gettext('Spanish') },
                    { code: 'pt', name: gettext('Portuguese') },
                    { code: 'cs', name: gettext('Czech') },
                ];
                angular.forEach(languages, function (language) {
                    if (language.code == current)
                        language.selected = true;
                });
                return languages
            },
            // get detected browser language code
            getBrowserLanguage: function () {
                var lang = navigator.language || navigator.userLanguage;
                if (lang.indexOf('-') !== -1)
                    lang = lang.split('-')[0];
                if (lang.indexOf('_') !== -1)
                    lang = lang.split('_')[0];
                return lang;
            },
            // set current language and return updated languages object array
            setCurrentLanguage: function (lang) {
                var languages = this.getLanguages();
                angular.forEach(languages, function (language) {
                    language.selected = false;
                    if (language.code == lang) {
                        language.selected = true;
                        gettextCatalog.setCurrentLanguage(lang);
                        if (lang != 'en') {
                            gettextCatalog.loadRemote("static/i18n/" + lang + ".json");
                        }
                    }
                });
                return languages;
            }
        }
    }
])

// set browser language as default language for OpenSlides
.run([
    'gettextCatalog',
    'Languages',
    function(gettextCatalog, Languages) {
        // set detected browser language as default language (fallback: 'en')
        Languages.setCurrentLanguage(Languages.getBrowserLanguage());

        // Set this to true for debug. Helps to find untranslated strings by
        // adding "[MISSING]:".
        gettextCatalog.debug = false;
    }
])

.factory('dsEject', [
    'DS',
    function (DS) {
        return function (collection, instance) {
            var Resource = DS.definitions[collection];
            if (Resource.relationList) {
                Resource.relationList.forEach(function (relationDef) {
                    if (relationDef.foreignKey) {
                        var query = {};
                        query[relationDef.foreignKey] = instance[Resource.idAttribute];
                        Resource.getResource(relationDef.relation).ejectAll(query);
                    }
                });
            }
        }
    }
])

.run([
    'DS',
    'autoupdate',
    'dsEject',
    function (DS, autoupdate, dsEject) {
        autoupdate.on_message(function(data) {
            // TODO: when MODEL.find() is called after this
            //       a new request is fired. This could be a bug in DS

            // TODO: Do not send the status code to the client, but make the decission
            //       on the server side. It is an implementation detail, that tornado
            //       sends request to wsgi, which should not concern the client.
            console.log("Received object: " + data.collection + ", " + data.id);
            var instance = DS.get(data.collection, data.id);
            if (data.status_code == 200) {
                if (instance) {
                    // The instance is in the local db
                    dsEject(data.collection, instance);
                }
                DS.inject(data.collection, data.data);
            } else if (data.status_code == 404) {
                if (instance) {
                    // The instance is in the local db
                    dsEject(data.collection, instance);
                }
                DS.eject(data.collection, data.id);
            }
            // TODO: handle other statuscodes
        });
    }
])

.factory('loadGlobalData', [
    '$rootScope',
    '$http',
    'ChatMessage',
    'Config',
    'Projector',
    function ($rootScope, $http, ChatMessage, Config, Projector) {
        return function () {
            // Puts the config object into each scope.
            Config.findAll().then(function() {
                $rootScope.config = function(key) {
                    try {
                        return Config.get(key).value;
                    }
                    catch(err) {
                        console.log("Unkown config key: " + key);
                        return '';
                    }
                };
            });

            // Loads all projector data
            Projector.findAll();

            // Loads all chat messages data and their user_ids
            // TODO: add permission check if user has required chat permission
            // error if include 'operator' here:
            // "Circular dependency found: loadGlobalData <- operator <- loadGlobalData"
            //if (operator.hasPerms("core.can_use_chat")) {
                ChatMessage.findAll().then( function(chatmessages) {
                    angular.forEach(chatmessages, function (chatmessage) {
                        ChatMessage.loadRelations(chatmessage, 'user');
                    });
                });
            //}

            // Loads server time and calculates server offset
            $http.get('/core/servertime/').then(function(data) {
                $rootScope.serverOffset = Math.floor( Date.now() / 1000 - data.data );
            });
        };
    }
])

// Load the global data on startup
.run([
    'loadGlobalData',
    function(loadGlobalData) {
        loadGlobalData();
    }
])

.factory('jsDataModel', [
    '$http',
    'Projector',
    function($http, Projector) {
        var BaseModel = function() {};
        BaseModel.prototype.project = function() {
            return $http.post(
                '/rest/core/projector/1/prune_elements/',
                [{name: this.getResourceName(), id: this.id}]
            );
        };
        BaseModel.prototype.isProjected = function() {
            // Returns true if there is a projector element with the same
            // name and the same id.
            var projector = Projector.get(1);
            if (typeof projector === 'undefined') return false;
            var self = this;
            var predicate = function (element) {
                return element.name == self.getResourceName() &&
                       typeof element.id !== 'undefined' &&
                       element.id == self.id;
            };
            return typeof _.findKey(projector.elements, predicate) === 'string';
        };
        return BaseModel;
    }
])

.factory('Customslide', [
    'DS',
    'jsDataModel',
    'gettext',
    function(DS, jsDataModel, gettext) {
        var name = 'core/customslide';
        return DS.defineResource({
            name: name,
            useClass: jsDataModel,
            verboseName: gettext('Agenda item'),
            methods: {
                getResourceName: function () {
                    return name;
                },
                getAgendaTitle: function () {
                    return this.title;
                },
                // link name which is shown in search result
                getSearchResultName: function () {
                    return this.getAgendaTitle();
                },
                // subtitle of search result
                getSearchResultSubtitle: function () {
                    return "Agenda item";
                },
            },
            relations: {
                belongsTo: {
                    'agenda/item': {
                        localKey: 'agenda_item_id',
                        localField: 'agenda_item',
                    }
                },
                hasMany: {
                    'mediafiles/mediafile': {
                        localField: 'attachments',
                        localKeys: 'attachments_id',
                    }
                }
            }
        });
    }
])

.factory('Tag', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/tag',
        });
    }
])

.factory('Config', [
    '$http',
    'DS',
    function($http, DS) {
        var configOptions;
        return DS.defineResource({
            name: 'core/config',
            idAttribute: 'key',
            configOptions: configOptions,
            getConfigOptions: function () {
                if (!this.configOptions) {
                    this.configOptions = $http({ 'method': 'OPTIONS', 'url': '/rest/core/config/' });
                }
                return this.configOptions;
            },
        });
    }
])

.factory('ChatMessage', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/chatmessage',
            relations: {
                belongsTo: {
                    'users/user': {
                        localField: 'user',
                        localKey: 'user_id',
                    }
                }
            }
        });
    }
])

/* Model for a projector.
 *
 * At the moment we use only one projector, so there will be only one object
 * in this model. It has the id 1. For later releases there will be multiple
 * projector objects.
 *
 * This model uses onConfilict: 'replace' instead of 'merge'. This is necessary
 * because the keys of the projector objects can change and old keys have to
 * be removed. See http://www.js-data.io/docs/dsdefaults#onconflict for
 * more information.
 */
.factory('Projector', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/projector',
            onConflict: 'replace',
        });
    }
])

/* Converts number of seconds into string "hh:mm:ss" or "mm:ss" */
.filter('osSecondsToTime', [
    function () {
        return function (totalseconds) {
            var time;
            // floor returns the largest integer of the absolut value of totalseconds
            var total = Math.floor(Math.abs(totalseconds));
            var hh = Math.floor(total / 3600);
            var mm = Math.floor(total % 3600 / 60);
            var ss = Math.floor(total % 60);
            var zero = "0";
            // Add leading "0" for double digit values
            hh = (zero+hh).slice(-2);
            mm = (zero+mm).slice(-2);
            ss = (zero+ss).slice(-2);
            if (hh == "00")
                time =  mm + ':' + ss;
            else
                time = hh + ":" + mm + ":" + ss;
            if (totalseconds < 0)
                time = "-"+time;
            return time;
        };
    }
])

.filter('osFilter', [
    '$filter',
    function ($filter) {
        return function (array, string, getFilterString) {
            if (!string) {
                return array;
            }
            return Array.prototype.filter.call(array, function (item) {
                return getFilterString(item).toLowerCase().indexOf(string.toLowerCase()) > -1;
            });
        }
    }
])

/* Options for CKEditor used in various create and edit views. */
.value('CKEditorOptions', {
    allowedContent:
        'h1 h2 h3 p pre b i u strike strong em blockquote;' +
        'a[!href];' +
        'img[!src,alt]{width,height,float};' +
        'table tr th td caption;' +
        'li ol ul{list-style};' +
        'span{color,background-color};',
    extraPlugins: 'colorbutton',
    toolbarGroups: [
        { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
        { name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] },
        { name: 'forms', groups: [ 'forms' ] },
        { name: 'tools', groups: [ 'tools' ] },
        { name: 'about', groups: [ 'about' ] },
        { name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
        { name: 'others', groups: [ 'others' ] },
        '/',
        { name: 'styles', groups: [ 'styles' ] },
        { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
        { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi', 'paragraph' ] },
        { name: 'links', groups: [ 'links' ] },
        { name: 'insert', groups: [ 'insert' ] },
        { name: 'colors', groups: [ 'colors' ] }
    ],
    removeButtons: 'Anchor,SpecialChar,Subscript,Superscript,Styles,RemoveFormat,HorizontalRule'
})

// Make sure that the DS factories are loaded by making them a dependency
.run([
    'ChatMessage',
    'Config',
    'Customslide',
    'Projector',
    'Tag',
    function (ChatMessage, Config, Customslide, Projector, Tag) {}
]);

}());
<|endoftext|>


<commit_before>var jsontr = require('./json-transform.js');

var items = require('./pages.json');
var transform = {
  nid: {
    newName: 'id',
    props: {value:String}
  },
  uuid: {
    props: {value:String}
  },
  title: {
    props: {value: String}
  },
  body: {
    props: {value: String}
  },
  field_parent_page: {
    newName: "parentPage",
    props: {target_id:{newName:'id',type:Number},target_uuid:{newName:'uuid',type:String}}
  },
  field_path: {
    newName: "path",
    props: {value: String}
  },
  field_sidebar: {
    newName: "sidebar",
    props: {target_uuid: {newName:'uuid',type:String}}
  },
  field_subnav: {
    newName: "subnav",
    props: {target_uuid: {newName:'uuid',type:String}}
  },
  field_serve_via_iframe: {
    newName: "iframe",
    props: {value:Boolean}
  }
};

console.log( JSON.stringify( jsontr.transform(items,transform) ) );
<commit_msg>added template field for pages<commit_after>var jsontr = require('./json-transform.js');

var items = require('./pages.json');
var transform = {
  nid: {
    newName: 'id',
    props: {value:String}
  },
  uuid: {
    props: {value:String}
  },
  title: {
    props: {value: String}
  },
  body: {
    props: {value: String}
  },
  field_parent_page: {
    newName: "parentPage",
    props: {target_id:{newName:'id',type:Number},target_uuid:{newName:'uuid',type:String}}
  },
  field_path: {
    newName: "path",
    props: {value: String}
  },
  field_sidebar: {
    newName: "sidebar",
    props: {target_uuid: {newName:'uuid',type:String}}
  },
  field_subnav: {
    newName: "subnav",
    props: {target_uuid: {newName:'uuid',type:String}}
  },
  field_serve_via_iframe: {
    newName: "iframe",
    props: {value:Boolean}
  },
  field_advanced_alt_template: {
    newName: "template",
    props: {value:String}
  }
};

console.log( JSON.stringify( jsontr.transform(items,transform) ) );
<|endoftext|>


<commit_before>'use strict';

const powName = 'pow';

const obj1 = {
  fn1: function inc(a) {
    return ++a;
  },
  sum: function(a, b) {
    return a + b;
  },
  inc(a) {
    return ++a;
  },
  max: (a, b) => {
    return a > b ? a : b;
  },
  min: (a, b) => (a < b ? a : b),
  dec: a => --a,
  [powName](a, b) {
    return Math.pow(a, b);
  }
};

console.log('obj1.fn1.name = ' + obj1.fn1.name);
console.log('obj1.sum.name = ' + obj1.sum.name);
console.log('obj1.inc.name = ' + obj1.inc.name);
console.log('obj1.max.name = ' + obj1.max.name);
console.log('obj1.min.name = ' + obj1.min.name);
console.log('obj1.dec.name = ' + obj1.dec.name);

console.log('obj1.fn1(5) = ' + obj1.fn1(5));
console.log('obj1.sum(1, 3) = ' + obj1.sum(1, 3));
console.log('obj1.max(8, 6) = ' + obj1.max(8, 6));

console.log('obj1.pow(8, 6) = ' + obj1.pow(8, 6));
console.log('obj1.[\'pow\'](8, 6) = ' + obj1['pow'](8, 6));
<commit_msg>Fix bug in example output<commit_after>'use strict';

const powName = 'pow';

const obj1 = {
  fn1: function inc(a) {
    return ++a;
  },
  sum: function(a, b) {
    return a + b;
  },
  inc(a) {
    return ++a;
  },
  max: (a, b) => {
    return a > b ? a : b;
  },
  min: (a, b) => (a < b ? a : b),
  dec: a => --a,
  [powName](a, b) {
    return Math.pow(a, b);
  }
};

console.log('obj1.fn1.name = ' + obj1.fn1.name);
console.log('obj1.sum.name = ' + obj1.sum.name);
console.log('obj1.inc.name = ' + obj1.inc.name);
console.log('obj1.max.name = ' + obj1.max.name);
console.log('obj1.min.name = ' + obj1.min.name);
console.log('obj1.dec.name = ' + obj1.dec.name);

console.log('obj1.fn1(5) = ' + obj1.fn1(5));
console.log('obj1.sum(1, 3) = ' + obj1.sum(1, 3));
console.log('obj1.max(8, 6) = ' + obj1.max(8, 6));

console.log('obj1.pow(8, 6) = ' + obj1.pow(8, 6));
console.log('obj1[\'pow\'](8, 6) = ' + obj1['pow'](8, 6));
<|endoftext|>


<commit_before>(function ($) {
    $.widget("roicp.treeview", {
        self: null,
        _treeViewDataSource: null,

        options: {
            //treeViewDataSource: null
        },

        _create: function () {
            self = this;
            self._initializeTreeViewBaseTag();
            self._getChildrenNodes(0, null, self._getRootNodesCompleted);
        },

        _initializeTreeViewBaseTag: function () {
            var baseTag = $("
");
            baseTag.addClass("treeview");
            baseTag.appendTo(self.element);
        },

        _getChildrenNodes: function (itemId, currentItemDataSource, funcCallback) {
            $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "/Home/LongGetCategories",
                data: "{ 'upperId':'" + itemId + "' }",
                dataType: "json",
                success: function (data) {
                    funcCallback(currentItemDataSource, data);
                },
                error: function () {
                    alert("An error occurred when trying to obtain the children");
                }
            });
        },

        _getRootNodesCompleted: function (currentItemDataSource, data) {
            self._treeViewDataSource = data;
            var baseElement = self.element.children(".treeview").first();

            self._createNode(self._treeViewDataSource, baseElement);
        },

        _getChildrenNodesCompleted: function (currentItemDataSource, data) {
            currentItemDataSource.Children = data;
            if (currentItemDataSource.Children != null && currentItemDataSource.Children.length > 0) {
                var baseElement = self.element.find("li[id='" + currentItemDataSource.Id + "']").first();

                var childNodeTag = $("
");

                self._createNode(currentItemDataSource.Children, childNodeTag);

                childNodeTag.appendTo(baseElement);
            }
        },

        _expandNode: function (itemNodeId) {
            var currentItem = self._findItemInDataSource(self._treeViewDataSource, itemNodeId);
            var currentNode = self.element.find("li[id='" + currentItem.Id + "']").first();

            self._switchCssClass(currentNode.children(".span-expand"));

            self._getChildrenNodes(currentItem.Id, currentItem, self._getChildrenNodesCompleted);
        },

        _collapseNode: function (itemNodeId) {
            var currentItem = self._findItemInDataSource(self._treeViewDataSource, itemNodeId);
            var currentNode = self.element.find("li[id='" + currentItem.Id + "']").first();

            self._switchCssClass(currentNode.children(".span-collapse"));

            currentNode.children("ul").remove();

            currentItem.Children = null;
        },

        _createNode: function (dataSource, baseElement) {
            for (var i = 0; i < dataSource.length; i++) {
                var item = dataSource[i];
                var hitPosition;

                if (dataSource.length == 1) {
                    hitPosition = "hit-single";
                } else {
                    switch (i) {
                        case 0:
                            hitPosition = "hit-first";
                            break;
                        case dataSource.length - 1:
                            hitPosition = "hit-last";
                            break;
                        default:
                            hitPosition = "";
                            break;
                    }
                }

                var nodeText = "";
                nodeText += ((item.HasChild) ? " " : " ");
                nodeText += " " + item.Name + "";
                nodeText += ((item.Selectable) ? " Select" : "");

                var nodeInnerTag = $("
");
                nodeInnerTag.html(nodeText).attr("id", item.Id);
                nodeInnerTag.addClass("node-bg-vimage");

                if (item.HasChild) {
                    nodeInnerTag.removeClass("without-child-node").addClass("with-child-node");
                } else {
                    nodeInnerTag.removeClass("with-child-node").addClass("without-child-node");
                }

                if (hitPosition == "hit-last" || hitPosition == "hit-single") {
                    nodeInnerTag.removeClass("node-bg-vimage");
                }

                nodeInnerTag.appendTo(baseElement);
            }

            baseElement.find(".span-expand").bind("click", function () {
                self._expandNode($(this).attr("id"));
            });

            baseElement.find(".span-selectable").bind("click", function () {
                self._selectNode($(this).attr("id"));
            });
        },

        _switchCssClass: function (workNode) {
            workNode.unbind('click');

            if (workNode.hasClass("span-collapse")) {
                workNode.removeClass("span-collapse").addClass("span-expand");

                workNode.bind("click", function () {
                    self._expandNode($(this).attr("id"));
                });
            } else {
                if (workNode.hasClass("span-expand")) {
                    workNode.removeClass("span-expand").addClass("span-collapse");

                    workNode.bind("click", function () {
                        self._collapseNode($(this).attr("id"));
                    });
                }
            }
        },

        _findItemInDataSource: function (dataSource, itemId) {
            var currentNode = null;

            for (var i = 0; i < dataSource.length; i++) {
                var item = dataSource[i];

                if (item.Id == itemId) {
                    currentNode = item;
                    break;
                }

                if (item.Children != null && item.Children.length > 0) {
                    currentNode = self._findItemInDataSource(item.Children, itemId);

                    if (currentNode != null) {
                        break;
                    }
                }
            }

            return currentNode;
        },

        _selectNode: function (itemNodeId) {
            var item = self._findItemInDataSource(self._treeViewDataSource, itemNodeId);
            alert(item.Description);
        },

        _setOption: function (key, value) {
            // Use the _setOption method to respond to changes to options
            switch (key) {
                case "length":
                    break;
            }

            $.Widget.prototype._setOption.apply(this, arguments);
        },

        destroy: function () {
            // Use the destroy method to reverse everything your plugin has applied
            $.Widget.prototype.destroy.call(this);
        }
    });
})(jQuery);<commit_msg>updating setOption method<commit_after>(function ($) {
    $.widget("roicp.treeview", {
        self: null,
        _treeViewDataSource: null,

        options: {
            //treeViewDataSource: null
        },

        _create: function () {
            self = this;
            self._initializeTreeViewBaseTag();
            self._getChildrenNodes(0, null, self._getRootNodesCompleted);
        },

        _initializeTreeViewBaseTag: function () {
            var baseTag = $("
");
            baseTag.addClass("treeview");
            baseTag.appendTo(self.element);
        },

        _getChildrenNodes: function (itemId, currentItemDataSource, funcCallback) {
            $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "/Home/LongGetCategories",
                data: "{ 'upperId':'" + itemId + "' }",
                dataType: "json",
                success: function (data) {
                    funcCallback(currentItemDataSource, data);
                },
                error: function () {
                    alert("An error occurred when trying to obtain the children");
                }
            });
        },

        _getRootNodesCompleted: function (currentItemDataSource, data) {
            self._treeViewDataSource = data;
            var baseElement = self.element.children(".treeview").first();

            self._createNode(self._treeViewDataSource, baseElement);
        },

        _getChildrenNodesCompleted: function (currentItemDataSource, data) {
            currentItemDataSource.Children = data;
            if (currentItemDataSource.Children != null && currentItemDataSource.Children.length > 0) {
                var baseElement = self.element.find("li[id='" + currentItemDataSource.Id + "']").first();

                var childNodeTag = $("
");

                self._createNode(currentItemDataSource.Children, childNodeTag);

                childNodeTag.appendTo(baseElement);
            }
        },

        _expandNode: function (itemNodeId) {
            var currentItem = self._findItemInDataSource(self._treeViewDataSource, itemNodeId);
            var currentNode = self.element.find("li[id='" + currentItem.Id + "']").first();

            self._switchCssClass(currentNode.children(".span-expand"));

            self._getChildrenNodes(currentItem.Id, currentItem, self._getChildrenNodesCompleted);
        },

        _collapseNode: function (itemNodeId) {
            var currentItem = self._findItemInDataSource(self._treeViewDataSource, itemNodeId);
            var currentNode = self.element.find("li[id='" + currentItem.Id + "']").first();

            self._switchCssClass(currentNode.children(".span-collapse"));

            currentNode.children("ul").remove();

            currentItem.Children = null;
        },

        _createNode: function (dataSource, baseElement) {
            for (var i = 0; i < dataSource.length; i++) {
                var item = dataSource[i];
                var hitPosition;

                if (dataSource.length == 1) {
                    hitPosition = "hit-single";
                } else {
                    switch (i) {
                        case 0:
                            hitPosition = "hit-first";
                            break;
                        case dataSource.length - 1:
                            hitPosition = "hit-last";
                            break;
                        default:
                            hitPosition = "";
                            break;
                    }
                }

                var nodeText = "";
                nodeText += ((item.HasChild) ? " " : " ");
                nodeText += " " + item.Name + "";
                nodeText += ((item.Selectable) ? " Select" : "");

                var nodeInnerTag = $("
");
                nodeInnerTag.html(nodeText).attr("id", item.Id);
                nodeInnerTag.addClass("node-bg-vimage");

                if (item.HasChild) {
                    nodeInnerTag.removeClass("without-child-node").addClass("with-child-node");
                } else {
                    nodeInnerTag.removeClass("with-child-node").addClass("without-child-node");
                }

                if (hitPosition == "hit-last" || hitPosition == "hit-single") {
                    nodeInnerTag.removeClass("node-bg-vimage");
                }

                nodeInnerTag.appendTo(baseElement);
            }

            baseElement.find(".span-expand").bind("click", function () {
                self._expandNode($(this).attr("id"));
            });

            baseElement.find(".span-selectable").bind("click", function () {
                self._selectNode($(this).attr("id"));
            });
        },

        _switchCssClass: function (workNode) {
            workNode.unbind('click');

            if (workNode.hasClass("span-collapse")) {
                workNode.removeClass("span-collapse").addClass("span-expand");

                workNode.bind("click", function () {
                    self._expandNode($(this).attr("id"));
                });
            } else {
                if (workNode.hasClass("span-expand")) {
                    workNode.removeClass("span-expand").addClass("span-collapse");

                    workNode.bind("click", function () {
                        self._collapseNode($(this).attr("id"));
                    });
                }
            }
        },

        _findItemInDataSource: function (dataSource, itemId) {
            var currentNode = null;

            for (var i = 0; i < dataSource.length; i++) {
                var item = dataSource[i];

                if (item.Id == itemId) {
                    currentNode = item;
                    break;
                }

                if (item.Children != null && item.Children.length > 0) {
                    currentNode = self._findItemInDataSource(item.Children, itemId);

                    if (currentNode != null) {
                        break;
                    }
                }
            }

            return currentNode;
        },

        _selectNode: function (itemNodeId) {
            var item = self._findItemInDataSource(self._treeViewDataSource, itemNodeId);
            alert(item.Description);
        },

        _setOption: function (key, value) {
            this._super(key, value);
        },

        destroy: function () {
            // Use the destroy method to reverse everything your plugin has applied
            $.Widget.prototype.destroy.call(this);
        }
    });
})(jQuery);<|endoftext|>


<commit_before>app
.directive('lineplot', ['d3Service','$document', function(d3,$document) {
  	return {
    	restrict: 'EA',
    	templateUrl: './directives/lineplot.html',
		link: function(scope, element, attributes) {

			var margin = {top: 40, right: 40, bottom: 40, left: 40};

			var temp = element[0].getElementsByTagName("div")[0];
			var el = temp.getElementsByTagName("div")[0];

			var width = temp.clientWidth;
			var height = temp.clientHeight;
			var svg = d3.select(el).append("svg")
					.attr("preserveAspectRatio", "xMinYMin meet")
                    .attr("viewBox", "0 0 "+width+" "+height+"")
                    .classed("svg-content", true),
			g = svg.append("g");

			var transHeight = height*.8 + 10 ;

			var x = d3.scaleLinear()
						.domain([0, 1])
						.range([0, width*.9]);

			var y = d3.scaleLinear()
						.domain([0, 1])
						.range([height*.8, 0]);

			g.append("g")
				.attr("transform", "translate(50,10)")
				.attr("class", "axis")
				.call(d3.axisLeft(y).tickSize(-width*.9));

			g.append("g")
				.attr("transform", "translate(50,"+ transHeight + ")")
				.attr("class", "axis")
				.call(d3.axisBottom(x).tickSize(-height*.8));

			g.selectAll("path")
				.attr("stroke","none");

			g.selectAll("line")
				.attr("opacity", 0.1);

			scope.goHome = function(){
				alert("HOME")
			}
		}
  	};
}])<commit_msg>Plot data<commit_after>app
.directive('lineplot', ['d3Service','dashboardService','$interval', function(d3,db,$interval) {
  	return {
    	restrict: 'EA',
    	templateUrl: './directives/lineplot.html',
		link: function(scope, element, attributes) {
			var vm = this;
			var theInterval = $interval(function(){
				getData();
			}.bind(vm), 1000);

			var data = [{x:"0",y:"0"},{x:"0.5",y:"0.4"},{x:"1",y:"0.2"},{x:"1.2",y:"0.6"},{x:"1.4",y:"1"},{x:"1.8",y:"0.2"}];

			var margin = {top: 10, right: 40, bottom: 10, left: 40};

			var temp = element[0].getElementsByTagName("div")[0];
			var el = temp.getElementsByTagName("div")[0];

			var width = temp.clientWidth;
			var height = temp.clientHeight;
			var svg = d3.select(el).append("svg")
					.attr("preserveAspectRatio", "xMinYMin meet")
                    .attr("viewBox", "0 0 "+width+" "+height+"")
                    .classed("svg-content", true),
			g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");;

			// Grids //
			var transHeight = height*.9;
			var transWidth = width*.9;

			var x = d3.scaleLinear()
						.domain(d3.extent(data, function(d) { return d.x; }))
						.rangeRound([0, transWidth]);

			var y = d3.scaleLinear()
						.domain(d3.extent(data, function(d) { return d.y; }))
						.rangeRound([transHeight, 0]);

			var line = d3.line()
							.x(function(d) { return x(d.x); })
							.y(function(d) { return y(d.y); });

			g.append("g")
				.attr("transform", "translate(0,0)")
				.attr("class", "axis")
				.call(d3.axisLeft(y).tickSize(-transWidth));

			g.append("g")
				.attr("transform", "translate(0,"+ transHeight + ")")
				.attr("class", "axis")
				.call(d3.axisBottom(x).tickSize(-transHeight));

			g.selectAll("path")
				.attr("stroke","none");

			g.selectAll("line")
				.attr("opacity", 0.1);
			// End Grids //

			// Plot lines//
			g.append("path")
				.datum(data)
				.attr("fill", "none")
				.attr("stroke", "steelblue")
				.attr("stroke-linejoin", "round")
				.attr("stroke-linecap", "round")
				.attr("stroke-width", 1.5)
				.attr("d", line);

			// End plot lines //

			function getData(){
				db.getTelemetry()
				.then(function(response) {
					vm.telemetry = response.data;
				});
			}

			scope.goHome = function(){
				alert("HOME!")
			}
		}
  	};
}])<|endoftext|>


<commit_before>(function () {

'use strict';

// The core module used for the OpenSlides site and the projector
angular.module('OpenSlidesApp.core', [
    'js-data',
    'gettext',
    'ngAnimate',
    'ngSanitize',  // TODO: only use this in functions that need it.
    'ui.bootstrap',
    'ui.tree',
    'pdf'
])

.config([
    'DSProvider',
    'DSHttpAdapterProvider',
    function(DSProvider, DSHttpAdapterProvider) {
        // Reloads everything after 5 minutes.
        // TODO: * find a way only to reload things that are still needed
        DSProvider.defaults.maxAge = 5 * 60 * 1000;  // 5 minutes
        DSProvider.defaults.reapAction = 'none';
        DSProvider.defaults.basePath = '/rest';
        DSProvider.defaults.afterReap = function(model, items) {
            if (items.length > 5) {
                model.findAll({}, {bypassCache: true});
            } else {
                _.forEach(items, function (item) {
                    model.refresh(item[model.idAttribute]);
                });
            }
        };
        DSHttpAdapterProvider.defaults.forceTrailingSlash = true;
    }
])

.factory('autoupdate', [
    'DS',
    '$rootScope',
    function (DS, $rootScope) {
        var socket = null;
        var recInterval = null;
        $rootScope.connected = true;

        var newConnect = function () {
            socket = new SockJS(location.origin + "/sockjs");
            clearInterval(recInterval);
            socket.onopen = function () {
                $rootScope.connected = true;
            };
            socket.onclose = function () {
                $rootScope.connected = false;
                socket = null;
                recInterval = setInterval(function () {
                    newConnect();
                }, 1000);
            };
        };
        var Autoupdate = {
            messageReceivers: [],
            connect: function () {
                socket.onmessage = function (event) {
                    _.forEach(Autoupdate.messageReceivers, function (receiver) {
                        receiver(event.data);
                    });
                };
            },
            on_message: function (receiver) {
                this.messageReceivers.push(receiver);
            },
            reconnect: function () {
                socket.close();
            }
        };
        newConnect();
        Autoupdate.connect();
        return Autoupdate;
    }
])

// gets all in OpenSlides available languages
.factory('Languages', [
    'gettext',
    'gettextCatalog',
    function (gettext, gettextCatalog) {
        return {
            // get all available languages
            getLanguages: function () {
                var current = gettextCatalog.getCurrentLanguage();
                // Define here new languages...
                var languages = [
                    { code: 'en', name: gettext('English') },
                    { code: 'de', name: gettext('German') },
                    { code: 'fr', name: gettext('French') },
                    { code: 'es', name: gettext('Spanish') },
                    { code: 'pt', name: gettext('Portuguese') },
                    { code: 'cs', name: gettext('Czech') },
                ];
                angular.forEach(languages, function (language) {
                    if (language.code == current)
                        language.selected = true;
                });
                return languages
            },
            // get detected browser language code
            getBrowserLanguage: function () {
                var lang = navigator.language || navigator.userLanguage;
                if (lang.indexOf('-') !== -1)
                    lang = lang.split('-')[0];
                if (lang.indexOf('_') !== -1)
                    lang = lang.split('_')[0];
                return lang;
            },
            // set current language and return updated languages object array
            setCurrentLanguage: function (lang) {
                var languages = this.getLanguages();
                angular.forEach(languages, function (language) {
                    language.selected = false;
                    if (language.code == lang) {
                        language.selected = true;
                        gettextCatalog.setCurrentLanguage(lang);
                        if (lang != 'en') {
                            gettextCatalog.loadRemote("static/i18n/" + lang + ".json");
                        }
                    }
                });
                return languages;
            }
        }
    }
])

// set browser language as default language for OpenSlides
.run([
    'gettextCatalog',
    'Languages',
    function(gettextCatalog, Languages) {
        // set detected browser language as default language (fallback: 'en')
        Languages.setCurrentLanguage(Languages.getBrowserLanguage());

        // Set this to true for debug. Helps to find untranslated strings by
        // adding "[MISSING]:".
        gettextCatalog.debug = false;
    }
])

.factory('dsEject', [
    'DS',
    function (DS) {
        return function (collection, instance) {
            var Resource = DS.definitions[collection];
            if (Resource.relationList) {
                Resource.relationList.forEach(function (relationDef) {
                    if (relationDef.foreignKey) {
                        var query = {};
                        query[relationDef.foreignKey] = instance[Resource.idAttribute];
                        Resource.getResource(relationDef.relation).ejectAll(query);
                    }
                });
            }
        }
    }
])

.run([
    'DS',
    'autoupdate',
    'dsEject',
    function (DS, autoupdate, dsEject) {
        autoupdate.on_message(function(data) {
            // TODO: when MODEL.find() is called after this
            //       a new request is fired. This could be a bug in DS

            // TODO: Do not send the status code to the client, but make the decission
            //       on the server side. It is an implementation detail, that tornado
            //       sends request to wsgi, which should not concern the client.
            console.log("Received object: " + data.collection + ", " + data.id);
            var instance = DS.get(data.collection, data.id);
            if (data.status_code == 200) {
                if (instance) {
                    // The instance is in the local db
                    dsEject(data.collection, instance);
                }
                DS.inject(data.collection, data.data);
            } else if (data.status_code == 404) {
                if (instance) {
                    // The instance is in the local db
                    dsEject(data.collection, instance);
                }
                DS.eject(data.collection, data.id);
            }
            // TODO: handle other statuscodes
        });
    }
])

.factory('loadGlobalData', [
    '$rootScope',
    '$http',
    'ChatMessage',
    'Config',
    'Projector',
    function ($rootScope, $http, ChatMessage, Config, Projector) {
        return function () {
            // Puts the config object into each scope.
            Config.findAll().then(function() {
                $rootScope.config = function(key) {
                    try {
                        return Config.get(key).value;
                    }
                    catch(err) {
                        console.log("Unkown config key: " + key);
                        return '';
                    }
                };
            });

            // Loads all projector data
            Projector.findAll();

            // Loads all chat messages data and their user_ids
            // TODO: add permission check if user has required chat permission
            // error if include 'operator' here:
            // "Circular dependency found: loadGlobalData <- operator <- loadGlobalData"
            //if (operator.hasPerms("core.can_use_chat")) {
                ChatMessage.findAll().then( function(chatmessages) {
                    angular.forEach(chatmessages, function (chatmessage) {
                        ChatMessage.loadRelations(chatmessage, 'user');
                    });
                });
            //}

            // Loads server time and calculates server offset
            $http.get('/core/servertime/').then(function(data) {
                $rootScope.serverOffset = Math.floor( Date.now() / 1000 - data.data );
            });
        };
    }
])

// Load the global data on startup
.run([
    'loadGlobalData',
    function(loadGlobalData) {
        loadGlobalData();
    }
])

.factory('jsDataModel', [
    '$http',
    'Projector',
    function($http, Projector) {
        var BaseModel = function() {};
        BaseModel.prototype.project = function() {
            return $http.post(
                '/rest/core/projector/1/prune_elements/',
                [{name: this.getResourceName(), id: this.id}]
            );
        };
        BaseModel.prototype.isProjected = function() {
            // Returns true if there is a projector element with the same
            // name and the same id.
            var projector = Projector.get(1);
            if (typeof projector === 'undefined') return false;
            var self = this;
            var predicate = function (element) {
                return element.name == self.getResourceName() &&
                       typeof element.id !== 'undefined' &&
                       element.id == self.id;
            };
            return typeof _.findKey(projector.elements, predicate) === 'string';
        };
        return BaseModel;
    }
])

.factory('Customslide', [
    'DS',
    'jsDataModel',
    'gettext',
    function(DS, jsDataModel, gettext) {
        var name = 'core/customslide';
        return DS.defineResource({
            name: name,
            useClass: jsDataModel,
            verboseName: gettext('Agenda item'),
            methods: {
                getResourceName: function () {
                    return name;
                },
                getAgendaTitle: function () {
                    return this.title;
                },
                // link name which is shown in search result
                getSearchResultName: function () {
                    return this.getAgendaTitle();
                },
                // subtitle of search result
                getSearchResultSubtitle: function () {
                    return "Agenda item";
                },
            },
            relations: {
                belongsTo: {
                    'agenda/item': {
                        localKey: 'agenda_item_id',
                        localField: 'agenda_item',
                    }
                },
                hasMany: {
                    'mediafiles/mediafile': {
                        localField: 'attachments',
                        localKeys: 'attachments_id',
                    }
                }
            }
        });
    }
])

.factory('Tag', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/tag',
        });
    }
])

.factory('Config', [
    '$http',
    'DS',
    function($http, DS) {
        var configOptions;
        return DS.defineResource({
            name: 'core/config',
            idAttribute: 'key',
            configOptions: configOptions,
            getConfigOptions: function () {
                if (!this.configOptions) {
                    this.configOptions = $http({ 'method': 'OPTIONS', 'url': '/rest/core/config/' });
                }
                return this.configOptions;
            },
        });
    }
])

.factory('ChatMessage', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/chatmessage',
            relations: {
                belongsTo: {
                    'users/user': {
                        localField: 'user',
                        localKey: 'user_id',
                    }
                }
            }
        });
    }
])

/* Model for a projector.
 *
 * At the moment we use only one projector, so there will be only one object
 * in this model. It has the id 1. For later releases there will be multiple
 * projector objects.
 *
 * This model uses onConfilict: 'replace' instead of 'merge'. This is necessary
 * because the keys of the projector objects can change and old keys have to
 * be removed. See http://www.js-data.io/docs/dsdefaults#onconflict for
 * more information.
 */
.factory('Projector', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/projector',
            onConflict: 'replace',
        });
    }
])

/* Converts number of seconds into string "hh:mm:ss" or "mm:ss" */
.filter('osSecondsToTime', [
    function () {
        return function (totalseconds) {
            var time;
            // floor returns the largest integer of the absolut value of totalseconds
            var total = Math.floor(Math.abs(totalseconds));
            var hh = Math.floor(total / 3600);
            var mm = Math.floor(total % 3600 / 60);
            var ss = Math.floor(total % 60);
            var zero = "0";
            // Add leading "0" for double digit values
            hh = (zero+hh).slice(-2);
            mm = (zero+mm).slice(-2);
            ss = (zero+ss).slice(-2);
            if (hh == "00")
                time =  mm + ':' + ss;
            else
                time = hh + ":" + mm + ":" + ss;
            if (totalseconds < 0)
                time = "-"+time;
            return time;
        };
    }
])

.filter('osFilter', [
    '$filter',
    function ($filter) {
        return function (array, string, getFilterString) {
            if (!string) {
                return array;
            }
            return Array.prototype.filter.call(array, function (item) {
                return getFilterString(item).toLowerCase().indexOf(string.toLowerCase()) > -1;
            });
        }
    }
])

/* Options for CKEditor used in various create and edit views. */
.value('CKEditorOptions', {
    allowedContent:
        'h1 h2 h3 p pre b i u strike strong em blockquote;' +
        'a[!href];' +
        'img[!src,alt]{width,height,float};' +
        'table tr th td caption;' +
        'li ol ul{list-style};' +
        'span{color,background-color};',
    extraPlugins: 'colorbutton',
    toolbarGroups: [
        { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
        { name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] },
        { name: 'forms', groups: [ 'forms' ] },
        { name: 'tools', groups: [ 'tools' ] },
        { name: 'about', groups: [ 'about' ] },
        { name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
        { name: 'others', groups: [ 'others' ] },
        '/',
        { name: 'styles', groups: [ 'styles' ] },
        { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
        { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi', 'paragraph' ] },
        { name: 'links', groups: [ 'links' ] },
        { name: 'insert', groups: [ 'insert' ] },
        { name: 'colors', groups: [ 'colors' ] }
    ],
    removeButtons: 'Anchor,SpecialChar,Subscript,Superscript,Styles,RemoveFormat,HorizontalRule'
})

// Make sure that the DS factories are loaded by making them a dependency
.run([
    'ChatMessage',
    'Config',
    'Customslide',
    'Projector',
    'Tag',
    function (ChatMessage, Config, Customslide, Projector, Tag) {}
]);

}());
<commit_msg>Fix the autoupdate<commit_after>(function () {

'use strict';

// The core module used for the OpenSlides site and the projector
angular.module('OpenSlidesApp.core', [
    'js-data',
    'gettext',
    'ngAnimate',
    'ngSanitize',  // TODO: only use this in functions that need it.
    'ui.bootstrap',
    'ui.tree',
    'pdf'
])

.config([
    'DSProvider',
    'DSHttpAdapterProvider',
    function(DSProvider, DSHttpAdapterProvider) {
        // Reloads everything after 5 minutes.
        // TODO: * find a way only to reload things that are still needed
        DSProvider.defaults.maxAge = 5 * 60 * 1000;  // 5 minutes
        DSProvider.defaults.reapAction = 'none';
        DSProvider.defaults.basePath = '/rest';
        DSProvider.defaults.afterReap = function(model, items) {
            if (items.length > 5) {
                model.findAll({}, {bypassCache: true});
            } else {
                _.forEach(items, function (item) {
                    model.refresh(item[model.idAttribute]);
                });
            }
        };
        DSHttpAdapterProvider.defaults.forceTrailingSlash = true;
    }
])

.factory('autoupdate', [
    'DS',
    '$rootScope',
    function (DS, $rootScope) {
        var socket = null;
        var recInterval = null;
        $rootScope.connected = true;

        var Autoupdate = {
            messageReceivers: [],
            onMessage: function (receiver) {
                this.messageReceivers.push(receiver);
            },
            reconnect: function () {
                socket.close();
            }
        };
        var newConnect = function () {
            socket = new SockJS(location.origin + "/sockjs");
            clearInterval(recInterval);
            socket.onopen = function () {
                $rootScope.connected = true;
            };
            socket.onclose = function () {
                $rootScope.connected = false;
                socket = null;
                recInterval = setInterval(function () {
                    newConnect();
                }, 1000);
            };
            socket.onmessage = function (event) {
                _.forEach(Autoupdate.messageReceivers, function (receiver) {
                    receiver(event.data);
                });
            };
        };

        newConnect();
        return Autoupdate;
    }
])

// gets all in OpenSlides available languages
.factory('Languages', [
    'gettext',
    'gettextCatalog',
    function (gettext, gettextCatalog) {
        return {
            // get all available languages
            getLanguages: function () {
                var current = gettextCatalog.getCurrentLanguage();
                // Define here new languages...
                var languages = [
                    { code: 'en', name: gettext('English') },
                    { code: 'de', name: gettext('German') },
                    { code: 'fr', name: gettext('French') },
                    { code: 'es', name: gettext('Spanish') },
                    { code: 'pt', name: gettext('Portuguese') },
                    { code: 'cs', name: gettext('Czech') },
                ];
                angular.forEach(languages, function (language) {
                    if (language.code == current)
                        language.selected = true;
                });
                return languages
            },
            // get detected browser language code
            getBrowserLanguage: function () {
                var lang = navigator.language || navigator.userLanguage;
                if (lang.indexOf('-') !== -1)
                    lang = lang.split('-')[0];
                if (lang.indexOf('_') !== -1)
                    lang = lang.split('_')[0];
                return lang;
            },
            // set current language and return updated languages object array
            setCurrentLanguage: function (lang) {
                var languages = this.getLanguages();
                angular.forEach(languages, function (language) {
                    language.selected = false;
                    if (language.code == lang) {
                        language.selected = true;
                        gettextCatalog.setCurrentLanguage(lang);
                        if (lang != 'en') {
                            gettextCatalog.loadRemote("static/i18n/" + lang + ".json");
                        }
                    }
                });
                return languages;
            }
        }
    }
])

// set browser language as default language for OpenSlides
.run([
    'gettextCatalog',
    'Languages',
    function(gettextCatalog, Languages) {
        // set detected browser language as default language (fallback: 'en')
        Languages.setCurrentLanguage(Languages.getBrowserLanguage());

        // Set this to true for debug. Helps to find untranslated strings by
        // adding "[MISSING]:".
        gettextCatalog.debug = false;
    }
])

.factory('dsEject', [
    'DS',
    function (DS) {
        return function (collection, instance) {
            var Resource = DS.definitions[collection];
            if (Resource.relationList) {
                Resource.relationList.forEach(function (relationDef) {
                    if (relationDef.foreignKey) {
                        var query = {};
                        query[relationDef.foreignKey] = instance[Resource.idAttribute];
                        Resource.getResource(relationDef.relation).ejectAll(query);
                    }
                });
            }
        }
    }
])

.run([
    'DS',
    'autoupdate',
    'dsEject',
    function (DS, autoupdate, dsEject) {
        autoupdate.onMessage(function(data) {
            // TODO: when MODEL.find() is called after this
            //       a new request is fired. This could be a bug in DS

            // TODO: Do not send the status code to the client, but make the decission
            //       on the server side. It is an implementation detail, that tornado
            //       sends request to wsgi, which should not concern the client.
            console.log("Received object: " + data.collection + ", " + data.id);
            var instance = DS.get(data.collection, data.id);
            if (data.status_code == 200) {
                if (instance) {
                    // The instance is in the local db
                    dsEject(data.collection, instance);
                }
                DS.inject(data.collection, data.data);
            } else if (data.status_code == 404) {
                if (instance) {
                    // The instance is in the local db
                    dsEject(data.collection, instance);
                }
                DS.eject(data.collection, data.id);
            }
            // TODO: handle other statuscodes
        });
    }
])

.factory('loadGlobalData', [
    '$rootScope',
    '$http',
    'ChatMessage',
    'Config',
    'Projector',
    function ($rootScope, $http, ChatMessage, Config, Projector) {
        return function () {
            // Puts the config object into each scope.
            Config.findAll().then(function() {
                $rootScope.config = function(key) {
                    try {
                        return Config.get(key).value;
                    }
                    catch(err) {
                        console.log("Unkown config key: " + key);
                        return '';
                    }
                };
            });

            // Loads all projector data
            Projector.findAll();

            // Loads all chat messages data and their user_ids
            // TODO: add permission check if user has required chat permission
            // error if include 'operator' here:
            // "Circular dependency found: loadGlobalData <- operator <- loadGlobalData"
            //if (operator.hasPerms("core.can_use_chat")) {
                ChatMessage.findAll().then( function(chatmessages) {
                    angular.forEach(chatmessages, function (chatmessage) {
                        ChatMessage.loadRelations(chatmessage, 'user');
                    });
                });
            //}

            // Loads server time and calculates server offset
            $http.get('/core/servertime/').then(function(data) {
                $rootScope.serverOffset = Math.floor( Date.now() / 1000 - data.data );
            });
        };
    }
])

// Load the global data on startup
.run([
    'loadGlobalData',
    function(loadGlobalData) {
        loadGlobalData();
    }
])

.factory('jsDataModel', [
    '$http',
    'Projector',
    function($http, Projector) {
        var BaseModel = function() {};
        BaseModel.prototype.project = function() {
            return $http.post(
                '/rest/core/projector/1/prune_elements/',
                [{name: this.getResourceName(), id: this.id}]
            );
        };
        BaseModel.prototype.isProjected = function() {
            // Returns true if there is a projector element with the same
            // name and the same id.
            var projector = Projector.get(1);
            if (typeof projector === 'undefined') return false;
            var self = this;
            var predicate = function (element) {
                return element.name == self.getResourceName() &&
                       typeof element.id !== 'undefined' &&
                       element.id == self.id;
            };
            return typeof _.findKey(projector.elements, predicate) === 'string';
        };
        return BaseModel;
    }
])

.factory('Customslide', [
    'DS',
    'jsDataModel',
    'gettext',
    function(DS, jsDataModel, gettext) {
        var name = 'core/customslide';
        return DS.defineResource({
            name: name,
            useClass: jsDataModel,
            verboseName: gettext('Agenda item'),
            methods: {
                getResourceName: function () {
                    return name;
                },
                getAgendaTitle: function () {
                    return this.title;
                },
                // link name which is shown in search result
                getSearchResultName: function () {
                    return this.getAgendaTitle();
                },
                // subtitle of search result
                getSearchResultSubtitle: function () {
                    return "Agenda item";
                },
            },
            relations: {
                belongsTo: {
                    'agenda/item': {
                        localKey: 'agenda_item_id',
                        localField: 'agenda_item',
                    }
                },
                hasMany: {
                    'mediafiles/mediafile': {
                        localField: 'attachments',
                        localKeys: 'attachments_id',
                    }
                }
            }
        });
    }
])

.factory('Tag', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/tag',
        });
    }
])

.factory('Config', [
    '$http',
    'DS',
    function($http, DS) {
        var configOptions;
        return DS.defineResource({
            name: 'core/config',
            idAttribute: 'key',
            configOptions: configOptions,
            getConfigOptions: function () {
                if (!this.configOptions) {
                    this.configOptions = $http({ 'method': 'OPTIONS', 'url': '/rest/core/config/' });
                }
                return this.configOptions;
            },
        });
    }
])

.factory('ChatMessage', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/chatmessage',
            relations: {
                belongsTo: {
                    'users/user': {
                        localField: 'user',
                        localKey: 'user_id',
                    }
                }
            }
        });
    }
])

/* Model for a projector.
 *
 * At the moment we use only one projector, so there will be only one object
 * in this model. It has the id 1. For later releases there will be multiple
 * projector objects.
 *
 * This model uses onConfilict: 'replace' instead of 'merge'. This is necessary
 * because the keys of the projector objects can change and old keys have to
 * be removed. See http://www.js-data.io/docs/dsdefaults#onconflict for
 * more information.
 */
.factory('Projector', [
    'DS',
    function(DS) {
        return DS.defineResource({
            name: 'core/projector',
            onConflict: 'replace',
        });
    }
])

/* Converts number of seconds into string "hh:mm:ss" or "mm:ss" */
.filter('osSecondsToTime', [
    function () {
        return function (totalseconds) {
            var time;
            // floor returns the largest integer of the absolut value of totalseconds
            var total = Math.floor(Math.abs(totalseconds));
            var hh = Math.floor(total / 3600);
            var mm = Math.floor(total % 3600 / 60);
            var ss = Math.floor(total % 60);
            var zero = "0";
            // Add leading "0" for double digit values
            hh = (zero+hh).slice(-2);
            mm = (zero+mm).slice(-2);
            ss = (zero+ss).slice(-2);
            if (hh == "00")
                time =  mm + ':' + ss;
            else
                time = hh + ":" + mm + ":" + ss;
            if (totalseconds < 0)
                time = "-"+time;
            return time;
        };
    }
])

.filter('osFilter', [
    '$filter',
    function ($filter) {
        return function (array, string, getFilterString) {
            if (!string) {
                return array;
            }
            return Array.prototype.filter.call(array, function (item) {
                return getFilterString(item).toLowerCase().indexOf(string.toLowerCase()) > -1;
            });
        }
    }
])

/* Options for CKEditor used in various create and edit views. */
.value('CKEditorOptions', {
    allowedContent:
        'h1 h2 h3 p pre b i u strike strong em blockquote;' +
        'a[!href];' +
        'img[!src,alt]{width,height,float};' +
        'table tr th td caption;' +
        'li ol ul{list-style};' +
        'span{color,background-color};',
    extraPlugins: 'colorbutton',
    toolbarGroups: [
        { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
        { name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] },
        { name: 'forms', groups: [ 'forms' ] },
        { name: 'tools', groups: [ 'tools' ] },
        { name: 'about', groups: [ 'about' ] },
        { name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
        { name: 'others', groups: [ 'others' ] },
        '/',
        { name: 'styles', groups: [ 'styles' ] },
        { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
        { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi', 'paragraph' ] },
        { name: 'links', groups: [ 'links' ] },
        { name: 'insert', groups: [ 'insert' ] },
        { name: 'colors', groups: [ 'colors' ] }
    ],
    removeButtons: 'Anchor,SpecialChar,Subscript,Superscript,Styles,RemoveFormat,HorizontalRule'
})

// Make sure that the DS factories are loaded by making them a dependency
.run([
    'ChatMessage',
    'Config',
    'Customslide',
    'Projector',
    'Tag',
    function (ChatMessage, Config, Customslide, Projector, Tag) {}
]);

}());
<|endoftext|>