<commit_before>/**
 * (c) 2016 Tieto Finland Oy
 * Licensed under the MIT license.
 */
'use strict';

/**
 * @ngdoc function
 * @name dashboard.controller:MeetingCtrl
 * @description
 * # MeetingCtrl
 * Controller of the dashboard
 */
angular.module('dashboard')
    .controller('meetingDetailsCtrl', ['$log', '$rootScope', '$scope', '$state', 'CONST', 'StorageSrv', 'AttachmentData', 'ListData', 'PROPS', 'Utils', '$timeout', 'ENV', function ($log, $rootScope, $scope, $state, CONST, StorageSrv, AttachmentData, ListData, PROPS, Utils, $timeout, ENV) {
        $log.debug("meetingDetailsCtrl: CONTROLLER");
        var self = this;
        self.isMobile = $rootScope.isMobile;
        var isTablet = $rootScope.isTablet;
        var mtgItemSelected = StorageSrv.getKey(CONST.KEY.MEETING_ITEM);
        self.primaryUrl = null;
        self.secondaryUrl = null;
        self.topic = null;
        self.bms = CONST.BLOCKMODE;
        self.bm = CONST.BLOCKMODE.DEFAULT; // State of view, which block(s) displayed
        self.pms = CONST.PRIMARYMODE;
        self.pm = CONST.PRIMARYMODE.DEFAULT; // State of primary view block
        self.sms = CONST.SECONDARYMODE;
        self.sm = CONST.SECONDARYMODE.PROPOSALS; // State of secondary view block
        self.header = null;
        $rootScope.menu = CONST.MENU.FULL;
        self.selData = null;

        self.tData = null;
        self.aData = null;
        self.dData = null;
        self.amData = null;

        self.unsavedConfig = { title: 'STR_CONFIRM', text: 'STR_WARNING_UNSAVED', yes: 'STR_CONTINUE' };
        self.hasUnsavedProposal = false;
        self.remarkIsUnsaved = false;
        self.isChairman = false;
        self.motionCount = null;
        self.isCityCouncil = false;

        function setBlockMode(mode) {
            self.bm = self.isMobile ? CONST.BLOCKMODE.SECONDARY : mode;
            $rootScope.$emit(CONST.MTGUICHANGED, { blockMode: self.bm });
        }

        function setPrimaryMode() {
            var secret = self.isSecret(self.tData);
            if (self.isMobile) {
                self.pm = CONST.PRIMARYMODE.HIDDEN;
            }
            else if (isTablet) {
                if (secret) {
                    self.pm = CONST.PRIMARYMODE.SECRET;
                }
                else {
                    self.pm = CONST.PRIMARYMODE.HIDDEN;
                }
            }
            else if (secret) {
                self.pm = CONST.PRIMARYMODE.SECRET;
            }
            else {
                self.pm = CONST.PRIMARYMODE.DEFAULT;
            }
            $rootScope.$emit(CONST.MTGUICHANGED, { primaryBlockMode: self.pm });
        }

        function setSecondaryMode(mode) {
            $timeout(function () {
                self.sm = mode;
            }, 0);
        }

        function setDefaultSecondaryMode() {
            if (self.isChairman) {
                setSecondaryMode(CONST.SECONDARYMODE.DECISIONS);
            }
            else {
                setSecondaryMode(CONST.SECONDARYMODE.PROPOSALS);
            }
        }

        function checkMode() {
            if (self.bm === CONST.BLOCKMODE.PRIMARY) {
                setBlockMode(CONST.BLOCKMODE.DEFAULT);
            }
            setPrimaryMode();
        }

        function setData(topic) {
            $log.debug("meetingDetailsCtrl: setData", arguments);
            self.topic = null;
            self.aData = null;
            self.tData = null;
            self.dData = null;
            self.secondaryUrl = null;
            self.primaryUrl = null;
            self.selData = null;
            self.header = null;
            self.isCityCouncil = false;

            if (self.sm !== CONST.SECONDARYMODE.PROPOSALS && self.sm !== CONST.SECONDARYMODE.REMARK) {
                setDefaultSecondaryMode();
            }

            if (angular.isObject(topic)) {
                self.isCityCouncil = topic.isCityCouncil;
                self.topic = topic;
                self.header = topic.topicTitle;
                if (angular.isArray(topic.esitykset)) {
                    var item = topic.esitykset[0];
                    if (angular.isObject(item)) {
                        $log.debug("meetingDetailsCtrl.setData: esitys publicity=" + item.publicity + " link=" + item.link + " pageCount=" + item.pageCount);
                        self.tData = AttachmentData.create(
                            ((angular.isString(item.documentTitle) && item.documentTitle.length) ? item.documentTitle : 'STR_TOPIC'), item.link, item.publicity, null, null, item.pageCount);
                    }
                }

                self.primaryUrl = (self.tData && self.tData.link) ? self.tData.link : {};

                self.aData = ListData.createAttachmentList({ 'header': 'STR_ATTACHMENTS', 'title': topic.topicTitle }, topic.attachment);
                self.dData = ListData.createDecisionList({ 'header': 'STR_DECISION_HISTORY', 'title': topic.topicTitle }, topic.decision);
                self.amData = ListData.createAdditionalMaterialList({ 'header': 'STR_ADDITIONAL_MATERIAL', 'title': topic.topicTitle }, topic.additionalMaterial);

                checkMode();
            }
        }

        function resetUnsaved() {
            self.hasUnsavedProposal = false;
            self.remarkIsUnsaved = false;
            $rootScope.$emit(CONST.UNSAVEMEETINGDDATA, false);
        }

        function attachmentSelected(attachment) {
            if (angular.isObject(attachment)) {
                if (!Utils.isAttConf(attachment) && (self.isMobile || isTablet)) {
                    Utils.openNewWin(attachment.link);
                }
                else {
                    setSecondaryMode(CONST.SECONDARYMODE.ATTACHMENTS);
                    self.selData = null;
                    self.secondaryUrl = attachment.link;
                }
                self.secondaryAtt = attachment;
            }
            resetUnsaved();
            checkMode();
        }

        function additionalMaterialSelected(material) {
            if (angular.isObject(material)) {
                if (!Utils.isAttConf(material) && (self.isMobile || isTablet)) {
                    Utils.openNewWin(material.link);
                }
                else {
                    setSecondaryMode(CONST.SECONDARYMODE.MATERIALS);
                    self.selData = null;
                    self.secondaryUrl = material.link;
                }
            }
            resetUnsaved();
            checkMode();
        }

        function decisionSelected(decision) {
            if (angular.isObject(decision)) {

                if (!Utils.isAttConf(decision) && (self.isMobile || isTablet)) {
                    Utils.openNewWin(decision.link);
                }
                else {
                    setSecondaryMode(CONST.SECONDARYMODE.MATERIALS);
                    self.selData = null;
                    self.secondaryUrl = decision.link;
                }
            }
            resetUnsaved();
            checkMode();
        }

        self.primaryClicked = function () {
            setBlockMode((self.bm === CONST.BLOCKMODE.PRIMARY || self.bm === CONST.BLOCKMODE.SECONDARY) ? CONST.BLOCKMODE.DEFAULT : CONST.BLOCKMODE.PRIMARY);
        };

        self.secondaryClicked = function () {
            setBlockMode((self.bm === CONST.BLOCKMODE.PRIMARY || self.bm === CONST.BLOCKMODE.SECONDARY) ? CONST.BLOCKMODE.DEFAULT : CONST.BLOCKMODE.SECONDARY);
        };

        self.presentationClicked = function (data) {
            if (self.isSecret(data)) {
                self.selData = null;
                setSecondaryMode(CONST.SECONDARYMODE.SECRET);
            }
            else {
                Utils.openNewWin(data.link);
            }
        };

        self.attachmentClicked = function () {
            setSecondaryMode(CONST.SECONDARYMODE.ATTACHMENTS);

            var data = [self.aData, self.amData, self.dData];
            if (!angular.equals(self.selData, data)) {
                self.selData = data;
            }
            resetUnsaved();
            checkMode();
        };

        self.selectionClicked = function (data) {
            if (self.aData.objects.indexOf(data) > CONST.NOTFOUND) {
                attachmentSelected(data);
            }
            else if (self.amData.objects.indexOf(data) > CONST.NOTFOUND) {
                additionalMaterialSelected(data);
            }
            else if (self.dData.objects.indexOf(data) > CONST.NOTFOUND) {
                decisionSelected(data);
            }
        };

        self.proposalsClicked = function () {
            self.selData = null;
            setSecondaryMode(CONST.SECONDARYMODE.PROPOSALS);
            resetUnsaved();
            checkMode();
        };

        self.remarkClicked = function () {
            self.selData = null;
            setSecondaryMode(CONST.SECONDARYMODE.REMARK);
            resetUnsaved();
            checkMode();
        };

        self.decisionsClicked = function () {
            self.selData = null;
            setSecondaryMode(CONST.SECONDARYMODE.DECISIONS);
            resetUnsaved();
            checkMode();
        };

        self.motionsClicked = function () {
            self.selData = null;
            setSecondaryMode(CONST.SECONDARYMODE.MOTIONS);
            resetUnsaved();
            checkMode();
        };

        self.motionsAppClicked = function motionsAppClicked() {
            Utils.openNewWin(ENV.AhjoApi_MotionApp);
        };

        self.isSecret = function (item) {
            return (item && item.publicity) ? (item.publicity === CONST.PUBLICITY.SECRET) : false;
        };

        self.materialCount = function () {
            var attachmentCount = ((self.aData instanceof Object) && (self.aData.objects instanceof Array)) ? self.aData.objects.length : 0;
            var decisionCount = ((self.dData instanceof Object) && (self.dData.objects instanceof Array)) ? self.dData.objects.length : 0;
            var additionalMaterialCount = ((self.amData instanceof Object) && (self.amData.objects instanceof Array)) ? self.amData.objects.length : 0;
            return attachmentCount + decisionCount + additionalMaterialCount;
        };

        self.toggleParallelMode = function () {
            $rootScope.parallelMode = $rootScope.parallelMode ? false : true;
            setBlockMode(CONST.BLOCKMODE.DEFAULT);
        };

        self.newTab = function (link) {
            Utils.openNewWin(link);
        };

        $scope.$watch(function () {
            return StorageSrv.getKey(CONST.KEY.TOPIC);
        }, function (topic, oldTopic) {
            if (!angular.equals(topic, oldTopic)) {
                setData(topic);
            }
        });

        $scope.$watch(function () {
            return $rootScope.parallelMode;
        }, function (parallel) {
            if (parallel) {
                setBlockMode(CONST.BLOCKMODE.DEFAULT);
            }
        });

        var proposalCountWatcher = $rootScope.$on(PROPS.COUNT, function (event, data) {
            if (angular.isObject(data) && !angular.isUndefined(data.published)) {
                if (angular.isObject(self.topic)) {
                    self.topic.db_publishedProposalCount = data.published;
                }
            }
        });

        var unsavedProposalWatcher = $rootScope.$on(CONST.PROPOSALSHASUNSAVED, function (event, hasUnsaved) {
            self.hasUnsavedProposal = hasUnsaved ? true : false;
            $rootScope.$emit(CONST.UNSAVEMEETINGDDATA, (self.hasUnsavedProposal || self.remarkIsUnsaved));
        });

        var unsavedRemarkWatcher = $rootScope.$on(CONST.REMARKISUNSAVED, function (event, isUnsaved) {
            self.remarkIsUnsaved = isUnsaved ? true : false;
            $rootScope.$emit(CONST.UNSAVEMEETINGDDATA, (self.hasUnsavedProposal || self.remarkIsUnsaved));
        });

        var motionsWatcher = $rootScope.$on(CONST.MOTIONSUPDATED, function (aEvent, aData) {
            $log.debug("meetingDetailsCtrl.motionsWatcher: ", arguments);
            if (angular.isObject(aData)) {
                self.motionCount = aData.count;
            }
            else {
                self.motionCount = null;
            }
        });

        $scope.$on('$destroy', function () {
            $log.debug("meetingDetailsCtrl: DESTROY");
            if (angular.isFunction(unsavedRemarkWatcher)) {
                unsavedRemarkWatcher();
            }
            if (angular.isFunction(unsavedProposalWatcher)) {
                unsavedProposalWatcher();
            }
            if (angular.isFunction(proposalCountWatcher)) {
                proposalCountWatcher();
            }
            if (angular.isFunction(motionsWatcher)) {
                motionsWatcher();
            }
        });

        // CONSTRUCT

        if (angular.isObject(mtgItemSelected) && angular.isObject(mtgItemSelected.dbUserRole) && mtgItemSelected.dbUserRole.RoleID === CONST.MTGROLE.CHAIRMAN.value) {
            self.isChairman = true;
        }
        setBlockMode(CONST.BLOCKMODE.DEFAULT);
        setPrimaryMode();
        setDefaultSecondaryMode();

        setData(StorageSrv.getKey(CONST.KEY.TOPIC));
    }]);
<commit_msg>meting.details: use lang-specific topicTitle<commit_after>/**
 * (c) 2016 Tieto Finland Oy
 * Licensed under the MIT license.
 */
'use strict';

/**
 * @ngdoc function
 * @name dashboard.controller:MeetingCtrl
 * @description
 * # MeetingCtrl
 * Controller of the dashboard
 */
angular.module('dashboard')
    .controller('meetingDetailsCtrl', ['$log', '$rootScope', '$scope', '$state', 'CONST', 'StorageSrv', 'AttachmentData', 'ListData', 'PROPS', 'Utils', '$timeout', 'ENV', function ($log, $rootScope, $scope, $state, CONST, StorageSrv, AttachmentData, ListData, PROPS, Utils, $timeout, ENV) {
        $log.debug("meetingDetailsCtrl: CONTROLLER");
        var self = this;
        self.isMobile = $rootScope.isMobile;
        var isTablet = $rootScope.isTablet;
        var mtgItemSelected = StorageSrv.getKey(CONST.KEY.MEETING_ITEM);
        self.primaryUrl = null;
        self.secondaryUrl = null;
        self.topic = null;
        self.bms = CONST.BLOCKMODE;
        self.bm = CONST.BLOCKMODE.DEFAULT; // State of view, which block(s) displayed
        self.pms = CONST.PRIMARYMODE;
        self.pm = CONST.PRIMARYMODE.DEFAULT; // State of primary view block
        self.sms = CONST.SECONDARYMODE;
        self.sm = CONST.SECONDARYMODE.PROPOSALS; // State of secondary view block
        self.header = null;
        $rootScope.menu = CONST.MENU.FULL;
        self.selData = null;

        self.tData = null;
        self.aData = null;
        self.dData = null;
        self.amData = null;

        self.unsavedConfig = { title: 'STR_CONFIRM', text: 'STR_WARNING_UNSAVED', yes: 'STR_CONTINUE' };
        self.hasUnsavedProposal = false;
        self.remarkIsUnsaved = false;
        self.isChairman = false;
        self.motionCount = null;
        self.isCityCouncil = false;

        function setBlockMode(mode) {
            self.bm = self.isMobile ? CONST.BLOCKMODE.SECONDARY : mode;
            $rootScope.$emit(CONST.MTGUICHANGED, { blockMode: self.bm });
        }

        function setPrimaryMode() {
            var secret = self.isSecret(self.tData);
            if (self.isMobile) {
                self.pm = CONST.PRIMARYMODE.HIDDEN;
            }
            else if (isTablet) {
                if (secret) {
                    self.pm = CONST.PRIMARYMODE.SECRET;
                }
                else {
                    self.pm = CONST.PRIMARYMODE.HIDDEN;
                }
            }
            else if (secret) {
                self.pm = CONST.PRIMARYMODE.SECRET;
            }
            else {
                self.pm = CONST.PRIMARYMODE.DEFAULT;
            }
            $rootScope.$emit(CONST.MTGUICHANGED, { primaryBlockMode: self.pm });
        }

        function setSecondaryMode(mode) {
            $timeout(function () {
                self.sm = mode;
            }, 0);
        }

        function setDefaultSecondaryMode() {
            if (self.isChairman) {
                setSecondaryMode(CONST.SECONDARYMODE.DECISIONS);
            }
            else {
                setSecondaryMode(CONST.SECONDARYMODE.PROPOSALS);
            }
        }

        function checkMode() {
            if (self.bm === CONST.BLOCKMODE.PRIMARY) {
                setBlockMode(CONST.BLOCKMODE.DEFAULT);
            }
            setPrimaryMode();
        }

        function setData(topic) {
            $log.debug("meetingDetailsCtrl: setData", arguments);
            self.topic = null;
            self.aData = null;
            self.tData = null;
            self.dData = null;
            self.secondaryUrl = null;
            self.primaryUrl = null;
            self.selData = null;
            self.header = null;
            self.isCityCouncil = false;

            if (self.sm !== CONST.SECONDARYMODE.PROPOSALS && self.sm !== CONST.SECONDARYMODE.REMARK) {
                setDefaultSecondaryMode();
            }

            if (angular.isObject(topic)) {
                self.isCityCouncil = topic.isCityCouncil;
                self.topic = topic;
                self.header = topic[$rootScope.locProp('topicTitle')];
                if (angular.isArray(topic.esitykset)) {
                    var item = topic.esitykset[0];
                    if (angular.isObject(item)) {
                        $log.debug("meetingDetailsCtrl.setData: esitys publicity=" + item.publicity + " link=" + item.link + " pageCount=" + item.pageCount);
                        self.tData = AttachmentData.create(
                            ((angular.isString(item.documentTitle) && item.documentTitle.length) ? item.documentTitle : 'STR_TOPIC'), item.link, item.publicity, null, null, item.pageCount);
                    }
                }

                self.primaryUrl = (self.tData && self.tData.link) ? self.tData.link : {};

                self.aData = ListData.createAttachmentList({ 'header': 'STR_ATTACHMENTS', 'title': self.header }, topic.attachment);
                self.dData = ListData.createDecisionList({ 'header': 'STR_DECISION_HISTORY', 'title': self.header }, topic.decision);
                self.amData = ListData.createAdditionalMaterialList({ 'header': 'STR_ADDITIONAL_MATERIAL', 'title': self.header }, topic.additionalMaterial);

                checkMode();
            }
        }

        function resetUnsaved() {
            self.hasUnsavedProposal = false;
            self.remarkIsUnsaved = false;
            $rootScope.$emit(CONST.UNSAVEMEETINGDDATA, false);
        }

        function attachmentSelected(attachment) {
            if (angular.isObject(attachment)) {
                if (!Utils.isAttConf(attachment) && (self.isMobile || isTablet)) {
                    Utils.openNewWin(attachment.link);
                }
                else {
                    setSecondaryMode(CONST.SECONDARYMODE.ATTACHMENTS);
                    self.selData = null;
                    self.secondaryUrl = attachment.link;
                }
                self.secondaryAtt = attachment;
            }
            resetUnsaved();
            checkMode();
        }

        function additionalMaterialSelected(material) {
            if (angular.isObject(material)) {
                if (!Utils.isAttConf(material) && (self.isMobile || isTablet)) {
                    Utils.openNewWin(material.link);
                }
                else {
                    setSecondaryMode(CONST.SECONDARYMODE.MATERIALS);
                    self.selData = null;
                    self.secondaryUrl = material.link;
                }
            }
            resetUnsaved();
            checkMode();
        }

        function decisionSelected(decision) {
            if (angular.isObject(decision)) {

                if (!Utils.isAttConf(decision) && (self.isMobile || isTablet)) {
                    Utils.openNewWin(decision.link);
                }
                else {
                    setSecondaryMode(CONST.SECONDARYMODE.MATERIALS);
                    self.selData = null;
                    self.secondaryUrl = decision.link;
                }
            }
            resetUnsaved();
            checkMode();
        }

        self.primaryClicked = function () {
            setBlockMode((self.bm === CONST.BLOCKMODE.PRIMARY || self.bm === CONST.BLOCKMODE.SECONDARY) ? CONST.BLOCKMODE.DEFAULT : CONST.BLOCKMODE.PRIMARY);
        };

        self.secondaryClicked = function () {
            setBlockMode((self.bm === CONST.BLOCKMODE.PRIMARY || self.bm === CONST.BLOCKMODE.SECONDARY) ? CONST.BLOCKMODE.DEFAULT : CONST.BLOCKMODE.SECONDARY);
        };

        self.presentationClicked = function (data) {
            if (self.isSecret(data)) {
                self.selData = null;
                setSecondaryMode(CONST.SECONDARYMODE.SECRET);
            }
            else {
                Utils.openNewWin(data.link);
            }
        };

        self.attachmentClicked = function () {
            setSecondaryMode(CONST.SECONDARYMODE.ATTACHMENTS);

            var data = [self.aData, self.amData, self.dData];
            if (!angular.equals(self.selData, data)) {
                self.selData = data;
            }
            resetUnsaved();
            checkMode();
        };

        self.selectionClicked = function (data) {
            if (self.aData.objects.indexOf(data) > CONST.NOTFOUND) {
                attachmentSelected(data);
            }
            else if (self.amData.objects.indexOf(data) > CONST.NOTFOUND) {
                additionalMaterialSelected(data);
            }
            else if (self.dData.objects.indexOf(data) > CONST.NOTFOUND) {
                decisionSelected(data);
            }
        };

        self.proposalsClicked = function () {
            self.selData = null;
            setSecondaryMode(CONST.SECONDARYMODE.PROPOSALS);
            resetUnsaved();
            checkMode();
        };

        self.remarkClicked = function () {
            self.selData = null;
            setSecondaryMode(CONST.SECONDARYMODE.REMARK);
            resetUnsaved();
            checkMode();
        };

        self.decisionsClicked = function () {
            self.selData = null;
            setSecondaryMode(CONST.SECONDARYMODE.DECISIONS);
            resetUnsaved();
            checkMode();
        };

        self.motionsClicked = function () {
            self.selData = null;
            setSecondaryMode(CONST.SECONDARYMODE.MOTIONS);
            resetUnsaved();
            checkMode();
        };

        self.motionsAppClicked = function motionsAppClicked() {
            Utils.openNewWin(ENV.AhjoApi_MotionApp);
        };

        self.isSecret = function (item) {
            return (item && item.publicity) ? (item.publicity === CONST.PUBLICITY.SECRET) : false;
        };

        self.materialCount = function () {
            var attachmentCount = ((self.aData instanceof Object) && (self.aData.objects instanceof Array)) ? self.aData.objects.length : 0;
            var decisionCount = ((self.dData instanceof Object) && (self.dData.objects instanceof Array)) ? self.dData.objects.length : 0;
            var additionalMaterialCount = ((self.amData instanceof Object) && (self.amData.objects instanceof Array)) ? self.amData.objects.length : 0;
            return attachmentCount + decisionCount + additionalMaterialCount;
        };

        self.toggleParallelMode = function () {
            $rootScope.parallelMode = $rootScope.parallelMode ? false : true;
            setBlockMode(CONST.BLOCKMODE.DEFAULT);
        };

        self.newTab = function (link) {
            Utils.openNewWin(link);
        };

        $scope.$watch(function () {
            return StorageSrv.getKey(CONST.KEY.TOPIC);
        }, function (topic, oldTopic) {
            if (!angular.equals(topic, oldTopic)) {
                setData(topic);
            }
        });

        $scope.$watch(function () {
            return $rootScope.parallelMode;
        }, function (parallel) {
            if (parallel) {
                setBlockMode(CONST.BLOCKMODE.DEFAULT);
            }
        });

        var proposalCountWatcher = $rootScope.$on(PROPS.COUNT, function (event, data) {
            if (angular.isObject(data) && !angular.isUndefined(data.published)) {
                if (angular.isObject(self.topic)) {
                    self.topic.db_publishedProposalCount = data.published;
                }
            }
        });

        var unsavedProposalWatcher = $rootScope.$on(CONST.PROPOSALSHASUNSAVED, function (event, hasUnsaved) {
            self.hasUnsavedProposal = hasUnsaved ? true : false;
            $rootScope.$emit(CONST.UNSAVEMEETINGDDATA, (self.hasUnsavedProposal || self.remarkIsUnsaved));
        });

        var unsavedRemarkWatcher = $rootScope.$on(CONST.REMARKISUNSAVED, function (event, isUnsaved) {
            self.remarkIsUnsaved = isUnsaved ? true : false;
            $rootScope.$emit(CONST.UNSAVEMEETINGDDATA, (self.hasUnsavedProposal || self.remarkIsUnsaved));
        });

        var motionsWatcher = $rootScope.$on(CONST.MOTIONSUPDATED, function (aEvent, aData) {
            $log.debug("meetingDetailsCtrl.motionsWatcher: ", arguments);
            if (angular.isObject(aData)) {
                self.motionCount = aData.count;
            }
            else {
                self.motionCount = null;
            }
        });

        $scope.$on('$destroy', function () {
            $log.debug("meetingDetailsCtrl: DESTROY");
            if (angular.isFunction(unsavedRemarkWatcher)) {
                unsavedRemarkWatcher();
            }
            if (angular.isFunction(unsavedProposalWatcher)) {
                unsavedProposalWatcher();
            }
            if (angular.isFunction(proposalCountWatcher)) {
                proposalCountWatcher();
            }
            if (angular.isFunction(motionsWatcher)) {
                motionsWatcher();
            }
        });

        // CONSTRUCT

        if (angular.isObject(mtgItemSelected) && angular.isObject(mtgItemSelected.dbUserRole) && mtgItemSelected.dbUserRole.RoleID === CONST.MTGROLE.CHAIRMAN.value) {
            self.isChairman = true;
        }
        setBlockMode(CONST.BLOCKMODE.DEFAULT);
        setPrimaryMode();
        setDefaultSecondaryMode();

        setData(StorageSrv.getKey(CONST.KEY.TOPIC));
    }]);
<|endoftext|>


<commit_before>var files = require("./files.js");
var Future = require("fibers/future");
var _ = require("underscore");
var switchFunctions = [];
var pollingInterval = 500;

// Set this environment variable to a truthy value to force the use of
// files.watchFile instead of pathwatcher.watch.
var canUsePathwatcher = !process.env.METEOR_WATCH_FORCE_POLLING;

// The pathwatcher library does not work on all platforms and file systems
// (notably, network file systems), so we have to do a little feature
// detection to see if we can use it.

// We optimistically watch files using pathwatcher.watch until one of the
// directories tested fails to support file system events. When that
// happens, we switch all previously created pathwatcher watches to use
// files.watchFile, and set canUsePathwatcher to false so that all future
// watches will use files.watchFile as well.

// There is some theoretical risk of missing file system events from
// pathwatcher watches created before we discover that we can't use
// pathwatcher.watch, but the window of time where that can happen is
// small enough (500ms) that developers are highly unlikely to care.

exports.testDirectory = function (dir) {
  if (! canUsePathwatcher) {
    // No need to test this directory if we've already decided we can't
    // use pathwatcher.watch.
    return;
  }

  var canaryFile = files.pathJoin(
    dir, "canary$" + Math.random().toString(36).slice(2)
  );

  files.mkdir_p(dir);

  try {
    files.unlink(canaryFile);
  } catch (err) {
    // ignore the error
  }

  var cleanUp = function () {
    if (watcher) {
      watcher.close();
      watcher = null;
      try {
        files.unlink(canaryFile);
      } catch (err) {
        // ignore the error
      }
    }
  };

  var fallBack = function () {
    // Disallow future uses of pathwatcher.watch.
    canUsePathwatcher = false;

    // Convert any pathwatcher watchers we previously created to
    // files.watchFile watchers.
    _.each(switchFunctions.splice(0), function (switchToPolling) {
      switchToPolling();
    });

    require("./console.js").Console.warn(
      "Falling back to files.watchFile instead of pathwatcher.watch..."
    );
  };

  try {
    // Watch the candidate directory using pathwatcher.watch.
    var watcher = files.pathwatcherWatch(dir, cleanUp);
  } catch (err) {
    // If the directory did not exist, do not treat this failure as
    // evidence against pathwatcher.watch, but simply return and leave
    // canUsePathwatcher set to true.
    if (err instanceof TypeError && err.message === "Unable to watch path") {
      return;
    }

    throw err;
  }

  // Create a new file to trigger a change event (hopefully). It's fine
  // if other events sneak in while we're waiting, since all we care
  // about is whether pathwatcher.watch works.
  files.writeFile(canaryFile, "ok", function (err) {
    if (err) {
      cleanUp();
      throw err;
    }
  });

  // Set a time limit of 500ms for the change event.
  setTimeout(function () {
    if (watcher) {
      cleanUp();
      fallBack();
    }
  }, 500);
};

exports.watch = function (absPath, callback) {
  if (canUsePathwatcher) {
    // In principle, all this logic for watching files should continue to
    // work perfectly if we substitute files.watch for pathwatcher.watch, but
    // that will probably have to wait until we upgrade Node to v0.11.x,
    // so that files.watch is more reliable.
    var watcher = files.pathwatcherWatch(absPath, callback);

    var closed = false;
    var switched = false;

    switchFunctions.push(function switchToPolling() {
      if (! switched && ! closed) {
        switched = true;
        watcher.close();

        // Re-watch the file using files.watchFile instead.
        files.watchFile(absPath, {
          interval: pollingInterval
        }, callback);
      }
    });

    return {
      close: function close() {
        if (! closed) {
          closed = true;
          if (switched) {
            files.unwatchFile(absPath, callback);
          } else {
            watcher.close();
          }
        }
      }
    };
  }

  files.watchFile(absPath, {
    interval: pollingInterval
  }, callback);

  return {
    close: function close () {
      files.unwatchFile(absPath, callback);
    }
  };
};
<commit_msg>Small fixes to tools/safe-pathwatcher.js.<commit_after>var files = require("./files.js");
var _ = require("underscore");
var switchFunctions = [];
var pollingInterval = 500;

// Set this environment variable to a truthy value to force the use of
// files.watchFile instead of pathwatcher.watch.
var canUsePathwatcher = !process.env.METEOR_WATCH_FORCE_POLLING;

// The pathwatcher library does not work on all platforms and file systems
// (notably, network file systems), so we have to do a little feature
// detection to see if we can use it.

// We optimistically watch files using pathwatcher.watch until one of the
// directories tested fails to support file system events. When that
// happens, we switch all previously created pathwatcher watches to use
// files.watchFile, and set canUsePathwatcher to false so that all future
// watches will use files.watchFile as well.

// There is some theoretical risk of missing file system events from
// pathwatcher watches created before we discover that we can't use
// pathwatcher.watch, but the window of time where that can happen is
// small enough (200ms) that developers are highly unlikely to care.

exports.testDirectory = function (dir) {
  if (! canUsePathwatcher) {
    // No need to test this directory if we've already decided we can't
    // use pathwatcher.watch.
    return;
  }

  var canaryFile = files.pathJoin(
    dir, "canary$" + Math.random().toString(36).slice(2)
  );

  files.mkdir_p(dir);

  var cleanUp = function () {
    if (watcher) {
      watcher.close();
      watcher = null;
      try {
        files.unlink(canaryFile);
      } catch (err) {
        // ignore the error
      }
    }
  };

  var fallBack = function () {
    // Disallow future uses of pathwatcher.watch.
    canUsePathwatcher = false;

    // Convert any pathwatcher watchers we previously created to
    // files.watchFile watchers.
    _.each(switchFunctions.splice(0), function (switchToPolling) {
      switchToPolling();
    });

    require("./console.js").Console.debug(
      "Falling back to files.watchFile instead of pathwatcher.watch..."
    );
  };

  try {
    // Watch the candidate directory using pathwatcher.watch.
    var watcher = files.pathwatcherWatch(dir, cleanUp);

  } catch (err) {
    // If the directory did not exist, do not treat this failure as
    // evidence against pathwatcher.watch, but simply return and leave
    // canUsePathwatcher set to true.
    if (err instanceof TypeError &&
        err.message === "Unable to watch path") {
      return;
    }

    throw err;
  }

  // Create a new file to trigger a change event (hopefully). It's fine
  // if other events sneak in while we're waiting, since all we care
  // about is whether pathwatcher.watch works.
  try {
    files.writeFile(canaryFile, "ok");
  } catch (err) {
    cleanUp();
    throw err;
  }

  // Set a time limit of 200ms, starting from the time the file was
  // written, in which the change event must fire, else we fall back to
  // using files.watchFile.
  setTimeout(function() {
    if (watcher) {
      cleanUp();
      fallBack();
    }
  }, 200);
};

exports.watch = function (absPath, callback) {
  if (canUsePathwatcher) {
    // In principle, all this logic for watching files should continue to
    // work perfectly if we substitute files.watch for pathwatcher.watch, but
    // that will probably have to wait until we upgrade Node to v0.11.x,
    // so that files.watch is more reliable.
    var watcher = files.pathwatcherWatch(absPath, callback);

    var closed = false;
    var switched = false;

    switchFunctions.push(function switchToPolling() {
      if (! switched && ! closed) {
        switched = true;
        watcher.close();

        // Re-watch the file using files.watchFile instead.
        files.watchFile(absPath, {
          interval: pollingInterval
        }, callback);
      }
    });

    return {
      close: function close() {
        if (! closed) {
          closed = true;
          if (switched) {
            files.unwatchFile(absPath, callback);
          } else {
            watcher.close();
          }
        }
      }
    };
  }

  files.watchFile(absPath, {
    interval: pollingInterval
  }, callback);

  return {
    close: function close () {
      files.unwatchFile(absPath, callback);
    }
  };
};
<|endoftext|>


<commit_before>//MIT License

//Copyright (c) 2017 Arc676/Alessandro Vinciguerra

//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.

const fs = require('fs')

const MTG = require('mtgsdk')
const Discord = require('discord.js')

const client = new Discord.Client()

var name = "titania"
var resultLimit = 10

client.on('ready', () => {
	console.log(`Logged in as ${client.user.username}`)
})

const properties = [
	[
		"name",
		"manaCost"
	],
	[
		"rarity",
		"types"
	],
	[
		"text"
	],
	[
		"power",
		"toughness"
	]
]
function printCard(message, card) {
	var text = ""
	for (var i = 0; i < properties.length; i++) {
		for (var j = 0; j < properties[i].length; j++) {
			if (properties[i][j] in card) {
				text += card[properties[i][j]]
				if (j + 1 < properties[i].length) {
					text += "/"
				}
			}
		}
		text += "\n"
	}
	message.reply(text)
}

function getQueryProperties(query) {
	var properties = {}
	for (var i = 0; i < query.length; i++) {
		const prop = query[i].split("=")
		properties[prop[0]] = prop[1].replace(/\+/g, ' ')
	}
	return properties
}

client.on('message', message => {
	if (message.content.startsWith(name + " ")) {
		if (message.content.endsWith(" die")) {
			client.destroy()
			process.exit(0)
		} else if (message.content.indexOf(" limit ") !== -1) {
			const args = message.content.split(" ")
			resultLimit = parseInt(args[2])
		}
		return
	}
	const startIndex = message.content.indexOf("[[")
	const endIndex = message.content.indexOf("]]")
	if (startIndex !== -1 && endIndex !== -1) {
		const query = message.content.substring(startIndex + 2, endIndex).split(" ")
		if (query.length === 0) {
			return
		}
		if (message.content.startsWith("set")) {
			//const properties = getQueryProperties(query.splice(1))
			message.reply("Set searching coming soon!")
		} else {
			var printText = true
			var printImage = false
			var debug = false
			if (message.content.startsWith("debug")) {
				debug = true
				printText = false
			} else if (message.content.startsWith("image")) {
				printImage = true
				printText = false
			} else if (message.content.startsWith("combo")) {
				printImage = true
			}
			const properties = getQueryProperties(query)
			if (properties === undefined) {
				message.reply("Sorry, your query failed")
				return
			}
			MTG.card.where(properties).then(cards => {
				distinct = {}
				found = 0
				for (var i = 0; i < cards.length; i++) {
					if (!(cards[i].name in distinct)) {
						distinct[cards[i].name] = cards[i]
						found++
					}
				}
				message.reply("Found " + found + " distinct card(s)")
				if (found > resultLimit) {
					message.reply("Result count exceeds limit. Aborting.")
					return
				}
				for (let card in distinct) {
					if (printText) {
						printCard(message, distinct[card])
					}
					if (printImage) {
						message.reply(distinct[card]['imageUrl'])
					}
					if (debug) {
						console.log(distinct[card])
					}
				}
				message.reply("End of search results")
			})
		}
	}

})

client.login(fs.readFileSync('tokens/' + name + '.token', 'utf8'))
<commit_msg>Added query validaion to Titania<commit_after>//MIT License

//Copyright (c) 2017 Arc676/Alessandro Vinciguerra

//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.

const fs = require('fs')

const MTG = require('mtgsdk')
const Discord = require('discord.js')

const client = new Discord.Client()

var name = "titania"
var resultLimit = 10

client.on('ready', () => {
	console.log(`Logged in as ${client.user.username}`)
})

const properties = [
	[
		"name",
		"manaCost"
	],
	[
		"rarity",
		"types"
	],
	[
		"text"
	],
	[
		"power",
		"toughness"
	]
]
function printCard(message, card) {
	var text = ""
	for (var i = 0; i < properties.length; i++) {
		for (var j = 0; j < properties[i].length; j++) {
			if (properties[i][j] in card) {
				text += card[properties[i][j]]
				if (j + 1 < properties[i].length) {
					text += "/"
				}
			}
		}
		text += "\n"
	}
	message.reply(text)
}

function getQueryProperties(query) {
	var properties = {}
	for (var i = 0; i < query.length; i++) {
		const prop = query[i].split("=")
		try {
			properties[prop[0]] = prop[1].replace(/\+/g, ' ')
		} catch (error) {
			return undefined;
		}
	}
	return properties
}

client.on('message', message => {
	if (message.content.startsWith(name + " ")) {
		if (message.content.endsWith(" die")) {
			client.destroy()
			process.exit(0)
		} else if (message.content.indexOf(" limit ") !== -1) {
			const args = message.content.split(" ")
			resultLimit = parseInt(args[2])
		}
		return
	}
	const startIndex = message.content.indexOf("[[")
	const endIndex = message.content.indexOf("]]")
	if (startIndex !== -1 && endIndex !== -1) {
		const query = message.content.substring(startIndex + 2, endIndex).split(" ")
		if (query.length === 0) {
			return
		}
		if (message.content.startsWith("set")) {
			//const properties = getQueryProperties(query.splice(1))
			message.reply("Set searching coming soon!")
		} else {
			var printText = true
			var printImage = false
			var debug = false
			if (message.content.startsWith("debug")) {
				debug = true
				printText = false
			} else if (message.content.startsWith("image")) {
				printImage = true
				printText = false
			} else if (message.content.startsWith("combo")) {
				printImage = true
			}
			const properties = getQueryProperties(query)
			if (properties === undefined) {
				message.reply("Sorry, your query failed")
				return
			}
			MTG.card.where(properties).then(cards => {
				distinct = {}
				found = 0
				for (var i = 0; i < cards.length; i++) {
					if (!(cards[i].name in distinct)) {
						distinct[cards[i].name] = cards[i]
						found++
					}
				}
				message.reply("Found " + found + " distinct card(s)")
				if (found > resultLimit) {
					message.reply("Result count exceeds limit. Aborting.")
					return
				}
				for (let card in distinct) {
					if (printText) {
						printCard(message, distinct[card])
					}
					if (printImage) {
						message.reply(distinct[card]['imageUrl'])
					}
					if (debug) {
						console.log(distinct[card])
					}
				}
				message.reply("End of search results")
			})
		}
	}

})

client.login(fs.readFileSync('tokens/' + name + '.token', 'utf8'))
<|endoftext|>


<commit_before>define(['jquery', './constants', './pubsub'], function ($, constants, pubSub) {
    'use strict';

    /* Private variables */
    var _achievements = {};
    var _achievementTooltipTimeout = 3000;
    var _points = 0;
    var _achievementDomNode = null;
    var _hintsCount = 0;

    var _achievementCallbacks = {
        'bug_captured': function () {
            _showTooltip('+50 Gotcha!');
            pubSub.publish('UI/talk', ['Great job!', constants.Text.HINTS_PERSON_NAME, constants.Text.BUG_CAPTURED]);
            _points += 50;
        },
        'darkness_removed': function () {
            _showTooltip('+50 Lights on');
            pubSub.publish('UI/talk', ['Great job!', constants.Text.HINTS_PERSON_NAME, constants.Text.LIGHTS_ON_ALERT]);
            _points += 50;
        },
        'bug_grown': function () {
            _showTooltip('+50 firstChild');
            _points += 50;
        },
        'glass_repaired': function () {
            _showTooltip('+50 Disaster prevented');
            _points += 50;
        },
        'collect_10_bugs': function () {
            _showTooltip('+100 Mission accomplished');
            _points += 100;
        },
        'logged_in': function () {
            _showTooltip('+50 Inside the system');
            _points += 50;
        },
        'game_over. yes, this is an achievement': function () {
            _showTooltip('+49 Game over...?');
            _points += 49;
        },
        'invisible_bug': function () {
            _points += 50;
        },
        'virus_bug': function () {
            _points += 50;
        },
        'bigger_bug': function () {
            _points += 50;
        },
        'inhibited_bug': function () {
            _points += 50;
        },
        'mutated_bug': function () {
            _points += 50;
        }
    };

    /* Private methods */
    var _getAchievementCount = function () {
        var i = 0;
        for(var a in _achievements) {
            i++;
        }
        return i;
    };

    var _showTooltip = function (text) {
        var jqNode = $(_achievementDomNode);
        jqNode.html(text);
        document.body.appendChild(_achievementDomNode);
        setTimeout(function () {
            jqNode.one('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () {
                setTimeout(function () {
                    if(_achievementDomNode.parentElement) {
                        jqNode.one('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () {
                            document.body.removeChild(_achievementDomNode);
                        });
                        _achievementDomNode.classList.remove('achievementNodeShown');
                    }
                }, _achievementTooltipTimeout);
            });
            _achievementDomNode.classList.add('achievementNodeShown');
        }, 1);
    };

    var _update = function () {
        var achievementTxt = '';
        var achievementCount = 0;
        for(var a in _achievements) {
            achievementTxt += a + '
';
            achievementCount++;
        }
        var totAchievementCount = 0;
        for(var b in _achievementCallbacks) {
            totAchievementCount++;
        }
        for(var i = totAchievementCount - achievementCount; i > 0; i--) {
            achievementTxt += '???
';
        }
        constants.JQ_ACHIEVEMENT_LIST.html(achievementTxt);
        constants.JQ_POINTS.html('' + _points);
    };

    /* PubSub */
    pubSub.subscribe('AchievementManager/achieve', function (evt, name) {
        if(!_achievements[name]) {
            _achievements[name] = true;
            pubSub.publish('AudioManager/playSound', [constants.Sound.SUCCESS]);
            if(_achievementCallbacks[name]) {
                _achievementCallbacks[name]();
            }
            if(window.localStorage) {
                window.localStorage.setItem('achievements', JSON.stringify(_achievements));
                window.localStorage.setItem('points', JSON.stringify(_points));
            }
            _update();
            window._gaq.push(['_trackEvent', 'Game', 'Achievement', name, _getAchievementCount()]);
        }
    });

    pubSub.subscribe('AchievementManager/openSpoiler', function () {
        _hintsCount++;
        _points -= 10;
        pubSub.publish('AudioManager/playSound', [constants.Sound.FAILURE]);
        _update();
        var hintRequested = '';
        if(constants.Text.I_AM_STUCK_TEXT === constants.Text.HINT_DARKNESS) {
            hintRequested = 'cannot_remove_darkness';
        } else if(constants.Text.I_AM_STUCK_TEXT === constants.Text.HINT_GROW_BUGTERIA) {
            hintRequested = 'cannot_grow_bug';
        } else if(constants.Text.I_AM_STUCK_TEXT === constants.Text.HINT_BUGTERIUM_TOO_BIG) {
            hintRequested = 'cannot_move_bug_to_flask';
        } else if(constants.Text.I_AM_STUCK_TEXT === constants.Text.HINT_BUGTERIUM_IN_FLASK) {
            hintRequested = 'cannot_collect_10_bugs';
        }
        window._gaq.push(['_trackEvent', 'Menu', 'Hints', hintRequested, _getAchievementCount()]);
    });

    pubSub.subscribe('AchievementManager/update', _update);

    var AchievementManager = function () {};
    AchievementManager.prototype = {
        getAchievementCount: function () {
            return _getAchievementCount();
        },
        getGivenHintsCount: function () {
            return _hintsCount;
        },
        getPoints: function () {
            return _points;
        },
        getTotalAchievementCount: function () {
            var i = 0;
            for(var a in _achievementCallbacks) {
                i++;
            }
            return i;
        },
        init: function () {
            _achievementDomNode = document.createElement('div');
            _achievementDomNode.classList.add('achievementNode');

            var tmpAchievements, tmpPoints;
            if(window.localStorage) {
                if(tmpAchievements = window.localStorage.getItem('achievements')) {
                    _achievements = JSON.parse(tmpAchievements);
                }
                if(tmpPoints = window.localStorage.getItem('points')) {
                    _points = parseInt(tmpPoints);
                }
            }
        }
    };
    return AchievementManager;
});<commit_msg>minor fix<commit_after>define(['jquery', './constants', './pubsub'], function ($, constants, pubSub) {
    'use strict';

    /* Private variables */
    var _achievements = {};
    var _achievementTooltipTimeout = 3000;
    var _points = 0;
    var _achievementDomNode = null;
    var _hintsCount = 0;

    var _achievementCallbacks = {
        'bug_captured': function () {
            _showTooltip('+50 Gotcha!');
            pubSub.publish('UI/talk', ['Great job!', constants.Text.HINTS_PERSON_NAME, constants.Text.BUG_CAPTURED]);
            _points += 50;
        },
        'darkness_removed': function () {
            _showTooltip('+50 Lights on');
            pubSub.publish('UI/talk', ['Great job!', constants.Text.HINTS_PERSON_NAME, constants.Text.LIGHTS_ON_ALERT]);
            _points += 50;
        },
        'bug_grown': function () {
            _showTooltip('+50 firstChild');
            _points += 50;
        },
        'glass_repaired': function () {
            _showTooltip('+50 Disaster prevented');
            _points += 50;
        },
        'collect_10_bugs': function () {
            _showTooltip('+100 Mission accomplished');
            _points += 100;
        },
        'logged_in': function () {
            _showTooltip('+50 Inside the system');
            _points += 50;
        },
        'game_over. yes, this is an achievement': function () {
            _showTooltip('+49 Game over...?');
            _points += 49;
        },
        'invisible_bug': function () {
            _points += 50;
        },
        'virus_bug': function () {
            _points += 50;
        },
        'bigger_bug': function () {
            _points += 50;
        },
        'inhibited_bug': function () {
            _points += 50;
        },
        'mutated_bug': function () {
            _points += 50;
        }
    };

    /* Private methods */
    var _getAchievementCount = function () {
        var i = 0;
        for(var a in _achievements) {
            i++;
        }
        return i;
    };

    var _showTooltip = function (text) {
        var jqNode = $(_achievementDomNode);
        jqNode.html(text);
        document.body.appendChild(_achievementDomNode);
        setTimeout(function () {
            jqNode.one('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () {
                setTimeout(function () {
                    if(_achievementDomNode.parentElement) {
                        jqNode.one('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () {
                            document.body.removeChild(_achievementDomNode);
                        });
                        _achievementDomNode.classList.remove('achievementNodeShown');
                    }
                }, _achievementTooltipTimeout);
            });
            _achievementDomNode.classList.add('achievementNodeShown');
        }, 1);
    };

    var _update = function () {
        var achievementTxt = '';
        var achievementCount = 0;
        for(var a in _achievements) {
            achievementTxt += a + '
';
            achievementCount++;
        }
        var totAchievementCount = 0;
        for(var b in _achievementCallbacks) {
            totAchievementCount++;
        }
        for(var i = totAchievementCount - achievementCount; i > 0; i--) {
            achievementTxt += '???
';
        }
        constants.JQ_ACHIEVEMENT_LIST.html(achievementTxt);
        constants.JQ_POINTS.html('' + _points);
    };

    /* PubSub */
    pubSub.subscribe('AchievementManager/achieve', function (evt, name) {
        if(!_achievements[name]) {
            _achievements[name] = true;
            pubSub.publish('AudioManager/playSound', [constants.Sound.SUCCESS]);
            if(_achievementCallbacks[name]) {
                _achievementCallbacks[name]();
            }
            if(window.localStorage) {
                window.localStorage.setItem('achievements', JSON.stringify(_achievements));
                window.localStorage.setItem('points', JSON.stringify(_points));
            }
            _update();
            window._gaq && window._gaq.push(['_trackEvent', 'Game', 'Achievement', name, _getAchievementCount()]);
        }
    });

    pubSub.subscribe('AchievementManager/openSpoiler', function () {
        _hintsCount++;
        _points -= 10;
        pubSub.publish('AudioManager/playSound', [constants.Sound.FAILURE]);
        _update();
        var hintRequested = '';
        if(constants.Text.I_AM_STUCK_TEXT === constants.Text.HINT_DARKNESS) {
            hintRequested = 'cannot_remove_darkness';
        } else if(constants.Text.I_AM_STUCK_TEXT === constants.Text.HINT_GROW_BUGTERIA) {
            hintRequested = 'cannot_grow_bug';
        } else if(constants.Text.I_AM_STUCK_TEXT === constants.Text.HINT_BUGTERIUM_TOO_BIG) {
            hintRequested = 'cannot_move_bug_to_flask';
        } else if(constants.Text.I_AM_STUCK_TEXT === constants.Text.HINT_BUGTERIUM_IN_FLASK) {
            hintRequested = 'cannot_collect_10_bugs';
        }
        window._gaq && window._gaq.push(['_trackEvent', 'Menu', 'Hints', hintRequested, _getAchievementCount()]);
    });

    pubSub.subscribe('AchievementManager/update', _update);

    var AchievementManager = function () {};
    AchievementManager.prototype = {
        getAchievementCount: function () {
            return _getAchievementCount();
        },
        getGivenHintsCount: function () {
            return _hintsCount;
        },
        getPoints: function () {
            return _points;
        },
        getTotalAchievementCount: function () {
            var i = 0;
            for(var a in _achievementCallbacks) {
                i++;
            }
            return i;
        },
        init: function () {
            _achievementDomNode = document.createElement('div');
            _achievementDomNode.classList.add('achievementNode');

            var tmpAchievements, tmpPoints;
            if(window.localStorage) {
                if(tmpAchievements = window.localStorage.getItem('achievements')) {
                    _achievements = JSON.parse(tmpAchievements);
                }
                if(tmpPoints = window.localStorage.getItem('points')) {
                    _points = parseInt(tmpPoints);
                }
            }
        }
    };
    return AchievementManager;
});<|endoftext|>


<commit_before>import absoluteToChr from './absolute-to-chr';

const scalesToGenomeLocations = (xScale, yScale, chromInfo) => {
  if (chromInfo === null) { return; }

  if (!xScale || !yScale) { return; }

  let x1 = absoluteToChr(xScale.domain()[0], chromInfo);
  let x2 = absoluteToChr(xScale.domain()[1], chromInfo);

  let y1 = absoluteToChr(yScale.domain()[0], chromInfo);
  let y2 = absoluteToChr(yScale.domain()[1], chromInfo);

  return [
    x1[0], Math.round(x1[1]),
    x2[0], Math.round(x2[1]),
    y1[0], Math.round(y1[1]),
    y2[0], Math.round(y2[1])
  ];
}

export default scalesToGenomeLocations;
<commit_msg>Remove duplicated code<commit_after><|endoftext|>


<commit_before>'use strict';
import path from 'path';
import Promise from 'bluebird';

import config from '../../config';
import { cloneDatabase, closeDatabase, importRoadNetwork, importPOI } from '../rra-osm-p2p';
import db from '../../db/';
import { setScenarioSetting, getScenarioSetting } from '../../utils/utils';
import { copyFile, copyDirectory, putFileStream, getFileContents, getJSONFileContents, getFileInfo } from '../../s3/utils';
import Operation from '../../utils/operation';
import AppLogger from '../../utils/app-logger';
import * as overpass from '../../utils/overpass';
import { createRoadNetworkVT } from '../../utils/vector-tiles';

const DEBUG = config.debug;
let appLogger = AppLogger({ output: DEBUG });
let logger;

process.on('message', function (e) {
  // Capture all the errors.
  try {
    logger = appLogger.group(`p${e.projId} s${e.scId} scen-create`);
    logger.log('init');
    e.callback = (err) => {
      if (err) return process.exit(1);
      else process.exit(0);
    };
    scenarioCreate(e);
  } catch (err) {
    process.send({type: 'error', data: err.message, stack: err.stack});
    throw err;
  }
});

// The scenario create script is setup so that it run on a different node process
// using fork. This allows us to offload the main server not causing blocking
// operations.

/**
 * Creates a new scenario by cloning the needed files. Depending on the source
 * it either copies the osm-p2p-db from the source scenario, or creates a new
 * one importing the road data from the file.
 *
 * @param  {object} e       Data.
 *         e.opId           Operation Id. It has to be already started.
 *         e.projId         Project Id.
 *         e.scId           Scenario Id.
 *         e.rnSource         Source for the road network (clone | new)
 *         e.rnSourceScenarioId  Id of the source scenario. Relevant if source
 *                             is `clone`.
 *         e.roadNetworkFile   Name of the road network file on s3. Relevant if
 *                             source is `new`.
 *         e.callback
 */
export function scenarioCreate (e) {
  const {
    projId,
    scId,
    opId,
    rnSource,
    rnSourceScenarioId,
    roadNetworkFile,
    poiSource,
    poiSourceScenarioId,
    callback
  } = e;

  let op = new Operation(db);
  op.loadById(opId)
    .then(op => op.log('admin-areas', {message: 'Cloning admin areas'}))
    .then(() => {
      let executor = Promise.resolve();

      logger && logger.log('poiSource', poiSource);
      logger && logger.log('rnSource', rnSource);

      if (poiSource === 'clone') {
        executor = executor
          // Copy the scenario files.
          .then(() => op.log('files', {message: 'Cloning points of interest'}))
          .then(() => db('scenarios_files')
            .select('*')
            .where('scenario_id', poiSourceScenarioId)
            .where('project_id', projId)
            .where('type', 'poi')
            .then(files => cloneScenarioFiles(db, files, projId, scId))
          )
          // Set poi source to file.
          .then(() => db('scenarios_source_data')
            .insert({
              project_id: projId,
              scenario_id: scId,
              name: 'poi',
              type: 'file'
            })
          );
      } else {
        throw new Error(`Poi source is invalid: ${poiSource}`);
      }

      // Road Network: Clone.
      if (rnSource === 'clone') {
        executor = executor
          // Copy the scenario files.
          .then(() => op.log('files', {message: 'Cloning road network'}))
          .then(() => db('scenarios_files')
            .select('*')
            .where('scenario_id', rnSourceScenarioId)
            .where('project_id', projId)
            .where('type', 'road-network')
            .then(files => cloneScenarioFiles(db, files, projId, scId))
          )
          // Set road network source to file.
          .then(() => db('scenarios_source_data')
            .insert({
              project_id: projId,
              scenario_id: scId,
              name: 'road-network',
              type: 'file'
            })
          )
          // Copy the setting for road network edition.
          .then(() => db('scenarios_settings')
            .select('value')
            .where('scenario_id', rnSourceScenarioId)
            .where('key', 'rn_active_editing')
            .first()
            .then(res => setScenarioSetting(db, scId, 'rn_active_editing', res ? res.value : false))
          )
          // Copy vector tiles.
          .then(() => copyDirectory(`scenario-${rnSourceScenarioId}/tiles/road-network`, `scenario-${scId}/tiles/road-network`));

      // Road Network: New
      } else if (rnSource === 'new') {
        executor = executor
          .then(() => op.log('files', {message: 'Uploading new road network'}))
          // Set road network source to file.
          .then(() => db('scenarios_source_data')
            .insert({
              project_id: projId,
              scenario_id: scId,
              name: 'road-network',
              type: 'file'
            })
          )
          // Add entry for road network file.
          .then(() => {
            let now = new Date();
            let data = {
              name: roadNetworkFile,
              type: 'road-network',
              path: `scenario-${scId}/${roadNetworkFile}`,
              project_id: projId,
              scenario_id: scId,
              created_at: now,
              updated_at: now
            };

            return db('scenarios_files')
              .returning('*')
              .insert(data)
              .then(() => data);
          })
          .then(file => Promise.all([file.path, getFileInfo(file.path)]))
          .then(([filePath, fileInfo]) => {
            // Disable road network editing if size over threshold.
            let allowImport = fileInfo.size < config.roadNetEditMax;
            return setScenarioSetting(db, scId, 'rn_active_editing', allowImport)
              .then(() => {
                if (process.env.DS_ENV !== 'test') {
                  logger && logger.log('process road network');
                  return createRoadNetworkVT(projId, scId, op, filePath).promise;
                }
              });
          });

      // Road Network: Osm
      } else if (rnSource === 'osm') {
        executor = executor
          .then(() => op.log('files', {message: 'Importing road network'}))
          // Set road network source to osm.
          .then(() => db('scenarios_source_data')
            .insert({
              project_id: projId,
              scenario_id: scId,
              name: 'road-network',
              type: 'osm'
            })
          )
          // Get the bbox for the overpass import.
          .then(() => db('projects')
            .select('bbox')
            .where('id', projId)
            .first()
            .then(res => res.bbox)
          )
          .then(bbox => overpass.importRoadNetwork(overpass.convertBbox(bbox)))
          // Just to log error
          .catch(err => {
            logger && logger.log('Error importing from overpass', err.message);
            throw err;
          })
          .then(osmData => {
            // Insert file into DB.
            let fileName = `road-network_${Date.now()}`;
            let filePath = `scenario-${scId}/${fileName}`;
            let data = {
              name: fileName,
              type: 'road-network',
              path: filePath,
              project_id: projId,
              scenario_id: scId,
              created_at: (new Date()),
              updated_at: (new Date())
            };

            return putFileStream(filePath, osmData)
              .then(() => db('scenarios_files').insert(data))
              .then(() => data);
          })
          .then(file => Promise.all([file.path, getFileInfo(file.path)]))
          .then(([filePath, fileInfo]) => {
            // Disable road network editing if size over threshold.
            let allowImport = fileInfo.size < config.roadNetEditMax;
            return setScenarioSetting(db, scId, 'rn_active_editing', allowImport)
              .then(() => {
                if (process.env.DS_ENV !== 'test') {
                  logger && logger.log('process road network');
                  return createRoadNetworkVT(projId, scId, op, filePath).promise;
                }
              });
          });
      } else {
        throw new Error(`Road network source is invalid: ${rnSource}`);
      }

      // If we're cloning both the pois and the rn from the same source
      // we can just clone the database. There's no need to import.
      if (rnSource === 'clone' && poiSource === 'clone' && rnSourceScenarioId === poiSourceScenarioId) {
        logger && logger.log('Cloning from same source. Duplicating osm db.');
        executor = executor
          // Copy the osm-p2p-db.
          .then(() => op.log('files', {message: 'Cloning osm database'}))
          .then(() => closeDatabase(projId, scId))
          .then(() => cloneOsmP2Pdb(projId, rnSourceScenarioId, projId, scId));
      } else {
        // Is there any importing to do?
        executor = executor
          .then(() => getScenarioSetting(db, scId, 'rn_active_editing'))
          // No import. Stop the chain with an error.
          .then(editing => {
            if (!editing) {
              logger && logger.log('Road network editing inactive.');
              throw new Error('not editing');
            }
          })
          // Get the road network from cache or form the db.
          .then(() => db('scenarios_files')
            .select('*')
            .where('project_id', projId)
            .where('scenario_id', scId)
            .where('type', 'road-network')
            .first()
            .then(file => getFileContents(file.path))
          )
          // Import into osm db.
          .then(roadNetwork => {
            let rnLogger = appLogger.group(`p${projId} s${scId} rn import`);
            rnLogger && rnLogger.log('process road network');
            return importRoadNetwork(projId, scId, op, roadNetwork, rnLogger);
          })
          // Get all the pois and create a feature collection.
          .then(() => db('scenarios_files')
            .select('*')
            .where('project_id', projId)
            .where('scenario_id', scId)
            .where('type', 'poi')
            .then(files => Promise.all([
              files,
              Promise.map(files, file => getJSONFileContents(file.path))
            ]))
            .then(([files, filesContent]) => {
              // Merge all feature collection together.
              // Add a property to keep track of the poi type.
              return {
                type: 'FeatureCollection',
                features: files.reduce((acc, file, idx) => {
                  let key = file.subtype;
                  let features = filesContent[idx].features;
                  features.forEach(f => { f.properties.ram_poi_type = key; });
                  return acc.concat(features);
                }, [])
              };
            })
          )
          // Import into osm db.
          .then(poiFc => {
            let poiLogger = appLogger.group(`p${projId} s${scId} poi import`);
            poiLogger && poiLogger.log('process poi');
            return importPOI(projId, scId, op, poiFc, poiLogger);
          })
          // Ignore not editing error.
          .catch(e => { if (e.message !== 'not editing') throw e; });
      }

      return executor
        .then(() => db('scenarios').update({status: 'active', updated_at: (new Date())}).where('id', scId))
        .then(() => db('projects').update({updated_at: (new Date())}).where('id', projId))
        .then(() => op.log('success', {message: 'Operation complete'}).then(op => op.finish()));
    })
    // Note: There's no need to close the osm-p2p-db because when the process
    // terminates the connection is automatically closed.
    .then(() => {
      logger && logger.log('process complete');
      DEBUG && appLogger && appLogger.toFile(path.resolve(__dirname, `../../../scenario-create_p${projId}s${scId}.log`));
      callback();
    })
    .catch(err => {
      logger && logger.log('error', err);
      DEBUG && appLogger && appLogger.toFile(path.resolve(__dirname, `../../../scenario-create_p${projId}s${scId}.log`));

      return op.log('error', {error: err.message})
        .then(() => op.finish())
        // If the process fails do some cleanup of what was not in
        // a transaction, namely the files, and the originally create scenario.
        // .then(() => onFailCleanup(projId, scId))
        .then(() => callback(err.message), () => callback(err.message));
    });
}

// Copies the given files from a to the new scenario, both the database entries
// and the physical file.
function cloneScenarioFiles (db, files, projId, scId) {
  logger && logger.log('cloning files');
  let newFiles = files.map(file => {
    const fileName = file.type === 'poi'
      ? `${file.type}_${file.subtype}_${Date.now()}`
      : `${file.type}_${Date.now()}`;

    const filePath = `scenario-${scId}/${fileName}`;

    return {
      name: fileName,
      type: file.type,
      subtype: file.subtype,
      path: filePath,
      project_id: projId,
      scenario_id: scId,
      created_at: (new Date()),
      updated_at: (new Date())
    };
  });

  return Promise.resolve([files, newFiles])
    // Insert new files in the db.
    .then(allFiles => {
      let [oldFiles, newFiles] = allFiles;
      return db.batchInsert('scenarios_files', newFiles).then(() => [oldFiles, newFiles]);
    })
    // Copy files on s3.
    .then(allFiles => {
      let [oldFiles, newFiles] = allFiles;
      return Promise.map(oldFiles, (old, i) => copyFile(old.path, newFiles[i].path));
    });
}

// Clone the osm-p2p-db.
function cloneOsmP2Pdb (srcProjId, srcScId, destProjId, destScId) {
  logger && logger.log('cloning osm-p2p-db');
  return cloneDatabase(srcProjId, srcScId, destProjId, destScId)
    .catch(err => {
      // If the road network is too big, the db is not created.
      // Account for this and avoid errors.
      // TODO: Check if the DB is supposed to not exist.
      if (err.code !== 'ENOENT') {
        throw err;
      }
    });
}
<commit_msg>Add wbcatalog source selection to scenario create<commit_after>'use strict';
import path from 'path';
import Promise from 'bluebird';

import config from '../../config';
import { cloneDatabase, closeDatabase, importRoadNetwork, importPOI } from '../rra-osm-p2p';
import db from '../../db/';
import { setScenarioSetting, getScenarioSetting } from '../../utils/utils';
import { copyFile, copyDirectory, putFileStream, getFileContents, getJSONFileContents, getFileInfo } from '../../s3/utils';
import Operation from '../../utils/operation';
import AppLogger from '../../utils/app-logger';
import * as overpass from '../../utils/overpass';
import { createRoadNetworkVT } from '../../utils/vector-tiles';
import { downloadWbCatalogScenarioFile } from '../../utils/wbcatalog';

const DEBUG = config.debug;
let appLogger = AppLogger({ output: DEBUG });
let logger;

process.on('message', function (e) {
  // Capture all the errors.
  try {
    logger = appLogger.group(`p${e.projId} s${e.scId} scen-create`);
    logger.log('init');
    e.callback = (err) => {
      if (err) return process.exit(1);
      else process.exit(0);
    };
    scenarioCreate(e);
  } catch (err) {
    process.send({type: 'error', data: err.message, stack: err.stack});
    throw err;
  }
});

// The scenario create script is setup so that it run on a different node process
// using fork. This allows us to offload the main server not causing blocking
// operations.

/**
 * Creates a new scenario by cloning the needed files. Depending on the source
 * it either copies the osm-p2p-db from the source scenario, or creates a new
 * one importing the road data from the file.
 *
 * @param  {object} e       Data.
 *         e.opId           Operation Id. It has to be already started.
 *         e.projId         Project Id.
 *         e.scId           Scenario Id.
 *         e.rnSource         Source for the road network (clone | new)
 *         e.rnSourceScenarioId  Id of the source scenario. Relevant if source
 *                             is `clone`.
 *         e.roadNetworkFile   Name of the road network file on s3. Relevant if
 *                             source is `new`.
 *         e.callback
 */
export function scenarioCreate (e) {
  const {
    projId,
    scId,
    opId,
    rnSource,
    rnSourceScenarioId,
    roadNetworkFile,
    poiSource,
    poiSourceScenarioId,
    rnSourceWbCatalogOption,
    callback
  } = e;

  let op = new Operation(db);
  op.loadById(opId)
    .then(op => op.log('admin-areas', {message: 'Cloning admin areas'}))
    .then(() => {
      let executor = Promise.resolve();

      logger && logger.log('poiSource', poiSource);
      logger && logger.log('rnSource', rnSource);

      if (poiSource === 'clone') {
        executor = executor
          // Copy the scenario files.
          .then(() => op.log('files', {message: 'Cloning points of interest'}))
          .then(() => db('scenarios_files')
            .select('*')
            .where('scenario_id', poiSourceScenarioId)
            .where('project_id', projId)
            .where('type', 'poi')
            .then(files => cloneScenarioFiles(db, files, projId, scId))
          )
          // Set poi source to file.
          .then(() => db('scenarios_source_data')
            .insert({
              project_id: projId,
              scenario_id: scId,
              name: 'poi',
              type: 'file'
            })
          );
      } else {
        throw new Error(`Poi source is invalid: ${poiSource}`);
      }

      const settingsAndVtProcess = ([filePath, fileInfo]) => {
        // Disable road network editing if size over threshold.
        let allowImport = fileInfo.size < config.roadNetEditMax;
        return setScenarioSetting(db, scId, 'rn_active_editing', allowImport)
          .then(() => {
            if (process.env.DS_ENV !== 'test') {
              logger && logger.log('process road network');
              return createRoadNetworkVT(projId, scId, op, filePath).promise;
            }
          });
      };

      // Road Network: Clone.
      if (rnSource === 'clone') {
        executor = executor
          // Copy the scenario files.
          .then(() => op.log('files', {message: 'Cloning road network'}))
          .then(() => db('scenarios_files')
            .select('*')
            .where('scenario_id', rnSourceScenarioId)
            .where('project_id', projId)
            .where('type', 'road-network')
            .then(files => cloneScenarioFiles(db, files, projId, scId))
          )
          // Set road network source to file.
          .then(() => db('scenarios_source_data')
            .insert({
              project_id: projId,
              scenario_id: scId,
              name: 'road-network',
              type: 'file'
            })
          )
          // Copy the setting for road network edition.
          .then(() => db('scenarios_settings')
            .select('value')
            .where('scenario_id', rnSourceScenarioId)
            .where('key', 'rn_active_editing')
            .first()
            .then(res => setScenarioSetting(db, scId, 'rn_active_editing', res ? res.value : false))
          )
          // Copy vector tiles.
          .then(() => copyDirectory(`scenario-${rnSourceScenarioId}/tiles/road-network`, `scenario-${scId}/tiles/road-network`));

      // Road Network: New
      } else if (rnSource === 'new') {
        executor = executor
          .then(() => op.log('files', {message: 'Uploading new road network'}))
          // Set road network source to file.
          .then(() => db('scenarios_source_data')
            .insert({
              project_id: projId,
              scenario_id: scId,
              name: 'road-network',
              type: 'file'
            })
          )
          // Add entry for road network file.
          .then(() => {
            let now = new Date();
            let data = {
              name: roadNetworkFile,
              type: 'road-network',
              path: `scenario-${scId}/${roadNetworkFile}`,
              project_id: projId,
              scenario_id: scId,
              created_at: now,
              updated_at: now
            };

            return db('scenarios_files')
              .returning('*')
              .insert(data)
              .then(() => data);
          })
          .then(file => Promise.all([file.path, getFileInfo(file.path)]))
          .then(settingsAndVtProcess);

      // Road Network: Osm
      } else if (rnSource === 'osm') {
        executor = executor
          .then(() => op.log('files', {message: 'Importing road network'}))
          // Set road network source to osm.
          .then(() => db('scenarios_source_data')
            .insert({
              project_id: projId,
              scenario_id: scId,
              name: 'road-network',
              type: 'osm'
            })
          )
          // Get the bbox for the overpass import.
          .then(() => db('projects')
            .select('bbox')
            .where('id', projId)
            .first()
            .then(res => res.bbox)
          )
          .then(bbox => overpass.importRoadNetwork(overpass.convertBbox(bbox)))
          // Just to log error
          .catch(err => {
            logger && logger.log('Error importing from overpass', err.message);
            throw err;
          })
          .then(osmData => {
            // Insert file into DB.
            let fileName = `road-network_${Date.now()}`;
            let filePath = `scenario-${scId}/${fileName}`;
            let data = {
              name: fileName,
              type: 'road-network',
              path: filePath,
              project_id: projId,
              scenario_id: scId,
              created_at: (new Date()),
              updated_at: (new Date())
            };

            return putFileStream(filePath, osmData)
              .then(() => db('scenarios_files').insert(data))
              .then(() => data);
          })
          .then(file => Promise.all([file.path, getFileInfo(file.path)]))
          .then(settingsAndVtProcess);

      // Road Network: WB Catalog
      } else if (rnSource === 'wbcatalog') {
        executor = executor
          .then(() => op.log('files', {message: 'Downloading road network'}))
          // Set road network source to osm.
          .then(() => {
            const data = {
              project_id: projId,
              scenario_id: scId,
              name: 'road-network',
              type: 'wbcatalog',
              // See scenario--source-data.js about this structure.
              data: JSON.stringify({ resources: [{ key: rnSourceWbCatalogOption }] })
            };
            return db('scenarios_source_data')
              .returning('*')
              .insert(data)
              .then(res => res[0]);
          })
          .then(source => downloadWbCatalogScenarioFile(projId, scId, source, logger))
          .then(file => Promise.all([file.path, getFileInfo(file.path)]))
          .then(settingsAndVtProcess);
      } else {
        throw new Error(`Road network source is invalid: ${rnSource}`);
      }

      // If we're cloning both the pois and the rn from the same source
      // we can just clone the database. There's no need to import.
      if (rnSource === 'clone' && poiSource === 'clone' && rnSourceScenarioId === poiSourceScenarioId) {
        logger && logger.log('Cloning from same source. Duplicating osm db.');
        executor = executor
          // Copy the osm-p2p-db.
          .then(() => op.log('files', {message: 'Cloning osm database'}))
          .then(() => closeDatabase(projId, scId))
          .then(() => cloneOsmP2Pdb(projId, rnSourceScenarioId, projId, scId));
      } else {
        // Is there any importing to do?
        executor = executor
          .then(() => getScenarioSetting(db, scId, 'rn_active_editing'))
          // No import. Stop the chain with an error.
          .then(editing => {
            if (!editing) {
              logger && logger.log('Road network editing inactive.');
              throw new Error('not editing');
            }
          })
          // Get the road network from the db.
          .then(() => db('scenarios_files')
            .select('*')
            .where('project_id', projId)
            .where('scenario_id', scId)
            .where('type', 'road-network')
            .first()
            .then(file => getFileContents(file.path))
          )
          // Import into osm db.
          .then(roadNetwork => {
            let rnLogger = appLogger.group(`p${projId} s${scId} rn import`);
            rnLogger && rnLogger.log('process road network');
            return importRoadNetwork(projId, scId, op, roadNetwork, rnLogger);
          })
          // Get all the pois and create a feature collection.
          .then(() => db('scenarios_files')
            .select('*')
            .where('project_id', projId)
            .where('scenario_id', scId)
            .where('type', 'poi')
            .then(files => Promise.all([
              files,
              Promise.map(files, file => getJSONFileContents(file.path))
            ]))
            .then(([files, filesContent]) => {
              // Merge all feature collection together.
              // Add a property to keep track of the poi type.
              return {
                type: 'FeatureCollection',
                features: files.reduce((acc, file, idx) => {
                  let key = file.subtype;
                  let features = filesContent[idx].features;
                  features.forEach(f => { f.properties.ram_poi_type = key; });
                  return acc.concat(features);
                }, [])
              };
            })
          )
          // Import into osm db.
          .then(poiFc => {
            let poiLogger = appLogger.group(`p${projId} s${scId} poi import`);
            poiLogger && poiLogger.log('process poi');
            return importPOI(projId, scId, op, poiFc, poiLogger);
          })
          // Ignore not editing error.
          .catch(e => { if (e.message !== 'not editing') throw e; });
      }

      return executor
        .then(() => db('scenarios').update({status: 'active', updated_at: (new Date())}).where('id', scId))
        .then(() => db('projects').update({updated_at: (new Date())}).where('id', projId))
        .then(() => op.log('success', {message: 'Operation complete'}).then(op => op.finish()));
    })
    // Note: There's no need to close the osm-p2p-db because when the process
    // terminates the connection is automatically closed.
    .then(() => {
      logger && logger.log('process complete');
      DEBUG && appLogger && appLogger.toFile(path.resolve(__dirname, `../../../scenario-create_p${projId}s${scId}.log`));
      callback();
    })
    .catch(err => {
      logger && logger.log('error', err);
      DEBUG && appLogger && appLogger.toFile(path.resolve(__dirname, `../../../scenario-create_p${projId}s${scId}.log`));

      return op.log('error', {error: err.message})
        .then(() => op.finish())
        // If the process fails do some cleanup of what was not in
        // a transaction, namely the files, and the originally create scenario.
        // .then(() => onFailCleanup(projId, scId))
        .then(() => callback(err.message), () => callback(err.message));
    });
}

// Copies the given files from a to the new scenario, both the database entries
// and the physical file.
function cloneScenarioFiles (db, files, projId, scId) {
  logger && logger.log('cloning files');
  let newFiles = files.map(file => {
    const fileName = file.type === 'poi'
      ? `${file.type}_${file.subtype}_${Date.now()}`
      : `${file.type}_${Date.now()}`;

    const filePath = `scenario-${scId}/${fileName}`;

    return {
      name: fileName,
      type: file.type,
      subtype: file.subtype,
      path: filePath,
      project_id: projId,
      scenario_id: scId,
      created_at: (new Date()),
      updated_at: (new Date())
    };
  });

  return Promise.resolve([files, newFiles])
    // Insert new files in the db.
    .then(allFiles => {
      let [oldFiles, newFiles] = allFiles;
      return db.batchInsert('scenarios_files', newFiles).then(() => [oldFiles, newFiles]);
    })
    // Copy files on s3.
    .then(allFiles => {
      let [oldFiles, newFiles] = allFiles;
      return Promise.map(oldFiles, (old, i) => copyFile(old.path, newFiles[i].path));
    });
}

// Clone the osm-p2p-db.
function cloneOsmP2Pdb (srcProjId, srcScId, destProjId, destScId) {
  logger && logger.log('cloning osm-p2p-db');
  return cloneDatabase(srcProjId, srcScId, destProjId, destScId)
    .catch(err => {
      // If the road network is too big, the db is not created.
      // Account for this and avoid errors.
      // TODO: Check if the DB is supposed to not exist.
      if (err.code !== 'ENOENT') {
        throw err;
      }
    });
}
<|endoftext|>


<commit_before>import styled from 'styled-components';
import Box from 'grommet-udacity/components/Box';
import Heading from 'grommet-udacity/components/Heading';
import TableRow from 'grommet-udacity/components/TableRow';
import GrommetLabel from 'grommet-udacity/components/Label';
import GrommetSelect from 'grommet-udacity/components/Select';

export const BoxWrapper = styled(Box)`
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-direction: row !important;
  width: 100%;
  margin-top: 40px;
`;

export const InnerWrapper = styled(Box)`
  width: 80vw;
  justify-content: center;
`;

export const ListWrapper = styled(Box)`
  min-height: 600px;
  max-width: 100vw !important;
  box-sizing: border-box;
`;

export const GrowBox = styled(Box)`
  flex-grow: 1;
  @media screen and (max-width: 1200px) {
    flex-grow: 0;
    max-width: 100vw;
    box-sizing: border-box;
  }
`;

export const UserName = styled(Heading)`
  flex: 1;
`;

export const TD = styled.td`
  min-width: 220px;
  @media screen and (max-width: 1200px) {
    min-width: 100px;
  }
`;

export const TRow = styled(TableRow)`
  cursor: pointer;
  &:hover {
    background-color: ${props => props.isEditing ? '#fff' : '#eee'};
  }
  border-bottom: 1px solid #eee;
`;

export const Input = styled.input`
  display: flex;
  flex: 1;
  margin-left: 20px !important;
`;

export const TextArea = styled.textarea`
  display: flex;
  flex: 1;
  margin-left: 20px !important;
`;

export const Label = styled(GrommetLabel)`
  width: 50px;
  margin: 5px;
`;

export const SelectBig = styled(GrommetSelect)`
  display: flex;
  flex: 1;
  margin-left: 20px;
  input {
    display: flex;
    flex: 1;
  }
`;
<commit_msg>Feat: add padding to user dash table<commit_after>import styled from 'styled-components';
import Box from 'grommet-udacity/components/Box';
import Heading from 'grommet-udacity/components/Heading';
import TableRow from 'grommet-udacity/components/TableRow';
import GrommetLabel from 'grommet-udacity/components/Label';
import GrommetSelect from 'grommet-udacity/components/Select';

export const BoxWrapper = styled(Box)`
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-direction: row !important;
  width: 100%;
  margin-top: 40px;
`;

export const InnerWrapper = styled(Box)`
  width: 80vw;
  justify-content: center;
`;

export const ListWrapper = styled(Box)`
  min-height: 600px;
  max-width: 100vw !important;
  box-sizing: border-box;
  padding-top: 40px;
  padding-bottom: 40px;
`;

export const GrowBox = styled(Box)`
  flex-grow: 1;
  @media screen and (max-width: 1200px) {
    flex-grow: 0;
    max-width: 100vw;
    box-sizing: border-box;
  }
`;

export const UserName = styled(Heading)`
  flex: 1;
`;

export const TD = styled.td`
  min-width: 220px;
  @media screen and (max-width: 1200px) {
    min-width: 100px;
  }
`;

export const TRow = styled(TableRow)`
  cursor: pointer;
  &:hover {
    background-color: ${props => props.isEditing ? '#fff' : '#eee'};
  }
  border-bottom: 1px solid #eee;
`;

export const Input = styled.input`
  display: flex;
  flex: 1;
  margin-left: 20px !important;
`;

export const TextArea = styled.textarea`
  display: flex;
  flex: 1;
  margin-left: 20px !important;
`;

export const Label = styled(GrommetLabel)`
  width: 50px;
  margin: 5px;
`;

export const SelectBig = styled(GrommetSelect)`
  display: flex;
  flex: 1;
  margin-left: 20px;
  input {
    display: flex;
    flex: 1;
  }
`;
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var passport = require('passport')
  , https = require('https')
  , querystring = require('querystring')
  , util = require('util')

/**
 * `Strategy` constructor.
 *
 * The BrowserID authentication strategy authenticates requests using the
 * BrowserID JavaScript API and Verified Email Protocol (VEP).
 *
 * BrowserID provides a federated and decentralized universal login system for
 * the web, based on email addresses as an identity token.  Authenticating in
 * this this manner involves a sequence of events, including prompting the user,
 * via their user agent, for an assertion of email address ownership.  Once this
 * assertion is obtained, it can be verified and the user can be authenticated.
 *
 * Applications must supply a `validate` callback which accepts an `email`
 * address, and then calls the `done` callback supplying a `user`, which should
 * be set to `false` if the credentials are not valid.  If an exception occured,
 * `err` should be set.
 *
 * Options:
 *   - `audience`        the website requesting and verifying an identity assertion
 *   - `assertionField`  field name where the assertion is found, defaults to 'assertion'
 *
 * Examples:
 *
 *     passport.use(new BrowserIDStrategy({
 *         audience: 'http://www.example.com'
 *       },
 *       function(email, done) {
 *         User.findByEmail(email, function (err, user) {
 *           done(err, user);
 *         });
 *       }
 *     ));
 *
 * @param {Object} options
 * @param {Function} validate
 * @api public
 */
function Strategy(options, validate) {
  if (!options.audience) throw new Error('BrowserID authentication requires an audience option');
  if (!validate) throw new Error('BrowserID authentication strategy requires a validate function');

  passport.Strategy.call(this);
  this.name = 'browserid';
  this._validate = validate;

  this._audience = options.audience;
  this._assertionField = options.assertionField || 'assertion';

  // options used to inject mock objects for testing purposes
  this._https = options.transport || https;
}

/**
 * Inherit from `passport.Strategy`.
 */
util.inherits(Strategy, passport.Strategy);

/**
 * Authenticate request by using browserid.org as a trusted secondary authority
 * for verifying email assertions.
 *
 * @param {Object} req
 * @api protected
 */
Strategy.prototype.authenticate = function(req) {
  var self = this;

  if (!req.body || !req.body[this._assertionField]) {
    return this.fail();
  }

  var assertion = req.body[this._assertionField];

  var query = querystring.stringify({ assertion: assertion, audience: this._audience });
  var headers = {};
  headers['Host'] = 'browserid.org';
  headers['Content-Type'] = 'application/x-www-form-urlencoded';
  headers['Content-Length'] = query.length;

  var options = {
    host: 'browserid.org',
    port: 443,
    path: '/verify',
    method: 'POST',
    headers: headers
  };
  var req = this._https.request(options, function(res) {
    var data = '';
    res.on('data', function(chunk) {
      data += chunk;
    });
    res.on('end', function() {
      try {
        var result = JSON.parse(data);
        if (result.status === 'okay') {
          return verified(result)
        } else {
          // TODO: Implement a mechanism in Passport to provide errors when
          //       authentication failures occur.
          // return self.fail(new Error(result.reason));
          return self.fail();
        }
      } catch(err) {
        return self.error(err);
      }
    });
    res.on('error', function(err) {
      return self.error(err);
    });
  });
  req.end(query, 'utf8');

  // TODO: Check that the audience matches this server, according to the Host
  //       header.  Also, implement an option to disable this check (defaulting
  //       to false).

  function verified(result) {
    self._validate(result.email, function(err, user) {
      if (err) { return self.error(err); }
      if (!user) { return self.fail(); }
      self.success(user);
    });
  }
}

/**
 * Expose `Strategy`.
 */
module.exports = Strategy;
<commit_msg>Standardize on verify callback terminology.<commit_after>/**
 * Module dependencies.
 */
var passport = require('passport')
  , https = require('https')
  , querystring = require('querystring')
  , util = require('util')

/**
 * `Strategy` constructor.
 *
 * The BrowserID authentication strategy authenticates requests using the
 * BrowserID JavaScript API and Verified Email Protocol (VEP).
 *
 * BrowserID provides a federated and decentralized universal login system for
 * the web, based on email addresses as an identity token.  Authenticating in
 * this this manner involves a sequence of events, including prompting the user,
 * via their user agent, for an assertion of email address ownership.  Once this
 * assertion is obtained, it can be verified and the user can be authenticated.
 *
 * Applications must supply a `verify` callback which accepts an `email`
 * address, and then calls the `done` callback supplying a `user`, which should
 * be set to `false` if the credentials are not valid.  If an exception occured,
 * `err` should be set.
 *
 * Options:
 *   - `audience`        the website requesting and verifying an identity assertion
 *   - `assertionField`  field name where the assertion is found, defaults to 'assertion'
 *
 * Examples:
 *
 *     passport.use(new BrowserIDStrategy({
 *         audience: 'http://www.example.com'
 *       },
 *       function(email, done) {
 *         User.findByEmail(email, function (err, user) {
 *           done(err, user);
 *         });
 *       }
 *     ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function Strategy(options, verify) {
  if (!options.audience) throw new Error('BrowserID authentication requires an audience option');
  if (!verify) throw new Error('BrowserID authentication strategy requires a verify function');

  passport.Strategy.call(this);
  this.name = 'browserid';
  this._verify = verify;

  this._audience = options.audience;
  this._assertionField = options.assertionField || 'assertion';

  // options used to inject mock objects for testing purposes
  this._https = options.transport || https;
}

/**
 * Inherit from `passport.Strategy`.
 */
util.inherits(Strategy, passport.Strategy);

/**
 * Authenticate request by using browserid.org as a trusted secondary authority
 * for verifying email assertions.
 *
 * @param {Object} req
 * @api protected
 */
Strategy.prototype.authenticate = function(req) {
  var self = this;

  if (!req.body || !req.body[this._assertionField]) {
    return this.fail();
  }

  var assertion = req.body[this._assertionField];

  var query = querystring.stringify({ assertion: assertion, audience: this._audience });
  var headers = {};
  headers['Host'] = 'browserid.org';
  headers['Content-Type'] = 'application/x-www-form-urlencoded';
  headers['Content-Length'] = query.length;

  var options = {
    host: 'browserid.org',
    port: 443,
    path: '/verify',
    method: 'POST',
    headers: headers
  };
  var req = this._https.request(options, function(res) {
    var data = '';
    res.on('data', function(chunk) {
      data += chunk;
    });
    res.on('end', function() {
      try {
        var result = JSON.parse(data);
        if (result.status === 'okay') {
          return verified(result)
        } else {
          // TODO: Implement a mechanism in Passport to provide errors when
          //       authentication failures occur.
          // return self.fail(new Error(result.reason));
          return self.fail();
        }
      } catch(err) {
        return self.error(err);
      }
    });
    res.on('error', function(err) {
      return self.error(err);
    });
  });
  req.end(query, 'utf8');

  // TODO: Check that the audience matches this server, according to the Host
  //       header.  Also, implement an option to disable this check (defaulting
  //       to false).

  function verified(result) {
    self._verify(result.email, function(err, user) {
      if (err) { return self.error(err); }
      if (!user) { return self.fail(); }
      self.success(user);
    });
  }
}

/**
 * Expose `Strategy`.
 */
module.exports = Strategy;
<|endoftext|>


<commit_before>var concat = require('gulp-concat'),
    remember = require('gulp-remember'),
    order = require('gulp-order'),
    closure = require('../../js/closure'),
    pipeChain = require('../../util/pipeChain');

module.exports = storeSolidPlugin;

/**
 * @ignore
 * Creates a single file of all concatenated modules preceded by a `init.js` contents.
 * Used for synchronous single-file projects.
 * @alias "modules.storeSolid"
 * @returns {stream.Transform} Stream
 */
function storeSolidPlugin (cfg) {
    return pipeChain(
        remember('ymb#default'),
        order(['init.js', '*']),
        concat(cfg.concatTo),
        closure(cfg)
    );
}<commit_msg>cache fix<commit_after>var concat = require('gulp-concat'),
    remember = require('gulp-remember'),
    order = require('gulp-order'),
    closure = require('../../js/closure'),
    pipeChain = require('../../util/pipeChain');

module.exports = storeSolidPlugin;

/**
 * @ignore
 * Creates a single file of all concatenated modules preceded by a `init.js` contents.
 * Used for synchronous single-file projects.
 * @alias "modules.storeSolid"
 * @returns {stream.Transform} Stream
 */
function storeSolidPlugin (cfg) {
    return pipeChain(
        remember(cfg.name || 'ymb#default'),
        order(['init.js', '*']),
        concat(cfg.concatTo),
        closure(cfg)
    );
}
<|endoftext|>