<commit_before>var map, gj, dtpicker, n0q;
var varname = 'tmpf';
var currentdt = new Date(defaultdt);

function pad(number) {
    var r = String(number);
    if ( r.length === 1 ) {
      r = '0' + r;
    }
    return r;
  }

Date.prototype.toIEMString = function() {
	return this.getUTCFullYear()
    + pad( this.getUTCMonth() + 1 )
    + pad( this.getUTCDate() )
    + pad( this.getUTCHours() )
    + '00';
};

if ( !Date.prototype.toISOString ) {
	  ( function() {

	    Date.prototype.toISOString = function() {
	      return this.getUTCFullYear()
	        + '-' + pad( this.getUTCMonth() + 1 )
	        + '-' + pad( this.getUTCDate() )
	        + 'T' + pad( this.getUTCHours() )
	        + ':' + pad( this.getUTCMinutes() )
	        + ':' + pad( this.getUTCSeconds() )
	        + '.' + String( (this.getUTCMilliseconds()/1000).toFixed(3) ).slice( 2, 5 )
	        + 'Z';
	    };

	  }() );
	}

function logic( dstring ){
	currentdt = dtpicker.datetimepicker('getDate'); // toISOString()
	updateMap();
}
function updateTitle(){
	$('#maptitle').text("The map is displaying "
			+ $('#varpicker :selected').text() + " valid at "+ currentdt);
}
function updateMap(){
	if (currentdt && typeof currentdt != "string"){
		gj.protocol.params.dt = currentdt.toISOString();
	}
	gj.refresh();
	if (n0q.getVisibility()){
		n0q.redraw();
		n0q.setVisibility(false);
		n0q.setVisibility(true);
	}
	updateTitle();
}
function get_my_url (bounds) {
    var res = this.map.getResolution();
    var x = Math.round((bounds.left - this.maxExtent.left)
                    / (res * this.tileSize.w));
    var y = Math.round((this.maxExtent.top - bounds.top)
                    / (res * this.tileSize.h));
    var z = this.map.getZoom();

    var path = z + "/" + x + "/" + y + "." + this.type ;
            /* Need no cache buster now that our service IDs are unique
             * + "?"+ parseInt(Math.random() * 9999);
             */
    var url = this.url;
    if (url instanceof Array) {
            url = this.selectUrl(path, url);
    }
    return url + this.service + "/ridge::" + this.radar + "-" + this.radarProduct + "-"
    +  currentdt.toIEMString() + "/" + path;
}
function get_my_url2(bounds){
    var res = this.map.getResolution();
    var x = Math.round((bounds.left - this.maxExtent.left)
                    / (res * this.tileSize.w));
    var y = Math.round((this.maxExtent.top - bounds.top)
                    / (res * this.tileSize.h));
    var z = this.map.getZoom();

    var path = z + "/" + x + "/" + y + "." + this.type + "?"
                    + parseInt(Math.random() * 9999);
    var url = this.url;
    if (url instanceof Array) {
            url = this.selectUrl(path, url);
    }
    return url + this.service + "/" + this.layername + "/" + path;
}

function init(){
	  // Build Map Object
	  map = new OpenLayers.Map( 'map',{
	        projection: new OpenLayers.Projection('EPSG:900913'),
	        displayProjection: new OpenLayers.Projection('EPSG:4326'),
	        units: 'm',
	        wrapDateLine: false,
	        numZoomLevels: 18,
	        maxResolution: 156543.0339,
	        maxExtent: new OpenLayers.Bounds(-20037508, -20037508,
	                                         20037508, 20037508.34)
	  });
	  // Traditional Google Map Layer
	  var googleLayer = new OpenLayers.Layer.Google(
	                'Google Streets',
	                 {'sphericalMercator': true}
	            );

      n0q = new OpenLayers.Layer.TMS(
              'NEXRAD Base Reflectivity',
              'http://mesonet1.agron.iastate.edu/cache/tile.py/', {
                  layername : 'bogus',
                  service : '1.0.0',
                  type : 'png',
                  visibility : true,
                  opacity : 1,
                  getURL : get_my_url,
                  radarProduct : 'N0Q',
                  radar : 'USCOMP',
                  isBaseLayer : false
          }
      );

      var context = {
    		  getLabel: function(feature){
    			  return feature.data[varname];
    		  }
      };

	  var template = OpenLayers.Util.extend({
               label : "${getLabel}",
               fontColor: "black",
               fontSize: "14px",
               fontFamily: "monospace",
               fontWeight: "bold",
               labelOutlineColor: "yellow",
               labelOutlineWidth: 6
	   });
      var style = new OpenLayers.Style(template, {context: context});
      var styleMap = new OpenLayers.StyleMap(style);

	  gj = new OpenLayers.Layer.Vector("Data", {
		  protocol: new OpenLayers.Protocol.HTTP({
			  params: {dt: currentdt.toISOString()},
	          url: "/geojson/agclimate.py",
	          format: new OpenLayers.Format.GeoJSON()
	      }),
	      projection: new OpenLayers.Projection('EPSG:4326'),
	      styleMap: styleMap,
	      strategies: [new OpenLayers.Strategy.Fixed()]
	  });

	  states = new OpenLayers.Layer.TMS('US States',
              'https://mesonet.agron.iastate.edu/c/c.py/', {
                      layername : 's-900913',
                      service : '1.0.0',
                      type : 'png',
                      visibility : true,
                      opacity : 1,
                      getURL : get_my_url2,
                      isBaseLayer : false
              });

	  map.addLayers([googleLayer, n0q, states, gj]);

	  var proj = new OpenLayers.Projection('EPSG:4326');
	   var proj2 = new OpenLayers.Projection('EPSG:900913');
	   var point = new OpenLayers.LonLat(-93.8, 42.2);
	   point.transform(proj, proj2);

	   map.setCenter(point, 7);

	   map.addControl( new OpenLayers.Control.LayerSwitcher({id:'ls'}) );
	   map.addControl( new OpenLayers.Control.MousePosition() );

	   dtpicker = $('#datetimepicker');
	   dtpicker.datetimepicker({
		   showMinute: false,
		   showSecond: false,
		   onSelect: logic,
		   minDateTime: (new Date(2013, 1, 1, 0, 0)),
		   maxDateTime: (new Date()),
		   timeFormat: 'h:mm TT'
	   });
	   setDate();
	   updateMap();
}
function setDate(){
	   dtpicker.datepicker( "disable" )
	   	.datetimepicker('setDate', currentdt)
	   	.datepicker( "enable" );
}

$('#plusonehour').click(function(e){
	$(this).removeClass('focus');
	currentdt = new Date(currentdt.valueOf() + 3600000);
	   setDate();
	updateMap();
});

$('#minusonehour').click(function(e){
	$(this).removeClass('focus');
	currentdt = new Date(currentdt - 3600000);
	   setDate();
	updateMap();
});

$('#varpicker').change(function(){
	varname = $('#varpicker').val();
	gj.redraw();
	updateTitle();
});
<commit_msg>make URIs stable<commit_after>var map, gj, dtpicker, n0q;
var varname = 'tmpf';
var currentdt = new Date(defaultdt);

function pad(number) {
    var r = String(number);
    if ( r.length === 1 ) {
    	r = '0' + r;
    }
    return r;
};

Date.prototype.toIEMString = function() {
	return this.getUTCFullYear()
    + pad( this.getUTCMonth() + 1 )
    + pad( this.getUTCDate() )
    + pad( this.getUTCHours() )
    + '00';
};

if ( !Date.prototype.toISOString ) {
	  ( function() {

	    Date.prototype.toISOString = function() {
	      return this.getUTCFullYear()
	        + '-' + pad( this.getUTCMonth() + 1 )
	        + '-' + pad( this.getUTCDate() )
	        + 'T' + pad( this.getUTCHours() )
	        + ':' + pad( this.getUTCMinutes() )
	        + ':' + pad( this.getUTCSeconds() )
	        + '.' + String( (this.getUTCMilliseconds()/1000).toFixed(3) ).slice( 2, 5 )
	        + 'Z';
	    };

	  }() );
	}

function logic( dstring ){
	currentdt = dtpicker.datetimepicker('getDate'); // toISOString()
	updateMap();
}
function updateTitle(){
	$('#maptitle').text("The map is displaying "
			+ $('#varpicker :selected').text() + " valid at "+ currentdt);
	window.location.href = '#'+ varname +'/'+ currentdt.toISOString();
}
function updateMap(){
	if (currentdt && typeof currentdt != "string"){
		gj.protocol.params.dt = currentdt.toISOString();
	}
	gj.refresh();
	if (n0q.getVisibility()){
		n0q.redraw();
		n0q.setVisibility(false);
		n0q.setVisibility(true);
	}
	updateTitle();
}
function get_my_url (bounds) {
    var res = this.map.getResolution();
    var x = Math.round((bounds.left - this.maxExtent.left)
                    / (res * this.tileSize.w));
    var y = Math.round((this.maxExtent.top - bounds.top)
                    / (res * this.tileSize.h));
    var z = this.map.getZoom();

    var path = z + "/" + x + "/" + y + "." + this.type ;
            /* Need no cache buster now that our service IDs are unique
             * + "?"+ parseInt(Math.random() * 9999);
             */
    var url = this.url;
    if (url instanceof Array) {
            url = this.selectUrl(path, url);
    }
    return url + this.service + "/ridge::" + this.radar + "-" + this.radarProduct + "-"
    +  currentdt.toIEMString() + "/" + path;
}
function get_my_url2(bounds){
    var res = this.map.getResolution();
    var x = Math.round((bounds.left - this.maxExtent.left)
                    / (res * this.tileSize.w));
    var y = Math.round((this.maxExtent.top - bounds.top)
                    / (res * this.tileSize.h));
    var z = this.map.getZoom();

    var path = z + "/" + x + "/" + y + "." + this.type + "?"
                    + parseInt(Math.random() * 9999);
    var url = this.url;
    if (url instanceof Array) {
            url = this.selectUrl(path, url);
    }
    return url + this.service + "/" + this.layername + "/" + path;
}

function init(){
	  // Build Map Object
	  map = new OpenLayers.Map( 'map',{
	        projection: new OpenLayers.Projection('EPSG:900913'),
	        displayProjection: new OpenLayers.Projection('EPSG:4326'),
	        units: 'm',
	        wrapDateLine: false,
	        numZoomLevels: 18,
	        maxResolution: 156543.0339,
	        maxExtent: new OpenLayers.Bounds(-20037508, -20037508,
	                                         20037508, 20037508.34)
	  });
	  // Traditional Google Map Layer
	  var googleLayer = new OpenLayers.Layer.Google(
	                'Google Streets',
	                 {'sphericalMercator': true}
	            );

      n0q = new OpenLayers.Layer.TMS(
              'NEXRAD Base Reflectivity',
              'http://mesonet1.agron.iastate.edu/cache/tile.py/', {
                  layername : 'bogus',
                  service : '1.0.0',
                  type : 'png',
                  visibility : true,
                  opacity : 1,
                  getURL : get_my_url,
                  radarProduct : 'N0Q',
                  radar : 'USCOMP',
                  isBaseLayer : false
          }
      );

      var context = {
    		  getLabel: function(feature){
    			  return feature.data[varname];
    		  }
      };

	  var template = OpenLayers.Util.extend({
               label : "${getLabel}",
               fontColor: "black",
               fontSize: "14px",
               fontFamily: "monospace",
               fontWeight: "bold",
               labelOutlineColor: "yellow",
               labelOutlineWidth: 6
	   });
      var style = new OpenLayers.Style(template, {context: context});
      var styleMap = new OpenLayers.StyleMap(style);

	  gj = new OpenLayers.Layer.Vector("Data", {
		  protocol: new OpenLayers.Protocol.HTTP({
			  params: {dt: currentdt.toISOString()},
	          url: "/geojson/agclimate.py",
	          format: new OpenLayers.Format.GeoJSON()
	      }),
	      projection: new OpenLayers.Projection('EPSG:4326'),
	      styleMap: styleMap,
	      strategies: [new OpenLayers.Strategy.Fixed()]
	  });

	  states = new OpenLayers.Layer.TMS('US States',
              'https://mesonet.agron.iastate.edu/c/c.py/', {
                      layername : 's-900913',
                      service : '1.0.0',
                      type : 'png',
                      visibility : true,
                      opacity : 1,
                      getURL : get_my_url2,
                      isBaseLayer : false
              });

	  map.addLayers([googleLayer, n0q, states, gj]);

	  var proj = new OpenLayers.Projection('EPSG:4326');
	   var proj2 = new OpenLayers.Projection('EPSG:900913');
	   var point = new OpenLayers.LonLat(-93.8, 42.2);
	   point.transform(proj, proj2);

	   map.setCenter(point, 7);

	   map.addControl( new OpenLayers.Control.LayerSwitcher({id:'ls'}) );
	   map.addControl( new OpenLayers.Control.MousePosition() );

	   dtpicker = $('#datetimepicker');
	   dtpicker.datetimepicker({
		   showMinute: false,
		   showSecond: false,
		   onSelect: logic,
		   minDateTime: (new Date(2013, 1, 1, 0, 0)),
		   maxDateTime: (new Date()),
		   timeFormat: 'h:mm TT'
	   });

	   try{
		   var tokens = window.location.href.split('#');
		   if (tokens.length == 2){
			   var tokens2 = tokens[1].split("/");
			   varname = tokens2[0];
			   currentdt = (new Date(Date.parse(tokens2[1])));
			   gj.redraw();
		   }
	   } catch(err) {
		   varname = 'tmpf';
		   currentdt = new Date(defaultdt);
	   }

	   setDate();
	   updateMap();
}
function setDate(){
	   dtpicker.datepicker( "disable" )
	   	.datetimepicker('setDate', currentdt)
	   	.datepicker( "enable" );
}

$('#plusonehour').click(function(e){
	$(this).removeClass('focus');
	currentdt = new Date(currentdt.valueOf() + 3600000);
	   setDate();
	updateMap();
});

$('#minusonehour').click(function(e){
	$(this).removeClass('focus');
	currentdt = new Date(currentdt - 3600000);
	setDate();
	updateMap();
});

$('#varpicker').change(function(){
	varname = $('#varpicker').val();
	gj.redraw();
	updateTitle();
});
<|endoftext|>


<commit_before>// Disabling autoDiscover, otherwise Dropzone will try to attach twice.
Dropzone.autoDiscover = false;

$(function () {

    var uploaded = [];

    var uploader = $('#upload');
    var element = $('.dropzone');
    var template = uploader.find('.template');
    var preview = template.html();

    template.remove();

    var dropzone = new Dropzone('.dropzone',
        {
            paramName: 'upload',
            url: REQUEST_ROOT_PATH + '/admin/files/upload/handle',
            headers: {
                'X-CSRF-TOKEN': CSRF_TOKEN
            },
            sending: function (file, xhr, formData) {
                formData.append('folder', element.data('folder'));
            },
            accept: function(file, done) {
                $.getJSON(REQUEST_ROOT_PATH + '/admin/files/exists/' + element.data('folder') + '/' + file.name, function(data) {
                    if(data.exists) {
                        if(!confirm(file.name + " " + element.data('overwrite'))) {
                            dropzone.removeFile(file);
                            return;
                        }
                    }

                    done();
                });
            },
            autoQueue: true,
            thumbnailWidth: 24,
            thumbnailHeight: 24,
            previewTemplate: preview,
            previewsContainer: '.uploads',
            maxFilesize: element.data('max-size'),
            acceptedFiles: element.data('allowed'),
            parallelUploads: element.data('max-parallel'),
            dictDefaultMessage: element.data('icon') + ' ' + element.data('message'),
            uploadprogress: function (file, progress) {
                file.previewElement.querySelector("[data-dz-uploadprogress]").setAttribute('value', progress);
            }
        }
    );

    // While file is in transit.
    dropzone.on('sending', function () {
        uploader.find('.uploaded .card-block').html(element.data('uploading') + '...');
    });

    // When file successfully uploads.
    dropzone.on('success', function (file) {

        var response = JSON.parse(file.xhr.response);

        uploaded.push(response.id);

        file.previewElement.querySelector('[data-dz-uploadprogress]').setAttribute('class', 'progress progress-success');

        setTimeout(function () {
            file.previewElement.remove();
        }, 500);
    });

    // When file fails to upload.
    dropzone.on('error', function (file, message) {

        file.previewElement.querySelector("[data-dz-uploadprogress]").setAttribute('value', 100);
        file.previewElement.querySelector('[data-dz-uploadprogress]').setAttribute('class', 'progress progress-danger');

        alert(message.error);
    });

    // When all files are processed.
    dropzone.on('queuecomplete', function () {

        uploader.find('.uploaded .card-block').html(element.data('loading') + '...');

        uploader.find('.uploaded').load(REQUEST_ROOT_PATH + '/admin/files/upload/recent?uploaded=' + uploaded.join(','));
    });
});
<commit_msg>Show orig messages too if possible<commit_after>// Disabling autoDiscover, otherwise Dropzone will try to attach twice.
Dropzone.autoDiscover = false;

$(function () {

    var uploaded = [];

    var uploader = $('#upload');
    var element = $('.dropzone');
    var template = uploader.find('.template');
    var preview = template.html();

    template.remove();

    var dropzone = new Dropzone('.dropzone',
        {
            paramName: 'upload',
            url: REQUEST_ROOT_PATH + '/admin/files/upload/handle',
            headers: {
                'X-CSRF-TOKEN': CSRF_TOKEN
            },
            sending: function (file, xhr, formData) {
                formData.append('folder', element.data('folder'));
            },
            accept: function (file, done) {
                $.getJSON(REQUEST_ROOT_PATH + '/admin/files/exists/' + element.data('folder') + '/' + file.name, function (data) {
                    if (data.exists) {
                        if (!confirm(file.name + " " + element.data('overwrite'))) {
                            dropzone.removeFile(file);
                            return;
                        }
                    }

                    done();
                });
            },
            autoQueue: true,
            thumbnailWidth: 24,
            thumbnailHeight: 24,
            previewTemplate: preview,
            previewsContainer: '.uploads',
            maxFilesize: element.data('max-size'),
            acceptedFiles: element.data('allowed'),
            parallelUploads: element.data('max-parallel'),
            dictDefaultMessage: element.data('icon') + ' ' + element.data('message'),
            uploadprogress: function (file, progress) {
                file.previewElement.querySelector("[data-dz-uploadprogress]").setAttribute('value', progress);
            }
        }
    );

    // While file is in transit.
    dropzone.on('sending', function () {
        uploader.find('.uploaded .card-block').html(element.data('uploading') + '...');
    });

    // When file successfully uploads.
    dropzone.on('success', function (file) {

        var response = JSON.parse(file.xhr.response);

        uploaded.push(response.id);

        file.previewElement.querySelector('[data-dz-uploadprogress]').setAttribute('class', 'progress progress-success');

        setTimeout(function () {
            file.previewElement.remove();
        }, 500);
    });

    // When file fails to upload.
    dropzone.on('error', function (file, message) {

        file.previewElement.querySelector("[data-dz-uploadprogress]").setAttribute('value', 100);
        file.previewElement.querySelector('[data-dz-uploadprogress]').setAttribute('class', 'progress progress-danger');

        alert(message.error ? message.error : message);
    });

    // When all files are processed.
    dropzone.on('queuecomplete', function () {

        uploader.find('.uploaded .card-block').html(element.data('loading') + '...');

        uploader.find('.uploaded').load(REQUEST_ROOT_PATH + '/admin/files/upload/recent?uploaded=' + uploaded.join(','));
    });
});
<|endoftext|>


<commit_before>/* global _, $ */
'use strict';

angular.module('metadatamanagementApp').controller('ProjectCockpitController',
  function($q, $scope, $state, $location, $transitions, UserResource, Principal,
           PageTitleService, LanguageService, ToolbarHeaderService,
           DataAcquisitionProjectResource, SimpleMessageToastService,
           CurrentProjectService, projectDeferred, CommonDialogsService,
           SearchDao, QuestionUploadService, VariableUploadService, $translate,
           $mdDialog, ProjectReleaseService, $timeout,
           ProjectUpdateAccessService,
           DataAcquisitionProjectPostValidationService) {

    var unregisterTransitionHook;
    var pageTitleKey = 'data-acquisition-project-management.project' +
      '-cockpit.title';

    ToolbarHeaderService.updateToolbarHeader({
      stateName: $state.current.name
    });

    var setTypeCounts = function(projectId) {
      SearchDao.search('', 1, projectId, {}, undefined, 0, undefined)
        .then(function(data) {
          $scope.counts = {};
          ['variables', 'questions', 'data_sets', 'surveys', 'instruments',
            'studies'].forEach(function(type) {
            var bucket  = _.find(data.aggregations.countByType.buckets,
              {key: type});
            $scope.counts[type] = _.get(bucket, 'doc_count', 0);
          });
        });
    };

    var registerConfirmOnDirtyHook = function() {
      if (unregisterTransitionHook) {
        unregisterTransitionHook();
      }

      unregisterTransitionHook = $transitions.onBefore({}, function(trans) {
        if ($scope.changed && trans.to().name !== trans.from().name) {
          return CommonDialogsService.showConfirmOnDirtyDialog();
        }
      });

      $scope.$on('$destroy', unregisterTransitionHook);
    };

    var setProjectRequirementsDisabled = function(project) {
      var loginName = Principal.loginName();
      var publishers = _.get(project, 'configuration.publishers');
      var result;
      if (_.isArray(publishers)) {
        result = publishers.indexOf(loginName) === -1;
      } else {
        result = false;
      }
      $scope.isProjectRequirementsDisabled = result;
      return result;
    };

    var setAssignedToProject = function() {
      var name = Principal.loginName();
      $scope.isAssignedPublisher =
        !!_.find($scope.activeUsers.publishers, function(o) {
          return o.login === name;
        });
      $scope.isAssignedDataProvider =
        !!_.find($scope.activeUsers.dataProviders, function(o) {
          return o.login === name;
        });
      $scope.isAssignedToProject =
        $scope.isAssignedPublisher || $scope.isAssignedDataProvider;
    };

    $state.loadStarted = true;

    $scope.$watch('project', function(newVal, oldVal) {
      if (oldVal !== undefined && newVal !== oldVal) {
        $scope.changed = true;
      }
    }, true);

    $scope.$on('project-deleted', function() {
        $state.go('search');
      });

    $scope.$on('current-project-changed',
      function(event, changedProject) { // jshint ignore:line
        if (changedProject) {
          $location.url('/' + LanguageService.getCurrentInstantly() +
            '/projects/' + changedProject.id);
          PageTitleService.setPageTitle(pageTitleKey,
            {projectId: changedProject.id});
          setTypeCounts(changedProject.id);
          PageTitleService.setPageTitle(
            pageTitleKey, {projectId: changedProject.id});
        }
      });

    $scope.isUpdateAllowed = function(type) {
      return !_.get($scope, 'project.configuration.requirements.' +
        type + 'Required');
    };

    $scope.isUploadAllowed = function(type) {
      return ProjectUpdateAccessService.isUpdateAllowed($scope.project, type,
        true);
    };

    var saveProject = function(project) {
      return DataAcquisitionProjectResource.save(
        project,
        //Success
        function() {
          $scope.changed = false;
          $scope.project = project;
          setAssignedToProject();
          setProjectRequirementsDisabled($scope.project);
          CurrentProjectService.setCurrentProject($scope.project);
          SimpleMessageToastService
            .openSimpleMessageToast(
              'data-acquisition-project-management.log-messages.' +
              'data-acquisition-project.saved', {
                id: $scope.project.id
              });
        },
        //Server Error
        function(response) {
          var errors = _.get(response, 'data.errors');

          if (errors) {
            errors.forEach(function(error) {
              SimpleMessageToastService.openAlertMessageToast(error.message);
            });
          }
        }
      );
    };

    var getNextAssigneeGroup = function(project) {
      switch (_.get(project, 'assigneeGroup')) {
        case 'DATA_PROVIDER':
          return 'PUBLISHER';
        case 'PUBLISHER':
          return 'DATA_PROVIDER';
        default:
          return '';
      }
    };

    var showAssigneeGroupMessageDialog = function() {
      var currentProject = CurrentProjectService.getCurrentProject();
      var assigneeGroup = _.get(currentProject, 'assigneeGroup');
      var recipient;

      switch (assigneeGroup) {
        case 'PUBLISHER':
          recipient = $translate.instant('data-acquisition' +
            '-project-management.project-cockpit.label.ROLE_DATA_PROVIDER');
          break;
        case 'DATA_PROVIDER':
          recipient = $translate.instant('data-acquisition' +
            '-project-management.project-cockpit.label.ROLE_PUBLISHER');
          break;
        default:
          recipient = '';
      }

      return $mdDialog.show({
        controller: 'AssigneeMessageDialogController',
        templateUrl: 'scripts/dataacquisitionprojectmanagement/views/' +
          'assignee-message-dialog.html.tmpl',
        fullscreen: true,
        locals: {
          recipient: recipient
        }
      });
    };

    var prepareProjectForSave = function(assigneeGroupMessage,
                                         newAssigneeGroup) {

      var project = _.assignIn({}, $scope.project);

      if (!project.configuration) {
        $scope.project.configuration = {};
      }

      var configuredPublishers = $scope.activeUsers.publishers
        .map(function(identity) {
          return identity.login;
        });

      var configuredDataProviders = $scope.activeUsers.dataProviders
        .map(function(identity) {
          return identity.login;
        });

      if (project.configuration.publishers) {
        project.configuration.publishers =
          _.filter(_.union(project.configuration.publishers,
            configuredPublishers), function(val) {
            return _.includes(configuredPublishers, val);
          });
      } else {
        project.configuration.publishers = configuredPublishers;
      }

      if (project.configuration.dataProviders) {
        project.configuration.dataProviders =
          _.filter(_.union(project.configuration.dataProviders,
            configuredDataProviders), function(val) {
            return _.includes(configuredDataProviders, val);
          });
      } else {
        project.configuration.dataProviders = configuredDataProviders;
      }

      if (assigneeGroupMessage) {
        project.lastAssigneeGroupMessage = assigneeGroupMessage;
      }

      if (newAssigneeGroup) {
        project.assigneeGroup = newAssigneeGroup;
      }

      return project;
    };

    $scope.onSaveChangesAndTakeBack = function() {
      var confirm = $mdDialog.confirm()
      .title($translate.instant('data-acquisition' +
        '-project-management.project-cockpit.takeback-dialog.title')
      ).textContent($translate.instant('data-acquisition' +
      '-project-management.project-cockpit.takeback-dialog.text')
      ).ok($translate.instant('global.common-dialogs.yes'))
      .cancel($translate.instant('global.common-dialogs.no'));
      $mdDialog.show(confirm).then(function() {
        var message = _.get($scope, 'project.lastAssigneeGroupMessage');
        var project = prepareProjectForSave(message, 'PUBLISHER');
        saveProject(project);
      });
    };

    $scope.onSaveChangesAndAssign = function() {
      if (!_.get($scope.project, 'configuration.dataProviders.length')) {
        SimpleMessageToastService.openAlertMessageToast('data-acquisition' +
          '-project-management.project-cockpit.no-data-providers' +
          '-dialog.text');
        return;
      }

      var postValidationStep = $q.defer();
      var newAssigneeGroup = getNextAssigneeGroup($scope.project);
      var isPublisher = Principal.hasAuthority('ROLE_PUBLISHER');

      if (newAssigneeGroup === 'PUBLISHER' && !isPublisher) {
        DataAcquisitionProjectPostValidationService
          .postValidate($scope.project.id)
          .then(postValidationStep.resolve, postValidationStep.reject);
      } else {
        postValidationStep.resolve();
      }

      postValidationStep.promise.then(function() {
        showAssigneeGroupMessageDialog().then(function(message) {
          var project = prepareProjectForSave(message, newAssigneeGroup);
          saveProject(project);
        });
      });
    };

    $scope.onSaveChanges = function(origin) {
      var project = prepareProjectForSave();
      saveProject(project).$promise.then(function() {
        if (origin !== 'requirements') {
          $state.reload();
        }
      });
    };

    $scope.changed = false;

    $scope.searchText = {
      publishers: '',
      dataProviders: ''
    };

    $scope.selectedUser = {
      publishers: null,
      dataProviders: null
    };

    $scope.selectedUserChanged = function(user, role) {
      if (user) {
        $scope.activeUsers[role].push(user);
        $scope.changed = true;
        $scope.searchText[role] = '';
        $scope.selectedUser[role] = null;
        $state.searchCache[role] = {};
        $timeout(function() {
          $(':focus').blur();
        }, 0);
      }
    };

    $scope.activeUsers = {
      publishers: [],
      dataProviders: []
    };

    $scope.fetching = false;

    $scope.advancedPrivileges = Principal.hasAnyAuthority(['ROLE_PUBLISHER',
      'ROLE_ADMIN']);
    $scope.isPublisher = Principal.hasAnyAuthority(['ROLE_PUBLISHER']);
    $scope.isDataProvider = Principal.hasAnyAuthority(['ROLE_DATA_PROVIDER']);
    $scope.isAssignedToProject = false;
    $scope.isAssignedPublisher = false;
    $scope.isAssignedDataProvider = false;

    // load all users assigned to the currrent project
    projectDeferred.promise.then(
      function(project) {
        setTypeCounts(project.id);
        $scope.project = project;
        $scope.fetching = true;

        PageTitleService.setPageTitle(pageTitleKey,
          {projectId: project.id});

        CurrentProjectService.setCurrentProject(project);

        function getAndAddUsers(key) {
          // get users of type {key} asynchronously
          // and return promise resolving when all are fetched
          if (project.configuration[key]) {
            return $q.all(
              project.configuration[key].map(function(userLogin) {
                return (
                  UserResource.getPublic({
                    login: userLogin
                  }).$promise.then(function(userResult) {
                    if (!_.includes($scope.activeUsers[key].map(function(u) {
                      return u.login;
                    }), userResult.login)) {
                      $scope.activeUsers[key].push(userResult);
                    }
                  })
                );
              })
            );
          } else {
            return $q.resolve([]);
          }
        }

        $q.resolve($q.all([
          getAndAddUsers('publishers'),
          getAndAddUsers('dataProviders')
        ])).then(function() {
          $scope.fetching = false;
          setAssignedToProject();
        }).catch(function(error) {
          SimpleMessageToastService
            .openAlertMessageToast(
              'global.error.server-error.internal-server-error', {
                status: error.data.error_description
              });
        });
        registerConfirmOnDirtyHook();
      }).finally(function() {
      $scope.loadStarted = false;
    });

    $scope.canDeleteUser = function(user, role) {
      if (user.restricted) {
        // cannot modify user whose details we can't read
        return false;
      }
      if (!$scope.advancedPrivileges && role === 'publishers') {
        // cannot remove publishers without advanced privilege
        return false;
      }
      if ($scope.activeUsers[role].length <= 1) {
        // cannot remove the last user in this list
        return false;
      }
      return true;
    };

    $state.currentPromise = null;
    $state.searchCache = {
      publishers: {},
      dataProviders: {}
    };
    var internalRoles = {
      'publishers': 'ROLE_PUBLISHER',
      'dataProviders': 'ROLE_DATA_PROVIDER'
    };
    $scope.searchUsers = function(search, role) {
      var roleInternal = internalRoles[role];
      if (!$state.loadComplete) {
        return [];
      }
      if ($state.searchCache[role][search]) {
        return $state.searchCache[role][search];
      }
      if (!$state.currentPromise) {
        $state.currentPromise = UserResource.search({
          login: search,
          role: roleInternal
        }).$promise.then(function(result) {
          $state.currentPromise = null;
          var results = result.filter(function(x) {
            // filter out already added users
            return $scope.activeUsers[role].map(function(u) {
              return u.login;
            }).indexOf(x.login) < 0 && _.includes(x.authorities, roleInternal);
          });
          $state.searchCache[role][search] = results;
          return results;
        });
      }
      return $state.currentPromise;
    };

    $scope.removeUser = function(user, role) {
      $scope.changed = true;
      $scope.activeUsers[role] = $scope.activeUsers[role]
        .filter(function(item) {
          return item.login !== user.login;
        });
      $state.searchCache[role] = {};
    };

    $scope.shareButtonShown = false;
    $scope.onTabSelect = function(tab) {
      $state.go('project-cockpit', {tab: tab});
      if (tab === 'config') {
        $scope.shareButtonShown = false;
      } else if (tab === 'status') {
        $scope.shareButtonShown = true;
      }
    };
    $scope.selectedTab = (function() {
      switch ($state.params.tab) {
        case 'status': return 0;
        case 'config': return 1;
        default: return 0;
      }
    })();

    $scope.setChanged = function(changed) {
      if (changed === undefined) {
        changed = true;
      }
      $scope.changed = changed;
    };

    $scope.toggleReleaseProject = function() {
      if ($scope.project.release) {
        ProjectReleaseService.unreleaseProject($scope.project);
      } else {
        ProjectReleaseService.releaseProject($scope.project);
      }
    };

    $scope.$on('upload-completed', function() {
      $timeout(function() {
        setTypeCounts($scope.project.id);
      }, 2000);
    });

    $scope.uploadQuestions = function(files) {
      QuestionUploadService.uploadQuestions(files, $scope.project.id);
    };

    $scope.uploadVariables = function(files) {
      VariableUploadService.uploadVariables(files, $scope.project.id);
    };

    $state.loadComplete = true;
  });
<commit_msg>#1844 Disable requirements if current publisher is removed from project<commit_after>/* global _, $ */
'use strict';

angular.module('metadatamanagementApp').controller('ProjectCockpitController',
  function($q, $scope, $state, $location, $transitions, UserResource, Principal,
           PageTitleService, LanguageService, ToolbarHeaderService,
           DataAcquisitionProjectResource, SimpleMessageToastService,
           CurrentProjectService, projectDeferred, CommonDialogsService,
           SearchDao, QuestionUploadService, VariableUploadService, $translate,
           $mdDialog, ProjectReleaseService, $timeout,
           ProjectUpdateAccessService,
           DataAcquisitionProjectPostValidationService) {

    var unregisterTransitionHook;
    var pageTitleKey = 'data-acquisition-project-management.project' +
      '-cockpit.title';

    ToolbarHeaderService.updateToolbarHeader({
      stateName: $state.current.name
    });

    var setTypeCounts = function(projectId) {
      SearchDao.search('', 1, projectId, {}, undefined, 0, undefined)
        .then(function(data) {
          $scope.counts = {};
          ['variables', 'questions', 'data_sets', 'surveys', 'instruments',
            'studies'].forEach(function(type) {
            var bucket  = _.find(data.aggregations.countByType.buckets,
              {key: type});
            $scope.counts[type] = _.get(bucket, 'doc_count', 0);
          });
        });
    };

    var registerConfirmOnDirtyHook = function() {
      if (unregisterTransitionHook) {
        unregisterTransitionHook();
      }

      unregisterTransitionHook = $transitions.onBefore({}, function(trans) {
        if ($scope.changed && trans.to().name !== trans.from().name) {
          return CommonDialogsService.showConfirmOnDirtyDialog();
        }
      });

      $scope.$on('$destroy', unregisterTransitionHook);
    };

    var setProjectRequirementsDisabled = function(project) {
      var loginName = Principal.loginName();
      var publishers = _.get(project, 'configuration.publishers');
      var result;
      if (_.isArray(publishers)) {
        result = publishers.indexOf(loginName) === -1;
      } else {
        result = false;
      }
      $scope.isProjectRequirementsDisabled = result;
      return result;
    };

    var setAssignedToProject = function() {
      var name = Principal.loginName();
      $scope.isAssignedPublisher =
        !!_.find($scope.activeUsers.publishers, function(o) {
          return o.login === name;
        });
      $scope.isAssignedDataProvider =
        !!_.find($scope.activeUsers.dataProviders, function(o) {
          return o.login === name;
        });
      $scope.isAssignedToProject =
        $scope.isAssignedPublisher || $scope.isAssignedDataProvider;
    };

    $state.loadStarted = true;

    $scope.$watch('project', function(newVal, oldVal) {
      if (oldVal !== undefined && newVal !== oldVal) {
        $scope.changed = true;
      }
    }, true);

    $scope.$on('project-deleted', function() {
        $state.go('search');
      });

    $scope.$on('current-project-changed',
      function(event, changedProject) { // jshint ignore:line
        if (changedProject) {
          $location.url('/' + LanguageService.getCurrentInstantly() +
            '/projects/' + changedProject.id);
          PageTitleService.setPageTitle(pageTitleKey,
            {projectId: changedProject.id});
          setTypeCounts(changedProject.id);
          setProjectRequirementsDisabled(changedProject);
        }
      });

    $scope.isUpdateAllowed = function(type) {
      return !_.get($scope, 'project.configuration.requirements.' +
        type + 'Required');
    };

    $scope.isUploadAllowed = function(type) {
      return ProjectUpdateAccessService.isUpdateAllowed($scope.project, type,
        true);
    };

    var saveProject = function(project) {
      return DataAcquisitionProjectResource.save(
        project,
        //Success
        function() {
          $scope.changed = false;
          $scope.project = project;
          setAssignedToProject();
          setProjectRequirementsDisabled($scope.project);
          CurrentProjectService.setCurrentProject($scope.project);
          SimpleMessageToastService
            .openSimpleMessageToast(
              'data-acquisition-project-management.log-messages.' +
              'data-acquisition-project.saved', {
                id: $scope.project.id
              });
        },
        //Server Error
        function(response) {
          var errors = _.get(response, 'data.errors');

          if (errors) {
            errors.forEach(function(error) {
              SimpleMessageToastService.openAlertMessageToast(error.message);
            });
          }
        }
      );
    };

    var getNextAssigneeGroup = function(project) {
      switch (_.get(project, 'assigneeGroup')) {
        case 'DATA_PROVIDER':
          return 'PUBLISHER';
        case 'PUBLISHER':
          return 'DATA_PROVIDER';
        default:
          return '';
      }
    };

    var showAssigneeGroupMessageDialog = function() {
      var currentProject = CurrentProjectService.getCurrentProject();
      var assigneeGroup = _.get(currentProject, 'assigneeGroup');
      var recipient;

      switch (assigneeGroup) {
        case 'PUBLISHER':
          recipient = $translate.instant('data-acquisition' +
            '-project-management.project-cockpit.label.ROLE_DATA_PROVIDER');
          break;
        case 'DATA_PROVIDER':
          recipient = $translate.instant('data-acquisition' +
            '-project-management.project-cockpit.label.ROLE_PUBLISHER');
          break;
        default:
          recipient = '';
      }

      return $mdDialog.show({
        controller: 'AssigneeMessageDialogController',
        templateUrl: 'scripts/dataacquisitionprojectmanagement/views/' +
          'assignee-message-dialog.html.tmpl',
        fullscreen: true,
        locals: {
          recipient: recipient
        }
      });
    };

    var prepareProjectForSave = function(assigneeGroupMessage,
                                         newAssigneeGroup) {

      var project = _.assignIn({}, $scope.project);

      if (!project.configuration) {
        $scope.project.configuration = {};
      }

      var configuredPublishers = $scope.activeUsers.publishers
        .map(function(identity) {
          return identity.login;
        });

      var configuredDataProviders = $scope.activeUsers.dataProviders
        .map(function(identity) {
          return identity.login;
        });

      if (project.configuration.publishers) {
        project.configuration.publishers =
          _.filter(_.union(project.configuration.publishers,
            configuredPublishers), function(val) {
            return _.includes(configuredPublishers, val);
          });
      } else {
        project.configuration.publishers = configuredPublishers;
      }

      if (project.configuration.dataProviders) {
        project.configuration.dataProviders =
          _.filter(_.union(project.configuration.dataProviders,
            configuredDataProviders), function(val) {
            return _.includes(configuredDataProviders, val);
          });
      } else {
        project.configuration.dataProviders = configuredDataProviders;
      }

      if (assigneeGroupMessage) {
        project.lastAssigneeGroupMessage = assigneeGroupMessage;
      }

      if (newAssigneeGroup) {
        project.assigneeGroup = newAssigneeGroup;
      }

      return project;
    };

    $scope.onSaveChangesAndTakeBack = function() {
      var confirm = $mdDialog.confirm()
      .title($translate.instant('data-acquisition' +
        '-project-management.project-cockpit.takeback-dialog.title')
      ).textContent($translate.instant('data-acquisition' +
      '-project-management.project-cockpit.takeback-dialog.text')
      ).ok($translate.instant('global.common-dialogs.yes'))
      .cancel($translate.instant('global.common-dialogs.no'));
      $mdDialog.show(confirm).then(function() {
        var message = _.get($scope, 'project.lastAssigneeGroupMessage');
        var project = prepareProjectForSave(message, 'PUBLISHER');
        saveProject(project);
      });
    };

    $scope.onSaveChangesAndAssign = function() {
      if (!_.get($scope.project, 'configuration.dataProviders.length')) {
        SimpleMessageToastService.openAlertMessageToast('data-acquisition' +
          '-project-management.project-cockpit.no-data-providers' +
          '-dialog.text');
        return;
      }

      var postValidationStep = $q.defer();
      var newAssigneeGroup = getNextAssigneeGroup($scope.project);
      var isPublisher = Principal.hasAuthority('ROLE_PUBLISHER');

      if (newAssigneeGroup === 'PUBLISHER' && !isPublisher) {
        DataAcquisitionProjectPostValidationService
          .postValidate($scope.project.id)
          .then(postValidationStep.resolve, postValidationStep.reject);
      } else {
        postValidationStep.resolve();
      }

      postValidationStep.promise.then(function() {
        showAssigneeGroupMessageDialog().then(function(message) {
          var project = prepareProjectForSave(message, newAssigneeGroup);
          saveProject(project);
        });
      });
    };

    $scope.onSaveChanges = function(origin) {
      var project = prepareProjectForSave();
      saveProject(project).$promise.then(function() {
        if (origin !== 'requirements') {
          $state.reload();
        }
      });
    };

    $scope.changed = false;

    $scope.searchText = {
      publishers: '',
      dataProviders: ''
    };

    $scope.selectedUser = {
      publishers: null,
      dataProviders: null
    };

    $scope.selectedUserChanged = function(user, role) {
      if (user) {
        $scope.activeUsers[role].push(user);
        $scope.changed = true;
        $scope.searchText[role] = '';
        $scope.selectedUser[role] = null;
        $state.searchCache[role] = {};
        $timeout(function() {
          $(':focus').blur();
        }, 0);
      }
    };

    $scope.activeUsers = {
      publishers: [],
      dataProviders: []
    };

    $scope.fetching = false;

    $scope.advancedPrivileges = Principal.hasAnyAuthority(['ROLE_PUBLISHER',
      'ROLE_ADMIN']);
    $scope.isPublisher = Principal.hasAnyAuthority(['ROLE_PUBLISHER']);
    $scope.isDataProvider = Principal.hasAnyAuthority(['ROLE_DATA_PROVIDER']);
    $scope.isAssignedToProject = false;
    $scope.isAssignedPublisher = false;
    $scope.isAssignedDataProvider = false;

    // load all users assigned to the currrent project
    projectDeferred.promise.then(
      function(project) {
        setTypeCounts(project.id);
        $scope.project = project;
        $scope.fetching = true;

        PageTitleService.setPageTitle(pageTitleKey,
          {projectId: project.id});

        CurrentProjectService.setCurrentProject(project);

        setProjectRequirementsDisabled(project);

        function getAndAddUsers(key) {
          // get users of type {key} asynchronously
          // and return promise resolving when all are fetched
          if (project.configuration[key]) {
            return $q.all(
              project.configuration[key].map(function(userLogin) {
                return (
                  UserResource.getPublic({
                    login: userLogin
                  }).$promise.then(function(userResult) {
                    if (!_.includes($scope.activeUsers[key].map(function(u) {
                      return u.login;
                    }), userResult.login)) {
                      $scope.activeUsers[key].push(userResult);
                    }
                  })
                );
              })
            );
          } else {
            return $q.resolve([]);
          }
        }

        $q.resolve($q.all([
          getAndAddUsers('publishers'),
          getAndAddUsers('dataProviders')
        ])).then(function() {
          $scope.fetching = false;
          setAssignedToProject();
        }).catch(function(error) {
          SimpleMessageToastService
            .openAlertMessageToast(
              'global.error.server-error.internal-server-error', {
                status: error.data.error_description
              });
        });
        registerConfirmOnDirtyHook();
      }).finally(function() {
      $scope.loadStarted = false;
    });

    $scope.canDeleteUser = function(user, role) {
      if (user.restricted) {
        // cannot modify user whose details we can't read
        return false;
      }
      if (!$scope.advancedPrivileges && role === 'publishers') {
        // cannot remove publishers without advanced privilege
        return false;
      }
      if ($scope.activeUsers[role].length <= 1) {
        // cannot remove the last user in this list
        return false;
      }
      return true;
    };

    $state.currentPromise = null;
    $state.searchCache = {
      publishers: {},
      dataProviders: {}
    };
    var internalRoles = {
      'publishers': 'ROLE_PUBLISHER',
      'dataProviders': 'ROLE_DATA_PROVIDER'
    };
    $scope.searchUsers = function(search, role) {
      var roleInternal = internalRoles[role];
      if (!$state.loadComplete) {
        return [];
      }
      if ($state.searchCache[role][search]) {
        return $state.searchCache[role][search];
      }
      if (!$state.currentPromise) {
        $state.currentPromise = UserResource.search({
          login: search,
          role: roleInternal
        }).$promise.then(function(result) {
          $state.currentPromise = null;
          var results = result.filter(function(x) {
            // filter out already added users
            return $scope.activeUsers[role].map(function(u) {
              return u.login;
            }).indexOf(x.login) < 0 && _.includes(x.authorities, roleInternal);
          });
          $state.searchCache[role][search] = results;
          return results;
        });
      }
      return $state.currentPromise;
    };

    $scope.removeUser = function(user, role) {
      $scope.changed = true;
      $scope.activeUsers[role] = $scope.activeUsers[role]
        .filter(function(item) {
          return item.login !== user.login;
        });
      $state.searchCache[role] = {};
    };

    $scope.shareButtonShown = false;
    $scope.onTabSelect = function(tab) {
      $state.go('project-cockpit', {tab: tab});
      if (tab === 'config') {
        $scope.shareButtonShown = false;
      } else if (tab === 'status') {
        $scope.shareButtonShown = true;
      }
    };
    $scope.selectedTab = (function() {
      switch ($state.params.tab) {
        case 'status': return 0;
        case 'config': return 1;
        default: return 0;
      }
    })();

    $scope.setChanged = function(changed) {
      if (changed === undefined) {
        changed = true;
      }
      $scope.changed = changed;
    };

    $scope.toggleReleaseProject = function() {
      if ($scope.project.release) {
        ProjectReleaseService.unreleaseProject($scope.project);
      } else {
        ProjectReleaseService.releaseProject($scope.project);
      }
    };

    $scope.$on('upload-completed', function() {
      $timeout(function() {
        setTypeCounts($scope.project.id);
      }, 2000);
    });

    $scope.uploadQuestions = function(files) {
      QuestionUploadService.uploadQuestions(files, $scope.project.id);
    };

    $scope.uploadVariables = function(files) {
      VariableUploadService.uploadVariables(files, $scope.project.id);
    };

    $state.loadComplete = true;
  });
<|endoftext|>


<commit_before>//Declarations
var margin, width, height, pointRadius;
var svg;

var xScale, yScale, xAxis, yAxis;

var textDataFile = "data/LIWC_chunk_counts_all_seasons.tsv",
textMetaDataFile = "data/top_5_category_words_per_episode.tsv",
textData, textMetaData, categoryNames, categoryVisibilities;

var color = d3.scaleOrdinal().range(["#020202", "#3c3c3c", "#4b4a4a", "#5e5d5d", "#727171", "#7e7e7e", "#8d8d8d", "#a19f9f", "#b6b5b5", "#C7C6C6"]);

var legendRects, legendLabels;

var seasonNumber = 1,episodeNumber = 1;
var pg, catG;
var catInFocus;
var circles = {};

function sliceData (data, season, episode){
  var slicedData = Array();
  for(var index = 0; index < data.length; index++) {
    if(data[index]['season'] == season &&
       data[index]['episode'] == episode){
      slicedData.push(data[index]);
    }
  }
  return slicedData;
}

function formatData (data, catName){
	return data.map(function (d){
		return {"x":parseInt(d.time),
				"y":parseInt(d[catName])};
	});
}

function findMaxY (data){
	var maxYVals = data.map (function (d){
		var y = Array();
		for (var key in d){
			if (categoryVisibilities[key]){
				y.push(parseInt(d[key]));
			}
		}
		return d3.max (y);
	});

	return d3.max (maxYVals);
}

function updateScatterPlot (data){
    var catName, grp;
    console.log (data.map (function (d){return parseInt(d.time);}));
    console.log (d3.extent(data, function(d) { return parseInt(d.time); }));
    xScale.domain(d3.extent(data, function(d) { return parseInt(d.time); }));

    maxY = findMaxY(data);
    yScale.domain([0,maxY]);

    // Step 1: Redraw both the axes.
    svg.select(".y.axis")
        .transition()
        .call(yAxis);

    svg.select(".x.axis")
        .transition()
        .call(xAxis);

    // Step 2: Enter or update the circles based on new data.
    for (var i=0; i < categoryNames.length; i++){
    	catName = categoryNames[i];
    	if (categoryVisibilities[catName]){
    		// Select the group corresponding to this category.
    		grp = svg.selectAll("#spg-"+ catName);
    		circles[catName] = grp.selectAll("circle")
    		.data (formatData(data, catName));

    		circles[catName]
    		.enter()
    		.append ("circle")
    		.attr ("r", pointRadius)
    		.attr ("cx", function (d){
    			return xScale (d.x);
    		})
    		.attr ("cy", function (d){
    			return yScale(d.y);
    		});

    		circles[catName]
    		.attr ("cx", function (d){
    			return xScale (d.x);
    		})
    		.attr ("cy", function (d){
    			return yScale(d.y);
    		});

			circles[catName].exit().remove();
    	}
    }

    // Step 2: Flip the visibility of the groups.
	catG.style ("visibility", function (d, i) {
	      return categoryVisibilities[d] ? "visible" : "hidden";
	});
}

function initScatterPlot (data){
	// Initialize margins
	margin = {top: 20, right: 200, bottom: 100, left: 50};
	width = 900 - margin.left - margin.right;
    height = 500 - margin.top - margin.bottom;
    pointRadius = 2;
    // Define the initial scales and axes
    xScale = d3.scaleLinear()
    .range([0, width]);

    yScale = d3.scaleLinear()
    .range([height, 0]);

    xAxis = d3.axisBottom()
    .scale(xScale);

	yAxis = d3.axisLeft()
    .scale(yScale);

    // Step 1: create an svg element with required height and width
    // The svg is the container element for the plot. All the
    // plot elements are grouped together in tag identified by id=textPlot.
	svg = d3.select("#text")
	.append("svg")
	.attr ("width", width + margin.left + margin.right)
	.attr ("height", height + margin.top + margin.bottom)
	.append ("g")
	.attr ("id", "textPlot")
	.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

	// Step 2: add an invisible rectange. This is not really required,
	// but is useful for mouse-tracking.
	svg.append("rect")
	.attr("width", width)
	.attr("height", height)
	.attr("x", 0)
	.attr("y", 0)
	.attr("id", "mouse-tracker")
	.style("fill", "white");

	// Step 3: Draw the x and the y axis
	    // draw line graph
    svg.append("g")
	  .attr("class", "x axis")
	  .attr("transform", "translate(0," + height + ")")
	  .call(xAxis);

    svg.append("g")
	  .attr("class", "y axis")
	  .call(yAxis)
	  .append("text")
	  .attr("transform", "rotate(-90)")
	  .attr("y", 6)
	  .attr("x", -10)
	  .attr("dy", ".71em")
	  .style("text-anchor", "end")
	  .text("Text counts");

	// Read the data and extract the column names
	categoryNames = d3.keys(data[0]).filter(function(key) {
            return key !== "time" && key !== "season" && key !== "episode";
        });

    categoryVisibilities = categoryNames.reduce (function (obj, d){
    	obj[d] = d=="positive_affect";
    	    return obj;
    	}, {});

    color.domain (categoryNames);

	// Step 4: draw the legend
	var legendSpace = 450 / categoryNames.length;
	var legendGroup = svg.append("g")
	   .attr("class", "legend");

	legendRects = legendGroup.selectAll ("rect")
	.data (categoryNames)
	.enter()
	.append("rect")
	.attr("width", 10)
    .attr("height", 10)
    .attr("x", width + (margin.right/3) - 15)
    .attr("y", function (d, i) { return (legendSpace)+i*(legendSpace) - 8; })
    .attr("fill", function (d, i){
    	return categoryVisibilities[d] ? color(d) : "#F1F1F2";
    })
    .attr("id", function (d){
    	return "rect-" + d;
    })
    .attr("class", "legend-box")
    .on("click", function (d){
    	categoryVisibilities[d] = !categoryVisibilities[d];
    	d3.selectAll("#rect-" + d).attr("fill", categoryVisibilities[d] ? color(d) : "#F1F1F2");
    	updateScatterPlot(sliceData (textData, seasonNumber, episodeNumber));
    })
    .on("mouseover", function (d){
    	catInFocus = d;
    	updateBarPlot(textMetaData, seasonNumber, episodeNumber);
    });

    legendLabels = legendGroup.selectAll ("text")
    .data (categoryNames)
    .enter()
    .append("text")
    .attr("x", width + (margin.right/3))
    .attr("y", function (d, i) { return (legendSpace)+i*(legendSpace);})
    .text(function(d) { return d; });

    pg = svg.append ("g")
         .attr ("id", "spg");

    catG = pg.selectAll ("g")
    .data (categoryNames)
    .enter()
    .append("g")
    .attr("id", function (d){
    	return "spg-" + d;
    })
    .attr("class", "spg-cats");
}

function initBarPlot (data){
	catInFocus = "positive_affect";
	var div = d3.select("#text-metadata");
	div.select ("#text-category")
	.text(catInFocus);
}

function updateBarPlot (data, season, episode){
	//var catInFocus = "positive_affect";
	var parts, wordCounter;
	var div = d3.select ("#text-metadata");
	div.select("#text-category").text(catInFocus);

	for (var i = data.length - 1; i >= 0; i--) {
		if (parseInt(data[i]["season"]) == season &&
			parseInt(data[i]["episode"]) == episode) {
			parts = data[i][catInFocus].split(",")
			wordCounter = parts.map (function (entry){
				return {
					word: entry.split(":")[0],
					freq: parseInt(entry.split(":")[1])
				}
			});
			break;
		}
	}

	var wordlist = d3.select ("#text-wordlist")
					.selectAll("li")
	               .data (wordCounter);

	wordlist.enter()
	.append("li")
	.text(function (d){
		return d.word;
	});

	wordlist.text(function (d){
		return d.word;
	});

	wordlist.exit().remove();
}

function init (){
	d3.tsv(textDataFile, function(error, data) {
    	textData = data;
    	initScatterPlot(textData);
    	updateScatterPlot(sliceData (textData, seasonNumber, episodeNumber));
	});

	d3.tsv(textMetaDataFile, function(error, data){
		textMetaData = data;
		initBarPlot (textMetaData);
		updateBarPlot (textMetaData, seasonNumber, episodeNumber);
	})
}

init();<commit_msg>added color focus/unfocus<commit_after>//Declarations
var margin, width, height, pointRadius;
var svg;

var xScale, yScale, xAxis, yAxis;

var textDataFile = "data/LIWC_chunk_counts_all_seasons.tsv",
textMetaDataFile = "data/top_5_category_words_per_episode.tsv",
textData, textMetaData, categoryNames, categoryVisibilities;

var color = d3.scaleOrdinal().range(["#020202", "#3c3c3c", "#4b4a4a", "#5e5d5d", "#727171", "#7e7e7e", "#8d8d8d", "#a19f9f", "#b6b5b5", "#C7C6C6"]);
var unfocusColor = "#BBBBB9";
var focusColor = "#020202";

var legendRects, legendLabels;

var seasonNumber = 1,episodeNumber = 1;
var pg, catG;
var catInFocus;
var circles = {};

function sliceData (data, season, episode){
  var slicedData = Array();
  for(var index = 0; index < data.length; index++) {
    if(data[index]['season'] == season &&
       data[index]['episode'] == episode){
      slicedData.push(data[index]);
    }
  }
  return slicedData;
}

function formatData (data, catName){
	return data.map(function (d){
		return {"x":parseInt(d.time),
				"y":parseInt(d[catName])};
	});
}

function findMaxY (data){
	var maxYVals = data.map (function (d){
		var y = Array();
		for (var key in d){
			if (categoryVisibilities[key]){
				y.push(parseInt(d[key]));
			}
		}
		return d3.max (y);
	});

	return d3.max (maxYVals);
}

function updateScatterPlot (data){
    var catName, grp;
    console.log (data.map (function (d){return parseInt(d.time);}));
    console.log (d3.extent(data, function(d) { return parseInt(d.time); }));
    xScale.domain(d3.extent(data, function(d) { return parseInt(d.time); }));

    maxY = findMaxY(data);
    yScale.domain([0,maxY]);

    // Step 1: Redraw both the axes.
    svg.select(".y.axis")
        .transition()
        .call(yAxis);

    svg.select(".x.axis")
        .transition()
        .call(xAxis);

    // Step 2: Enter or update the circles based on new data.
    for (var i=0; i < categoryNames.length; i++){
    	catName = categoryNames[i];
    	if (categoryVisibilities[catName]){
    		// Select the group corresponding to this category.
    		grp = svg.selectAll("#spg-"+ catName);
    		circles[catName] = grp.selectAll("circle")
    		.data (formatData(data, catName));

    		circles[catName]
    		.enter()
    		.append ("circle")
    		.attr ("r", pointRadius)
    		.attr ("cx", function (d){
    			return xScale (d.x);
    		})
    		.attr ("cy", function (d){
    			return yScale(d.y);
    		});

    		circles[catName]
    		.attr ("cx", function (d){
    			return xScale (d.x);
    		})
    		.attr ("cy", function (d){
    			return yScale(d.y);
    		});

			circles[catName].exit().remove();
    	}
    }

    // Step 2: Flip the visibility of the groups.
	catG.style ("visibility", function (d, i) {
	      return categoryVisibilities[d] ? "visible" : "hidden";
	});
}

function initScatterPlot (data){
	// Initialize margins
	margin = {top: 20, right: 200, bottom: 100, left: 50};
	width = 900 - margin.left - margin.right;
    height = 500 - margin.top - margin.bottom;
    pointRadius = 2;
    // Define the initial scales and axes
    xScale = d3.scaleLinear()
    .range([0, width]);

    yScale = d3.scaleLinear()
    .range([height, 0]);

    xAxis = d3.axisBottom()
    .scale(xScale);

	yAxis = d3.axisLeft()
    .scale(yScale);

    // Step 1: create an svg element with required height and width
    // The svg is the container element for the plot. All the
    // plot elements are grouped together in tag identified by id=textPlot.
	svg = d3.select("#text")
	.append("svg")
	.attr ("width", width + margin.left + margin.right)
	.attr ("height", height + margin.top + margin.bottom)
	.append ("g")
	.attr ("id", "textPlot")
	.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

	// Step 2: add an invisible rectange. This is not really required,
	// but is useful for mouse-tracking.
	svg.append("rect")
	.attr("width", width)
	.attr("height", height)
	.attr("x", 0)
	.attr("y", 0)
	.attr("id", "mouse-tracker")
	.style("fill", "white");

	// Step 3: Draw the x and the y axis
	    // draw line graph
    svg.append("g")
	  .attr("class", "x axis")
	  .attr("transform", "translate(0," + height + ")")
	  .call(xAxis);

    svg.append("g")
	  .attr("class", "y axis")
	  .call(yAxis)
	  .append("text")
	  .attr("transform", "rotate(-90)")
	  .attr("y", 6)
	  .attr("x", -10)
	  .attr("dy", ".71em")
	  .style("text-anchor", "end")
	  .text("Text counts");

	// Read the data and extract the column names
	categoryNames = d3.keys(data[0]).filter(function(key) {
            return key !== "time" && key !== "season" && key !== "episode";
        });

    categoryVisibilities = categoryNames.reduce (function (obj, d){
    	obj[d] = d=="positive_affect";
    	    return obj;
    	}, {});

    color.domain (categoryNames);

	// Step 4: draw the legend
	var legendSpace = 450 / categoryNames.length;
	var legendGroup = svg.append("g")
	   .attr("class", "legend");

	legendRects = legendGroup.selectAll ("rect")
	.data (categoryNames)
	.enter()
	.append("rect")
	.attr("width", 10)
    .attr("height", 10)
    .attr("x", width + (margin.right/3) - 15)
    .attr("y", function (d, i) { return (legendSpace)+i*(legendSpace) - 8; })
    .attr("fill", function (d, i){
    	return categoryVisibilities[d] ? color(d) : "#F1F1F2";
    })
    .attr("id", function (d){
    	return "rect-" + d;
    })
    .attr("class", "legend-box")
    .on("click", function (d){
    	categoryVisibilities[d] = !categoryVisibilities[d];
    	d3.selectAll("#rect-" + d).attr("fill", categoryVisibilities[d] ? color(d) : "#F1F1F2");
    	updateScatterPlot(sliceData (textData, seasonNumber, episodeNumber));
    })
    .on("mouseover", function (d){
        // update formerly focused category
        if(categoryVisibilities[catInFocus]) {
            circles[catInFocus].
            transition().
            attr("fill", unfocusColor);
        }
    	catInFocus = d;
    	updateBarPlot(textMetaData, seasonNumber, episodeNumber);
        // update plot colors if visible
        if(categoryVisibilities[catInFocus]) {
            circles[catInFocus].
            transition().
            attr("fill", focusColor);
        }
    });

    legendLabels = legendGroup.selectAll ("text")
    .data (categoryNames)
    .enter()
    .append("text")
    .attr("x", width + (margin.right/3))
    .attr("y", function (d, i) { return (legendSpace)+i*(legendSpace);})
    .text(function(d) { return d; });

    pg = svg.append ("g")
         .attr ("id", "spg");

    catG = pg.selectAll ("g")
    .data (categoryNames)
    .enter()
    .append("g")
    .attr("id", function (d){
    	return "spg-" + d;
    })
    .attr("class", "spg-cats");
}

function initBarPlot (data){
	catInFocus = "positive_affect";
	var div = d3.select("#text-metadata");
	div.select ("#text-category")
	.text(catInFocus);
}

function updateBarPlot (data, season, episode){
	//var catInFocus = "positive_affect";
	var parts, wordCounter;
	var div = d3.select ("#text-metadata");
	div.select("#text-category").text(catInFocus);

	for (var i = data.length - 1; i >= 0; i--) {
		if (parseInt(data[i]["season"]) == season &&
			parseInt(data[i]["episode"]) == episode) {
			parts = data[i][catInFocus].split(",")
			wordCounter = parts.map (function (entry){
				return {
					word: entry.split(":")[0],
					freq: parseInt(entry.split(":")[1])
				}
			});
			break;
		}
	}

	var wordlist = d3.select ("#text-wordlist")
					.selectAll("li")
	               .data (wordCounter);

	wordlist.enter()
	.append("li")
	.text(function (d){
		return d.word;
	});

	wordlist.text(function (d){
		return d.word;
	});

	wordlist.exit().remove();
}

function init (){
	d3.tsv(textDataFile, function(error, data) {
    	textData = data;
    	initScatterPlot(textData);
    	updateScatterPlot(sliceData (textData, seasonNumber, episodeNumber));
	});

	d3.tsv(textMetaDataFile, function(error, data){
		textMetaData = data;
		initBarPlot (textMetaData);
		updateBarPlot (textMetaData, seasonNumber, episodeNumber);
	})
}

init();<|endoftext|>


<commit_before>"use strict";

const _ = require("ramda")

require("./pcss/main.pcss")

const DB = require("./local-pouch-db")
const sound = require("./sound")
const $ = require("jquery")
window.jQuery = $
require("./jquery.trap")
require("jquery-ui/ui/position")

async function boot() {
    $("#root").trap();

    // setTimeout(() => {
    //     $(".big-dialog").position({
    //         my: "left top", at: "left bottom", of: ".focusable-list"
    //         // , within: "#main-view > div"
    //         , collision: "fit"
    //     })
    // }, 2000)

    let syncList = []
    const dbMap = {
        "todo-db": await DB("todo-db"),
        "project-db": await DB("project-db"),
        "context-db": await DB("context-db")
    }

    // _.mapObjIndexed(db=>db.startRemoteSync(), dbMap)

    const todos = await dbMap["todo-db"].find({selector: {"_id": {"$ne": null}}})
    const projects = await dbMap["project-db"].find({selector: {"_id": {"$ne": null}}})
    const contexts = await dbMap["context-db"].find({selector: {"_id": {"$ne": null}}})

    const flags = {
        now: Date.now(),
        encodedTodoList: todos,
        encodedProjectList: projects,
        encodedContextList: contexts,
        pouchDBRemoteSyncURI: localStorage.getItem("pouchdb.remote-sync-uri") || ""
    }

    const Elm = require("elm/Main.elm")
    const app = Elm["Main"]
        .embed(document.getElementById("elm-app-container"), flags)

    app.ports["syncWithRemotePouch"].subscribe(async (uri) => {
        localStorage.setItem("pouchdb.remote-sync-uri", uri)
        await Promise.all(_.map(sync => sync.cancel())(syncList))
        syncList = _.compose(_.map(db => db.startRemoteSync(uri, "sgtd2-")), _.values)(dbMap)
    })

    app.ports["pouchDBUpsert"].subscribe(async ([dbName, id, doc]) => {
        // console.log("upserting", dbName, doc, id)
        const upsertResult = await dbMap[dbName].upsert(id, doc)
        if (_.F()) {
            console.log("upsertResult", upsertResult)
        }
    });

    setupNotifications(app)
        .catch(console.error)

    app.ports["focusSelector"].subscribe((selector) => {
        setTimeout(() => {
            requestAnimationFrame(() => {
                $(selector).focus()
            })
        }, 0)
    })

    app.ports["login"].subscribe(()=>{
        const intervalId = setInterval(()=>{
            let googleAuth = document.getElementById('google-auth');
            if(!googleAuth) return
            googleAuth
                .signInWithPopup()
                .then(console.info)
                .catch(console.error)
            clearTimeout(intervalId);
        },500)
    })

    app.ports["focusPaperInput"].subscribe((selector) => {
        setTimeout(() => {
            requestAnimationFrame(() => {
                const toFocus = document.querySelector(selector)
                // console.log("toFocus", toFocus, document.activeElement)
                if (toFocus && document.activeElement !== toFocus) {
                    toFocus.focus()
                } else {
                    // console.log("not focusing")
                }
                if (toFocus) {
                    // console.log(toFocus.inputElement, toFocus.$.input)
                    toFocus.inputElement.focus()
                    // toFocus.$.input.focus()
                }
            })
        }, 0)
    })

    app.ports["startAlarm"].subscribe(() => {
        sound.start()
    })

    app.ports["stopAlarm"].subscribe(() => {
        sound.stop()
    })
}

boot().catch(console.error)

async function setupNotifications(app) {

    if (!'serviceWorker' in navigator) {
        console.warn("servieWorker not found in navigator")
        return
    }

    const swScriptPath = WEB_PACK_DEV_SERVER ? "/notification-sw.js" : '/service-worker.js'

    navigator.serviceWorker.addEventListener('message', event => {
        console.info("message event received", event.data)
        app.ports["notificationClicked"].send(event.data)
        // event.ports[0].postMessage("Client 1 Says 'Hello back!'");
    });
    const reg = await navigator.serviceWorker.register(swScriptPath)

    app.ports["showNotification"].subscribe(showNotification(reg))
    app.ports["closeNotification"].subscribe(closeNotification(reg))

}

const closeNotification = reg => async (tag) => {
    const n = _.find(_.propEq("tag", tag), await reg.getNotifications())
    if (n) {
        n.close()
    }
}

const showNotification = reg => async ({tag, title, data}) => {
    //console.info(msg)
    const permission = await Notification.requestPermission()
    if (permission !== "granted") return
    reg.showNotification(title, {
        tag,
        requiresInteraction: true,
        sticky: true,
        renotify: true,
        vibrate: [500, 110, 500, 110, 450, 110, 200, 110, 170, 40, 450, 110, 200, 110, 170, 40, 500],
        sound: "/alarm.ogg",
        actions: [
            {title: "Mark Done", action: "mark-done"},
            {title: "Snooze", action: "snooze"},
        ],
        body: title,
        data
    })
}
/*
 //noinspection JSUnresolvedVariable
 if (!WEB_PACK_DEV_SERVER && 'serviceWorker' in navigator) {
 //noinspection JSUnresolvedVariable
 navigator.serviceWorker.register('/service-worker.js');
 }
 */
<commit_msg>add fcm push<commit_after>"use strict";

const _ = require("ramda")

require("./pcss/main.pcss")

const DB = require("./local-pouch-db")
const sound = require("./sound")
const $ = require("jquery")
window.jQuery = $
require("./jquery.trap")
require("jquery-ui/ui/position")

async function boot() {
    $("#root").trap();

    // setTimeout(() => {
    //     $(".big-dialog").position({
    //         my: "left top", at: "left bottom", of: ".focusable-list"
    //         // , within: "#main-view > div"
    //         , collision: "fit"
    //     })
    // }, 2000)

    let syncList = []
    const dbMap = {
        "todo-db": await DB("todo-db"),
        "project-db": await DB("project-db"),
        "context-db": await DB("context-db")
    }

    // _.mapObjIndexed(db=>db.startRemoteSync(), dbMap)

    const todos = await dbMap["todo-db"].find({selector: {"_id": {"$ne": null}}})
    const projects = await dbMap["project-db"].find({selector: {"_id": {"$ne": null}}})
    const contexts = await dbMap["context-db"].find({selector: {"_id": {"$ne": null}}})

    const flags = {
        now: Date.now(),
        encodedTodoList: todos,
        encodedProjectList: projects,
        encodedContextList: contexts,
        pouchDBRemoteSyncURI: localStorage.getItem("pouchdb.remote-sync-uri") || ""
    }

    const Elm = require("elm/Main.elm")
    const app = Elm["Main"]
        .embed(document.getElementById("elm-app-container"), flags)

    app.ports["syncWithRemotePouch"].subscribe(async (uri) => {
        localStorage.setItem("pouchdb.remote-sync-uri", uri)
        await Promise.all(_.map(sync => sync.cancel())(syncList))
        syncList = _.compose(_.map(db => db.startRemoteSync(uri, "sgtd2-")), _.values)(dbMap)
    })

    app.ports["pouchDBUpsert"].subscribe(async ([dbName, id, doc]) => {
        // console.log("upserting", dbName, doc, id)
        const upsertResult = await dbMap[dbName].upsert(id, doc)
        if (_.F()) {
            console.log("upsertResult", upsertResult)
        }
    });

    setupNotifications(app)
        .catch(console.error)

    app.ports["focusSelector"].subscribe((selector) => {
        setTimeout(() => {
            requestAnimationFrame(() => {
                $(selector).focus()
            })
        }, 0)
    })

    app.ports["login"].subscribe(()=>{
        const intervalId = setInterval(()=>{
            let googleAuth = document.getElementById('google-auth');
            if(!googleAuth) return
            googleAuth
                .signInWithRedirect()
                .then(console.info)
                .catch(console.error)
            clearTimeout(intervalId);
        },500)
    })

    app.ports["focusPaperInput"].subscribe((selector) => {
        setTimeout(() => {
            requestAnimationFrame(() => {
                const toFocus = document.querySelector(selector)
                // console.log("toFocus", toFocus, document.activeElement)
                if (toFocus && document.activeElement !== toFocus) {
                    toFocus.focus()
                } else {
                    // console.log("not focusing")
                }
                if (toFocus) {
                    // console.log(toFocus.inputElement, toFocus.$.input)
                    toFocus.inputElement.focus()
                    // toFocus.$.input.focus()
                }
            })
        }, 0)
    })

    app.ports["startAlarm"].subscribe(() => {
        sound.start()
    })

    app.ports["stopAlarm"].subscribe(() => {
        sound.stop()
    })
}

boot().catch(console.error)

async function setupNotifications(app) {

    if (!'serviceWorker' in navigator) {
        console.warn("servieWorker not found in navigator")
        return
    }

    const swScriptPath = WEB_PACK_DEV_SERVER ? "/notification-sw.js" : '/service-worker.js'

    navigator.serviceWorker.addEventListener('message', event => {
        console.info("message event received", event.data)
        app.ports["notificationClicked"].send(event.data)
        // event.ports[0].postMessage("Client 1 Says 'Hello back!'");
    });
    const reg = await navigator.serviceWorker.register(swScriptPath)

    app.ports["showNotification"].subscribe(showNotification(reg))
    app.ports["closeNotification"].subscribe(closeNotification(reg))

}

const closeNotification = reg => async (tag) => {
    const n = _.find(_.propEq("tag", tag), await reg.getNotifications())
    if (n) {
        n.close()
    }
}

const showNotification = reg => async ({tag, title, data}) => {
    //console.info(msg)
    const permission = await Notification.requestPermission()
    if (permission !== "granted") return
    reg.showNotification(title, {
        tag,
        requiresInteraction: true,
        sticky: true,
        renotify: true,
        vibrate: [500, 110, 500, 110, 450, 110, 200, 110, 170, 40, 450, 110, 200, 110, 170, 40, 500],
        sound: "/alarm.ogg",
        actions: [
            {title: "Mark Done", action: "mark-done"},
            {title: "Snooze", action: "snooze"},
        ],
        body: title,
        data
    })
}
/*
 //noinspection JSUnresolvedVariable
 if (!WEB_PACK_DEV_SERVER && 'serviceWorker' in navigator) {
 //noinspection JSUnresolvedVariable
 navigator.serviceWorker.register('/service-worker.js');
 }
 */
<|endoftext|>


<commit_before>"use strict";

var net = require('net'),
    Backbone = require('backbone'),
    _ = require('underscore'),
    Client = require('./client'),
    EventEmitter = require('events').EventEmitter;

var InputServer = Backbone.Model.extend({

    defaults: {
        port: 9000,
        server: null,
        emitter: new EventEmitter(),
        clients: []
    },

    initialize: function() {
        var self = this;

        this.set("server", net.createServer(function(socket) {
            console.log('New connection received!');

            var client = new Client({socket: socket, server: self});
            self.addClient(client);

            socket.on('data', function(data) {
                console.log('>> Data received: ' + data.toString());
                try {
                    var jsonContent = JSON.parse(data.toString());
                } catch(err) {
                    console.log('##### PARSER ERROR #####');
                    console.log(err);
                }

                if (typeof jsonContent !== 'undefined') self.get("emitter").emit('turn-received', jsonContent, client);
            });

            socket.on('end', _.bind(client.endConnection, client));
        }));
    },

    start: function() {
        var self = this;

        this.get("server").listen(this.get("port"), function() {
            console.log('Listening on ' + self.get("port") + '...');
        });
    },

    addClient: function(client) {
        this.get("clients").push(client);
    },

    removeClient: function(client) {
        this.set("clients", _.without(this.clients, client));
    }

});

module.exports = InputServer;
<commit_msg>InputServer default values refactored to avoid bad assignments<commit_after>"use strict";

var net = require('net'),
    Backbone = require('backbone'),
    _ = require('underscore'),
    Client = require('./client'),
    EventEmitter = require('events').EventEmitter;

var InputServer = Backbone.Model.extend({

    defaults: {
        port: 9000,
        server: null,
        emitter: null,
        clients: null
    },

    initialize: function() {
        var self = this;
        this.set("emitter", new EventEmitter());
        this.set("clients", []);

        this.set("server", net.createServer(function(socket) {
            console.log('New connection received!');

            var client = new Client({socket: socket, server: self});
            self.addClient(client);

            socket.on('data', function(data) {
                console.log('>> Data received: ' + data.toString());
                try {
                    var jsonContent = JSON.parse(data.toString());
                } catch(err) {
                    console.log('##### PARSER ERROR #####');
                    console.log(err);
                }

                if (typeof jsonContent !== 'undefined') self.get("emitter").emit('turn-received', jsonContent, client);
            });

            socket.on('end', _.bind(client.endConnection, client));
        }));
    },

    start: function() {
        var self = this;

        this.get("server").listen(this.get("port"), function() {
            console.log('Listening on ' + self.get("port") + '...');
        });
    },

    addClient: function(client) {
        this.get("clients").push(client);
    },

    removeClient: function(client) {
        this.set("clients", _.without(this.clients, client));
    }

});

module.exports = InputServer;
<|endoftext|>


<commit_before>const { Gpio } = require('onoff')
const io = require('socket.io-client')
const config = require('./config')

const socket = io(config.api)

function onPush (err, value, self, press, hold) {
  if (err) return console.error(err.stack || err)

  if (value) self.on = Date.now()
  else self.off = Date.now()

  // Is released after being pushed.
  if (!value && self.last && !self.disabled) {
    self.disabled = true

    const holdTime = self.off - self.on

    // If released 1700 milliseconds after pushed, button was held.
    if (holdTime > 1700) {
      hold && hold()
    } else {
      press()
    }

    // Only accept button pushes every 100 milliseconds.
    setTimeout(() => {
      self.disabled = false
    }, 100)
  }

  self.last = value
}

function button (gpio, press, hold) {
  const self = { on: 0, off: 0, last: 0, disabled: false }

  new Gpio(gpio, 'in', 'both')
    .watch((err, value) => {
      onPush(err, value, self, press, hold)
    })
}

const emit = event => () => socket.emit(event)

button(config.playerOne.green, emit('increment-player-one'))
button(config.playerOne.red, emit('decrement-player-one'), emit('end-game'))
button(config.playerTwo.green, emit('increment-player-two'))
button(config.playerTwo.red, emit('decrement-player-two'), emit('end-game'))
<commit_msg>Add GPIO logging<commit_after>const { Gpio } = require('onoff')
const io = require('socket.io-client')
const config = require('./config')

const socket = io(config.api)

const gpioReverse = {
  [config.playerOne.green]: 'player one green',
  [config.playerOne.red]: 'player one red',
  [config.playerTwo.green]: 'player two green',
  [config.playerTwo.red]: 'player two red',
}

function onPush (err, value, self, press, hold) {
  console.log(self.name, value)

  if (err) return console.error(self.name, err.stack || err)

  if (value) self.on = Date.now()
  else self.off = Date.now()

  // Is released after being pushed.
  if (!value && self.last && !self.disabled) {
    self.disabled = true

    const holdTime = self.off - self.on

    // If released 1700 milliseconds after pushed, button was held.
    if (holdTime > 1700) {
      console.log(self.name, 'hold')
      hold && hold()
    } else {
      console.log(self.name, 'press')
      press()
    }

    // Only accept button pushes every 100 milliseconds.
    setTimeout(() => {
      self.disabled = false
    }, 100)
  }

  self.last = value
}

function button (gpio, press, hold) {
  const self = { name: gpioReverse[gpio], on: 0, off: 0, last: 0, disabled: false }

  new Gpio(gpio, 'in', 'both')
    .watch((err, value) => {
      onPush(err, value, self, press, hold)
    })
}

const emit = event => () => socket.emit(event)

button(config.playerOne.green, emit('increment-player-one'))
button(config.playerOne.red, emit('decrement-player-one'), emit('end-game'))
button(config.playerTwo.green, emit('increment-player-two'))
button(config.playerTwo.red, emit('decrement-player-two'), emit('end-game'))
<|endoftext|>


<commit_before>// @flow
import * as React from 'react'
import * as TabConstants from '../../constants/tabs'
import * as Constants from '../../constants/settings'
import {StyleSheet} from 'react-native'
import {globalStyles, globalColors, globalMargins} from '../../styles'
import {Box, Badge, ClickableBox, Text, HeaderHoc, NativeScrollView} from '../../common-adapters/mobile.native'
import {isAndroid} from '../../constants/platform'
import {compose, defaultProps} from 'recompose'
import flags from '../../util/feature-flags'

import type {Props} from './index'

export function SettingsItem({
  text,
  onClick,
  badgeNumber,
}: {
  text: string,
  onClick: () => void,
  badgeNumber: number,
}) {
  return (
    <ClickableBox onClick={onClick} style={itemStyle}>
      <Box style={{...globalStyles.flexBoxRow}}>
        <Text type={'BodySmallSemibold'} style={itemTextStyle}>
          {text.toUpperCase()}
        </Text>
        {!!badgeNumber && badgeNumber > 0 && <Badge badgeStyle={badgeStyle} badgeNumber={badgeNumber} />}
      </Box>
    </ClickableBox>
  )
}

function SettingsNav({badgeNotifications, badgeNumbers, selectedTab, onTabChange, onLogout}: Props) {
  return (
    <NativeScrollView style={{width: '100%', height: '100%'}}>
      <Box style={styleNavBox}>
        <SettingsItem
          text="Files"
          badgeNumber={badgeNumbers[TabConstants.fsTab]}
          onClick={() => onTabChange(Constants.fsTab)}
        />
        <SettingsItem
          text="Git"
          badgeNumber={badgeNumbers[TabConstants.gitTab]}
          onClick={() => onTabChange(Constants.gitTab)}
        />
        <SettingsItem
          text="Devices"
          badgeNumber={badgeNumbers[TabConstants.devicesTab]}
          onClick={() => onTabChange(Constants.devicesTab)}
        />
        {flags.walletsEnabled && (
          <SettingsItem
            text="Wallets"
            badgeNumber={badgeNumbers[TabConstants.walletsTab]}
            onClick={() => onTabChange(Constants.walletsTab)}
          />
        )}
        <SettingsItem
          text="Notifications"
          badgeNumber={badgeNotifications ? 1 : 0}
          onClick={() => onTabChange(Constants.notificationsTab)}
        />
        <SettingsItem
          text="Passphrase"
          badgeNumber={0}
          onClick={() => onTabChange(Constants.passphraseTab)}
        />
        <SettingsItem text="About" badgeNumber={0} onClick={() => onTabChange(Constants.aboutTab)} />
        <SettingsItem text="Feedback" badgeNumber={0} onClick={() => onTabChange(Constants.feedbackTab)} />
        {isAndroid && (
          <SettingsItem
            text="Screen Protector"
            badgeNumber={0}
            onClick={() => onTabChange(Constants.screenprotectorTab)}
          />
        )}
        <SettingsItem
          text="Advanced"
          selected={selectedTab === Constants.advancedTab}
          badgeNumber={0}
          onClick={() => onTabChange(Constants.advancedTab)}
        />
        <SettingsItem text="Sign out" badgeNumber={0} onClick={onLogout} />
        {__DEV__ && (
          <SettingsItem
            text="😎   Dev Menu"
            badgeNumber={0}
            onClick={() => onTabChange(Constants.devMenuTab)}
          />
        )}
      </Box>
    </NativeScrollView>
  )
}
const styleNavBox = {
  ...globalStyles.flexBoxColumn,
  backgroundColor: globalColors.white,
  borderBottomColor: globalColors.black_05,
}
const itemStyle = {
  ...globalStyles.flexBoxRow,
  height: 64,
  paddingLeft: globalMargins.small,
  paddingRight: globalMargins.small,
  alignItems: 'center',
  position: 'relative',
  borderBottomColor: globalColors.black_05,
  borderBottomWidth: StyleSheet.hairlineWidth,
}
const itemTextStyle = {
  color: globalColors.black_60,
}
const badgeStyle = {
  marginRight: 0,
  marginLeft: 4,
  marginTop: 2,
}
export default compose(defaultProps({title: 'SETTINGS'}), HeaderHoc)(SettingsNav)
<commit_msg>Update mobile settings tab with sections. (#12123)<commit_after>// @flow
import * as React from 'react'
import * as TabConstants from '../../constants/tabs'
import * as Constants from '../../constants/settings'
import {StyleSheet} from 'react-native'
import {globalStyles, globalColors, globalMargins, type Color} from '../../styles'
import {
  Badge,
  Box,
  ClickableBox,
  HeaderHoc,
  Icon,
  NativeSectionList,
  Text,
} from '../../common-adapters/mobile.native'
import {isAndroid} from '../../constants/platform'
import flags from '../../util/feature-flags'

import type {Props} from './index'

function SettingsItem({
  badgeNumber,
  icon,
  onClick,
  text,
  textColor,
}: {
  badgeNumber: number,
  icon?: any,
  onClick: () => void,
  text: string,
  textColor?: Color,
}) {
  return text ? (
    <ClickableBox onClick={onClick} style={itemStyle}>
      <Box style={{...globalStyles.flexBoxRow}}>
        {icon && (
          <Icon type={icon} color={globalColors.black_20} style={{marginRight: globalMargins.small}} />
        )}
        <Text
          type="BodySemibold"
          style={{color: textColor || globalColors.black_75, position: 'relative', top: 3}}
        >
          {text}
        </Text>
        {!!badgeNumber && badgeNumber > 0 && <Badge badgeStyle={badgeStyle} badgeNumber={badgeNumber} />}
      </Box>
    </ClickableBox>
  ) : null
}

const renderItem = ({item}) => {
  return <SettingsItem {...item} />
}

function SettingsNav({badgeNotifications, badgeNumbers, selectedTab, onTabChange, onLogout}: Props) {
  return (
    <NativeSectionList
      keyExtractor={(item, index) => item.text + index}
      renderItem={renderItem}
      renderSectionHeader={({section: {title}}) =>
        title ? (
          <Text type="BodySmallSemibold" style={sectionTitleStyle}>
            {title}
          </Text>
        ) : null
      }
      style={globalStyles.fullHeight}
      sections={[
        {
          data: [
            {
              badgeNumber: badgeNumbers[TabConstants.fsTab],
              icon: 'iconfont-nav-files',
              onClick: () => onTabChange(Constants.fsTab),
              text: 'Files',
            },
            {
              badgeNumber: badgeNumbers[TabConstants.gitTab],
              icon: 'iconfont-nav-git',
              onClick: () => onTabChange(Constants.gitTab),
              text: 'Git',
            },
            {
              badgeNumber: badgeNumbers[TabConstants.devicesTab],
              icon: 'iconfont-nav-devices',
              onClick: () => onTabChange(Constants.devicesTab),
              text: 'Devices',
            },
            {
              ...(flags.walletsEnabled
                ? {
                    badgeNumber: badgeNumbers[TabConstants.walletsTab],
                    icon: 'iconfont-nav-wallets',
                    onClick: () => onTabChange(Constants.walletsTab),
                    text: 'Wallet',
                  }
                : {}),
            },
            {
              ...(__DEV__
                ? {
                    badgeNumber: 0,
                    icon: 'iconfont-nav-settings',
                    onClick: () => onTabChange(Constants.devMenuTab),
                    text: 'Dev Menu',
                  }
                : {}),
            },
          ],
          title: '',
        },
        {
          data: [
            {
              badgeNumber: badgeNotifications ? 1 : 0,
              onClick: () => onTabChange(Constants.notificationsTab),
              text: 'Notifications',
            },
            {
              badgeNumber: 0,
              onClick: () => onTabChange(Constants.passphraseTab),
              text: 'Change passphrase',
            },
            {
              ...(isAndroid
                ? {
                    badgeNumber: 0,
                    onClick: () => onTabChange(Constants.screenprotectorTab),
                    text: 'Screen Protector',
                  }
                : {}),
            },
          ],
          title: 'Settings',
        },
        {
          data: [
            {
              badgeNumber: 0,
              onClick: () => onTabChange(Constants.aboutTab),
              text: 'About',
            },
            {
              badgeNumber: 0,
              onClick: () => onTabChange(Constants.feedbackTab),
              text: 'Feedback',
            },
            {
              badgeNumber: 0,
              onClick: () => onTabChange(Constants.advancedTab),
              text: 'Advanced',
            },
            {
              badgeNumber: 0,
              onClick: onLogout,
              text: 'Sign out',
              textColor: globalColors.red,
            },
          ],
          title: 'More',
        },
      ]}
    />
  )
}

const itemStyle = {
  ...globalStyles.flexBoxRow,
  alignItems: 'center',
  borderBottomColor: globalColors.black_05,
  borderBottomWidth: StyleSheet.hairlineWidth,
  height: 56,
  paddingLeft: globalMargins.small,
  paddingRight: globalMargins.small,
  position: 'relative',
}

const badgeStyle = {
  marginLeft: 4,
  marginRight: 0,
  marginTop: 2,
}

const sectionTitleStyle = {
  backgroundColor: globalColors.blue5,
  color: globalColors.black_40,
  paddingBottom: 7,
  paddingLeft: globalMargins.small,
  paddingRight: globalMargins.small,
  paddingTop: 7,
}

export default HeaderHoc(SettingsNav)
<|endoftext|>