<commit_before>Polymer({
  is: "c4c-data-service",
  behaviors: [
    Polymer.C4CLogging
  ],
  properties: {
    logLevel: {
      type: Number,
      value: 3
    },
    auth: {
      type: Object,
      value: {
        user: null
      }
    },
    status: {
      type: String,
      value: '',
      notify: true,
    },
    route: {
      type: String,
      value: ''
    },
    data: {
      type: Array,
      value: function() { return []; },
      notify: true
    },
    metadata: {
      type: Object,
      value: function() { return {}; },
      notify: true
    },
    liveData: {
      type: Array,
      value: []
    },
    readOnly: {
      type: Boolean,
      value: false,
      reflectToAttribute: true
    },
    urlPrefix: {
      type: String,
      value: function() {
        return 'http://dev.rhizome.com/api/v1';
      }
    },
    vectorBaseUrl: {
      type: String,
      computed: "__computeVectorBaseUrl(urlPrefix, route)"
    },
    scalarBaseUrl: {
      type: String,
      computed: "__computeScalarBaseUrl(urlPrefix, route, rqEntityId)"
    },
    requestQueue: {
      type: Array,
      value: function () {
        return [];
      }
    },
    request: {
      type: Object,
      value: {
        url: this.vectorBaseUrl,
        contentType: '',
        response: [],
        entityId: '',
        body: {}
      }
    },
    rqEntityId: String,
    rqUrl: String,
    rqContentType: String,
    rqParams: {},
    rqBody: {},
    rqResponse: []
  },
  observers: [
    '__dataSplices(data.splices)',
    '__dataChanges(data.*)',
    '__metadataChanged(metadata.*)',
    '__auth(route, auth.user)'
  ],

  __auth: function() {
    this.__silly(`data:${this.route}:${this.status}`);

    if (!this.get('auth.user')) {
      return;
    }

    if (this.status === "uninitialised") {
      this.__generateListRequest();
    }
  },

  /**
   * Used to generate Add and Remove requests
   * @param {Object} cr - data needed to calculate what has changed
   * @private
   */
  __dataSplices: function(cr) {
    if (!cr || this.readOnly) {
      return;
    }
    this.__debug('__dataSplices', cr);

    cr.indexSplices.forEach(i => {
      let o = i.object[i.index];
      if (i.addedCount > 0 && o.__readonly__ !== true) {
        this.__generateAddRequest(o);
      }

      // i.object.forEach((a, idx) => {
      //   this.__generateAddRequest(this.get(`data.${idx}`));
      // });

      i.removed.forEach(r => {
        if (!r.__readonly__) {
          this.__generateRmRequest(r.id);
        }
      });
    });
  },

  /**
   * Used to update individual records
   * @param {Object} cr - definition of what's changed
   * @private
   */
  __dataChanges: function(cr) {
    // this.__debug(`Internal Change: ${this.__internalChange}`);
    if (this.__internalChange__) {
      delete this.__internalChange__;
      return;
    }
    if (/\.length$/.test(cr.path) === true
      || this.readOnly) {
      return;
    }

    this.__silly('__dataChanges: ', cr);
    // Ignore mutations on the whole array
    // if (cr.base.length !== 1) {
    //   return;
    // }

    // ignore paths with fields with __ as prefix and suffix
    if (/__(\w+)__/.test(cr.path)) {
      this.__warn(`Ignoring internal change: ${cr.path}`);
      return;
    }

    let path = cr.path.split('.');
    // Is this an array mutation?
    if (/\.splices$/.test(cr.path) === true) {
      if (path.length < 4) {
        this.__warn('Ignoring path too short:', path);
        return;
      }

      let entity = this.get(path.slice(0,2));
      // let index = path[1].replace('#', '');
      // if (!cr.base[index]) {
      //   this.__warn(`Ignoring: invalid change index: ${index}`);
      //   return;
      // }
      // let entity = cr.base[index];

      // Ignore a one-off readonly change (remove the field afterwards)
      if (entity.__readOnlyChange__) {
        this.__warn(`Ignoring readonly change: ${cr.path}`);
        delete entity.__readOnlyChange__;
        return;
      }

      this.__warn('Child array mutation', cr);

      this.__silly('Key Splices: ', cr.value.indexSplices.length);

      cr.value.indexSplices.forEach(i => {
        let o = i.object[i.index];
        if (i.addedCount > 0) {
          path.splice(0,2);
          path.splice(-1,1);
          // this.__warn('Update request', entity.id, path.join('.'), cr.value);
          this.__generateUpdateRequest(entity.id, path.join('.'), o);
        } else if (i.removed.length > 0){
          if(i.removed.length > 1) {
            this.__warn('Index splice removed.length > 1', i.removed);
          } else {
            path.splice(0, 2);
            path.splice(-1, 1);
            path.push(i.index);
            path.push('__remove__');

            this.__generateUpdateRequest(entity.id, path.join('.'), '');
          }
        }
      });

      if (cr.value.indexSplices.length || !cr.value.keySplices) {
        return;
      }

      this.__silly('Key Splices: ', cr.value.keySplices.length);

      cr.value.keySplices.forEach((k, idx) => {
        k.removed.forEach(() => {
          let itemIndex = cr.value.indexSplices[idx].index;
          this.__debug(itemIndex);

          path.splice(0, 2); // drop the prefix
          path.splice(-1, 1); // drop the .splices
          path.push(itemIndex); // add the correct index

          // path.push(k.replace('#', ''));
          path.push('__remove__'); // add the remove command
          this.__generateUpdateRequest(entity.id, path.join('.'), '');
        });
      });
    } else {
      if (path.length < 3) {
        // this.__warn('Ignoring path too short:', path);
        return;
      }
      let entity = this.get(path.slice(0,2));

      // let index = path[1].replace('#', '');
      if (!entity) {
        this.__warn(`Ignoring: invalid change index: ${path.slice(0,2)}`);
        return;
      }

      // let entity = cr.base[index];
      // Ignore a one-off readonly change (remove the field afterwards)
      if (entity.__readOnlyChange__) {
        this.__warn(`Ignoring readonly change: ${cr.path}`);
        delete entity.__readOnlyChange__;
        return;
      }

      let pathPrefix = path.splice(0, 2).join('.');
      path.forEach((p, idx) => {
        const rex = /^#\d+$/;
        // Is this an assignment directly into an array item?
        if (rex.test(p)) {
          // Grab the base array
          let arr = this.get(pathPrefix);
          // Get the item
          let item = this.get(`${pathPrefix}.${p}`);
          // Replace the 'opaque key' with the correct array index
          path[idx] = arr.indexOf(item);
        }
        pathPrefix += `.${p}`;
      });

      // path.splice(0,2);

      // let tail = path[path.length-1];
      // const rex = /#\d+$/;
      // // Is this an assignment directly into an array item?
      // if (rex.test(tail)) {
      //   // Look up the item
      //   let item = this.get(path);
      //   // Grab the base array
      //   let arr = this.get(path.slice(0,-1));
      //   // Replace the 'opaque key' with the correct array index
      //   path[path.length-1] = arr.indexOf(item);
      // }

      // this.__warn('Update request', entity.id, path.join('.'), cr.value);
      this.__generateUpdateRequest(entity.id, path.join('.'), cr.value);
    }
  },

  __metadataChanged: function(cr) {
    if (this.__internalChange__) {
      this.__silly(`Ignoring internal metadata change: ${cr.path}`);
      delete this.__internalChange__;
      return;
    }

    if (/\.length$/.test(cr.path) === true
      || this.readOnly) {
      this.__debug('Ignoring .length or readOnly change');
      return;
    }

    // ignore paths with fields with __ as prefix and suffix
    let matches = /^metadata.([0-9a-fA-F]+)/.exec(cr.path);
    if (!matches) {
      this.__debug(`Ignoring invalid metadata path: ${cr.path}`);
      return;
    }
    let entityId = matches[1];
    this.__debug('__metadataChange', cr);
    if (cr.base.__readOnlyChange__) {
      delete cr.base.__readOnlyChange__;
      this.__warn(`Ignoring read only change`);
      return;
    }

    if (cr.value.__populate__) {
      this.__warn(`Populating metadata for ${entityId}`);
      delete cr.value.__populate__;
      this.__generateMetadataGetAllRequest(entityId, cr.value);
      return;
    }

    // ignore paths with fields with __ as prefix and suffix
    if (/__(\w+)__/.test(cr.path)) {
      this.__warn(`Ignoring internal change: ${cr.path}`);
      return;
    }

    this.__info('__metadataChanged', cr);
    let path = cr.path.split('.');
    // Is this an array mutation?
    if (/\.splices$/.test(cr.path) === true) {
      let remotePath = path.concat();
      remotePath.splice(-1,1);
      let base = this.get(remotePath);
      remotePath.splice(0,2);
      this.__assert(remotePath.length === 1); // Metadata doesn't support remote paths
      this.__generateMetadataUpdateRequest(entityId, remotePath.join('.'), base);
    } else {
      let value = cr.value;
      if (path.length > 3) {
        path = path.splice(0, 3);
        value = this.get(path);
      }
      path.splice(0,2);

      this.__assert(path.length === 1); // Metadata doesn't support remote paths
      this.__generateMetadataUpdateRequest(entityId, path[0], value);
    }
  },

  __generateMetadataGetAllRequest: function(entityId, defaults) {
    this.rqEntityId = entityId;
    let request = {
      type: 'list-metadata',
      url: `${this.scalarBaseUrl}/metadata`,
      entityId: this.rqEntityId,
      method: 'GET',
      contentType: '',
      body: {},
      defaults: defaults
    };

    this.__queueRequest(request);
  },

  __generateMetadataUpdateRequest: function(entityId, key, value) {
    this.rqEntityId = entityId;
    let request = {
      type: 'update-metadata',
      url: `${this.scalarBaseUrl}/metadata/${key}`,
      entityId: this.rqEntityId,
      method: 'POST',
      contentType: 'application/json',
      body: {
        value: JSON.stringify(value)
      }
    };

    this.__queueRequest(request);
  },

  __generateListRequest: function() {
    this.rqEntityId = -1;
    let request = {
      type: 'list',
      url: this.vectorBaseUrl,
      entityId: this.rqEntityId,
      method: 'GET',
      contentType: '',
      body: {}
    };

    this.__queueRequest(request);
  },
  __generateRmRequest: function(entityId) {
    this.__warn(`remove rq: ${entityId}`);

    this.rqEntityId = entityId;
    let request = {
      type: 'rm',
      url: this.scalarBaseUrl,
      entityId: this.rqEntityId,
      method: 'DELETE',
      contentType: '',
      body: {}
    };

    this.__queueRequest(request);
  },
  __generateAddRequest: function(entity) {
    this.__warn(`add rq: ${entity.name}`);

    this.rqEntityId = -1;
    let request = {
      type: 'add',
      url: this.vectorBaseUrl,
      entityId: this.rqEntityId,
      method: 'POST',
      contentType: 'application/json',
      body: entity
    };
    this.__queueRequest(request);
  },
  __generateUpdateRequest: function(entityId, path, value) {
    this.__warn('update rq:',entityId, path, value);

    this.rqEntityId = entityId;
    let request = {
      type: 'update',
      url: this.scalarBaseUrl,
      entityId: this.rqEntityId,
      method: 'PUT',
      contentType: 'application/json',
      body: {
        path: path,
        value: value
      }
    };
    this.__queueRequest(request);
  },

  __queueRequest: function(request) {
    this.requestQueue.push(request);
    this.__updateQueue();
  },

  __updateQueue: function() {
    if (this.requestQueue.length === 0) {
      return;
    }

    if (this.status === 'working') {
      return;
    }

    this.__generateRequest(this.requestQueue[0]);
  },

  __generateRequest: function(rq) {
    rq.response = null;
    rq.params = {
      urq: Date.now(),
      token: this.auth.user.authToken
    };

    this.__silly(rq.body);
    this.rqUrl = rq.url;
    this.rqMethod = rq.method;
    this.rqContentType = rq.contentType;
    this.rqParams = rq.params;
    this.rqBody = rq.body;

    this.$.ajaxService.generateRequest();
    this.status = 'working';
  },

  __ajaxResponse: function(ev) {
    let rq = this.requestQueue.shift();

    if (!rq) {
      this.__warn('Response on an empty requestQueue!!!');
      return;
    }

    rq.response = ev.detail.response;
    switch (rq.type) {
      default: {
        this.__warn('Unhandled rq.type', rq.type);
      } break;
      case 'list': {
        this.__ajaxListResponse(rq);
      } break;
      case 'list-metadata': {
        this.__ajaxListMetadataResponse(rq);
      } break;
      case 'update': {
        this.__ajaxUpdateResponse(rq);
      } break;
      case 'add': {
        this.__ajaxAddResponse(rq);
      } break;
    }

    this.status = 'done';
    this.__updateQueue();
  },
  __ajaxError: function() {
    this.status = 'error';
  },

  __ajaxListResponse: function(rq) {
    this.__internalChange__ = true;
    this.data = this.liveData = rq.response;
  },
  __ajaxListMetadataResponse: function(rq) {
    // this.set(['metadata',rq.entityId], rq.response);
    for (let field in rq.defaults) {
      if (!Object.prototype.hasOwnProperty.call(rq.defaults, field)) {
        continue;
      }
      this.__internalChange__ = true;
      if (rq.response[field]) {
        this.set(['metadata', rq.entityId, field], rq.response[field]);
      } else {
        this.set(['metadata', rq.entityId, field], rq.defaults[field]);
      }
    }
  },

  __ajaxAddResponse: function(rq) {
    this.data.forEach((d, idx) => {
      if (!d.id) {
        this.data[idx].__readOnlyChange__ = true;
        this.set(['data', idx, 'id'], rq.response.id);
      }
    })
  },

  __ajaxUpdateResponse: function(rq) {
    this.__debug('__ajaxUpdateResponse', rq);
    const responses = rq.response;
    responses.forEach(r => {
      if (!(r.value instanceof Object) || r.type !== 'vector-add' || !r.value.id) {
        this.__warn('update early out', r.value instanceof Object);
        return;
      }
      let idx = this.get('data').findIndex(e => e.id == rq.entityId); //eslint-disable-line eqeqeq
      if (idx === -1) {
        this.__warn('Invalid entity id', rq.entityId);
        return;
      }
      let base = this.get(['data', idx, r.path]);
      this.__debug(['data', idx, r.path], base);
      if (base instanceof Array) {
        for (let x=0; x<base.length; x++) {
          if (!base[x].id) {
            this.data[idx].__readOnlyChange__ = true;
            this.__debug(['data', idx, rq.body.path, x, 'id']);
            this.set(['data', idx, rq.body.path, x, 'id'], r.value.id);
            break;
          }
        }
      }
    });
  },

  __computeVectorBaseUrl: function(urlPrefix, route) {
    return `${urlPrefix}/${route}`
  },
  __computeScalarBaseUrl: function() {
    return `${this.urlPrefix}/${this.route}/${this.rqEntityId}`
  }
});

<commit_msg>- FIXED: use the correct url.<commit_after>Polymer({
  is: "c4c-data-service",
  behaviors: [
    Polymer.C4CLogging
  ],
  properties: {
    logLevel: {
      type: Number,
      value: 3
    },
    auth: {
      type: Object,
      value: {
        user: null
      }
    },
    status: {
      type: String,
      value: '',
      notify: true,
    },
    route: {
      type: String,
      value: ''
    },
    data: {
      type: Array,
      value: function() { return []; },
      notify: true
    },
    metadata: {
      type: Object,
      value: function() { return {}; },
      notify: true
    },
    liveData: {
      type: Array,
      value: []
    },
    readOnly: {
      type: Boolean,
      value: false,
      reflectToAttribute: true
    },
    urlPrefix: {
      type: String,
      value: function() {
        return 'http://rhizome.codersforlabour.com/api/v1';
      }
    },
    vectorBaseUrl: {
      type: String,
      computed: "__computeVectorBaseUrl(urlPrefix, route)"
    },
    scalarBaseUrl: {
      type: String,
      computed: "__computeScalarBaseUrl(urlPrefix, route, rqEntityId)"
    },
    requestQueue: {
      type: Array,
      value: function () {
        return [];
      }
    },
    request: {
      type: Object,
      value: {
        url: this.vectorBaseUrl,
        contentType: '',
        response: [],
        entityId: '',
        body: {}
      }
    },
    rqEntityId: String,
    rqUrl: String,
    rqContentType: String,
    rqParams: {},
    rqBody: {},
    rqResponse: []
  },
  observers: [
    '__dataSplices(data.splices)',
    '__dataChanges(data.*)',
    '__metadataChanged(metadata.*)',
    '__auth(route, auth.user)'
  ],

  __auth: function() {
    this.__silly(`data:${this.route}:${this.status}`);

    if (!this.get('auth.user')) {
      return;
    }

    if (this.status === "uninitialised") {
      this.__generateListRequest();
    }
  },

  /**
   * Used to generate Add and Remove requests
   * @param {Object} cr - data needed to calculate what has changed
   * @private
   */
  __dataSplices: function(cr) {
    if (!cr || this.readOnly) {
      return;
    }
    this.__debug('__dataSplices', cr);

    cr.indexSplices.forEach(i => {
      let o = i.object[i.index];
      if (i.addedCount > 0 && o.__readonly__ !== true) {
        this.__generateAddRequest(o);
      }

      // i.object.forEach((a, idx) => {
      //   this.__generateAddRequest(this.get(`data.${idx}`));
      // });

      i.removed.forEach(r => {
        if (!r.__readonly__) {
          this.__generateRmRequest(r.id);
        }
      });
    });
  },

  /**
   * Used to update individual records
   * @param {Object} cr - definition of what's changed
   * @private
   */
  __dataChanges: function(cr) {
    // this.__debug(`Internal Change: ${this.__internalChange}`);
    if (this.__internalChange__) {
      delete this.__internalChange__;
      return;
    }
    if (/\.length$/.test(cr.path) === true
      || this.readOnly) {
      return;
    }

    this.__silly('__dataChanges: ', cr);
    // Ignore mutations on the whole array
    // if (cr.base.length !== 1) {
    //   return;
    // }

    // ignore paths with fields with __ as prefix and suffix
    if (/__(\w+)__/.test(cr.path)) {
      this.__warn(`Ignoring internal change: ${cr.path}`);
      return;
    }

    let path = cr.path.split('.');
    // Is this an array mutation?
    if (/\.splices$/.test(cr.path) === true) {
      if (path.length < 4) {
        this.__warn('Ignoring path too short:', path);
        return;
      }

      let entity = this.get(path.slice(0,2));
      // let index = path[1].replace('#', '');
      // if (!cr.base[index]) {
      //   this.__warn(`Ignoring: invalid change index: ${index}`);
      //   return;
      // }
      // let entity = cr.base[index];

      // Ignore a one-off readonly change (remove the field afterwards)
      if (entity.__readOnlyChange__) {
        this.__warn(`Ignoring readonly change: ${cr.path}`);
        delete entity.__readOnlyChange__;
        return;
      }

      this.__warn('Child array mutation', cr);

      this.__silly('Key Splices: ', cr.value.indexSplices.length);

      cr.value.indexSplices.forEach(i => {
        let o = i.object[i.index];
        if (i.addedCount > 0) {
          path.splice(0,2);
          path.splice(-1,1);
          // this.__warn('Update request', entity.id, path.join('.'), cr.value);
          this.__generateUpdateRequest(entity.id, path.join('.'), o);
        } else if (i.removed.length > 0){
          if(i.removed.length > 1) {
            this.__warn('Index splice removed.length > 1', i.removed);
          } else {
            path.splice(0, 2);
            path.splice(-1, 1);
            path.push(i.index);
            path.push('__remove__');

            this.__generateUpdateRequest(entity.id, path.join('.'), '');
          }
        }
      });

      if (cr.value.indexSplices.length || !cr.value.keySplices) {
        return;
      }

      this.__silly('Key Splices: ', cr.value.keySplices.length);

      cr.value.keySplices.forEach((k, idx) => {
        k.removed.forEach(() => {
          let itemIndex = cr.value.indexSplices[idx].index;
          this.__debug(itemIndex);

          path.splice(0, 2); // drop the prefix
          path.splice(-1, 1); // drop the .splices
          path.push(itemIndex); // add the correct index

          // path.push(k.replace('#', ''));
          path.push('__remove__'); // add the remove command
          this.__generateUpdateRequest(entity.id, path.join('.'), '');
        });
      });
    } else {
      if (path.length < 3) {
        // this.__warn('Ignoring path too short:', path);
        return;
      }
      let entity = this.get(path.slice(0,2));

      // let index = path[1].replace('#', '');
      if (!entity) {
        this.__warn(`Ignoring: invalid change index: ${path.slice(0,2)}`);
        return;
      }

      // let entity = cr.base[index];
      // Ignore a one-off readonly change (remove the field afterwards)
      if (entity.__readOnlyChange__) {
        this.__warn(`Ignoring readonly change: ${cr.path}`);
        delete entity.__readOnlyChange__;
        return;
      }

      let pathPrefix = path.splice(0, 2).join('.');
      path.forEach((p, idx) => {
        const rex = /^#\d+$/;
        // Is this an assignment directly into an array item?
        if (rex.test(p)) {
          // Grab the base array
          let arr = this.get(pathPrefix);
          // Get the item
          let item = this.get(`${pathPrefix}.${p}`);
          // Replace the 'opaque key' with the correct array index
          path[idx] = arr.indexOf(item);
        }
        pathPrefix += `.${p}`;
      });

      // path.splice(0,2);

      // let tail = path[path.length-1];
      // const rex = /#\d+$/;
      // // Is this an assignment directly into an array item?
      // if (rex.test(tail)) {
      //   // Look up the item
      //   let item = this.get(path);
      //   // Grab the base array
      //   let arr = this.get(path.slice(0,-1));
      //   // Replace the 'opaque key' with the correct array index
      //   path[path.length-1] = arr.indexOf(item);
      // }

      // this.__warn('Update request', entity.id, path.join('.'), cr.value);
      this.__generateUpdateRequest(entity.id, path.join('.'), cr.value);
    }
  },

  __metadataChanged: function(cr) {
    if (this.__internalChange__) {
      this.__silly(`Ignoring internal metadata change: ${cr.path}`);
      delete this.__internalChange__;
      return;
    }

    if (/\.length$/.test(cr.path) === true
      || this.readOnly) {
      this.__debug('Ignoring .length or readOnly change');
      return;
    }

    // ignore paths with fields with __ as prefix and suffix
    let matches = /^metadata.([0-9a-fA-F]+)/.exec(cr.path);
    if (!matches) {
      this.__debug(`Ignoring invalid metadata path: ${cr.path}`);
      return;
    }
    let entityId = matches[1];
    this.__debug('__metadataChange', cr);
    if (cr.base.__readOnlyChange__) {
      delete cr.base.__readOnlyChange__;
      this.__warn(`Ignoring read only change`);
      return;
    }

    if (cr.value.__populate__) {
      this.__warn(`Populating metadata for ${entityId}`);
      delete cr.value.__populate__;
      this.__generateMetadataGetAllRequest(entityId, cr.value);
      return;
    }

    // ignore paths with fields with __ as prefix and suffix
    if (/__(\w+)__/.test(cr.path)) {
      this.__warn(`Ignoring internal change: ${cr.path}`);
      return;
    }

    this.__info('__metadataChanged', cr);
    let path = cr.path.split('.');
    // Is this an array mutation?
    if (/\.splices$/.test(cr.path) === true) {
      let remotePath = path.concat();
      remotePath.splice(-1,1);
      let base = this.get(remotePath);
      remotePath.splice(0,2);
      this.__assert(remotePath.length === 1); // Metadata doesn't support remote paths
      this.__generateMetadataUpdateRequest(entityId, remotePath.join('.'), base);
    } else {
      let value = cr.value;
      if (path.length > 3) {
        path = path.splice(0, 3);
        value = this.get(path);
      }
      path.splice(0,2);

      this.__assert(path.length === 1); // Metadata doesn't support remote paths
      this.__generateMetadataUpdateRequest(entityId, path[0], value);
    }
  },

  __generateMetadataGetAllRequest: function(entityId, defaults) {
    this.rqEntityId = entityId;
    let request = {
      type: 'list-metadata',
      url: `${this.scalarBaseUrl}/metadata`,
      entityId: this.rqEntityId,
      method: 'GET',
      contentType: '',
      body: {},
      defaults: defaults
    };

    this.__queueRequest(request);
  },

  __generateMetadataUpdateRequest: function(entityId, key, value) {
    this.rqEntityId = entityId;
    let request = {
      type: 'update-metadata',
      url: `${this.scalarBaseUrl}/metadata/${key}`,
      entityId: this.rqEntityId,
      method: 'POST',
      contentType: 'application/json',
      body: {
        value: JSON.stringify(value)
      }
    };

    this.__queueRequest(request);
  },

  __generateListRequest: function() {
    this.rqEntityId = -1;
    let request = {
      type: 'list',
      url: this.vectorBaseUrl,
      entityId: this.rqEntityId,
      method: 'GET',
      contentType: '',
      body: {}
    };

    this.__queueRequest(request);
  },
  __generateRmRequest: function(entityId) {
    this.__warn(`remove rq: ${entityId}`);

    this.rqEntityId = entityId;
    let request = {
      type: 'rm',
      url: this.scalarBaseUrl,
      entityId: this.rqEntityId,
      method: 'DELETE',
      contentType: '',
      body: {}
    };

    this.__queueRequest(request);
  },
  __generateAddRequest: function(entity) {
    this.__warn(`add rq: ${entity.name}`);

    this.rqEntityId = -1;
    let request = {
      type: 'add',
      url: this.vectorBaseUrl,
      entityId: this.rqEntityId,
      method: 'POST',
      contentType: 'application/json',
      body: entity
    };
    this.__queueRequest(request);
  },
  __generateUpdateRequest: function(entityId, path, value) {
    this.__warn('update rq:',entityId, path, value);

    this.rqEntityId = entityId;
    let request = {
      type: 'update',
      url: this.scalarBaseUrl,
      entityId: this.rqEntityId,
      method: 'PUT',
      contentType: 'application/json',
      body: {
        path: path,
        value: value
      }
    };
    this.__queueRequest(request);
  },

  __queueRequest: function(request) {
    this.requestQueue.push(request);
    this.__updateQueue();
  },

  __updateQueue: function() {
    if (this.requestQueue.length === 0) {
      return;
    }

    if (this.status === 'working') {
      return;
    }

    this.__generateRequest(this.requestQueue[0]);
  },

  __generateRequest: function(rq) {
    rq.response = null;
    rq.params = {
      urq: Date.now(),
      token: this.auth.user.authToken
    };

    this.__silly(rq.body);
    this.rqUrl = rq.url;
    this.rqMethod = rq.method;
    this.rqContentType = rq.contentType;
    this.rqParams = rq.params;
    this.rqBody = rq.body;

    this.$.ajaxService.generateRequest();
    this.status = 'working';
  },

  __ajaxResponse: function(ev) {
    let rq = this.requestQueue.shift();

    if (!rq) {
      this.__warn('Response on an empty requestQueue!!!');
      return;
    }

    rq.response = ev.detail.response;
    switch (rq.type) {
      default: {
        this.__warn('Unhandled rq.type', rq.type);
      } break;
      case 'list': {
        this.__ajaxListResponse(rq);
      } break;
      case 'list-metadata': {
        this.__ajaxListMetadataResponse(rq);
      } break;
      case 'update': {
        this.__ajaxUpdateResponse(rq);
      } break;
      case 'add': {
        this.__ajaxAddResponse(rq);
      } break;
    }

    this.status = 'done';
    this.__updateQueue();
  },
  __ajaxError: function() {
    this.status = 'error';
  },

  __ajaxListResponse: function(rq) {
    this.__internalChange__ = true;
    this.data = this.liveData = rq.response;
  },
  __ajaxListMetadataResponse: function(rq) {
    // this.set(['metadata',rq.entityId], rq.response);
    for (let field in rq.defaults) {
      if (!Object.prototype.hasOwnProperty.call(rq.defaults, field)) {
        continue;
      }
      this.__internalChange__ = true;
      if (rq.response[field]) {
        this.set(['metadata', rq.entityId, field], rq.response[field]);
      } else {
        this.set(['metadata', rq.entityId, field], rq.defaults[field]);
      }
    }
  },

  __ajaxAddResponse: function(rq) {
    this.data.forEach((d, idx) => {
      if (!d.id) {
        this.data[idx].__readOnlyChange__ = true;
        this.set(['data', idx, 'id'], rq.response.id);
      }
    })
  },

  __ajaxUpdateResponse: function(rq) {
    this.__debug('__ajaxUpdateResponse', rq);
    const responses = rq.response;
    responses.forEach(r => {
      if (!(r.value instanceof Object) || r.type !== 'vector-add' || !r.value.id) {
        this.__warn('update early out', r.value instanceof Object);
        return;
      }
      let idx = this.get('data').findIndex(e => e.id == rq.entityId); //eslint-disable-line eqeqeq
      if (idx === -1) {
        this.__warn('Invalid entity id', rq.entityId);
        return;
      }
      let base = this.get(['data', idx, r.path]);
      this.__debug(['data', idx, r.path], base);
      if (base instanceof Array) {
        for (let x=0; x<base.length; x++) {
          if (!base[x].id) {
            this.data[idx].__readOnlyChange__ = true;
            this.__debug(['data', idx, rq.body.path, x, 'id']);
            this.set(['data', idx, rq.body.path, x, 'id'], r.value.id);
            break;
          }
        }
      }
    });
  },

  __computeVectorBaseUrl: function(urlPrefix, route) {
    return `${urlPrefix}/${route}`
  },
  __computeScalarBaseUrl: function() {
    return `${this.urlPrefix}/${this.route}/${this.rqEntityId}`
  }
});

<|endoftext|>


<commit_before>import RecordArray from "ember-data/system/record_arrays/record_array";

/**
  @module ember-data
*/

var get = Ember.get, set = Ember.set;

/**
  A `ManyArray` is a `RecordArray` that represents the contents of a has-many
  relationship.

  The `ManyArray` is instantiated lazily the first time the relationship is
  requested.

  ### Inverses

  Often, the relationships in Ember Data applications will have
  an inverse. For example, imagine the following models are
  defined:

  ```javascript
  App.Post = DS.Model.extend({
    comments: DS.hasMany('comment')
  });

  App.Comment = DS.Model.extend({
    post: DS.belongsTo('post')
  });
  ```

  If you created a new instance of `App.Post` and added
  a `App.Comment` record to its `comments` has-many
  relationship, you would expect the comment's `post`
  property to be set to the post that contained
  the has-many.

  We call the record to which a relationship belongs the
  relationship's _owner_.

  @class ManyArray
  @namespace DS
  @extends DS.RecordArray
*/
export default RecordArray.extend({
  init: function() {
    this._super.apply(this, arguments);
  },

  /**
    The property name of the relationship

    @property {String} name
    @private
  */
  name: null,

  /**
    The record to which this relationship belongs.

    @property {DS.Model} owner
    @private
  */
  owner: null,

  /**
    `true` if the relationship is polymorphic, `false` otherwise.

    @property {Boolean} isPolymorphic
    @private
  */
  isPolymorphic: false,

  // LOADING STATE

  isLoaded: false,

   /**
     The relationship which manages this array.

     @property {DS.Model} owner
     @private
   */

  relationship: null,

  /**
    Used for async `hasMany` arrays
    to keep track of when they will resolve.

    @property {Ember.RSVP.Promise} promise
    @private
  */
  promise: null,

  /**
    @method loadingRecordsCount
    @param {Number} count
    @private
  */
  loadingRecordsCount: function(count) {
    this.loadingRecordsCount = count;
  },

  /**
    @method loadedRecord
    @private
  */
  loadedRecord: function() {
    this.loadingRecordsCount--;
    if (this.loadingRecordsCount === 0) {
      set(this, 'isLoaded', true);
      this.trigger('didLoad');
    }
  },

  replaceContent: function(idx, amt, objects){
    var records;
    if (amt > 0){
      records = get(this, 'content').slice(idx, idx+amt);
      this.get('relationship').removeRecords(records);
    }
    if (objects){
      this.get('relationship').addRecords(objects, idx);
    }
  },

  /**
    Create a child record within the owner

    @method createRecord
    @private
    @param {Object} hash
    @return {DS.Model} record
  */
  createRecord: function(hash) {
    var store = get(this, 'store');
    var type = get(this, 'type');
    var record;

    Ember.assert("You cannot add '" + type.typeKey + "' records to this polymorphic relationship.", !get(this, 'isPolymorphic'));

    record = store.createRecord.call(store, type, hash);
    this.pushObject(record);

    return record;
  }
});
<commit_msg>removed private unused properties in ManyArray<commit_after>import RecordArray from "ember-data/system/record_arrays/record_array";

/**
  @module ember-data
*/

var get = Ember.get, set = Ember.set;

/**
  A `ManyArray` is a `RecordArray` that represents the contents of a has-many
  relationship.

  The `ManyArray` is instantiated lazily the first time the relationship is
  requested.

  ### Inverses

  Often, the relationships in Ember Data applications will have
  an inverse. For example, imagine the following models are
  defined:

  ```javascript
  App.Post = DS.Model.extend({
    comments: DS.hasMany('comment')
  });

  App.Comment = DS.Model.extend({
    post: DS.belongsTo('post')
  });
  ```

  If you created a new instance of `App.Post` and added
  a `App.Comment` record to its `comments` has-many
  relationship, you would expect the comment's `post`
  property to be set to the post that contained
  the has-many.

  We call the record to which a relationship belongs the
  relationship's _owner_.

  @class ManyArray
  @namespace DS
  @extends DS.RecordArray
*/
export default RecordArray.extend({
  init: function() {
    this._super.apply(this, arguments);
  },

  /**
    `true` if the relationship is polymorphic, `false` otherwise.

    @property {Boolean} isPolymorphic
    @private
  */
  isPolymorphic: false,

  // LOADING STATE

  isLoaded: false,

   /**
     The relationship which manages this array.

     @property {DS.Model} owner
     @private
   */

  relationship: null,

  /**
    Used for async `hasMany` arrays
    to keep track of when they will resolve.

    @property {Ember.RSVP.Promise} promise
    @private
  */
  promise: null,

  /**
    @method loadingRecordsCount
    @param {Number} count
    @private
  */
  loadingRecordsCount: function(count) {
    this.loadingRecordsCount = count;
  },

  /**
    @method loadedRecord
    @private
  */
  loadedRecord: function() {
    this.loadingRecordsCount--;
    if (this.loadingRecordsCount === 0) {
      set(this, 'isLoaded', true);
      this.trigger('didLoad');
    }
  },

  replaceContent: function(idx, amt, objects){
    var records;
    if (amt > 0){
      records = get(this, 'content').slice(idx, idx+amt);
      this.get('relationship').removeRecords(records);
    }
    if (objects){
      this.get('relationship').addRecords(objects, idx);
    }
  },

  /**
    Create a child record within the owner

    @method createRecord
    @private
    @param {Object} hash
    @return {DS.Model} record
  */
  createRecord: function(hash) {
    var store = get(this, 'store');
    var type = get(this, 'type');
    var record;

    Ember.assert("You cannot add '" + type.typeKey + "' records to this polymorphic relationship.", !get(this, 'isPolymorphic'));

    record = store.createRecord.call(store, type, hash);
    this.pushObject(record);

    return record;
  }
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux'
import { push } from 'connected-react-router';

import { selectors } from '@openchemistry/redux'
import { molecules } from '@openchemistry/redux'

import { isNil } from 'lodash-es';

import Molecules from '../components/molecules';

class MoleculesContainer extends Component {

  componentDidMount() {
    var options = { limit: 25, offset: 0, sort: '_id', sortDir: -1 }
    this.props.dispatch(molecules.loadMolecules(options));
  }

  onOpen = (inchikey) => {
    this.props.dispatch(push(`/molecules/inchikey/${inchikey}`));
  }

  render() {
    const { molecules } = this.props;
    if (isNil(molecules)) {
      return null;
    }
    return (
      <Molecules molecules={molecules} onOpen={this.onOpen} />
    );
  }
}

MoleculesContainer.propTypes = {
}

MoleculesContainer.defaultProps = {
}

function mapStateToProps(state, ownProps) {
  let molecules = selectors.molecules.getMolecules(state);
  return { molecules };
}

export default connect(mapStateToProps)(MoleculesContainer)
<commit_msg>Make `sortDir` all lowercase<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux'
import { push } from 'connected-react-router';

import { selectors } from '@openchemistry/redux'
import { molecules } from '@openchemistry/redux'

import { isNil } from 'lodash-es';

import Molecules from '../components/molecules';

class MoleculesContainer extends Component {

  componentDidMount() {
    var options = { limit: 25, offset: 0, sort: '_id', sortdir: -1 }
    this.props.dispatch(molecules.loadMolecules(options));
  }

  onOpen = (inchikey) => {
    this.props.dispatch(push(`/molecules/inchikey/${inchikey}`));
  }

  render() {
    const { molecules } = this.props;
    if (isNil(molecules)) {
      return null;
    }
    return (
      <Molecules molecules={molecules} onOpen={this.onOpen} />
    );
  }
}

MoleculesContainer.propTypes = {
}

MoleculesContainer.defaultProps = {
}

function mapStateToProps(state, ownProps) {
  let molecules = selectors.molecules.getMolecules(state);
  return { molecules };
}

export default connect(mapStateToProps)(MoleculesContainer)
<|endoftext|>


<commit_before>/**
 * Define an API-Umbrella specific Error type
 * This error prototypally inherits from the Error constructor.
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
 */
ApiUmbrellaError = function (messageOrError) {
  this.name = 'ApiUmbrellaError';
  this.message = messageOrError.message || messageOrError || 'ApiUmbrellaError';
  // Parses HTTP.error containing a string message
  // Ex:
  //  'failed [422] {"errors":{"backend_protocol":["is not included in the list"]}'
  var parseErrorMessage = /failed \[(\d+)\] ({.+})/.exec(this.message);
  if (typeof(parseErrorMessage) === 'object' &&
      parseErrorMessage.length === 5) {
    // Assigns the http_status number, e.g. 422
    this.http_status = JSON.parse(parsedErrorMessage[1]);

    // Assigns the backend_errors as JSON, e.g. {"backend_protocol":["is not included in the list"]}
    this.backend_errors = JSON.parse(parsedErrorMessage[2].errors);
  } else {
    this.http_status = 'undefined';
    this.backend_errors = 'undefined';
  }
  this.stack = (new Error()).stack;
}
ApiUmbrellaError.prototype = Object.create(Error.prototype);
ApiUmbrellaError.prototype.constructor = ApiUmbrellaError;
<commit_msg>Improve ApiUmbrellaError constructor.<commit_after>/**
 * Define an API-Umbrella specific Error type
 * This error prototypally inherits from the Error constructor.
 * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
 *
 * @constructor
 * @param {object|string} originalError - Original HTTP.call error thrown.
 */
ApiUmbrellaError = function (originalError) {
  if (originalError.message) {
    // originalError should be an Error object, with message attribute.
    this.message = originalError.message;
  } else {
    // if it is not an Error, assumes it is a string with the error message.
    this.message = originalError;
  }

  // Parses the message returned by api-umbrella backend and captured by HTTP.call
  // Ex:
  //  'failed [422] {"errors":{"backend_protocol":["is not included in the list"]}'
  var parseErrorMessage = /failed \[(\d+)\] ({.+})/.exec(this.message);
  if (typeof(parseErrorMessage) === 'object' &&
      parseErrorMessage.length === 5) {
    // Only changes the Error name if its message got parsed.
    this.name = 'ApiUmbrellaError';

    // Assigns the http_status number, e.g. 422
    this.http_status = JSON.parse(parsedErrorMessage[1]);

    // Assigns the backend_errors as JSON, e.g. {"backend_protocol":["is not included in the list"]}
    this.backend_errors = JSON.parse(parsedErrorMessage[2].errors);
  }
  this.stack = (new Error()).stack;
}
ApiUmbrellaError.prototype = Object.create(Error.prototype);
ApiUmbrellaError.prototype.constructor = ApiUmbrellaError;
<|endoftext|>


<commit_before>class VideoRendererController {
  constructor($timeout, $rootScope) {
    this.$timeout = $timeout;
    this.$rootScope = $rootScope;
    this.listenEvent();
    this.listenConnectionChangeOrder();
  }

  listenConnectionChangeOrder() {
    this.$rootScope.$on('connection:on', () => {
      if (!this.$rootScope.vidyoConnector) {
        this.loadVidyoClientLibrary();
      } else {
        this.connectVidyo(this.$rootScope.vidyoConnector);
      }
    });

    this.$rootScope.$on('connection:off', () => {
      this.disconnectVidyo(this.$rootScope.vidyoConnector);
    });

    this.$rootScope.$on('micMute:on', () => {
      this.$rootScope.vidyoConnector.SetMicrophonePrivacy(true);
    });

    this.$rootScope.$on('micMute:off', () => {
      this.$rootScope.vidyoConnector.SetMicrophonePrivacy(false);
    });

    this.$rootScope.$on('cameraMute:on', () => {
      this.$rootScope.vidyoConnector.SetCameraPrivacy(true);
    });

    this.$rootScope.$on('cameraMute:off', () => {
      this.$rootScope.vidyoConnector.SetCameraPrivacy(false);
    });
  }

  listenEvent() {
    document.addEventListener('vidyoclient:ready', (e) => {
      this.renderVideo(e.detail);
    });
  }

  renderVideo(VC) {
    this.$timeout(() => {
      VC.CreateVidyoConnector({
        viewId: "renderer",                            // Div ID where the composited video will be rendered, see VidyoConnector.html
        viewStyle: "VIDYO_CONNECTORVIEWSTYLE_Default", // Visual style of the composited renderer
        remoteParticipants: 16,                        // Maximum number of participants
        logFileFilter: "warning all@VidyoConnector info@VidyoClient",
        logFileName:"",
        userData:""
      }).then((vidyoConnector) => {
        this.$rootScope.vidyoConnector = vidyoConnector;
        this.connectVidyo(vidyoConnector);
      }).catch(() => {
        console.error("CreateVidyoConnector Failed");
      });
    });
  }

  loadVidyoClientLibrary() {
		var script = document.createElement('script');
		script.type = 'text/javascript';
		script.src = 'https://static.vidyo.io/4.1.11.4/javascript/VidyoClient/VidyoClient.js?onload=onVidyoClientLoaded';
		document.getElementsByTagName('head')[0].appendChild(script);
	}

  disconnectVidyo(vidyoConnector) {
    vidyoConnector.Disconnect();
  }

  connectVidyo(vidyoConnector) {
    console.log('tttt',this.$rootScope.user.token);
    console.log('tttt',this.$rootScope.user.name);
    console.log('tttt',this.$rootScope.user.roomId);

    vidyoConnector.Connect({
      host: "prod.vidyo.io",
      token: this.$rootScope.user.token ||"cHJvdmlzaW9uAHRlc3R1c2VyQGU4ZDlhMy52aWR5by5pbwA2MzY2MTgzMDM1MwAAYmJlNjIwMzU1YjlkOWFhMmVmMjYxODZmYjYyMDRmYzI1NjJmMTdjNTU5YzgxNGMxNDkwMmU0N2FhYzI2ZjJiNWI0ZGM0MWFmNmM4Y2I1Y2Y5ZTkxZmMxZTA2Njc1OTY2",
      displayName: this.$rootScope.user.name || 'testuser',
      resourceId: this.$rootScope.user.roomId || 'KPDemoRoom',

      onSuccess: () => {
        /* Connected */
        console.log('connected!');
        this.$rootScope.$broadcast('connectedStatus', { isConnected: true });
      },
      onFailure: (reason) => {
        /* Failed */
        console.log('failed! The reason: ', reason);
      },
      onDisconnected: (reason) => {
        /* Disconnected */
        console.log('disconnected! Reason: ', reason);
        this.$rootScope.$broadcast('connectedStatus', { isConnected: false });
      }
    }).then((status) => {
      if (status) {
        this.handlePaticipants(vidyoConnector);
        this.receiveMessage(vidyoConnector);
      } else {
        console.error("ConnectCall Failed");
      }
    }).catch(() => {
      console.error("ConnectCall Failed");
    });
  }

  receiveMessage(vidyoConnector) {
    vidyoConnector.RegisterMessageEventListener({
      onChatMessageReceived: (participant, chatMessage) => {
        console.log('********', chatMessage);
        this.onSendMessage({ id: participant.id, name: participant.name, content: chatMessage.body });
      }
    }).then(() => {
      console.log("RegisterParticipantEventListener Success");
    }).catch(() => {
      console.err("RegisterParticipantEventListener Failed");
    });
  }

  handlePaticipants(vidyoConnector) {
    vidyoConnector.RegisterParticipantEventListener(
      {
        onJoined: (participant) => {
          console.log('Joined', participant);
          this.onAddUser({ id:participant.id, name:participant.name });
        },
        onLeft: (participant) => {
          console.log('Left', participant);
          this.onRemoveUser({ id:participant.id, name:participant.name });
        },
        onDynamicChanged: (participants, cameras) => { /* Ordered array of participants according to rank */ },
        onLoudestChanged: (participant, audioOnly) => { /* Current loudest speaker */ }
      }
    ).then(() => {
      console.log("RegisterParticipantEventListener Success");
    }).catch(() => {
      console.err("RegisterParticipantEventListener Failed");
    });
  }
}

VideoRendererController.$inject = ['$timeout', '$rootScope'];

export default VideoRendererController;
<commit_msg>Loading vidyo library right away<commit_after>class VideoRendererController {
  constructor($timeout, $rootScope) {
    this.$timeout = $timeout;
    this.$rootScope = $rootScope;
    this.listenEvent();
    this.listenConnectionChangeOrder();
    this.loadVidyoClientLibrary();
  }

  listenConnectionChangeOrder() {
    this.$rootScope.$on('connection:on', () => {
      if (!this.$rootScope.vidyoConnector) {
        this.loadVidyoClientLibrary();
      } else {
        this.connectVidyo(this.$rootScope.vidyoConnector);
      }
    });

    this.$rootScope.$on('connection:off', () => {
      this.disconnectVidyo(this.$rootScope.vidyoConnector);
    });

    this.$rootScope.$on('micMute:on', () => {
      this.$rootScope.vidyoConnector.SetMicrophonePrivacy(true);
    });

    this.$rootScope.$on('micMute:off', () => {
      this.$rootScope.vidyoConnector.SetMicrophonePrivacy(false);
    });

    this.$rootScope.$on('cameraMute:on', () => {
      this.$rootScope.vidyoConnector.SetCameraPrivacy(true);
    });

    this.$rootScope.$on('cameraMute:off', () => {
      this.$rootScope.vidyoConnector.SetCameraPrivacy(false);
    });
  }

  listenEvent() {
    document.addEventListener('vidyoclient:ready', (e) => {
      this.renderVideo(e.detail);
    });
  }

  renderVideo(VC) {
    this.$timeout(() => {
      VC.CreateVidyoConnector({
        viewId: "renderer",                            // Div ID where the composited video will be rendered, see VidyoConnector.html
        viewStyle: "VIDYO_CONNECTORVIEWSTYLE_Default", // Visual style of the composited renderer
        remoteParticipants: 16,                        // Maximum number of participants
        logFileFilter: "warning all@VidyoConnector info@VidyoClient",
        logFileName:"",
        userData:""
      }).then((vidyoConnector) => {
        this.$rootScope.vidyoConnector = vidyoConnector;
        //this.connectVidyo(vidyoConnector);
      }).catch(() => {
        console.error("CreateVidyoConnector Failed");
      });
    });
  }

  loadVidyoClientLibrary() {
		var script = document.createElement('script');
		script.type = 'text/javascript';
		script.src = 'https://static.vidyo.io/4.1.11.4/javascript/VidyoClient/VidyoClient.js?onload=onVidyoClientLoaded';
		document.getElementsByTagName('head')[0].appendChild(script);
	}

  disconnectVidyo(vidyoConnector) {
    vidyoConnector.Disconnect();
  }

  connectVidyo(vidyoConnector) {
    console.log('tttt',this.$rootScope.user.token);
    console.log('tttt',this.$rootScope.user.name);
    console.log('tttt',this.$rootScope.user.roomId);

    vidyoConnector.Connect({
      host: "prod.vidyo.io",
      token: this.$rootScope.user.token ||"cHJvdmlzaW9uAHRlc3R1c2VyQGU4ZDlhMy52aWR5by5pbwA2MzY2MTgzMDM1MwAAYmJlNjIwMzU1YjlkOWFhMmVmMjYxODZmYjYyMDRmYzI1NjJmMTdjNTU5YzgxNGMxNDkwMmU0N2FhYzI2ZjJiNWI0ZGM0MWFmNmM4Y2I1Y2Y5ZTkxZmMxZTA2Njc1OTY2",
      displayName: this.$rootScope.user.name || 'testuser',
      resourceId: this.$rootScope.user.roomId || 'KPDemoRoom',

      onSuccess: () => {
        /* Connected */
        console.log('connected!');
        this.$rootScope.$broadcast('connectedStatus', { isConnected: true });
      },
      onFailure: (reason) => {
        /* Failed */
        console.log('failed! The reason: ', reason);
      },
      onDisconnected: (reason) => {
        /* Disconnected */
        console.log('disconnected! Reason: ', reason);
        this.$rootScope.$broadcast('connectedStatus', { isConnected: false });
      }
    }).then((status) => {
      if (status) {
        this.handlePaticipants(vidyoConnector);
        this.receiveMessage(vidyoConnector);
      } else {
        console.error("ConnectCall Failed");
      }
    }).catch(() => {
      console.error("ConnectCall Failed");
    });
  }

  receiveMessage(vidyoConnector) {
    vidyoConnector.RegisterMessageEventListener({
      onChatMessageReceived: (participant, chatMessage) => {
        console.log('********', chatMessage);
        this.onSendMessage({ id: participant.id, name: participant.name, content: chatMessage.body });
      }
    }).then(() => {
      console.log("RegisterParticipantEventListener Success");
    }).catch(() => {
      console.err("RegisterParticipantEventListener Failed");
    });
  }

  handlePaticipants(vidyoConnector) {
    vidyoConnector.RegisterParticipantEventListener(
      {
        onJoined: (participant) => {
          console.log('Joined', participant);
          this.onAddUser({ id:participant.id, name:participant.name });
        },
        onLeft: (participant) => {
          console.log('Left', participant);
          this.onRemoveUser({ id:participant.id, name:participant.name });
        },
        onDynamicChanged: (participants, cameras) => { /* Ordered array of participants according to rank */ },
        onLoudestChanged: (participant, audioOnly) => { /* Current loudest speaker */ }
      }
    ).then(() => {
      console.log("RegisterParticipantEventListener Success");
    }).catch(() => {
      console.err("RegisterParticipantEventListener Failed");
    });
  }
}

VideoRendererController.$inject = ['$timeout', '$rootScope'];

export default VideoRendererController;
<|endoftext|>


<commit_before>import {Plugin, PluginKey} from "prosemirror-state"
import {READ_ONLY_ROLES, COMMENT_ONLY_ROLES} from "../.."

const key = new PluginKey('accessRights')

export let accessRightsPlugin = function(options) {
    return new Plugin({
        key,
        filterTransaction: (transaction, state) => {
            let allowed = true
            let remote = transaction.getMeta('remote')
            let filterFree = transaction.getMeta('filterFree')
            if (remote || filterFree) {
                return allowed
            }

            if (
                COMMENT_ONLY_ROLES.includes(this.mod.editor.docInfo.access_rights) ||
                READ_ONLY_ROLES.includes(this.mod.editor.docInfo.access_rights)
            ) {
                allowed = false
            }

            if (transaction.docs.length && transaction.docs[0].childCount !== transaction.doc.childCount) {
                allowed = false
            }

            return allowed
        }
    })
}
<commit_msg>fix editor link<commit_after>import {Plugin, PluginKey} from "prosemirror-state"
import {READ_ONLY_ROLES, COMMENT_ONLY_ROLES} from "../.."

const key = new PluginKey('accessRights')

export let accessRightsPlugin = function(options) {
    return new Plugin({
        key,
        filterTransaction: (transaction, state) => {
            let allowed = true
            let remote = transaction.getMeta('remote')
            let filterFree = transaction.getMeta('filterFree')
            if (remote || filterFree) {
                return allowed
            }

            if (
                COMMENT_ONLY_ROLES.includes(options.editor.docInfo.access_rights) ||
                READ_ONLY_ROLES.includes(options.editor.docInfo.access_rights)
            ) {
                allowed = false
            }

            if (transaction.docs.length && transaction.docs[0].childCount !== transaction.doc.childCount) {
                allowed = false
            }

            return allowed
        }
    })
}
<|endoftext|>


<commit_before>define([
  'app',
  'utils/chartHelpers',
  'utils/duration',
  'utils/escapeHtml'
], function(app, chartHelpers, duration, escapeHtml) {
  'use strict';

  return {
    parent: 'project_details',
    url: 'tests/:test_id/',
    templateUrl: 'partials/project-test-details.html',
    controller: function($scope, $state, testData, historicalData) {
      var chart_options = {
          linkFormatter: function(item) {
            return $state.href('build_details', {build_id: item.job.build.id});
          },
          tooltipFormatter: function(item) {
            var content = '';
            var build = item.job.build;

            content += '
';
            content += escapeHtml(build.name);
            content += '
';
            content += escapeHtml(build.target);
            if (build.author) {
              content += ' — ' + build.author.name;
            }
            content += '';
            content += '
';
            content += '
Test ' + item.result.name;
            if (item.duration) {
              content += ' in ' + duration(item.duration);
            }
            content += ' (Build ' + build.result.name + ')
';

            return content;
          }
        };

      $scope.test = testData;
      $scope.results = historicalData;
      $scope.chartData = chartHelpers.getChartData($scope.results, null, chart_options);
    },
    resolve: {
      testData: function($http, $stateParams, projectData) {
        return $http.get('/api/0/projects/' + projectData.id + '/tests/' + $stateParams.test_id + '/').then(function(response){
          return response.data;
        });
      },
      historicalData: function($http, $stateParams, projectData) {
        return $http.get('/api/0/projects/' + projectData.id + '/tests/' + $stateParams.test_id + '/history/').then(function(response){
          return response.data;
        });
      }
    }
  };
});
<commit_msg>Add explicit historical limit<commit_after>define([
  'app',
  'utils/chartHelpers',
  'utils/duration',
  'utils/escapeHtml'
], function(app, chartHelpers, duration, escapeHtml) {
  'use strict';

  var HISTORICAL_ITEMS = 100;

  return {
    parent: 'project_details',
    url: 'tests/:test_id/',
    templateUrl: 'partials/project-test-details.html',
    controller: function($scope, $state, testData, historicalData) {
      var chart_options = {
          linkFormatter: function(item) {
            return $state.href('build_details', {build_id: item.job.build.id});
          },
          tooltipFormatter: function(item) {
            var content = '';
            var build = item.job.build;

            content += '
';
            content += escapeHtml(build.name);
            content += '
';
            content += escapeHtml(build.target);
            if (build.author) {
              content += ' — ' + build.author.name;
            }
            content += '';
            content += '
';
            content += '
Test ' + item.result.name;
            if (item.duration) {
              content += ' in ' + duration(item.duration);
            }
            content += ' (Build ' + build.result.name + ')
';

            return content;
          },
          limit: HISTORICAL_ITEMS
        };

      $scope.test = testData;
      $scope.results = historicalData;
      $scope.chartData = chartHelpers.getChartData($scope.results, null, chart_options);
    },
    resolve: {
      testData: function($http, $stateParams, projectData) {
        return $http.get('/api/0/projects/' + projectData.id + '/tests/' + $stateParams.test_id + '/').then(function(response){
          return response.data;
        });
      },
      historicalData: function($http, $stateParams, projectData) {
        return $http.get('/api/0/projects/' + projectData.id + '/tests/' + $stateParams.test_id + '/history/?per_page=' + HISTORICAL_ITEMS).then(function(response){
          return response.data;
        });
      }
    }
  };
});
<|endoftext|>


<commit_before>//check if need relogin
if(document.getElementById('UserID')){
    window.location.href = 'https://cas.coloradocollege.edu/cas/login?service=https%3A%2F%2Fbanssop.coloradocollege.edu%3A443%2Fssomanager%2Fc%2FSSB';
}

//create menu table
{
    var table = document.createElement('table');
    table.setAttribute('class', 'menu-table');
    var table_container = document.createElement('div');
    document.body.appendChild(table_container);
    table_container.appendChild(table);
    table.appendChild(document.createElement('tbody'));

    var fst = false;
    $('.menuplaintable').eq(0).find('tr').each(function() {
        tr = $(this);
        var a = tr.find('a').last();
        var href = a.attr('href');
        var title = a.text();
        var desc = tr.find('span.menulinkdesctext').first().text().replace(/$\s*/, '');

        var row;
        if(fst){
            fst = false;
            row = table.rows[table.rows.length - 1];
        }else{
            fst = true;
            row = table.insertRow(-1);
        }
        var div = document.createElement('div');
        div.innerHTML = `<a class="list" href="${href}"> <div class="list-container"> <div class="list-title">${title}</div> <div class="list-description">${desc}</div> </div> </a>`;
        var cell = row.insertCell(0);
        cell.setAttribute('class', 'menu-cell');
        cell.appendChild(div);
    });
}

//load easier cc tool -> on_tool_loaded()
function load_tool(){
    var container = document.createElement('div');
    var cell = table.insertRow(0).insertCell(0);
    $(cell).attr('colspan', 2).html('

');
    $('#cceasier-tool').toggle().load(chrome.runtime.getURL('html/tool_div.html'), on_tool_loaded);
}

load_tool();

function download(filename, text) {
    var element = document.createElement('a');
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    element.setAttribute('download', filename);

    element.style.display = 'none';
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);
}

function show_modal_window(schedule) {
    //preprocess data
    {
        //sieve out duplicated courses
        var courses = $('#course_pool').val().split(',');
        var hash = {};
        $.each(courses, function () { hash[this] = true; });
        courses = [];
        $.each(hash, function (k, v) { courses.push(k); });

        var departs = {};
        $.each(courses, function () {
            var course_code = this;
            if (schedule[course_code] == null) return;
            var depart_code = course_code.slice(0, 2);
            if (departs[depart_code] == null) departs[depart_code] = [[], [], [], [], [], [], [], []];
            $.each(schedule[course_code], function () {
                var block = parseInt(this['block']);
                if (isNaN(block)) return;
                departs[depart_code][block - 1].push(this);
            });
        });
    }

    //if no valid courses
    if(Object.keys(departs).length == 0) {
        $('#course_pool').css('transition', '200ms');
        $('#course_pool').css('background-color', '#ffcdd2');
        setTimeout(function(){
            $('#course_pool').css('transition', '200ms');
            $('#course_pool').css('background-color', 'transparent');
        }, 200);
        return;
    }

    //build table, build export array
    {
        var modal_table = $('#result_modal_table')[0];
        modal_table.children[0].innerHTML = '';
        for (i = 0; i < 9; i++) modal_table.insertRow(-1);
        for (i = 1; i < 9; i++) {
            var cell = modal_table.rows[i].insertCell(-1);
            cell.innerText = i;
        }
        modal_table.rows[0].insertCell(-1);

        var export_arr = [[''],['1'],['2'],['3'],['4'],['5'],['6'],['7'],['8']];

        var depart2name = { "AN": "Anthropology", "AR": "Arabic", "AH": "Art History", "AS": "Art Studio", "PA": "Asian Studies", "BY": "Biology", "CH": "Chemistry", "CN": "Chinese Language", "CL": "Classics", "CO": "Comparative Literature", "CP": "Computer Science", "DS": "Dance Studio", "DA": "Dance Theory", "EC": "Economics", "ED": "Education", "EN": "English", "EV": "Environmental Program", "FG": "Feminist & Gender Studies", "FM": "Film and Media Studies", "FS": "Film Studies", "FR": "French", "GS": "General Studies", "GY": "Geology", "GR": "German", "HE": "Hebrew", "HY": "History", "HK": "Human Biology and Kinesiology", "IT": "Italian", "JA": "Japanese", "MA": "Mathematics", "MB": "Molecular Biology", "MU": "Music", "BE": "Organismal Biology and Ecology", "PH": "Philosophy", "PC": "Physics", "PS": "Political Science", "PG": "Portuguese", "PY": "Psychology", "RM": "Race, Ethnicity, and Migration", "RE": "Religion", "RU": "Russian", "RS": "Russian & Eurasian Studies", "SO": "Sociology", "SW": "Southwest Studies", "SP": "Spanish", "HS": "Studies in Humanities", "NS": "Studies in Natural Science", "TH": "Theatre" };
        $.each(departs, function (depart, blocks) {
            var cell = modal_table.rows[0].insertCell(-1);
            var depart_name = depart2name[depart];
            cell.innerText = depart_name;
            export_arr[0].push(depart_name);
            var max_len = Math.max(...$(blocks).map((_,x)=>x.length));
            for(i=1;i<max_len;i++) export_arr[0].push('');
            for (j = 0; j < 8; j++) {
                var cell = modal_table.rows[j + 1].insertCell(-1);
                cell.innerHTML = '

';
                var container_row = cell.children[0].children[0].children[0];
                $.each(blocks[j], function () {
                    export_arr[j+1].push(`${this['course_no']} (${this['available']}/${this['limit']}, ${this['waitlist']}, ${this['reserved']})`);
                    var card_container = container_row.insertCell(-1);
                    card_container.innerHTML = `<h3>${this['course_no']}<h3><br>${this['available']}/${this['limit']} (<small>${this['waitlist']}</small>, <small>${this['reserved']}</small>)`
                });
                for(i=blocks[j].length;i<max_len;i++) export_arr[j+1].push('');
            }
        });
    }
    //export
    {
        $('#btn_export').click(function(){
            csv = new CSV(export_arr).encode();
            download('course-schedule.csv', csv);
        });
    }
    $('[data-remodal-id=result_modal]').remodal().open();
}

function on_tool_loaded(){
    //create cc easer tool toggler
    {
        var container = document.createElement('div');
        var cell = table.insertRow(0).insertCell(0);
        $(cell).attr('colspan', 2).attr('class', 'menu-cell');
        cell.appendChild(container);
        container.innerHTML = `

Easier CC Banner Course Scheduler

Scheduling courses has never been easier.

 `;
        $(container.children[0]).click(function () {
            $('#cceasier-tool').slideToggle();
        });
    }

    //course scheduler style
    {
        $("#course_pool").focus(function () {
            $(".dropdown-menu").css('display', 'block');
            $(".dropdown-menu").addClass("hover-over-boxshadow");
            $("#course_pool").addClass("hover-over-boxshadow");
        });
        $("#course_pool").blur(function () {
            $(".dropdown-menu").css('display', 'none');
            $(".dropdown-menu").removeClass("hover-over-boxshadow");
            $("#course_pool").removeClass("hover-over-boxshadow");
        });
        var arrowImgUrl = chrome.runtime.getURL('img/arrow.png');
        $("#course_pool_confirm").append('');
    }

    //confirm button positioning
    $('#course_pool_confirm').css('left',($(window).width()*0.75-35-25).toString()+'px' );
    //console.log('b'+$(document.body).width());
    //console.log("before: "+($($(document.body).width()).toString()+'px'));
    //console.log( ($(document.body).width()*0.75-20-25).toString());

    $( window ).resize(function() {
        $('#course_pool_confirm').css('left',($(window).width()*0.75-35-25).toString()+'px' );
        console.log('a'+$(document.body).width());
        //console.log("after: "+($($(document.body).width()).toString()+'px'));
    });

    //transition & progress bar
    {
        $('#course_pool').css('background-color', '#b5b5b5 !important');
        var start_time = new Date().getTime();
        window.progressTimer = setInterval(function () {
            var t = (new Date().getTime() - start_time) / 1000;
            var p = 100 * (1 - Math.pow(0.85, t));
            $('#loading_bar').css('width', p + "%").css('width', '+=5px');
        }, 20);
        $('#cceasier-tool *').prop('disabled', true);
    }

    get_schedule(on_schedule_loaded);

    $(document.head).append(`<link rel="stylesheet" href="${chrome.runtime.getURL('style/main.css')}">`); //TODO: change injection
}

function on_schedule_loaded(schedule) {
    //transition & progress bar
    {
        clearInterval(window.progressTimer);
        setTimeout(function () {
            $('#loading_bar').css('width', '100%').css('width', '+=5px');
            $('#loading_bar').css('transition', '0.3s');
            $('#loading_bar').css('background-color', 'transparent');
            $('#course_pool').css('transition', '1s');
            $('#course_pool').css('background-color', 'transparent');
        }, 1000);
        $('#cceasier-tool *').prop('disabled', false);
    }

    //preprocess schedule data
    {
        var course_list = [];
        var instructor_sum = {};
        $.each(schedule, function () {
            var prof = '';
            var hash = {};
            $.each(schedule[this[0]['course_no']], function () {
                if (hash[this['instructor']] == null) {
                    prof += this['instructor'] + ', ';
                    hash[this['instructor']] = true;
                }
            });
            prof = prof.slice(0, -2);
            course_list.push({
                "course_code": this[0]["course_no"],
                "course_title": this[0]["course_title"],
                "instructor": prof
            });
            instructor_sum[this[0]['course_no']] = prof;
        });
    }

    var fuse = new Fuse(course_list, {
        shouldSort: true,
        threshold: 0.4,
        location: 0,
        distance: 100,
        maxPatternLength: 32,
        minMatchCharLength: 2,
        keys: [
            "course_code",
            "instructor",
            "course_title"]
    });

    new Textcomplete(new Textcomplete.editors.Textarea(document.getElementById('course_pool'))).register([
        {
            match: /(^|,)([^,]+)$/,
            search: function (term, callback) {
                if(/([A-Z][A-Z]|[a-z][a-z])\d{0,3}$/.test(term)){
                    term = term.toUpperCase();
                    var ans = [];
                    for(i=0;i<course_list.length;i++){
                        if(course_list[i]['course_code'].startsWith(term)){
                            ans.push(course_list[i]['course_code']);
                            if(ans.length >= 8) break;
                        }
                    }
                    callback(ans);
                    return;
                }
                var result = fuse.search(term);
                result = result.slice(0, 8);
                var match = [];
                $.each(result, function () { match.push(this['course_code']); });
                callback(match);
            },
            template: function (course_code) {
                var title = schedule[course_code][0]['course_title'].replace(/(\[.*\])/g, '$1').replace(/(\(.*\))/g, '$1');
                return `<b>${course_code}</b> <small>(${instructor_sum[course_code]})</small><br>${title}`
            },
            replace: function (course_code) {
                return '$1' + course_code + ',';
            }
        }
    ]);

    //modal window event
    {
        $('#course_pool_confirm').click(function () { show_modal_window(schedule) });
        key('ctrl+enter', function () {
            if ($('#course_pool').is(':focus')) show_modal_window(schedule);
        });
        key.filter = ev => true;
    }
}

//remove the orignal menu
$(document.body.children[1]).remove();

<commit_msg>fix capitalize bug<commit_after>//check if need relogin
if(document.getElementById('UserID')){
    window.location.href = 'https://cas.coloradocollege.edu/cas/login?service=https%3A%2F%2Fbanssop.coloradocollege.edu%3A443%2Fssomanager%2Fc%2FSSB';
}

//create menu table
{
    var table = document.createElement('table');
    table.setAttribute('class', 'menu-table');
    var table_container = document.createElement('div');
    document.body.appendChild(table_container);
    table_container.appendChild(table);
    table.appendChild(document.createElement('tbody'));

    var fst = false;
    $('.menuplaintable').eq(0).find('tr').each(function() {
        tr = $(this);
        var a = tr.find('a').last();
        var href = a.attr('href');
        var title = a.text();
        var desc = tr.find('span.menulinkdesctext').first().text().replace(/$\s*/, '');

        var row;
        if(fst){
            fst = false;
            row = table.rows[table.rows.length - 1];
        }else{
            fst = true;
            row = table.insertRow(-1);
        }
        var div = document.createElement('div');
        div.innerHTML = `<a class="list" href="${href}"> <div class="list-container"> <div class="list-title">${title}</div> <div class="list-description">${desc}</div> </div> </a>`;
        var cell = row.insertCell(0);
        cell.setAttribute('class', 'menu-cell');
        cell.appendChild(div);
    });
}

//load easier cc tool -> on_tool_loaded()
function load_tool(){
    var container = document.createElement('div');
    var cell = table.insertRow(0).insertCell(0);
    $(cell).attr('colspan', 2).html('

');
    $('#cceasier-tool').toggle().load(chrome.runtime.getURL('html/tool_div.html'), on_tool_loaded);
}

load_tool();

function download(filename, text) {
    var element = document.createElement('a');
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    element.setAttribute('download', filename);

    element.style.display = 'none';
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);
}

function show_modal_window(schedule) {
    //preprocess data
    {
        //sieve out duplicated courses
        var courses = $('#course_pool').val().split(',');
        var hash = {};
        $.each(courses, function () { hash[this] = true; });
        courses = [];
        $.each(hash, function (k, v) { courses.push(k); });

        var departs = {};
        $.each(courses, function () {
            var course_code = this;
            if (schedule[course_code] == null) return;
            var depart_code = course_code.slice(0, 2);
            if (departs[depart_code] == null) departs[depart_code] = [[], [], [], [], [], [], [], []];
            $.each(schedule[course_code], function () {
                var block = parseInt(this['block']);
                if (isNaN(block)) return;
                departs[depart_code][block - 1].push(this);
            });
        });
    }

    //if no valid courses
    if(Object.keys(departs).length == 0) {
        $('#course_pool').css('transition', '200ms');
        $('#course_pool').css('background-color', '#ffcdd2');
        setTimeout(function(){
            $('#course_pool').css('transition', '200ms');
            $('#course_pool').css('background-color', 'transparent');
        }, 200);
        return;
    }

    //build table, build export array
    {
        var modal_table = $('#result_modal_table')[0];
        modal_table.children[0].innerHTML = '';
        for (i = 0; i < 9; i++) modal_table.insertRow(-1);
        for (i = 1; i < 9; i++) {
            var cell = modal_table.rows[i].insertCell(-1);
            cell.innerText = i;
        }
        modal_table.rows[0].insertCell(-1);

        var export_arr = [[''],['1'],['2'],['3'],['4'],['5'],['6'],['7'],['8']];

        var depart2name = { "AN": "Anthropology", "AR": "Arabic", "AH": "Art History", "AS": "Art Studio", "PA": "Asian Studies", "BY": "Biology", "CH": "Chemistry", "CN": "Chinese Language", "CL": "Classics", "CO": "Comparative Literature", "CP": "Computer Science", "DS": "Dance Studio", "DA": "Dance Theory", "EC": "Economics", "ED": "Education", "EN": "English", "EV": "Environmental Program", "FG": "Feminist & Gender Studies", "FM": "Film and Media Studies", "FS": "Film Studies", "FR": "French", "GS": "General Studies", "GY": "Geology", "GR": "German", "HE": "Hebrew", "HY": "History", "HK": "Human Biology and Kinesiology", "IT": "Italian", "JA": "Japanese", "MA": "Mathematics", "MB": "Molecular Biology", "MU": "Music", "BE": "Organismal Biology and Ecology", "PH": "Philosophy", "PC": "Physics", "PS": "Political Science", "PG": "Portuguese", "PY": "Psychology", "RM": "Race, Ethnicity, and Migration", "RE": "Religion", "RU": "Russian", "RS": "Russian & Eurasian Studies", "SO": "Sociology", "SW": "Southwest Studies", "SP": "Spanish", "HS": "Studies in Humanities", "NS": "Studies in Natural Science", "TH": "Theatre" };
        $.each(departs, function (depart, blocks) {
            var cell = modal_table.rows[0].insertCell(-1);
            var depart_name = depart2name[depart];
            cell.innerText = depart_name;
            export_arr[0].push(depart_name);
            var max_len = Math.max(...$(blocks).map((_,x)=>x.length));
            for(i=1;i<max_len;i++) export_arr[0].push('');
            for (j = 0; j < 8; j++) {
                var cell = modal_table.rows[j + 1].insertCell(-1);
                cell.innerHTML = '

';
                var container_row = cell.children[0].children[0].children[0];
                $.each(blocks[j], function () {
                    export_arr[j+1].push(`${this['course_no']} (${this['available']}/${this['limit']}, ${this['waitlist']}, ${this['reserved']})`);
                    var card_container = container_row.insertCell(-1);
                    card_container.innerHTML = `<h3>${this['course_no']}<h3><br>${this['available']}/${this['limit']} (<small>${this['waitlist']}</small>, <small>${this['reserved']}</small>)`
                });
                for(i=blocks[j].length;i<max_len;i++) export_arr[j+1].push('');
            }
        });
    }
    //export
    {
        $('#btn_export').click(function(){
            csv = new CSV(export_arr).encode();
            download('course-schedule.csv', csv);
        });
    }
    $('[data-remodal-id=result_modal]').remodal().open();
}

function on_tool_loaded(){
    //create cc easer tool toggler
    {
        var container = document.createElement('div');
        var cell = table.insertRow(0).insertCell(0);
        $(cell).attr('colspan', 2).attr('class', 'menu-cell');
        cell.appendChild(container);
        container.innerHTML = `

Easier CC Banner Course Scheduler

Scheduling courses has never been easier.

 `;
        $(container.children[0]).click(function () {
            $('#cceasier-tool').slideToggle();
        });
    }

    //course scheduler style
    {
        $("#course_pool").focus(function () {
            $(".dropdown-menu").css('display', 'block');
            $(".dropdown-menu").addClass("hover-over-boxshadow");
            $("#course_pool").addClass("hover-over-boxshadow");
        });
        $("#course_pool").blur(function () {
            $(".dropdown-menu").css('display', 'none');
            $(".dropdown-menu").removeClass("hover-over-boxshadow");
            $("#course_pool").removeClass("hover-over-boxshadow");
        });
        var arrowImgUrl = chrome.runtime.getURL('img/arrow.png');
        $("#course_pool_confirm").append('');
    }

    //confirm button positioning
    $('#course_pool_confirm').css('left',($(window).width()*0.75-35-25).toString()+'px' );
    //console.log('b'+$(document.body).width());
    //console.log("before: "+($($(document.body).width()).toString()+'px'));
    //console.log( ($(document.body).width()*0.75-20-25).toString());

    $( window ).resize(function() {
        $('#course_pool_confirm').css('left',($(window).width()*0.75-35-25).toString()+'px' );
        console.log('a'+$(document.body).width());
        //console.log("after: "+($($(document.body).width()).toString()+'px'));
    });

    //transition & progress bar
    {
        $('#course_pool').css('background-color', '#b5b5b5 !important');
        var start_time = new Date().getTime();
        window.progressTimer = setInterval(function () {
            var t = (new Date().getTime() - start_time) / 1000;
            var p = 100 * (1 - Math.pow(0.85, t));
            $('#loading_bar').css('width', p + "%").css('width', '+=5px');
        }, 20);
        $('#cceasier-tool *').prop('disabled', true);
    }

    get_schedule(on_schedule_loaded);

    $(document.head).append(`<link rel="stylesheet" href="${chrome.runtime.getURL('style/main.css')}">`); //TODO: change injection
}

function on_schedule_loaded(schedule) {
    //transition & progress bar
    {
        clearInterval(window.progressTimer);
        setTimeout(function () {
            $('#loading_bar').css('width', '100%').css('width', '+=5px');
            $('#loading_bar').css('transition', '0.3s');
            $('#loading_bar').css('background-color', 'transparent');
            $('#course_pool').css('transition', '1s');
            $('#course_pool').css('background-color', 'transparent');
        }, 1000);
        $('#cceasier-tool *').prop('disabled', false);
    }

    //preprocess schedule data
    {
        var course_list = [];
        var instructor_sum = {};
        $.each(schedule, function () {
            var prof = '';
            var hash = {};
            $.each(schedule[this[0]['course_no']], function () {
                if (hash[this['instructor']] == null) {
                    prof += this['instructor'] + ', ';
                    hash[this['instructor']] = true;
                }
            });
            prof = prof.slice(0, -2);
            course_list.push({
                "course_code": this[0]["course_no"],
                "course_title": this[0]["course_title"],
                "instructor": prof
            });
            instructor_sum[this[0]['course_no']] = prof;
        });
    }

    var fuse = new Fuse(course_list, {
        shouldSort: true,
        threshold: 0.4,
        location: 0,
        distance: 100,
        maxPatternLength: 32,
        minMatchCharLength: 2,
        keys: [
            "course_code",
            "instructor",
            "course_title"]
    });

    new Textcomplete(new Textcomplete.editors.Textarea(document.getElementById('course_pool'))).register([
        {
            match: /(^|,)([^,]+)$/,
            search: function (term, callback) {
                if(/(^|,)([A-Z][A-Z]|[a-z][a-z])\d{0,3}$/.test(term)){
                    term = term.toUpperCase();
                    var ans = [];
                    for(i=0;i<course_list.length;i++){
                        if(course_list[i]['course_code'].startsWith(term)){
                            ans.push(course_list[i]['course_code']);
                            if(ans.length >= 8) break;
                        }
                    }
                    callback(ans);
                    return;
                }
                var result = fuse.search(term);
                result = result.slice(0, 8);
                var match = [];
                $.each(result, function () { match.push(this['course_code']); });
                callback(match);
            },
            template: function (course_code) {
                var title = schedule[course_code][0]['course_title'].replace(/(\[.*\])/g, '$1').replace(/(\(.*\))/g, '$1');
                return `<b>${course_code}</b> <small>(${instructor_sum[course_code]})</small><br>${title}`
            },
            replace: function (course_code) {
                return '$1' + course_code + ',';
            }
        }
    ]);

    //modal window event
    {
        $('#course_pool_confirm').click(function () { show_modal_window(schedule) });
        key('ctrl+enter', function () {
            if ($('#course_pool').is(':focus')) show_modal_window(schedule);
        });
        key.filter = ev => true;
    }
}

//remove the orignal menu
$(document.body.children[1]).remove();

<|endoftext|>


<commit_before>/// Required Core Modules
var vm = require('vm');
///
/// Modules
var async = require('async');
var defaultsDeep = require('lodash.defaultsdeep');
///
/// Predefined Types
// TYPES
var ST_LOCAL_TYPE = 0, ST_SHARED_TYPE = 1, ST_FOREIGN_TYPE = 2;
// PERMISSIONS
var ST_NONE = 0, ST_RESTRICTED = 1, ST_MINIMAL = 2, ST_UNRESTRICTED = 3;
///

var SuperTask = function ST_INIT() {
    this.cargo = async.cargo(this._next, 50);
    this._batch = [];
    this._paused = true;
    this._busy = false;
    this.map = new Map();
};

SuperTask.prototype._createTask = function ST__CREATE_TASK(func, type, access, context, isModule, remote, sandboxed) {
    return {
        func: func,
        local: (type === ST_LOCAL_TYPE),
        shared: (type === ST_SHARED_TYPE),
        sandboxed: ((!!sandboxed) || (type === ST_FOREIGN_TYPE)),
        module: (isModule === false) ? false : true,
        isCompiled: (typeof func === 'function'),
        isRemote: (!!remote),
        lastStarted: [],
        lastFinished: [],
        lastDiff: 0,
        averageExecutionTime: -1,
        executionRounds: 0,
        defaultContext: context || {},
        access: access || ST_NONE
    };
};

SuperTask.prototype._extendContextFromPermissions = require('./lib/ContextPermissions');

SuperTask.prototype._next = function ST__CARGO_NEXT(tasks, callback) {
    /* At this point the source is fully compiled
    /* to a function or a function is resupplied
    /* from cache to be executed. Here we transfer
    /* the given function (task.func) to the cargo
    /* after attaching the pre tracker */

    // Go through tasks in parallel
    async.each(tasks, function ST__CARGO_EACH(task, done) {
        // Cargo Tracker
        function ST__CARGO_TRACKER(error) {
            done();
            task.callback.apply(this, arguments);
        }
        // Call preTracker
        task.pre();
        // Push Callback to args
        task.args.push(ST__CARGO_TRACKER);
        // Call Function with context & args
        if(task.sandboxed) {
            try {
                task.func.apply(task.context, task.args);
            }catch(error) {
                ST__CARGO_TRACKER(error);
            }
        }else{
            task.func.apply(task.context, task.args);
        }

    }, callback);
};

SuperTask.prototype._newCargo = function ST__CARGO_ADD(name, func, sandboxed, context, args, preTracker, postTracker) {
    // Push Cargo Object & Attach postTracker
    this.cargo.push({
        name: name,
        pre: preTracker,
        func: func,
        context: context,
        args: args,
        sandboxed: sandboxed,
        callback: postTracker
    });
    // Resume Cargo
    this.cargo.resume();
};

SuperTask.prototype._addTask = function ST__ADD_TASK() {
    var args = Array.prototype.slice.call(arguments);
    var name = args.shift();
    var callback = args.pop();

    // Make sure Map Key is not taken
    if (this.map.has(name)) {
        if (typeof callback === 'function') callback(new Error('Enable to create new task. A Task with the given name already exists.'));
        return;
    }

    var task = this._createTask.apply(this, args);
    // Add Task to Map
    this.map.set(name, task);

    if (typeof callback === 'function') callback(null, task);
};

SuperTask.prototype.addLocal = function ST_ADD_LOCAL(name, func, callback) {
    this._addTask(name, func, ST_LOCAL_TYPE, callback);
};

SuperTask.prototype.addLocalWithContext = function ST_ADD_LOCAL_W_CONTEXT(name, func, context, permissions, callback) {
    this._addTask(name, func, ST_LOCAL_TYPE, permissions, context, callback);
};

SuperTask.prototype.addForeign = function ST_ADD_FOREIGN(name, source, callback) {
    // VM requires a String source to compile
    // If given source is a function convert it to source (context is lost)
    if (typeof source === 'function') {
        source = 'module.exports = ' + source.toString();
    }
    this._addTask(name, source, ST_FOREIGN_TYPE, callback);
};

SuperTask.prototype.addForeignWithContext = function ST_ADD_FOREIGN_W_CONTEXT(name, source, context, permissions, callback) {
    // VM requires a String source to compile
    // If given source is a function convert it to source (context is lost)
    if (typeof source === 'function') {
        source = 'module.exports = ' + source.toString();
    }
    this._addTask(name, source, ST_FOREIGN_TYPE, permissions, context, callback);
};

SuperTask.prototype.do = function ST_DO(name, context, args, callback) {
    if (!this.map.has(name)) {
        if (typeof callback === 'function') callback(new Error('Task not found!'));
        return;
    }
    var task = this.map.get(name);
    // Combine Contexts
    if (task.defaultContext && (Object.keys(task.defaultContext).length !== 0)) defaultsDeep(context, task.defaultContext);
    // Combine Permissions Context (SLOWS DOWN EXECUTION)
    if (task.access !== ST_NONE) {
        context = this._extendContextFromPermissions(context, task.access);
    }
    // Function executed on cargo execution
    var preTracker = function ST_DO_PRETRACKER() {
        task.lastStarted = process.hrtime();
    };
    var postTracker = function ST_DO_POSTTRACKER(error) {
        // Calculate High Resolution time it took to run the function
        task.lastFinished = process.hrtime(task.lastStarted);
        // Calculate Time Difference
        task.lastDiff = task.lastFinished[0] * 1e9 + task.lastFinished[1];
        // Calculate Average Execution Time
        if (task.averageExecutionTime === -1) {
            task.averageExecutionTime = task.lastDiff;
        } else {
            task.averageExecutionTime = ((task.averageExecutionTime * task.executionRounds) + task.lastDiff) / (task.executionRounds + 1);
        }
        // Bump execution rounds
        task.executionRounds++;
        // Call Callback function if provided
        if (typeof callback === 'function') callback.apply(task, arguments);
    };
    // Sanitize args
    args = (Array.isArray(args)) ? args : [];

    if (typeof task.func !== 'function') {
        // Check if script is not compiled
        if (typeof task.func === 'string') {
            // Compile script using VM
            task.func = new vm.Script(task.func);
        }
        // Make sure we can call run on the compiled script
        if (typeof task.func.runInContext !== 'function') {
            if (typeof callback === 'function') callback(new Error("Unknown Error Occurred. Function property of Task is invalid or failed to compile."));
            return;
        }
        // Define module.exports and exports in context
        context.module = {};
        context.exports = context.module.exports = {};

        // Create VM Context from context object
        vm.createContext(context);
        // Run Compiled Script
        task.func.runInContext(context);
        // If task is defined as module
        if (task.module) {
            // Make sure module.exports is set to a function
            if (typeof context.module.exports === 'function') {
                // Cache and Call the function
                task.func = context.module.exports;
                // Set isCompiled property
                task.isCompiled = true;
                // Push to Cargo
                this._newCargo(name, task.func, task.sandboxed, context, args, preTracker, postTracker);
            } else {
                // Call Callback with an error if module.exports is not set to a function
                if (typeof callback === 'function') callback(new Error("Compiled Script is not a valid foreign task or module. Failed to identify module.exports as a function."));
            }
        }
    } else {
        // Push to Cargo
        this._newCargo(name, task.func, task.sandboxed, context, args, preTracker, postTracker);
    }
};

SuperTask.prototype.remove = function ST_REMOVE(name, callback) {
    var result = this.map.delete(name);
    if (typeof callback === 'function') callback((!result) ? (new Error('Task not found!')) : null);
};

SuperTask.prototype.has = function ST_HAS(name, callback) {
    if (typeof callback === 'function') callback(null, (!!this.map.has(name)));
};

/// EXTEND PREDEFINED VARS
SuperTask.ST_LOCAL_TYPE = ST_LOCAL_TYPE;
SuperTask.ST_SHARED_TYPE = ST_SHARED_TYPE;
SuperTask.ST_FOREIGN_TYPE = ST_FOREIGN_TYPE;

SuperTask.ST_NONE = ST_NONE;
SuperTask.ST_RESTRICTED = ST_RESTRICTED;
SuperTask.ST_MINIMAL = ST_MINIMAL;
SuperTask.ST_UNRESTRICTED = ST_UNRESTRICTED;
///

module.exports = SuperTask;<commit_msg>Changed Cargo Object creation structure<commit_after>/// Required Core Modules
var vm = require('vm');
///
/// Modules
var async = require('async');
var defaultsDeep = require('lodash.defaultsdeep');
///
/// Predefined Types
// TYPES
var ST_LOCAL_TYPE = 0, ST_SHARED_TYPE = 1, ST_FOREIGN_TYPE = 2;
// PERMISSIONS
var ST_NONE = 0, ST_RESTRICTED = 1, ST_MINIMAL = 2, ST_UNRESTRICTED = 3;
///

var SuperTask = function ST_INIT() {
    this.cargo = async.cargo(this._next, 50);
    this._batch = [];
    this._paused = true;
    this._busy = false;
    this.map = new Map();
};

SuperTask.prototype._createTask = function ST__CREATE_TASK(func, type, access, context, isModule, remote, sandboxed) {
    return {
        func: func,
        local: (type === ST_LOCAL_TYPE),
        shared: (type === ST_SHARED_TYPE),
        sandboxed: ((!!sandboxed) || (type === ST_FOREIGN_TYPE)),
        module: (isModule === false) ? false : true,
        isCompiled: (typeof func === 'function'),
        isRemote: (!!remote),
        lastStarted: [],
        lastFinished: [],
        lastDiff: 0,
        averageExecutionTime: -1,
        executionRounds: 0,
        defaultContext: context || {},
        access: access || ST_NONE
    };
};

SuperTask.prototype._extendContextFromPermissions = require('./lib/ContextPermissions');

SuperTask.prototype._next = function ST__CARGO_NEXT(tasks, callback) {
    /* At this point the source is fully compiled
    /* to a function or a function is resupplied
    /* from cache to be executed. Here we transfer
    /* the given function (task.func) to the cargo
    /* after attaching the pre tracker */

    // Go through tasks in parallel
    async.each(tasks, function ST__CARGO_EACH(task, done) {
        // Cargo Tracker
        function ST__CARGO_TRACKER(error) {
            done();
            task.callback.apply(this, arguments);
        }
        // Call preTracker
        task.pre();
        // Push Callback to args
        task.args.push(ST__CARGO_TRACKER);
        // Call Function with context & args
        if(task.sandboxed) {
            try {
                task.func.apply(task.context, task.args);
            }catch(error) {
                ST__CARGO_TRACKER(error);
            }
        }else{
            task.func.apply(task.context, task.args);
        }

    }, callback);
};

SuperTask.prototype._newCargo = function ST__CARGO_ADD(CargoTask) {
    // Push Cargo Object & Attach postTracker
    this.cargo.push(CargoTask);
    // Resume Cargo
    this.cargo.resume();
};

SuperTask.prototype._addTask = function ST__ADD_TASK() {
    var args = Array.prototype.slice.call(arguments);
    var name = args.shift();
    var callback = args.pop();

    // Make sure Map Key is not taken
    if (this.map.has(name)) {
        if (typeof callback === 'function') callback(new Error('Enable to create new task. A Task with the given name already exists.'));
        return;
    }

    var task = this._createTask.apply(this, args);
    // Add Task to Map
    this.map.set(name, task);

    if (typeof callback === 'function') callback(null, task);
};

SuperTask.prototype.addLocal = function ST_ADD_LOCAL(name, func, callback) {
    this._addTask(name, func, ST_LOCAL_TYPE, callback);
};

SuperTask.prototype.addLocalWithContext = function ST_ADD_LOCAL_W_CONTEXT(name, func, context, permissions, callback) {
    this._addTask(name, func, ST_LOCAL_TYPE, permissions, context, callback);
};

SuperTask.prototype.addForeign = function ST_ADD_FOREIGN(name, source, callback) {
    // VM requires a String source to compile
    // If given source is a function convert it to source (context is lost)
    if (typeof source === 'function') {
        source = 'module.exports = ' + source.toString();
    }
    this._addTask(name, source, ST_FOREIGN_TYPE, callback);
};

SuperTask.prototype.addForeignWithContext = function ST_ADD_FOREIGN_W_CONTEXT(name, source, context, permissions, callback) {
    // VM requires a String source to compile
    // If given source is a function convert it to source (context is lost)
    if (typeof source === 'function') {
        source = 'module.exports = ' + source.toString();
    }
    this._addTask(name, source, ST_FOREIGN_TYPE, permissions, context, callback);
};

SuperTask.prototype.do = function ST_DO(name, context, args, callback) {
    if (!this.map.has(name)) {
        if (typeof callback === 'function') callback(new Error('Task not found!'));
        return;
    }
    var task = this.map.get(name);
    // Combine Contexts
    if (task.defaultContext && (Object.keys(task.defaultContext).length !== 0)) defaultsDeep(context, task.defaultContext);
    // Combine Permissions Context (SLOWS DOWN EXECUTION)
    if (task.access !== ST_NONE) {
        context = this._extendContextFromPermissions(context, task.access);
    }
    // Function executed on cargo execution
    var preTracker = function ST_DO_PRETRACKER() {
        task.lastStarted = process.hrtime();
    };
    var postTracker = function ST_DO_POSTTRACKER(error) {
        // Calculate High Resolution time it took to run the function
        task.lastFinished = process.hrtime(task.lastStarted);
        // Calculate Time Difference
        task.lastDiff = task.lastFinished[0] * 1e9 + task.lastFinished[1];
        // Calculate Average Execution Time
        if (task.averageExecutionTime === -1) {
            task.averageExecutionTime = task.lastDiff;
        } else {
            task.averageExecutionTime = ((task.averageExecutionTime * task.executionRounds) + task.lastDiff) / (task.executionRounds + 1);
        }
        // Bump execution rounds
        task.executionRounds++;
        // Call Callback function if provided
        if (typeof callback === 'function') callback.apply(task, arguments);
    };
    // Sanitize args
    args = (Array.isArray(args)) ? args : [];

    // Create a Cargo-able Clone of Task
    var CargoTask = {};
    CargoTask.name = name;
    CargoTask.func = task.func;
    CargoTask.sandboxed = task.sandboxed;
    CargoTask.averageExecutionTime = task.averageExecutionTime;
    CargoTask.executionRounds = task.executionRounds;
    CargoTask.local = task.local;
    CargoTask.context = context;
    CargoTask.args = args;
    CargoTask.pre = preTracker;
    CargoTask.callback = postTracker;
    //

    if (typeof task.func !== 'function') {
        // Check if script is not compiled
        if (typeof task.func === 'string') {
            // Compile script using VM
            task.func = new vm.Script(task.func);
        }
        // Make sure we can call run on the compiled script
        if (typeof task.func.runInContext !== 'function') {
            if (typeof callback === 'function') callback(new Error("Unknown Error Occurred. Function property of Task is invalid or failed to compile."));
            return;
        }
        // Define module.exports and exports in context
        context.module = {};
        context.exports = context.module.exports = {};

        // Create VM Context from context object
        vm.createContext(context);
        // Run Compiled Script
        task.func.runInContext(context);
        // If task is defined as module
        if (task.module) {
            // Make sure module.exports is set to a function
            if (typeof context.module.exports === 'function') {
                // Cache and Call the function
                task.func = context.module.exports;
                // Set isCompiled property
                task.isCompiled = true;
                // Set Task Compile Function to CargoTask
                CargoTask.func = task.func;
                // Push to Cargo
                this._newCargo(CargoTask);
            } else {
                // Call Callback with an error if module.exports is not set to a function
                if (typeof callback === 'function') callback(new Error("Compiled Script is not a valid foreign task or module. Failed to identify module.exports as a function."));
            }
        }
    } else {
        // Push to Cargo
        this._newCargo(CargoTask);
    }
};

SuperTask.prototype.remove = function ST_REMOVE(name, callback) {
    var result = this.map.delete(name);
    if (typeof callback === 'function') callback((!result) ? (new Error('Task not found!')) : null);
};

SuperTask.prototype.has = function ST_HAS(name, callback) {
    if (typeof callback === 'function') callback(null, (!!this.map.has(name)));
};

/// EXTEND PREDEFINED VARS
SuperTask.ST_LOCAL_TYPE = ST_LOCAL_TYPE;
SuperTask.ST_SHARED_TYPE = ST_SHARED_TYPE;
SuperTask.ST_FOREIGN_TYPE = ST_FOREIGN_TYPE;

SuperTask.ST_NONE = ST_NONE;
SuperTask.ST_RESTRICTED = ST_RESTRICTED;
SuperTask.ST_MINIMAL = ST_MINIMAL;
SuperTask.ST_UNRESTRICTED = ST_UNRESTRICTED;
///

module.exports = SuperTask;<|endoftext|>