<commit_before>describe('Home controller', function() {
    'use strict';

    var ctrl, createController, scope, $httpBackend;

    beforeEach(module('data-prep.home'));

    beforeEach(inject(function ($injector, MessageService) {
        $httpBackend = $injector.get('$httpBackend');
        $httpBackend.when('GET', 'i18n/en.json').respond({});
        $httpBackend.when('GET', 'i18n/fr.json').respond({});

        spyOn(MessageService, 'success').and.callThrough();
        spyOn(MessageService, 'error').and.callThrough();
    }));

    beforeEach(inject(function($rootScope, $controller) {
        scope = $rootScope.$new();

        createController = function() {
            return $controller('HomeCtrl', {
                $scope: scope
            });
        };
    }));

    it('should init upload list to empty array', function() {
        //when
        ctrl = createController();

        //then
        expect(ctrl.uploadingDatasets).toEqual([]);
    });

    describe('with created controller', function() {
        var uploadDefer;

        beforeEach(inject(function($q, DatasetService) {
            ctrl = createController();
            ctrl.datasetFile = [{name: 'my dataset.csv'}];
            ctrl.datasetName = 'my cool dataset';

            uploadDefer = $q.defer();
            uploadDefer.promise.progress = function(callback) {
                uploadDefer.progressCb = callback;
                return uploadDefer.promise;
            };

            spyOn(DatasetService, 'fileToDataset').and.callThrough();
            spyOn(DatasetService, 'create').and.returnValue(uploadDefer.promise);
            spyOn(DatasetService, 'update').and.returnValue(uploadDefer.promise);
        }));

        it('should toggle right panel flag', function() {
            //given
            expect(ctrl.showRightPanel).toBe(true);

            //when
            ctrl.toggleRightPanel();

            //then
            expect(ctrl.showRightPanel).toBe(false);

            //when
            ctrl.toggleRightPanel();

            //then
            expect(ctrl.showRightPanel).toBe(true);
        });

        it('should remove file extension for name init and display name modal on step 1', function() {
            //given
            expect(ctrl.datasetNameModal).toBeFalsy();

            //when
            ctrl.uploadDatasetFile();

            //then
            expect(ctrl.datasetName).toBeTruthy('my dataset');
            expect(ctrl.datasetNameModal).toBeTruthy();
        });

        describe('step 2 with unique name', function() {

            beforeEach(inject(function($rootScope, DatasetService) {
                spyOn(DatasetService, 'getDatasetByName').and.returnValue(null);
                spyOn($rootScope, '$emit').and.callThrough();
            }));

            it('should create dataset if name is unique', inject(function($q, $rootScope, MessageService, DatasetService, UploadWorkflowService) {
                //given
                var dataset = {id: 'ec4834d9bc2af8', name: 'Customers (50 lines)', draft: false};
                spyOn(DatasetService, 'getDatasetById').and.returnValue($q.when(dataset));
                spyOn(UploadWorkflowService, 'openDataset').and.returnValue();

                expect(ctrl.uploadingDatasets.length).toBe(0);
                ctrl.uploadDatasetName();
                expect(ctrl.uploadingDatasets.length).toBe(1);

                //when
                uploadDefer.resolve({data: dataset.id});
                scope.$digest();

                //then
                expect(DatasetService.create).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets.length).toBe(0);
                expect(DatasetService.getDatasetById).toHaveBeenCalledWith(dataset.id);
                expect(UploadWorkflowService.openDataset).toHaveBeenCalled();
            }));

            it('should update progress on create', inject(function(DatasetService) {
                //given
                ctrl.uploadDatasetName();
                expect(ctrl.uploadingDatasets[0].progress).toBeFalsy();

                var event = {
                    loaded: 140,
                    total: 200
                };

                //when
                uploadDefer.progressCb(event);
                scope.$digest();

                //then
                expect(DatasetService.create).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets[0].progress).toBe(70);
            }));

            it('should set error flag and show error toast', inject(function(DatasetService, MessageService) {
                //given
                ctrl.uploadDatasetName();
                expect(ctrl.uploadingDatasets[0].error).toBeFalsy();

                //when
                uploadDefer.reject();
                scope.$digest();

                //then
                expect(DatasetService.create).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets[0].error).toBeTruthy();
                expect(MessageService.error).toHaveBeenCalledWith('UPLOAD_ERROR_TITLE', 'UPLOAD_ERROR');
            }));
        });

        describe('step 2 with existing name', function() {
            var dataset = {
                name: 'my cool dataset'
            };
            var confirmDefer;

            beforeEach(inject(function ($rootScope, $q, DatasetService, TalendConfirmService) {
                confirmDefer = $q.defer();

                spyOn(DatasetService, 'getDatasetByName').and.returnValue(dataset);
                spyOn(DatasetService, 'getUniqueName').and.returnValue('my cool dataset (1)');
                spyOn(TalendConfirmService, 'confirm').and.returnValue(confirmDefer.promise);
                spyOn($rootScope, '$emit').and.callThrough();
            }));

            it('should do nothing on confirm modal dismiss', inject(function (TalendConfirmService, DatasetService) {
                //given
                ctrl.uploadDatasetName();

                //when
                confirmDefer.reject('dismiss');
                scope.$digest();

                //then
                expect(DatasetService.getDatasetByName).toHaveBeenCalledWith(ctrl.datasetName);
                expect(TalendConfirmService.confirm).toHaveBeenCalledWith(null, [ 'UPDATE_EXISTING_DATASET' ], { dataset: 'my cool dataset' });
                expect(DatasetService.create).not.toHaveBeenCalled();
                expect(DatasetService.update).not.toHaveBeenCalled();
            }));

            //it('should create dataset with modified name', inject(function ($rootScope, MessageService, TalendConfirmService, DatasetService) {
            //    //given
            //    ctrl.uploadDatasetName();
			//
            //    //when
            //    confirmDefer.reject();
            //    scope.$digest();
            //    uploadDefer.resolve({data :'dataset_id_XYZ'});
            //    scope.$digest();
			//
            //    //then
            //    expect(DatasetService.fileToDataset).toHaveBeenCalledWith(ctrl.datasetFile[0], 'my cool dataset (1)');
            //    expect($rootScope.$emit).toHaveBeenCalledWith('talend.dataset.open', 'dataset_id_XYZ');
            //}));

            it('should update existing dataset', inject(function (MessageService, TalendConfirmService, DatasetService) {
                //given
                ctrl.uploadDatasetName();

                //when
                confirmDefer.resolve();
                scope.$digest();
                expect(ctrl.uploadingDatasets.length).toBe(1);
                uploadDefer.resolve();
                scope.$digest();

                //then
                expect(DatasetService.update).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets.length).toBe(0);
                expect(MessageService.success).toHaveBeenCalledWith('DATASET_UPDATE_SUCCESS_TITLE', 'DATASET_UPDATE_SUCCESS', {dataset : 'my cool dataset'});
            }));

            it('should set error flag and show error toast on update error', inject(function (MessageService, TalendConfirmService, DatasetService) {
                //given
                ctrl.uploadDatasetName();

                //when
                confirmDefer.resolve();
                scope.$digest();
                expect(ctrl.uploadingDatasets.length).toBe(1);
                uploadDefer.reject();
                scope.$digest();

                //then
                expect(DatasetService.update).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets[0].error).toBeTruthy();
                expect(MessageService.error).toHaveBeenCalledWith('UPLOAD_ERROR_TITLE', 'UPLOAD_ERROR');
            }));

            it('should update progress on update', inject(function (TalendConfirmService, DatasetService) {
                //given
                ctrl.uploadDatasetName();
                confirmDefer.resolve();
                scope.$digest();
                expect(ctrl.uploadingDatasets[0].progress).toBeFalsy();

                var event = {
                    loaded: 140,
                    total: 200
                };

                //when
                uploadDefer.progressCb(event);
                scope.$digest();

                //then
                expect(DatasetService.update).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets[0].progress).toBe(70);
            }));
        });
    });

});
<commit_msg>bugfix/262 upload file after preparation with refacto and fixes<commit_after>describe('Home controller', function() {
    'use strict';

    var ctrl, createController, scope, $httpBackend;

    beforeEach(module('data-prep.home'));

    beforeEach(inject(function ($injector, MessageService) {
        $httpBackend = $injector.get('$httpBackend');
        $httpBackend.when('GET', 'i18n/en.json').respond({});
        $httpBackend.when('GET', 'i18n/fr.json').respond({});

        spyOn(MessageService, 'success').and.callThrough();
        spyOn(MessageService, 'error').and.callThrough();
    }));

    beforeEach(inject(function($rootScope, $controller) {
        scope = $rootScope.$new();

        createController = function() {
            return $controller('HomeCtrl', {
                $scope: scope
            });
        };
    }));

    it('should init upload list to empty array', function() {
        //when
        ctrl = createController();

        //then
        expect(ctrl.uploadingDatasets).toEqual([]);
    });

    describe('with created controller', function() {
        var uploadDefer;

        beforeEach(inject(function($q, DatasetService, UploadWorkflowService) {
            ctrl = createController();
            ctrl.datasetFile = [{name: 'my dataset.csv'}];
            ctrl.datasetName = 'my cool dataset';

            uploadDefer = $q.defer();
            uploadDefer.promise.progress = function(callback) {
                uploadDefer.progressCb = callback;
                return uploadDefer.promise;
            };
            var dataset = {id: 'ec4834d9bc2af8', name: 'Customers (50 lines)', draft: false};
            spyOn(DatasetService, 'getDatasetById').and.returnValue($q.when(dataset));
            spyOn(UploadWorkflowService, 'openDataset').and.returnValue();
            spyOn(DatasetService, 'fileToDataset').and.callThrough();
            spyOn(DatasetService, 'create').and.returnValue(uploadDefer.promise);
            spyOn(DatasetService, 'update').and.returnValue(uploadDefer.promise);
        }));

        it('should toggle right panel flag', function() {
            //given
            expect(ctrl.showRightPanel).toBe(true);

            //when
            ctrl.toggleRightPanel();

            //then
            expect(ctrl.showRightPanel).toBe(false);

            //when
            ctrl.toggleRightPanel();

            //then
            expect(ctrl.showRightPanel).toBe(true);
        });

        it('should remove file extension for name init and display name modal on step 1', function() {
            //given
            expect(ctrl.datasetNameModal).toBeFalsy();

            //when
            ctrl.uploadDatasetFile();

            //then
            expect(ctrl.datasetName).toBeTruthy('my dataset');
            expect(ctrl.datasetNameModal).toBeTruthy();
        });

        describe('step 2 with unique name', function() {

            beforeEach(inject(function($rootScope, DatasetService) {
                spyOn(DatasetService, 'getDatasetByName').and.returnValue(null);
                spyOn($rootScope, '$emit').and.callThrough();
            }));

            it('should create dataset if name is unique', inject(function($q, $rootScope, MessageService, DatasetService, UploadWorkflowService) {
                //given
                var dataset = {id: 'ec4834d9bc2af8', name: 'Customers (50 lines)', draft: false};
                expect(ctrl.uploadingDatasets.length).toBe(0);
                ctrl.uploadDatasetName();
                expect(ctrl.uploadingDatasets.length).toBe(1);

                //when
                uploadDefer.resolve({data: dataset.id});
                scope.$digest();

                //then
                expect(DatasetService.create).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets.length).toBe(0);
                expect(DatasetService.getDatasetById).toHaveBeenCalledWith(dataset.id);
                expect(UploadWorkflowService.openDataset).toHaveBeenCalled();
            }));

            it('should update progress on create', inject(function(DatasetService) {
                //given
                ctrl.uploadDatasetName();
                expect(ctrl.uploadingDatasets[0].progress).toBeFalsy();

                var event = {
                    loaded: 140,
                    total: 200
                };

                //when
                uploadDefer.progressCb(event);
                scope.$digest();

                //then
                expect(DatasetService.create).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets[0].progress).toBe(70);
            }));

            it('should set error flag and show error toast', inject(function(DatasetService, MessageService) {
                //given
                ctrl.uploadDatasetName();
                expect(ctrl.uploadingDatasets[0].error).toBeFalsy();

                //when
                uploadDefer.reject();
                scope.$digest();

                //then
                expect(DatasetService.create).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets[0].error).toBeTruthy();
                expect(MessageService.error).toHaveBeenCalledWith('UPLOAD_ERROR_TITLE', 'UPLOAD_ERROR');
            }));
        });

        describe('step 2 with existing name', function() {
            var dataset = {
                name: 'my cool dataset'
            };
            var confirmDefer;

            beforeEach(inject(function ($rootScope, $q, DatasetService, TalendConfirmService) {
                confirmDefer = $q.defer();

                spyOn(DatasetService, 'getDatasetByName').and.returnValue(dataset);
                spyOn(DatasetService, 'getUniqueName').and.returnValue('my cool dataset (1)');
                spyOn(TalendConfirmService, 'confirm').and.returnValue(confirmDefer.promise);
                spyOn($rootScope, '$emit').and.callThrough();
            }));

            it('should do nothing on confirm modal dismiss', inject(function (TalendConfirmService, DatasetService) {
                //given
                ctrl.uploadDatasetName();

                //when
                confirmDefer.reject('dismiss');
                scope.$digest();

                //then
                expect(DatasetService.getDatasetByName).toHaveBeenCalledWith(ctrl.datasetName);
                expect(TalendConfirmService.confirm).toHaveBeenCalledWith(null, [ 'UPDATE_EXISTING_DATASET' ], { dataset: 'my cool dataset' });
                expect(DatasetService.create).not.toHaveBeenCalled();
                expect(DatasetService.update).not.toHaveBeenCalled();
            }));

            it('should create dataset with modified name', inject(function ($rootScope, MessageService, TalendConfirmService, DatasetService) {
                //given
                ctrl.uploadDatasetName();

                //when
                confirmDefer.reject();
                scope.$digest();
                uploadDefer.resolve({data :'dataset_id_XYZ'});
                scope.$digest();

                //then
                expect(DatasetService.fileToDataset).toHaveBeenCalledWith(ctrl.datasetFile[0], 'my cool dataset (1)');
            }));

            it('should update existing dataset', inject(function (MessageService, TalendConfirmService, DatasetService) {
                //given
                ctrl.uploadDatasetName();

                //when
                confirmDefer.resolve();
                scope.$digest();
                expect(ctrl.uploadingDatasets.length).toBe(1);
                uploadDefer.resolve();
                scope.$digest();

                //then
                expect(DatasetService.update).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets.length).toBe(0);
                expect(MessageService.success).toHaveBeenCalledWith('DATASET_UPDATE_SUCCESS_TITLE', 'DATASET_UPDATE_SUCCESS', {dataset : 'my cool dataset'});
            }));

            it('should set error flag and show error toast on update error', inject(function (MessageService, TalendConfirmService, DatasetService) {
                //given
                ctrl.uploadDatasetName();

                //when
                confirmDefer.resolve();
                scope.$digest();
                expect(ctrl.uploadingDatasets.length).toBe(1);
                uploadDefer.reject();
                scope.$digest();

                //then
                expect(DatasetService.update).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets[0].error).toBeTruthy();
                expect(MessageService.error).toHaveBeenCalledWith('UPLOAD_ERROR_TITLE', 'UPLOAD_ERROR');
            }));

            it('should update progress on update', inject(function (TalendConfirmService, DatasetService) {
                //given
                ctrl.uploadDatasetName();
                confirmDefer.resolve();
                scope.$digest();
                expect(ctrl.uploadingDatasets[0].progress).toBeFalsy();

                var event = {
                    loaded: 140,
                    total: 200
                };

                //when
                uploadDefer.progressCb(event);
                scope.$digest();

                //then
                expect(DatasetService.update).toHaveBeenCalled();
                expect(ctrl.uploadingDatasets[0].progress).toBe(70);
            }));
        });
    });

});
<|endoftext|>


<commit_before>/* Helper function */
function sendAjax(divname,ajaxurl,text,nextstep)
{
  $.ajax({
   type: "GET",
   url: ajaxurl,
   success: function(msg){

    $(divname).html(msg);

    var index = msg.indexOf(':');
    var prefix = '';
    var error = '';
    if(index>0)
      {
      prefix = msg.substr(0,index);
      error = msg.substr(index+1);
      }

    if(prefix != "ERROR" && prefix != "WARNING")
      {
      $(divname).html(text+": <img src=\"images/check.gif\"");
      nextstep();
      }
    else if(prefix == "WARNING")
      {
      $(divname).html(text+": "+error+" <img src=\"images/check.gif\"");
      nextstep();
      }
    else
      {
      $(divname).html("An error as occured");
      }
   }
   });
}

function upgrade_tables()
{
  var text = "Upgrading tables";
  $("#Upgrade-Tables-Status").html(" "+text+"...");

  // Go directly to the appropriate version
  nextstep = upgrade_0_8;
  if(version < 1.0)
    {
    nextstep = upgrade_1_0;
    }
  else if(version < 1.2)
    {
    nextstep = upgrade_1_2;
    }

  sendAjax("#Upgrade-Tables-Status","backwardCompatibilityTools.php?upgrade-tables=1",text,nextstep);
}

function upgrade_0_8()
{
  var text = "Applying 0.8 patches";
  $("#Upgrade-0-8-Status").html(" "+text+"...");
  sendAjax("#Upgrade-0-8-Status","backwardCompatibilityTools.php?upgrade-0-8=1",text,upgrade_1_0);
}

function upgrade_1_0()
{
  var text = "Applying 1.0 patches";
  $("#Upgrade-1-0-Status").html(" "+text+"...");
  sendAjax("#Upgrade-1-0-Status","backwardCompatibilityTools.php?upgrade-1-0=1",text,upgrade_1_2);
}

function upgrade_1_2()
{
  var text = "Applying 1.2 patches";
  $("#Upgrade-1-2-Status").html(" "+text+"...");
  sendAjax("#Upgrade-1-2-Status","backwardCompatibilityTools.php?upgrade-1-2=1",text,done);
}

// empty function needed
function done()
{
  $("#DoneStatus").html("CDash Upgrade Successful.");
}

$(document).ready(function() {
  // Trigger the first ajax function
  upgrade_tables();
});
<commit_msg>BUG: 7668: Broken image link on database upgrade <commit_after>/* Helper function */
function sendAjax(divname,ajaxurl,text,nextstep)
{
  $.ajax({
   type: "GET",
   url: ajaxurl,
   success: function(msg){

    $(divname).html(msg);

    var index = msg.indexOf(':');
    var prefix = '';
    var error = '';
    if(index>0)
      {
      prefix = msg.substr(0,index);
      error = msg.substr(index+1);
      }

    if(prefix != "ERROR" && prefix != "WARNING")
      {
      $(divname).html(text+": ");
      nextstep();
      }
    else if(prefix == "WARNING")
      {
      $(divname).html(text+": "+error+" ");
      nextstep();
      }
    else
      {
      $(divname).html("An error as occured");
      }
   }
   });
}

function upgrade_tables()
{
  var text = "Upgrading tables";
  $("#Upgrade-Tables-Status").html(" "+text+"...");

  // Go directly to the appropriate version
  nextstep = upgrade_0_8;
  if(version < 1.0)
    {
    nextstep = upgrade_1_0;
    }
  else if(version < 1.2)
    {
    nextstep = upgrade_1_2;
    }

  sendAjax("#Upgrade-Tables-Status","backwardCompatibilityTools.php?upgrade-tables=1",text,nextstep);
}

function upgrade_0_8()
{
  var text = "Applying 0.8 patches";
  $("#Upgrade-0-8-Status").html(" "+text+"...");
  sendAjax("#Upgrade-0-8-Status","backwardCompatibilityTools.php?upgrade-0-8=1",text,upgrade_1_0);
}

function upgrade_1_0()
{
  var text = "Applying 1.0 patches";
  $("#Upgrade-1-0-Status").html(" "+text+"...");
  sendAjax("#Upgrade-1-0-Status","backwardCompatibilityTools.php?upgrade-1-0=1",text,upgrade_1_2);
}

function upgrade_1_2()
{
  var text = "Applying 1.2 patches";
  $("#Upgrade-1-2-Status").html(" "+text+"...");
  sendAjax("#Upgrade-1-2-Status","backwardCompatibilityTools.php?upgrade-1-2=1",text,done);
}

// empty function needed
function done()
{
  $("#DoneStatus").html("CDash Upgrade Successful.");
}

$(document).ready(function() {
  // Trigger the first ajax function
  upgrade_tables();
});
<|endoftext|>


<commit_before>import {containerless, bindable} from 'aurelia-framework';
import {Field} from './abstract/field';
import {parseJSON} from '../jsonparser';

/**
 * Typefield is a {@link Field} that shows different child forms depending on
 * the type the user chooses.
 *
 * This allows for theoretically infinite nesting because it uses lazy
 * evaluation and supports $refs in type options.
 */
@containerless
export class Typefield extends Field {
  /**
   * The type that is currently selected.
   * @type {String}
   */
  @bindable selectedType = '';
  /**
   * The key where to put the value of the child field to in the output of this
   * field.
   * @type {String}
   */
  valueKey = '';
  /**
   * The key where to put the key of this field ({@link #key}) in the output of
   * this field.
   * @type {String}
   */
  keyKey = '';
  /**
   * The current key of this field. Exists as a legend field in the form if
   * {@link #keyKey} is defined.
   * @type {String}
   */
  key = '';
  /**
   * The placeholder for the key form field.
   * @type {String}
   */
  keyPlaceholder = '';
  /**
   * The key where to put the type of this field.
   * @type {String}
   */
  typeKey = 'x-oad-type';
  /**
   * Whether or not to copy the value over to the new child when switching types.
   *
   * N.B. Absolutely nothing is done to ensure the data ends up in the right
   * place. Only use this if most of the fields in different types are in nearly
   * the same places.
   * @type {Boolean}
   */
  copyValue = false;
  /**
   * The current child field.
   * @type {Field}
   * @private
   */
  child = undefined;
  /**
   * The schemas for the available types.
   * @type {Object}
   */
  types = {};
  /**
   * Whether or not the UI element should be collapsed (i.e. only show the title)
   * @type {Boolean}
   */
  collapsed = false;
  isCollapsible = true;

  /*
   * Called by child fields when they are collapsed/uncollapsed.
   * Unused in Typefields, currently only used in Arrayfields.
   */
  childCollapseChanged(field, isNowCollapsed) {}

  toggleCollapse() {
    this.setCollapsed(!this.collapsed);
  }

  setCollapsed(collapsed) {
    this.collapsed = collapsed;
    if (this.parent) {
      this.parent.childCollapseChanged(this, this.collapsed);
    }
  }

  /** @inheritdoc */
  init(id = '', args = {}) {
    args = Object.assign({
      valueKey: '',
      typeKey: 'x-oad-type',
      keyKey: '',
      keyPlaceholder: 'Object key...',
      copyValue: false,
      collapsed: false,
      types: { 'null': { 'type': 'text' } }
    }, args);
    this.types = args.types;
    this.valueKey = args.valueKey;
    this.typeKey = args.typeKey;
    this.keyKey = args.keyKey;
    this.keyPlaceholder = args.keyPlaceholder;
    this.copyValue = args.copyValue;
    this.collapsed = args.collapsed;
    this.defaultType = args.defaultType;
    this.selectedType = args.defaultType || Object.keys(this.types)[0];
    this.selectedTypeChanged(this.selectedType);
    return super.init(id, args);
  }

  /**
   * Check if this field doesn't currently have a child or if the child is empty.
   */
  isEmpty() {
    if (!this.child) {
      return true;
    }
    return this.child.isEmpty();
  }

  /**
   * Called by Aurelia when the selected type changes (e.g. from the dropdown)
   * @param {String} newType The new type.
   */
  selectedTypeChanged(newType) {
    const newSchema = this.types[newType];
    const value = this.copyValue ? this.getValue() : undefined;
    let newChild;
    if (newSchema.hasOwnProperty('$ref')) {
      newChild = this.resolveRef(newSchema.$ref).clone();
    } else {
      newChild = parseJSON(newType, JSON.parse(JSON.stringify(newSchema)));
    }
    if (newChild) {
      newChild.parent = this;
      if (value) {
        this.setValue(value);
      }
      this.child = newChild;
    }
    this.onChange();
  }

  /**
   * Get the value of this field.
   *
   * If the value of the child is undefined, this will return undefined.
   *
   * The value of the child will be put into an object with {@link #valueKey} or
   * `value` as the key if the value is not already an object and one of the
   * following fields is defined:
   *   a) {@link #typeKey}
   *   b) {@link #keyKey}
   *   c) {@link #valueKey}
   * If {@link #valueKey} is defined, the child value will be put into an object
   * as described previously regardless of whether or not the child value is an
   * object.
   *
   * If {@link #typeKey} is defined, the name of the selected type will be added
   * to the return object with {@link #typeKey} as its key.
   * If {@link #keyKey} is defined, the return object will contain a field with
   * {@link #keyKey} as its key and the key from the fieldset legend as the value.
   *
   * @return {Object} The processed value.
   */
  getValue() {
    if (!this.child) {
      return undefined;
    }

    let value = this.child.getValue();
    // True if the value of the child is either not an object or is an array.
    // In other words, can/should we put named fields in the value directly?
    const valueIsNotObject = typeof value !== 'object' || Array.isArray(value);
    // If valueKey is set, the value of the child should always be stored in an
    // object with valueKey as the key for the value of the child.
    //
    // If the value is not an object or is an array AND either keyKey or
    // typeKey is set, the above should be done regardless of whether or not
    // valueKey is set.
    if (this.valueKey || (valueIsNotObject && (this.keyKey || this.typeKey))) {
      const valueKey = this.valueKey || 'value';
      value = {
        [valueKey]: value
      };
    }
    if (this.keyKey) {
      value[this.keyKey] = this.key;
    }
    if (this.typeKey) {
      value[this.typeKey] = this.selectedType;
    }
    return value;
  }

  setValue(value) {
    if (this.keyKey && value.hasOwnProperty(this.keyKey)) {
      this.key = value[this.keyKey];
      delete value[this.keyKey];
    }
    if (this.typeKey && value.hasOwnProperty(this.typeKey)) {
      this.setType(value[this.typeKey]);
      delete value[this.typeKey];
    }
    if (!this.valueKey && typeof value === 'object' && !Array.isArray(value)) {
      this.child.setValue(value);
    } else {
      this.child.setValue(value[this.valueKey || 'value']);
    }
  }

  setType(type) {
    this.selectedType = type;
  }

  getType() {
    return this.selectedType;
  }

  /**
   * Get all the possible type names.
   * @return {String[]} The names of the possible types.
   */
  get possibleTypes() {
    return Object.keys(this.types);
  }
}
<commit_msg>Improve and comment some Typefield methods<commit_after>import {containerless, bindable} from 'aurelia-framework';
import {Field} from './abstract/field';
import {parseJSON} from '../jsonparser';

/**
 * Typefield is a {@link Field} that shows different child forms depending on
 * the type the user chooses.
 *
 * This allows for theoretically infinite nesting because it uses lazy
 * evaluation and supports $refs in type options.
 */
@containerless
export class Typefield extends Field {
  /**
   * The type that is currently selected.
   * @type {String}
   */
  @bindable selectedType = '';
  /**
   * The key where to put the value of the child field to in the output of this
   * field.
   * @type {String}
   */
  valueKey = '';
  /**
   * The key where to put the key of this field ({@link #key}) in the output of
   * this field.
   * @type {String}
   */
  keyKey = '';
  /**
   * The current key of this field. Exists as a legend field in the form if
   * {@link #keyKey} is defined.
   * @type {String}
   */
  key = '';
  /**
   * The placeholder for the key form field.
   * @type {String}
   */
  keyPlaceholder = '';
  /**
   * The key where to put the type of this field.
   * @type {String}
   */
  typeKey = 'x-oad-type';
  /**
   * Whether or not to copy the value over to the new child when switching types.
   *
   * N.B. Absolutely nothing is done to ensure the data ends up in the right
   * place. Only use this if most of the fields in different types are in nearly
   * the same places.
   * @type {Boolean}
   */
  copyValue = false;
  /**
   * The current child field.
   * @type {Field}
   * @private
   */
  child = undefined;
  /**
   * The schemas for the available types.
   * @type {Object}
   */
  types = {};
  /**
   * Whether or not the UI element should be collapsed (i.e. only show the title)
   * @type {Boolean}
   */
  collapsed = false;
  isCollapsible = true;

  /*
   * Called by child fields when they are collapsed/uncollapsed.
   * Unused in Typefields, currently only used in Arrayfields.
   */
  childCollapseChanged(field, isNowCollapsed) {}

  toggleCollapse() {
    this.setCollapsed(!this.collapsed);
  }

  setCollapsed(collapsed) {
    this.collapsed = collapsed;
    if (this.parent) {
      this.parent.childCollapseChanged(this, this.collapsed);
    }
  }

  /** @inheritdoc */
  init(id = '', args = {}) {
    args = Object.assign({
      valueKey: '',
      typeKey: 'x-oad-type',
      keyKey: '',
      keyPlaceholder: 'Object key...',
      copyValue: false,
      collapsed: false,
      types: { 'null': { 'type': 'text' } }
    }, args);
    this.types = args.types;
    this.valueKey = args.valueKey;
    this.typeKey = args.typeKey;
    this.keyKey = args.keyKey;
    this.keyPlaceholder = args.keyPlaceholder;
    this.copyValue = args.copyValue;
    this.collapsed = args.collapsed;
    this.defaultType = args.defaultType;
    this.selectedType = args.defaultType || Object.keys(this.types)[0];
    this.selectedTypeChanged(this.selectedType);
    return super.init(id, args);
  }

  /**
   * Check if this field doesn't currently have a child or if the child is empty.
   */
  isEmpty() {
    if (!this.child) {
      return true;
    }
    return this.child.isEmpty();
  }

  /**
   * Called by Aurelia when the selected type changes (e.g. from the dropdown)
   * @param {String} newType The new type.
   */
  selectedTypeChanged(newType) {
    const newSchema = this.types[newType];
    const value = this.copyValue ? this.getValue() : undefined;
    let newChild;
    if (newSchema.hasOwnProperty('$ref')) {
      newChild = this.resolveRef(newSchema.$ref).clone();
    } else {
      newChild = parseJSON(newType, JSON.parse(JSON.stringify(newSchema)));
    }
    if (newChild) {
      newChild.parent = this;
      if (value) {
        this.setValue(value);
      }
      this.child = newChild;
    }
    this.onChange();
  }

  /**
   * Get the value of this field.
   *
   * If the value of the child is undefined, this will return undefined.
   *
   * The value of the child will be put into an object with {@link #valueKey} or
   * `value` as the key if the value is not already an object and one of the
   * following fields is defined:
   *   a) {@link #typeKey}
   *   b) {@link #keyKey}
   *   c) {@link #valueKey}
   * If {@link #valueKey} is defined, the child value will be put into an object
   * as described previously regardless of whether or not the child value is an
   * object.
   *
   * If {@link #typeKey} is defined, the name of the selected type will be added
   * to the return object with {@link #typeKey} as its key.
   * If {@link #keyKey} is defined, the return object will contain a field with
   * {@link #keyKey} as its key and the key from the fieldset legend as the value.
   *
   * @return {Object} The processed value.
   */
  getValue() {
    if (!this.child) {
      return undefined;
    }

    let value = this.child.getValue();
    // True if the value of the child is either not an object or is an array.
    // In other words, can/should we put named fields in the value directly?
    const valueIsNotObject = typeof value !== 'object' || Array.isArray(value);
    // If valueKey is set, the value of the child should always be stored in an
    // object with valueKey as the key for the value of the child.
    //
    // If the value is not an object or is an array AND either keyKey or
    // typeKey is set, the above should be done regardless of whether or not
    // valueKey is set.
    if (this.valueKey || (valueIsNotObject && (this.keyKey || this.typeKey))) {
      const valueKey = this.valueKey || 'value';
      value = {
        [valueKey]: value
      };
    }
    if (this.keyKey) {
      value[this.keyKey] = this.key;
    }
    if (this.typeKey) {
      value[this.typeKey] = this.selectedType;
    }
    return value;
  }

  /**
   * Set the value of this field. This reverses anything that{@link #getValue()}
   * does.
   * @param {Object} value The value to set to this field.
   */
  setValue(value) {
    // If the key is available in the given value object, get the key from there
    // and delete the field (from the value object) it was stored in.
    if (this.keyKey && value.hasOwnProperty(this.keyKey)) {
      this.key = value[this.keyKey];
      delete value[this.keyKey];
    }
    // Do the same for the type
    if (this.typeKey && value.hasOwnProperty(this.typeKey)) {
      this.setType(value[this.typeKey]);
      delete value[this.typeKey];
    }
    // Try to reverse getValue() in a reliable way.
    // Currently this looks at whether or not valueKey is set and also the type
    // of the object found with valueKey.
    const valueInValueKey = value[this.valueKey || 'value'];
    const valueIsNotObject = typeof valueInValueKey === 'object' && !Array.isArray(valueInValueKey);
    if (this.valueKey || ((this.typeKey || this.keyKey) && valueIsNotObject)) {
      this.child.setValue(valueInValueKey);
    } else {
      this.child.setValue(value);
    }
  }

  setType(type) {
    this.selectedType = type;
  }

  getType() {
    return this.selectedType;
  }

  /**
   * Get all the possible type names.
   * @return {String[]} The names of the possible types.
   */
  get possibleTypes() {
    return Object.keys(this.types);
  }
}
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var savingsPolicy = require('../policies/savings.server.policy'),
    savings = require('../controllers/savings.server.controller');

module.exports = function (app) {

    app.route('/api/savings/picture')
        .post(savings.changeProductPictureSaving);

    // Savings collection routes
    app.route('/api/savings').all(savingsPolicy.isAllowed)
        .get(savings.list)
        .post(savings.create);

    // Single saving routes
    app.route('/api/savings/:savingId')
        // .all(savingsPolicy.isAllowed)
        .get(savings.read)
        .put(savings.update)
        .delete(savings.delete);

    // Single saving routes
    app.route('/api/savings/app/:appSavingId/:userEmail').all()
        .post(savings.appUpvoteSaving);

    app.route('/savings/savingCount').all()
        .get(savings.countSavings);

    app.route('/savings/savingCountToday').all()
        .get(savings.countSavingsToday);

    //app.route('/savings/usersSavingsPostedTotal').all()
    //    .get(savings.usersSavingsPostedTotal);

    app.route('/api/savings/of/:userid')
        .get(savings.listOf);

    app.route('/api/savings/of/:username')
        .get(savings.listOf);

    app.route('/savings/usersSavingsPostedTotal/:userIdString')
        .get(savings.usersSavingsPostedTotal);

    app.route('/savings/usersUpvotesTotal/:userIdString')
        .get(savings.usersUpvotesTotal);

    app.route('/savings/removeVotesDaily')
        .get(savings.removeVotesDaily);

    // Finish by binding the saving middleware
    app.param('savingId', savings.savingByID);
    app.param('userid', savings.listOf);
    app.param('userIdString', savings.usersSavingsPostedTotal);
    app.param('userIdString', savings.usersUpvotesTotal);
    app.param('appSavingId', savings.appUpvoteSaving);
    app.param('userEmail', savings.appUpvoteSaving);

};
<commit_msg>Minified JS.<commit_after>'use strict';

/**
 * Module dependencies.
 */
var savingsPolicy = require('../policies/savings.server.policy'),
    savings = require('../controllers/savings.server.controller');

module.exports = function (app) {

    app.route('/api/savings/picture')
        .post(savings.changeProductPictureSaving);

    // Savings collection routes
    app.route('/api/savings').all(savingsPolicy.isAllowed)
        .get(savings.list)
        .post(savings.create);

    // Single saving routes
    app.route('/api/savings/:savingId')
        .all(savingsPolicy.isAllowed)
        .get(savings.read)
        .put(savings.update)
        .delete(savings.delete);

    // Single saving routes
    app.route('/api/savings/app/:appSavingId/:userEmail').all()
        .post(savings.appUpvoteSaving);

    app.route('/savings/savingCount').all()
        .get(savings.countSavings);

    app.route('/savings/savingCountToday').all()
        .get(savings.countSavingsToday);

    //app.route('/savings/usersSavingsPostedTotal').all()
    //    .get(savings.usersSavingsPostedTotal);

    app.route('/api/savings/of/:userid')
        .get(savings.listOf);

    app.route('/api/savings/of/:username')
        .get(savings.listOf);

    app.route('/savings/usersSavingsPostedTotal/:userIdString')
        .get(savings.usersSavingsPostedTotal);

    app.route('/savings/usersUpvotesTotal/:userIdString')
        .get(savings.usersUpvotesTotal);

    app.route('/savings/removeVotesDaily')
        .get(savings.removeVotesDaily);

    // Finish by binding the saving middleware
    app.param('savingId', savings.savingByID);
    app.param('userid', savings.listOf);
    app.param('userIdString', savings.usersSavingsPostedTotal);
    app.param('userIdString', savings.usersUpvotesTotal);
    app.param('appSavingId', savings.appUpvoteSaving);
    app.param('userEmail', savings.appUpvoteSaving);

};
<|endoftext|>


<commit_before>$(window).on('load', function() {
    /** Define dom shorthands for key html elements */
    var dom = {
        intface: $("#interface"),
        loadSpinner: $("#loading-spinner"),
        animationInput: $("input#animation"),
        animationDisplay: $("#animation-display"),
        positionInput: $("input#position"),
        positionDisplay: $("#position-display"),
        },
        /** Create initial layout of plotly plot */
        plt = {
            MaxTraceNo: 12,
            layout: {
                autosize: true,
                  legend: {
                    x: 0,
                      y: 1
                },
                margin: {
                    l: 0, r: 0, b: 0, t: 1, pad: 5
                },
                scene: {
                    aspectmode: "cube",
                    xaxis: {
                        range: [-1, 1], autorange: false, zeroline: true, showspikes: false,dtick: 0.5,
                    },
                    yaxis: {
                        range: [-1, 1], autorange: false, zeroline: true, showspikes: false,dtick: 0.5,
                    },
                    zaxis: {
                        range: [-0.5, 1.5], autorange: false, zeroline: true, showspikes: false,dtick: 0.5,
                    }
                },
                hovermode: false,
                font: {
                    family: "Fira Sans",
                    size: 14
                }
            },
        },
        /** Phys is a ish-class that stores and updates the js animation position and data variables */
        phys = {
            animation: 1,
            position: 0,
            data: [],
            setAnimation: function(anim) {
                this.animation = anim;
            },
            setPosition: function(pos) {
                this.position = pos;
            },
            getPlotData: function() {
                return this.data.Position[this.position].Animation[this.animation];
            },
        };

    /** import JSON and define an onload function  */
    $.when(
        $.getJSON("https://rawgit.com/cydcowley/public-test-data/master/BiotData.json"),
    ).then(function(data) { // i.e., function(JSON1, JSON2) {// success}, function() {// error}
        data = JSON.parse(data);
        init(data);
    }, showJSONLoadError);

    //define function to plot the initial static graph
    function init(data) {
        phys.data = data;
        endLoadingScreen();
        traces = [];
        linewidth = 5;
        colors = ["#1A40B1","#E47F1A","#2E9849","#D81C1C"]

        traces.push({type: "scatter3d",mode: "lines",name: "dI", line: {width: linewidth,color:colors[0]},x: deepCopy(phys.getPlotData())[0].x,
            y:deepCopy(phys.getPlotData())[0].y,z:deepCopy(phys.getPlotData())[0].z,})
        traces.push({type: "scatter3d",mode: "lines",name: "dB", line: {width: linewidth,color:colors[1]},x: deepCopy(phys.getPlotData())[1].x,
            y:deepCopy(phys.getPlotData())[1].y,z:deepCopy(phys.getPlotData())[1].z})
        traces.push({type: "scatter3d",mode: "lines",name: "r", line: {width: linewidth,color:colors[2]},x: deepCopy(phys.getPlotData())[2].x,
            y:deepCopy(phys.getPlotData())[2].y,z:deepCopy(phys.getPlotData())[2].z})
        traces.push({type: "scatter3d",mode: "lines",name: "B", line: {width: linewidth,color: colors[3]},x: deepCopy(phys.getPlotData())[3].x,
            y:deepCopy(phys.getPlotData())[3].y,z:deepCopy(phys.getPlotData())[3].z})
        traces.push({type: "scatter3d",mode: "lines",name: "Circle", line: {width: 10},x: deepCopy(phys.getPlotData())[4].x,
            y:deepCopy(phys.getPlotData())[4].y,z:deepCopy(phys.getPlotData())[4].z})

        //Create arrowheads for each necessary trace
        for (let i = 0; i < 4; i++) {
            [x,y,z,u,v,w] = make_arrows(deepCopy(phys.getPlotData())[i].x,deepCopy(phys.getPlotData())[i].y,deepCopy(phys.getPlotData())[i].z)
            traces.push({type: "cone",colorscale: [[0, colors[i]], [1, colors[i]]],x:[x],y:[y],z:[z],u:[u],v:[v],w:[w],sizemode: "absolute",sizeref :0.125,showscale: false})
        }
        Plotly.plot(div='graph', traces, layout=plt.layout);
        dom.animationInput.on("input", handleAnimationSlider);
        dom.positionInput.on("input", handlePositionSlider);
    }

    function make_arrows(pointsx,pointsy,pointsz){
        /** Returns an arrowhead based on an inputed line */
        var x = pointsx[1],
            y = pointsy[1],
            z = pointsz[[1]],
            u = 0.5*(pointsx[1]-pointsx[0]),
            v = 0.5*(pointsy[1]-pointsy[0]),
            w =0.5*(pointsz[1]-pointsz[0]);
        return[x,y,z,u,v,w]
    }

    function handlePositionSlider() {
        /** Updates plotly plot with new position */
        phys.setPosition(
            input2index($(this), phys.data.Position)
        );
        updatePlot();
        dom.positionDisplay.html(
            roundInput($(this), phys.data.Position)
        );
    }

    function handleAnimationSlider() {
        /** Updates plotly plot with new animation frame*/
        phys.setAnimation(
            input2index($(this), phys.data.Position[phys.position].Animation)
        );
        updatePlot();
        dom.animationDisplay.text(
            roundInput($(this), phys.data.Position[phys.position].Animation));
    }

    function endLoadingScreen() {
        dom.loadSpinner.fadeOut(0);
    }

    function input2index(domInput, array) {
        /** Compute the corresponding JSON array index for a given input value, rounding to the nearest integer */
        var inputValue = domInput.val(),
            maxInput = parseFloat(domInput.attr("max")),
            minInput = parseFloat(domInput.attr("min")),
            arrayLen = array.length;
        return Math.round(((inputValue - minInput) / (maxInput - minInput)) * (arrayLen - 1));
    }
    function roundInput(domInput, array) {
        /** Round a given input value to the actual value in the array. Returns a string */
        var inputValue = domInput.val(),
            maxInput = parseFloat(domInput.attr("max")),
            minInput = parseFloat(domInput.attr("min")),
            arrayLen = array.length;
        return (minInput + ((maxInput - minInput) / (arrayLen - 1)) * input2index(domInput, array)).toFixed(1);
    }

    function updatePlot() {
        var update = {},
            plotData = phys.getPlotData();
        for (let i = 0; i <4 ; i++) {
            update[i] = {
                x: plotData[i].x,
                y: plotData[i].y,
                z: plotData[i].z,
            };
            for (let j = 5; j <9; j++) {
                var [x,y,z,u,v,w]=make_arrows(plotData[j-5].x,plotData[j-5].y,plotData[j-5].z)
                update[j]={
                    x: [x], y: [y], z: [z],
                u: [u], v: [v], w: [w],
                }
            }
        }
        Plotly.animate(div="graph", {
            data: getObjValues(update),
            traces: getObjKeysAsInts(update),
            layout: {}
        }, {
            transition: {duration: 0},
            frame: {duration: 0, redraw: false}
        });
    }

    function showJSONLoadError() {
        dom.loadSpinner.children(".spinner-span").html("Error: Failed to load JSON resources");
        dom.loadSpinner.children("div").fadeOut(0);
    }

    function getObjKeys(obj) {
        return Object.keys(obj);
    }
    function getObjKeysAsInts(obj) {
        return Object.keys(obj).map(Number);
    }
    function getObjValues(obj) {
        return Object.keys(obj).map(function(key) {
            return obj[key];
        });
    }

    function deepCopy(obj) {
        return JSON.parse(JSON.stringify(obj));
    }

});
<commit_msg>Biot savart edit<commit_after>$(window).on('load', function() {
    /** Define dom shorthands for key html elements */
    var dom = {
        intface: $("#interface"),
        loadSpinner: $("#loading-spinner"),
        animationInput: $("input#animation"),
        animationDisplay: $("#animation-display"),
        positionInput: $("input#position"),
        positionDisplay: $("#position-display"),
        },
        /** Create initial layout of plotly plot */
        plt = {
            MaxTraceNo: 12,
            layout: {
                autosize: true,
                 showlegend: false,
                margin: {
                    l: 0, r: 0, b: 0, t: 1, pad: 5
                },
                scene: {
                    aspectmode: "cube",
                    camera:{eye:{x:-1.25,},},
                    xaxis: {
                        range: [-1, 1], autorange: false, zeroline: true, showspikes: false,dtick: 0.5,
                    },
                    yaxis: {
                        range: [-1, 1], autorange: false, zeroline: true, showspikes: false,dtick: 0.5,
                    },
                    zaxis: {
                        range: [-0.5, 1.5], autorange: false, zeroline: true, showspikes: false,dtick: 0.5,
                    }
                },
                hovermode: false,
                font: {
                    family: "Fira Sans",
                    size: 14
                }
            },
        },
        /** Phys is a ish-class that stores and updates the js animation position and data variables */
        phys = {
            animation: 1,
            position: 0,
            data: [],
            setAnimation: function(anim) {
                this.animation = anim;
            },
            setPosition: function(pos) {
                this.position = pos;
            },
            getPlotData: function() {
                return this.data.Position[this.position].Animation[this.animation];
            },
        };

    /** import JSON and define an onload function  */
    $.when(
        $.getJSON("https://rawgit.com/cydcowley/public-test-data/master/BiotData.json"),
    ).then(function(data) { // i.e., function(JSON1, JSON2) {// success}, function() {// error}
        data = JSON.parse(data);
        init(data);
    }, showJSONLoadError);

    //define function to plot the initial static graph
    function init(data) {
        phys.data = data;
        endLoadingScreen();
        traces = [];
        linewidth = 5;
        colors = ["#1A40B1","#E47F1A","#2E9849","#D81C1C"]

        traces.push({type: "scatter3d",mode: "lines",name: "dI", line: {width: linewidth,color:colors[0]},x: deepCopy(phys.getPlotData())[0].x,
            y:deepCopy(phys.getPlotData())[0].y,z:deepCopy(phys.getPlotData())[0].z,})
        traces.push({type: "scatter3d",mode: "lines",name: "dB", line: {width: linewidth,color:colors[1]},x: deepCopy(phys.getPlotData())[1].x,
            y:deepCopy(phys.getPlotData())[1].y,z:deepCopy(phys.getPlotData())[1].z})
        traces.push({type: "scatter3d",mode: "lines",name: "r", line: {width: linewidth,color:colors[2]},x: deepCopy(phys.getPlotData())[2].x,
            y:deepCopy(phys.getPlotData())[2].y,z:deepCopy(phys.getPlotData())[2].z})
        traces.push({type: "scatter3d",mode: "lines",name: "B", line: {width: linewidth,color: colors[3]},x: deepCopy(phys.getPlotData())[3].x,
            y:deepCopy(phys.getPlotData())[3].y,z:deepCopy(phys.getPlotData())[3].z})
        traces.push({type: "scatter3d",mode: "lines",name: "Circle", line: {width: 10},x: deepCopy(phys.getPlotData())[4].x,
            y:deepCopy(phys.getPlotData())[4].y,z:deepCopy(phys.getPlotData())[4].z})

        //Create arrowheads for each necessary trace
        for (let i = 0; i < 4; i++) {
            [x,y,z,u,v,w] = make_arrows(deepCopy(phys.getPlotData())[i].x,deepCopy(phys.getPlotData())[i].y,deepCopy(phys.getPlotData())[i].z)
            traces.push({type: "cone",colorscale: [[0, colors[i]], [1, colors[i]]],x:[x],y:[y],z:[z],u:[u],v:[v],w:[w],sizemode: "absolute",sizeref :0.125,showscale: false})
        }
        Plotly.plot(div='graph', traces, layout=plt.layout);
        dom.animationInput.on("input", handleAnimationSlider);
        dom.positionInput.on("input", handlePositionSlider);
    }

    function make_arrows(pointsx,pointsy,pointsz){
        /** Returns an arrowhead based on an inputed line */
        var x = pointsx[1],
            y = pointsy[1],
            z = pointsz[[1]],
            u = 0.5*(pointsx[1]-pointsx[0]),
            v = 0.5*(pointsy[1]-pointsy[0]),
            w =0.5*(pointsz[1]-pointsz[0]);
        return[x,y,z,u,v,w]
    }

    function handlePositionSlider() {
        /** Updates plotly plot with new position */
        phys.setPosition(
            input2index($(this), phys.data.Position)
        );
        updatePlot();
        dom.positionDisplay.html(
            roundInput($(this), phys.data.Position)
        );
    }

    function handleAnimationSlider() {
        /** Updates plotly plot with new animation frame*/
        phys.setAnimation(
            input2index($(this), phys.data.Position[phys.position].Animation)
        );
        updatePlot();
        dom.animationDisplay.text(
            roundInput($(this), phys.data.Position[phys.position].Animation));
    }

    function endLoadingScreen() {
        dom.loadSpinner.fadeOut(0);
    }

    function input2index(domInput, array) {
        /** Compute the corresponding JSON array index for a given input value, rounding to the nearest integer */
        var inputValue = domInput.val(),
            maxInput = parseFloat(domInput.attr("max")),
            minInput = parseFloat(domInput.attr("min")),
            arrayLen = array.length;
        return Math.round(((inputValue - minInput) / (maxInput - minInput)) * (arrayLen - 1));
    }
    function roundInput(domInput, array) {
        /** Round a given input value to the actual value in the array. Returns a string */
        var inputValue = domInput.val(),
            maxInput = parseFloat(domInput.attr("max")),
            minInput = parseFloat(domInput.attr("min")),
            arrayLen = array.length;
        return (minInput + ((maxInput - minInput) / (arrayLen - 1)) * input2index(domInput, array)).toFixed(1);
    }

    function updatePlot() {
        var update = {},
            plotData = phys.getPlotData();
        for (let i = 0; i <4 ; i++) {
            update[i] = {
                x: plotData[i].x,
                y: plotData[i].y,
                z: plotData[i].z,
            };
            for (let j = 5; j <9; j++) {
                var [x,y,z,u,v,w]=make_arrows(plotData[j-5].x,plotData[j-5].y,plotData[j-5].z)
                update[j]={
                    x: [x], y: [y], z: [z],
                u: [u], v: [v], w: [w],
                }
            }
        }
        Plotly.animate(div="graph", {
            data: getObjValues(update),
            traces: getObjKeysAsInts(update),
            layout: {}
        }, {
            transition: {duration: 0},
            frame: {duration: 0, redraw: false}
        });
    }

    function showJSONLoadError() {
        dom.loadSpinner.children(".spinner-span").html("Error: Failed to load JSON resources");
        dom.loadSpinner.children("div").fadeOut(0);
    }

    function getObjKeys(obj) {
        return Object.keys(obj);
    }
    function getObjKeysAsInts(obj) {
        return Object.keys(obj).map(Number);
    }
    function getObjValues(obj) {
        return Object.keys(obj).map(function(key) {
            return obj[key];
        });
    }

    function deepCopy(obj) {
        return JSON.parse(JSON.stringify(obj));
    }

});
<|endoftext|>


<commit_before>#!/usr/bin/env node
var path = require('path');

var express = require('express');

var config = require('./config');

main();

function main() {
    var port = config.port;

    var app = express();

    app.configure(function() {
        var halfDay = 43200000;

        app.set('port', port);

        app.use(express.favicon(path.join(__dirname, 'public/images/favicon.ico')));
        app.use(express.logger('dev'));
        app.use(express.compress());
        app.use(express['static'](path.join(__dirname, 'public'), {
            maxAge: halfDay
        }));

        app.use(app.router);
    });

    app.configure('development', function() {
        app.use(express.errorHandler());
    });

    app.listen(port, function() {
        console.log('%s: Node (version: %s) %s started on %d ...', Date(Date.now() ), process.version, process.argv[1], port);

        init(app);
    });

    process.on('exit', terminator);

    ['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT', 'SIGBUS',
    'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGPIPE', 'SIGTERM'
    ].forEach(function(element) {
        process.on(element, function() { terminator(element); });
    });
}

function init(app) {
    var apiPrefix = 'v1';

    var api = require('./api');
    var routes = require('./routes');

    app.get('/', routes('index'));
    app.get('/about', routes('about'));
    app.get('/resources', routes('resources'));
    app.get('/resources/how-cdns-work', routes('howCdnsWork'));
    app.get('/resources/how-to-use-cdns', routes('howToUseCdns'));
    app.get('/api', routes('api'));

    app.get('/api/' + apiPrefix + '/cdns', api.cdns.getNames);
    app.get('/api/' + apiPrefix + '/cdns/:name', api.cdns.get);

    require('taskist')(config.tasks, require('./tasks'), {
        instant: function(err) {
            if(err) {
                return console.error(err);
            }

            console.log('Tasks initialized!');

            api.cdns.updateData(require('./public/data'));
        }
    });

}

function terminator(sig) {
    if(typeof sig === 'string') {
        console.log('%s: Received %s - terminating Node server ...',
            Date(Date.now()), sig);

        process.exit(1);
    }

    console.log('%s: Node server stopped.', Date(Date.now()) );
}
<commit_msg>Give a trace in case of error<commit_after>#!/usr/bin/env node
var path = require('path');

var express = require('express');

var config = require('./config');

main();

function main() {
    var port = config.port;

    var app = express();

    app.configure(function() {
        var halfDay = 43200000;

        app.set('port', port);

        app.use(express.favicon(path.join(__dirname, 'public/images/favicon.ico')));
        app.use(express.logger('dev'));
        app.use(express.compress());
        app.use(express['static'](path.join(__dirname, 'public'), {
            maxAge: halfDay
        }));

        app.use(app.router);
    });

    app.configure('development', function() {
        app.use(express.errorHandler());
    });

    app.listen(port, function() {
        console.log('%s: Node (version: %s) %s started on %d ...', Date(Date.now() ), process.version, process.argv[1], port);

        init(app);
    });

    process.on('exit', terminator);

    ['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT', 'SIGBUS',
    'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGPIPE', 'SIGTERM'
    ].forEach(function(element) {
        process.on(element, function() { terminator(element); });
    });
}

function init(app) {
    var apiPrefix = 'v1';

    var api = require('./api');
    var routes = require('./routes');

    app.get('/', routes('index'));
    app.get('/about', routes('about'));
    app.get('/resources', routes('resources'));
    app.get('/resources/how-cdns-work', routes('howCdnsWork'));
    app.get('/resources/how-to-use-cdns', routes('howToUseCdns'));
    app.get('/api', routes('api'));

    app.get('/api/' + apiPrefix + '/cdns', api.cdns.getNames);
    app.get('/api/' + apiPrefix + '/cdns/:name', api.cdns.get);

    require('taskist')(config.tasks, require('./tasks'), {
        instant: function(err) {
            if(err) {
                console.trace();

                return console.error(err);
            }

            console.log('Tasks initialized!');

            api.cdns.updateData(require('./public/data'));
        }
    });

}

function terminator(sig) {
    if(typeof sig === 'string') {
        console.log('%s: Received %s - terminating Node server ...',
            Date(Date.now()), sig);

        process.exit(1);
    }

    console.log('%s: Node server stopped.', Date(Date.now()) );
}
<|endoftext|>


<commit_before>Ext.define('Ozone.components.admin.StackExportWindow', {
    extend: 'Ext.window.Window',
    alias: ['widget.stackexportwindow', 'widget.StackExportWindow'],

    mixins: {
        widget: 'Ozone.components.focusable.CircularFocus'
    },

    title: 'Export',
    itemId: 'stackexportwindow',
    modal: true,
    closable: true,
    draggable: false,
    resizable: false,
    closeAction: 'hide',
    border: false,
    minWidth: 250,
    minHeight: 200,
    layout: {
        type: 'vbox',
        align: 'stretch'
    },
    items: [{
        xtype: 'panel',
        itemId: 'stackexportpanel',
        cls: 'admineditoraddpanel',
        layout: 'fit',
        border: false,
        flex: 1,
        items: [{
            xtype: 'form',
            itemId: 'form',
            layout: 'anchor',
            bodyCls: 'properties-body',
            border: false,
            preventHeader: true,
            padding: 5,
            autoScroll: true,
            defaults: {
                anchor: '100%',
                msgTarget: 'side',
                labelSeparator: '',
                margin: '5 5 0 5'
            },
            items: [{
                xtype: 'textfield',
                itemId: 'filename',
                fieldLabel: 'Filename',
                labelWidth: 140,
                allowBlank: true,
                name: 'filename',
                maxLength: 200,
                regex: /^[a-zA-Z\d\-\_]+$/,
                regexText: 'Invalid characters! The Filename may only contain letters, numbers, dashes, and underscores.'
            }, {
                xtype: 'radiogroup',
                itemId: 'extension',
                fieldLabel: 'File Type',
                labelWidth: 140,
                columns: [100, 100],
                vertical: true,
                items: [
                    {
                        boxLabel: '.war',
                        name: 'val',
                        inputValue: 'war',
                        checked: true
                    }, {
                        boxLabel: '.zip',
                        name: 'val',
                        inputValue: 'zip'
                    }
                ]
            }]
        }]
    }],
    buttons: [{
        text: 'OK',
        itemId: 'ok'
    }, {
        text: 'Cancel',
        itemId: 'cancel'
    }],

    initComponent: function() {
        var me = this;

        var vpSize = Ext.getBody().getViewSize();
        me.setWidth(Math.round(vpSize.width * .9));
        me.setHeight(Math.round(vpSize.height * .5));

        me.on('beforeshow', function() {
            me.setTitle(me.generateTitle());
        });

        me.on('afterrender', function() {

            var form = me.down('#form');
            var filename = me.down('#filename');
            var extension = me.down('#extension');
            var okBtn = me.down('#ok');
            var cancelBtn = me.down('#cancel');

            form.on('fieldvaliditychange', function(form, t, isValid, eOpts) {
                if (isValid) {
                    okBtn.enable();
                } else {
                    okBtn.disable();
                }
            });

            cancelBtn.on('click', function(btn, e) {
                me.close();
            });

            okBtn.on('click', function(btn, e) {
                if(me.okFn) {
                    var extn = extension.getValue();
                    me.okFn(filename.value, extn.val);
                }
                me.close();
            });

            me.setupFocus(filename.getFocusEl(), cancelBtn.getFocusEl());
        });

        me.on('beforeclose', function() {
            me.down('#form').clearListeners();
            me.down('#ok').clearListeners();
            me.down('#cancel').clearListeners();
            me.focusOnClose && me.focusOnClose.focus();
        });

        me.callParent(arguments);
    },

    generateTitle: function() {
        var title = "Export";
        if (this.itemName) { title = "Export " + this.itemName; }

        //Set a character limit to start at and truncate the title to it if necessary
        var charLimit = 100;
        title = Ext.util.Format.ellipsis(title, charLimit);

        //Get the size of the parent container
        var vpSize = Ext.getBody().getViewSize();

        //Use TextMetrics to get the pixel width of the title
        var textMetrics = new Ext.util.TextMetrics();
        var titleWidth = textMetrics.getWidth(title);

        //If the title's pixel width is too large for the window, decrease it
        //by 5 characters until its pixel width fits
        while(titleWidth > ((vpSize.width * .8))) {
            charLimit -= 5;
            title = Ext.util.Format.ellipsis(title, charLimit);
            titleWidth = textMetrics.getWidth(title);
        }

        textMetrics.destroy();

        return Ext.htmlEncode(title);
    }
});<commit_msg>OWF-6938: Create option to export to war or zip.<commit_after>Ext.define('Ozone.components.admin.StackExportWindow', {
    extend: 'Ext.window.Window',
    alias: ['widget.stackexportwindow', 'widget.StackExportWindow'],

    mixins: {
        widget: 'Ozone.components.focusable.CircularFocus'
    },

    title: 'Export',
    itemId: 'stackexportwindow',
    modal: true,
    closable: true,
    draggable: false,
    resizable: false,
    closeAction: 'hide',
    border: false,
    minWidth: 250,
    minHeight: 200,
    layout: {
        type: 'vbox',
        align: 'stretch'
    },
    items: [{
        xtype: 'panel',
        itemId: 'stackexportpanel',
        cls: 'admineditoraddpanel',
        layout: 'fit',
        border: false,
        flex: 1,
        items: [{
            xtype: 'form',
            itemId: 'form',
            layout: 'anchor',
            bodyCls: 'properties-body',
            border: false,
            preventHeader: true,
            padding: 5,
            autoScroll: true,
            defaults: {
                anchor: '100%',
                msgTarget: 'side',
                labelSeparator: '',
                margin: '5 5 0 5'
            },
            items: [{
                xtype: 'textfield',
                itemId: 'filename',
                fieldLabel: 'Filename',
                labelWidth: 140,
                allowBlank: false,
                name: 'filename',
                maxLength: 200,
                regex: /^[a-zA-Z\d\-\_]+$/,
                regexText: 'Invalid characters! The Filename may only contain letters, numbers, dashes, and underscores.'
            }, {
                xtype: 'radiogroup',
                itemId: 'extension',
                fieldLabel: 'File Type',
                labelWidth: 140,
                columns: [100, 100],
                vertical: true,
                items: [
                    {
                        boxLabel: '.war',
                        name: 'val',
                        inputValue: 'war',
                        checked: true
                    }, {
                        boxLabel: '.zip',
                        name: 'val',
                        inputValue: 'zip'
                    }
                ]
            }]
        }]
    }],
    buttons: [{
        text: 'OK',
        itemId: 'ok',
        disabled: true
    }, {
        text: 'Cancel',
        itemId: 'cancel'
    }],

    initComponent: function() {
        var me = this;

        var vpSize = Ext.getBody().getViewSize();
        me.setWidth(Math.round(vpSize.width * .9));
        me.setHeight(Math.round(vpSize.height * .5));

        me.on('beforeshow', function() {
            me.setTitle(me.generateTitle());
        });

        me.on('afterrender', function() {

            var form = me.down('#form');
            var filename = me.down('#filename');
            var extension = me.down('#extension');
            var okBtn = me.down('#ok');
            var cancelBtn = me.down('#cancel');

            form.on('fieldvaliditychange', function(form, t, isValid, eOpts) {
                if (isValid) {
                    okBtn.enable();
                } else {
                    okBtn.disable();
                }
            });

            cancelBtn.on('click', function(btn, e) {
                me.close();
            });

            okBtn.on('click', function(btn, e) {
                if(me.okFn) {
                    var extn = extension.getValue();
                    me.okFn(filename.value, extn.val);
                }
                me.close();
            });

            me.setupFocus(filename.getFocusEl(), cancelBtn.getFocusEl());
        });

        me.on('beforeclose', function() {
            me.down('#form').clearListeners();
            me.down('#ok').clearListeners();
            me.down('#cancel').clearListeners();
            me.focusOnClose && me.focusOnClose.focus();
        });

        me.callParent(arguments);
    },

    generateTitle: function() {
        var title = "Export";
        if (this.itemName) { title = "Export " + this.itemName; }

        //Set a character limit to start at and truncate the title to it if necessary
        var charLimit = 100;
        title = Ext.util.Format.ellipsis(title, charLimit);

        //Get the size of the parent container
        var vpSize = Ext.getBody().getViewSize();

        //Use TextMetrics to get the pixel width of the title
        var textMetrics = new Ext.util.TextMetrics();
        var titleWidth = textMetrics.getWidth(title);

        //If the title's pixel width is too large for the window, decrease it
        //by 5 characters until its pixel width fits
        while(titleWidth > ((vpSize.width * .8))) {
            charLimit -= 5;
            title = Ext.util.Format.ellipsis(title, charLimit);
            titleWidth = textMetrics.getWidth(title);
        }

        textMetrics.destroy();

        return Ext.htmlEncode(title);
    }
});<|endoftext|>


<commit_before>function (doc) {
    // !code util/mvp.js
    if (isChildCase(doc)) {
        var indicator_entries_open = {},
            indicator_entries_closed = {},
            indicator_entries_dob = {};

        var status = (doc.closed) ? "closed" : "open";

        if (doc.dob || doc.dob_calc) {
            var dob_date = doc.dob_calc || doc.dob,
                weight_at_birth = doc.weight_at_birth,
                is_delivered = doc.delivered_in_facility === 'yes' || doc.delivered_in_facility === 'no',
                is_delivered_in_facility = doc.delivered_in_facility === 'yes',
                opened_on_date = new Date(doc.opened_on);

            if (is_delivered) {
                indicator_entries_dob["dob delivered"] = dob_date;
            }
            if (is_delivered_in_facility) {
                indicator_entries_dob["dob delivered_in_facility"] = dob_date;
            }

            indicator_entries_open["opened_on"] = dob_date;
            indicator_entries_open["opened_on "+status] = dob_date;
            if (weight_at_birth) {
                try {
                    var weight = parseFloat(weight_at_birth);
                    if (weight < 2.5) {
                        indicator_entries_open["opened_on low_birth_weight"] = dob_date;
                    }
                } catch (e) {
                    // pass
                }
            }
            emit_special(doc, opened_on_date, indicator_entries_open, [doc._id]);
            emit_special(doc, dob_date, indicator_entries_dob, [doc._id]);

            if (doc.closed_on) {
                var closed_on_date = new Date(doc.closed_on);
                indicator_entries_closed["closed_on"] = dob_date;
                indicator_entries_closed["closed_on "+status] = dob_date;
                emit_special(doc, closed_on_date, indicator_entries_closed, [doc._id]);
            }
        }
    }
}
<commit_msg>actually emit a date<commit_after>function (doc) {
    // !code util/mvp.js
    if (isChildCase(doc)) {
        var indicator_entries_open = {},
            indicator_entries_closed = {},
            indicators_dob = [];

        var status = (doc.closed) ? "closed" : "open";

        if (doc.dob || doc.dob_calc) {
            var dob_date = doc.dob_calc || doc.dob,
                weight_at_birth = doc.weight_at_birth,
                is_delivered = doc.delivered_in_facility === 'yes' || doc.delivered_in_facility === 'no',
                is_delivered_in_facility = doc.delivered_in_facility === 'yes',
                opened_on_date = new Date(doc.opened_on);

            if (is_delivered) {
                indicators_dob.push("dob delivered");
            }
            if (is_delivered_in_facility) {
                indicators_dob.push("dob delivered_in_facility");
            }

            try {
                emit_standard(doc, new Date(dob_date), indicators_dob, [doc._id]);
            } catch (e) {
                // just in case the date parsing fails miserably.
            }

            indicator_entries_open["opened_on"] = dob_date;
            indicator_entries_open["opened_on "+status] = dob_date;
            if (weight_at_birth) {
                try {
                    var weight = parseFloat(weight_at_birth);
                    if (weight < 2.5) {
                        indicator_entries_open["opened_on low_birth_weight"] = dob_date;
                    }
                } catch (e) {
                    // pass
                }
            }
            emit_special(doc, opened_on_date, indicator_entries_open, [doc._id]);

            if (doc.closed_on) {
                var closed_on_date = new Date(doc.closed_on);
                indicator_entries_closed["closed_on"] = dob_date;
                indicator_entries_closed["closed_on "+status] = dob_date;
                emit_special(doc, closed_on_date, indicator_entries_closed, [doc._id]);
            }
        }
    }
}
<|endoftext|>


<commit_before>import selectorParser from "postcss-selector-parser"
import {
  report,
  ruleMessages,
  validateOptions,
} from "../../utils"

export const ruleName = "selector-no-type"

export const messages = ruleMessages(ruleName, {
  rejected: "Unexpected type selector",
})

export default function (actual) {
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, { actual })
    if (!validOptions) { return }
    // 1st for nesting, 2nd to 4th for nth-child, and last two for keyframes
    const exclusions = ["&", "n", "even", "odd", "to", "from"]
    root.walkRules(rule => {
      selectorParser(selectorAST => {
        selectorAST.eachTag(tag => {
          const firstChar = tag.value.charAt(0)
          // Check if in exclusions
          if (exclusions.indexOf(tag.value) !== -1) { return }
          // Also check if starts with a digit, for nth-child(3n) and %s in keyframes
          if (!isNaN(firstChar)) { return }
          // Lastly check for "-", for nth-child(-n)
          if (firstChar === "-") { return }
          report({
            message: messages.rejected,
            node: rule,
            index: tag.sourceIndex,
            ruleName,
            result,
          })
        })
      })
        .process(rule.selector)
    })
  }
}
<commit_msg>Cleanup selector-no-type exclusions<commit_after>import selectorParser from "postcss-selector-parser"
import {
  report,
  ruleMessages,
  validateOptions,
} from "../../utils"

export const ruleName = "selector-no-type"

export const messages = ruleMessages(ruleName, {
  rejected: "Unexpected type selector",
})

export default function (actual) {
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, { actual })
    if (!validOptions) { return }

    root.walkRules(rule => {
      // Ignore keyframe selectors
      if (rule.parent.type === "atrule" && rule.parent.name === "keyframes") {
        return
      }

      selectorParser(selectorAST => {
        selectorAST.eachTag(tag => {
          // postcss-selector-parser includes the arguments to nth-child() functions
          // as "tags", so we need to ignore them ourselves.
          // The fake-tag's "parent" is actually a selector node, whose parent
          // should be the :nth-child pseudo node.
          if (tag.parent.parent.type === "pseudo" && tag.parent.parent.value === ":nth-child") {
            return
          }

          // & is not a type selector: it's used for nesting
          if (tag.value === "&") { return }

          report({
            message: messages.rejected,
            node: rule,
            index: tag.sourceIndex,
            ruleName,
            result,
          })
        })
      })
        .process(rule.selector)
    })
  }
}
<|endoftext|>


<commit_before>/**
 * Copy folders and files from source to destination.
 * Get parameters from userProperties,
 * Loop until time runs out,
 * then call timeout methods, saveProperties and createTrigger.
 *
 * @param {boolean} resuming whether or not the copy call is resuming an existing folder copy or starting fresh
 */
function copy() {
    // CONSTANTS
    var MAX_RUNNING_TIME = 4.7 * 60000; // return millisecs
    var START_TIME = (new Date()).getTime();

    var timeIsUp,       // {boolean} true if max execution time is reached while executing script
        currTime,       // {number} integer representing current time in milliseconds
        ss,             // {object} instance of Sheet class
        //properties is a global object now, stored in the file propertiesObject
        query,          // {string} query to generate Files list
        files,          // {object} list of files within Drive folder
        item,           // {object} metadata of child item from current iteration
        currFolder,     // {object} metadata of folder whose children are currently being processed
        newfile,        // {Object} JSON metadata for newly created folder or file
        timeZone,       // {string} time zone of user
        stop,           // {boolean} true if the user has clicked the 'stop' button
        userProperties = PropertiesService.getUserProperties(), // reference to userProperties store
        triggerId = userProperties.getProperties().triggerId;      // {string} Unique ID for the most recently created trigger

    stop = userProperties.getProperties().stop == 'true';

    /*****************************
     * deleteAllTriggers()
     *  - get rid of all triggers that exist from previous runs, or anything else
     */

    /*****************************
     * createTrigger()
     *
     */

    /*****************************
     * Load properties
     */
    try {
        // Load properties and initialize logger spreadsheet
        properties = exponentialBackoff(loadProperties, 'Error restarting script, will retry in 1-2 minutes');

    } catch (err) {

        var n = Number(userProperties.getProperties().trials);
        Logger.log(n);

        if (n < 5) {
            Logger.log('setting trials property');
            userProperties.setProperty('trials', (n + 1).toString());

            exponentialBackoff(createTrigger,
                'Error setting trigger.  There has been a server error with Google Apps Script.' +
                'To successfully finish copying, please refresh the app and click "Resume Copying"' +
                'and follow the instructions on the page.');
        }
        return;
    }

    /*****************************
     * Initialize logger spreadsheet
     */
    ss = SpreadsheetApp.openById(properties.spreadsheetId).getSheetByName("Log");
    timeZone = SpreadsheetApp.openById(properties.spreadsheetId).getSpreadsheetTimeZone();
    if (timeZone === undefined || timeZone === null) {
        timeZone = 'GMT-7';
    }

    // TODO: Move this higher in function calls
    // delete prior trigger
    if ( triggerId !== undefined && triggerId !== null) {
        try {
            // delete prior trigger
            deleteTrigger(triggerId);
        } catch (err) {
            log(ss, [err.message, err.fileName, err.lineNumber, Utilities.formatDate(new Date(), timeZone, "MM-dd-yy hh:mm:ss aaa")]);
        }
    }

    /*****************************
     * Handle leftovers from prior run
     */

    // TODO: Make a separate function processLeftovers() or something like that

    // get current children, or skip if none exist
    if ( properties.leftovers.items && properties.leftovers.items.length > 0) {
        properties.destFolder = properties.leftovers.items[0].parents[0].id;
        processFileList(properties.leftovers.items, timeZone, properties.permissions, userProperties, START_TIME, MAX_RUNNING_TIME, properties.map);
    }

    /*****************************
     * Query the next folder from properties.remaining
     */
    // When leftovers are complete, query next folder from properties.remaining
    Logger.log("beginning processFiles on next remaining folder");
    while ( properties.remaining.length > 0 && !timeIsUp && !stop) {

        try {
            // if pages remained in the previous query, use them first
            if ( properties.pageToken ) {
                currFolder = properties.destFolder;
            } else {
                currFolder = properties.remaining.shift();
            }
        } catch (err) {
            log(ss, [err.message, err.fileName, err.lineNumber, Utilities.formatDate(new Date(), timeZone, "MM-dd-yy hh:mm:ss aaa")]);
        }

        // build query
        query = '"' + currFolder + '" in parents and trashed = false';

        // Get fileList using query.
        // Repeat if pageToken exists (i.e. more than 1000 results return from the query)
        do {

            try {
                // Get fileList
                files = getFiles(query, properties.pageToken);
            } catch (err) {
                log(ss, [err.message, err.fileName, err.lineNumber]);
            }

            // Send items to processFileList() to copy
            if (files.items && files.items.length > 0) {
                processFileList(files.items, timeZone, properties.permissions, userProperties, START_TIME, MAX_RUNNING_TIME, properties.map);
            } else {
                Logger.log('No children found.');
            }

            // get next page token to continue iteration
            properties.pageToken = files.nextPageToken;

        } while (properties.pageToken && !timeIsUp && !stop);

    }

    // TODO: Delete trigger if script is complete, or if "stop" is selected

    // TODO: Pass log message to saveState() and have it log from within the function
    if (stop) {
        saveState('notrigger');
        log(ss, ["Stopped manually by user.  Please use 'Resume' button to restart copying"]);
        return;
    }

    // If timeIsUp, maximum execution time has been reached
    // Update logger spreadsheet, and save current items to properties.leftovers
    if ( timeIsUp ) {
        saveState();
        log(ss, ["Paused due to Google quota limits - copy will resume in 1-2 minutes"]);
    } else {
        // If script reaches here and !timeIsUp, then the copy is complete!
        // Delete prior trigger, move propertiesDoc to trash, and update logger spreadsheet,

        try {
            Drive.Files.update({"labels": {"trashed": true}},properties.propertiesDocId);
        } catch (err) {
            log(ss, [err.message, err.fileName, err.lineNumber]);
        }
        ss.getRange(2, 3, 1, 1).setValue("Complete").setBackground("#66b22c");
        ss.getRange(2, 4, 1, 1).setValue(Utilities.formatDate(new Date(), timeZone, "MM-dd-yy hh:mm:ss a"));
    }
}<commit_msg>adding todos<commit_after>/**
 * Copy folders and files from source to destination.
 * Get parameters from userProperties,
 * Loop until time runs out,
 * then call timeout methods, saveProperties and createTrigger.
 *
 * @param {boolean} resuming whether or not the copy call is resuming an existing folder copy or starting fresh
 */
function copy() {
    // CONSTANTS
    var MAX_RUNNING_TIME = 4.7 * 60000; // return millisecs
    var START_TIME = (new Date()).getTime();

    // TODO: clean up variable declarations
    var timeIsUp,       // {boolean} true if max execution time is reached while executing script
        currTime,       // {number} integer representing current time in milliseconds
        ss,             // {object} instance of Sheet class
        //properties is a global object now, stored in the file propertiesObject
        query,          // {string} query to generate Files list
        files,          // {object} list of files within Drive folder
        item,           // {object} metadata of child item from current iteration
        currFolder,     // {object} metadata of folder whose children are currently being processed
        newfile,        // {Object} JSON metadata for newly created folder or file
        timeZone,       // {string} time zone of user
        stop,           // {boolean} true if the user has clicked the 'stop' button
        userProperties = PropertiesService.getUserProperties(), // reference to userProperties store
        triggerId = userProperties.getProperties().triggerId;      // {string} Unique ID for the most recently created trigger

    stop = userProperties.getProperties().stop == 'true';

    /*****************************
     * deleteAllTriggers()
     *  - get rid of all triggers that exist from previous runs, or anything else
     */

    /*****************************
     * createTrigger()
     *
     */

    /*****************************
     * Load properties
     */
    try {
        // Load properties and initialize logger spreadsheet
        properties = exponentialBackoff(loadProperties, 'Error restarting script, will retry in 1-2 minutes');

    } catch (err) {

        var n = Number(userProperties.getProperties().trials);
        Logger.log(n);

        if (n < 5) {
            Logger.log('setting trials property');
            userProperties.setProperty('trials', (n + 1).toString());

            exponentialBackoff(createTrigger,
                'Error setting trigger.  There has been a server error with Google Apps Script.' +
                'To successfully finish copying, please refresh the app and click "Resume Copying"' +
                'and follow the instructions on the page.');
        }
        return;
    }

    /*****************************
     * Initialize logger spreadsheet
     */
    ss = SpreadsheetApp.openById(properties.spreadsheetId).getSheetByName("Log");
    timeZone = SpreadsheetApp.openById(properties.spreadsheetId).getSpreadsheetTimeZone();
    if (timeZone === undefined || timeZone === null) {
        timeZone = 'GMT-7';
    }

    // TODO: Move this higher in function calls
    // delete prior trigger
    if ( triggerId !== undefined && triggerId !== null) {
        try {
            // delete prior trigger
            deleteTrigger(triggerId);
        } catch (err) {
            log(ss, [err.message, err.fileName, err.lineNumber, Utilities.formatDate(new Date(), timeZone, "MM-dd-yy hh:mm:ss aaa")]);
        }
    }

    /*****************************
     * Handle leftovers from prior run
     */

    // TODO: Make a separate function processLeftovers() or something like that

    // get current children, or skip if none exist
    if ( properties.leftovers.items && properties.leftovers.items.length > 0) {
        properties.destFolder = properties.leftovers.items[0].parents[0].id;
        processFileList(properties.leftovers.items, timeZone, properties.permissions, userProperties, START_TIME, MAX_RUNNING_TIME, properties.map);
    }

    /*****************************
     * Query the next folder from properties.remaining
     */
    // When leftovers are complete, query next folder from properties.remaining
    Logger.log("beginning processFiles on next remaining folder");
    while ( properties.remaining.length > 0 && !timeIsUp && !stop) {

        try {
            // if pages remained in the previous query, use them first
            if ( properties.pageToken ) {
                currFolder = properties.destFolder;
            } else {
                currFolder = properties.remaining.shift();
            }
        } catch (err) {
            log(ss, [err.message, err.fileName, err.lineNumber, Utilities.formatDate(new Date(), timeZone, "MM-dd-yy hh:mm:ss aaa")]);
        }

        // build query
        query = '"' + currFolder + '" in parents and trashed = false';

        // Get fileList using query.
        // Repeat if pageToken exists (i.e. more than 1000 results return from the query)
        do {

            try {
                // Get fileList
                files = getFiles(query, properties.pageToken);
            } catch (err) {
                log(ss, [err.message, err.fileName, err.lineNumber]);
            }

            // Send items to processFileList() to copy
            if (files.items && files.items.length > 0) {
                processFileList(files.items, timeZone, properties.permissions, userProperties, START_TIME, MAX_RUNNING_TIME, properties.map);
            } else {
                Logger.log('No children found.');
            }

            // get next page token to continue iteration
            properties.pageToken = files.nextPageToken;

        } while (properties.pageToken && !timeIsUp && !stop);

    }

    // TODO: Delete trigger if script is complete, or if "stop" is selected

    // TODO: Pass log message to saveState() and have it log from within the function
    if (stop) {
        saveState('notrigger');
        log(ss, ["Stopped manually by user.  Please use 'Resume' button to restart copying"]);
        return;
    }

    // If timeIsUp, maximum execution time has been reached
    // Update logger spreadsheet, and save current items to properties.leftovers
    if ( timeIsUp ) {
        saveState();
        log(ss, ["Paused due to Google quota limits - copy will resume in 1-2 minutes"]);
    } else {
        // If script reaches here and !timeIsUp, then the copy is complete!
        // Delete prior trigger, move propertiesDoc to trash, and update logger spreadsheet,

        try {
            Drive.Files.update({"labels": {"trashed": true}},properties.propertiesDocId);
        } catch (err) {
            log(ss, [err.message, err.fileName, err.lineNumber]);
        }
        ss.getRange(2, 3, 1, 1).setValue("Complete").setBackground("#66b22c");
        ss.getRange(2, 4, 1, 1).setValue(Utilities.formatDate(new Date(), timeZone, "MM-dd-yy hh:mm:ss a"));
    }
}<|endoftext|>