<commit_before>import Ember from 'ember';
import layout from './ember-collection/template';
var decodeEachKey = Ember.__loader.require('ember-htmlbars/utils/decode-each-key')['default'];

class Cell {
  constructor(key, item, index, style) {
    this.key = key;
    this.hidden = false;
    this.item = item;
    this.index = index;
    this.style = style;
  }
}

function formatStyle(pos, width, height) {
  return 'position: absolute; top: 0; left: 0;' +
    ' -webkit-transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' -moz-transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' -ms-transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' -o-transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' width: '+width+'px; height: '+height+'px;';
}

export default Ember.Component.extend({
  layout: layout,
  classNames: ['ember-list'],

  init() {
    this._super();
    this.offsetX = 0;
    this.offsetY = 0;
    this.width = 0;
    this.height = 0;
    this.contentElement = undefined;
    Ember.set(this, 'cells', Ember.A([]));
    this.cellMap = Object.create(null);
    this.startingIndex = undefined;
    this.visibleCount = undefined;
    // XXX bug: didReceiveAttrs received before init! redo initial attrs setup
    if (this.attrs != null) {
      this.didReceiveAttrs();
    }
  },
  didInitAttrs() {
    this._super();
    this.buffer = this.getAttr('buffer') | 5;
    this.offsetX = this.getAttr('offset-x') | 0;
    this.offsetY = this.getAttr('offset-y') | 0;
    this.width = this.getAttr('width') | 0;
    this.height = this.getAttr('height') | 0;
  },

  didReceiveAttrs() {
    this._super();
    // Reset cells when cell layout or items array changes
    var buffer = this.getAttr('buffer') | 5;
    var cellLayout = this.getAttr('cell-layout');
    var items = this.getAttr('items');
    var contentWidth = this.getAttr('width') | 0;
    var contentHeight = this.getAttr('height') | 0;
    var offsetX = this.getAttr('offset-x') | 0;
    var offsetY = this.getAttr('offset-y') | 0;
    var calculateSize = false;

    if (this.cellLayout !== cellLayout || this.items !== items) {
      if (this.items != null && this.items !== items &&
          this.items.removeArrayObserver != null ) {
        this.items.removeArrayObserver(this);
      }
      this.items = items;
      if (this.items != null && this.items.addArrayObserver != null ) {
        this.items.addArrayObserver(this);
      }
      this.cellLayout = cellLayout;
      calculateSize = true;
    }
    if (contentWidth !== this.width || contentHeight !== this.height ||
        buffer !== this.buffer) {
      this.set('width', contentWidth);
      this.set('height', contentHeight);
      this.buffer = buffer;
      this.calculateBounds();
      calculateSize = true;
    }
    if (offsetX !== this.offsetY || offsetY !== this.offsetY) {
      this.offsetX = offsetX;
      this.offsetY = offsetY;
      calculateSize = true;
    }
    if (calculateSize) {
      this.calculateBounds();
      this.calculateContentSize();
    }
  },
  arrayWillChange() { },
  arrayDidChange() {
    this.rerender();
  },
  didInsertElement() {
    this._super();
    this.contentElement = this.element.firstElementChild;
    this.calculateBounds();      // viewport setup
    this.calculateContentSize(); // content size
    this.initContentOffset();    // content scroll in viewport
    this.setupScroller();

    var component = this;
    function callback() {
      var element = component.element;
      if (element) {
        var offsetX = element.scrollLeft;
        var offsetY = element.scrollTop;

        if (offsetX !== component.offsetX || offsetY !== component.offsetY) {
          component.offsetX = offsetX;
          component.offsetY = offsetY;

          var index = component.cellLayout.indexAt(offsetX, offsetY, component.width, component.height);
          var count = component.cellLayout.count(offsetX, offsetY, component.width, component.height);
          if (index !== component.currentIndex || count !== component.currentCount) {
            component.currentIndex = index;
            component.currentCount = count;
            Ember.run(component, 'rerender');
          }
        }
      }
      requestAnimationFrame(callback);
    }
    callback();
  },
  willDestroyElement() {
    this._super();
    if (this.items != null && this.items.removeArrayObserver != null) {
      this.items.removeArrayObserver(this);
    }
  },
  setupScroller() {
    //this.element.addEventListener('scroll', Ember.run.bind(this, 'updateOffset'));
    // TODO save for teardown
  },
  willRender() {
    if (!this.items) { return; }
    if (this.cellLayout.length !== this.items.length) {
      this.cellLayout.length = this.items.length;
      this.calculateContentSize();
    }

    var priorMap = this.cellMap;
    var cellMap = Object.create(null);

    var startingIndex = this.cellLayout.indexAt(
      this.offsetX, this.offsetY, this.width, this.height);
    var visibleCount = this.cellLayout.count(
      this.offsetX, this.offsetY, this.width, this.height);
    var items = this.items;
    // adjust for buffer
    var index = Math.max(startingIndex - this.buffer, 0);
    var count = Math.min(visibleCount + this.buffer, Ember.get(items, 'length') - index);
    var i, pos, width, height, style, itemIndex, itemKey, cell;

    var newItems = [];

    for (i=0; i<count; i++) {
      itemIndex = index+i;
      itemKey = decodeEachKey(items[itemIndex], '@identity');
      if (priorMap) {
        cell = priorMap[itemKey];
      }
      if (cell) {
        pos = this.cellLayout.positionAt(itemIndex, this.width, this.height);
        width = this.cellLayout.widthAt(itemIndex, this.width, this.height);
        height = this.cellLayout.heightAt(itemIndex, this.width, this.height);
        style = formatStyle(pos, width, height);
        Ember.set(cell, 'style', style);
        Ember.set(cell, 'hidden', false);
        Ember.set(cell, 'key', itemKey);
        cellMap[itemKey] = cell;
      } else {
        newItems.push(itemIndex);
      }
    }

    for (i=0; i<this.cells.length; i++) {
      cell = this.cells[i];
      if (!cellMap[cell.key]) {
        if (newItems.length) {
          itemIndex = newItems.pop();
          itemKey = decodeEachKey(items[itemIndex], '@identity');
          pos = this.cellLayout.positionAt(itemIndex, this.width, this.height);
          width = this.cellLayout.widthAt(itemIndex, this.width, this.height);
          height = this.cellLayout.heightAt(itemIndex, this.width, this.height);
          style = formatStyle(pos, width, height);
          Ember.set(cell, 'style', style);
          Ember.set(cell, 'key', itemKey);
          Ember.set(cell, 'index', itemIndex);
          Ember.set(cell, 'item', items[itemIndex]);
          Ember.set(cell, 'hidden', false);
          cellMap[itemKey] = cell;
        } else {
          Ember.set(cell, 'hidden', true);
          Ember.set(cell, 'style', 'height: 0; display: none;');
        }
      }
    }

    for (i=0; i<newItems.length; i++) {
      itemIndex = newItems[i];
      itemKey = decodeEachKey(items[itemIndex], '@identity');
      pos = this.cellLayout.positionAt(itemIndex, this.width, this.height);
      width = this.cellLayout.widthAt(itemIndex, this.width, this.height);
      height = this.cellLayout.heightAt(itemIndex, this.width, this.height);
      style = formatStyle(pos, width, height);
      cell = new Cell(itemKey, items[itemIndex], itemIndex, style);
      cellMap[itemKey] = cell;
      this.cells.pushObject(cell);
    }
    this.cellMap = cellMap;
    if (startingIndex !== this.startingIndex) {
      this.startingIndex = startingIndex;
      (this.attrs.startingIndexDidChange || Ember.K)(startingIndex);
    }
    if (visibleCount !== this.visibleCount) {
      this.visibleCount = visibleCount;
      (this.attrs.visibleCountDidChange || Ember.K)(visibleCount);
    }
  },
  calculateBounds() {
    // make sure rendered before accessing style.
    if (this.element == null) { return; }

    // TODO measure clientWidth and clientHeight vs offsetWidth and offsetHeight
    this.element.style.overflow = 'scroll';
    this.element.style.webkitOverflowScrolling = 'touch';
    this.element.style.webkitTransform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.mozTransform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.msTransform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.oTransform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.transform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.position = 'relative';
    this.element.style.boxSizing = 'border-box';
    if (this.width > 0) {
      this.element.style.width = this.width + 'px';
    }
    if (this.height > 0) {
      this.element.style.height = this.height + 'px';
    }
  },
  calculateContentSize() {
    var cellLayout = this.get('cellLayout');
    if (this.contentElement == null || cellLayout == null || this.width == null || this.height == null) { return; }
    var contentWidth = cellLayout.contentWidth(this.width);
    var contentHeight = cellLayout.contentHeight(this.width);
    this.contentElement.style.width = contentWidth + 'px';
    this.contentElement.style.height = contentHeight + 'px';
    this.initContentOffset();
  },
  initContentOffset() {
    if (this.element == null) { return; }
    if (this.offsetX > 0) {
      this.element.scrollLeft = this.offsetX;
    }
    if (this.offsetY > 0 && this.cellLayout != null) {
      this.element.scrollTop = Math.min(
        this.offsetY, this.cellLayout.maxScroll(this.width, this.height));
    }
  }
});
<commit_msg>fixes imperative array observation<commit_after>import Ember from 'ember';
import layout from './ember-collection/template';
var decodeEachKey = Ember.__loader.require('ember-htmlbars/utils/decode-each-key')['default'];

class Cell {
  constructor(key, item, index, style) {
    this.key = key;
    this.hidden = false;
    this.item = item;
    this.index = index;
    this.style = style;
  }
}

function formatStyle(pos, width, height) {
  return 'position: absolute; top: 0; left: 0;' +
    ' -webkit-transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' -moz-transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' -ms-transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' -o-transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' transform: translate('+pos.x+'px, '+pos.y+'px);' +
    ' width: '+width+'px; height: '+height+'px;';
}

export default Ember.Component.extend({
  layout: layout,
  classNames: ['ember-list'],

  init() {
    this._super();
    this.offsetX = 0;
    this.offsetY = 0;
    this.width = 0;
    this.height = 0;
    this.contentElement = undefined;
    Ember.set(this, 'cells', Ember.A([]));
    this.cellMap = Object.create(null);
    this.startingIndex = undefined;
    this.visibleCount = undefined;
    // XXX bug: didReceiveAttrs received before init! redo initial attrs setup
    if (this.attrs != null) {
      this.didReceiveAttrs();
    }
  },
  didInitAttrs() {
    this._super();
    this.buffer = this.getAttr('buffer') | 5;
    this.offsetX = this.getAttr('offset-x') | 0;
    this.offsetY = this.getAttr('offset-y') | 0;
    this.width = this.getAttr('width') | 0;
    this.height = this.getAttr('height') | 0;
  },

  didReceiveAttrs() {
    this._super();
    // Reset cells when cell layout or items array changes
    var buffer = this.getAttr('buffer') | 5;
    var cellLayout = this.getAttr('cell-layout');
    var items = this.getAttr('items');
    var contentWidth = this.getAttr('width') | 0;
    var contentHeight = this.getAttr('height') | 0;
    var offsetX = this.getAttr('offset-x') | 0;
    var offsetY = this.getAttr('offset-y') | 0;
    var calculateSize = false;

    if (this.cellLayout !== cellLayout || this.items !== items) {
      this.set('items', items);
      this.cellLayout = cellLayout;
      calculateSize = true;
    }
    if (contentWidth !== this.width || contentHeight !== this.height ||
        buffer !== this.buffer) {
      this.set('width', contentWidth);
      this.set('height', contentHeight);
      this.buffer = buffer;
      this.calculateBounds();
      calculateSize = true;
    }
    if (offsetX !== this.offsetY || offsetY !== this.offsetY) {
      this.offsetX = offsetX;
      this.offsetY = offsetY;
      calculateSize = true;
    }
    if (calculateSize) {
      this.calculateBounds();
      this.calculateContentSize();
    }
  },
  itemsDidChange: Ember.observer('items.[]', function() {
    this.rerender();
  }),
  didInsertElement() {
    this._super();
    this.contentElement = this.element.firstElementChild;
    this.calculateBounds();      // viewport setup
    this.calculateContentSize(); // content size
    this.initContentOffset();    // content scroll in viewport
    this.setupScroller();

    var component = this;
    function callback() {
      var element = component.element;
      if (element) {
        var offsetX = element.scrollLeft;
        var offsetY = element.scrollTop;

        if (offsetX !== component.offsetX || offsetY !== component.offsetY) {
          component.offsetX = offsetX;
          component.offsetY = offsetY;

          var index = component.cellLayout.indexAt(offsetX, offsetY, component.width, component.height);
          var count = component.cellLayout.count(offsetX, offsetY, component.width, component.height);
          if (index !== component.currentIndex || count !== component.currentCount) {
            component.currentIndex = index;
            component.currentCount = count;
            Ember.run(component, 'rerender');
          }
        }
      }
      requestAnimationFrame(callback);
    }
    callback();
  },
  setupScroller() {
    //this.element.addEventListener('scroll', Ember.run.bind(this, 'updateOffset'));
    // TODO save for teardown
  },
  willRender() {
    if (!this.items) { return; }
    if (this.cellLayout.length !== this.items.length) {
      this.cellLayout.length = this.items.length;
      this.calculateContentSize();
    }

    var priorMap = this.cellMap;
    var cellMap = Object.create(null);

    var startingIndex = this.cellLayout.indexAt(
      this.offsetX, this.offsetY, this.width, this.height);
    var visibleCount = this.cellLayout.count(
      this.offsetX, this.offsetY, this.width, this.height);
    var items = this.items;
    // adjust for buffer
    var index = Math.max(startingIndex - this.buffer, 0);
    var count = Math.min(visibleCount + this.buffer, Ember.get(items, 'length') - index);
    var i, pos, width, height, style, itemIndex, itemKey, cell;

    var newItems = [];

    for (i=0; i<count; i++) {
      itemIndex = index+i;
      itemKey = decodeEachKey(items[itemIndex], '@identity');
      if (priorMap) {
        cell = priorMap[itemKey];
      }
      if (cell) {
        pos = this.cellLayout.positionAt(itemIndex, this.width, this.height);
        width = this.cellLayout.widthAt(itemIndex, this.width, this.height);
        height = this.cellLayout.heightAt(itemIndex, this.width, this.height);
        style = formatStyle(pos, width, height);
        Ember.set(cell, 'style', style);
        Ember.set(cell, 'hidden', false);
        Ember.set(cell, 'key', itemKey);
        cellMap[itemKey] = cell;
      } else {
        newItems.push(itemIndex);
      }
    }

    for (i=0; i<this.cells.length; i++) {
      cell = this.cells[i];
      if (!cellMap[cell.key]) {
        if (newItems.length) {
          itemIndex = newItems.pop();
          itemKey = decodeEachKey(items[itemIndex], '@identity');
          pos = this.cellLayout.positionAt(itemIndex, this.width, this.height);
          width = this.cellLayout.widthAt(itemIndex, this.width, this.height);
          height = this.cellLayout.heightAt(itemIndex, this.width, this.height);
          style = formatStyle(pos, width, height);
          Ember.set(cell, 'style', style);
          Ember.set(cell, 'key', itemKey);
          Ember.set(cell, 'index', itemIndex);
          Ember.set(cell, 'item', items[itemIndex]);
          Ember.set(cell, 'hidden', false);
          cellMap[itemKey] = cell;
        } else {
          Ember.set(cell, 'hidden', true);
          Ember.set(cell, 'style', 'height: 0; display: none;');
        }
      }
    }

    for (i=0; i<newItems.length; i++) {
      itemIndex = newItems[i];
      itemKey = decodeEachKey(items[itemIndex], '@identity');
      pos = this.cellLayout.positionAt(itemIndex, this.width, this.height);
      width = this.cellLayout.widthAt(itemIndex, this.width, this.height);
      height = this.cellLayout.heightAt(itemIndex, this.width, this.height);
      style = formatStyle(pos, width, height);
      cell = new Cell(itemKey, items[itemIndex], itemIndex, style);
      cellMap[itemKey] = cell;
      this.cells.pushObject(cell);
    }
    this.cellMap = cellMap;
    if (startingIndex !== this.startingIndex) {
      this.startingIndex = startingIndex;
      (this.attrs.startingIndexDidChange || Ember.K)(startingIndex);
    }
    if (visibleCount !== this.visibleCount) {
      this.visibleCount = visibleCount;
      (this.attrs.visibleCountDidChange || Ember.K)(visibleCount);
    }
  },
  calculateBounds() {
    // make sure rendered before accessing style.
    if (this.element == null) { return; }

    // TODO measure clientWidth and clientHeight vs offsetWidth and offsetHeight
    this.element.style.overflow = 'scroll';
    this.element.style.webkitOverflowScrolling = 'touch';
    this.element.style.webkitTransform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.mozTransform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.msTransform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.oTransform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.transform = 'translate3d(0px, 0px, 0px) scale(1)';
    this.element.style.position = 'relative';
    this.element.style.boxSizing = 'border-box';
    if (this.width > 0) {
      this.element.style.width = this.width + 'px';
    }
    if (this.height > 0) {
      this.element.style.height = this.height + 'px';
    }
  },
  calculateContentSize() {
    var cellLayout = this.get('cellLayout');
    if (this.contentElement == null || cellLayout == null || this.width == null || this.height == null) { return; }
    var contentWidth = cellLayout.contentWidth(this.width);
    var contentHeight = cellLayout.contentHeight(this.width);
    this.contentElement.style.width = contentWidth + 'px';
    this.contentElement.style.height = contentHeight + 'px';
    this.initContentOffset();
  },
  initContentOffset() {
    if (this.element == null) { return; }
    if (this.offsetX > 0) {
      this.element.scrollLeft = this.offsetX;
    }
    if (this.offsetY > 0 && this.cellLayout != null) {
      this.element.scrollTop = Math.min(
        this.offsetY, this.cellLayout.maxScroll(this.width, this.height));
    }
  }
});
<|endoftext|>


<commit_before>import Service from '@ember/service';
import { inject as service } from '@ember/service';

export default Service.extend({
  currentUser: service(),
  permissionMatrix: service(),
  async canDoInSchool(school, capability) {
    const currentUser = await this.get('currentUser');
    const isRoot = await currentUser.get('isRoot');
    if (isRoot) {
      return true;
    }
    const permissionMatrix = this.get('permissionMatrix');
    const rolesInSchool = await currentUser.getRolesInSchool(school);

    return permissionMatrix.hasPermission(school, capability, rolesInSchool);
  },
  async canUpdateCourse(course) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    if (course.get('locked') || course.get('archived')) {
      return false;
    }
    const school = await course.get('school');

    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_COURSES')) {
      return true;
    }

    const rolesInCourse = await currentUser.getRolesInCourse(course);
    return await permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_COURSES', rolesInCourse);
  },
  async canDeleteCourse(course) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    if (course.get('locked') || course.get('archived')) {
      return false;
    }

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_COURSES')) {
      return true;
    }

    const rolesInCourse = await currentUser.getRolesInCourse(course);
    return await permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_COURSES', rolesInCourse);
  },
  async canCreateCourse(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_COURSES');
  },
  async canUnlockCourse(course) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_UNLOCK_ALL_COURSES')) {
      return true;
    }

    const rolesInCourse = await currentUser.getRolesInCourse(course);
    return await permissionMatrix.hasPermission(school, 'CAN_UNLOCK_THEIR_COURSES', rolesInCourse);
  },
  async canUpdateSession(session) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const course = await session.get('course');

    if (course.get('locked') || course.get('archived')) {
      return false;
    }

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_SESSIONS')) {
      return true;
    }

    const rolesInSession = await currentUser.getRolesInSession(session);
    if (await permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_SESSIONS', rolesInSession)) {
      return true;
    }

    return this.canUpdateCourse(course);
  },
  async canDeleteSession(session) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const course = await session.get('course');

    if (course.get('locked') || course.get('archived')) {
      return false;
    }

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_SESSIONS')) {
      return true;
    }

    const rolesInSession = await currentUser.getRolesInSession(session);
    if (await permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_SESSIONS', rolesInSession)) {
      return true;
    }

    return this.canUpdateCourse(course);
  },
  async canCreateSession(course) {
    if (course.get('locked') || course.get('archived')) {
      return false;
    }

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_CREATE_SESSIONS')) {
      return true;
    }

    return this.canUpdateCourse(course);
  },
  async canUpdateSessionType(sessionType) {
    const school = await sessionType.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_SESSION_TYPES');
  },
  async canDeleteSessionType(sessionType) {
    const school = await sessionType.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_SESSION_TYPES');
  },
  async canCreateSessionType(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_SESSION_TYPES');
  },
  async canUpdateDepartment(department) {
    const school = await department.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_DEPARTMENTS');
  },
  async canDeleteDepartment(department) {
    const school = await department.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_DEPARTMENTS');
  },
  async canCreateDepartment(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_DEPARTMENTS');
  },
  async canUpdateProgram(program) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_PROGRAMS')) {
      return true;
    }

    const rolesInProgram = await currentUser.getRolesInProgram(program);
    return await permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_PROGRAMS', rolesInProgram);
  },
  async canDeleteProgram(program) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_PROGRAMS')) {
      return true;
    }

    const rolesInProgram = await currentUser.getRolesInProgram(program);
    return await permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_PROGRAMS', rolesInProgram);
  },
  async canCreateProgram(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_PROGRAMS');
  },
  async canUpdateProgramYear(programYear) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const program = await programYear.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_PROGRAM_YEARS')) {
      return true;
    }
    const rolesInProgramYear = await currentUser.getRolesInProgramYear(programYear);
    if (await permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_PROGRAM_YEARS', rolesInProgramYear)) {
      return true;
    }

    return this.canUpdateProgram(program);
  },
  async canDeleteProgramYear(programYear) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const program = await programYear.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_PROGRAM_YEARS')) {
      return true;
    }
    const rolesInProgramYear = await currentUser.getRolesInProgramYear(programYear);
    if (await permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_PROGRAM_YEARS', rolesInProgramYear)) {
      return true;
    }

    return this.canUpdateProgram(program);
  },
  async canCreateProgramYear(program) {
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_CREATE_PROGRAM_YEARS')) {
      return true;
    }
    return this.canUpdateProgram(program);
  },
  async canUnlockProgramYear(programYear) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    const program = await programYear.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_UNLOCK_ALL_PROGRAM_YEARS')) {
      return true;
    }
    const rolesInProgramYear = await currentUser.getRolesInProgramYear(programYear);
    if (await permissionMatrix.hasPermission(school, 'CAN_UNLOCK_THEIR_PROGRAM_YEARS', rolesInProgramYear)) {
      return true;
    }

    return this.canUpdateProgram(program);
  },
  async canUpdateSchoolConfig(school) {
    return this.canDoInSchool(school, 'CAN_UPDATE_SCHOOL_CONFIGS');
  },
  async canUpdateSchool(school) {
    return this.canDoInSchool(school, 'CAN_UPDATE_SCHOOLS');
  },
  async canUpdateCompetency(competency) {
    const school = await competency.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_COMPETENCIES');
  },
  async canDeleteCompetency(competency) {
    const school = await competency.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_COMPETENCIES');
  },
  async canCreateCompetency(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_COMPETENCIES');
  },
  async canUpdateVocabulary(vocabulary) {
    const school = await vocabulary.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_VOCABULARIES');
  },
  async canDeleteVocabulary(vocabulary) {
    const school = await vocabulary.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_VOCABULARIES');
  },
  async canCreateVocabulary(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_VOCABULARIES');
  },
  async canUpdateTerm(term) {
    const school = await term.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_TERMS');
  },
  async canDeleteTerm(term) {
    const school = await term.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_TERMS');
  },
  async canCreateTerm(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_TERMS');
  },
  async canUpdateInstructorGroup(instructorGroup) {
    const school = await instructorGroup.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_INSTRUCTOR_GROUPS');
  },
  async canDeleteInstructorGroup(instructorGroup) {
    const school = await instructorGroup.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_INSTRUCTOR_GROUPS');
  },
  async canCreateInstructorGroup(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_INSTRUCTOR_GROUPS');
  },
  async canUpdateCurriculumInventoryReport(curriculumInventoryReport) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    const program = await curriculumInventoryReport.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_CURRICULUM_INVENTORY_REPORTS')) {
      return true;
    }
    const rolesInReport = await currentUser.getRolesInCurriculumInventoryReport(curriculumInventoryReport);

    return permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_CURRICULUM_INVENTORY_REPORTS', rolesInReport);
  },
  async canDeleteCurriculumInventoryReport(curriculumInventoryReport) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    const program = await curriculumInventoryReport.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_CURRICULUM_INVENTORY_REPORTS')) {
      return true;
    }

    const rolesInReport = await currentUser.getRolesInCurriculumInventoryReport(curriculumInventoryReport);
    return permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_CURRICULUM_INVENTORY_REPORTS', rolesInReport);
  },
  async canCreateCurriculumInventoryReport(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_CURRICULUM_INVENTORY_REPORTS');
  },
  async canUpdateLearnerGroup(learnerGroup) {
    const school = await learnerGroup.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_LEARNER_GROUPS');
  },
  async canDeleteLearnerGroup(learnerGroup) {
    const school = await learnerGroup.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_LEARNER_GROUPS');
  },
  async canCreateLearnerGroup(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_LEARNER_GROUPS');
  },
  async canUpdateUser(user) {
    const school = await user.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_USERS');
  },
  async canDeleteUser(user) {
    const school = await user.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_USERS');
  },
  async canCreateUser(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_USERS');
  },
  async canUpdateUserInSchool(school) {
    return this.canDoInSchool(school, 'CAN_UPDATE_USERS');
  },
});
<commit_msg>Add convenience methods to see if groups can be updated/created<commit_after>import Service from '@ember/service';
import { inject as service } from '@ember/service';

export default Service.extend({
  currentUser: service(),
  permissionMatrix: service(),
  async canDoInSchool(school, capability) {
    const currentUser = await this.get('currentUser');
    const isRoot = await currentUser.get('isRoot');
    if (isRoot) {
      return true;
    }
    const permissionMatrix = this.get('permissionMatrix');
    const rolesInSchool = await currentUser.getRolesInSchool(school);

    return permissionMatrix.hasPermission(school, capability, rolesInSchool);
  },
  async canUpdateCourse(course) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    if (course.get('locked') || course.get('archived')) {
      return false;
    }
    const school = await course.get('school');

    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_COURSES')) {
      return true;
    }

    const rolesInCourse = await currentUser.getRolesInCourse(course);
    return await permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_COURSES', rolesInCourse);
  },
  async canDeleteCourse(course) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    if (course.get('locked') || course.get('archived')) {
      return false;
    }

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_COURSES')) {
      return true;
    }

    const rolesInCourse = await currentUser.getRolesInCourse(course);
    return await permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_COURSES', rolesInCourse);
  },
  async canCreateCourse(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_COURSES');
  },
  async canUnlockCourse(course) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_UNLOCK_ALL_COURSES')) {
      return true;
    }

    const rolesInCourse = await currentUser.getRolesInCourse(course);
    return await permissionMatrix.hasPermission(school, 'CAN_UNLOCK_THEIR_COURSES', rolesInCourse);
  },
  async canUpdateSession(session) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const course = await session.get('course');

    if (course.get('locked') || course.get('archived')) {
      return false;
    }

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_SESSIONS')) {
      return true;
    }

    const rolesInSession = await currentUser.getRolesInSession(session);
    if (await permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_SESSIONS', rolesInSession)) {
      return true;
    }

    return this.canUpdateCourse(course);
  },
  async canDeleteSession(session) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const course = await session.get('course');

    if (course.get('locked') || course.get('archived')) {
      return false;
    }

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_SESSIONS')) {
      return true;
    }

    const rolesInSession = await currentUser.getRolesInSession(session);
    if (await permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_SESSIONS', rolesInSession)) {
      return true;
    }

    return this.canUpdateCourse(course);
  },
  async canCreateSession(course) {
    if (course.get('locked') || course.get('archived')) {
      return false;
    }

    const school = await course.get('school');
    if (await this.canDoInSchool(school, 'CAN_CREATE_SESSIONS')) {
      return true;
    }

    return this.canUpdateCourse(course);
  },
  async canUpdateSessionType(sessionType) {
    const school = await sessionType.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_SESSION_TYPES');
  },
  async canDeleteSessionType(sessionType) {
    const school = await sessionType.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_SESSION_TYPES');
  },
  async canCreateSessionType(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_SESSION_TYPES');
  },
  async canUpdateDepartment(department) {
    const school = await department.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_DEPARTMENTS');
  },
  async canDeleteDepartment(department) {
    const school = await department.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_DEPARTMENTS');
  },
  async canCreateDepartment(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_DEPARTMENTS');
  },
  async canUpdateProgram(program) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_PROGRAMS')) {
      return true;
    }

    const rolesInProgram = await currentUser.getRolesInProgram(program);
    return await permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_PROGRAMS', rolesInProgram);
  },
  async canDeleteProgram(program) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_PROGRAMS')) {
      return true;
    }

    const rolesInProgram = await currentUser.getRolesInProgram(program);
    return await permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_PROGRAMS', rolesInProgram);
  },
  async canCreateProgram(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_PROGRAMS');
  },
  async canUpdateProgramYear(programYear) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const program = await programYear.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_PROGRAM_YEARS')) {
      return true;
    }
    const rolesInProgramYear = await currentUser.getRolesInProgramYear(programYear);
    if (await permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_PROGRAM_YEARS', rolesInProgramYear)) {
      return true;
    }

    return this.canUpdateProgram(program);
  },
  async canDeleteProgramYear(programYear) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');

    const program = await programYear.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_PROGRAM_YEARS')) {
      return true;
    }
    const rolesInProgramYear = await currentUser.getRolesInProgramYear(programYear);
    if (await permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_PROGRAM_YEARS', rolesInProgramYear)) {
      return true;
    }

    return this.canUpdateProgram(program);
  },
  async canCreateProgramYear(program) {
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_CREATE_PROGRAM_YEARS')) {
      return true;
    }
    return this.canUpdateProgram(program);
  },
  async canUnlockProgramYear(programYear) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    const program = await programYear.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_UNLOCK_ALL_PROGRAM_YEARS')) {
      return true;
    }
    const rolesInProgramYear = await currentUser.getRolesInProgramYear(programYear);
    if (await permissionMatrix.hasPermission(school, 'CAN_UNLOCK_THEIR_PROGRAM_YEARS', rolesInProgramYear)) {
      return true;
    }

    return this.canUpdateProgram(program);
  },
  async canUpdateSchoolConfig(school) {
    return this.canDoInSchool(school, 'CAN_UPDATE_SCHOOL_CONFIGS');
  },
  async canUpdateSchool(school) {
    return this.canDoInSchool(school, 'CAN_UPDATE_SCHOOLS');
  },
  async canUpdateCompetency(competency) {
    const school = await competency.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_COMPETENCIES');
  },
  async canDeleteCompetency(competency) {
    const school = await competency.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_COMPETENCIES');
  },
  async canCreateCompetency(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_COMPETENCIES');
  },
  async canUpdateVocabulary(vocabulary) {
    const school = await vocabulary.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_VOCABULARIES');
  },
  async canDeleteVocabulary(vocabulary) {
    const school = await vocabulary.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_VOCABULARIES');
  },
  async canCreateVocabulary(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_VOCABULARIES');
  },
  async canUpdateTerm(term) {
    const school = await term.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_TERMS');
  },
  async canDeleteTerm(term) {
    const school = await term.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_TERMS');
  },
  async canCreateTerm(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_TERMS');
  },
  async canUpdateInstructorGroup(instructorGroup) {
    const school = await instructorGroup.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_INSTRUCTOR_GROUPS');
  },
  async canDeleteInstructorGroup(instructorGroup) {
    const school = await instructorGroup.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_INSTRUCTOR_GROUPS');
  },
  async canCreateInstructorGroup(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_INSTRUCTOR_GROUPS');
  },
  async canUpdateInstructorGroupInSchool(school) {
    return this.canDoInSchool(school, 'CAN_UPDATE_INSTRUCTOR_GROUPS');
  },
  async canDeleteInstructorGroupInSchool(school) {
    return this.canDoInSchool(school, 'CAN_DELETE_INSTRUCTOR_GROUPS');
  },
  async canUpdateCurriculumInventoryReport(curriculumInventoryReport) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    const program = await curriculumInventoryReport.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_UPDATE_ALL_CURRICULUM_INVENTORY_REPORTS')) {
      return true;
    }
    const rolesInReport = await currentUser.getRolesInCurriculumInventoryReport(curriculumInventoryReport);

    return permissionMatrix.hasPermission(school, 'CAN_UPDATE_THEIR_CURRICULUM_INVENTORY_REPORTS', rolesInReport);
  },
  async canDeleteCurriculumInventoryReport(curriculumInventoryReport) {
    const currentUser = await this.get('currentUser');
    const permissionMatrix = this.get('permissionMatrix');
    const program = await curriculumInventoryReport.get('program');
    const school = await program.get('school');
    if (await this.canDoInSchool(school, 'CAN_DELETE_ALL_CURRICULUM_INVENTORY_REPORTS')) {
      return true;
    }

    const rolesInReport = await currentUser.getRolesInCurriculumInventoryReport(curriculumInventoryReport);
    return permissionMatrix.hasPermission(school, 'CAN_DELETE_THEIR_CURRICULUM_INVENTORY_REPORTS', rolesInReport);
  },
  async canCreateCurriculumInventoryReport(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_CURRICULUM_INVENTORY_REPORTS');
  },
  async canUpdateLearnerGroup(learnerGroup) {
    const school = await learnerGroup.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_LEARNER_GROUPS');
  },
  async canDeleteLearnerGroup(learnerGroup) {
    const school = await learnerGroup.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_LEARNER_GROUPS');
  },
  async canUpdateLearnerGroupInSchool(school) {
    return this.canDoInSchool(school, 'CAN_UPDATE_LEARNER_GROUPS');
  },
  async canDeleteLearnerGroupInSchool(school) {
    return this.canDoInSchool(school, 'CAN_DELETE_LEARNER_GROUPS');
  },
  async canCreateLearnerGroup(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_LEARNER_GROUPS');
  },
  async canUpdateUser(user) {
    const school = await user.get('school');
    return this.canDoInSchool(school, 'CAN_UPDATE_USERS');
  },
  async canDeleteUser(user) {
    const school = await user.get('school');
    return this.canDoInSchool(school, 'CAN_DELETE_USERS');
  },
  async canCreateUser(school) {
    return this.canDoInSchool(school, 'CAN_CREATE_USERS');
  },
  async canUpdateUserInSchool(school) {
    return this.canDoInSchool(school, 'CAN_UPDATE_USERS');
  },
});
<|endoftext|>


<commit_before>module.exports = function(grunt) {
    var path = require("path");

    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha-test');

    var moduleCache = {};

    grunt.initConfig({
        build: {
            options: {
                modules: []
            },
            sweetjs: {
                options: {
                    compileFrom: "./lib/sweet"
                },
                src: "src/*.js",
                dest: ["build/lib/", "browser/scripts/"]
            },
            test: {
                options: {
                    // sourceMap: false,
                    compileFrom: "./build/lib/sweet"
                },
                src: "test/*.js",
                dest: "build/"
            }
        },
        copy: {
            buildMacros: {
                expand: true,
                flatten: true,
                src: "macros/*",
                dest: "build/macros/"
            },

            scopedEval: {
                expand: true,
                flatten: true,
                src: "lib/scopedEval.js",
                dest: "build/lib/"
            },
            scopedEvalBrowser: {
                expand: true,
                flatten: true,
                src: "lib/scopedEval.js",
                dest: "browser/scripts/"
            },

            browserMacros: {
                expand: true,
                flatten: true,
                src: "macros/*",
                dest: "browser/scripts/"
            },

            browserSrc: {
                expand: true,
                flatten: true,
                src: "src/*",
                dest: "browser/scripts/src/"
            },

            dist: {
                expand: true,
                flatten: true,
                src: "build/lib/*.js",
                dest: "lib/"
            }
        },
        mochaTest: {
            test: {
                options:{
                    colors: !grunt.option('no-color')
                },
                src: ["build/*.js"]
            }
        },
        jshint: {
            options: {
                eqnull: true,
                evil: true,
                boss: true,
                laxcomma: true,
                shadow: true,
                loopfunc: true
            },
            all: ["build/lib/*.js"]
        }
    });

    grunt.registerMultiTask("build", function() {
        var options = this.options({
            modules: [],
            sourceMap: true,
            compileFrom: "./lib/sweet"
        });
        var sweet = require(options.compileFrom);

        var moduleSrc = options.modules.map(function(m) {
            return moduleCache[m] || (moduleCache[m] = readModule(m));
        }).join("\n");

        this.files.forEach(function(f) {
            var dest = Array.isArray(f.dest) ? f.dest : [f.dest];
            grunt.log.writeln("output to " + dest.join(", "));

            f.src.forEach(function(file) {
                grunt.log.writeln("compiling " + file);

                var code = grunt.file.read(file);
                var output = sweet.compile(code, {
                    sourceMap: options.sourceMap,
                    filename: file,
                    macros: moduleSrc
                });

                dest.forEach(function(dest) {
                    var sourceMappingURL = dest + path.basename(file) + ".map";
                    var outputFile = output.code + "\n//# sourceMappingURL=" + path.basename(file) + ".map"
                    // macro expanded result
                    grunt.file.write(dest + path.basename(file),
                                     outputFile);
                    if (options.sourceMap) {
                        // sourcemap
                        grunt.file.write(sourceMappingURL,
                                         output.sourceMap);

                    }
                });
            })
        });

    });

    grunt.registerTask("dist", ["build:sweetjs", "copy:dist"]);

    grunt.registerTask("default", ["copy:scopedEval",
                                   "copy:buildMacros",
                                   "build",
                                   "copy:browserSrc",
                                   "copy:browserMacros",
                                   "copy:scopedEvalBrowser",
                                   "mochaTest",
                                   "jshint"]);

    function readModule(mod) {
        var path = require.resolve(mod);
        return grunt.file.read(path);
    }
};
<commit_msg>building with readable names enabled<commit_after>module.exports = function(grunt) {
    var path = require("path");

    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha-test');

    var moduleCache = {};

    grunt.initConfig({
        build: {
            options: {
                modules: []
            },
            sweetjs: {
                options: {
                    compileFrom: "./lib/sweet"
                },
                src: "src/*.js",
                dest: ["build/lib/", "browser/scripts/"]
            },
            test: {
                options: {
                    // sourceMap: false,
                    compileFrom: "./build/lib/sweet"
                },
                src: "test/*.js",
                dest: "build/"
            }
        },
        copy: {
            buildMacros: {
                expand: true,
                flatten: true,
                src: "macros/*",
                dest: "build/macros/"
            },

            scopedEval: {
                expand: true,
                flatten: true,
                src: "lib/scopedEval.js",
                dest: "build/lib/"
            },
            scopedEvalBrowser: {
                expand: true,
                flatten: true,
                src: "lib/scopedEval.js",
                dest: "browser/scripts/"
            },

            browserMacros: {
                expand: true,
                flatten: true,
                src: "macros/*",
                dest: "browser/scripts/"
            },

            browserSrc: {
                expand: true,
                flatten: true,
                src: "src/*",
                dest: "browser/scripts/src/"
            },

            dist: {
                expand: true,
                flatten: true,
                src: "build/lib/*.js",
                dest: "lib/"
            }
        },
        mochaTest: {
            test: {
                options:{
                    colors: !grunt.option('no-color')
                },
                src: ["build/*.js"]
            }
        },
        jshint: {
            options: {
                eqnull: true,
                evil: true,
                boss: true,
                laxcomma: true,
                shadow: true,
                loopfunc: true
            },
            all: ["build/lib/*.js"]
        }
    });

    grunt.registerMultiTask("build", function() {
        var options = this.options({
            modules: [],
            sourceMap: true,
            compileFrom: "./lib/sweet"
        });
        var sweet = require(options.compileFrom);

        var moduleSrc = options.modules.map(function(m) {
            return moduleCache[m] || (moduleCache[m] = readModule(m));
        }).join("\n");

        this.files.forEach(function(f) {
            var dest = Array.isArray(f.dest) ? f.dest : [f.dest];
            grunt.log.writeln("output to " + dest.join(", "));

            f.src.forEach(function(file) {
                grunt.log.writeln("compiling " + file);

                var code = grunt.file.read(file);
                var output = sweet.compile(code, {
                    sourceMap: options.sourceMap,
                    filename: file,
                    readableNames: true,
                    macros: moduleSrc
                });

                dest.forEach(function(dest) {
                    var sourceMappingURL = dest + path.basename(file) + ".map";
                    var outputFile = output.code + "\n//# sourceMappingURL=" + path.basename(file) + ".map"
                    // macro expanded result
                    grunt.file.write(dest + path.basename(file),
                                     outputFile);
                    if (options.sourceMap) {
                        // sourcemap
                        grunt.file.write(sourceMappingURL,
                                         output.sourceMap);

                    }
                });
            })
        });

    });

    grunt.registerTask("dist", ["build:sweetjs", "copy:dist"]);

    grunt.registerTask("default", ["copy:scopedEval",
                                   "copy:buildMacros",
                                   "build",
                                   "copy:browserSrc",
                                   "copy:browserMacros",
                                   "copy:scopedEvalBrowser",
                                   "mochaTest",
                                   "jshint"]);

    function readModule(mod) {
        var path = require.resolve(mod);
        return grunt.file.read(path);
    }
};
<|endoftext|>


<commit_before>module.exports = function(grunt) {
  'use strict';

  var jsFiles = 'public/js/**/*.js';
  var testFiles = 'test/**/*.js';
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    jshint: {
      options: {
        jshintrc: true
      },
      all: ['*.js', 'config/**/*.js', jsFiles, testFiles]
    },
    karma: {
      options: {
        configFile: 'config/karma.conf.js',
        preprocessors: {
          'public/partials/*.html': 'ng-html2js'
        }
      },
      once: {
        singleRun: true
      },
      ci: {
        singleRun: true,
        preprocessors: {
          'public/partials/*.html': 'ng-html2js',
          'public/js/**/*.js': ['coverage']
        },
        reporters: ['progress', 'coverage'],
        coverageReporter: {
          type: "lcov",
          dir: "coverage/"
        }
      },
      dev: {
        background: true
      }
    },
    connect: {
      server: {
        options: {
          port: 8080,
          base: 'public'
        }
      }
    },
    protractor: {
      options: {
        configFile: 'protractor.conf.js'
      },
      ci: {
        options: {
          keepAlive: false
        }
      }
    },
    shell: {
      protractor_update: {
        command: 'node_modules/grunt-protractor-runner/node_modules/protractor/bin/webdriver-manager update'
      }
    },
    watch: {
      karma: {
        files: [jsFiles, testFiles],
        tasks: ['karma:dev:run']
      }
    },
    bower: {
      install: {}
    },
    coveralls: {
      options: {
        debug: true,
        coverage_dir: 'coverage',
        force: true
      }
    }
  });

  grunt.loadNpmTasks('grunt-karma-coveralls');
  grunt.loadNpmTasks('grunt-karma');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-protractor-runner');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-bower-task');
  grunt.loadNpmTasks('grunt-contrib-connect');

  grunt.registerTask('pre_push', ['jshint', 'karma:once']);
  grunt.registerTask('e2e', ['shell:protractor_update', 'connect:server', 'protractor:ci']);
  grunt.registerTask('test', ['bower:install', 'jshint', 'karma:ci', 'e2e', 'coveralls']);
  grunt.registerTask('dev', ['karma:dev', 'watch']);

};
<commit_msg>refactor grunt config<commit_after>module.exports = function(grunt) {
  'use strict';

  var jsFiles = 'public/js/**/*.js';
  var testFiles = 'test/**/*.js';

  var config = {};

  (function configureCommon() {
    config.pkg = grunt.file.readJSON('package.json');
    config.jshint = {
      options: {
        jshintrc: true
      },
      all: ['*.js', 'config/**/*.js', jsFiles, testFiles]
    };
    config.bower = {
      install: {}
    };
  })();

  (function configureTests() {
    config.watch = {
      karma: {
        files: [jsFiles, testFiles],
        tasks: ['karma:dev:run']
      }
    };
    config.coveralls = {
      options: {
        debug: true,
        coverage_dir: 'coverage',
        force: true
      }
    };
    (function configureKarma() {
      config.karma = {
        options: {
          configFile: 'config/karma.conf.js',
          preprocessors: {
            'public/partials/*.html': 'ng-html2js'
          }
        },
        once: {
          singleRun: true
        },
        ci: {
          singleRun: true,
          preprocessors: {
            'public/partials/*.html': 'ng-html2js',
            'public/js/**/*.js': ['coverage']
          },
          reporters: ['progress', 'coverage'],
          coverageReporter: {
            type: 'lcov',
            dir: 'coverage/'
          }
        },
        dev: {
          background: true
        }
      };
    })();
    (function configureE2e() {
      config.connect = {
        server: {
          options: {
            port: 8080,
            base: 'public'
          }
        }
      };
      config.protractor = {
        options: {
          configFile: 'protractor.conf.js'
        },
        ci: {
          options: {
            keepAlive: false
          }
        }
      };
      config.shell = {
        protractor_update: {
          command: 'node_modules/grunt-protractor-runner/node_modules/protractor/bin/webdriver-manager update'
        }
      };
    })();
  })();

  // Project configuration.
  grunt.initConfig(config);

  grunt.loadNpmTasks('grunt-karma-coveralls');
  grunt.loadNpmTasks('grunt-karma');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-protractor-runner');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-bower-task');
  grunt.loadNpmTasks('grunt-contrib-connect');

  grunt.registerTask('pre_push', ['jshint', 'karma:once']);
  grunt.registerTask('e2e', ['shell:protractor_update', 'connect:server', 'protractor:ci']);
  grunt.registerTask('test', ['bower:install', 'jshint', 'karma:ci', 'e2e', 'coveralls']);
  grunt.registerTask('dev', ['karma:dev', 'watch']);

};
<|endoftext|>


<commit_before>module.exports = function (grunt) {
    'use strict';

    require('load-grunt-tasks')(grunt);
    require('time-grunt')(grunt);
    grunt.task.loadTasks('tasks');

    var LIVERELOAD_PORT = 35729;
    var lrSnippet = require('connect-livereload')({
        port: LIVERELOAD_PORT
    });
    var mountFolder = function (connect, dir) {
        return connect.static(require('path').resolve(dir));
    };
    var modRewrite = require('connect-modrewrite');
    var rewriteRules = [
        '!\\.html|\\.xml|\\images|\\.js|\\.css|\\.png|\\.jpg|\\.woff|\\.ttf|\\.svg|\\.ico /index.html [L]'
    ];

    var readConfigJson = function() {
        var _ = require('lodash');

        var isCustomEndpoint = _.findIndex(process.argv, function (val) {
            return val === 'ngconstant:custom';
        }) > -1;

        var buildId;
        var idx = _.findIndex(process.argv, function (val) {
            return val.substring(0, '--build-id='.length) === '--build-id=';
        });
        buildId = idx > -1 ? process.argv[idx].substring('--build-id='.length) : undefined;
        if (buildId !== undefined) {
            buildId = buildId.replace('.', '-');
        } else if (isCustomEndpoint) {
            grunt.fail.fatal('Unable to find --build-id=myfeature. ngconstant:custom only works with arg --build-id.');
        }
        var id = buildId === '' ? 'secxbrl' : 'secxbrl-' + buildId;
        var config = grunt.file.readJSON('config.json');
        config.custom = {};
        if (buildId !== undefined) {
            grunt.log.writeln('Report editor will be setup to run against backend: ' + id);
            config.custom.buildId = id;
        }
        return config;
    };

    // Project configuration.
    grunt.initConfig({
        config: readConfigJson(),
        watch: {
            less: {
                files:  ['app/**/*.less'],
                tasks: ['less']
            },
            livereload: {
                options: {
                    livereload: LIVERELOAD_PORT
                },
                files: [
                    'app/**/*.html',
                    '{.tmp,app}/styles/{,*/}*.css',
                    '{.tmp,app}/**/*.js',
                    'app/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
                ]
            }
        },
        //Connect
        connect: {
            options: {
                port: grunt.option('port') || 9000,
                hostname: '0.0.0.0'
            },
            livereload: {
                options: {
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            modRewrite(rewriteRules),
                            mountFolder(connect, 'app'),
                            mountFolder(connect, '')
                        ];
                    }
                }
            },
            dist: {
                options: {
                    keepalive: false,
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            modRewrite(rewriteRules),
                            mountFolder(connect, 'dist')
                        ];
                    }
                }
            },
            'dist-dev': {
                options: {
                    keepalive: false,
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            modRewrite(rewriteRules),
                            mountFolder(connect, 'app'),
                            mountFolder(connect, '')
                        ];
                    }
                }
            }
        },
        open: {
            server: {
                url: 'http://localhost:<%= connect.options.port %>'
            }
        },
        less: {
            dist: {
                options: {
                },
                files: {
                    'app/styles/index.css': ['app/styles/index.less']
                }
            }
        },
        peg: {
            options: { trackLineAndColumn: true },
            excelGrammar : {
                src: 'pegjs/excelGrammar.pegjs',
                dest: 'app/modules/excel-parser.js',
                angular: {
                    module: 'excel-parser',
                    factory: 'ExcelParser'
                }
            },
            formulaGrammar : {
                src: 'pegjs/formulaGrammar.pegjs',
                dest: 'app/modules/formula-parser.js',
                angular: {
                    module: 'formula-parser',
                    factory: 'FormulaParser'
                }
            }
        },
        'swagger-js-codegen': {
            options: {
                apis: [
                    {
                        swagger: 'swagger/reports.json',
                        moduleName: 'report-api',
                        className: 'ReportAPI',
                        fileName: 'report-api.js',
                        angularjs: true
                    },
                    {
                        swagger: 'swagger/session.json',
                        moduleName: 'session-api',
                        className: 'SessionAPI',
                        fileName: 'session-api.js',
                        angularjs: true
                    },
                    {
                        swagger: 'swagger/queries.json',
                        moduleName: 'queries-api',
                        className: 'QueriesAPI',
                        fileName: 'queries-api.js',
                        angularjs: true
                    }
                ],
                dest: 'app/modules'
            },
            all: {}
        },
        clean: {
            dist: {
                files: [{
                    dot: true,
                    src: ['.tmp', 'dist/*', '!/.git*']
                }]
            },
            server: '.tmp'
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            src: ['Gruntfile.js',
                  'app/**/*.js',
                  'tasks/**/*.js',
                  'tests/**/*.js'
            ]
        },
        karma: {
            options: {
                configFile: './karma.conf.js'
            },
            dev: {
                options: {
                    files: [
                        'bower_components/angular/angular.js',
                        'bower_components/angular-mocks-1.2.9/angular-mocks.js',
                        'bower_components/ngprogress-lite/ngprogress-lite.js',
                        'bower_components/angular-ui-router/release/angular-ui-router.js',
                        'bower_components/angular-sanitize/angular-sanitize.js',
                        'bower_components/angular-ui-bootstrap-bower/ui-bootstrap.js',
                        'bower_components/angular-ui-bootstrap-bower/ui-bootstrap-tpls.js',
                        'bower_components/angular-cache/dist/angular-cache.js',
                        'bower_components/layoutmodel-renderer-angular/app/directive/layoutmodel.js',
                        'bower_components/layoutmodel-renderer-angular/app/directive/layoutmodeltemplate.js',
                        'bower_components/flexy-layout/flexy-layout.debug.js',
                        'bower_components/angular-ui-router/release/angular-ui-router.js',
                        'bower_components/angular-ui-tree/dist/angular-ui-tree.js',

                        'app/constants.js',
                        'app/modules/report-api.js',
                        'app/modules/session-api.js',
                        'app/modules/queries-api.js',
                        'app/modules/api.js',
                        'app/modules/excel-parser.js',
                        'app/modules/formula-parser.js',
                        'app/modules/report-api.js',
                        'app/modules/report-model.js',
                        'app/modules/rules-model.js',
                        'app/app.js',
                        'app/modules/excel-parser.js',
                        'app/modules/session-model.js',
                        'app/modules/rules-model.js',
                        'app/modules/filter-model.js',
                        'app/modules/ui/api-status.js',
                        'app/modules/ui/forms.js',
                        'app/modules/ui/account.js',
                        'app/modules/ui/resize.js',
                        'app/modules/formula-parser.js',

                        'app/report/taxonomy/taxonomy.js',
                        'app/report/taxonomy/concept/overview/overview.js',

                        'tests/unit/karma.start.js',
                        'app/**/*-test.js'
                    ]
                }
            }
        },
        coveralls: {
            options: {
                'coverage_dir': 'coverage'
            }
        },
        protractor: {
            travis: 'tests/e2e/config/protractor-travis-nosaucelabs-conf.js',
            local: 'tests/e2e/config/protractor-conf.js'
        },
        ngconstant: {
            options: {
                space: '    '
            },
            server: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': '//<%= config.server.api %>/v1',
                    'REGISTRATION_URL': '<%= config.server.registration %>',
                    'ACCOUNT_URL': '<%= config.server.account %>',
                    'DEBUG': true
                }
            },
            test: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': '//<%= config.test.api %>/v1',
                    'REGISTRATION_URL': '<%= config.test.registration %>',
                    'ACCOUNT_URL': '<%= config.test.account %>',
                    'DEBUG': true
                }
            },
            beta: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': '//<%= config.beta.api %>/v1',
                    'REGISTRATION_URL': '<%= config.beta.registration %>',
                    'ACCOUNT_URL': '<%= config.beta.account %>',
                    'DEBUG': false
                }
            },
            prod: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': '//<%= config.prod.api %>/v1',
                    'REGISTRATION_URL': '<%= config.prod.registration %>',
                    'ACCOUNT_URL': '<%= config.prod.account %>',
                    'DEBUG': false
                }
            },
            custom: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': '//<%= config.custom.buildId %>.28.io/v1',
                    'REGISTRATION_URL': 'http://<%= config.custom.buildId %>.s3-website-us-east-1.amazonaws.com/auth',
                    'ACCOUNT_URL': 'http://<%= config.custom.buildId %>.s3-website-us-east-1.amazonaws.com/account/info',
                    'DEBUG': true
                }
            }
        },
        s3: {
            options: {
                access: 'public-read',
                maxOperations: 5,
                gzip: true,
                gzipExclude: ['.jpg', '.jpeg', '.png', '.xml', '.json', '.pdf', '.txt', '.ico']
            },
            prod: {
                bucket: 'reports.secxbrl.info',
                upload: [{
                    src: 'dist/**/*',
                    dest: '',
                    rel: 'dist/',
                }]
            }
        },
        jsonlint: {
            all: {
                src: [
                    'package.json',
                    'config.json',
                    'bower.json',
                    '.bowerrc',
                    'swagger/*'
                ]
            }
        },
        useminPrepare: {
            html: [ 'app/**/*.html' ],
            css: 'app/styles/**/*.css',
            options: {
                dest: 'dist'
            }
        },
        usemin: {
            html: [ 'dist/*.html' ],
            css: 'dist/styles/**/*.css',
            options: {
                dirs: ['dist']
            }
        },
        ngmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '.tmp/concat/scripts',
                    src: '*.js',
                    dest: '.tmp/concat/scripts'
                }]
            }
        },
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: 'app/images',
                    src: '*.{png,jpg,jpeg,svg}',
                    dest: 'dist/images'
                }]
            }
        },
        htmlmin: {
            dist: {
                options: {},
                files: [{
                    expand: true,
                    cwd: 'app',
                    src: [ '**/*.html'],
                    dest: 'dist'
                }]
            }
        },
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: 'app',
                    dest: 'dist',
                    src: [
                        '*.{ico,png,txt}',
                        'images/**/*.{png,jpg,jpeg,gif,webp,svg}',
                    ]
                }, {
                    expand: true,
                    cwd: 'bower_components/font-awesome/fonts',
                    dest: 'dist/fonts',
                    src: ['*']
                }, {
                    expand: true,
                    cwd: '.tmp/concat/scripts',
                    dest: 'dist/scripts',
                    src: ['*']
                }]
            }
        },
        concurrent: {
            server: [],
            test: [],
            dist: [
                'less',
                'imagemin',
                'htmlmin'
            ]
        },
        rev: {
            dist: {
                files: {
                    src: [
                        'dist/scripts/**/*.js',
                        'dist/styles/**/*.css',
                        'dist/images/**/*.{png,jpg,jpeg,gif,webp,svg}',
                        'dist/styles/fonts/*'
                    ]
                }
            }
        },
        uglify: {
            options: {
                //sourceMap: true,
                //sourceMapIncludeSources: true
            }
        }
    });

    grunt.registerTask('deploy', function() {
        if(process.env.TRAVIS_BRANCH === 'master' && process.env.TRAVIS_PULL_REQUEST === 'false') {
            grunt.task.run(['s3:prod']);
        }
    });

    grunt.registerTask('e2e', function(){
        var target = process.env.TRAVIS_JOB_NUMBER ? 'travis' : 'local';

        // log backend url
        var constants = grunt.file.read('app/constants.js');
        var startFound = constants.indexOf('"API_URL", "') + 12;
        var endFound = constants.indexOf('/v1")') - startFound;
        var backendURL = constants.substr(startFound, endFound);
        grunt.log.writeln('Running tests against backend: ' + backendURL);

        grunt.task.run([
            'webdriver',
            'connect:dist',
            'protractor:' + target
        ]);
    });

    grunt.registerTask('e2e-dev', function(){
        var target = process.env.TRAVIS_JOB_NUMBER ? 'travis' : 'local';
        grunt.task.run([
            'webdriver',
            'connect:dist-dev',
            'protractor:' + target
        ]);
    });

    grunt.registerTask('server', function (target) {
        if(target === 'dist') {
            return grunt.task.run(['build', 'open', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'peg',
            'swagger-js-codegen',
            'less',
            'concurrent:server',
            'connect:livereload',
            'open',
            'watch'
        ]);
    });

    grunt.registerTask('build', function () {
        //var env = (target ? target : 'server');

        grunt.task.run([
            'ngconstant:prod',
            'clean:dist',
            'less',
            'peg',
            'swagger-js-codegen',
            'useminPrepare',
            'concurrent:dist',
            'concat',
            'copy',
            'ngmin',
            'cssmin',
            'uglify',
            'rev',
            'usemin'
        ]);
    });

    grunt.registerTask('test', ['build', 'karma', 'e2e']);
    grunt.registerTask('default', ['jsonlint', 'jshint', 'test', 'deploy']);
};
<commit_msg>Run production backend on HTTPS<commit_after>module.exports = function (grunt) {
    'use strict';

    require('load-grunt-tasks')(grunt);
    require('time-grunt')(grunt);
    grunt.task.loadTasks('tasks');

    var LIVERELOAD_PORT = 35729;
    var lrSnippet = require('connect-livereload')({
        port: LIVERELOAD_PORT
    });
    var mountFolder = function (connect, dir) {
        return connect.static(require('path').resolve(dir));
    };
    var modRewrite = require('connect-modrewrite');
    var rewriteRules = [
        '!\\.html|\\.xml|\\images|\\.js|\\.css|\\.png|\\.jpg|\\.woff|\\.ttf|\\.svg|\\.ico /index.html [L]'
    ];

    var readConfigJson = function() {
        var _ = require('lodash');

        var isCustomEndpoint = _.findIndex(process.argv, function (val) {
            return val === 'ngconstant:custom';
        }) > -1;

        var buildId;
        var idx = _.findIndex(process.argv, function (val) {
            return val.substring(0, '--build-id='.length) === '--build-id=';
        });
        buildId = idx > -1 ? process.argv[idx].substring('--build-id='.length) : undefined;
        if (buildId !== undefined) {
            buildId = buildId.replace('.', '-');
        } else if (isCustomEndpoint) {
            grunt.fail.fatal('Unable to find --build-id=myfeature. ngconstant:custom only works with arg --build-id.');
        }
        var id = buildId === '' ? 'secxbrl' : 'secxbrl-' + buildId;
        var config = grunt.file.readJSON('config.json');
        config.custom = {};
        if (buildId !== undefined) {
            grunt.log.writeln('Report editor will be setup to run against backend: ' + id);
            config.custom.buildId = id;
        }
        return config;
    };

    // Project configuration.
    grunt.initConfig({
        config: readConfigJson(),
        watch: {
            less: {
                files:  ['app/**/*.less'],
                tasks: ['less']
            },
            livereload: {
                options: {
                    livereload: LIVERELOAD_PORT
                },
                files: [
                    'app/**/*.html',
                    '{.tmp,app}/styles/{,*/}*.css',
                    '{.tmp,app}/**/*.js',
                    'app/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
                ]
            }
        },
        //Connect
        connect: {
            options: {
                port: grunt.option('port') || 9000,
                hostname: '0.0.0.0'
            },
            livereload: {
                options: {
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            modRewrite(rewriteRules),
                            mountFolder(connect, 'app'),
                            mountFolder(connect, '')
                        ];
                    }
                }
            },
            dist: {
                options: {
                    keepalive: false,
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            modRewrite(rewriteRules),
                            mountFolder(connect, 'dist')
                        ];
                    }
                }
            },
            'dist-dev': {
                options: {
                    keepalive: false,
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            modRewrite(rewriteRules),
                            mountFolder(connect, 'app'),
                            mountFolder(connect, '')
                        ];
                    }
                }
            }
        },
        open: {
            server: {
                url: 'http://localhost:<%= connect.options.port %>'
            }
        },
        less: {
            dist: {
                options: {
                },
                files: {
                    'app/styles/index.css': ['app/styles/index.less']
                }
            }
        },
        peg: {
            options: { trackLineAndColumn: true },
            excelGrammar : {
                src: 'pegjs/excelGrammar.pegjs',
                dest: 'app/modules/excel-parser.js',
                angular: {
                    module: 'excel-parser',
                    factory: 'ExcelParser'
                }
            },
            formulaGrammar : {
                src: 'pegjs/formulaGrammar.pegjs',
                dest: 'app/modules/formula-parser.js',
                angular: {
                    module: 'formula-parser',
                    factory: 'FormulaParser'
                }
            }
        },
        'swagger-js-codegen': {
            options: {
                apis: [
                    {
                        swagger: 'swagger/reports.json',
                        moduleName: 'report-api',
                        className: 'ReportAPI',
                        fileName: 'report-api.js',
                        angularjs: true
                    },
                    {
                        swagger: 'swagger/session.json',
                        moduleName: 'session-api',
                        className: 'SessionAPI',
                        fileName: 'session-api.js',
                        angularjs: true
                    },
                    {
                        swagger: 'swagger/queries.json',
                        moduleName: 'queries-api',
                        className: 'QueriesAPI',
                        fileName: 'queries-api.js',
                        angularjs: true
                    }
                ],
                dest: 'app/modules'
            },
            all: {}
        },
        clean: {
            dist: {
                files: [{
                    dot: true,
                    src: ['.tmp', 'dist/*', '!/.git*']
                }]
            },
            server: '.tmp'
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            src: ['Gruntfile.js',
                  'app/**/*.js',
                  'tasks/**/*.js',
                  'tests/**/*.js'
            ]
        },
        karma: {
            options: {
                configFile: './karma.conf.js'
            },
            dev: {
                options: {
                    files: [
                        'bower_components/angular/angular.js',
                        'bower_components/angular-mocks-1.2.9/angular-mocks.js',
                        'bower_components/ngprogress-lite/ngprogress-lite.js',
                        'bower_components/angular-ui-router/release/angular-ui-router.js',
                        'bower_components/angular-sanitize/angular-sanitize.js',
                        'bower_components/angular-ui-bootstrap-bower/ui-bootstrap.js',
                        'bower_components/angular-ui-bootstrap-bower/ui-bootstrap-tpls.js',
                        'bower_components/angular-cache/dist/angular-cache.js',
                        'bower_components/layoutmodel-renderer-angular/app/directive/layoutmodel.js',
                        'bower_components/layoutmodel-renderer-angular/app/directive/layoutmodeltemplate.js',
                        'bower_components/flexy-layout/flexy-layout.debug.js',
                        'bower_components/angular-ui-router/release/angular-ui-router.js',
                        'bower_components/angular-ui-tree/dist/angular-ui-tree.js',

                        'app/constants.js',
                        'app/modules/report-api.js',
                        'app/modules/session-api.js',
                        'app/modules/queries-api.js',
                        'app/modules/api.js',
                        'app/modules/excel-parser.js',
                        'app/modules/formula-parser.js',
                        'app/modules/report-api.js',
                        'app/modules/report-model.js',
                        'app/modules/rules-model.js',
                        'app/app.js',
                        'app/modules/excel-parser.js',
                        'app/modules/session-model.js',
                        'app/modules/rules-model.js',
                        'app/modules/filter-model.js',
                        'app/modules/ui/api-status.js',
                        'app/modules/ui/forms.js',
                        'app/modules/ui/account.js',
                        'app/modules/ui/resize.js',
                        'app/modules/formula-parser.js',

                        'app/report/taxonomy/taxonomy.js',
                        'app/report/taxonomy/concept/overview/overview.js',

                        'tests/unit/karma.start.js',
                        'app/**/*-test.js'
                    ]
                }
            }
        },
        coveralls: {
            options: {
                'coverage_dir': 'coverage'
            }
        },
        protractor: {
            travis: 'tests/e2e/config/protractor-travis-nosaucelabs-conf.js',
            local: 'tests/e2e/config/protractor-conf.js'
        },
        ngconstant: {
            options: {
                space: '    '
            },
            server: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': '//<%= config.server.api %>/v1',
                    'REGISTRATION_URL': '<%= config.server.registration %>',
                    'ACCOUNT_URL': '<%= config.server.account %>',
                    'DEBUG': true
                }
            },
            test: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': '//<%= config.test.api %>/v1',
                    'REGISTRATION_URL': '<%= config.test.registration %>',
                    'ACCOUNT_URL': '<%= config.test.account %>',
                    'DEBUG': true
                }
            },
            beta: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': '//<%= config.beta.api %>/v1',
                    'REGISTRATION_URL': '<%= config.beta.registration %>',
                    'ACCOUNT_URL': '<%= config.beta.account %>',
                    'DEBUG': false
                }
            },
            prod: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': 'https://<%= config.prod.api %>/v1',
                    'REGISTRATION_URL': '<%= config.prod.registration %>',
                    'ACCOUNT_URL': '<%= config.prod.account %>',
                    'DEBUG': false
                }
            },
            custom: {
                dest: 'app/constants.js',
                name: 'constants',
                wrap: '/*jshint quotmark:double */\n"use strict";\n\n<%= __ngModule %>',
                constants: {
                    'APPNAME': 'report-editor',
                    'API_URL': '//<%= config.custom.buildId %>.28.io/v1',
                    'REGISTRATION_URL': 'http://<%= config.custom.buildId %>.s3-website-us-east-1.amazonaws.com/auth',
                    'ACCOUNT_URL': 'http://<%= config.custom.buildId %>.s3-website-us-east-1.amazonaws.com/account/info',
                    'DEBUG': true
                }
            }
        },
        s3: {
            options: {
                access: 'public-read',
                maxOperations: 5,
                gzip: true,
                gzipExclude: ['.jpg', '.jpeg', '.png', '.xml', '.json', '.pdf', '.txt', '.ico']
            },
            prod: {
                bucket: 'reports.secxbrl.info',
                upload: [{
                    src: 'dist/**/*',
                    dest: '',
                    rel: 'dist/',
                }]
            }
        },
        jsonlint: {
            all: {
                src: [
                    'package.json',
                    'config.json',
                    'bower.json',
                    '.bowerrc',
                    'swagger/*'
                ]
            }
        },
        useminPrepare: {
            html: [ 'app/**/*.html' ],
            css: 'app/styles/**/*.css',
            options: {
                dest: 'dist'
            }
        },
        usemin: {
            html: [ 'dist/*.html' ],
            css: 'dist/styles/**/*.css',
            options: {
                dirs: ['dist']
            }
        },
        ngmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '.tmp/concat/scripts',
                    src: '*.js',
                    dest: '.tmp/concat/scripts'
                }]
            }
        },
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: 'app/images',
                    src: '*.{png,jpg,jpeg,svg}',
                    dest: 'dist/images'
                }]
            }
        },
        htmlmin: {
            dist: {
                options: {},
                files: [{
                    expand: true,
                    cwd: 'app',
                    src: [ '**/*.html'],
                    dest: 'dist'
                }]
            }
        },
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: 'app',
                    dest: 'dist',
                    src: [
                        '*.{ico,png,txt}',
                        'images/**/*.{png,jpg,jpeg,gif,webp,svg}',
                    ]
                }, {
                    expand: true,
                    cwd: 'bower_components/font-awesome/fonts',
                    dest: 'dist/fonts',
                    src: ['*']
                }, {
                    expand: true,
                    cwd: '.tmp/concat/scripts',
                    dest: 'dist/scripts',
                    src: ['*']
                }]
            }
        },
        concurrent: {
            server: [],
            test: [],
            dist: [
                'less',
                'imagemin',
                'htmlmin'
            ]
        },
        rev: {
            dist: {
                files: {
                    src: [
                        'dist/scripts/**/*.js',
                        'dist/styles/**/*.css',
                        'dist/images/**/*.{png,jpg,jpeg,gif,webp,svg}',
                        'dist/styles/fonts/*'
                    ]
                }
            }
        },
        uglify: {
            options: {
                //sourceMap: true,
                //sourceMapIncludeSources: true
            }
        }
    });

    grunt.registerTask('deploy', function() {
        if(process.env.TRAVIS_BRANCH === 'master' && process.env.TRAVIS_PULL_REQUEST === 'false') {
            grunt.task.run(['s3:prod']);
        }
    });

    grunt.registerTask('e2e', function(){
        var target = process.env.TRAVIS_JOB_NUMBER ? 'travis' : 'local';

        // log backend url
        var constants = grunt.file.read('app/constants.js');
        var startFound = constants.indexOf('"API_URL", "') + 12;
        var endFound = constants.indexOf('/v1")') - startFound;
        var backendURL = constants.substr(startFound, endFound);
        grunt.log.writeln('Running tests against backend: ' + backendURL);

        grunt.task.run([
            'webdriver',
            'connect:dist',
            'protractor:' + target
        ]);
    });

    grunt.registerTask('e2e-dev', function(){
        var target = process.env.TRAVIS_JOB_NUMBER ? 'travis' : 'local';
        grunt.task.run([
            'webdriver',
            'connect:dist-dev',
            'protractor:' + target
        ]);
    });

    grunt.registerTask('server', function (target) {
        if(target === 'dist') {
            return grunt.task.run(['build', 'open', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'clean:server',
            'peg',
            'swagger-js-codegen',
            'less',
            'concurrent:server',
            'connect:livereload',
            'open',
            'watch'
        ]);
    });

    grunt.registerTask('build', function () {
        //var env = (target ? target : 'server');

        grunt.task.run([
            'ngconstant:prod',
            'clean:dist',
            'less',
            'peg',
            'swagger-js-codegen',
            'useminPrepare',
            'concurrent:dist',
            'concat',
            'copy',
            'ngmin',
            'cssmin',
            'uglify',
            'rev',
            'usemin'
        ]);
    });

    grunt.registerTask('test', ['build', 'karma', 'e2e']);
    grunt.registerTask('default', ['jsonlint', 'jshint', 'test', 'deploy']);
};
<|endoftext|>