<commit_before>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Utility for fast string concatenation.
 */

goog.provide('goog.string.StringBuffer');

/**
 * Utility class to facilitate string concatenation.
 *
 * @param {Object|number|string|boolean=} opt_a1 Optional first initial item
 *     to append.
 * @param {...Object|number|string|boolean} var_args Other initial items to
 *     append, e.g., new goog.string.StringBuffer('foo', 'bar').
 * @constructor
 */
goog.string.StringBuffer = function(opt_a1, var_args) {
  if (opt_a1 != null) {
    this.append.apply(this, arguments);
  }
};

/**
 * Internal buffer for the string to be concatenated.
 * @type {string}
 * @private
 */
goog.string.StringBuffer.prototype.buffer_ = '';

/**
 * Sets the contents of the string buffer object, replacing what's currently
 * there.
 *
 * @param {Object|number|string|boolean} s String to set.
 */
goog.string.StringBuffer.prototype.set = function(s) {
  this.buffer_ = '' + s;
};

/**
 * Appends one or more items to the buffer.
 *
 * Calling this with null, undefined, or empty arguments is an error.
 *
 * @param {*} a1 Required first string.
 * @param {*=} opt_a2 Optional second string.
 * @param {...*} var_args Other items to append,
 *     e.g., sb.append('foo', 'bar', 'baz').
 * @return {goog.string.StringBuffer} This same StringBuffer object.
 * @suppress {duplicate}
 */
goog.string.StringBuffer.prototype.append = function(a1, opt_a2, var_args) {
  // Use a1 directly to avoid arguments instantiation for single-arg case.
  this.buffer_ += a1;
  if (opt_a2 != null) { // second argument is undefined (null == undefined)
    for (var i = 1; i < arguments.length; i++) {
      this.buffer_ += arguments[i];
    }
  }
  return this;
};

/**
 * Clears the internal buffer.
 */
goog.string.StringBuffer.prototype.clear = function() {
  this.buffer_ = '';
};

/**
 * @return {number} the length of the current contents of the buffer.
 */
goog.string.StringBuffer.prototype.getLength = function() {
  return this.buffer_.length;
};

/**
 * @return {string} The concatenated string.
 * @override
 */
goog.string.StringBuffer.prototype.toString = function() {
  return this.buffer_;
};
<commit_msg><commit_after>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Utility for fast string concatenation.
 */

goog.provide('goog.string.StringBuffer');

/**
 * Utility class to facilitate string concatenation.
 *
 * @param {Object|number|string|boolean=} opt_a1 Optional first initial item
 *     to append.
 * @param {...Object|number|string|boolean} var_args Other initial items to
 *     append, e.g., new goog.string.StringBuffer('foo', 'bar').
 * @constructor
 */
goog.string.StringBuffer = function(opt_a1, var_args) {
  if (opt_a1 != null) {
    this.append.apply(this, arguments);
  }
};

/**
 * Internal buffer for the string to be concatenated.
 * @type {string}
 * @private
 */
goog.string.StringBuffer.prototype.buffer_ = '';

/**
 * Sets the contents of the string buffer object, replacing what's currently
 * there.
 *
 * @param {Object|number|string|boolean} s String to set.
 */
goog.string.StringBuffer.prototype.set = function(s) {
  this.buffer_ = '' + s;
};

/**
 * Appends one or more items to the buffer.
 *
 * Calling this with null, undefined, or empty arguments is an error.
 *
 * @param {Object|number|string|boolean} a1 Required first string.
 * @param {Object|number|string|boolean=} opt_a2 Optional second string.
 * @param {...Object|number|string|boolean} var_args Other items to append,
 *     e.g., sb.append('foo', 'bar', 'baz').
 * @return {goog.string.StringBuffer} This same StringBuffer object.
 * @suppress {duplicate}
 */
goog.string.StringBuffer.prototype.append = function(a1, opt_a2, var_args) {
  // Use a1 directly to avoid arguments instantiation for single-arg case.
  this.buffer_ += a1;
  if (opt_a2 != null) { // second argument is undefined (null == undefined)
    for (var i = 1; i < arguments.length; i++) {
      this.buffer_ += arguments[i];
    }
  }
  return this;
};

/**
 * Clears the internal buffer.
 */
goog.string.StringBuffer.prototype.clear = function() {
  this.buffer_ = '';
};

/**
 * @return {number} the length of the current contents of the buffer.
 */
goog.string.StringBuffer.prototype.getLength = function() {
  return this.buffer_.length;
};

/**
 * @return {string} The concatenated string.
 * @override
 */
goog.string.StringBuffer.prototype.toString = function() {
  return this.buffer_;
};

<|endoftext|>


<commit_before>// Copyright 2010 The Closure Library Authors. All Rights Reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Native browser textarea renderer for {@link goog.ui.Textarea}s.
 */

goog.provide('goog.ui.TextareaRenderer');

goog.require('goog.dom.TagName');
goog.require('goog.ui.Component');
goog.require('goog.ui.ControlRenderer');

/**
 * Renderer for {@link goog.ui.Textarea}s.  Renders and decorates native HTML
 * textarea elements.  Since native HTML textareas have built-in support for
 * many features, overrides many expensive (and redundant) superclass methods to
 * be no-ops.
 * @constructor
 * @extends {goog.ui.ControlRenderer}
 * @final
 */
goog.ui.TextareaRenderer = function() {
  goog.ui.ControlRenderer.call(this);
};
goog.inherits(goog.ui.TextareaRenderer, goog.ui.ControlRenderer);
goog.addSingletonGetter(goog.ui.TextareaRenderer);

/**
 * Default CSS class to be applied to the root element of components rendered
 * by this renderer.
 * @type {string}
 */
goog.ui.TextareaRenderer.CSS_CLASS = goog.getCssName('goog-textarea');

/** @override */
goog.ui.TextareaRenderer.prototype.getAriaRole = function() {
  // textareas don't need ARIA roles to be recognized by screen readers.
  return undefined;
};

/** @override */
goog.ui.TextareaRenderer.prototype.decorate = function(control, element) {
  this.setUpTextarea_(control);
  goog.ui.TextareaRenderer.superClass_.decorate.call(this, control, element);
  control.setContent(element.value);
  return element;
};

/**
 * Returns the textarea's contents wrapped in an HTML textarea element.  Sets
 * the textarea's disabled attribute as needed.
 * @param {goog.ui.Control} textarea Textarea to render.
 * @return {!Element} Root element for the Textarea control (an HTML textarea
 *     element).
 * @override
 */
goog.ui.TextareaRenderer.prototype.createDom = function(textarea) {
  this.setUpTextarea_(textarea);
  var element = textarea.getDomHelper().createDom(
      goog.dom.TagName.TEXTAREA, {
        'class': this.getClassNames(textarea).join(' '),
        'disabled': !textarea.isEnabled()
      },
      textarea.getContent() || '');
  return element;
};

/**
 * Overrides {@link goog.ui.TextareaRenderer#canDecorate} by returning true only
 * if the element is an HTML textarea.
 * @param {Element} element Element to decorate.
 * @return {boolean} Whether the renderer can decorate the element.
 * @override
 */
goog.ui.TextareaRenderer.prototype.canDecorate = function(element) {
  return element.tagName == goog.dom.TagName.TEXTAREA;
};

/**
 * Textareas natively support right-to-left rendering.
 * @override
 */
goog.ui.TextareaRenderer.prototype.setRightToLeft = goog.nullFunction;

/**
 * Textareas are always focusable as long as they are enabled.
 * @override
 */
goog.ui.TextareaRenderer.prototype.isFocusable = function(textarea) {
  return textarea.isEnabled();
};

/**
 * Textareas natively support keyboard focus.
 * @override
 */
goog.ui.TextareaRenderer.prototype.setFocusable = goog.nullFunction;

/**
 * Textareas also expose the DISABLED state in the HTML textarea's
 * {@code disabled} attribute.
 * @override
 */
goog.ui.TextareaRenderer.prototype.setState = function(
    textarea, state, enable) {
  goog.ui.TextareaRenderer.superClass_.setState.call(
      this, textarea, state, enable);
  var element = textarea.getElement();
  if (element && state == goog.ui.Component.State.DISABLED) {
    element.disabled = enable;
  }
};

/**
 * Textareas don't need ARIA states to support accessibility, so this is
 * a no-op.
 * @override
 */
goog.ui.TextareaRenderer.prototype.updateAriaState = goog.nullFunction;

/**
 * Sets up the textarea control such that it doesn't waste time adding
 * functionality that is already natively supported by browser
 * textareas.
 * @param {goog.ui.Control} textarea Textarea control to configure.
 * @private
 */
goog.ui.TextareaRenderer.prototype.setUpTextarea_ = function(textarea) {
  textarea.setHandleMouseEvents(false);
  textarea.setAutoStates(goog.ui.Component.State.ALL, false);
  textarea.setSupportedState(goog.ui.Component.State.FOCUSED, false);
};

/** @override **/
goog.ui.TextareaRenderer.prototype.setContent = function(element, value) {
  if (element) {
    element.value = value;
  }
};

/** @override **/
goog.ui.TextareaRenderer.prototype.getCssClass = function() {
  return goog.ui.TextareaRenderer.CSS_CLASS;
};
<commit_msg>Release @final from goog.ui.TextareaRenderer so that it can be extended by docs.revisions.RevisionTileTextboxRenderer in cl/142862368<commit_after>// Copyright 2010 The Closure Library Authors. All Rights Reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Native browser textarea renderer for {@link goog.ui.Textarea}s.
 */

goog.provide('goog.ui.TextareaRenderer');

goog.require('goog.dom.TagName');
goog.require('goog.ui.Component');
goog.require('goog.ui.ControlRenderer');

/**
 * Renderer for {@link goog.ui.Textarea}s.  Renders and decorates native HTML
 * textarea elements.  Since native HTML textareas have built-in support for
 * many features, overrides many expensive (and redundant) superclass methods to
 * be no-ops.
 * @constructor
 * @extends {goog.ui.ControlRenderer}
 */
goog.ui.TextareaRenderer = function() {
  goog.ui.ControlRenderer.call(this);
};
goog.inherits(goog.ui.TextareaRenderer, goog.ui.ControlRenderer);
goog.addSingletonGetter(goog.ui.TextareaRenderer);

/**
 * Default CSS class to be applied to the root element of components rendered
 * by this renderer.
 * @type {string}
 */
goog.ui.TextareaRenderer.CSS_CLASS = goog.getCssName('goog-textarea');

/** @override */
goog.ui.TextareaRenderer.prototype.getAriaRole = function() {
  // textareas don't need ARIA roles to be recognized by screen readers.
  return undefined;
};

/** @override */
goog.ui.TextareaRenderer.prototype.decorate = function(control, element) {
  this.setUpTextarea_(control);
  goog.ui.TextareaRenderer.superClass_.decorate.call(this, control, element);
  control.setContent(element.value);
  return element;
};

/**
 * Returns the textarea's contents wrapped in an HTML textarea element.  Sets
 * the textarea's disabled attribute as needed.
 * @param {goog.ui.Control} textarea Textarea to render.
 * @return {!Element} Root element for the Textarea control (an HTML textarea
 *     element).
 * @override
 */
goog.ui.TextareaRenderer.prototype.createDom = function(textarea) {
  this.setUpTextarea_(textarea);
  var element = textarea.getDomHelper().createDom(
      goog.dom.TagName.TEXTAREA, {
        'class': this.getClassNames(textarea).join(' '),
        'disabled': !textarea.isEnabled()
      },
      textarea.getContent() || '');
  return element;
};

/**
 * Overrides {@link goog.ui.TextareaRenderer#canDecorate} by returning true only
 * if the element is an HTML textarea.
 * @param {Element} element Element to decorate.
 * @return {boolean} Whether the renderer can decorate the element.
 * @override
 */
goog.ui.TextareaRenderer.prototype.canDecorate = function(element) {
  return element.tagName == goog.dom.TagName.TEXTAREA;
};

/**
 * Textareas natively support right-to-left rendering.
 * @override
 */
goog.ui.TextareaRenderer.prototype.setRightToLeft = goog.nullFunction;

/**
 * Textareas are always focusable as long as they are enabled.
 * @override
 */
goog.ui.TextareaRenderer.prototype.isFocusable = function(textarea) {
  return textarea.isEnabled();
};

/**
 * Textareas natively support keyboard focus.
 * @override
 */
goog.ui.TextareaRenderer.prototype.setFocusable = goog.nullFunction;

/**
 * Textareas also expose the DISABLED state in the HTML textarea's
 * {@code disabled} attribute.
 * @override
 */
goog.ui.TextareaRenderer.prototype.setState = function(
    textarea, state, enable) {
  goog.ui.TextareaRenderer.superClass_.setState.call(
      this, textarea, state, enable);
  var element = textarea.getElement();
  if (element && state == goog.ui.Component.State.DISABLED) {
    element.disabled = enable;
  }
};

/**
 * Textareas don't need ARIA states to support accessibility, so this is
 * a no-op.
 * @override
 */
goog.ui.TextareaRenderer.prototype.updateAriaState = goog.nullFunction;

/**
 * Sets up the textarea control such that it doesn't waste time adding
 * functionality that is already natively supported by browser
 * textareas.
 * @param {goog.ui.Control} textarea Textarea control to configure.
 * @private
 */
goog.ui.TextareaRenderer.prototype.setUpTextarea_ = function(textarea) {
  textarea.setHandleMouseEvents(false);
  textarea.setAutoStates(goog.ui.Component.State.ALL, false);
  textarea.setSupportedState(goog.ui.Component.State.FOCUSED, false);
};

/** @override **/
goog.ui.TextareaRenderer.prototype.setContent = function(element, value) {
  if (element) {
    element.value = value;
  }
};

/** @override **/
goog.ui.TextareaRenderer.prototype.getCssClass = function() {
  return goog.ui.TextareaRenderer.CSS_CLASS;
};
<|endoftext|>


<commit_before>import Ember from 'ember';
import DS from 'ember-data';

var attr = DS.attr,
    hasMany = DS.hasMany,
    belongsTo = DS.belongsTo;

export default DS.Model.extend({
  language:       attr('string'),
  state:          attr('string', {defaultValue: 'draft'}),
  origin:         attr('string'),
  stairs:         attr('boolean'),
  parking:        attr('boolean'),
  estimatedSize:  attr('string'),
  notes:          attr('string'),
  createdAt:      attr('date'),
  updatedAt:      attr('date'),
  submittedAt:    attr('date'),
  cancelledAt:    attr('date'),
  state_event:    attr('string'),
  reviewedAt:     attr('date'),
  receivedAt:     attr('date'),
  reviewCompletedAt: attr('date'),
  deliveredBy:    attr('string'),

  gogovanTransport:    belongsTo('gogovan_transport'),
  crossroadsTransport: belongsTo('crossroads_transport'),

  // used for items of current-offer
  saleable:       attr('boolean'),

  items:          hasMany('item'),
  messages:       hasMany('message'),

  delivery:       belongsTo('delivery'),
  createdBy:      belongsTo('user'),
  reviewedBy:     belongsTo('user'),
  closedBy:       belongsTo('user'),

  // User details
  userName:       attr('string'),
  userPhone:      attr('string'),

  crossroadsTruckCost: function(){
    return this.get('crossroadsTransport.cost');
  }.property('crossroadsTransport'),

  itemCount: function() {
    return this.get("items").rejectBy("state", "draft").length;
  }.property('items.@each.state'),

  packages: function() {
    return this.store.filter("package", p => p.get("offerId") === parseInt(this.get("id")));
  }.property(),

  itemPackages: function() {
    return this.store.all("package").filterBy("offerId", parseInt(this.get("id")));
  }.property(),

  approvedItems: Ember.computed.filterBy("items", "state", "accepted"),
  rejectedItems: Ember.computed.filterBy("items", "state", "rejected"),
  submittedItems: Ember.computed.filterBy("items", "state", "submitted"),
  isDraft: Ember.computed.equal("state", "draft"),
  isSubmitted: Ember.computed.equal("state", "submitted"),
  isScheduled: Ember.computed.equal("state", "scheduled"),
  isUnderReview: Ember.computed.equal("state", "under_review"),
  isReviewed: Ember.computed.equal("state", "reviewed"),
  isClosed: Ember.computed.equal("state", "closed"),
  isReceived: Ember.computed.equal("state", "received"),
  isCancelled: Ember.computed.equal("state", "cancelled"),

  activeItems: function(){
    return this.get('items').rejectBy("state", "draft");
  }.property('items.@each.state'),

  isReviewing: function(){
    return this.get('isUnderReview') || this.get('isReviewed');
  }.property('isUnderReview', 'isReviewed'),

  needReview: function(){
    return this.get('isUnderReview') || this.get('isSubmitted') || this.get("isClosed");
  }.property('isUnderReview', 'isSubmitted', 'isClosed'),

  isFinished: function() {
    return this.get('isClosed') || this.get('isReceived') || this.get('isCancelled');
  }.property('isClosed', 'isReceived', 'isCancelled'),

  nonEmptyOffer: function(){
    return this.get('itemCount') > 0;
  }.property('items.@each'),

  allItemsReviewed: function(){
    var reviewedItems = this.get('activeItems').filterBy('state', 'submitted');
    return this.get('needReview') && reviewedItems.get('length') === 0;
  }.property('items.@each.state', 'needReview'),

  allItemsRejected: function(){
    var rejectedItems = this.get('activeItems').filterBy('state', 'rejected');
    return this.get('needReview') && (rejectedItems.get('length') === this.get('itemCount'));
  }.property('items.@each.state', 'needReview'),

  displayImageUrl: function(){
    return this.get("activeItems.firstObject.displayImageUrl") || "assets/images/default_item.jpg";
  }.property('items.@each.displayImageUrl'),

  isCharitableSale: function() {
    var isSaleable = this.get("items").rejectBy("saleable", false).length > 0;
    return  isSaleable ? this.locale("yes") : this.locale("no");
  }.property('items.@each.saleable'),

  isAccepted: function() {
    return (this.get("approvedItems").length > 0) && this.get('isReviewed');
  }.property('items.@each.saleable'),

  status: function(){
    var state = this.get('state');
    var status;
    switch(state) {
      case 'draft': return this.locale('offers.index.complete_offer');
      case 'under_review' : return this.locale('offers.index.in_review');
      case 'submitted' : return this.locale('offers.index.awaiting_review');
      case 'reviewed' : return this.locale('offers.index.arrange_transport');
      case 'scheduled' : return this.scheduledStatus();
      case 'closed' : return this.locale('offers.index.closed');
      case 'received' : return this.locale('offers.index.received');
    }
    return status;
  }.property('state'),

  locale: function(text) {
    return Ember.I18n.t(text);
  },

  statusText: function(){
    return this.get("isDraft") ? this.get("status") : (this.get("status") + " ("+ this.get("itemCount") + " "+ this.locale("items_text") +")")
  }.property('status'),

  scheduledStatus: function(){
    var deliveryType = this.get("delivery.deliveryType")
    switch(deliveryType) {
      case "Gogovan" : return this.get("gogovan_status");
      case "Drop Off" : return this.locale("offers.index.drop_off");
      case "Alternate" : return this.locale("offers.index.alternate");
    }
  },

  gogovan_status: function(){
    var ggvStatus = this.get("delivery.gogovanOrder.status");
    switch(ggvStatus) {
      case "pending": return this.locale("offers.index.van_booked");
      case "active": return this.locale("offers.index.van_confirmed");
      case "completed": return this.locale("offers.index.picked_up");
    }
  }.property("delivery.gogovanOrder.status"),

  isOffer: function() {
    return this.get('constructor.typeKey') === 'offer';
  }.property('this'),

  // unread offer-items messages
  unreadMessagesCount: function() {
    return this.get('messages').filterBy('state', 'unread').length;
  }.property('messages.@each.state'),

  hasUnreadMessages: function() {
    return this.get('unreadMessagesCount') > 0;
  }.property('unreadMessagesCount'),

  // unread offer-messages
  unreadOfferMessages: function(){
    return this.get('messages').filterBy('state', 'unread').filterBy('item', null).sortBy('createdAt');
  }.property('messages.@each.state'),

  unreadOfferMessagesCount: function(){
    var count = this.get('unreadOfferMessages.length');
    return count > 0 ? count : '';
  }.property('unreadOfferMessages'),

  // unread offer-messages by donor
  hasUnreadDonorMessages: function(){
    return this.get('unreadOfferMessages').filterBy('isPrivate', false).length > 0;
  }.property('unreadOfferMessages'),

  // unread offer-messages by supervisor-reviewer
  hasUnreadPrivateMessages: function(){
    return this.get('unreadOfferMessages').filterBy('isPrivate', true).length > 0;
  }.property('unreadOfferMessages'),

  // recent offer message
  lastMessage: function() {
    var messages = this.get('messages').filterBy('item', null).sortBy('createdAt');
    return messages.get('length') > 0 ? messages.get('lastObject') : null;
  }.property('messages.[]'),

  hasCrossroadsTransport: function(){
    return this.get('crossroadsTransport') && this.get('crossroadsTransport.isVanAllowed')
  }.property('crossroadsTransport'),

  hasGogovanTransport: function(){
    return this.get('gogovanTransport') && this.get('gogovanTransport.name') !== Ember.I18n.t("offer.disable");
  }.property('gogovanTransport'),

  // display "General Messages Thread"
  displayGeneralMessages: function(){
    return !(this.get('isDraft') && this.get('lastMessage') === null);
  }.property('isDraft', 'lastMessage'),

  // to sort on offer-details page for updated-offer and latest-message
  latestUpdatedTime: function(){
    var value;
    switch(Ember.compare(this.get('lastMessage.createdAt'), this.get('updatedAt'))) {
      case 0 :
      case 1 : value = this.get('lastMessage.createdAt'); break;
      case -1 : value = this.get('updatedAt'); break;
    }
    return value;
  }.property('lastMessage'),

  showOfferIcons:  function(){
    return this.get("itemCount") > 0 && !(this.get('isClosed') || this.get('isReceived'));
  }.property('itemCount', 'isClosed', 'isReceived'),

  preventNewItem:  function(){
    return this.get('isReviewed') || this.get('isScheduled') || this.get('isFinished');
  }.property('isReviewed', 'isScheduled', 'isFinished'),

  statusBarClass: function(){
    if(this.get("isSubmitted")){ return "is-submitted"}
    else if(this.get("isUnderReview")){ return "is-under-review"}
    else if(this.get("isReviewed")){return "is-reviewed"}
    else if(this.get("isScheduled")){return "is-scheduled"}
    else if(this.get("isClosed")){return "is-closed"}
    else if(this.get("isReceived")){return "is-received"}
  }.property("state"),

  showDeliveryDetails: function(){
    return this.get("isScheduled") || this.get("isReceived");
  }.property("state"),

  hideBookingModification: function(){
    var session = this.container.lookup("service:session");
    return !session.get('isAdminApp') && this.get("delivery.isGogovan")
    && this.get("delivery.gogovanOrder.isCompleted");
  }.property("delivery.gogovanOrder", "delivery.gogovanOrder.status")

});
<commit_msg>Fixed my list tab count<commit_after>import Ember from 'ember';
import DS from 'ember-data';

var attr = DS.attr,
    hasMany = DS.hasMany,
    belongsTo = DS.belongsTo;

export default DS.Model.extend({
  language:       attr('string'),
  state:          attr('string', {defaultValue: 'draft'}),
  origin:         attr('string'),
  stairs:         attr('boolean'),
  parking:        attr('boolean'),
  estimatedSize:  attr('string'),
  notes:          attr('string'),
  createdAt:      attr('date'),
  updatedAt:      attr('date'),
  submittedAt:    attr('date'),
  cancelledAt:    attr('date'),
  state_event:    attr('string'),
  reviewedAt:     attr('date'),
  receivedAt:     attr('date'),
  reviewCompletedAt: attr('date'),
  deliveredBy:    attr('string'),

  gogovanTransport:    belongsTo('gogovan_transport'),
  crossroadsTransport: belongsTo('crossroads_transport'),

  // used for items of current-offer
  saleable:       attr('boolean'),

  items:          hasMany('item'),
  messages:       hasMany('message'),

  delivery:       belongsTo('delivery'),
  createdBy:      belongsTo('user'),
  reviewedBy:     belongsTo('user'),
  closedBy:       belongsTo('user'),

  // User details
  userName:       attr('string'),
  userPhone:      attr('string'),

  crossroadsTruckCost: function(){
    return this.get('crossroadsTransport.cost');
  }.property('crossroadsTransport'),

  itemCount: function() {
    return this.get("items").rejectBy("state", "draft").length;
  }.property('items.@each.state'),

  packages: function() {
    return this.store.filter("package", p => p.get("offerId") === parseInt(this.get("id")));
  }.property(),

  itemPackages: function() {
    return this.store.all("package").filterBy("offerId", parseInt(this.get("id")));
  }.property(),

  approvedItems: Ember.computed.filterBy("items", "state", "accepted"),
  rejectedItems: Ember.computed.filterBy("items", "state", "rejected"),
  submittedItems: Ember.computed.filterBy("items", "state", "submitted"),
  isDraft: Ember.computed.equal("state", "draft"),
  isSubmitted: Ember.computed.equal("state", "submitted"),
  isScheduled: Ember.computed.equal("state", "scheduled"),
  isUnderReview: Ember.computed.equal("state", "under_review"),
  isReviewed: Ember.computed.equal("state", "reviewed"),
  isClosed: Ember.computed.equal("state", "closed"),
  isReceived: Ember.computed.equal("state", "received"),
  isCancelled: Ember.computed.equal("state", "cancelled"),

  activeItems: function(){
    return this.get('items').rejectBy("state", "draft");
  }.property('items.@each.state'),

  isReviewing: function(){
    return this.get('isUnderReview') || this.get('isReviewed');
  }.property('isUnderReview', 'isReviewed'),

  adminCurrentOffer: function() {
    return this.get("isReviewing") || this.get("isScheduled");
  }.property('isReviewing', 'isScheduled'),

  needReview: function(){
    return this.get('isUnderReview') || this.get('isSubmitted') || this.get("isClosed");
  }.property('isUnderReview', 'isSubmitted', 'isClosed'),

  isFinished: function() {
    return this.get('isClosed') || this.get('isReceived') || this.get('isCancelled');
  }.property('isClosed', 'isReceived', 'isCancelled'),

  nonEmptyOffer: function(){
    return this.get('itemCount') > 0;
  }.property('items.@each'),

  allItemsReviewed: function(){
    var reviewedItems = this.get('activeItems').filterBy('state', 'submitted');
    return this.get('needReview') && reviewedItems.get('length') === 0;
  }.property('items.@each.state', 'needReview'),

  allItemsRejected: function(){
    var rejectedItems = this.get('activeItems').filterBy('state', 'rejected');
    return this.get('needReview') && (rejectedItems.get('length') === this.get('itemCount'));
  }.property('items.@each.state', 'needReview'),

  displayImageUrl: function(){
    return this.get("activeItems.firstObject.displayImageUrl") || "assets/images/default_item.jpg";
  }.property('items.@each.displayImageUrl'),

  isCharitableSale: function() {
    var isSaleable = this.get("items").rejectBy("saleable", false).length > 0;
    return  isSaleable ? this.locale("yes") : this.locale("no");
  }.property('items.@each.saleable'),

  isAccepted: function() {
    return (this.get("approvedItems").length > 0) && this.get('isReviewed');
  }.property('items.@each.saleable'),

  status: function(){
    var state = this.get('state');
    var status;
    switch(state) {
      case 'draft': return this.locale('offers.index.complete_offer');
      case 'under_review' : return this.locale('offers.index.in_review');
      case 'submitted' : return this.locale('offers.index.awaiting_review');
      case 'reviewed' : return this.locale('offers.index.arrange_transport');
      case 'scheduled' : return this.scheduledStatus();
      case 'closed' : return this.locale('offers.index.closed');
      case 'received' : return this.locale('offers.index.received');
    }
    return status;
  }.property('state'),

  locale: function(text) {
    return Ember.I18n.t(text);
  },

  statusText: function(){
    return this.get("isDraft") ? this.get("status") : (this.get("status") + " ("+ this.get("itemCount") + " "+ this.locale("items_text") +")")
  }.property('status'),

  scheduledStatus: function(){
    var deliveryType = this.get("delivery.deliveryType")
    switch(deliveryType) {
      case "Gogovan" : return this.get("gogovan_status");
      case "Drop Off" : return this.locale("offers.index.drop_off");
      case "Alternate" : return this.locale("offers.index.alternate");
    }
  },

  gogovan_status: function(){
    var ggvStatus = this.get("delivery.gogovanOrder.status");
    switch(ggvStatus) {
      case "pending": return this.locale("offers.index.van_booked");
      case "active": return this.locale("offers.index.van_confirmed");
      case "completed": return this.locale("offers.index.picked_up");
    }
  }.property("delivery.gogovanOrder.status"),

  isOffer: function() {
    return this.get('constructor.typeKey') === 'offer';
  }.property('this'),

  // unread offer-items messages
  unreadMessagesCount: function() {
    return this.get('messages').filterBy('state', 'unread').length;
  }.property('messages.@each.state'),

  hasUnreadMessages: function() {
    return this.get('unreadMessagesCount') > 0;
  }.property('unreadMessagesCount'),

  // unread offer-messages
  unreadOfferMessages: function(){
    return this.get('messages').filterBy('state', 'unread').filterBy('item', null).sortBy('createdAt');
  }.property('messages.@each.state'),

  unreadOfferMessagesCount: function(){
    var count = this.get('unreadOfferMessages.length');
    return count > 0 ? count : '';
  }.property('unreadOfferMessages'),

  // unread offer-messages by donor
  hasUnreadDonorMessages: function(){
    return this.get('unreadOfferMessages').filterBy('isPrivate', false).length > 0;
  }.property('unreadOfferMessages'),

  // unread offer-messages by supervisor-reviewer
  hasUnreadPrivateMessages: function(){
    return this.get('unreadOfferMessages').filterBy('isPrivate', true).length > 0;
  }.property('unreadOfferMessages'),

  // recent offer message
  lastMessage: function() {
    var messages = this.get('messages').filterBy('item', null).sortBy('createdAt');
    return messages.get('length') > 0 ? messages.get('lastObject') : null;
  }.property('messages.[]'),

  hasCrossroadsTransport: function(){
    return this.get('crossroadsTransport') && this.get('crossroadsTransport.isVanAllowed')
  }.property('crossroadsTransport'),

  hasGogovanTransport: function(){
    return this.get('gogovanTransport') && this.get('gogovanTransport.name') !== Ember.I18n.t("offer.disable");
  }.property('gogovanTransport'),

  // display "General Messages Thread"
  displayGeneralMessages: function(){
    return !(this.get('isDraft') && this.get('lastMessage') === null);
  }.property('isDraft', 'lastMessage'),

  // to sort on offer-details page for updated-offer and latest-message
  latestUpdatedTime: function(){
    var value;
    switch(Ember.compare(this.get('lastMessage.createdAt'), this.get('updatedAt'))) {
      case 0 :
      case 1 : value = this.get('lastMessage.createdAt'); break;
      case -1 : value = this.get('updatedAt'); break;
    }
    return value;
  }.property('lastMessage'),

  showOfferIcons:  function(){
    return this.get("itemCount") > 0 && !(this.get('isClosed') || this.get('isReceived'));
  }.property('itemCount', 'isClosed', 'isReceived'),

  preventNewItem:  function(){
    return this.get('isReviewed') || this.get('isScheduled') || this.get('isFinished');
  }.property('isReviewed', 'isScheduled', 'isFinished'),

  statusBarClass: function(){
    if(this.get("isSubmitted")){ return "is-submitted"}
    else if(this.get("isUnderReview")){ return "is-under-review"}
    else if(this.get("isReviewed")){return "is-reviewed"}
    else if(this.get("isScheduled")){return "is-scheduled"}
    else if(this.get("isClosed")){return "is-closed"}
    else if(this.get("isReceived")){return "is-received"}
  }.property("state"),

  showDeliveryDetails: function(){
    return this.get("isScheduled") || this.get("isReceived");
  }.property("state"),

  hideBookingModification: function(){
    var session = this.container.lookup("service:session");
    return !session.get('isAdminApp') && this.get("delivery.isGogovan")
    && this.get("delivery.gogovanOrder.isCompleted");
  }.property("delivery.gogovanOrder", "delivery.gogovanOrder.status")

});
<|endoftext|>


<commit_before>import { parse as urlParse } from 'url'
import { normalize as pathNormalize, join as pathJoin } from 'path'
import fetch from 'node-fetch'
import { createStore, applyMiddleware } from 'redux'
import createLogger from 'redux-logger'
import moment from 'moment'
import { postToSlack } from '../../lib/slack'
import { download, upload } from '../../lib/s3'

let invocationCounter = 0

const initialState = {}

const logger = createLogger({
  colors: {
    title: false,
    prevState: false,
    action: false,
    nextState: false,
    error: false
  }
})

function reducer (state = initialState, action) {
  switch (action.type) {
    case 'FETCH_OLD_COMMENTS':
      {
        const { dirName, comments, timestamp } = action
        return {
          ...state,
          [dirName]: {
            timestamp,
            comments,
          }
        }
      }
    case 'NEW_COMMENT':
      {
        const {
          dirName,
          submittedDate: date,
          payload: {
            id,
            commentContent,
            authorName,
            authorUrl
          }
        } = action
        const comments = state[dirName] ? [...state[dirName].comments] : []
        const timestamp = moment.utc()
        comments.push({
          id,
          date,
          authorName,
          authorUrl,
          commentContent
        })
        return {
          ...state,
          [dirName]: {
            timestamp,
            comments,
          }
        }
      }
    default:
      return state
  }
}

// const store = createStore(reducer, applyMiddleware(logger))
const store = createStore(reducer)

async function fetchOldComments({ dirName, quiet }) {
  const state = store.getState()
  if (state[dirName] &&
      moment().subtract(20, 'seconds').isBefore(state[dirName].timestamp)) {
    // Use cache if it's under 20 seconds old
    if (!quiet) {
      console.log('Using cached old comments')
    }
    return
  }
  const key = `${dirName}/comments.json`
  try {
    if (!quiet) {
      console.log('Loading old comments from S3')
    }
    const fileData = await download({ key })
    const { LastModified: lastModified } = fileData
    const timestamp = moment.utc(new Date(lastModified))
    const comments = JSON.parse(fileData.Body.toString())
    await store.dispatch({
      type: 'FETCH_OLD_COMMENTS',
      dirName,
      comments,
      timestamp
    })
  } catch (error) {
    // For some reason, when there is no file in S3, we get an 'NoSuchKey'
    // error when running from the developer account, but an 'AccessDenied'
    // when running on Lambda
    if (error.code === 'NoSuchKey' || error.code === 'AccessDenied') {
      // It's okay if the file doesn't exist. That is normal
      // for the first post
      if (!quiet) {
        console.log('No old comments found')
      }
      const timestamp = moment.utc()
      const comments = []
      await store.dispatch({
        type: 'FETCH_OLD_COMMENTS',
        dirName,
        comments,
        timestamp
      })
      return
    }
    throw error
  }
}

async function postMessageToSlack({ action, quiet }) {
  const {
    type,
    payload: {
      permalink,
      authorName,
      authorEmail,
      authorUrl,
      commentContent
    }
  } = action
  if (type !== 'NEW_COMMENT') {
    return
  }
  await postToSlack({
    message: {
      text: `Comment posted <${permalink}>`,
      attachments: [
        {
          color: "good",
          fields: [
            {
              title: "Author Name",
              value: authorName,
              short: true,
            },
            {
              title: "Author Email",
              value: authorEmail,
              short: true,
            },
            {
              title: "Author Url",
              value: authorUrl,
              short: true,
            },
            {
              title: "Comment",
              value: commentContent,
              short: false,
            },
            /*
            {
              title: "JSON",
              value: JSON.stringify(action, null, 2),
              short: false,
            },
            */
          ]
        },
      ]
    },
    quiet
  })
}

async function downloadActionAndDispatch({ dirName, actionRef, quiet }) {
  await fetchOldComments({ dirName, quiet })
  const key = `${dirName}/.actions/${actionRef}/action.json`
  const fileData = await download({ key })
  const action = JSON.parse(fileData.Body.toString())
  await store.dispatch({ ...action, dirName })
  await postMessageToSlack({ action, quiet })
}

async function saveAllComments ({ quiet }) {
  const allComments = store.getState()
  for (const key in allComments) {
    if (!quiet) {
      console.log('Saving', key)
    }
    await upload({
      key: `${key}/comments.json`,
      data: JSON.stringify(allComments[key].comments, null, 2),
      contentType: 'application/json'
    })
  }
}

export async function handler (event, context, callback) {
  if (!callback) {
    const errorMessage = 'Requires Node 4.3 or greater on Lambda'
    console.log(errorMessage)
    context.error(context.fail(errorMessage))
    return
  }
  try {
    // console.log('Event', JSON.stringify(event, null, 2))
    const {
      Records: [
        {
          dynamodb: {
            NewImage: {
              actionRef: {
                S: actionRef
              },
              dirName: {
                S: dirName
              }
            }
          }
        }
      ],
      quiet,
      dryRun
    } = event
    if (!quiet) {
      console.log('Invocation count:', ++invocationCounter)
      // console.log(JSON.stringify(event, null, 2))
      console.log('dirName:', dirName)
      console.log('actionRef:', actionRef)
    }
    if (!dryRun) {
      await downloadActionAndDispatch({ dirName, actionRef, quiet })
    }
    await saveAllComments({ quiet })
    callback( null, { success: true } )
  } catch (error) {
    // console.log('Worker error', error)
    // console.log(error.stack)
    callback(error)
  }
}
<commit_msg>Move comment content into a separate slack attachment<commit_after>import { parse as urlParse } from 'url'
import { normalize as pathNormalize, join as pathJoin } from 'path'
import fetch from 'node-fetch'
import { createStore, applyMiddleware } from 'redux'
import createLogger from 'redux-logger'
import moment from 'moment'
import { postToSlack } from '../../lib/slack'
import { download, upload } from '../../lib/s3'

let invocationCounter = 0

const initialState = {}

const logger = createLogger({
  colors: {
    title: false,
    prevState: false,
    action: false,
    nextState: false,
    error: false
  }
})

function reducer (state = initialState, action) {
  switch (action.type) {
    case 'FETCH_OLD_COMMENTS':
      {
        const { dirName, comments, timestamp } = action
        return {
          ...state,
          [dirName]: {
            timestamp,
            comments,
          }
        }
      }
    case 'NEW_COMMENT':
      {
        const {
          dirName,
          submittedDate: date,
          payload: {
            id,
            commentContent,
            authorName,
            authorUrl
          }
        } = action
        const comments = state[dirName] ? [...state[dirName].comments] : []
        const timestamp = moment.utc()
        comments.push({
          id,
          date,
          authorName,
          authorUrl,
          commentContent
        })
        return {
          ...state,
          [dirName]: {
            timestamp,
            comments,
          }
        }
      }
    default:
      return state
  }
}

// const store = createStore(reducer, applyMiddleware(logger))
const store = createStore(reducer)

async function fetchOldComments({ dirName, quiet }) {
  const state = store.getState()
  if (state[dirName] &&
      moment().subtract(20, 'seconds').isBefore(state[dirName].timestamp)) {
    // Use cache if it's under 20 seconds old
    if (!quiet) {
      console.log('Using cached old comments')
    }
    return
  }
  const key = `${dirName}/comments.json`
  try {
    if (!quiet) {
      console.log('Loading old comments from S3')
    }
    const fileData = await download({ key })
    const { LastModified: lastModified } = fileData
    const timestamp = moment.utc(new Date(lastModified))
    const comments = JSON.parse(fileData.Body.toString())
    await store.dispatch({
      type: 'FETCH_OLD_COMMENTS',
      dirName,
      comments,
      timestamp
    })
  } catch (error) {
    // For some reason, when there is no file in S3, we get an 'NoSuchKey'
    // error when running from the developer account, but an 'AccessDenied'
    // when running on Lambda
    if (error.code === 'NoSuchKey' || error.code === 'AccessDenied') {
      // It's okay if the file doesn't exist. That is normal
      // for the first post
      if (!quiet) {
        console.log('No old comments found')
      }
      const timestamp = moment.utc()
      const comments = []
      await store.dispatch({
        type: 'FETCH_OLD_COMMENTS',
        dirName,
        comments,
        timestamp
      })
      return
    }
    throw error
  }
}

async function postMessageToSlack({ action, quiet }) {
  const {
    type,
    payload: {
      permalink,
      authorName,
      authorEmail,
      authorUrl,
      commentContent
    }
  } = action
  if (type !== 'NEW_COMMENT') {
    return
  }
  await postToSlack({
    message: {
      text: `Comment posted <${permalink}>`,
      attachments: [
        {
          fields: [
            {
              title: "Author Name",
              value: authorName,
              short: true,
            },
            {
              title: "Author Email",
              value: authorEmail,
              short: true,
            },
            {
              title: "Author Url",
              value: authorUrl,
              short: true,
            },
          ]
        },
        {
          title: "Comment",
          text: commentContent
        }
        /*
        {
          title: "JSON",
          value: JSON.stringify(action, null, 2),
          short: false,
        },
        */
      ]
    },
    quiet
  })
}

async function downloadActionAndDispatch({ dirName, actionRef, quiet }) {
  await fetchOldComments({ dirName, quiet })
  const key = `${dirName}/.actions/${actionRef}/action.json`
  const fileData = await download({ key })
  const action = JSON.parse(fileData.Body.toString())
  await store.dispatch({ ...action, dirName })
  await postMessageToSlack({ action, quiet })
}

async function saveAllComments ({ quiet }) {
  const allComments = store.getState()
  for (const key in allComments) {
    if (!quiet) {
      console.log('Saving', key)
    }
    await upload({
      key: `${key}/comments.json`,
      data: JSON.stringify(allComments[key].comments, null, 2),
      contentType: 'application/json'
    })
  }
}

export async function handler (event, context, callback) {
  if (!callback) {
    const errorMessage = 'Requires Node 4.3 or greater on Lambda'
    console.log(errorMessage)
    context.error(context.fail(errorMessage))
    return
  }
  try {
    // console.log('Event', JSON.stringify(event, null, 2))
    const {
      Records: [
        {
          dynamodb: {
            NewImage: {
              actionRef: {
                S: actionRef
              },
              dirName: {
                S: dirName
              }
            }
          }
        }
      ],
      quiet,
      dryRun
    } = event
    if (!quiet) {
      console.log('Invocation count:', ++invocationCounter)
      // console.log(JSON.stringify(event, null, 2))
      console.log('dirName:', dirName)
      console.log('actionRef:', actionRef)
    }
    if (!dryRun) {
      await downloadActionAndDispatch({ dirName, actionRef, quiet })
    }
    await saveAllComments({ quiet })
    callback( null, { success: true } )
  } catch (error) {
    // console.log('Worker error', error)
    // console.log(error.stack)
    callback(error)
  }
}
<|endoftext|>


<commit_before>/* eslint-disable prefer-arrow-callback */
import Promise from 'bluebird'
import generateProjectName from 'src/server/actions/generateProjectName'
import sendCycleLaunchAnnouncements from 'src/server/actions/sendCycleLaunchAnnouncements'
import {formProjectsIfNoneExist} from 'src/server/actions/formProjects'
import {getGoalInfo} from 'src/server/services/goalLibraryService'
import {Phase, Member, Project} from 'src/server/services/dataService'

export function start() {
  const jobService = require('src/server/services/jobService')
  jobService.processJobs('cycleLaunched', processCycleLaunched)
}

export async function processCycleLaunched(cycle) {
  console.log(`Forming teams for cycle ${cycle.cycleNumber} of chapter ${cycle.chapterId}`)

  const nonVotingProjects = await _createProjectsInCycleForNonVotingPhases(cycle)
  console.log(`${nonVotingProjects.length} project(s) created for non-voting phases`)

  const votingProjects = await formProjectsIfNoneExist(cycle.id, null)
  console.log(`${votingProjects.length} project(s) created for voting phases`)

  try {
    await sendCycleLaunchAnnouncements(cycle.id)
  } catch (err) {
    console.warn(`Failed to send cycle launch announcement for cycle ${cycle.cycleNumber}: ${err}`)
  }
}

async function _createProjectsInCycleForNonVotingPhases(cycle) {
  console.log('Automatically creating projects for non-voting phases')

  const nonVotingPhases = await Phase.filter({hasVoting: false}).hasFields('practiceGoalNumber')
  if (nonVotingPhases.length === 0) {
    console.log('No non-voting phases found; skipped')
    return []
  }

  let newPhaseProjects = []
  await Promise.each(nonVotingPhases, async phase => {
    const existingProjects = await Project.filter({cycleId: cycle.id, phaseId: phase.id})
    if (existingProjects.length > 0) {
      console.log(`Existing projects found for non-voting phase ${phase.number}; skipped`)
      return
    }

    const members = await Member.filter({phaseId: phase.id})
    if (members.length === 0) {
      console.log(`No members found in Phase ${phase.number}; skipped`)
      return
    }

    const goal = await getGoalInfo(phase.practiceGoalNumber)

    const projects = await Promise.map(members, async member => ({
      name: await generateProjectName(),
      chapterId: cycle.chapterId,
      cycleId: cycle.id,
      phaseId: phase.id,
      memberIds: [member.id],
      goal,
    }), {concurrency: 5})

    const savedProjects = await Project.save(projects)

    console.log(`${savedProjects.length} project(s) automatically created for Phase ${phase.number}`)

    newPhaseProjects = newPhaseProjects.concat(savedProjects)
  })

  return newPhaseProjects
}
<commit_msg>Removes unnecessary null parameter<commit_after>/* eslint-disable prefer-arrow-callback */
import Promise from 'bluebird'
import generateProjectName from 'src/server/actions/generateProjectName'
import sendCycleLaunchAnnouncements from 'src/server/actions/sendCycleLaunchAnnouncements'
import {formProjectsIfNoneExist} from 'src/server/actions/formProjects'
import {getGoalInfo} from 'src/server/services/goalLibraryService'
import {Phase, Member, Project} from 'src/server/services/dataService'

export function start() {
  const jobService = require('src/server/services/jobService')
  jobService.processJobs('cycleLaunched', processCycleLaunched)
}

export async function processCycleLaunched(cycle) {
  console.log(`Forming teams for cycle ${cycle.cycleNumber} of chapter ${cycle.chapterId}`)

  const nonVotingProjects = await _createProjectsInCycleForNonVotingPhases(cycle)
  console.log(`${nonVotingProjects.length} project(s) created for non-voting phases`)

  const votingProjects = await formProjectsIfNoneExist(cycle.id)
  console.log(`${votingProjects.length} project(s) created for voting phases`)

  try {
    await sendCycleLaunchAnnouncements(cycle.id)
  } catch (err) {
    console.warn(`Failed to send cycle launch announcement for cycle ${cycle.cycleNumber}: ${err}`)
  }
}

async function _createProjectsInCycleForNonVotingPhases(cycle) {
  console.log('Automatically creating projects for non-voting phases')

  const nonVotingPhases = await Phase.filter({hasVoting: false}).hasFields('practiceGoalNumber')
  if (nonVotingPhases.length === 0) {
    console.log('No non-voting phases found; skipped')
    return []
  }

  let newPhaseProjects = []
  await Promise.each(nonVotingPhases, async phase => {
    const existingProjects = await Project.filter({cycleId: cycle.id, phaseId: phase.id})
    if (existingProjects.length > 0) {
      console.log(`Existing projects found for non-voting phase ${phase.number}; skipped`)
      return
    }

    const members = await Member.filter({phaseId: phase.id})
    if (members.length === 0) {
      console.log(`No members found in Phase ${phase.number}; skipped`)
      return
    }

    const goal = await getGoalInfo(phase.practiceGoalNumber)

    const projects = await Promise.map(members, async member => ({
      name: await generateProjectName(),
      chapterId: cycle.chapterId,
      cycleId: cycle.id,
      phaseId: phase.id,
      memberIds: [member.id],
      goal,
    }), {concurrency: 5})

    const savedProjects = await Project.save(projects)

    console.log(`${savedProjects.length} project(s) automatically created for Phase ${phase.number}`)

    newPhaseProjects = newPhaseProjects.concat(savedProjects)
  })

  return newPhaseProjects
}
<|endoftext|>


<commit_before>/* @flow */

import React, { Component } from 'react';

import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { connect } from '../../../base/redux';
import { E2EELabel } from '../../../e2ee';
import { LocalRecordingLabel } from '../../../local-recording';
import { RecordingLabel } from '../../../recording';
import { isToolboxVisible } from '../../../toolbox/functions.web';
import { TranscribingLabel } from '../../../transcribing';
import { VideoQualityLabel } from '../../../video-quality';
import ConferenceTimer from '../ConferenceTimer';
import { getConferenceInfo } from '../functions';

import ConferenceInfoContainer from './ConferenceInfoContainer';
import InsecureRoomNameLabel from './InsecureRoomNameLabel';
import ParticipantsCount from './ParticipantsCount';
import SubjectText from './SubjectText';

/**
 * The type of the React {@code Component} props of {@link Subject}.
 */
type Props = {

    /**
     * The conference info labels to be shown in the conference header.
     */
    _conferenceInfo: Object,

    /**
     * Indicates whether the component should be visible or not.
     */
    _visible: boolean
};

const COMPONENTS = [
    {
        Component: SubjectText,
        id: 'subject'
    },
    {
        Component: ConferenceTimer,
        id: 'conference-timer'
    },
    {
        Component: ParticipantsCount,
        id: 'participants-count'
    },
    {
        Component: E2EELabel,
        id: 'e2ee'
    },
    {
        Component: () => (
            <>
                <RecordingLabel mode = { JitsiRecordingConstants.mode.FILE } />
                <RecordingLabel mode = { JitsiRecordingConstants.mode.STREAM } />
            </>
        ),
        id: 'recording'
    },
    {
        Component: LocalRecordingLabel,
        id: 'local-recording'
    },
    {
        Component: TranscribingLabel,
        id: 'transcribing'
    },
    {
        Component: VideoQualityLabel,
        id: 'video-quality'
    },
    {
        Component: InsecureRoomNameLabel,
        id: 'insecure-room'
    }
];

/**
 * The upper band of the meeing containing the conference name, timer and labels.
 *
 * @param {Object} props - The props of the component.
 * @returns {React$None}
 */
class ConferenceInfo extends Component<Props> {
    /**
     * Initializes a new {@code ConferenceInfo} instance.
     *
     * @param {Props} props - The read-only React {@code Component} props with
     * which the new instance is to be initialized.
     */
    constructor(props: Props) {
        super(props);

        this._renderAutoHide = this._renderAutoHide.bind(this);
        this._renderAlwaysVisible = this._renderAlwaysVisible.bind(this);
    }

    _renderAutoHide: () => void;

    /**
     * Renders auto-hidden info header labels.
     *
     * @returns {void}
     */
    _renderAutoHide() {
        const { autoHide } = this.props._conferenceInfo;

        if (!autoHide || !autoHide.length) {
            return null;
        }

        return (
            <ConferenceInfoContainer visible = { this.props._visible } >
                {
                    COMPONENTS
                        .filter(comp => autoHide.includes(comp.id))
                        .map(c =>
                            <c.Component key = { c.id } />
                        )
                }
            </ConferenceInfoContainer>
        );
    }

    _renderAlwaysVisible: () => void;

    /**
     * Renders the always visible info header labels.
     *
     * @returns {void}
     */
    _renderAlwaysVisible() {
        const { alwaysVisible } = this.props._conferenceInfo;

        if (!alwaysVisible || !alwaysVisible.length) {
            return null;
        }

        return (
            <ConferenceInfoContainer visible = { true } >
                {
                    COMPONENTS
                        .filter(comp => alwaysVisible.includes(comp.id))
                        .map(c =>
                            <c.Component key = { c.id } />
                        )
                }
            </ConferenceInfoContainer>
        );
    }

    /**
     * Implements React's {@link Component#render()}.
     *
     * @inheritdoc
     * @returns {ReactElement}
     */
    render() {
        return (

                { [
                    this._renderAlwaysVisible(),
                    this._renderAutoHide()
                ] }

        );
    }
}

/**
 * Maps (parts of) the Redux state to the associated
 * {@code Subject}'s props.
 *
 * @param {Object} state - The Redux state.
 * @private
 * @returns {{
 *     _visible: boolean,
 *     _conferenceInfo: Object
 * }}
 */
function _mapStateToProps(state) {
    return {
        _visible: isToolboxVisible(state),
        _conferenceInfo: getConferenceInfo(state)
    };
}

export default connect(_mapStateToProps)(ConferenceInfo);
<commit_msg>fix(chore): Don't show react "unique key" warning<commit_after>/* @flow */

import React, { Component } from 'react';

import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { connect } from '../../../base/redux';
import { E2EELabel } from '../../../e2ee';
import { LocalRecordingLabel } from '../../../local-recording';
import { RecordingLabel } from '../../../recording';
import { isToolboxVisible } from '../../../toolbox/functions.web';
import { TranscribingLabel } from '../../../transcribing';
import { VideoQualityLabel } from '../../../video-quality';
import ConferenceTimer from '../ConferenceTimer';
import { getConferenceInfo } from '../functions';

import ConferenceInfoContainer from './ConferenceInfoContainer';
import InsecureRoomNameLabel from './InsecureRoomNameLabel';
import ParticipantsCount from './ParticipantsCount';
import SubjectText from './SubjectText';

/**
 * The type of the React {@code Component} props of {@link Subject}.
 */
type Props = {

    /**
     * The conference info labels to be shown in the conference header.
     */
    _conferenceInfo: Object,

    /**
     * Indicates whether the component should be visible or not.
     */
    _visible: boolean
};

const COMPONENTS = [
    {
        Component: SubjectText,
        id: 'subject'
    },
    {
        Component: ConferenceTimer,
        id: 'conference-timer'
    },
    {
        Component: ParticipantsCount,
        id: 'participants-count'
    },
    {
        Component: E2EELabel,
        id: 'e2ee'
    },
    {
        Component: () => (
            <>
                <RecordingLabel mode = { JitsiRecordingConstants.mode.FILE } />
                <RecordingLabel mode = { JitsiRecordingConstants.mode.STREAM } />
            </>
        ),
        id: 'recording'
    },
    {
        Component: LocalRecordingLabel,
        id: 'local-recording'
    },
    {
        Component: TranscribingLabel,
        id: 'transcribing'
    },
    {
        Component: VideoQualityLabel,
        id: 'video-quality'
    },
    {
        Component: InsecureRoomNameLabel,
        id: 'insecure-room'
    }
];

/**
 * The upper band of the meeing containing the conference name, timer and labels.
 *
 * @param {Object} props - The props of the component.
 * @returns {React$None}
 */
class ConferenceInfo extends Component<Props> {
    /**
     * Initializes a new {@code ConferenceInfo} instance.
     *
     * @param {Props} props - The read-only React {@code Component} props with
     * which the new instance is to be initialized.
     */
    constructor(props: Props) {
        super(props);

        this._renderAutoHide = this._renderAutoHide.bind(this);
        this._renderAlwaysVisible = this._renderAlwaysVisible.bind(this);
    }

    _renderAutoHide: () => void;

    /**
     * Renders auto-hidden info header labels.
     *
     * @returns {void}
     */
    _renderAutoHide() {
        const { autoHide } = this.props._conferenceInfo;

        if (!autoHide || !autoHide.length) {
            return null;
        }

        return (
            <ConferenceInfoContainer visible = { this.props._visible } >
                {
                    COMPONENTS
                        .filter(comp => autoHide.includes(comp.id))
                        .map(c =>
                            <c.Component key = { c.id } />
                        )
                }
            </ConferenceInfoContainer>
        );
    }

    _renderAlwaysVisible: () => void;

    /**
     * Renders the always visible info header labels.
     *
     * @returns {void}
     */
    _renderAlwaysVisible() {
        const { alwaysVisible } = this.props._conferenceInfo;

        if (!alwaysVisible || !alwaysVisible.length) {
            return null;
        }

        return (
            <ConferenceInfoContainer visible = { true } >
                {
                    COMPONENTS
                        .filter(comp => alwaysVisible.includes(comp.id))
                        .map(c =>
                            <c.Component key = { c.id } />
                        )
                }
            </ConferenceInfoContainer>
        );
    }

    /**
     * Implements React's {@link Component#render()}.
     *
     * @inheritdoc
     * @returns {ReactElement}
     */
    render() {
        return (

                { this._renderAlwaysVisible() }
                { this._renderAutoHide() }

        );
    }
}

/**
 * Maps (parts of) the Redux state to the associated
 * {@code Subject}'s props.
 *
 * @param {Object} state - The Redux state.
 * @private
 * @returns {{
 *     _visible: boolean,
 *     _conferenceInfo: Object
 * }}
 */
function _mapStateToProps(state) {
    return {
        _visible: isToolboxVisible(state),
        _conferenceInfo: getConferenceInfo(state)
    };
}

export default connect(_mapStateToProps)(ConferenceInfo);
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import styles from './adBanner.css';

const AdBanner = ({
  link,
  imageSource,
  altText,
  adBannerText,
  clickText
}) =>
  (

 {adBannerText}

 {clickText}

  );

AdBanner.propTypes = {
  link: PropTypes.string.isRequired,
  imageSource: PropTypes.string.isRequired,
  altText: PropTypes.string.isRequired,
  adBannerText: PropTypes.string.isRequired,
  clickText: PropTypes.string.isRequired
};

export default AdBanner;
<commit_msg>Connect GA to ad banner<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import OutboundLink from 'shared/components/outboundLink/outboundLink';
import styles from './adBanner.css';

const AdBanner = ({ link, imageSource, altText, adBannerText, clickText }) => {
  if (process.env.NODE_ENV === 'production') {
    return (
      <OutboundLink
        href={link}
        analyticsEventLabel={`[AdBanner Hit] to ${link} from /`}
        className={styles.adBannerLink}
      >

            {' '}
            {adBannerText}

 {clickText}

      </OutboundLink>
    );
  }

  const onDevAdBannerClick = () => {
    console.log(`OUTBOUND ${analyticsEventLabel} analytics event clicked`); // eslint-disable-line
  };

  return (

          {' '}
          {adBannerText}

 {clickText}

  );
};

AdBanner.propTypes = {
  link: PropTypes.string.isRequired,
  imageSource: PropTypes.string.isRequired,
  altText: PropTypes.string.isRequired,
  adBannerText: PropTypes.string.isRequired,
  clickText: PropTypes.string.isRequired,
};

export default AdBanner;
<|endoftext|>


<commit_before>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactPropTypeLocations
 */

'use strict';

var keyMirror = require('keyMirror');

var ReactPropTypeLocations = keyMirror({
  prop: null,
  context: null,
  childContext: null,
});

module.exports = ReactPropTypeLocations;
<commit_msg>Type ReactPropTypeLocations (#7502)<commit_after>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 * @providesModule ReactPropTypeLocations
 */

'use strict';

var keyMirror = require('keyMirror');

var ReactPropTypeLocations = keyMirror({
  prop: null,
  context: null,
  childContext: null,
});

module.exports = ReactPropTypeLocations;
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var vinylPaths = require('vinyl-paths');
var globby = require('globby');
var mergeStream = require('merge-stream');
var path = require('path');
var runSequence = require('run-sequence');
var browserify = require('browserify');
var watchify = require('watchify');
var autoprefixer = require('autoprefixer');
var cssnano = require('cssnano');
var bs = require('browser-sync').create();
var del = require('del');

var browsers = [
  'last 2 versions',
  'Explorer >= 8',
  'Firefox ESR',
  'Android >= 4',
  'iOS >= 7'
];
var entries = [];

// Lint JavaScript
gulp.task('lint', function () {
  return gulp.src('app/scripts/**/*.js')
    .pipe($.eslint())
    .pipe($.eslint.format())
    .pipe($.eslint.failAfterError());
});

// Build stylesheets for local development
gulp.task('styles:dev', ['sprites', 'fonts'], function () {
  return gulp.src('app/styles/**/*.scss')
    .pipe($.sourcemaps.init({loadMaps: true}))
    .pipe($.sass({
      outputStyle: 'expanded',
      includePaths: ['.tmp/styles']
    })
    .on('error', $.sass.logError))
    .pipe($.postcss([
      autoprefixer({browsers: browsers})
    ]))
    .pipe($.sourcemaps.write('.'))
    .pipe(gulp.dest('.tmp/styles'));
});

// Build stylesheets for production
gulp.task('styles', ['sprites', 'fonts'], function () {
  return gulp.src('app/styles/**/*.scss')
    .pipe($.sass({
      outputStyle: 'expanded',
      includePaths: ['.tmp/styles']
    })
    .on('error', $.sass.logError))
    .pipe($.postcss([
      autoprefixer({browsers: browsers}),
      cssnano({
        safe: true,
        autoprefixer: false
      })
    ]))
    .pipe(gulp.dest('dist/styles'));
});

// Generate CSS sprites from PNG files
gulp.task('sprites', function () {
  return gulp.src('app/images/_sprites/*.png')
    .pipe($.newer('.tmp/images/sprites.png'))
    .pipe($.spritesmith({
      imgName: 'images/sprites.png',
      cssName: 'styles/sprites.css',
      padding: 2,
      cssOpts: {
        cssSelector: function (item) {
          return '.sprite-' + item.name;
        }
      }
    }))
    .pipe(gulp.dest('.tmp'));
});

// Generate icon fonts from SVG files
gulp.task('fonts', function () {
  return gulp.src('app/fonts/_glyphs/*.svg')
    .pipe($.newer('.tmp/styles/glyphs.css'))
    .pipe($.iconfontCss({
      fontName: 'glyphs',
      targetPath: '../styles/glyphs.css',   // Relative path from gulp.dest()
      fontPath: '../fonts/',                // Base url(...) in CSS code
      cssClass: 'glyph'
    }))
    .pipe($.iconfont({
      fontName: 'glyphs',
      prependUnicode: true,
      formats: ['eot', 'woff2', 'woff', 'ttf', 'svg']
    }))
    .pipe(gulp.dest('.tmp/fonts'));
});

// Build and watch scripts for local development
gulp.task('scripts:dev', function () {
  var stream = mergeStream();
  globby.sync('app/scripts/*.js').forEach(function (file) {
    if (entries.indexOf(file) !== -1) {
      return;
    }
    var bundler = browserify({
      entries: file,
      cache: {},
      packageCache: {},
      plugin: [watchify],
      debug: true
    });
    bundler
      .on('log', $.util.log)
      .on('update', bundle);
    stream.add(bundle());
    entries.push(file);
    function bundle() {
      return bundler.bundle()
        .on('error', function (error) {
          $.util.log($.util.colors.red('Browserify error:') + '\n' + error.message);
          this.emit('end');
        })
        .pipe(source(path.relative('app/scripts', file)))
        .pipe(gulp.dest('.tmp/scripts'));
    }
  });
  return stream.isEmpty() ? null : stream;
});

// Build scripts for production
gulp.task('scripts', function () {
  var stream = mergeStream();
  globby.sync('app/scripts/*.js').forEach(function (file) {
    var bundleStream = browserify(file).bundle()
      .on('error', function (error) {
        $.util.log($.util.colors.red('Browserify error:') + '\n' + error.message);
        this.emit('end');
      })
      .pipe(source(path.relative('app/scripts', file)))
      .pipe(buffer())
      .pipe($.uglify())
      .pipe(gulp.dest('dist/scripts'));
    stream.add(bundleStream);
  });
  return stream.isEmpty() ? null : stream;
});

// Minify HTML
gulp.task('html', function () {
  return gulp.src('app/**/*.html')
    .pipe($.htmlmin({
      collapseBooleanAttributes: true,
      collapseWhitespace: true,
      conservativeCollapse: true,
      minifyCSS: true,
      minifyJS: true,
      preventAttributesEscaping: true,
      removeAttributeQuotes: true,
      removeComments: true,
      removeCommentsFromCDATA: true,
      removeEmptyAttributes: true,
      removeOptionalTags: true,
      removeRedundantAttributes: true,
      removeScriptTypeAttributes: true,
      removeStyleLinkTypeAttributes: true,
      removeTagWhitespace: true,
      useShortDoctype: true
    }))
    .pipe(gulp.dest('dist'));
});

// Optimize images
gulp.task('images', ['sprites'], function () {
  return gulp.src([
    'app/images/**',
    '!app/images/_*/**'
  ])
    .pipe($.ignore.include({isFile: true}))
    .pipe($.imagemin({
      progressive: true,
      interlaced: true,
      svgoPlugins: [{cleanupIDs: false}]
    }))
    .pipe(gulp.dest('dist/images'));
});

// Copy all extra files like favicon, .htaccess
gulp.task('extras', ['sprites', 'fonts'], function () {
  return gulp.src([
    'app/**',
    '.tmp/{images,fonts}/*',
    '!app/{styles,scripts,images}/**',
    '!app/fonts/_*/**',
    '!**/{*.html,.DS_Store}'
  ], {dot: true})
    .pipe($.ignore.include({isFile: true}))
    .pipe(gulp.dest('dist'));
});

// Static asset revisioning: "main.css" -> "main-e90e18eef7.css"
gulp.task('filerev', function () {
  return gulp.src('dist/**/*.{css,js,png,jpg,gif,eot,svg,ttf,woff,woff2}')
    .pipe(vinylPaths(del))
    .pipe($.rev())
    .pipe(gulp.dest('dist'))
    .pipe($.rev.manifest())
    .pipe(gulp.dest('.tmp'));
});

gulp.task('rev', ['filerev'], function () {
  var manifest = gulp.src('.tmp/rev-manifest.json');
  return gulp.src('dist/**/*.{html,css}')
    .pipe($.revReplace({manifest: manifest}))
    .pipe(gulp.dest('dist'));
});

// Clean output directories
gulp.task('clean:tmp', del.bind(null, '.tmp'));
gulp.task('clean:dist', del.bind(null, 'dist'));

// Start browsersync development server
gulp.task('serve', ['pre:serve'], function () {
  bs.init({
    notify: false,
    server: {
      baseDir: ['.tmp', 'app']
    },
    files: ['app/**/*.html', '.tmp/**']
  });
  gulp.watch('app/scripts/*.js', function (event) {
    if (event.type === 'added' || event.type === 'renamed') {
      runSequence('scripts:dev');
    }
  });
  gulp.watch('app/scripts/**/*.js', ['lint']);
  gulp.watch('app/styles/**/*.scss', ['styles:dev']);
  gulp.watch('app/images/_sprites/*.png', ['styles:dev']);
  gulp.watch('app/fonts/_glyphs/*.svg', ['styles:dev']);
});

gulp.task('pre:serve', function (callback) {
  runSequence('clean:tmp', ['styles:dev', 'scripts:dev'], callback);
});

// Start local server from the "dist" directory
gulp.task('serve:dist', function () {
  bs.init({
    notify: false,
    server: 'dist'
  });
});

// Build production files
gulp.task('build', function (callback) {
  runSequence('clean:dist', ['html', 'styles', 'scripts', 'images', 'extras'], 'rev', callback);
});

// Push production files to "gh-pages" branch
gulp.task('deploy', ['default'], function () {
  return gulp.src('dist/**/*')
    .pipe($.ghPages());
});

// Default task: lint and build files
gulp.task('default', function (callback) {
  runSequence('lint', 'build', callback);
});
<commit_msg>Minify sprites image<commit_after>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var vinylPaths = require('vinyl-paths');
var globby = require('globby');
var mergeStream = require('merge-stream');
var path = require('path');
var runSequence = require('run-sequence');
var browserify = require('browserify');
var watchify = require('watchify');
var autoprefixer = require('autoprefixer');
var cssnano = require('cssnano');
var bs = require('browser-sync').create();
var del = require('del');

var browsers = [
  'last 2 versions',
  'Explorer >= 8',
  'Firefox ESR',
  'Android >= 4',
  'iOS >= 7'
];
var entries = [];

// Lint JavaScript
gulp.task('lint', function () {
  return gulp.src('app/scripts/**/*.js')
    .pipe($.eslint())
    .pipe($.eslint.format())
    .pipe($.eslint.failAfterError());
});

// Build stylesheets for local development
gulp.task('styles:dev', ['sprites', 'fonts'], function () {
  return gulp.src('app/styles/**/*.scss')
    .pipe($.sourcemaps.init({loadMaps: true}))
    .pipe($.sass({
      outputStyle: 'expanded',
      includePaths: ['.tmp/styles']
    })
    .on('error', $.sass.logError))
    .pipe($.postcss([
      autoprefixer({browsers: browsers})
    ]))
    .pipe($.sourcemaps.write('.'))
    .pipe(gulp.dest('.tmp/styles'));
});

// Build stylesheets for production
gulp.task('styles', ['sprites', 'fonts'], function () {
  return gulp.src('app/styles/**/*.scss')
    .pipe($.sass({
      outputStyle: 'expanded',
      includePaths: ['.tmp/styles']
    })
    .on('error', $.sass.logError))
    .pipe($.postcss([
      autoprefixer({browsers: browsers}),
      cssnano({
        safe: true,
        autoprefixer: false
      })
    ]))
    .pipe(gulp.dest('dist/styles'));
});

// Generate CSS sprites from PNG files
gulp.task('sprites', function () {
  return gulp.src('app/images/_sprites/*.png')
    .pipe($.newer('.tmp/images/sprites.png'))
    .pipe($.spritesmith({
      imgName: 'images/sprites.png',
      cssName: 'styles/sprites.css',
      padding: 2,
      cssOpts: {
        cssSelector: function (item) {
          return '.sprite-' + item.name;
        }
      }
    }))
    .pipe(gulp.dest('.tmp'));
});

// Generate icon fonts from SVG files
gulp.task('fonts', function () {
  return gulp.src('app/fonts/_glyphs/*.svg')
    .pipe($.newer('.tmp/styles/glyphs.css'))
    .pipe($.iconfontCss({
      fontName: 'glyphs',
      targetPath: '../styles/glyphs.css',   // Relative path from gulp.dest()
      fontPath: '../fonts/',                // Base url(...) in CSS code
      cssClass: 'glyph'
    }))
    .pipe($.iconfont({
      fontName: 'glyphs',
      prependUnicode: true,
      formats: ['eot', 'woff2', 'woff', 'ttf', 'svg']
    }))
    .pipe(gulp.dest('.tmp/fonts'));
});

// Build and watch scripts for local development
gulp.task('scripts:dev', function () {
  var stream = mergeStream();
  globby.sync('app/scripts/*.js').forEach(function (file) {
    if (entries.indexOf(file) !== -1) {
      return;
    }
    var bundler = browserify({
      entries: file,
      cache: {},
      packageCache: {},
      plugin: [watchify],
      debug: true
    });
    bundler
      .on('log', $.util.log)
      .on('update', bundle);
    stream.add(bundle());
    entries.push(file);
    function bundle() {
      return bundler.bundle()
        .on('error', function (error) {
          $.util.log($.util.colors.red('Browserify error:') + '\n' + error.message);
          this.emit('end');
        })
        .pipe(source(path.relative('app/scripts', file)))
        .pipe(gulp.dest('.tmp/scripts'));
    }
  });
  return stream.isEmpty() ? null : stream;
});

// Build scripts for production
gulp.task('scripts', function () {
  var stream = mergeStream();
  globby.sync('app/scripts/*.js').forEach(function (file) {
    var bundleStream = browserify(file).bundle()
      .on('error', function (error) {
        $.util.log($.util.colors.red('Browserify error:') + '\n' + error.message);
        this.emit('end');
      })
      .pipe(source(path.relative('app/scripts', file)))
      .pipe(buffer())
      .pipe($.uglify())
      .pipe(gulp.dest('dist/scripts'));
    stream.add(bundleStream);
  });
  return stream.isEmpty() ? null : stream;
});

// Minify HTML
gulp.task('html', function () {
  return gulp.src('app/**/*.html')
    .pipe($.htmlmin({
      collapseBooleanAttributes: true,
      collapseWhitespace: true,
      conservativeCollapse: true,
      minifyCSS: true,
      minifyJS: true,
      preventAttributesEscaping: true,
      removeAttributeQuotes: true,
      removeComments: true,
      removeCommentsFromCDATA: true,
      removeEmptyAttributes: true,
      removeOptionalTags: true,
      removeRedundantAttributes: true,
      removeScriptTypeAttributes: true,
      removeStyleLinkTypeAttributes: true,
      removeTagWhitespace: true,
      useShortDoctype: true
    }))
    .pipe(gulp.dest('dist'));
});

// Optimize images
gulp.task('images', ['sprites'], function () {
  return gulp.src([
    'app/images/**',
    '.tmp/images/**',
    '!app/images/_*/**'
  ])
    .pipe($.ignore.include({isFile: true}))
    .pipe($.imagemin({
      progressive: true,
      interlaced: true,
      svgoPlugins: [{cleanupIDs: false}]
    }))
    .pipe(gulp.dest('dist/images'));
});

// Copy all extra files like favicon, .htaccess
gulp.task('extras', ['fonts'], function () {
  return gulp.src([
    'app/**',
    '.tmp/fonts/**',
    '!app/{styles,scripts,images}/**',
    '!app/fonts/_*/**',
    '!**/{*.html,.DS_Store}'
  ], {dot: true})
    .pipe($.ignore.include({isFile: true}))
    .pipe(gulp.dest('dist'));
});

// Static asset revisioning: "main.css" -> "main-e90e18eef7.css"
gulp.task('filerev', function () {
  return gulp.src('dist/**/*.{css,js,png,jpg,gif,eot,svg,ttf,woff,woff2}')
    .pipe(vinylPaths(del))
    .pipe($.rev())
    .pipe(gulp.dest('dist'))
    .pipe($.rev.manifest())
    .pipe(gulp.dest('.tmp'));
});

gulp.task('rev', ['filerev'], function () {
  var manifest = gulp.src('.tmp/rev-manifest.json');
  return gulp.src('dist/**/*.{html,css}')
    .pipe($.revReplace({manifest: manifest}))
    .pipe(gulp.dest('dist'));
});

// Clean output directories
gulp.task('clean:tmp', del.bind(null, '.tmp'));
gulp.task('clean:dist', del.bind(null, 'dist'));

// Start browsersync development server
gulp.task('serve', ['pre:serve'], function () {
  bs.init({
    notify: false,
    server: {
      baseDir: ['.tmp', 'app']
    },
    files: ['app/**/*.html', '.tmp/**']
  });
  gulp.watch('app/scripts/*.js', function (event) {
    if (event.type === 'added' || event.type === 'renamed') {
      runSequence('scripts:dev');
    }
  });
  gulp.watch('app/scripts/**/*.js', ['lint']);
  gulp.watch('app/styles/**/*.scss', ['styles:dev']);
  gulp.watch('app/images/_sprites/*.png', ['styles:dev']);
  gulp.watch('app/fonts/_glyphs/*.svg', ['styles:dev']);
});

gulp.task('pre:serve', function (callback) {
  runSequence('clean:tmp', ['styles:dev', 'scripts:dev'], callback);
});

// Start local server from the "dist" directory
gulp.task('serve:dist', function () {
  bs.init({
    notify: false,
    server: 'dist'
  });
});

// Build production files
gulp.task('build', function (callback) {
  runSequence('clean:dist', ['html', 'styles', 'scripts', 'images', 'extras'], 'rev', callback);
});

// Push production files to "gh-pages" branch
gulp.task('deploy', ['default'], function () {
  return gulp.src('dist/**/*')
    .pipe($.ghPages());
});

// Default task: lint and build files
gulp.task('default', function (callback) {
  runSequence('lint', 'build', callback);
});
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { twitterFollowersApp } from '../reducers/combine_reducers';
import App from '../containers/App';

ReactDOM.render(
  <Provider store={ createStore( twitterFollowersApp ) }>
    <App />
  </Provider>,
  document.getElementById( 'app' )
);
<commit_msg>update index.js with routes from react-router<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import routes from '../config/routes';
import App from '../containers/App';

ReactDOM.render(
  routes,
  document.getElementById( 'app' )
);
<|endoftext|>


<commit_before>angular.module('routes', ['ui.router'])
  .controller('error-handler', require('./controllers/error-handler'))
  .controller('home', require('./controllers/home'))
  .controller('login', require('./controllers/login'))
  .controller('signup', require('./controllers/signup'))
  .controller('user', require('./controllers/user'))
  .controller('modules', require('./controllers/modules'))
  .controller('modules.create-edit', require('./controllers/modules/create-edit'))
  .controller('admin', require('./controllers/admin'))
  .controller('classes', require('./controllers/classes'))
  .controller('orgs', require('./controllers/orgs'))
  .controller('orgs.create-edit', require('./controllers/orgs/create-edit'))
  .controller('courses', require('./controllers/courses'))
  .controller('courses.create-edit', require('./controllers/courses/create-edit'))
  .config(function($stateProvider) {
    $stateProvider

      /**
       * Core Routes
       */
      .state('home', {
        url: '/',
        controller: 'home',
        template: require('./views/home'),

        // This is an example of a resolve
        // It is commented out, because it will cause the route to fail
        //
        // resolve: {
        //   things: function(CoolThings) {
        //     return CoolThings.getList()
        //   }
        // }
      })
      .state('login', {
        url: '/login',
        template: require('./views/login'),
        controller: 'login',
      })
      // Static about page
      .state('about', {
        url: '/about',
        template: require('./views/about'),
      })
      // New User signup form
      .state('signup', {
        url: '/signup',
        controller: 'signup',
        template: require('./views/signup'),
      })
      // Password Reset
      .state('reset', {
        url: '/reset',
        template: require('./views/reset'),
      })
      /**
       * User routes
       */
      .state('user', {
        url: '/user',
        template: require('./views/user'),
        controller: 'user',
      })
      .state('user.id', {
        url: '/user/:id',
        template: require('./views/user'),
        controller: 'user',
      })
      /**
       * Admin Routes
       */
      .state('admin', {
        url: '/admin',
        template: require('./views/admin'),
        controller: 'admin',
      })
      /**
       * Organization Routes
       */
      .state('orgs', {
        url: '/orgs',
        template: require('./views/orgs'),
        controller: 'orgs',
        resolve: {
           orgs: function(Orgs) {
             return Orgs.getList();
            }
          }
      })
      .state('orgs.create', {
        url: '/create',
        template: require('./views/orgs/create-edit'),
        controller: 'orgs.create-edit',
        resolve: {
          org: function () {
            return {}
          }

        }
      })
      .state('orgs.edit', {
        url: '/:id',
        template: require('./views/orgs/create-edit'),
        controller: 'orgs.create-edit',
        resolve: {
          org: function (orgs, $stateParams) {
            return _.find(orgs, {id: $stateParams.id})
          }
        }
      })
      /**
       * Module Routes
       */
      .state('modules', {
        url: '/modules',
        template: require('./views/modules'),
        controller: 'modules',
          resolve: {
              modules: function(Module) {
                  return Module.getList();
              }
          }
      })
      .state('modules.create', {
        url: '/create',
        template: require('./views/modules/create-edit'),
        controller: 'modules.create-edit',
        resolve: {
          module: function () {
            return {}
          }
        }
      })
      .state('modules.edit', {
        url: '/:id',
        template: require('./views/modules/create-edit'),
        controller: 'modules.create-edit',
        resolve: {
          module: function (modules, $stateParams) {
            return _.find(modules, {id: $stateParams.id})
          }
        }
      })
      /**
       * Class Routes
       */
      .state('classes', {
        url: '/classes',
        template: require('./views/classes'),
        controller: 'classes',
          resolve: {
              modules: function(Class) {
                  return Class.getList();
              }
          }
      })
      /**
       * Course Routes
       */
      .state('courses', {
        url: '/courses',
        template: require('./views/courses'),
        controller: 'courses',
          resolve: {
              courses: function(Courses) {
                  return Courses.getList();
              }
          }
      })
      .state('courses.create', {
        url: '/create',
        template: require('./views/courses/create-edit'),
        controller: 'courses.create-edit',
        resolve: {
          org: function () {
            return {}
          }

        }
      })
      .state('courses.edit', {
        url: '/:id',
        template: require('./views/courses/create-edit'),
        controller: 'courses.create-edit',
        resolve: {
          org: function (orgs, $stateParams) {
            return _.find(orgs, {id: $stateParams.id})
          }
        }
      })
  })
<commit_msg>Added test route, added routing info for classes and courses.<commit_after>angular.module('routes', ['ui.router'])
  .controller('error-handler', require('./controllers/error-handler'))
  .controller('home', require('./controllers/home'))
  .controller('login', require('./controllers/login'))
  .controller('signup', require('./controllers/signup'))
  .controller('user', require('./controllers/user'))
  .controller('modules', require('./controllers/modules'))
  .controller('modules.create-edit', require('./controllers/modules/create-edit'))
  .controller('admin', require('./controllers/admin'))
  .controller('classes', require('./controllers/classes'))
  .controller('courses.create-edit', require('./controllers/courses/create-edit'))
  .controller('orgs', require('./controllers/orgs'))
  .controller('orgs.create-edit', require('./controllers/orgs/create-edit'))
  .controller('courses', require('./controllers/courses'))
  .controller('courses.create-edit', require('./controllers/courses/create-edit'))
  .config(function($stateProvider) {
    $stateProvider

      /**
       * Core Routes
       */
      .state('home', {
        url: '/',
        controller: 'home',
        template: require('./views/home'),

        // This is an example of a resolve
        // It is commented out, because it will cause the route to fail
        //
        // resolve: {
        //   things: function(CoolThings) {
        //     return CoolThings.getList()
        //   }
        // }
      })
      .state('login', {
        url: '/login',
        template: require('./views/login'),
        controller: 'login',
      })
      // Static about page
      .state('about', {
        url: '/about',
        template: require('./views/about'),
      })
      // New User signup form
      .state('signup', {
        url: '/signup',
        controller: 'signup',
        template: require('./views/signup'),
      })
      // Password Reset
      .state('reset', {
        url: '/reset',
        template: require('./views/reset'),
      })
      // Test route
      .state('test', {
        url: '/test',
        template: require('./views/test'),
      })
      /**
       * User routes
       */
      .state('user', {
        url: '/user',
        template: require('./views/user'),
        controller: 'user',
      })
      .state('user.id', {
        url: '/user/:id',
        template: require('./views/user'),
        controller: 'user',
      })
      /**
       * Admin Routes
       */
      .state('admin', {
        url: '/admin',
        template: require('./views/admin'),
        controller: 'admin',
      })
      /**
       * Organization Routes
       */
      .state('orgs', {
        url: '/orgs',
        template: require('./views/orgs'),
        controller: 'orgs',
        resolve: {
           orgs: function(Orgs) {
             return Orgs.getList();
            }
          }
      })
      .state('orgs.create', {
        url: '/create',
        template: require('./views/orgs/create-edit'),
        controller: 'orgs.create-edit',
        resolve: {
          org: function () {
            return {}
          }

        }
      })
      .state('orgs.edit', {
        url: '/:id',
        template: require('./views/orgs/create-edit'),
        controller: 'orgs.create-edit',
        resolve: {
          org: function (orgs, $stateParams) {
            return _.find(orgs, {id: $stateParams.id})
          }
        }
      })
      /**
       * Module Routes
       */
      .state('modules', {
        url: '/modules',
        template: require('./views/modules'),
        controller: 'modules',
          resolve: {
              modules: function(Module) {
                  return Module.getList();
              }
          }
      })
      .state('modules.create', {
        url: '/create',
        template: require('./views/modules/create-edit'),
        controller: 'modules.create-edit',
        resolve: {
          module: function () {
            return {}
          }
        }
      })
      .state('modules.edit', {
        url: '/:id',
        template: require('./views/modules/create-edit'),
        controller: 'modules.create-edit',
        resolve: {
          module: function (modules, $stateParams) {
            return _.find(modules, {id: $stateParams.id})
          }
        }
      })
      /**
       * Class Routes
       */
      .state('classes', {
        url: '/classes',
        template: require('./views/classes'),
        controller: 'classes',
          resolve: {
              modules: function(Class) {
                  return Class.getList();
              }
          }
      })
      .state('classes.create', {
        url: '/create',
        template: require('./views/classes/create-edit'),
        controller: 'classes.create-edit',
        resolve: {
          org: function () {
            return {}
          }

        }
      })
      .state('classes.edit', {
        url: '/:id',
        template: require('./views/classes/create-edit'),
        controller: 'classes.create-edit',
        resolve: {
          org: function (orgs, $stateParams) {
            return _.find(orgs, {id: $stateParams.id})
          }
        }
      })
      /**
       * Course Routes
       */
      .state('courses', {
        url: '/courses',
        template: require('./views/courses'),
        controller: 'courses',
          resolve: {
              courses: function(Courses) {
                  return Courses.getList();
              }
          }
      })
      .state('courses.create', {
        url: '/create',
        template: require('./views/courses/create-edit'),
        controller: 'courses.create-edit',
        resolve: {
          org: function () {
            return {}
          }

        }
      })
      .state('courses.edit', {
        url: '/:id',
        template: require('./views/courses/create-edit'),
        controller: 'courses.create-edit',
        resolve: {
          org: function (orgs, $stateParams) {
            return _.find(orgs, {id: $stateParams.id})
          }
        }
      })
  })
<|endoftext|>


<commit_before>import React from 'react';
import { Route, IndexRoute } from 'react-router';

import App from 'containers/App/';
import Main from 'containers/Main/';

const routes = (
  <Route path="/" component={ App } >
    <IndexRoute component={ Main } />
    <Route path="/main" component={ Main } />
  </Route>
);

export default routes;<commit_msg>Fake import :)<commit_after>import React from 'react';
import { Route, IndexRoute } from 'react-router';
import try from 'try';

import App from 'containers/App/';
import Main from 'containers/Main/';

const routes = (
  <Route path="/" component={ App } >
    <IndexRoute component={ Main } />
    <Route path="/main" component={ Main } />
  </Route>
);

export default routes;
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose');
var Polls = require('../models/polls.js');
var handlebars  = require('handlebars');
var fs = require('fs');

module.exports = function (app, db) {
app.route('/polls/:pollID')
  .get(function (req, res) {
    var pollID = Number(req.params.pollID);
    if(Number.isInteger(pollID)){
        Polls.findOne({ 'id': pollID }, function (err, poll) {
             if (err) throw err;
             if(poll){
               displayChart(poll,res);
             } else {
                  console.log("no result")
             }

        })
    } else {
        //not an integer pollID
        console.log ("Incorrect Poll ID should 404");
    }

  // res.sendFile(process.cwd() + '/public/poll.html');
});
//Base case user visits home screen

};

// This grabs stuff from the database and formats it for chart.js. First 10 colors are defined, after that colors are random

function formatPoll (poll){
    var formatted = []
    var colorSlice;

    for (var i=0; i<poll.choices.length; i++){
         switch (i) {
         case 0:
            colorSlice = "#2E6171";
            break;
         case 1:
            colorSlice = "#556F7A";
            break;
        case 2:
            colorSlice = '#798086';
            break;
         case 3:
             colorSlice = '#B79FAD';
             break;
         case 4:
             colorSlice = '#D4AFCD';
             break;
         case 5:
             colorSlice = '#8A96B5';
             break;
         case 6:
             colorSlice = '#586994';
             break;
         case 7:
             colorSlice = "#924F7C";
             break;
         case 8:
             colorSlice = '#895D88';
             break;
         case 9:
             colorSlice = '#564639';
             break;
         default:
             colorSlice = '#'+Math.floor(Math.random()*16777215).toString(16);

         }

        formatted.push({value: poll.choices[i].votes,label: poll.choices[i].category,color: colorSlice});
    }
    return formatted;
}
function displayChart (poll, res){
                var display = formatPoll(poll)

                //add chart.js data into body
                var data = {
                    body: '
'poll.question + '

<canvas id="myChart" width="400" height="400"></canvas>',
                   // chartData: 'var data =' + JSON.stringify(display) + '; var ctx = document.getElementById("myChart").getContext("2d"); var myPieChart = new Chart(ctx).Pie(data);'
                  chartData: ' var data =[{"value":4,"label":"blueberry","color":"#2E6171"},{"value":3,"label":"raspberry","color":"#556F7A"},{"value":2,"label":"strawberry","color":"#798086"},{"value":2,"label":"tangerine","color":"#B79FAD"}]; var ctx = document.getElementById("myChart").getContext("2d"); var myPieChart = new Chart(ctx).Pie(data);'
                }

                //handle bars start

                fs.readFile('public/poll.html', 'utf-8', function(error, source){
               // handlebars.registerHelper('body')
                var template = handlebars.compile(source);
                var html = template(data);
                res.send(html);

                });

}<commit_msg>formatting for no data available<commit_after>'use strict';

var mongoose = require('mongoose');
var Polls = require('../models/polls.js');
var handlebars  = require('handlebars');
var fs = require('fs');

module.exports = function (app, db) {
app.route('/polls/:pollID')
  .get(function (req, res) {
    var pollID = Number(req.params.pollID);
    if(Number.isInteger(pollID)){
        Polls.findOne({ 'id': pollID }, function (err, poll) {
             if (err) throw err;
             if(poll){
               displayChart(poll,res);
             } else {
                  console.log("no result")
             }

        })
    } else {
        //not an integer pollID
        console.log ("Incorrect Poll ID should 404");
    }

  // res.sendFile(process.cwd() + '/public/poll.html');
});
//Base case user visits home screen

};

// This grabs stuff from the database and formats it for chart.js. First 10 colors are defined, after that colors are random

function formatPoll (poll){
    var formatted = []
    var colorSlice;

    for (var i=0; i<poll.choices.length; i++){
         switch (i) {
         case 0:
            colorSlice = "#2E6171";
            break;
         case 1:
            colorSlice = "#556F7A";
            break;
        case 2:
            colorSlice = '#798086';
            break;
         case 3:
             colorSlice = '#B79FAD';
             break;
         case 4:
             colorSlice = '#D4AFCD';
             break;
         case 5:
             colorSlice = '#8A96B5';
             break;
         case 6:
             colorSlice = '#586994';
             break;
         case 7:
             colorSlice = "#924F7C";
             break;
         case 8:
             colorSlice = '#895D88';
             break;
         case 9:
             colorSlice = '#564639';
             break;
         default:
             colorSlice = '#'+Math.floor(Math.random()*16777215).toString(16);

         }

        formatted.push({value: poll.choices[i].votes,label: poll.choices[i].category,color: colorSlice});
    }
    return formatted;
}
function displayChart (poll, res){
                var display = formatPoll(poll)

                //check if poll is empty for special case
                var empty = true;
                for (var i=0; i<display.length; i++){
                    if (display[i] >0){
                        empty = false;
                    }
                }

                //add chart.js data into body
                if (empty){
                    var data = {
                        body: '
No results to display

Get voting already!
',
                        chartData: " "
                    }
                }else{
                    var data = {
                        body: '
'+ poll.question + '

<canvas id="myChart" width="400" height="400"></canvas>',
                        chartData: 'var data =' + JSON.stringify(display) + '; var ctx = document.getElementById("myChart").getContext("2d"); var myPieChart = new Chart(ctx).Pie(data);'
                    }
                }

                //handle bars start

                fs.readFile('public/poll.html', 'utf-8', function(error, source){
               // handlebars.registerHelper('body')
                var template = handlebars.compile(source);
                var html = template(data);
                res.send(html);

                });

}<|endoftext|>