<commit_before>// ***********************************************//
//                 models and stores
// ***********************************************//
require('akvo-flow/core-common');
require('akvo-flow/models/store_def-common');

FLOW.BaseModel = DS.Model.extend({
  keyId: DS.attr('number'),
  savingStatus: null,

  // this method calls the checkSaving method on the savingMessageControl, which
  // checks if there are any records inflight. If yes, it sets a boolean,
  // so a saving message can be displayed. savingStatus is used to capture the
  // moment that nothing is being saved anymore, but in the previous event it was
  // so we can turn off the saving message.
  anySaving: function () {
    if (this.get('isSaving') || this.get('isDirty') || this.get('savingStatus')) {
      FLOW.savingMessageControl.checkSaving();
    }
    this.set('savingStatus', (this.get('isSaving') || this.get('isDirty')));
  }.observes('isSaving', 'isDirty')
});

FLOW.CascadeResource = FLOW.BaseModel.extend({
	name: DS.attr('string', {
	   defaultValue: ''
	}),
	version: DS.attr('number', {
		defaultValue: 1
	}),
	numLevels: DS.attr('number', {
		defaultValue: 1
	}),
	status: DS.attr('string', {
		defaultValue: 'NOT_PUBLISHED'
	}),
	levelNames: DS.attr('array', {defaultValue: []
	}),
});

FLOW.CascadeNode = FLOW.BaseModel.extend({
	name: DS.attr('string', {
	   defaultValue: ''
	}),
	code: DS.attr('string', {
		defaultValue: ''
	}),
	parentNodeId: DS.attr('number', {
		defaultValue: ''
	}),
	cascadeResourceId: DS.attr('number', {
		defaultValue: ''
	})
});

FLOW.SurveyGroup = FLOW.BaseModel.extend({
  description: DS.attr('string', {
    defaultValue: ''
  }),
  name: DS.attr('string', {
    defaultValue: ''
  }),
  path: DS.attr('string', {
    defaultValue: null
  }),
  ancestorIds: DS.attr('array', {
    defaultValue: []
  }),
  createdDateTime: DS.attr('string', {
    defaultValue: ''
  }),
  monitoringGroup: DS.attr('boolean', {
    defaultValue: false
  }),
  newLocaleSurveyId: DS.attr('number'),
  lastUpdateDateTime: DS.attr('string', {
    defaultValue: ''
  }),
  // the code field is used as name
  code: DS.attr('string', {
    defaultValue: ''
  }),

  parentId: DS.attr('number', {
    defaultValue: null
  }),

  projectType: DS.attr('string', {
    defaultValue: "PROJECT"
  }),

  privacyLevel: DS.attr('string', {
    defaultValue: "PRIVATE"
  }),

  defaultLanguageCode: DS.attr('string', {
    defaultValue: "en"
  }),

  published: DS.attr('boolean', {
    defaultValue: false
  }),

  surveyList: DS.attr('array', {
    defaultValue: null
  })

});

FLOW.Survey = FLOW.BaseModel.extend({
  didLoad: function () {
    // set the survey group name
    var sg = FLOW.store.find(FLOW.SurveyGroup, this.get('surveyGroupId'));
    if (!Ember.empty(sg)) {
      this.set('surveyGroupName', sg.get('code'));
    }
  },

  defaultLanguageCode: DS.attr('string'),
  status: DS.attr('string'),
  sector: DS.attr('string'),
  code: DS.attr('string'),
  requireApproval: DS.attr('string'),
  version: DS.attr('string'),
  description: DS.attr('string'),
  name: DS.attr('string'),
  path: DS.attr('string'),
  ancestorIds: DS.attr('ancestorIds'),
  pointType: DS.attr('string'),
  surveyGroupId: DS.attr('number'),
  createdDateTime: DS.attr('number'),
  lastUpdateDateTime: DS.attr('number'),
  instanceCount: DS.attr('number'),

  // This attribute is used for the 'Copy Survey' functionality
  // Most of the times is `null`
  sourceId: DS.attr('number', {
    defaultValue: null
  }),

  // used in the assignment edit page, not saved to backend
  surveyGroupName: null,

  allowEdit: function () {
	  return !this.get('isNew') && this.get('status') !== 'COPYING';
  }.property('status', 'isNew')

});

FLOW.QuestionGroup = FLOW.BaseModel.extend({
  order: DS.attr('number'),
  description: DS.attr('string'),
  name: DS.attr('string'),
  path: DS.attr('string'),
  code: DS.attr('string'),
  surveyId: DS.attr('number'),
  status: DS.attr('string'),
  sourceId: DS.attr('number', {
    defaultValue: null
  })
});

FLOW.Question = FLOW.BaseModel.extend({
  questionOptions: DS.hasMany('FLOW.QuestionOption'),
  questionOptionList: null,
  allowDecimal: DS.attr('boolean', {
    defaultValue: false
  }),
  allowMultipleFlag: DS.attr('boolean', {
    defaultValue: false
  }),
  allowOtherFlag: DS.attr('boolean', {
    defaultValue: false
  }),
  localeNameFlag: DS.attr('boolean', {
	    defaultValue: false
	  }),
  localeLocationFlag: DS.attr('boolean', {
		defaultValue: false
  }),
  allowSign: DS.attr('boolean', {
    defaultValue: false
  }),
  geoLocked: DS.attr('boolean', {
	    defaultValue: false
	  }),
  requireDoubleEntry: DS.attr('boolean', {
    defaultValue: false
  }),
  collapseable: DS.attr('boolean', {
    defaultValue: false
  }),
  immutable: DS.attr('boolean', {
    defaultValue: false
  }),
  isName: DS.attr('boolean', {
    defaultValue: false
  }),
  mandatoryFlag: DS.attr('boolean', {
    defaultValue: true
  }),
  dependentFlag: DS.attr('boolean', {
    defaultValue: false
  }),
  dependentQuestionAnswer: DS.attr('string'),
  dependentQuestionId: DS.attr('number'),
  maxVal: DS.attr('number', {
    defaultValue: null
  }),
  minVal: DS.attr('number', {
    defaultValue: null
  }),
  order: DS.attr('number'),
  cascadeResourceId: DS.attr('number'),
  path: DS.attr('string'),
  questionGroupId: DS.attr('number'),
  surveyId: DS.attr('number'),
  questionId: DS.attr('string'),
  metricId: DS.attr('number'),
  text: DS.attr('string'),
  tip: DS.attr('string'),
  type: DS.attr('string', {
	defaultValue: "FREE_TEXT"
  }),
  // This attribute is used for the 'Copy Survey' functionality
  // Most of the times is `null`
  sourceId: DS.attr('number', {
	 defaultValue: null
  }),
  allowExternalSources: DS.attr('boolean', {
    defaultValue: false
  }),
  // Geoshape question type options
  allowPoints: DS.attr('boolean', {
    defaultValue: true
  }),
  allowLine: DS.attr('boolean', {
    defaultValue: true
  }),
  allowPolygon: DS.attr('boolean', {
    defaultValue: true
  })
});

FLOW.QuestionOption = FLOW.BaseModel.extend({
  question: DS.belongsTo('FLOW.Question'),
  order: DS.attr('number'),
  questionId: DS.attr('number'),
  text: DS.attr('string')
});

FLOW.DeviceGroup = FLOW.BaseModel.extend({
  code: DS.attr('string', {
    defaultValue: ''
  })
});

FLOW.Device = FLOW.BaseModel.extend({
  didLoad: function () {
    var combinedName;
    if (Ember.empty(this.get('deviceIdentifier'))) {
      combinedName = "no identifer";
    } else {
      combinedName = this.get('deviceIdentifier');
    }
    this.set('combinedName', combinedName + " " + this.get('phoneNumber'));
  },
  esn: DS.attr('string', {
    defaultValue: ''
  }),
  phoneNumber: DS.attr('string', {
    defaultValue: ''
  }),
  deviceIdentifier: DS.attr('string', {
    defaultValue: ''
  }),
  gallatinSoftwareManifest: DS.attr('string'),
  lastKnownLat: DS.attr('number', {
    defaultValue: 0
  }),
  lastKnownLon: DS.attr('number', {
    defaultValue: 0
  }),
  lastKnownAccuracy: DS.attr('number', {
    defaultValue: 0
  }),
  lastPositionDate: DS.attr('number', {
    defaultValue: ''
  }),
  deviceGroup: DS.attr('string', {
    defaultValue: ''
  }),
  deviceGroupName: DS.attr('string', {
    defaultValue: ''
  }),
  isSelected: false,
  combinedName: null
});

FLOW.SurveyAssignment = FLOW.BaseModel.extend({
  name: DS.attr('string'),
  startDate: DS.attr('number'),
  endDate: DS.attr('number'),
  devices: DS.attr('array'),
  surveys: DS.attr('array'),
  language: DS.attr('string')
});

FLOW.SurveyedLocale = DS.Model.extend({
  description: DS.attr('string', {
    defaultValue: ''
  }),
  keyId: DS.attr('number'),
  latitude: DS.attr('number'),
  longitude: DS.attr('number'),
  displayName: DS.attr('string'),
  lastUpdateDateTime: DS.attr('number'),
  surveyGroupId: DS.attr('number'),
  identifier: DS.attr('string'),
  primaryKey: 'keyId'
});

// Explicitly avoid to use belongTo and hasMany as
// Ember-Data lacks of partial loading
// https://github.com/emberjs/data/issues/51
FLOW.PlacemarkDetail = FLOW.BaseModel.extend({
  placemarkId: DS.attr('number'),
  collectionDate: DS.attr('number'),
  order: DS.attr('number'),
  questionText: DS.attr('string'),
  metricName: DS.attr('string'),
  stringValue: DS.attr('string'),
  questionType: DS.attr('string')
});

FLOW.Placemark = FLOW.BaseModel.extend({
	latitude: DS.attr('number'),
	longitude: DS.attr('number'),
	count: DS.attr('number'),
	level: DS.attr('number'),
	surveyId: DS.attr('number'),
	detailsId: DS.attr('number'),
	collectionDate: DS.attr('number')
});

FLOW.SurveyInstance = FLOW.BaseModel.extend({
  approvedFlag: DS.attr('string'),
  approximateLocationFlag: DS.attr('string'),
  surveyId: DS.attr('number'),
  surveyedLocaleId:DS.attr('number'),
  collectionDate: DS.attr('number'),
  surveyCode: DS.attr('string'),
  submitterName: DS.attr('string'),
  deviceIdentifier: DS.attr('string')
});

FLOW.QuestionAnswer = FLOW.BaseModel.extend({
  value: DS.attr('string'),
  type: DS.attr('string'),
  oldValue: DS.attr('string'),
  surveyId: DS.attr('number'),
  collectionDate: DS.attr('number'),
  surveyInstanceId: DS.attr('number'),
  questionID: DS.attr('string'),
  questionText: DS.attr('string')
});

FLOW.SurveyQuestionSummary = FLOW.BaseModel.extend({
  response: DS.attr('string'),
  count: DS.attr('number'),
  percentage: null,
  questionId: DS.attr('string')
});

FLOW.User = FLOW.BaseModel.extend({
  userName: DS.attr('string'),
  emailAddress: DS.attr('string'),
  admin: DS.attr('boolean', {
    defaultValue: 0
  }),
  superAdmin: DS.attr('boolean', {
    defaultValue: 0
  }),
  permissionList: DS.attr('string'),
  accessKey: DS.attr('string')
});

FLOW.UserConfig = FLOW.BaseModel.extend({
  group: DS.attr('string'),
  name: DS.attr('string'),
  value: DS.attr('string'),
  userId: DS.attr('number')
});

// this is called attribute in the dashboard, but metric in the backend, for historic reasons.
FLOW.Metric = FLOW.BaseModel.extend({
  organization: DS.attr('string'),
  name: DS.attr('string'),
  group: DS.attr('string'),
  valueType: DS.attr('string'),
  questionId: DS.attr('number')
});

FLOW.Message = FLOW.BaseModel.extend({
  objectId: DS.attr('number'),
  lastUpdateDateTime: DS.attr('number'),
  userName: DS.attr('string'),
  objectTitle: DS.attr('string'),
  actionAbout: DS.attr('string'),
  shortMessage: DS.attr('string')
});

FLOW.Action = FLOW.BaseModel.extend({});

FLOW.Translation = FLOW.BaseModel.extend({
  didUpdate: function () {
    FLOW.translationControl.putSingleTranslationInList(this.get('parentType'), this.get('parentId'), this.get('text'), this.get('keyId'), false);
  },

  // can't use this at the moment, as the didCreate is fired before the id is back from the ajax call
  // didCreate: function(){
  //   console.log('didCreate',this.get('keyId'));
  //   FLOW.translationControl.putSingleTranslationInList(this.get('parentType'),this.get('parentId'),this.get('text'),this.get('keyId'), false);
  // },

  // temporary hack to fire the didCreate event after the keyId is known
  didCreateId: function () {
    if (!Ember.none(this.get('keyId')) && this.get('keyId') > 0) {
      FLOW.translationControl.putSingleTranslationInList(this.get('parentType'), this.get('parentId'), this.get('text'), this.get('keyId'), false);
    }
  }.observes('this.keyId'),

  didDelete: function () {
    FLOW.translationControl.putSingleTranslationInList(this.get('parentType'), this.get('parentId'), null, null, true);
  },

  parentType: DS.attr('string'),
  parentId: DS.attr('string'),
  surveyId: DS.attr('string'),
  questionGroupId: DS.attr('string'),
  text: DS.attr('string'),
  langCode: DS.attr('string')
});

FLOW.NotificationSubscription = FLOW.BaseModel.extend({
  notificationDestination: DS.attr('string'),
  notificationOption: DS.attr('string'),
  notificationMethod: DS.attr('string'),
  notificationType: DS.attr('string'),
  expiryDate: DS.attr('number'),
  entityId: DS.attr('number')
});

FLOW.SubCountry = FLOW.BaseModel.extend({
  countryCode: DS.attr('string'),
  level: DS.attr('number'),
  name: DS.attr('string'),
  parentKey: DS.attr('number'),
  parentName: DS.attr('string')
});
<commit_msg>[#1215] Fix `Survey` model attribute<commit_after>// ***********************************************//
//                 models and stores
// ***********************************************//
require('akvo-flow/core-common');
require('akvo-flow/models/store_def-common');

FLOW.BaseModel = DS.Model.extend({
  keyId: DS.attr('number'),
  savingStatus: null,

  // this method calls the checkSaving method on the savingMessageControl, which
  // checks if there are any records inflight. If yes, it sets a boolean,
  // so a saving message can be displayed. savingStatus is used to capture the
  // moment that nothing is being saved anymore, but in the previous event it was
  // so we can turn off the saving message.
  anySaving: function () {
    if (this.get('isSaving') || this.get('isDirty') || this.get('savingStatus')) {
      FLOW.savingMessageControl.checkSaving();
    }
    this.set('savingStatus', (this.get('isSaving') || this.get('isDirty')));
  }.observes('isSaving', 'isDirty')
});

FLOW.CascadeResource = FLOW.BaseModel.extend({
	name: DS.attr('string', {
	   defaultValue: ''
	}),
	version: DS.attr('number', {
		defaultValue: 1
	}),
	numLevels: DS.attr('number', {
		defaultValue: 1
	}),
	status: DS.attr('string', {
		defaultValue: 'NOT_PUBLISHED'
	}),
	levelNames: DS.attr('array', {defaultValue: []
	}),
});

FLOW.CascadeNode = FLOW.BaseModel.extend({
	name: DS.attr('string', {
	   defaultValue: ''
	}),
	code: DS.attr('string', {
		defaultValue: ''
	}),
	parentNodeId: DS.attr('number', {
		defaultValue: ''
	}),
	cascadeResourceId: DS.attr('number', {
		defaultValue: ''
	})
});

FLOW.SurveyGroup = FLOW.BaseModel.extend({
  description: DS.attr('string', {
    defaultValue: ''
  }),
  name: DS.attr('string', {
    defaultValue: ''
  }),
  path: DS.attr('string', {
    defaultValue: null
  }),
  ancestorIds: DS.attr('array', {
    defaultValue: []
  }),
  createdDateTime: DS.attr('string', {
    defaultValue: ''
  }),
  monitoringGroup: DS.attr('boolean', {
    defaultValue: false
  }),
  newLocaleSurveyId: DS.attr('number'),
  lastUpdateDateTime: DS.attr('string', {
    defaultValue: ''
  }),
  // the code field is used as name
  code: DS.attr('string', {
    defaultValue: ''
  }),

  parentId: DS.attr('number', {
    defaultValue: null
  }),

  projectType: DS.attr('string', {
    defaultValue: "PROJECT"
  }),

  privacyLevel: DS.attr('string', {
    defaultValue: "PRIVATE"
  }),

  defaultLanguageCode: DS.attr('string', {
    defaultValue: "en"
  }),

  published: DS.attr('boolean', {
    defaultValue: false
  }),

  surveyList: DS.attr('array', {
    defaultValue: null
  })

});

FLOW.Survey = FLOW.BaseModel.extend({
  didLoad: function () {
    // set the survey group name
    var sg = FLOW.store.find(FLOW.SurveyGroup, this.get('surveyGroupId'));
    if (!Ember.empty(sg)) {
      this.set('surveyGroupName', sg.get('code'));
    }
  },

  defaultLanguageCode: DS.attr('string'),
  status: DS.attr('string'),
  sector: DS.attr('string'),
  code: DS.attr('string'),
  requireApproval: DS.attr('string'),
  version: DS.attr('string'),
  description: DS.attr('string'),
  name: DS.attr('string'),
  path: DS.attr('string'),
  ancestorIds: DS.attr('array'),
  pointType: DS.attr('string'),
  surveyGroupId: DS.attr('number'),
  createdDateTime: DS.attr('number'),
  lastUpdateDateTime: DS.attr('number'),
  instanceCount: DS.attr('number'),

  // This attribute is used for the 'Copy Survey' functionality
  // Most of the times is `null`
  sourceId: DS.attr('number', {
    defaultValue: null
  }),

  // used in the assignment edit page, not saved to backend
  surveyGroupName: null,

  allowEdit: function () {
	  return !this.get('isNew') && this.get('status') !== 'COPYING';
  }.property('status', 'isNew')

});

FLOW.QuestionGroup = FLOW.BaseModel.extend({
  order: DS.attr('number'),
  description: DS.attr('string'),
  name: DS.attr('string'),
  path: DS.attr('string'),
  code: DS.attr('string'),
  surveyId: DS.attr('number'),
  status: DS.attr('string'),
  sourceId: DS.attr('number', {
    defaultValue: null
  })
});

FLOW.Question = FLOW.BaseModel.extend({
  questionOptions: DS.hasMany('FLOW.QuestionOption'),
  questionOptionList: null,
  allowDecimal: DS.attr('boolean', {
    defaultValue: false
  }),
  allowMultipleFlag: DS.attr('boolean', {
    defaultValue: false
  }),
  allowOtherFlag: DS.attr('boolean', {
    defaultValue: false
  }),
  localeNameFlag: DS.attr('boolean', {
	    defaultValue: false
	  }),
  localeLocationFlag: DS.attr('boolean', {
		defaultValue: false
  }),
  allowSign: DS.attr('boolean', {
    defaultValue: false
  }),
  geoLocked: DS.attr('boolean', {
	    defaultValue: false
	  }),
  requireDoubleEntry: DS.attr('boolean', {
    defaultValue: false
  }),
  collapseable: DS.attr('boolean', {
    defaultValue: false
  }),
  immutable: DS.attr('boolean', {
    defaultValue: false
  }),
  isName: DS.attr('boolean', {
    defaultValue: false
  }),
  mandatoryFlag: DS.attr('boolean', {
    defaultValue: true
  }),
  dependentFlag: DS.attr('boolean', {
    defaultValue: false
  }),
  dependentQuestionAnswer: DS.attr('string'),
  dependentQuestionId: DS.attr('number'),
  maxVal: DS.attr('number', {
    defaultValue: null
  }),
  minVal: DS.attr('number', {
    defaultValue: null
  }),
  order: DS.attr('number'),
  cascadeResourceId: DS.attr('number'),
  path: DS.attr('string'),
  questionGroupId: DS.attr('number'),
  surveyId: DS.attr('number'),
  questionId: DS.attr('string'),
  metricId: DS.attr('number'),
  text: DS.attr('string'),
  tip: DS.attr('string'),
  type: DS.attr('string', {
	defaultValue: "FREE_TEXT"
  }),
  // This attribute is used for the 'Copy Survey' functionality
  // Most of the times is `null`
  sourceId: DS.attr('number', {
	 defaultValue: null
  }),
  allowExternalSources: DS.attr('boolean', {
    defaultValue: false
  }),
  // Geoshape question type options
  allowPoints: DS.attr('boolean', {
    defaultValue: true
  }),
  allowLine: DS.attr('boolean', {
    defaultValue: true
  }),
  allowPolygon: DS.attr('boolean', {
    defaultValue: true
  })
});

FLOW.QuestionOption = FLOW.BaseModel.extend({
  question: DS.belongsTo('FLOW.Question'),
  order: DS.attr('number'),
  questionId: DS.attr('number'),
  text: DS.attr('string')
});

FLOW.DeviceGroup = FLOW.BaseModel.extend({
  code: DS.attr('string', {
    defaultValue: ''
  })
});

FLOW.Device = FLOW.BaseModel.extend({
  didLoad: function () {
    var combinedName;
    if (Ember.empty(this.get('deviceIdentifier'))) {
      combinedName = "no identifer";
    } else {
      combinedName = this.get('deviceIdentifier');
    }
    this.set('combinedName', combinedName + " " + this.get('phoneNumber'));
  },
  esn: DS.attr('string', {
    defaultValue: ''
  }),
  phoneNumber: DS.attr('string', {
    defaultValue: ''
  }),
  deviceIdentifier: DS.attr('string', {
    defaultValue: ''
  }),
  gallatinSoftwareManifest: DS.attr('string'),
  lastKnownLat: DS.attr('number', {
    defaultValue: 0
  }),
  lastKnownLon: DS.attr('number', {
    defaultValue: 0
  }),
  lastKnownAccuracy: DS.attr('number', {
    defaultValue: 0
  }),
  lastPositionDate: DS.attr('number', {
    defaultValue: ''
  }),
  deviceGroup: DS.attr('string', {
    defaultValue: ''
  }),
  deviceGroupName: DS.attr('string', {
    defaultValue: ''
  }),
  isSelected: false,
  combinedName: null
});

FLOW.SurveyAssignment = FLOW.BaseModel.extend({
  name: DS.attr('string'),
  startDate: DS.attr('number'),
  endDate: DS.attr('number'),
  devices: DS.attr('array'),
  surveys: DS.attr('array'),
  language: DS.attr('string')
});

FLOW.SurveyedLocale = DS.Model.extend({
  description: DS.attr('string', {
    defaultValue: ''
  }),
  keyId: DS.attr('number'),
  latitude: DS.attr('number'),
  longitude: DS.attr('number'),
  displayName: DS.attr('string'),
  lastUpdateDateTime: DS.attr('number'),
  surveyGroupId: DS.attr('number'),
  identifier: DS.attr('string'),
  primaryKey: 'keyId'
});

// Explicitly avoid to use belongTo and hasMany as
// Ember-Data lacks of partial loading
// https://github.com/emberjs/data/issues/51
FLOW.PlacemarkDetail = FLOW.BaseModel.extend({
  placemarkId: DS.attr('number'),
  collectionDate: DS.attr('number'),
  order: DS.attr('number'),
  questionText: DS.attr('string'),
  metricName: DS.attr('string'),
  stringValue: DS.attr('string'),
  questionType: DS.attr('string')
});

FLOW.Placemark = FLOW.BaseModel.extend({
	latitude: DS.attr('number'),
	longitude: DS.attr('number'),
	count: DS.attr('number'),
	level: DS.attr('number'),
	surveyId: DS.attr('number'),
	detailsId: DS.attr('number'),
	collectionDate: DS.attr('number')
});

FLOW.SurveyInstance = FLOW.BaseModel.extend({
  approvedFlag: DS.attr('string'),
  approximateLocationFlag: DS.attr('string'),
  surveyId: DS.attr('number'),
  surveyedLocaleId:DS.attr('number'),
  collectionDate: DS.attr('number'),
  surveyCode: DS.attr('string'),
  submitterName: DS.attr('string'),
  deviceIdentifier: DS.attr('string')
});

FLOW.QuestionAnswer = FLOW.BaseModel.extend({
  value: DS.attr('string'),
  type: DS.attr('string'),
  oldValue: DS.attr('string'),
  surveyId: DS.attr('number'),
  collectionDate: DS.attr('number'),
  surveyInstanceId: DS.attr('number'),
  questionID: DS.attr('string'),
  questionText: DS.attr('string')
});

FLOW.SurveyQuestionSummary = FLOW.BaseModel.extend({
  response: DS.attr('string'),
  count: DS.attr('number'),
  percentage: null,
  questionId: DS.attr('string')
});

FLOW.User = FLOW.BaseModel.extend({
  userName: DS.attr('string'),
  emailAddress: DS.attr('string'),
  admin: DS.attr('boolean', {
    defaultValue: 0
  }),
  superAdmin: DS.attr('boolean', {
    defaultValue: 0
  }),
  permissionList: DS.attr('string'),
  accessKey: DS.attr('string')
});

FLOW.UserConfig = FLOW.BaseModel.extend({
  group: DS.attr('string'),
  name: DS.attr('string'),
  value: DS.attr('string'),
  userId: DS.attr('number')
});

// this is called attribute in the dashboard, but metric in the backend, for historic reasons.
FLOW.Metric = FLOW.BaseModel.extend({
  organization: DS.attr('string'),
  name: DS.attr('string'),
  group: DS.attr('string'),
  valueType: DS.attr('string'),
  questionId: DS.attr('number')
});

FLOW.Message = FLOW.BaseModel.extend({
  objectId: DS.attr('number'),
  lastUpdateDateTime: DS.attr('number'),
  userName: DS.attr('string'),
  objectTitle: DS.attr('string'),
  actionAbout: DS.attr('string'),
  shortMessage: DS.attr('string')
});

FLOW.Action = FLOW.BaseModel.extend({});

FLOW.Translation = FLOW.BaseModel.extend({
  didUpdate: function () {
    FLOW.translationControl.putSingleTranslationInList(this.get('parentType'), this.get('parentId'), this.get('text'), this.get('keyId'), false);
  },

  // can't use this at the moment, as the didCreate is fired before the id is back from the ajax call
  // didCreate: function(){
  //   console.log('didCreate',this.get('keyId'));
  //   FLOW.translationControl.putSingleTranslationInList(this.get('parentType'),this.get('parentId'),this.get('text'),this.get('keyId'), false);
  // },

  // temporary hack to fire the didCreate event after the keyId is known
  didCreateId: function () {
    if (!Ember.none(this.get('keyId')) && this.get('keyId') > 0) {
      FLOW.translationControl.putSingleTranslationInList(this.get('parentType'), this.get('parentId'), this.get('text'), this.get('keyId'), false);
    }
  }.observes('this.keyId'),

  didDelete: function () {
    FLOW.translationControl.putSingleTranslationInList(this.get('parentType'), this.get('parentId'), null, null, true);
  },

  parentType: DS.attr('string'),
  parentId: DS.attr('string'),
  surveyId: DS.attr('string'),
  questionGroupId: DS.attr('string'),
  text: DS.attr('string'),
  langCode: DS.attr('string')
});

FLOW.NotificationSubscription = FLOW.BaseModel.extend({
  notificationDestination: DS.attr('string'),
  notificationOption: DS.attr('string'),
  notificationMethod: DS.attr('string'),
  notificationType: DS.attr('string'),
  expiryDate: DS.attr('number'),
  entityId: DS.attr('number')
});

FLOW.SubCountry = FLOW.BaseModel.extend({
  countryCode: DS.attr('string'),
  level: DS.attr('number'),
  name: DS.attr('string'),
  parentKey: DS.attr('number'),
  parentName: DS.attr('string')
});
<|endoftext|>


<commit_before><commit_msg>First Commit<commit_after><|endoftext|>


<commit_before>var chalk = require('chalk');
var ansi = require('ansi-escapes');
var readline = require('readline');
var execSync = require('child_process').execSync;

function Interactive() {
	this.prompt = 'Enter a file glob: ';
	this.input = '';
	this.getGitFiles = true;
	this.getCommitMessage = false;
	this.inputColor = 'red';

	this.setup();
};

var proto = Interactive.prototype;

proto.setup = function() {
	readline.emitKeypressEvents(process.stdin);
	process.stdin.setRawMode(true);
	process.stdin.resume();

	process.stdin.on('keypress', function(char, key) {
		if (key.ctrl && key.name === 'c') {
	    process.exit();
	  }
	});

	process.stdin.on('keypress', function(char, key) {
		if (key.name === 'backspace') {
			this.onBackspace();
		} else if (key.name === 'return') {
			this.onReturn();
		} else {
			this.onType(char, key);
		}

		if (this.getGitFiles) {
			this.renderGitFiles();
		}
	}.bind(this));

	process.on('exit', function() {
		this.eraseBelow();
		console.log();
	}.bind(this));
};

proto.onReturn = function() {
	if (this.getGitFiles) {
		this.getGitFiles = false;
		this.getCommitMessage = true;
		this.renderAddSuccess();

		this.prompt = 'Commit message: ' + chalk.green('"');
		this.input = '';
		this.inputColor = 'green';

		this.renderLine();
	} else if (this.getCommitMessage) {
		var message = this.input;
		execSync('git commit -m "' + message + '"');

		console.log();
		console.log();
		console.log('----------------');
		console.log();
		console.log('Files committed successfully.');
		process.exit();
	}
};

proto.onBackspace = function() {
	this.input = this.input.slice(0, this.input.length - 1);

	if (this.input.length !== 0) {
		process.stdout.write(ansi.cursorMove(-1));
	}
	this.renderLine();
};

proto.onType = function(char, key) {
	if (typeof char !== 'undefined') {
		this.input += char + ''
	}
	this.renderLine();
};

proto.colorInput = function(input) {
	return chalk[this.inputColor](input);
};

proto.run = function() {
	this.renderLine();
	let files = this.getAllGitFiles();
	this.printBelow(files);
};

proto.renderLine = function() {
	var string = this.prompt + this.colorInput(this.input);
	if (this.getCommitMessage) {
		string += chalk.green('"');
	}

	process.stdout.clearLine();
	process.stdout.cursorTo(0);
	process.stdout.write(string);

	if (this.getCommitMessage) {
		process.stdout.write(ansi.cursorMove(-1));
	}
};

proto.renderGitFiles = function() {
	this.eraseBelow();
	var glob = this.input;
	var files = this.getAllGitFiles(glob);
	this.printBelow(files);
};

proto.renderAddSuccess = function() {
	this.eraseBelow();
	process.stdout.clearLine();
	process.stdout.write(ansi.cursorLeft);

	var glob = this.input;
	var files = this.getAllGitFiles(glob);

	try {
		execSync('git add *' + glob + '* &> /dev/null');
	} catch (e) {

	}

	console.log('Files added: ');
	console.log(chalk.green(files));
	console.log('----------------');
	console.log();
};

proto.getAllGitFiles = function(glob) {
	if (typeof glob === 'undefined') {
		glob = '';
	}

	try {
		var files = execSync("{ git diff --name-only; git ls-files --other --exclude-standard; } | sort | uniq | grep '" + glob +  "'");
		return files.toString('utf8');
	} catch (e) {
		return '';
	}
};

proto.eraseBelow = function() {
	process.stdout.write(ansi.eraseDown);
};

proto.printBelow = function(files) {
	process.stdout.write(ansi.cursorSavePosition);
	console.log();
	console.log();
	console.log(chalk.green('Files found: '));
	console.log(chalk.red(files));
	process.stdout.write(ansi.cursorRestorePosition);
};

module.exports = Interactive;
<commit_msg>Pipe error to /dev/null<commit_after>var chalk = require('chalk');
var ansi = require('ansi-escapes');
var readline = require('readline');
var execSync = require('child_process').execSync;

function Interactive() {
	this.prompt = 'Enter a file glob: ';
	this.input = '';
	this.getGitFiles = true;
	this.getCommitMessage = false;
	this.inputColor = 'red';

	this.setup();
};

var proto = Interactive.prototype;

proto.setup = function() {
	readline.emitKeypressEvents(process.stdin);
	process.stdin.setRawMode(true);
	process.stdin.resume();

	process.stdin.on('keypress', function(char, key) {
		if (key.ctrl && key.name === 'c') {
	    process.exit();
	  }
	});

	process.stdin.on('keypress', function(char, key) {
		if (key.name === 'backspace') {
			this.onBackspace();
		} else if (key.name === 'return') {
			this.onReturn();
		} else {
			this.onType(char, key);
		}

		if (this.getGitFiles) {
			this.renderGitFiles();
		}
	}.bind(this));

	process.on('exit', function() {
		this.eraseBelow();
		console.log();
	}.bind(this));
};

proto.onReturn = function() {
	if (this.getGitFiles) {
		this.getGitFiles = false;
		this.getCommitMessage = true;
		this.renderAddSuccess();

		this.prompt = 'Commit message: ' + chalk.green('"');
		this.input = '';
		this.inputColor = 'green';

		this.renderLine();
	} else if (this.getCommitMessage) {
		var message = this.input;
		execSync('git commit -m "' + message + '"');

		console.log();
		console.log();
		console.log('----------------');
		console.log();
		console.log('Files committed successfully.');
		process.exit();
	}
};

proto.onBackspace = function() {
	this.input = this.input.slice(0, this.input.length - 1);

	if (this.input.length !== 0) {
		process.stdout.write(ansi.cursorMove(-1));
	}
	this.renderLine();
};

proto.onType = function(char, key) {
	if (typeof char !== 'undefined') {
		this.input += char + ''
	}
	this.renderLine();
};

proto.colorInput = function(input) {
	return chalk[this.inputColor](input);
};

proto.run = function() {
	this.renderLine();
	let files = this.getAllGitFiles();
	this.printBelow(files);
};

proto.renderLine = function() {
	var string = this.prompt + this.colorInput(this.input);
	if (this.getCommitMessage) {
		string += chalk.green('"');
	}

	process.stdout.clearLine();
	process.stdout.cursorTo(0);
	process.stdout.write(string);

	if (this.getCommitMessage) {
		process.stdout.write(ansi.cursorMove(-1));
	}
};

proto.renderGitFiles = function() {
	this.eraseBelow();
	var glob = this.input;
	var files = this.getAllGitFiles(glob);
	this.printBelow(files);
};

proto.renderAddSuccess = function() {
	this.eraseBelow();
	process.stdout.clearLine();
	process.stdout.write(ansi.cursorLeft);

	var glob = this.input;
	var files = this.getAllGitFiles(glob);

	try {
		execSync('git add *' + glob + '* &> /dev/null');
	} catch (e) {

	}

	console.log('Files added: ');
	console.log(chalk.green(files));
	console.log('----------------');
	console.log();
};

proto.getAllGitFiles = function(glob) {
	if (typeof glob === 'undefined') {
		glob = '';
	}

	try {
		var files = execSync("{ git diff --name-only; git ls-files --other --exclude-standard; } | sort | uniq | grep '" + glob +  "' 2> /dev/null");
		return files.toString('utf8');
	} catch (e) {
		return '';
	}
};

proto.eraseBelow = function() {
	process.stdout.write(ansi.eraseDown);
};

proto.printBelow = function(files) {
	process.stdout.write(ansi.cursorSavePosition);
	console.log();
	console.log();
	console.log(chalk.green('Files found: '));
	console.log(chalk.red(files));
	process.stdout.write(ansi.cursorRestorePosition);
};

module.exports = Interactive;
<|endoftext|>


<commit_before>/* eslint-disable no-empty, import/no-dynamic-require, global-require */
import { graphql } from 'graphql';
import glob from 'glob';
import path from 'path';
import fse from 'fs-extra';
import get from 'lodash/get';
import set from 'lodash/set';
import has from 'lodash/has';
import pick from 'lodash/pick';
import isPlainObject from 'lodash/isPlainObject';
import invariant from 'invariant';
import identity from 'lodash/identity';
import { Module } from 'oors';
import { PubSub } from 'graphql-subscriptions';
import merge from 'lodash/merge';
import {
  makeExecutableSchema,
  makeRemoteExecutableSchema,
  mergeSchemas,
  addResolveFunctionsToSchema,
  addSchemaLevelResolveFunction,
  attachDirectiveResolvers,
} from 'graphql-tools';
import { express as voyagerMiddleware } from 'graphql-voyager/middleware';
import { importSchema } from 'graphql-import';
import { Binding } from 'graphql-binding';
import Ajv from 'ajv';
import ajvKeywords from 'ajv-keywords';
import ConstraintDirective from 'graphql-constraint-directive';
import depthLimit from 'graphql-depth-limit';
import mainResolvers from './graphql/resolvers';
import modulesResolvers from './graphql/modulesResolvers';
import LoadersMap from './libs/LoadersMap';
import * as decorators from './decorators';
import Server from './libs/Server';

class Gql extends Module {
  static schema = {
    type: 'object',
    properties: {
      voyager: {
        type: 'object',
        properties: {
          enabled: {
            type: 'boolean',
            default: true,
          },
          params: {
            type: 'object',
            properties: {
              endpointURL: {
                type: 'string',
                default: '/graphql',
              },
            },
            default: {},
          },
        },
        default: {},
      },
      middlewarePivot: {
        type: 'string',
        default: 'isMethod',
      },
      configureSchema: {
        instanceof: 'Function',
      },
      exposeModules: {
        type: 'boolean',
        default: true,
      },
      serverOptions: {
        type: 'object',
        default: {},
      },
      pubsub: {
        type: 'object',
      },
      depthLimit: {
        type: 'object',
        properties: {
          limit: {
            type: 'integer',
            default: 10,
          },
          options: {
            type: 'object',
            properties: {
              ignore: {
                type: 'array',
                default: [],
              },
            },
          },
          callback: {
            instanceof: 'Function',
          },
        },
        default: {},
      },
      costAnalysis: {
        type: 'object',
        properties: {
          maximumCost: {
            type: 'integer',
            default: 1000,
          },
        },
        default: {},
      },
    },
  };

  name = 'oors.graphql';

  initialize() {
    this.ajv = new Ajv({
      allErrors: true,
      verbose: true,
      async: 'es7',
      useDefaults: true,
    });
    ajvKeywords(this.ajv, 'instanceof');

    this.typeDefs = [];
    this.directives = {
      constraint: ConstraintDirective,
    };
    this.resolvers = mainResolvers;
    this.resolverMiddlewares = [];
    this.pubsub = this.getConfig('pubsub', new PubSub());
    this.gqlContext = {
      pubsub: this.pubsub,
      ajv: this.ajv,
      app: this.app,
    };
    this.loaders = new LoadersMap();
    this.contextExtenders = [];
    this.formatters = {
      params: [],
      error: [],
      response: [],
    };
  }

  async setup() {
    await this.runHook(
      'load',
      this.collectFromModule,
      pick(this, [
        'pubsub',
        'addTypeDefs',
        'addDirectives',
        'addTypeDefsByPath',
        'addResolvers',
        'addResolverMiddleware',
        'addLoader',
        'loadFromDir',
      ]),
    );

    if (this.getConfig('exposeModules')) {
      this.addResolvers(modulesResolvers);
      await this.addTypeDefsByPath(path.resolve(__dirname, './graphql/modulesTypeDefs.graphql'));
    }

    await this.runHook('buildContext', () => {}, {
      context: this.gqlContext,
    });

    this.schema = await this.buildSchema();
    this.server = this.buildServer();

    this.applyMiddlewares(this.server);

    const binding = this.bindSchema(this.schema);

    this.exportProperties([
      'extendContext',
      'schema',
      'server',
      'loaders',
      'addResolverMiddleware',
      'addLoader',
      'addLoaders',
      'addResolvers',
      'importSchema',
      'bindSchema',
      'binding',
      'setupListen',
      'pubsub',
      'formatters',
      'buildContext',
      'execute',
    ]);

    this.export({
      context: this.gqlContext,
      addSchemaResolvers: rootResolveFunction =>
        addSchemaLevelResolveFunction(this.schema, rootResolveFunction),
      addDirectivesResolvers: directivesResolvers =>
        attachDirectiveResolvers(this.schema, directivesResolvers),
    });

    this.on('after:setup', () => {
      Object.assign(this.gqlContext, {
        binding,
      });
    });
  }

  extendContext = extender => {
    invariant(
      typeof extender === 'function' || isPlainObject(extender),
      `Invalid context extender! Needs to be either a function or a an object that will get
      assigned to the context.`,
    );
    this.contextExtenders.push(extender);
    return this.contextExtenders;
  };

  bindSchema = (schema, options = {}) =>
    new Binding({
      schema,
      ...options,
    });

  addTypeDefs = typeDefs => {
    this.typeDefs.push(typeDefs);
  };

  addDirectives = directives => {
    Object.assign(this.directives, directives);
  };

  addResolvers = resolvers => {
    if (this.schema) {
      addResolveFunctionsToSchema({ schema: this.schema, resolvers });
    } else {
      merge(this.resolvers, resolvers);
    }
  };

  addResolverMiddleware = (matcher, middleware) => {
    this.resolverMiddlewares.push({
      matcher: typeof matcher === 'string' ? new RegExp(`^${matcher}$`) : matcher,
      middleware,
    });

    return this;
  };

  addLoader = (...args) => {
    this.loaders.add(...args);
  };

  addLoaders = (...args) => {
    this.loaders.multiAdd(...args);
  };

  addTypeDefsByPath = async filePath => {
    this.addTypeDefs(await fse.readFile(filePath, 'utf8'));
  };

  importSchema = schemaPath => {
    this.addTypeDefs(importSchema(schemaPath));
  };

  loadFromDir = async dirPath => {
    try {
      const stats = await fse.stat(dirPath);
      const isDirectory = stats && stats.isDirectory();
      if (!isDirectory) {
        return;
      }
    } catch (err) {
      return;
    }

    try {
      // try to load /graphql/typeDefs/**/*.graphl
      const typeDefsDirPath = path.join(dirPath, 'typeDefs');
      const stats = await fse.stat(typeDefsDirPath);
      if (stats.isDirectory()) {
        await new Promise((resolve, reject) => {
          glob(path.resolve(typeDefsDirPath, '**/*.graphql'), { nodir: true }, (err, filePaths) => {
            if (err) {
              return reject(err);
            }

            return resolve(
              Promise.all(filePaths.map(filePath => this.addTypeDefsByPath(filePath))),
            );
          });
        });
      }
    } catch {
      // try to load /graphql/typeDefs.graphl
      try {
        await this.addTypeDefsByPath(path.join(dirPath, 'typeDefs.graphql'));
      } catch {}
    }

    try {
      const resolvers = require(`${dirPath}/resolvers`);
      if (resolvers.default) {
        Object.assign(resolvers, resolvers.default);
        delete resolvers.default;
      }
      this.addResolvers(resolvers);
    } catch (err) {
      const resolvers = await new Promise((resolve, reject) => {
        glob(path.resolve(`${dirPath}/resolvers`, '**/*.js'), (globErr, resolversPath) => {
          if (globErr) {
            reject(err);
          } else {
            resolve(
              resolversPath.reduce((acc, resolverPath) => {
                const resolverName = path
                  .relative(`${dirPath}/resolvers`, resolverPath)
                  .slice(0, -3)
                  .split(path.sep)
                  .join('.');

                set(acc, resolverName, require(resolverPath).default);

                return acc;
              }, {}),
            );
          }
        });
      });

      this.addResolvers(resolvers);
    }

    try {
      const directives = require(`${dirPath}/directives`);
      if (directives.default) {
        Object.assign(directives, directives.default);
        delete directives.default;
      }
      this.addDirectives(directives);
    } catch (err) {}
  };

  collectFromModule = async module => {
    if (!module.getConfig('graphql.autoload', true)) {
      return;
    }

    try {
      if (has(module, 'graphql')) {
        this.addTypeDefs(get(module, 'graphql.typeDefs', ''));
        this.addResolvers(get(module, 'graphql.resolvers', {}));
        if (has(module, 'graphql.typeDefsPath')) {
          await this.addTypeDefsByPath(get(module, 'graphql.typeDefsPath'));
        }
      } else {
        await this.loadFromDir(path.resolve(path.dirname(module.filePath), 'graphql'));
      }
    } catch (err) {}
  };

  buildSchema = async () => {
    const schema = makeExecutableSchema(
      this.getConfig('configureSchema', identity)({
        typeDefs: this.typeDefs,
        resolvers: this.applyResolversMiddlewares(this.resolvers),
        logger: {
          log: err => {
            this.emit('error', err);
          },
        },
        allowUndefinedInResolve: false,
        inheritResolversFromInterfaces: true,
        schemaDirectives: this.directives,
      }),
    );

    const schemas = (await this.runHook('getSchema', () => {}, {
      schema,
      mergeSchemas,
      makeExecutableSchema,
      makeRemoteExecutableSchema,
    })).filter(s => s);

    return schemas.length
      ? mergeSchemas({
          schemas: [schema, ...schemas],
        })
      : schema;
  };

  buildServer = (options = {}) => {
    const config = {
      context: this.buildContext,
      formatError: this.format('error'),
      formatParams: this.format('params'),
      formatResponse: this.format('response'),
      schema: this.schema,
      debug: true,
      tracing: true,
      cacheControl: true,
      subscriptions: true,
      introspection: true,
      mocks: false,
      persistedQueries: true,
      validationRules: [
        depthLimit(
          this.getConfig('depthLimit.limit'),
          this.getConfig('depthLimit.options'),
          this.getConfig('depthLimit.callback'),
        ),
        // costAnalysis(this.getConfig('costAnalysis')),
      ],
      costAnalysisConfig: this.getConfig('costAnalysis'),
      ...this.getConfig('serverOptions'),
      ...options,
    };

    const server = new Server(config);

    if (config.subscriptions) {
      server.installSubscriptionHandlers(this.app.server);
    }

    return server;
  };

  buildContext = ({ req, connection } = {}) => {
    const context = {
      ...this.gqlContext,
      loaders: this.loaders.build(),
      execute: (source, options = {}) =>
        this.execute(source, {
          ...options,
          context: () => ({
            ...context,
            ...(options.context || {}),
          }),
        }),
    };

    if (req) {
      Object.assign(context, {
        ...this.contextExtenders.reduce(
          (acc, extender) => ({
            ...acc,
            ...(typeof extender === 'function'
              ? extender({ req, connection }, this.context)
              : extender),
          }),
          {},
        ),
        req,
        user: req.user,
      });
    } else if (connection) {
      Object.assign(context, {
        connection,
      });
    }

    return context;
  };

  applyResolversMiddlewares(resolvers) {
    if (!this.resolverMiddlewares.length) {
      return resolvers;
    }

    return Object.keys(resolvers).reduce(
      (resolversAcc, type) => ({
        ...resolversAcc,
        [type]: Object.keys(resolvers[type]).reduce((typeAcc, field) => {
          let resolver = resolvers[type][field];
          const branch = `${type}.${field}`;
          const middlewares = this.resolverMiddlewares.filter(({ matcher }) =>
            matcher.test(branch),
          );

          if (middlewares.length) {
            resolver = [...middlewares]
              .reverse()
              .reduce((acc, { middleware }) => (...args) => middleware(...args, acc), resolver);
          }

          return {
            ...typeAcc,
            [field]: resolver,
          };
        }, {}),
      }),
      {},
    );
  }

  execute = (source, options = {}) => {
    const { root, context, variables, operation } = {
      root: undefined,
      variables: {},
      operation: undefined,
      ...options,
      context:
        typeof options.context === 'function'
          ? options.context(this.buildContext)
          : {
              ...this.buildContext(),
              ...(options.context || {}),
            },
    };

    return graphql(this.schema, source, root, context, variables, operation);
  };

  applyMiddlewares(server) {
    this.app.middlewares.insertBefore(
      this.getConfig('middlewarePivot'),
      this.getApolloServerMiddlewares(server),
      this.getVoyagerMiddleware(),
    );
  }

  // eslint-disable-next-line class-methods-use-this
  getApolloServerMiddlewares(server) {
    return {
      id: 'apolloServer',
      apply: ({ app }) => {
        server.applyMiddleware({
          app,
          cors: false,
          bodyParserConfig: false,
          onHealthCheck: req => this.asyncEmit('healthCheck', req),
        });
      },
    };
  }

  getVoyagerMiddleware() {
    return {
      id: 'voyager',
      path: '/voyager',
      factory: ({ endpointURL }) => voyagerMiddleware({ endpointUrl: endpointURL }),
      params: this.getConfig('voyager.params'),
      enabled: this.getConfig('voyager.enabled'),
    };
  }

  format = type => {
    invariant(Array.isArray(this.formatters[type]), `Unknown formatter type - ${type}!`);
    return arg => this.formatters[type].reduce((acc, formatter) => formatter(acc), arg);
  };
}

export { Gql as default, decorators };
export { default as Resolvers } from './libs/Resolvers';
<commit_msg>[oors-graphql] improved context builder<commit_after>/* eslint-disable no-empty, import/no-dynamic-require, global-require */
import { graphql } from 'graphql';
import glob from 'glob';
import path from 'path';
import fse from 'fs-extra';
import get from 'lodash/get';
import set from 'lodash/set';
import has from 'lodash/has';
import pick from 'lodash/pick';
import isPlainObject from 'lodash/isPlainObject';
import invariant from 'invariant';
import identity from 'lodash/identity';
import { Module } from 'oors';
import { PubSub } from 'graphql-subscriptions';
import merge from 'lodash/merge';
import {
  makeExecutableSchema,
  makeRemoteExecutableSchema,
  mergeSchemas,
  addResolveFunctionsToSchema,
  addSchemaLevelResolveFunction,
  attachDirectiveResolvers,
} from 'graphql-tools';
import { express as voyagerMiddleware } from 'graphql-voyager/middleware';
import { importSchema } from 'graphql-import';
import { Binding } from 'graphql-binding';
import Ajv from 'ajv';
import ajvKeywords from 'ajv-keywords';
import ConstraintDirective from 'graphql-constraint-directive';
import depthLimit from 'graphql-depth-limit';
import mainResolvers from './graphql/resolvers';
import modulesResolvers from './graphql/modulesResolvers';
import LoadersMap from './libs/LoadersMap';
import * as decorators from './decorators';
import Server from './libs/Server';

class Gql extends Module {
  static schema = {
    type: 'object',
    properties: {
      voyager: {
        type: 'object',
        properties: {
          enabled: {
            type: 'boolean',
            default: true,
          },
          params: {
            type: 'object',
            properties: {
              endpointURL: {
                type: 'string',
                default: '/graphql',
              },
            },
            default: {},
          },
        },
        default: {},
      },
      middlewarePivot: {
        type: 'string',
        default: 'isMethod',
      },
      configureSchema: {
        instanceof: 'Function',
      },
      exposeModules: {
        type: 'boolean',
        default: true,
      },
      serverOptions: {
        type: 'object',
        default: {},
      },
      pubsub: {
        type: 'object',
      },
      depthLimit: {
        type: 'object',
        properties: {
          limit: {
            type: 'integer',
            default: 10,
          },
          options: {
            type: 'object',
            properties: {
              ignore: {
                type: 'array',
                default: [],
              },
            },
          },
          callback: {
            instanceof: 'Function',
          },
        },
        default: {},
      },
      costAnalysis: {
        type: 'object',
        properties: {
          maximumCost: {
            type: 'integer',
            default: 1000,
          },
        },
        default: {},
      },
    },
  };

  name = 'oors.graphql';

  initialize() {
    this.ajv = new Ajv({
      allErrors: true,
      verbose: true,
      async: 'es7',
      useDefaults: true,
    });
    ajvKeywords(this.ajv, 'instanceof');

    this.typeDefs = [];
    this.directives = {
      constraint: ConstraintDirective,
    };
    this.resolvers = mainResolvers;
    this.resolverMiddlewares = [];
    this.pubsub = this.getConfig('pubsub', new PubSub());
    this.gqlContext = {
      pubsub: this.pubsub,
      ajv: this.ajv,
      app: this.app,
    };
    this.loaders = new LoadersMap();
    this.contextExtenders = [];
    this.formatters = {
      params: [],
      error: [],
      response: [],
    };
  }

  async setup() {
    await this.runHook(
      'load',
      this.collectFromModule,
      pick(this, [
        'pubsub',
        'addTypeDefs',
        'addDirectives',
        'addTypeDefsByPath',
        'addResolvers',
        'addResolverMiddleware',
        'addLoader',
        'loadFromDir',
      ]),
    );

    if (this.getConfig('exposeModules')) {
      this.addResolvers(modulesResolvers);
      await this.addTypeDefsByPath(path.resolve(__dirname, './graphql/modulesTypeDefs.graphql'));
    }

    await this.runHook('buildContext', () => {}, {
      context: this.gqlContext,
    });

    this.schema = await this.buildSchema();
    this.server = this.buildServer();

    this.applyMiddlewares(this.server);

    const binding = this.bindSchema(this.schema);

    this.exportProperties([
      'extendContext',
      'schema',
      'server',
      'loaders',
      'addResolverMiddleware',
      'addLoader',
      'addLoaders',
      'addResolvers',
      'importSchema',
      'bindSchema',
      'binding',
      'setupListen',
      'pubsub',
      'formatters',
      'buildContext',
      'execute',
    ]);

    this.export({
      context: this.gqlContext,
      addSchemaResolvers: rootResolveFunction =>
        addSchemaLevelResolveFunction(this.schema, rootResolveFunction),
      addDirectivesResolvers: directivesResolvers =>
        attachDirectiveResolvers(this.schema, directivesResolvers),
    });

    this.on('after:setup', () => {
      Object.assign(this.gqlContext, {
        binding,
      });
    });
  }

  extendContext = extender => {
    invariant(
      typeof extender === 'function' || isPlainObject(extender),
      `Invalid context extender! Needs to be either a function or a an object that will get
      assigned to the context.`,
    );
    this.contextExtenders.push(extender);
    return this.contextExtenders;
  };

  bindSchema = (schema, options = {}) =>
    new Binding({
      schema,
      ...options,
    });

  addTypeDefs = typeDefs => {
    this.typeDefs.push(typeDefs);
  };

  addDirectives = directives => {
    Object.assign(this.directives, directives);
  };

  addResolvers = resolvers => {
    if (this.schema) {
      addResolveFunctionsToSchema({ schema: this.schema, resolvers });
    } else {
      merge(this.resolvers, resolvers);
    }
  };

  addResolverMiddleware = (matcher, middleware) => {
    this.resolverMiddlewares.push({
      matcher: typeof matcher === 'string' ? new RegExp(`^${matcher}$`) : matcher,
      middleware,
    });

    return this;
  };

  addLoader = (...args) => {
    this.loaders.add(...args);
  };

  addLoaders = (...args) => {
    this.loaders.multiAdd(...args);
  };

  addTypeDefsByPath = async filePath => {
    this.addTypeDefs(await fse.readFile(filePath, 'utf8'));
  };

  importSchema = schemaPath => {
    this.addTypeDefs(importSchema(schemaPath));
  };

  loadFromDir = async dirPath => {
    try {
      const stats = await fse.stat(dirPath);
      const isDirectory = stats && stats.isDirectory();
      if (!isDirectory) {
        return;
      }
    } catch (err) {
      return;
    }

    try {
      // try to load /graphql/typeDefs/**/*.graphl
      const typeDefsDirPath = path.join(dirPath, 'typeDefs');
      const stats = await fse.stat(typeDefsDirPath);
      if (stats.isDirectory()) {
        await new Promise((resolve, reject) => {
          glob(path.resolve(typeDefsDirPath, '**/*.graphql'), { nodir: true }, (err, filePaths) => {
            if (err) {
              return reject(err);
            }

            return resolve(
              Promise.all(filePaths.map(filePath => this.addTypeDefsByPath(filePath))),
            );
          });
        });
      }
    } catch {
      // try to load /graphql/typeDefs.graphl
      try {
        await this.addTypeDefsByPath(path.join(dirPath, 'typeDefs.graphql'));
      } catch {}
    }

    try {
      const resolvers = require(`${dirPath}/resolvers`);
      if (resolvers.default) {
        Object.assign(resolvers, resolvers.default);
        delete resolvers.default;
      }
      this.addResolvers(resolvers);
    } catch (err) {
      const resolvers = await new Promise((resolve, reject) => {
        glob(path.resolve(`${dirPath}/resolvers`, '**/*.js'), (globErr, resolversPath) => {
          if (globErr) {
            reject(err);
          } else {
            resolve(
              resolversPath.reduce((acc, resolverPath) => {
                const resolverName = path
                  .relative(`${dirPath}/resolvers`, resolverPath)
                  .slice(0, -3)
                  .split(path.sep)
                  .join('.');

                set(acc, resolverName, require(resolverPath).default);

                return acc;
              }, {}),
            );
          }
        });
      });

      this.addResolvers(resolvers);
    }

    try {
      const directives = require(`${dirPath}/directives`);
      if (directives.default) {
        Object.assign(directives, directives.default);
        delete directives.default;
      }
      this.addDirectives(directives);
    } catch (err) {}
  };

  collectFromModule = async module => {
    if (!module.getConfig('graphql.autoload', true)) {
      return;
    }

    try {
      if (has(module, 'graphql')) {
        this.addTypeDefs(get(module, 'graphql.typeDefs', ''));
        this.addResolvers(get(module, 'graphql.resolvers', {}));
        if (has(module, 'graphql.typeDefsPath')) {
          await this.addTypeDefsByPath(get(module, 'graphql.typeDefsPath'));
        }
      } else {
        await this.loadFromDir(path.resolve(path.dirname(module.filePath), 'graphql'));
      }
    } catch (err) {}
  };

  buildSchema = async () => {
    const schema = makeExecutableSchema(
      this.getConfig('configureSchema', identity)({
        typeDefs: this.typeDefs,
        resolvers: this.applyResolversMiddlewares(this.resolvers),
        logger: {
          log: err => {
            this.emit('error', err);
          },
        },
        allowUndefinedInResolve: false,
        inheritResolversFromInterfaces: true,
        schemaDirectives: this.directives,
      }),
    );

    const schemas = (await this.runHook('getSchema', () => {}, {
      schema,
      mergeSchemas,
      makeExecutableSchema,
      makeRemoteExecutableSchema,
    })).filter(s => s);

    return schemas.length
      ? mergeSchemas({
          schemas: [schema, ...schemas],
        })
      : schema;
  };

  buildServer = (options = {}) => {
    const config = {
      context: this.buildContext,
      formatError: this.format('error'),
      formatParams: this.format('params'),
      formatResponse: this.format('response'),
      schema: this.schema,
      debug: true,
      tracing: true,
      cacheControl: true,
      subscriptions: true,
      introspection: true,
      mocks: false,
      persistedQueries: true,
      validationRules: [
        depthLimit(
          this.getConfig('depthLimit.limit'),
          this.getConfig('depthLimit.options'),
          this.getConfig('depthLimit.callback'),
        ),
        // costAnalysis(this.getConfig('costAnalysis')),
      ],
      costAnalysisConfig: this.getConfig('costAnalysis'),
      ...this.getConfig('serverOptions'),
      ...options,
    };

    const server = new Server(config);

    if (config.subscriptions) {
      server.installSubscriptionHandlers(this.app.server);
    }

    return server;
  };

  buildContext = ({ req, connection } = {}) => {
    const context = {
      ...this.gqlContext,
      loaders: this.loaders.build(),
      req,
      connection,
      ...(req
        ? {
            user: req.user,
          }
        : {}),
    };

    this.contextExtenders.forEach(extender => extender(context));

    context.execute = (source, options = {}) =>
      this.execute(source, {
        ...options,
        context: () => ({
          ...context,
          ...(options.context || {}),
        }),
      });

    return context;
  };

  applyResolversMiddlewares(resolvers) {
    if (!this.resolverMiddlewares.length) {
      return resolvers;
    }

    return Object.keys(resolvers).reduce(
      (resolversAcc, type) => ({
        ...resolversAcc,
        [type]: Object.keys(resolvers[type]).reduce((typeAcc, field) => {
          let resolver = resolvers[type][field];
          const branch = `${type}.${field}`;
          const middlewares = this.resolverMiddlewares.filter(({ matcher }) =>
            matcher.test(branch),
          );

          if (middlewares.length) {
            resolver = [...middlewares]
              .reverse()
              .reduce((acc, { middleware }) => (...args) => middleware(...args, acc), resolver);
          }

          return {
            ...typeAcc,
            [field]: resolver,
          };
        }, {}),
      }),
      {},
    );
  }

  execute = (source, options = {}) => {
    const { root, context, variables, operation } = {
      root: undefined,
      variables: {},
      operation: undefined,
      ...options,
      context:
        typeof options.context === 'function'
          ? options.context(this.buildContext)
          : {
              ...this.buildContext(),
              ...(options.context || {}),
            },
    };

    return graphql(this.schema, source, root, context, variables, operation);
  };

  applyMiddlewares(server) {
    this.app.middlewares.insertBefore(
      this.getConfig('middlewarePivot'),
      this.getApolloServerMiddlewares(server),
      this.getVoyagerMiddleware(),
    );
  }

  // eslint-disable-next-line class-methods-use-this
  getApolloServerMiddlewares(server) {
    return {
      id: 'apolloServer',
      apply: ({ app }) => {
        server.applyMiddleware({
          app,
          cors: false,
          bodyParserConfig: false,
          onHealthCheck: req => this.asyncEmit('healthCheck', req),
        });
      },
    };
  }

  getVoyagerMiddleware() {
    return {
      id: 'voyager',
      path: '/voyager',
      factory: ({ endpointURL }) => voyagerMiddleware({ endpointUrl: endpointURL }),
      params: this.getConfig('voyager.params'),
      enabled: this.getConfig('voyager.enabled'),
    };
  }

  format = type => {
    invariant(Array.isArray(this.formatters[type]), `Unknown formatter type - ${type}!`);
    return arg => this.formatters[type].reduce((acc, formatter) => formatter(acc), arg);
  };
}

export { Gql as default, decorators };
export { default as Resolvers } from './libs/Resolvers';
<|endoftext|>


<commit_before>export default function stylesheet(props, themeData) {
  const { variant } = props;
  return {
    label: {
      fontSize:
        variant === "side"
          ? themeData["label.fontSize"]
          : themeData["label.top.fontSize"],
      fontFamily: themeData["label.fontFamily"],
      fontWeight: themeData["label.fontWeight"],
      lineHeight: themeData["label.lineHeight"],
      color: themeData["label.fontColor"],
      opacity: props.disabled ? themeData["component.disabled.opacity"] : "1.0"
    }
  };
}
<commit_msg>fix: stop using deprecated theme-data-roles<commit_after>export default function stylesheet(props, themeData) {
  const { variant } = props;
  return {
    label: {
      fontSize:
        variant === "side"
          ? themeData["label.fontSize"]
          : themeData["label.top.fontSize"],
      fontFamily: themeData["label.fontFamily"],
      fontWeight: themeData["label.fontWeight"],
      lineHeight: themeData["label.lineHeight"],
      color: themeData["label.fontColor"],
      opacity: props.disabled
        ? themeData["colorScheme.opacity.disabled"]
        : "1.0"
    }
  };
}
<|endoftext|>


<commit_before>'use strict';

import * as _ from 'lodash'
import * as React from 'react'
import * as humanize from 'humanize-plus'

import add from '../helpers/add'
import randomChar from '../helpers/randomChar'

let goodGraduationMessage = 'It looks like you\'ll make it! Just follow the plan, and go over my output with your advisor a few times.'
let badGraduationMessage = 'You haven\'t planned everything out yet. Ask your advisor if you need help fitting everything in.'

var StudentSummary = React.createClass({
	render() {
		var student = this.props.student
		var studies = student.studies
		var name = student.name || randomChar()
		var has = _.mapValues(_.groupBy(studies, 'type'), _.size)

		let objects = {
			degree: _.filter(studies, {type: 'degree'}),
			major: _.filter(studies, {type: 'major'}),
			concentration: _.filter(studies, {type: 'concentration'}),
			emphasis: _.filter(studies, {type: 'emphasis'}),
		}

		let titles = {
			degree: humanize.oxford(_.pluck(objects.degree, 'title')),
			major: humanize.oxford(_.pluck(objects.major, 'title')),
			concentration: humanize.oxford(_.pluck(objects.concentration, 'title')),
			emphasis: humanize.oxford(_.pluck(objects.emphasis, 'title')),
		}

		let words = {
			degree: humanize.pluralize(_.size(objects.degree), 'degree'),
			major: humanize.pluralize(_.size(objects.major), 'major'),
			concentration: humanize.pluralize(_.size(objects.concentration), 'concentration'),
			emphasis: humanize.pluralize(_.size(objects.emphasis), 'emphasis', 'emphases'),
		}

		// var canGraduate = checkElegibilityForGraduation(this.props)
		var canGraduate = false

		let phrases = {
			degree: React.DOM.span({className: 'area-of-study-list', key:'degree'}, titles.degree),
			major: React.DOM.span({className: 'area-of-study-list', key:'major'}, titles.major),
			concentration: React.DOM.span({className: 'area-of-study-list', key:'concentration'}, titles.concentration),
			emphasis: React.DOM.span({className: 'area-of-study-list', key:'emphasis'}, titles.emphasis),
		}

		var emphasisEmphasizer = has.emphasis > 0 && has.emphasis < 2 ? 'an ' : ''

		return React.DOM.article({id: 'student-summary', className: canGraduate ? 'can-graduate' : 'cannot-graduate'},
			React.DOM.div({key: 'letter', id: 'student-letter'}, name[0]),
			React.DOM.p({key: 'hi'}, 'Hi, ', name, '!'),
			React.DOM.p({key: 'overview'},
				'You are planning on ', _.size(objects.degree === 1) ? 'a ' : '', phrases.degree,
				' ', words.degree, ', with ', words.major, ' in ', phrases.major,
				has.concentration > 0 ? [', and ', words.concentration, ' in ', phrases.concentration] : '',
				has.emphasis > 0 ? [', not to mention ', emphasisEmphasizer, words.emphasis, ' in ', phrases.emphasis] : '',
				'.'),
			React.DOM.p({key: 'message', className: 'graduation-message'},
				canGraduate ? goodGraduationMessage : badGraduationMessage)
		)
	}
})

export default StudentSummary
<commit_msg>Reindent a bit of studentSummary<commit_after>'use strict';

import * as _ from 'lodash'
import * as React from 'react'
import * as humanize from 'humanize-plus'

import add from '../helpers/add'
import randomChar from '../helpers/randomChar'

let goodGraduationMessage = 'It looks like you\'ll make it! Just follow the plan, and go over my output with your advisor a few times.'
let badGraduationMessage = 'You haven\'t planned everything out yet. Ask your advisor if you need help fitting everything in.'

var StudentSummary = React.createClass({
	render() {
		var student = this.props.student
		var studies = student.studies
		var name = student.name || randomChar()
		var has = _.mapValues(_.groupBy(studies, 'type'), _.size)

		let objects = {
			degree: _.filter(studies, {type: 'degree'}),
			major: _.filter(studies, {type: 'major'}),
			concentration: _.filter(studies, {type: 'concentration'}),
			emphasis: _.filter(studies, {type: 'emphasis'}),
		}

		let titles = {
			degree: humanize.oxford(_.pluck(objects.degree, 'title')),
			major: humanize.oxford(_.pluck(objects.major, 'title')),
			concentration: humanize.oxford(_.pluck(objects.concentration, 'title')),
			emphasis: humanize.oxford(_.pluck(objects.emphasis, 'title')),
		}

		let words = {
			degree: humanize.pluralize(_.size(objects.degree), 'degree'),
			major: humanize.pluralize(_.size(objects.major), 'major'),
			concentration: humanize.pluralize(_.size(objects.concentration), 'concentration'),
			emphasis: humanize.pluralize(_.size(objects.emphasis), 'emphasis', 'emphases'),
		}

		// var canGraduate = checkElegibilityForGraduation(this.props)
		var canGraduate = false

		let phrases = {
			degree: React.DOM.span({className: 'area-of-study-list', key:'degree'}, titles.degree),
			major: React.DOM.span({className: 'area-of-study-list', key:'major'}, titles.major),
			concentration: React.DOM.span({className: 'area-of-study-list', key:'concentration'}, titles.concentration),
			emphasis: React.DOM.span({className: 'area-of-study-list', key:'emphasis'}, titles.emphasis),
		}

		var emphasisEmphasizer = has.emphasis > 0 && has.emphasis < 2 ? 'an ' : ''

		return React.DOM.article({id: 'student-summary', className: canGraduate ? 'can-graduate' : 'cannot-graduate'},
			React.DOM.div({key: 'letter', id: 'student-letter'}, name[0]),
			React.DOM.p({key: 'hi'}, 'Hi, ', name, '!'),
			React.DOM.p({key: 'overview'},
				'You are planning on ', _.size(objects.degree === 1) ? 'a ' : '',
				phrases.degree, ' ', words.degree, ', with ', words.major, ' in ', phrases.major,
				has.concentration > 0 ? [', and ', words.concentration, ' in ', phrases.concentration] : '',
				has.emphasis > 0 ? [', not to mention ', emphasisEmphasizer, words.emphasis, ' in ', phrases.emphasis] : '',
				'.'),
			React.DOM.p({key: 'message', className: 'graduation-message'},
				canGraduate ? goodGraduationMessage : badGraduationMessage)
		)
	}
})

export default StudentSummary
<|endoftext|>


<commit_before>// import

import React, {Component, PropTypes} from 'react';
import styles from './JobsList.css';
import cn from 'classnames';
import _ from 'lodash';
import {orderJobsBy, getJobType, getJobNiceInterval} from '../JobsHelper/JobsHelper.js';
import {routeJobUpdate} from '../RouterStore/RouterStore.js';
import {connect} from 'react-redux';

// export

@connect((state) => {
  return {
    useLocalTime: state.localStorage.useLocalTime === 'true',
  };
})
export default class JobsList extends Component {
  static propTypes = {
    className: PropTypes.string,
    jobs: PropTypes.array,
    useLocalTime: PropTypes.bool.isRequired,
  };

  state = {
    orderBy: 'name',
    orderDir: 'asc',
  };

  className() {
    return cn(styles.JobsList, this.props.className);
  }

  cellClassName(field, head = false) {
    const headClass = head && this.state.orderBy === field && {
      [styles.orderBy]: true,
      [styles.orderAsc]: this.state.orderDir === 'asc',
      [styles.orderDesc]: this.state.orderDir === 'desc',
    };

    return cn(styles.cell, styles['cell' + _.capitalize(field)], headClass);
  }

  changeOrder(orderBy) {
    return () => {
      this.setState({
        orderBy,
        orderDir: this.state.orderBy !== orderBy ? 'asc' : this.state.orderDir === 'asc' ? 'desc' : 'asc',
      });
    };
  }

  viewJobs(job) {
    return () => {
      routeJobUpdate(job);
    };
  }

  render() {
    const {jobs, useLocalTime} = this.props;
    const {orderBy, orderDir} = this.state;

    return (

              Job

              Run Interval

          {_.orderBy(jobs || [], orderJobsBy[orderBy], orderDir)
            .map((job, i) => {
              return (

                    {job.enabled &&
}

                    {job.name}

                    {getJobNiceInterval(job.cronString, useLocalTime).toLowerCase()}

              );
            })}

    );
  }
}
<commit_msg>dependent jobs ready<commit_after>// import

import React, {Component, PropTypes} from 'react';
import styles from './JobsList.css';
import cn from 'classnames';
import _ from 'lodash';
import {orderJobsBy, getJobType, getJobNiceInterval} from '../JobsHelper/JobsHelper.js';
import {routeJobUpdate} from '../RouterStore/RouterStore.js';
import {connect} from 'react-redux';

// export

@connect((state) => {
  return {
    useLocalTime: state.localStorage.useLocalTime === 'true',
  };
})
export default class JobsList extends Component {
  static propTypes = {
    className: PropTypes.string,
    jobs: PropTypes.array,
    useLocalTime: PropTypes.bool.isRequired,
  };

  state = {
    orderBy: 'name',
    orderDir: 'asc',
  };

  className() {
    return cn(styles.JobsList, this.props.className);
  }

  cellClassName(field, head = false) {
    const headClass = head && this.state.orderBy === field && {
      [styles.orderBy]: true,
      [styles.orderAsc]: this.state.orderDir === 'asc',
      [styles.orderDesc]: this.state.orderDir === 'desc',
    };

    return cn(styles.cell, styles['cell' + _.capitalize(field)], headClass);
  }

  changeOrder(orderBy) {
    return () => {
      this.setState({
        orderBy,
        orderDir: this.state.orderBy !== orderBy ? 'asc' : this.state.orderDir === 'asc' ? 'desc' : 'asc',
      });
    };
  }

  viewJobs(job) {
    return () => {
      routeJobUpdate(job);
    };
  }

  render() {
    const {jobs, useLocalTime} = this.props;
    const {orderBy, orderDir} = this.state;

    return (

              Job

              Run Interval

          {_.orderBy(jobs || [], orderJobsBy[orderBy], orderDir)
            .map((job, i) => {
              return (

                    {job.enabled &&
}

                    {job.name}

                    {getJobNiceInterval(job.cronString, useLocalTime).toLowerCase()}

              );
            })}

    );
  }
}
<|endoftext|>


<commit_before>const path = require('path'),
    webpack = require('webpack'),
    HtmlWebpackPlugin = require('html-webpack-plugin'),
    ProgressBarPlugin = require('progress-bar-webpack-plugin')

module.exports = {
    devtool: 'eval-source-map',
    context: path.resolve(__dirname, '..'),
    entry: {
        bundle: [
            './client',
            'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000'
        ],
        vendor: [
            'react',
            'react-dom',
            'redux',
            'react-redux',
            'superagent'
        ]
    },
    output: {
        path: path.resolve(__dirname, '../dist/client'),
        filename: '[name].js',
        chunkFilename: 'chunk.[name].js',
        publicPath: '/'
    },
    module: {
        loaders: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel',
            query: {
                presets: ['es2015', 'react', 'stage-0', 'react-hmre'],
                plugins: ['transform-runtime', 'add-module-exports']
            }
        }, {
            test: /\.scss$/,
            loaders: [
                'style',
                'css?modules&camelCase&importLoaders=1&localIdentName=[name]__[local]__[hash:base64:8]',
                'sass'
            ]
        }, {
            test: /\.(jpg|png|gif|webp)$/,
            loader: 'url?limit=8000'
        }, {
            test: /\.json$/,
            loader: 'json'
        }, {
            test: /\.html$/,
            loader: 'html?minimize=false'
        }]
    },
    resolve: {extensions: ['', '.js', '.json', '.scss']},
    plugins: [
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.optimize.DedupePlugin(),
        new webpack.optimize.CommonsChunkPlugin({
            names: ['vendor', 'manifest'],
            filename: '[name].js'
        }),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin(),
        new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)}),
        new HtmlWebpackPlugin({
            filename: '../views/dev/index.html',
            template: './views/tpl/index.tpl.html'
        }),
        new ProgressBarPlugin({summary: false})
    ]
}
<commit_msg>Emergency Fix: don't use webpack DedupePlugin in dev mode for causing HMR failed when using different React UI framework<commit_after>const path = require('path'),
    webpack = require('webpack'),
    HtmlWebpackPlugin = require('html-webpack-plugin'),
    ProgressBarPlugin = require('progress-bar-webpack-plugin')

module.exports = {
    devtool: 'eval-source-map',
    context: path.resolve(__dirname, '..'),
    entry: {
        bundle: [
            './client',
            'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000'
        ],
        vendor: [
            'react',
            'react-dom',
            'redux',
            'react-redux',
            'superagent'
        ]
    },
    output: {
        path: path.resolve(__dirname, '../dist/client'),
        filename: '[name].js',
        chunkFilename: 'chunk.[name].js',
        publicPath: '/'
    },
    module: {
        loaders: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel',
            query: {
                presets: ['es2015', 'react', 'stage-0', 'react-hmre'],
                plugins: ['transform-runtime', 'add-module-exports']
            }
        }, {
            test: /\.scss$/,
            loaders: [
                'style',
                'css?modules&camelCase&importLoaders=1&localIdentName=[name]__[local]__[hash:base64:8]',
                'sass'
            ]
        }, {
            test: /\.(jpg|png|gif|webp)$/,
            loader: 'url?limit=8000'
        }, {
            test: /\.json$/,
            loader: 'json'
        }, {
            test: /\.html$/,
            loader: 'html?minimize=false'
        }]
    },
    resolve: {extensions: ['', '.js', '.json', '.scss']},
    plugins: [
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.optimize.CommonsChunkPlugin({
            names: ['vendor', 'manifest'],
            filename: '[name].js'
        }),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin(),
        new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)}),
        new HtmlWebpackPlugin({
            filename: '../views/dev/index.html',
            template: './views/tpl/index.tpl.html'
        }),
        new ProgressBarPlugin({summary: false})
    ]
}
<|endoftext|>


<commit_before><commit_msg>Deleted multi-initializations<commit_after><|endoftext|>


<commit_before>var assert = require('assert');
var path = require('path');
var exec = require('child_process').execFile;
var cmd = path.join(__dirname, "..", "live-server.js");
var opts = {
	timeout: 1000,
	maxBuffer: 1024
};

describe('command line usage', function() {
	it('--version', function(done) {
		exec(cmd, [ "--version" ], opts, function(error, stdout, stdin) {
			assert(!error, error);
			assert(stdout.indexOf("live-server") == 0);
			done();
		});
	});
	it('--help', function(done) {
		exec(cmd, [ "--help" ], opts, function(error, stdout, stdin) {
			assert(!error, error);
			assert(stdout.indexOf("Usage: live-server") == 0);
			done();
		});
	});
});
<commit_msg>Test for --quiet.<commit_after>var assert = require('assert');
var path = require('path');
var exec = require('child_process').execFile;
var cmd = path.join(__dirname, "..", "live-server.js");
var opts = {
	timeout: 2000,
	maxBuffer: 1024
};

describe('command line usage', function() {
	it('--version', function(done) {
		exec(cmd, [ "--version" ], opts, function(error, stdout, stdin) {
			assert(!error, error);
			assert(stdout.indexOf("live-server") == 0, "version not found");
			done();
		});
	});
	it('--help', function(done) {
		exec(cmd, [ "--help" ], opts, function(error, stdout, stdin) {
			assert(!error, error);
			assert(stdout.indexOf("Usage: live-server") == 0, "usage not found");
			done();
		});
	});
	it('--quiet', function(done) {
		exec(cmd, [ "--quiet", "--no-browser", "--test" ], opts, function(error, stdout, stdin) {
			assert(!error, error);
			assert(stdout === "", "stdout not empty");
			done();
		});
	});
});
<|endoftext|>


<commit_before>/*global module,require*/
var connect = require('connect'),
    connectLivereload = require('connect-livereload'),
    serveStatic = require('serve-static'),
    http = require('http'),
    open = require('open'),
    _ = require('lodash'),
    yaml = require('js-yaml'),
    packageJson = require('./package.json'),
    path = require('path');

function correctBaseUrl(_baseurl) {
  if (_baseurl.length) {
    if (_baseurl.substr(0, 1) !== '/') {
      // add leading slash
      _baseurl = '/' + _baseurl;
    }
    if (_baseurl.substr(-1, 1) === '/') {
      // remove trailing slash
      _baseurl = _baseurl.slice(0, -1);
    }
  }
  return _baseurl;
}

module.exports = function (grunt) {
  // load all grunt tasks
  require('matchdep').filterDev(['grunt-*', '!grunt-cli']).forEach(grunt.loadNpmTasks);

  var config = {
    site: '_site',
    build: '_build',
    source: 'source',
    defaultTarget: 'staging',
    baseurl: correctBaseUrl(grunt.option('baseurl') || '/v3')
  };

  grunt.initConfig({
    clean: {
      build: '<%= config.build %>',
      site: '<%= config.site %>'
    },
    config: config,
    sync: {
      source: {
        files: [
          {
            expand: true,
            cwd: '<%= config.source %>',
            src: ['**', '!<%= config.build %>/assets/css'],
            dest: '<%= config.build %>'
          }
        ]
      },
      design: {
        files: [
          {
            expand: true,
            cwd: 'node_modules/src-design/pattern-library',
            src: ['**/design/**', '!**/documents/**'],
            dest: '<%= config.build %>/_includes/pattern-library'
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/pattern-library',
            src: ['**/design/**', '!**/documents/**', '!**/*.md'],
            dest: '<%= config.build %>/pattern-library',
            rename: function(dest, src) {
              return dest + '/' + src.replace('/design', '');
            }
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/pattern-library',
            src: ['**/site.md'],
            dest: '<%= config.build %>/pattern-library',
            rename: function(dest, src) {
              return dest + '/' + src.replace('site.md', 'index.md');
            }
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/styles',
            src: ['**/*.md'],
            dest: '<%= config.build %>/_includes/styles'
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/styles',
            src: ['**/!(*.md)'],
            dest: '<%= config.build %>/styles'
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/styles/icons',
            src: ['icons.json'],
            dest: '<%= config.build %>/_data'
          }
        ]
      },
      examples: {
        files: [
          // Copy resources from git repos
          {
            expand: true,
            cwd: 'node_modules/src-core/tests/pages/_includes/widgets',
            src: ['**'],
            dest: '<%= config.build %>/_includes/widgets'
          },
          {
            expand: true,
            cwd: 'node_modules/src-angular/dist/docs/partials',
            src: ['**'],
            dest: '<%= config.build %>/_includes/angular-partials'
          }
        ]
      },
      patternflyDist: {
        files: [
          // Copy resources from git repos
          {
            expand: true,
            cwd: 'node_modules/src-core/dist',
            src: ['**'],
            dest: '<%= config.build %>/components/patternfly/dist'
          },
          {
            expand: true,
            cwd: 'node_modules/src-angular/dist',
            src: ['**'],
            dest: '<%= config.build %>/components/angular-patternfly/dist'
          }
        ]
      }
    },
    copy: {
      components: {
        files: [
          {
            expand: true,
            cwd: 'node_modules',
            src: ['**/*'],
            filter: function(filepath) { // this filter is 5x faster as the corresponding glob
              let shouldCopy = false;
              for (let package of packageJson.workspaces.nohoist) {
                if (
                  filepath.includes(path.join('node_modules', package) &&
                  !filepath.includes(path.join('node_modules', 'src'))
                )) {
                  shouldCopy = true;
                }
              }
              if (!grunt.file.isFile(filepath) || !shouldCopy) {
                return false;
              }
              var fileparts = filepath.split('/');
              if (fileparts[2] == 'node_modules') {
                return false;
              }
              var packages = _.keys(packageJson.dependencies);
              if (fileparts[1] === 'patternfly' || fileparts[1] === 'angular-patternfly' || packages.indexOf(fileparts[1]) < 0) {
                return false;
              }
              var extensions = ['html','txt','js','coffee','css','scss','less','otf','eot','svg','ttf','woff','woff2','png','jpg','gif','ico','xml','yml','yaml','map','json','md'];
              var extparts = fileparts[fileparts.length - 1].split('.');
              return extensions.indexOf(extparts[extparts.length-1]) >= 0;
            },
            dest: '<%= config.build %>/components'
          },
        ]
      }
    },
    csscount: {
      source: {
        src: [
          '<%= config.build %>/assets/css/patternfly*.min.css'
        ],
        options: {
          maxSelectors: 4096
        }
      }
    },
    cssmin: {
      source: {
        files: [{
          expand: true,
          cwd: '<%= config.build %>/assets/css',
          src: ['patternfly*.css', '!*.min.css'],
          dest: '<%= config.build %>/assets/css',
          ext: '.min.css',
        }],
        options: {
          sourceMap: true
        }
      }
    },
    http: {
      pattern_status: {
        options: {
          url: 'https://www.patternfly.org/patternfly-design/status/pattern-status.json'
        },
        dest: '_build/_data/pattern-status.json'
      }
    },
    jekyll: {
      options: {
        dest: '<%= config.site %>',
        config: '<%= config.build %>/_config.yml',
        src: '<%= config.build %>',
        bundleExec: 'true',
        incremental: 'true'
      },
      production: {
        incremental: 'false'
      },
      staging: {
      }
    },
    less: {
      patternflySite: {
        files: {
          '<%= config.build %>/assets/css/patternfly-site.css': '<%= config.source %>/_less/patternfly-site.less'
        },
        options: {
          paths: [
            'less/',
            'node_modules/'
          ],
          sourceMap: true,
          outputSourceFiles: true,
          sourceMapFilename: '<%= config.build %>/assets/css/patternfly-site.css.map',
          sourceMapURL: 'patternfly-site.css.map'
        }
      },
      patternflySiteAdjusted: {
        files: {
          '<%= config.build %>/assets/css/patternfly-adjusted.css': '<%= config.source %>/_less/patternfly-adjusted.less'
        },
        options: {
          paths: [
            'less/',
            'node_modules/'
          ],
          sourceMap: true,
          outputSourceFiles: true,
          sourceMapFilename: '<%= config.build %>/assets/css/patternfly-adjusted.css.map',
          sourceMapURL: 'patternfly-adjusted.css.map'
        }
      }
    },
    uglify: {
      options: {
        mangle: false
      },
      production: {
        files: {
          '<%= config.build %>/assets/js/patternfly-site.min.js': ['<%= config.source %>/assets/js/patternfly-site.js']
        }
      }
    },
    watch: {
      source: {
        files: ['<%= config.source %>/**/*', '!<%= config.source %>/_less/**/*', '!<%= config.source %>/assets/js/**/*'],
        tasks: ['sync:source']
      },
      less: {
        files: ['<%= config.source %>/_less/*.less'],
        tasks: ['less', 'cssmin']
      },
      js: {
        files: ['<%= config.source %>/assets/js/*.js'],
        tasks: ['uglify']
      },
      jekyll: {
        files: ['<%= config.build %>/**/*', '!<%= config.source %>/_less/**/*'],
        tasks: ['jekyll:staging']
      },
      design: {
        files: ['node_modules/src-design/**/*'],
        tasks: ['sync:design']
      },
      examples: {
        files: ['node_modules/src-core/tests/pages/_includes/widgets',
                'node_modules/src-angular/dist/docs/partials'],
        tasks: ['sync:examples']
      },
      livereload: {
        files: ['<%= config.site %>/**/*'],
        options: {
          livereload: 35731
        }
      }
    }
  });

  grunt.registerTask('jenkins', [
    'less',
    'cssmin',
    'uglify'
  ]);

  grunt.registerTask('buildConfig', function (target) {
    if (target === 'staging') {
      var jekyllConfig = grunt.file.readYAML(`${config.source}/_config.yml`);
      jekyllConfig.baseurl = config.baseurl;
      grunt.file.write(`${config.build}/_config.yml`, yaml.safeDump(jekyllConfig));
    }
  })

  grunt.registerTask('serve', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'build:' + target,
      'connect:' + target,
      'watch'
    ]);
  });

  grunt.registerTask('prebuild', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'clean',
      // 'http:pattern_status',
      'copy:components',
      'sync:patternflyDist',
      'buildConfig:' + target,
      'sync:source',
      'sync:design',
      'sync:examples',
      'less',
      'cssmin',
      // 'csscount',
      'uglify',
    ]);
  });

  grunt.registerTask('build', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'prebuild:' + target,
      'jekyll:' + target
    ]);
  });

  grunt.registerTask('connect', function(target) {
    // Load the jekyll config
    var jekyllConfig = grunt.file.readYAML(`${config.source}/_config.yml`);
    if (target === 'staging') {
      jekyllConfig.baseurl = config.baseurl;
    }

    var host = '0.0.0.0';
    var port = 9002;
    grunt.log.writeln(`Starting static web server for folder ${config.site} on host ${host}:${port}.`);
    var url = `http://localhost:${port}${config.baseurl}/`;
    grunt.log.writeln(url);
    var app = connect();
    app.use(connectLivereload({
      port: 35731
    }));
    app.use(config.baseurl, serveStatic(config.site));
    http.createServer(app).listen(port, host);
    open(url);
  });

  grunt.registerTask('server', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve:'+target]);
  });

  grunt.registerTask('default', ['build']);
};
<commit_msg>copy node_modules again (#1731)<commit_after>/*global module,require*/
var connect = require('connect'),
    connectLivereload = require('connect-livereload'),
    serveStatic = require('serve-static'),
    http = require('http'),
    open = require('open'),
    _ = require('lodash'),
    yaml = require('js-yaml'),
    packageJson = require('./package.json'),
    path = require('path');

function correctBaseUrl(_baseurl) {
  if (_baseurl.length) {
    if (_baseurl.substr(0, 1) !== '/') {
      // add leading slash
      _baseurl = '/' + _baseurl;
    }
    if (_baseurl.substr(-1, 1) === '/') {
      // remove trailing slash
      _baseurl = _baseurl.slice(0, -1);
    }
  }
  return _baseurl;
}

module.exports = function (grunt) {
  // load all grunt tasks
  require('matchdep').filterDev(['grunt-*', '!grunt-cli']).forEach(grunt.loadNpmTasks);

  var config = {
    site: '_site',
    build: '_build',
    source: 'source',
    defaultTarget: 'staging',
    baseurl: correctBaseUrl(grunt.option('baseurl') || '/v3')
  };

  grunt.initConfig({
    clean: {
      build: '<%= config.build %>',
      site: '<%= config.site %>'
    },
    config: config,
    sync: {
      source: {
        files: [
          {
            expand: true,
            cwd: '<%= config.source %>',
            src: ['**', '!<%= config.build %>/assets/css'],
            dest: '<%= config.build %>'
          }
        ]
      },
      design: {
        files: [
          {
            expand: true,
            cwd: 'node_modules/src-design/pattern-library',
            src: ['**/design/**', '!**/documents/**'],
            dest: '<%= config.build %>/_includes/pattern-library'
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/pattern-library',
            src: ['**/design/**', '!**/documents/**', '!**/*.md'],
            dest: '<%= config.build %>/pattern-library',
            rename: function(dest, src) {
              return dest + '/' + src.replace('/design', '');
            }
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/pattern-library',
            src: ['**/site.md'],
            dest: '<%= config.build %>/pattern-library',
            rename: function(dest, src) {
              return dest + '/' + src.replace('site.md', 'index.md');
            }
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/styles',
            src: ['**/*.md'],
            dest: '<%= config.build %>/_includes/styles'
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/styles',
            src: ['**/!(*.md)'],
            dest: '<%= config.build %>/styles'
          },
          {
            expand: true,
            cwd: 'node_modules/src-design/styles/icons',
            src: ['icons.json'],
            dest: '<%= config.build %>/_data'
          }
        ]
      },
      examples: {
        files: [
          // Copy resources from git repos
          {
            expand: true,
            cwd: 'node_modules/src-core/tests/pages/_includes/widgets',
            src: ['**'],
            dest: '<%= config.build %>/_includes/widgets'
          },
          {
            expand: true,
            cwd: 'node_modules/src-angular/dist/docs/partials',
            src: ['**'],
            dest: '<%= config.build %>/_includes/angular-partials'
          }
        ]
      },
      patternflyDist: {
        files: [
          // Copy resources from git repos
          {
            expand: true,
            cwd: 'node_modules/src-core/dist',
            src: ['**'],
            dest: '<%= config.build %>/components/patternfly/dist'
          },
          {
            expand: true,
            cwd: 'node_modules/src-angular/dist',
            src: ['**'],
            dest: '<%= config.build %>/components/angular-patternfly/dist'
          }
        ]
      }
    },
    copy: {
      components: {
        files: [
          {
            expand: true,
            cwd: 'node_modules',
            src: ['**/*'],
            filter: function(filepath) { // this filter is 5x faster as the corresponding glob
              if (!grunt.file.isFile(filepath) || filepath.includes(path.join('node_modules', 'src-'))) {
                return false;
              }

              var isNotHoisted = packageJson.workspaces.nohoist
                .filter(package => filepath.includes(path.join('node_modules', package)))
                .length > 0;

              if (!isNotHoisted) {
                return false;
              }

              var fileparts = filepath.split('/');
              if (fileparts[2] == 'node_modules') {
                return false;
              }
              var packages = _.keys(packageJson.dependencies);
              if (fileparts[1] === 'patternfly' || fileparts[1] === 'angular-patternfly' || packages.indexOf(fileparts[1]) < 0) {
                return false;
              }
              var extensions = ['html','txt','js','coffee','css','scss','less','otf','eot','svg','ttf','woff','woff2','png','jpg','gif','ico','xml','yml','yaml','map','json','md'];
              var extparts = fileparts[fileparts.length - 1].split('.');
              return extensions.indexOf(extparts[extparts.length-1]) >= 0;
            },
            dest: '<%= config.build %>/components'
          },
        ]
      }
    },
    csscount: {
      source: {
        src: [
          '<%= config.build %>/assets/css/patternfly*.min.css'
        ],
        options: {
          maxSelectors: 4096
        }
      }
    },
    cssmin: {
      source: {
        files: [{
          expand: true,
          cwd: '<%= config.build %>/assets/css',
          src: ['patternfly*.css', '!*.min.css'],
          dest: '<%= config.build %>/assets/css',
          ext: '.min.css',
        }],
        options: {
          sourceMap: true
        }
      }
    },
    http: {
      pattern_status: {
        options: {
          url: 'https://www.patternfly.org/patternfly-design/status/pattern-status.json'
        },
        dest: '_build/_data/pattern-status.json'
      }
    },
    jekyll: {
      options: {
        dest: '<%= config.site %>',
        config: '<%= config.build %>/_config.yml',
        src: '<%= config.build %>',
        bundleExec: 'true',
        incremental: 'true'
      },
      production: {
        incremental: 'false'
      },
      staging: {
      }
    },
    less: {
      patternflySite: {
        files: {
          '<%= config.build %>/assets/css/patternfly-site.css': '<%= config.source %>/_less/patternfly-site.less'
        },
        options: {
          paths: [
            'less/',
            'node_modules/'
          ],
          sourceMap: true,
          outputSourceFiles: true,
          sourceMapFilename: '<%= config.build %>/assets/css/patternfly-site.css.map',
          sourceMapURL: 'patternfly-site.css.map'
        }
      },
      patternflySiteAdjusted: {
        files: {
          '<%= config.build %>/assets/css/patternfly-adjusted.css': '<%= config.source %>/_less/patternfly-adjusted.less'
        },
        options: {
          paths: [
            'less/',
            'node_modules/'
          ],
          sourceMap: true,
          outputSourceFiles: true,
          sourceMapFilename: '<%= config.build %>/assets/css/patternfly-adjusted.css.map',
          sourceMapURL: 'patternfly-adjusted.css.map'
        }
      }
    },
    uglify: {
      options: {
        mangle: false
      },
      production: {
        files: {
          '<%= config.build %>/assets/js/patternfly-site.min.js': ['<%= config.source %>/assets/js/patternfly-site.js']
        }
      }
    },
    watch: {
      source: {
        files: ['<%= config.source %>/**/*', '!<%= config.source %>/_less/**/*', '!<%= config.source %>/assets/js/**/*'],
        tasks: ['sync:source']
      },
      less: {
        files: ['<%= config.source %>/_less/*.less'],
        tasks: ['less', 'cssmin']
      },
      js: {
        files: ['<%= config.source %>/assets/js/*.js'],
        tasks: ['uglify']
      },
      jekyll: {
        files: ['<%= config.build %>/**/*', '!<%= config.source %>/_less/**/*'],
        tasks: ['jekyll:staging']
      },
      design: {
        files: ['node_modules/src-design/**/*'],
        tasks: ['sync:design']
      },
      examples: {
        files: ['node_modules/src-core/tests/pages/_includes/widgets',
                'node_modules/src-angular/dist/docs/partials'],
        tasks: ['sync:examples']
      },
      livereload: {
        files: ['<%= config.site %>/**/*'],
        options: {
          livereload: 35731
        }
      }
    }
  });

  grunt.registerTask('jenkins', [
    'less',
    'cssmin',
    'uglify'
  ]);

  grunt.registerTask('buildConfig', function (target) {
    if (target === 'staging') {
      var jekyllConfig = grunt.file.readYAML(`${config.source}/_config.yml`);
      jekyllConfig.baseurl = config.baseurl;
      grunt.file.write(`${config.build}/_config.yml`, yaml.safeDump(jekyllConfig));
    }
  })

  grunt.registerTask('serve', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'build:' + target,
      'connect:' + target,
      'watch'
    ]);
  });

  grunt.registerTask('prebuild', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'clean',
      // 'http:pattern_status',
      'copy:components',
      'sync:patternflyDist',
      'buildConfig:' + target,
      'sync:source',
      'sync:design',
      'sync:examples',
      'less',
      'cssmin',
      // 'csscount',
      'uglify',
    ]);
  });

  grunt.registerTask('build', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'prebuild:' + target,
      'jekyll:' + target
    ]);
  });

  grunt.registerTask('connect', function(target) {
    // Load the jekyll config
    var jekyllConfig = grunt.file.readYAML(`${config.source}/_config.yml`);
    if (target === 'staging') {
      jekyllConfig.baseurl = config.baseurl;
    }

    var host = '0.0.0.0';
    var port = 9002;
    grunt.log.writeln(`Starting static web server for folder ${config.site} on host ${host}:${port}.`);
    var url = `http://localhost:${port}${config.baseurl}/`;
    grunt.log.writeln(url);
    var app = connect();
    app.use(connectLivereload({
      port: 35731
    }));
    app.use(config.baseurl, serveStatic(config.site));
    http.createServer(app).listen(port, host);
    open(url);
  });

  grunt.registerTask('server', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve:'+target]);
  });

  grunt.registerTask('default', ['build']);
};
<|endoftext|>