<commit_before>import { Meteor } from 'meteor/meteor'
import { Mongo } from 'meteor/mongo'
import SimpleSchema from 'simpl-schema'
import { startingTime, endingTime, startingDate, endingDate, getHour, weekDays, getDate, videoHosts } from './helpers'
// import categoryTree from '/imports/both/i18n/en/categories.json'
// import labels from '/imports/both/i18n/en/new-event-modal.json'
import DaySchema from './DaysSchema'

import i18n from '/imports/both/i18n/en'

let categoryTree = i18n.Categories
let labels = i18n.NewEventModal

// categoryTree includes parent-child level categories, following operation build an all-child array of sub-categories
let possibleCategories = categoryTree.reduce((tot, elem) => {
  return tot.concat([{name: elem.name, parent: true}].concat(elem.categories))
}, [])

// sets allowedValues to include Community Resource without it being in dropdown
// someone should refactor this in the future: let allowedValues = possibleCategories.concat([{ 'name': 'Meet Me and Take #PublicHappiness to the Street', 'color': '#f82d2d' }])
let allowedValues = possibleCategories

// Extend SimpleSchema to support the uniforms field.
SimpleSchema.extendOptions(['uniforms'])

const Events = new Mongo.Collection('events')

/**
 * Instantiates a Schema for the events collection (aka events database).
 * required to defined all the database fields
 * and specify options such as default values/conditions for when they are required
 * NOTE: these definitions feed through to the React forms so any changes should start here
 */
const EventsSchema = new SimpleSchema({

  // Organiser
  'organiser': {
    type: Object,
    autoValue: function () {
      // Dont change this!
      const { _id, profile } = Meteor.user() || { _id: '-', profile: { name: '-' } }
      return {
        _id,
        name: profile.name
      }
    }
  },
  'organiser._id': {
    type: String
  },
  'organiser.name': {
    type: String
  },

  // Categories sub level
  'categories': {
    type: Array,
    custom: function () {
      if (!this.value || this.value.length === 0) {
        return 'required'
      }
    },
    uniforms: {
      customType: 'select',
      selectOptions: {
        multi: true,
        labelKey: 'name',
        catLevel: 'child'
      },
      allowedValues: possibleCategories, // keep it here so options will be rendered by react-select
      label: null,
      placeholder_: labels.categories
    }
  },
  'categories.$': {
    type: Object
  },
  'categories.$.name': {
    type: String,
    allowedValues: allowedValues.reduce((arr, obj) => (arr.concat(obj.name)), [])
  },
  'categories.$.color': {
    type: String,
    allowedValues: allowedValues.reduce((arr, obj) => (arr.concat(obj.color)), []),
    defaultValue: '#f82d2d'
  },
  'categories.resourceType': {
    type: String,
    defaultValue: ''
  },

  // Details
  'name': {
    type: String,
    uniforms: {
      label: labels.event_name
    }
  },
  'address': {
    type: Object,
    custom: function () {
      if (!this.value || !this.value.name) {
        return 'required'
      }
    },
    uniforms: {
      customType: 'select',
      selectOptions: {
        'googleMaps': true
      },
      label: 'Select an address',
      placeholder_: 'Ex: New York, USA'
    }
  },
  'address.name': {
    type: String
  },
  'address.location': {
    type: Object
  },
  'address.location.type': {
    type: String,
    defaultValue: 'Point',
    allowedValues: ['Point']
  },
  'address.location.coordinates': {
    type: Array,
    max: 2,
    min: 2
  },
  'address.location.coordinates.$': {
    type: Number
  },
  'findHints': {
    type: String,
    max: 250,
    uniforms: {
      customType: 'textarea',
      label: labels.contact_info
    }
  },

  // Date and Time
  'when': {
    type: Object,
    custom: function () {
      const type = this.field('when.type')
      const obj = !this.field('when.' + type)

      // ensure we have a valid when object
      if (!type || obj.value) {
        return 'required'
      }
    }
  },
  'when.startingDate': {
    ...startingDate,
    uniforms: {
      label: labels.active_from
    },
    optional: false
  },
  'when.endingDate': {
    ...endingDate,
    uniforms: {
      label: labels.active_until
    },
    optional: false,
    // NOTE: catch 22... autoValue will not pre-populate form UI as it fires after submit
    // defaultValue would work BUT including it will also fire this.isSet()
    // meaning autoValue will never trigger correctly
    // Solution: omit defaultValue and pre-populate form client-side via React
    autoValue: function () {
      const categories = this.field('categories').value
      const specialCat = categories.some(e => {
        return e.name === 'Community Offer' || e.name === 'Meet me for Action!'
      })
      if (!this.isSet && specialCat) {
        let now = new Date()
        return new Date(now.setFullYear(now.getFullYear() + 10))
      } else if (!this.isSet && !specialCat) {
        return getDate(3)
      } else if (!this.isSet && this.siblingField('repeat').value) {
        return getDate(3)
      }
    }
  },
  'when.startingTime': {
    ...startingTime,
    optional: true,
    custom: function () {
      if (this.field('when.multipleDays').value) {
        return undefined
      }

      if (!this.value) {
        return 'required'
      }
    },
    autoValue: function () {
      if (this.field('when.multipleDays').value) {
        return null
      }
      if (!this.value) {
        return getHour()
      }
    }
  },
  'when.endingTime': {
    ...endingTime,
    optional: true,
    custom: function () {
      if (this.field('when.multipleDays').value) {
        return undefined
      }

      if (!this.value) {
        return 'required'
      }
    },
    autoValue: function () {
      if (this.field('when.multipleDays').value) {
        return null
      }

      if (!this.value) {
        return getHour(1)
      }
    }
  },
  'when.multipleDays': {
    type: Boolean,
    defaultValue: false
  },
  'when.days': { // used with multipleDays
    type: Array,
    optional: true,
    custom: function () {
      if (!this.field('when.multipleDays').value) {
        return undefined
      }

      if (!this.value || this.value.length === 0) {
        return 'required'
      }
    },
    autoValue: function () {
      if (!this.field('when.multipleDays').value) {
        return null
      }

      if (this.value) {
        return this.value.map(d => !d ? false : d) // remove empty slots
      }
    }
  },
  'when.days.$': {
    type: SimpleSchema.oneOf(DaySchema, Boolean),
    required: false
  },
  'when.repeat': {
    type: Boolean,
    defaultValue: false
  },
  'when.recurring': { // used with repeat
    type: Object,
    optional: true,
    autoValue: function () {
      if (!this.field('when.repeat').value) {
        return null
      }
    }
  },
  'when.recurring.type': {
    type: String,
    allowedValues: ['day', 'week', 'month'],
    defaultValue: 'day',
    uniforms: {
      customType: 'select',
      selectOptions: {
        labelMapper: {
          'day': 'day(s)',
          'week': 'week(s)',
          'month': 'month(s)'
        }
      }
    }
  },
  'when.recurring.days': { // used with 'week'
    type: Array,
    optional: true,
    custom: function () {
      const type = this.siblingField('type')
      if (type.value === 'week') {
        const atLeastOneDay = !this.value || !this.value.join('')
        return atLeastOneDay ? 'required' : undefined
      }
    },
    autoValue: function () {
      const type = this.siblingField('type')
      if (type.value !== 'week') {
        return null
      }
    }
  },
  'when.recurring.days.$': {
    type: String,
    allowedValues: weekDays
  },
  'when.recurring.monthly': {
    type: Object,
    optional: true,
    autoValue: function () {
      if (this.siblingField('type').value === 'month') {
        return this.value || {} // empty object will generate default values automatically
      } else {
        return null
      }
    }
  },
  'when.recurring.monthly.type': {
    type: String,
    allowedValues: ['byPosition', 'byDayInMonth'],
    autoValue: function () {
      if (!this.value) {
        return 'byDayInMonth'
      }
    }
  },
  'when.recurring.monthly.value': {
    type: Number,
    autoValue: function () {
      if (!this.value) {
        return this.field('when.startingDate').value.getDate()
      }
    }
  },
  'when.recurring.every': {
    type: Number,
    min: 0,
    max: 12,
    defaultValue: 1,
    autoValue: function () {
      if (!this.value || this.value < 1) {
        return 1
      }
    }
  },
  'when.recurring.forever': {
    type: Boolean,
    optional: true
  },
  'when.recurring.occurences': {
    type: Number,
    min: 1,
    max: 999,
    optional: true,
    custom: function () {
      if (this.siblingField('forever').value) {
        return undefined
      } else if (!this.value && !this.siblingField('until').value) {
        return 'required'
      }
    },
    autoValue: function () {
      if (this.siblingField('forever').value) {
        return null
      }
      if (this.siblingField('until').value) {
        return null
      }
    }
  },
  'when.recurring.recurrenceEndDate': {
    type: Date,
    optional: true,
    autoValue: function () {
      const initialEndDate = this.field('when.endingDate').value
        ? Date.parse(this.field('when.endingDate').value) : Date.parse(getDate(3))
      const type = this.field('when.recurring.type').value
      const skip = this.field('when.recurring.every').value
      const occurences = this.field('when.recurring.occurences').value
      let millisecondsPerPeriod = 24 * 60 * 60000
      // check type of recurrence, and that a number of repetitions has been set (rather than an "until" date)
      if (type === 'day' && occurences >= 1) return new Date(initialEndDate + (skip * occurences * millisecondsPerPeriod))
      else if (type === 'week' && occurences >= 1) return new Date(initialEndDate + (skip * occurences * millisecondsPerPeriod * 7))
      else if (type === 'month' && occurences >= 1) return new Date(initialEndDate + (skip * occurences * millisecondsPerPeriod * 365.25 / 12))
      else return null
    }
  },
  'when.recurring.until': {
    type: Date,
    optional: true,
    custom: function () {
      if (!this.value && !this.siblingField('occurences').value && !this.siblingField('forever').value) {
        return 'required'
      }
    }
  },

  // Description and More
  'overview': {
    type: String,
    max: 300,
    uniforms: {
      customType: 'textarea',
      label: labels.overview
    }
  },
  'description': {
    type: String,
    max: 1000,
    uniforms: {
      customType: 'textarea',
      label: labels.description
    }
  },
  engagement: {
    type: Object,
    defaultValue: {}
  },
  'engagement.limit': {
    type: Number,
    min: 0,
    defaultValue: labels.attendee_limit,
    uniforms: {
      customType: 'number',
      label: 'Attendee limit (leave as is, if no limit)'
    }
  },
  'engagement.attendees': {
    type: Array,
    defaultValue: []
  },
  'engagement.attendees.$': {
    type: Object,
    optional: true
  },
  'engagement.attendees.$.id': {
    type: String,
    max: 36
  },
  'engagement.attendees.$.name': {
    type: String,
    max: 120
  },
  'video': {
    type: Object,
    optional: true,
    // defaultValue: {}
  },

  // NOTE: Following fields relate to video links added to the event mongodb document
  // Attempted to create via an Array, but ran into difficulties with uniforms connecting to SimplSchema
  // Consequently these have been written out as individual numbered fields...
  // Someone more experienced with SimplSchema may wish to refactor in the future to limit code re-use
  'video.link1': {
    type: Object,
    optional: true,
    defaultValue: {}
  },
  'video.link1.host': {
    optional: true,
    type: String,
    defaultValue: labels.video.host,
    uniforms: {
      customType: 'select',
      label: null,
      allowedValues: videoHosts.map((e) => `${e.host} (eg. ${e.prefix}<VIDEO_ID>)`),
      selectOptions: {
        url: true
      },
    }
  },
  'video.link1.address': {
    optional: true,
    type: String,
    custom: function () {
      if (this.value && this.value !== "") {
        const host = this.siblingField('host').value.split(' (eg.')[0]  // <-- split out the 'example' at the end of host field text
        const prefixServer = videoHosts.find(e => e.host === host).prefix
        const prefixClient = this.value.slice(0, prefixServer.length)
        if (prefixClient !== prefixServer) return 'required'
      }
    },
    uniforms: {
      label: null
    }
  },
  'video.link2': {
    type: Object,
    optional: true
  },
  'video.link2.host': {
    optional: true,
    type: String,
    defaultValue: labels.video.host,
    uniforms: {
      customType: 'select',
      label: null,
      allowedValues: videoHosts.map((e) => `${e.host} (eg. ${e.prefix}<VIDEO_ID>)`),
      selectOptions: {
        url: true
      },
    }
  },
  'video.link2.address': {
    optional: true,
    type: String,
    custom: function () {
      if (this.value && this.value !== "") {
        const host = this.siblingField('host').value.split(' (eg.')[0]  // <-- split out the 'example' at the end of host field text
        const prefixServer = videoHosts.find(e => e.host === host).prefix
        const prefixClient = this.value.slice(0, prefixServer.length)
        if (prefixClient !== prefixServer) return 'required'
      }
    },
    uniforms: {
      label: null
    }
  },
  'video.link3': {
    type: Object,
    optional: true,
  },
  'video.link3.host': {
    optional: true,
    type: String,
    defaultValue: labels.video.host,
    uniforms: {
      customType: 'select',
      label: null,
      allowedValues: videoHosts.map((e) => `${e.host} (eg. ${e.prefix}<VIDEO_ID>)`),
      selectOptions: {
        url: true
      },
    }
  },
  'video.link3.address': {
    optional: true,
    type: String,
    custom: function () {
      if (this.value && this.value !== "") {
        const host = this.siblingField('host').value.split(' (eg.')[0]  // <-- split out the 'example' at the end of host field text
        const prefixServer = videoHosts.find(e => e.host === host).prefix
        const prefixClient = this.value.slice(0, prefixServer.length)
        if (prefixClient !== prefixServer) return 'required'
      }
    },
    uniforms: {
      label: null
    }
  },
  'createdAt': {
    type: Date,
    autoValue: () => new Date()
  }
}, {
  clean: {
    filter: true,
    autoConvert: true,
    removeEmptyStrings: true,
    trimStrings: true,
    getAutoValues: true
  }
})

Events.attachSchema(EventsSchema)

// if (Meteor.isServer) {
//  Events._ensureIndex({ 'address.location': '2dsphere' })
// }

export {
  Events as default,
  EventsSchema
}
<commit_msg>removed commenting out code<commit_after>import { Meteor } from 'meteor/meteor'
import { Mongo } from 'meteor/mongo'
import SimpleSchema from 'simpl-schema'
import { startingTime, endingTime, startingDate, endingDate, getHour, weekDays, getDate, videoHosts } from './helpers'
// import categoryTree from '/imports/both/i18n/en/categories.json'
// import labels from '/imports/both/i18n/en/new-event-modal.json'
import DaySchema from './DaysSchema'

import i18n from '/imports/both/i18n/en'

let categoryTree = i18n.Categories
let labels = i18n.NewEventModal

// categoryTree includes parent-child level categories, following operation build an all-child array of sub-categories
let possibleCategories = categoryTree.reduce((tot, elem) => {
  return tot.concat([{name: elem.name, parent: true}].concat(elem.categories))
}, [])

// sets allowedValues to include Community Resource without it being in dropdown
// someone should refactor this in the future: let allowedValues = possibleCategories.concat([{ 'name': 'Meet Me and Take #PublicHappiness to the Street', 'color': '#f82d2d' }])
let allowedValues = possibleCategories

// Extend SimpleSchema to support the uniforms field.
SimpleSchema.extendOptions(['uniforms'])

const Events = new Mongo.Collection('events')

/**
 * Instantiates a Schema for the events collection (aka events database).
 * required to defined all the database fields
 * and specify options such as default values/conditions for when they are required
 * NOTE: these definitions feed through to the React forms so any changes should start here
 */
const EventsSchema = new SimpleSchema({

  // Organiser
  'organiser': {
    type: Object,
    autoValue: function () {
      // Dont change this!
      const { _id, profile } = Meteor.user() || { _id: '-', profile: { name: '-' } }
      return {
        _id,
        name: profile.name
      }
    }
  },
  'organiser._id': {
    type: String
  },
  'organiser.name': {
    type: String
  },

  // Categories sub level
  'categories': {
    type: Array,
    custom: function () {
      if (!this.value || this.value.length === 0) {
        return 'required'
      }
    },
    uniforms: {
      customType: 'select',
      selectOptions: {
        multi: true,
        labelKey: 'name',
        catLevel: 'child'
      },
      allowedValues: possibleCategories, // keep it here so options will be rendered by react-select
      label: null,
      placeholder_: labels.categories
    }
  },
  'categories.$': {
    type: Object
  },
  'categories.$.name': {
    type: String,
    allowedValues: allowedValues.reduce((arr, obj) => (arr.concat(obj.name)), [])
  },
  'categories.$.color': {
    type: String,
    allowedValues: allowedValues.reduce((arr, obj) => (arr.concat(obj.color)), []),
    defaultValue: '#f82d2d'
  },
  'categories.resourceType': {
    type: String,
    defaultValue: ''
  },

  // Details
  'name': {
    type: String,
    uniforms: {
      label: labels.event_name
    }
  },
  'address': {
    type: Object,
    custom: function () {
      if (!this.value || !this.value.name) {
        return 'required'
      }
    },
    uniforms: {
      customType: 'select',
      selectOptions: {
        'googleMaps': true
      },
      label: 'Select an address',
      placeholder_: 'Ex: New York, USA'
    }
  },
  'address.name': {
    type: String
  },
  'address.location': {
    type: Object
  },
  'address.location.type': {
    type: String,
    defaultValue: 'Point',
    allowedValues: ['Point']
  },
  'address.location.coordinates': {
    type: Array,
    max: 2,
    min: 2
  },
  'address.location.coordinates.$': {
    type: Number
  },
  'findHints': {
    type: String,
    max: 250,
    uniforms: {
      customType: 'textarea',
      label: labels.contact_info
    }
  },

  // Date and Time
  'when': {
    type: Object,
    custom: function () {
      const type = this.field('when.type')
      const obj = !this.field('when.' + type)

      // ensure we have a valid when object
      if (!type || obj.value) {
        return 'required'
      }
    }
  },
  'when.startingDate': {
    ...startingDate,
    uniforms: {
      label: labels.active_from
    },
    optional: false
  },
  'when.endingDate': {
    ...endingDate,
    uniforms: {
      label: labels.active_until
    },
    optional: false,
    // NOTE: catch 22... autoValue will not pre-populate form UI as it fires after submit
    // defaultValue would work BUT including it will also fire this.isSet()
    // meaning autoValue will never trigger correctly
    // Solution: omit defaultValue and pre-populate form client-side via React
    autoValue: function () {
      const categories = this.field('categories').value
      const specialCat = categories.some(e => {
        return e.name === 'Community Offer' || e.name === 'Meet me for Action!'
      })
      if (!this.isSet && specialCat) {
        let now = new Date()
        return new Date(now.setFullYear(now.getFullYear() + 10))
      } else if (!this.isSet && !specialCat) {
        return getDate(3)
      } else if (!this.isSet && this.siblingField('repeat').value) {
        return getDate(3)
      }
    }
  },
  'when.startingTime': {
    ...startingTime,
    optional: true,
    custom: function () {
      if (this.field('when.multipleDays').value) {
        return undefined
      }

      if (!this.value) {
        return 'required'
      }
    },
    autoValue: function () {
      if (this.field('when.multipleDays').value) {
        return null
      }
      if (!this.value) {
        return getHour()
      }
    }
  },
  'when.endingTime': {
    ...endingTime,
    optional: true,
    custom: function () {
      if (this.field('when.multipleDays').value) {
        return undefined
      }

      if (!this.value) {
        return 'required'
      }
    },
    autoValue: function () {
      if (this.field('when.multipleDays').value) {
        return null
      }

      if (!this.value) {
        return getHour(1)
      }
    }
  },
  'when.multipleDays': {
    type: Boolean,
    defaultValue: false
  },
  'when.days': { // used with multipleDays
    type: Array,
    optional: true,
    custom: function () {
      if (!this.field('when.multipleDays').value) {
        return undefined
      }

      if (!this.value || this.value.length === 0) {
        return 'required'
      }
    },
    autoValue: function () {
      if (!this.field('when.multipleDays').value) {
        return null
      }

      if (this.value) {
        return this.value.map(d => !d ? false : d) // remove empty slots
      }
    }
  },
  'when.days.$': {
    type: SimpleSchema.oneOf(DaySchema, Boolean),
    required: false
  },
  'when.repeat': {
    type: Boolean,
    defaultValue: false
  },
  'when.recurring': { // used with repeat
    type: Object,
    optional: true,
    autoValue: function () {
      if (!this.field('when.repeat').value) {
        return null
      }
    }
  },
  'when.recurring.type': {
    type: String,
    allowedValues: ['day', 'week', 'month'],
    defaultValue: 'day',
    uniforms: {
      customType: 'select',
      selectOptions: {
        labelMapper: {
          'day': 'day(s)',
          'week': 'week(s)',
          'month': 'month(s)'
        }
      }
    }
  },
  'when.recurring.days': { // used with 'week'
    type: Array,
    optional: true,
    custom: function () {
      const type = this.siblingField('type')
      if (type.value === 'week') {
        const atLeastOneDay = !this.value || !this.value.join('')
        return atLeastOneDay ? 'required' : undefined
      }
    },
    autoValue: function () {
      const type = this.siblingField('type')
      if (type.value !== 'week') {
        return null
      }
    }
  },
  'when.recurring.days.$': {
    type: String,
    allowedValues: weekDays
  },
  'when.recurring.monthly': {
    type: Object,
    optional: true,
    autoValue: function () {
      if (this.siblingField('type').value === 'month') {
        return this.value || {} // empty object will generate default values automatically
      } else {
        return null
      }
    }
  },
  'when.recurring.monthly.type': {
    type: String,
    allowedValues: ['byPosition', 'byDayInMonth'],
    autoValue: function () {
      if (!this.value) {
        return 'byDayInMonth'
      }
    }
  },
  'when.recurring.monthly.value': {
    type: Number,
    autoValue: function () {
      if (!this.value) {
        return this.field('when.startingDate').value.getDate()
      }
    }
  },
  'when.recurring.every': {
    type: Number,
    min: 0,
    max: 12,
    defaultValue: 1,
    autoValue: function () {
      if (!this.value || this.value < 1) {
        return 1
      }
    }
  },
  'when.recurring.forever': {
    type: Boolean,
    optional: true
  },
  'when.recurring.occurences': {
    type: Number,
    min: 1,
    max: 999,
    optional: true,
    custom: function () {
      if (this.siblingField('forever').value) {
        return undefined
      } else if (!this.value && !this.siblingField('until').value) {
        return 'required'
      }
    },
    autoValue: function () {
      if (this.siblingField('forever').value) {
        return null
      }
      if (this.siblingField('until').value) {
        return null
      }
    }
  },
  'when.recurring.recurrenceEndDate': {
    type: Date,
    optional: true,
    autoValue: function () {
      const initialEndDate = this.field('when.endingDate').value
        ? Date.parse(this.field('when.endingDate').value) : Date.parse(getDate(3))
      const type = this.field('when.recurring.type').value
      const skip = this.field('when.recurring.every').value
      const occurences = this.field('when.recurring.occurences').value
      let millisecondsPerPeriod = 24 * 60 * 60000
      // check type of recurrence, and that a number of repetitions has been set (rather than an "until" date)
      if (type === 'day' && occurences >= 1) return new Date(initialEndDate + (skip * occurences * millisecondsPerPeriod))
      else if (type === 'week' && occurences >= 1) return new Date(initialEndDate + (skip * occurences * millisecondsPerPeriod * 7))
      else if (type === 'month' && occurences >= 1) return new Date(initialEndDate + (skip * occurences * millisecondsPerPeriod * 365.25 / 12))
      else return null
    }
  },
  'when.recurring.until': {
    type: Date,
    optional: true,
    custom: function () {
      if (!this.value && !this.siblingField('occurences').value && !this.siblingField('forever').value) {
        return 'required'
      }
    }
  },

  // Description and More
  'overview': {
    type: String,
    max: 300,
    uniforms: {
      customType: 'textarea',
      label: labels.overview
    }
  },
  'description': {
    type: String,
    max: 1000,
    uniforms: {
      customType: 'textarea',
      label: labels.description
    }
  },
  engagement: {
    type: Object,
    defaultValue: {}
  },
  'engagement.limit': {
    type: Number,
    min: 0,
    defaultValue: labels.attendee_limit,
    uniforms: {
      customType: 'number',
      label: 'Attendee limit (leave as is, if no limit)'
    }
  },
  'engagement.attendees': {
    type: Array,
    defaultValue: []
  },
  'engagement.attendees.$': {
    type: Object,
    optional: true
  },
  'engagement.attendees.$.id': {
    type: String,
    max: 36
  },
  'engagement.attendees.$.name': {
    type: String,
    max: 120
  },
  'video': {
    type: Object,
    optional: true,
    // defaultValue: {}
  },

  // NOTE: Following fields relate to video links added to the event mongodb document
  // Attempted to create via an Array, but ran into difficulties with uniforms connecting to SimplSchema
  // Consequently these have been written out as individual numbered fields...
  // Someone more experienced with SimplSchema may wish to refactor in the future to limit code re-use
  'video.link1': {
    type: Object,
    optional: true,
    defaultValue: {}
  },
  'video.link1.host': {
    optional: true,
    type: String,
    defaultValue: labels.video.host,
    uniforms: {
      customType: 'select',
      label: null,
      allowedValues: videoHosts.map((e) => `${e.host} (eg. ${e.prefix}<VIDEO_ID>)`),
      selectOptions: {
        url: true
      },
    }
  },
  'video.link1.address': {
    optional: true,
    type: String,
    custom: function () {
      if (this.value && this.value !== "") {
        const host = this.siblingField('host').value.split(' (eg.')[0]  // <-- split out the 'example' at the end of host field text
        const prefixServer = videoHosts.find(e => e.host === host).prefix
        const prefixClient = this.value.slice(0, prefixServer.length)
        if (prefixClient !== prefixServer) return 'required'
      }
    },
    uniforms: {
      label: null
    }
  },
  'video.link2': {
    type: Object,
    optional: true
  },
  'video.link2.host': {
    optional: true,
    type: String,
    defaultValue: labels.video.host,
    uniforms: {
      customType: 'select',
      label: null,
      allowedValues: videoHosts.map((e) => `${e.host} (eg. ${e.prefix}<VIDEO_ID>)`),
      selectOptions: {
        url: true
      },
    }
  },
  'video.link2.address': {
    optional: true,
    type: String,
    custom: function () {
      if (this.value && this.value !== "") {
        const host = this.siblingField('host').value.split(' (eg.')[0]  // <-- split out the 'example' at the end of host field text
        const prefixServer = videoHosts.find(e => e.host === host).prefix
        const prefixClient = this.value.slice(0, prefixServer.length)
        if (prefixClient !== prefixServer) return 'required'
      }
    },
    uniforms: {
      label: null
    }
  },
  'video.link3': {
    type: Object,
    optional: true,
  },
  'video.link3.host': {
    optional: true,
    type: String,
    defaultValue: labels.video.host,
    uniforms: {
      customType: 'select',
      label: null,
      allowedValues: videoHosts.map((e) => `${e.host} (eg. ${e.prefix}<VIDEO_ID>)`),
      selectOptions: {
        url: true
      },
    }
  },
  'video.link3.address': {
    optional: true,
    type: String,
    custom: function () {
      if (this.value && this.value !== "") {
        const host = this.siblingField('host').value.split(' (eg.')[0]  // <-- split out the 'example' at the end of host field text
        const prefixServer = videoHosts.find(e => e.host === host).prefix
        const prefixClient = this.value.slice(0, prefixServer.length)
        if (prefixClient !== prefixServer) return 'required'
      }
    },
    uniforms: {
      label: null
    }
  },
  'createdAt': {
    type: Date,
    autoValue: () => new Date()
  }
}, {
  clean: {
    filter: true,
    autoConvert: true,
    removeEmptyStrings: true,
    trimStrings: true,
    getAutoValues: true
  }
})

Events.attachSchema(EventsSchema)

 if (Meteor.isServer) {
  Events._ensureIndex({ 'address.location': '2dsphere' })
 }

export {
  Events as default,
  EventsSchema
}
<|endoftext|>


<commit_before>import { BodyComponent } from 'mjml-core'
import { get, each } from 'lodash'

const IMG_BASE_URL = 'https://www.mailjet.com/images/theme/v1/icons/ico-social/'

const defaultSocialNetworks = {
  facebook: {
    'share-url': 'https://www.facebook.com/sharer/sharer.php?u=[[URL]]',
    'background-color': '#3b5998',
    src: `${IMG_BASE_URL}facebook.png`,
  },
  twitter: {
    'share-url': 'https://twitter.com/home?status=[[URL]]',
    'background-color': '#55acee',
    src: `${IMG_BASE_URL}twitter.png`,
  },
  google: {
    'share-url': 'https://plus.google.com/share?url=[[URL]]',
    'background-color': '#dc4e41',
    src: `${IMG_BASE_URL}google-plus.png`,
  },
  pinterest: {
    'share-url':
      'https://pinterest.com/pin/create/button/?url=[[URL]]&media=&description=',
    'background-color': '#bd081c',
    src: `${IMG_BASE_URL}pinterest.png`,
  },
  linkedin: {
    'share-url':
      'https://www.linkedin.com/shareArticle?mini=true&url=[[URL]]&title=&summary=&source=',
    'background-color': '#0077b5',
    src: `${IMG_BASE_URL}linkedin.png`,
  },
  instagram: {
    'background-color': '#3f729b',
    src: `${IMG_BASE_URL}instagram.png`,
  },
  web: {
    src: `${IMG_BASE_URL}web.png`,
    'background-color': '#4BADE9',
  },
  snapchat: {
    src: `${IMG_BASE_URL}snapchat.png`,
    'background-color': '#FFFA54',
  },
  youtube: {
    src: `${IMG_BASE_URL}youtube.png`,
    'background-color': '#EB3323',
  },
  tumblr: {
    src: `${IMG_BASE_URL}tumblr.png`,
    'share-url':
      'https://www.tumblr.com/widgets/share/tool?canonicalUrl=[[URL]]',
    'background-color': '#344356',
  },
  github: {
    src: `${IMG_BASE_URL}github.png`,
    'background-color': '#000000',
  },
  xing: {
    src: `${IMG_BASE_URL}xing.png`,
    'share-url': 'https://www.xing.com/app/user?op=share&url=[[URL]]',
    'background-color': '#296366',
  },
  vimeo: {
    src: `${IMG_BASE_URL}vimeo.png`,
    'background-color': '#53B4E7',
  },
  medium: {
    src: `${IMG_BASE_URL}medium.png`,
    'background-color': '#000000',
  },
  soundcloud: {
    src: `${IMG_BASE_URL}soundcloud.png`,
    'background-color': '#EF7F31',
  },
  dribbble: {
    src: `${IMG_BASE_URL}dribbble.png`,
    'background-color': '#D95988',
  },
}

each(defaultSocialNetworks, (val, key) => {
  defaultSocialNetworks[`${key}-noshare`] = {
    ...val,
    'share-url': '[[URL]]',
  }
})

export default class MjSocialElement extends BodyComponent {
  static endingTag = true

  static allowedAttributes = {
    align: 'enum(left,center,right)',
    'background-color': 'color',
    color: 'color',
    'border-radius': 'unit(px)',
    'font-family': 'string',
    'font-size': 'unit(px)',
    'font-style': 'string',
    'font-weight': 'string',
    href: 'string',
    'icon-size': 'unit(px,%)',
    'icon-height': 'unit(px,%)',
    'icon-padding': 'unit(px,%){1,4}',
    'line-height': 'unit(px,%,)',
    name: 'string',
    'padding-bottom': 'unit(px,%)',
    'padding-left': 'unit(px,%)',
    'padding-right': 'unit(px,%)',
    'padding-top': 'unit(px,%)',
    padding: 'unit(px,%){1,4}',
    'text-padding': 'unit(px,%){1,4}',
    src: 'string',
    alt: 'string',
    title: 'string',
    target: 'string',
    'text-decoration': 'string',
  }

  static defaultAttributes = {
    align: 'left',
    color: '#000',
    'border-radius': '3px',
    'font-family': 'Ubuntu, Helvetica, Arial, sans-serif',
    'font-size': '13px',
    'line-height': '1',
    padding: '4px',
    'text-padding': '4px 4px 4px 0',
    target: '_blank',
    'text-decoration': 'none',
  }

  getStyles() {
    const {
      'icon-size': iconSize,
      'icon-height': iconHeight,
      'background-color': backgroundColor,
    } = this.getSocialAttributes()

    return {
      td: {
        padding: this.getAttribute('padding'),
      },
      table: {
        background: backgroundColor,
        'border-radius': this.getAttribute('border-radius'),
        width: iconSize,
      },
      icon: {
        padding: this.getAttribute('icon-padding'),
        'font-size': '0',
        height: iconHeight || iconSize,
        'vertical-align': 'middle',
        width: iconSize,
      },
      img: {
        'border-radius': this.getAttribute('border-radius'),
        display: 'block',
      },
      tdText: {
        'vertical-align': 'middle',
        padding: this.getAttribute('text-padding'),
      },
      text: {
        color: this.getAttribute('color'),
        'font-size': this.getAttribute('font-size'),
        'font-weight': this.getAttribute('font-weight'),
        'font-style': this.getAttribute('font-style'),
        'font-family': this.getAttribute('font-family'),
        'line-height': this.getAttribute('line-height'),
        'text-decoration': this.getAttribute('text-decoration'),
      },
    }
  }

  getSocialAttributes() {
    const socialNetwork = defaultSocialNetworks[this.getAttribute('name')] || {}
    let href = this.getAttribute('href')

    if (href && get(socialNetwork, 'share-url')) {
      href = socialNetwork['share-url'].replace('[[URL]]', href)
    }

    const attrs = [
      'icon-size',
      'icon-height',
      'src',
      'background-color',
    ].reduce(
      (r, attr) => ({
        ...r,
        [attr]: this.getAttribute(attr) || socialNetwork[attr],
      }),
      {},
    )

    return {
      href,
      ...attrs,
    }
  }

  render() {
    const {
      src,
      href,
      'icon-size': iconSize,
      'icon-height': iconHeight,
    } = this.getSocialAttributes()

    const hasLink = !!this.getAttribute('href')

    return `

                ${
                  hasLink
                    ? ``
                    : ''
                }

                  ${hasLink ? `</a>` : ''}

        ${
          this.getContent()
            ? `

            ${
              hasLink
                ? ``
                : ``
            }
              ${this.getContent()}
            ${hasLink ? `</a>` : ''}

          `
            : ''
        }

    `
  }
}
<commit_msg>change to new twitter share link<commit_after>import { BodyComponent } from 'mjml-core'
import { get, each } from 'lodash'

const IMG_BASE_URL = 'https://www.mailjet.com/images/theme/v1/icons/ico-social/'

const defaultSocialNetworks = {
  facebook: {
    'share-url': 'https://www.facebook.com/sharer/sharer.php?u=[[URL]]',
    'background-color': '#3b5998',
    src: `${IMG_BASE_URL}facebook.png`,
  },
  twitter: {
    'share-url': 'https://twitter.com/intent/tweet?url=[[URL]]',
    'background-color': '#55acee',
    src: `${IMG_BASE_URL}twitter.png`,
  },
  google: {
    'share-url': 'https://plus.google.com/share?url=[[URL]]',
    'background-color': '#dc4e41',
    src: `${IMG_BASE_URL}google-plus.png`,
  },
  pinterest: {
    'share-url':
      'https://pinterest.com/pin/create/button/?url=[[URL]]&media=&description=',
    'background-color': '#bd081c',
    src: `${IMG_BASE_URL}pinterest.png`,
  },
  linkedin: {
    'share-url':
      'https://www.linkedin.com/shareArticle?mini=true&url=[[URL]]&title=&summary=&source=',
    'background-color': '#0077b5',
    src: `${IMG_BASE_URL}linkedin.png`,
  },
  instagram: {
    'background-color': '#3f729b',
    src: `${IMG_BASE_URL}instagram.png`,
  },
  web: {
    src: `${IMG_BASE_URL}web.png`,
    'background-color': '#4BADE9',
  },
  snapchat: {
    src: `${IMG_BASE_URL}snapchat.png`,
    'background-color': '#FFFA54',
  },
  youtube: {
    src: `${IMG_BASE_URL}youtube.png`,
    'background-color': '#EB3323',
  },
  tumblr: {
    src: `${IMG_BASE_URL}tumblr.png`,
    'share-url':
      'https://www.tumblr.com/widgets/share/tool?canonicalUrl=[[URL]]',
    'background-color': '#344356',
  },
  github: {
    src: `${IMG_BASE_URL}github.png`,
    'background-color': '#000000',
  },
  xing: {
    src: `${IMG_BASE_URL}xing.png`,
    'share-url': 'https://www.xing.com/app/user?op=share&url=[[URL]]',
    'background-color': '#296366',
  },
  vimeo: {
    src: `${IMG_BASE_URL}vimeo.png`,
    'background-color': '#53B4E7',
  },
  medium: {
    src: `${IMG_BASE_URL}medium.png`,
    'background-color': '#000000',
  },
  soundcloud: {
    src: `${IMG_BASE_URL}soundcloud.png`,
    'background-color': '#EF7F31',
  },
  dribbble: {
    src: `${IMG_BASE_URL}dribbble.png`,
    'background-color': '#D95988',
  },
}

each(defaultSocialNetworks, (val, key) => {
  defaultSocialNetworks[`${key}-noshare`] = {
    ...val,
    'share-url': '[[URL]]',
  }
})

export default class MjSocialElement extends BodyComponent {
  static endingTag = true

  static allowedAttributes = {
    align: 'enum(left,center,right)',
    'background-color': 'color',
    color: 'color',
    'border-radius': 'unit(px)',
    'font-family': 'string',
    'font-size': 'unit(px)',
    'font-style': 'string',
    'font-weight': 'string',
    href: 'string',
    'icon-size': 'unit(px,%)',
    'icon-height': 'unit(px,%)',
    'icon-padding': 'unit(px,%){1,4}',
    'line-height': 'unit(px,%,)',
    name: 'string',
    'padding-bottom': 'unit(px,%)',
    'padding-left': 'unit(px,%)',
    'padding-right': 'unit(px,%)',
    'padding-top': 'unit(px,%)',
    padding: 'unit(px,%){1,4}',
    'text-padding': 'unit(px,%){1,4}',
    src: 'string',
    alt: 'string',
    title: 'string',
    target: 'string',
    'text-decoration': 'string',
  }

  static defaultAttributes = {
    align: 'left',
    color: '#000',
    'border-radius': '3px',
    'font-family': 'Ubuntu, Helvetica, Arial, sans-serif',
    'font-size': '13px',
    'line-height': '1',
    padding: '4px',
    'text-padding': '4px 4px 4px 0',
    target: '_blank',
    'text-decoration': 'none',
  }

  getStyles() {
    const {
      'icon-size': iconSize,
      'icon-height': iconHeight,
      'background-color': backgroundColor,
    } = this.getSocialAttributes()

    return {
      td: {
        padding: this.getAttribute('padding'),
      },
      table: {
        background: backgroundColor,
        'border-radius': this.getAttribute('border-radius'),
        width: iconSize,
      },
      icon: {
        padding: this.getAttribute('icon-padding'),
        'font-size': '0',
        height: iconHeight || iconSize,
        'vertical-align': 'middle',
        width: iconSize,
      },
      img: {
        'border-radius': this.getAttribute('border-radius'),
        display: 'block',
      },
      tdText: {
        'vertical-align': 'middle',
        padding: this.getAttribute('text-padding'),
      },
      text: {
        color: this.getAttribute('color'),
        'font-size': this.getAttribute('font-size'),
        'font-weight': this.getAttribute('font-weight'),
        'font-style': this.getAttribute('font-style'),
        'font-family': this.getAttribute('font-family'),
        'line-height': this.getAttribute('line-height'),
        'text-decoration': this.getAttribute('text-decoration'),
      },
    }
  }

  getSocialAttributes() {
    const socialNetwork = defaultSocialNetworks[this.getAttribute('name')] || {}
    let href = this.getAttribute('href')

    if (href && get(socialNetwork, 'share-url')) {
      href = socialNetwork['share-url'].replace('[[URL]]', href)
    }

    const attrs = [
      'icon-size',
      'icon-height',
      'src',
      'background-color',
    ].reduce(
      (r, attr) => ({
        ...r,
        [attr]: this.getAttribute(attr) || socialNetwork[attr],
      }),
      {},
    )

    return {
      href,
      ...attrs,
    }
  }

  render() {
    const {
      src,
      href,
      'icon-size': iconSize,
      'icon-height': iconHeight,
    } = this.getSocialAttributes()

    const hasLink = !!this.getAttribute('href')

    return `

                ${
                  hasLink
                    ? ``
                    : ''
                }

                  ${hasLink ? `</a>` : ''}

        ${
          this.getContent()
            ? `

            ${
              hasLink
                ? ``
                : ``
            }
              ${this.getContent()}
            ${hasLink ? `</a>` : ''}

          `
            : ''
        }

    `
  }
}
<|endoftext|>


<commit_before>const fs      = require('fs')
const path    = require('path')
const {name}  = require('./package.json')
const {spawn} = require('child_process')

// TODO: make it work
/* make sure pkg will pick up only needed binaries */
const binaries = {
    'darwin': [
        path.join(__dirname, 'node_modules/ffmpeg-static/bin/darwin/x64/ffmpeg'),
        path.join(__dirname, '../../ffmpeg-static/bin/darwin/x64/ffmpeg'),
    ],
    'win32': [
        path.join(__dirname, 'node_modules/ffmpeg-static/bin/win32/x64/ffmpeg.exe'),
        path.join(__dirname, '../../ffmpeg-static/bin/win32/x64/ffmpeg.exe'),
    ]
}

// /snapshot/nexrender/packages/nexrender-cli/node_modules/@nexrender/core/node_modules/@nexrender/action-encode/node_modules/ffmpeg-static/bin/darwin/x64/ffmpeg

const getBinary = (job, settings) => {
    return new Promise((resolve, reject) => {
        if (process.pkg) {
            const output = path.join(job.workpath, process.platform == 'win32' ? 'ffmpeg.exe' : 'ffmpeg')

            if (fs.existsSync(output)) {
                return resolve(output);
            }

            const binpath = binaries[process.platform].filter(file => fs.existsSync(file))[0]
            const rd = fs.createReadStream(binpath)
            const wr = fs.createWriteStream(output)

            const handleError = err => {
                rd.destroy()
                wr.end()
                reject(err)
            }

            rd.on('error', handleError)
            wr.on('error', handleError)

            wr.on('close', () => {
                fs.chmodSync(output, 0o765)
                resolve(output)
            })

            rd.pipe(wr);

        } else {
            const mymodule = 'ffmpeg'; /* prevent pkg from including everything */
            resolve(require(mymodule + '-static').path)
        }
    })
}

/* pars of snippet taken from https://github.com/xonecas/ffmpeg-node/blob/master/ffmpeg-node.js#L136 */
const constructParams = (job, settings, { preset, input, output, params }) => {
    input = input || job.output;

    if (!path.isAbsolute(input)) input = path.join(job.workpath, input);
    if (!path.isAbsolute(output)) output = path.join(job.workpath, output);

    settings.logger.log(`[${job.uid}] action-encode: input file ${input}`)
    settings.logger.log(`[${job.uid}] action-encode: output file ${output}`)

    switch(preset) {
        case 'mp4':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'aac',
                '-ab': '128k',
                '-ar': '44100',
                '-vcodec': 'libx264',
                '-r': '25',
                '-pix_fmt' : 'yuv420p',
            }, params, {
              '-y': output
            });
        break;

        case 'ogg':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'libvorbis',
                '-ab': '128k',
                '-ar': '44100',
                '-vcodec': 'libtheora',
                '-r': '25',
            }, params, {
                '-y': output
            });
        break;

        case 'webm':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'libvorbis',
                '-ab': '128k',
                '-ar': '44100',
                '-vcodec': 'libvpx',
                '-b': '614400',
                '-aspect': '16:9',
            }, params, {
                '-y': output
            });
        break;

        case 'mp3':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'libmp3lame',
                '-ab': '128k',
                '-ar': '44100',
            }, params, {
                '-y': output
            });
        break;

        case 'm4a':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'aac',
                '-ab': '64k',
                '-ar': '44100',
                '-strict': '-2',
            }, params, {
                '-y': output
            });
        break;

        default:
            params = Object.assign({}, {
                '-i': input
            }, params, {
                '-y': output
            });
        break;
    }

    /* convert to plain array */
    return Object.keys(params).reduce(
        (cur, key) => cur.concat(key, params[key]), []
    );
}

module.exports = (job, settings, options, type) => {
    settings.logger.log(`[${job.uid}] starting action-encode action (ffmpeg)`)

    return new Promise((resolve, reject) => {
        const params = constructParams(job, settings, options);
        const binary = getBinary(job, settings).then(binary => {
            const instance = spawn(binary, params);

            instance.on('error', err => reject(new Error(`Error starting ffmpeg process: ${err}`)));
            instance.stderr.on('data', (data) => settings.logger.log(`[${job.uid}] ${data.toString()}`));
            instance.stdout.on('data', (data) => settings.debug && settings.logger.log(`[${job.uid}] ${data.toString()}`));

            /* on finish (code 0 - success, other - error) */
            instance.on('close', (code) => {
                if (code !== 0) {
                    return reject(new Error('Error in action-encode module (ffmpeg)'))
                }

                resolve(job)
            });
        }).catch(e => {
            return reject(new Error('Error in action-encode module (ffmpeg)'))
        });
    });
}
<commit_msg>Update index.js<commit_after>const fs      = require('fs')
const path    = require('path')
const {name}  = require('./package.json')
const {spawn} = require('child_process')

// TODO: make it work
/* make sure pkg will pick up only needed binaries */
const binaries = {
    'darwin': [
        path.join(__dirname, 'node_modules/ffmpeg-static/bin/darwin/x64/ffmpeg'),
        path.join(__dirname, '../../ffmpeg-static/bin/darwin/x64/ffmpeg'),
    ],
    'win32': [
        path.join(__dirname, 'node_modules/ffmpeg-static/bin/win32/x64/ffmpeg.exe'),
        path.join(__dirname, '../../ffmpeg-static/bin/win32/x64/ffmpeg.exe'),
    ]
}

// /snapshot/nexrender/packages/nexrender-cli/node_modules/@nexrender/core/node_modules/@nexrender/action-encode/node_modules/ffmpeg-static/bin/darwin/x64/ffmpeg

const getBinary = (job, settings) => {
    return new Promise((resolve, reject) => {
        if (process.pkg) {
            const output = path.join(job.workpath, process.platform == 'win32' ? 'ffmpeg.exe' : 'ffmpeg')

            if (fs.existsSync(output)) {
                return resolve(output);
            }

            const binpath = binaries[process.platform].filter(file => fs.existsSync(file))[0]
            const rd = fs.createReadStream(binpath)
            const wr = fs.createWriteStream(output)

            const handleError = err => {
                rd.destroy()
                wr.end()
                reject(err)
            }

            rd.on('error', handleError)
            wr.on('error', handleError)

            wr.on('close', () => {
                fs.chmodSync(output, 0o765)
                resolve(output)
            })

            rd.pipe(wr);

        } else {
            const mymodule = 'ffmpeg'; /* prevent pkg from including everything */
            resolve(require(mymodule + '-static').path)
        }
    })
}

/* pars of snippet taken from https://github.com/xonecas/ffmpeg-node/blob/master/ffmpeg-node.js#L136 */
const constructParams = (job, settings, { preset, input, output, params }) => {
    input = input || job.output;

    if (!path.isAbsolute(input)) input = path.join(job.workpath, input);
    if (!path.isAbsolute(output)) output = path.join(job.workpath, output);

    settings.logger.log(`[${job.uid}] action-encode: input file ${input}`)
    settings.logger.log(`[${job.uid}] action-encode: output file ${output}`)

    switch(preset) {
        case 'mp4':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'aac',
                '-ab': '128k',
                '-ar': '44100',
                '-vcodec': 'libx264',
                '-r': '25',
                '-pix_fmt' : 'yuv420p',
            }, params, {
              '-y': output
            });
        break;

        case 'ogg':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'libvorbis',
                '-ab': '128k',
                '-ar': '44100',
                '-vcodec': 'libtheora',
                '-r': '25',
            }, params, {
                '-y': output
            });
        break;

        case 'webm':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'libvorbis',
                '-ab': '128k',
                '-ar': '44100',
                '-vcodec': 'libvpx',
                '-b': '614400',
                '-aspect': '16:9',
            }, params, {
                '-y': output
            });
        break;

        case 'mp3':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'libmp3lame',
                '-ab': '128k',
                '-ar': '44100',
            }, params, {
                '-y': output
            });
        break;

        case 'm4a':
            params = Object.assign({}, {
                '-i': input,
                '-acodec': 'aac',
                '-ab': '64k',
                '-ar': '44100',
                '-strict': '-2',
            }, params, {
                '-y': output
            });
        break;

        default:
            params = Object.assign({}, {
                '-i': input
            }, params, {
                '-y': output
            });
        break;
    }

    /* convert to plain array */
    return Object.keys(params).reduce(
        (cur, key) => cur.concat(key, params[key]), []
    );
}

module.exports = (job, settings, options, type) => {
    settings.logger.log(`[${job.uid}] starting action-encode action (ffmpeg)`)

    return new Promise((resolve, reject) => {
        const params = constructParams(job, settings, options);
        const binary = getBinary(job, settings).then(binary => {
            const instance = spawn(binary, params);

            instance.on('error', err => reject(new Error(`Error starting ffmpeg process: ${err}`)));
            instance.stderr.on('data', (data) => settings.logger.log(`[${job.uid}] ${data.toString()}`));
            instance.stdout.on('data', (data) => settings.debug && settings.logger.log(`[${job.uid}] ${data.toString()}`));

            /* on finish (code 0 - success, other - error) */
            instance.on('close', (code) => {
                if (code !== 0) {
                    return reject(new Error('Error in action-encode module (ffmpeg) code : ' + code))
                }

                resolve(job)
            });
        }).catch(e => {
            return reject(new Error('Error in action-encode module (ffmpeg) ' + e))
        });
    });
}
<|endoftext|>


<commit_before>fabric.ElementsParser = function(elements, callback, options, reviver) {
  this.elements = elements;
  this.callback = callback;
  this.options = options;
  this.reviver = reviver;

  this.parse = function() {

    this.instances = new Array(this.elements.length);
    this.numElements = this.elements.length;

    this.createObjects();
  },

  this.createObjects = function() {
    for (var i = 0, len = this.elements.length; i < len; i++) {
      (function(_this, i) {
        setTimeout(function() {
          _this.createObject(_this.elements[i], i);
        }, 0);
      })(this, i);
    }
  },

  this.createObject = function(el, index) {
    var klass = fabric[fabric.util.string.capitalize(el.tagName)];
    if (klass && klass.fromElement) {
      try {
        this._createObject(klass, el, index);
      }
      catch (err) {
        fabric.log(err);
      }
    }
    else {
      this.checkIfDone();
    }
  },

  this._createObject = function(klass, el, index) {
    if (klass.async) {
      klass.fromElement(el, this.createCallback(index, el), this.options);
    }
    else {
      var obj = klass.fromElement(el, this.options);
      this.reviver && this.reviver(el, obj);
      this.instances.splice(index, 0, obj);
      this.checkIfDone();
    }
  },

  this.createCallback = function(index, el) {
    var _this = this;
    return function(obj) {
      _this.reviver && _this.reviver(el, obj);
      _this.instances.splice(index, 0, obj);
      _this.checkIfDone();
    };
  },

  this.checkIfDone = function() {
    if (--this.numElements === 0) {
      this.instances = this.instances.filter(function(el) {
        return el != null;
      });
      fabric.resolveGradients(this.instances);
      this.callback(this.instances);
    }
  }
};
<commit_msg>Added semicolon to satisfy jshint<commit_after>fabric.ElementsParser = function(elements, callback, options, reviver) {
  this.elements = elements;
  this.callback = callback;
  this.options = options;
  this.reviver = reviver;

  this.parse = function() {

    this.instances = new Array(this.elements.length);
    this.numElements = this.elements.length;

    this.createObjects();
  },

  this.createObjects = function() {
    for (var i = 0, len = this.elements.length; i < len; i++) {
      (function(_this, i) {
        setTimeout(function() {
          _this.createObject(_this.elements[i], i);
        }, 0);
      })(this, i);
    }
  },

  this.createObject = function(el, index) {
    var klass = fabric[fabric.util.string.capitalize(el.tagName)];
    if (klass && klass.fromElement) {
      try {
        this._createObject(klass, el, index);
      }
      catch (err) {
        fabric.log(err);
      }
    }
    else {
      this.checkIfDone();
    }
  },

  this._createObject = function(klass, el, index) {
    if (klass.async) {
      klass.fromElement(el, this.createCallback(index, el), this.options);
    }
    else {
      var obj = klass.fromElement(el, this.options);
      this.reviver && this.reviver(el, obj);
      this.instances.splice(index, 0, obj);
      this.checkIfDone();
    }
  },

  this.createCallback = function(index, el) {
    var _this = this;
    return function(obj) {
      _this.reviver && _this.reviver(el, obj);
      _this.instances.splice(index, 0, obj);
      _this.checkIfDone();
    };
  },

  this.checkIfDone = function() {
    if (--this.numElements === 0) {
      this.instances = this.instances.filter(function(el) {
        return el != null;
      });
      fabric.resolveGradients(this.instances);
      this.callback(this.instances);
    }
  };
};
<|endoftext|>


<commit_before>'use strict';

var questionView = {
  $getOptions: $( '.get-options' ),
  $followupNoNotSure: $( '.followup__no-not-sure' ),
  $followupYes: $( '.followup__yes' ),
  $nextSteps: $( '.next-steps' ),
  $feedback: $( '.feedback' ),

  init: function() {
    this.$followupNoNotSure.hide();
    this.$followupYes.hide();
    this.$getOptions.hide();
    this.$nextSteps.hide();
    this.$feedback.hide();
    this.bigQuestionListener();
  },

  bigQuestionListener: function() {
    $( '.question_answers > .btn' ).on( 'click', function() {
      if ( $( this ).attr( 'id' ) === 'question_answer-yes' ) {
        questionView.$followupYes.show();
        questionView.$followupNoNotSure.hide();
      } else {
        questionView.$followupNoNotSure.show();
        questionView.$followupYes.hide();
      }
      // Show the rest of the page with a 600 millisecond animation.
      questionView.$getOptions.show( 'slow' );
      questionView.$nextSteps.show( 'slow' );
      questionView.$feedback.show( 'slow' );
    } );
  }

};

module.exports = questionView;
<commit_msg>Remove hide()s on page load (already done with CSS)<commit_after>'use strict';

var questionView = {
  $getOptions: $( '.get-options' ),
  $followupNoNotSure: $( '.followup__no-not-sure' ),
  $followupYes: $( '.followup__yes' ),
  $nextSteps: $( '.next-steps' ),
  $feedback: $( '.feedback' ),

  init: function() {
    this.bigQuestionListener();
  },

  bigQuestionListener: function() {
    $( '.question_answers > .btn' ).on( 'click', function() {
      if ( $( this ).attr( 'id' ) === 'question_answer-yes' ) {
        questionView.$followupYes.show();
        questionView.$followupNoNotSure.hide();
      } else {
        questionView.$followupNoNotSure.show();
        questionView.$followupYes.hide();
      }
      // Show the rest of the page with a 600 millisecond animation.
      questionView.$getOptions.show( 'slow' );
      questionView.$nextSteps.show( 'slow' );
      questionView.$feedback.show( 'slow' );
    } );
  }

};

module.exports = questionView;
<|endoftext|>


<commit_before>Player = Creature.extend(
{
	WalkAnimationSpeed : 10,
	ActionAnimations:
	{
		"Shoot" : [ 4, 7, 3 ]
	},

    initialize: function(){
        var playerSpeed = gameContainer.conf.get("PLAYER_SPEED");
        var playerSize = gameContainer.conf.get("PLAYER_SIZE");

    	var model = this;
//    	var entity = Crafty.e("2D, Canvas, malePlayer, KeyMoveControls, Mouse, Hero, Animate, Collision")
//    	var entity = Crafty.e("2D, Canvas, malePlayer, KeyMoveControls, Mouse, Hero")
	    var entity = Crafty.e("2D, Canvas, mage, Body, Pawn, Hero, BodyAnimations, Damageable, NavigationHandle, HeroControl, AbilityUser, DebugRendering")
		    .attr({x: 160, y: 144, z: 1, w:playerSize, h:playerSize, Faction : Factions.Monk, MovementSpeed: 0.2, MaxHealth : 300 });

	    for (var slot in SpellBook)
	    {
		    var data = SpellBook[slot];
		    var ability = new data.Type();
		    for (var key in data)
		    {
			    if (key === "Type")
				    continue;
			    else if (key === "Costs")
			        continue;
			    else if (key === "Icon")
			        continue;

			    ability[key] = data[key];
		    }
		    entity.AddAbility(slot, ability);

		    if (data.Costs)
		    {
			    entity.AddSpell(slot, data.Costs, data.Icon);
		    }
	    }

	    // must bind to visual updated but not BodyMoved, otherwise could cause the map redraw twice
	    entity.bind("VisualUpdated", this.followCamera.bind(this));

    	model.set({'entity' : entity });

	    this._setupAnimations();
    },

	followCamera: function()
	{
		//if (this._x === undefined || this._y === undefined)
		//	return;
		var entity = this.getEntity();

		var center = entity.GetCenterReal();
		var x0 = center.x - Crafty.viewport.width / 2,
			y0 = center.y - Crafty.viewport.height / 2;
		if (x0 < 0) x0 = 0;
		if (y0 < 0) y0 = 0;

		var tileMap = entity._world.TileMap;
		if (x0 + Crafty.viewport.width > tileMap._width)
			x0 = tileMap._width - Crafty.viewport.width;
		if (y0 + Crafty.viewport.height > tileMap._height)
			y0 = tileMap._height - Crafty.viewport.height;
		Crafty.viewport.scrollTo(-x0, -y0);
	}
});

var SpellBook =
{
	Fireball :
	{
		Type : Ability_Shoot,
		PlayAnim : true,
		Projectile : FireBall
	},

	FlamingHound :
	{
		Costs : { 'light' : 0, 'fire' : 1 },
		Icon : 'flamingHoundIcon',
		Type : Ability_Spell,
		PlayAnim : true,
		Spell :
		{
			Pattern : SpellPatterns.Line,
			Projectile : FlamingHound,
			Total : 6
		}
	},

	LightningStrike :
	{
		Costs : { 'light' : 1, 'dark' : 0 },
		Icon : 'lightningStrikeIcon',
		Type : Ability_Spell,
		PlayAnim : true,
		Spell :
		{
			Pattern : SpellPatterns.Area,
			Projectile : Lightning,
			Radius : 9,
			Total : 15
		}
	}
};
<commit_msg>Revert the spell value<commit_after>Player = Creature.extend(
{
	WalkAnimationSpeed : 10,
	ActionAnimations:
	{
		"Shoot" : [ 4, 7, 3 ]
	},

    initialize: function(){
        var playerSpeed = gameContainer.conf.get("PLAYER_SPEED");
        var playerSize = gameContainer.conf.get("PLAYER_SIZE");

    	var model = this;
//    	var entity = Crafty.e("2D, Canvas, malePlayer, KeyMoveControls, Mouse, Hero, Animate, Collision")
//    	var entity = Crafty.e("2D, Canvas, malePlayer, KeyMoveControls, Mouse, Hero")
	    var entity = Crafty.e("2D, Canvas, mage, Body, Pawn, Hero, BodyAnimations, Damageable, NavigationHandle, HeroControl, AbilityUser, DebugRendering")
		    .attr({x: 160, y: 144, z: 1, w:playerSize, h:playerSize, Faction : Factions.Monk, MovementSpeed: 0.2, MaxHealth : 300 });

	    for (var slot in SpellBook)
	    {
		    var data = SpellBook[slot];
		    var ability = new data.Type();
		    for (var key in data)
		    {
			    if (key === "Type")
				    continue;
			    else if (key === "Costs")
			        continue;
			    else if (key === "Icon")
			        continue;

			    ability[key] = data[key];
		    }
		    entity.AddAbility(slot, ability);

		    if (data.Costs)
		    {
			    entity.AddSpell(slot, data.Costs, data.Icon);
		    }
	    }

	    // must bind to visual updated but not BodyMoved, otherwise could cause the map redraw twice
	    entity.bind("VisualUpdated", this.followCamera.bind(this));

    	model.set({'entity' : entity });

	    this._setupAnimations();
    },

	followCamera: function()
	{
		//if (this._x === undefined || this._y === undefined)
		//	return;
		var entity = this.getEntity();

		var center = entity.GetCenterReal();
		var x0 = center.x - Crafty.viewport.width / 2,
			y0 = center.y - Crafty.viewport.height / 2;
		if (x0 < 0) x0 = 0;
		if (y0 < 0) y0 = 0;

		var tileMap = entity._world.TileMap;
		if (x0 + Crafty.viewport.width > tileMap._width)
			x0 = tileMap._width - Crafty.viewport.width;
		if (y0 + Crafty.viewport.height > tileMap._height)
			y0 = tileMap._height - Crafty.viewport.height;
		Crafty.viewport.scrollTo(-x0, -y0);
	}
});

var SpellBook =
{
	Fireball :
	{
		Type : Ability_Shoot,
		PlayAnim : true,
		Projectile : FireBall
	},

	FlamingHound :
	{
		Costs : { 'light' : 1, 'fire' : 3 },
		Icon : 'flamingHoundIcon',
		Type : Ability_Spell,
		PlayAnim : true,
		Spell :
		{
			Pattern : SpellPatterns.Line,
			Projectile : FlamingHound,
			Total : 6
		}
	},

	LightningStrike :
	{
		Costs : { 'light' : 3, 'dark' : 1 },
		Icon : 'lightningStrikeIcon',
		Type : Ability_Spell,
		PlayAnim : true,
		Spell :
		{
			Pattern : SpellPatterns.Area,
			Projectile : Lightning,
			Radius : 9,
			Total : 15
		}
	}
};
<|endoftext|>


<commit_before>import { ModelExperimental, when } from "../../../Source/Cesium.js";
import pollToPromise from "../../pollToPromise.js";

function loadAndZoomToModelExperimental(options, scene) {

  var model;

  try {
    model = ModelExperimental.fromGltf({
      content: options.content,
      color: options.color,
      gltf: options.gltf,
      show: options.show,
      customShader: options.customShader,
      basePath: options.basePath,
      modelMatrix: options.modelMatrix,
      allowPicking: options.allowPicking,
      upAxis: options.upAxis,
      forwardAxis: options.forwardAxis,
      debugShowBoundingVolume: options.debugShowBoundingVolume,
      featureIdAttributeIndex: options.featureIdAttributeIndex,
      featureIdTextureIndex: options.featureIdTextureIndex,
      incrementallyLoadTextures: options.incrementallyLoadTextures
    });
  } catch (error) {
    return when.reject(error);
  }

  scene.primitives.add(model);

  var finished = false;
  var rejected = false;
  model.readyPromise
    .otherwise(function () {
      rejected = true;
    })
    .always(function () {
      finished = true;
    });

  return pollToPromise(
    function () {
      scene.renderForSpecs();
      return finished;
    },
    { timeout: 10000 }
  ).then(function () {
    if (rejected) {
      return model.readyPromise;
    }
    scene.camera.flyToBoundingSphere(model.boundingSphere, {
      duration: 0,
      offset: options.offset,
    });
    return model.readyPromise;
  });
}

export default loadAndZoomToModelExperimental;
<commit_msg>Runs prettier<commit_after>import { ModelExperimental, when } from "../../../Source/Cesium.js";
import pollToPromise from "../../pollToPromise.js";

function loadAndZoomToModelExperimental(options, scene) {
  var model;

  try {
    model = ModelExperimental.fromGltf({
      content: options.content,
      color: options.color,
      gltf: options.gltf,
      show: options.show,
      customShader: options.customShader,
      basePath: options.basePath,
      modelMatrix: options.modelMatrix,
      allowPicking: options.allowPicking,
      upAxis: options.upAxis,
      forwardAxis: options.forwardAxis,
      debugShowBoundingVolume: options.debugShowBoundingVolume,
      featureIdAttributeIndex: options.featureIdAttributeIndex,
      featureIdTextureIndex: options.featureIdTextureIndex,
      incrementallyLoadTextures: options.incrementallyLoadTextures,
    });
  } catch (error) {
    return when.reject(error);
  }

  scene.primitives.add(model);

  var finished = false;
  var rejected = false;
  model.readyPromise
    .otherwise(function () {
      rejected = true;
    })
    .always(function () {
      finished = true;
    });

  return pollToPromise(
    function () {
      scene.renderForSpecs();
      return finished;
    },
    { timeout: 10000 }
  ).then(function () {
    if (rejected) {
      return model.readyPromise;
    }
    scene.camera.flyToBoundingSphere(model.boundingSphere, {
      duration: 0,
      offset: options.offset,
    });
    return model.readyPromise;
  });
}

export default loadAndZoomToModelExperimental;
<|endoftext|>


<commit_before>//webhooks.js: Client for the zendesk API.

var util        = require('util'),
  Client      = require('./client').Client;

var Webhooks = exports.Webhooks = function (options) {
  this.jsonAPINames = [ 'webhooks', 'webhook' ];
  Client.call(this, options);
};

// Inherit from Client base object
util.inherits(Webhooks, Client);

// ######################################################## Webhooks
// ====================================== Listing Webhooks
Webhooks.prototype.list = function (cb) {
  return this.requestAll('GET', '/webhooks', cb);//all
};

// ====================================== Viewing Webhooks
Webhooks.prototype.show = function (webhookID, cb) {
  return this.request('GET', `/webhooks/${webhookID}`, cb);
};

// ====================================== Creating Webhooks
Webhooks.prototype.create = function (webhook, cb) {
  return this.request('POST', '/webhooks', webhook,  cb);
};

// ====================================== Updating Webhooks
Webhooks.prototype.update = function (webhookID, webhook, cb) {
  return this.request('PUT', `/webhooks/${webhookID}`, webhook,  cb);
};

// ====================================== Deleting Webhooks
Webhooks.prototype.delete = function (webhookID, cb) {
  return this.request('DELETE', `/webhooks/${webhookID}`,  cb);
};
<commit_msg>Pretty print<commit_after>//webhooks.js: Client for the zendesk API.

var util = require('util');
var Client = require('./client').Client;

var Webhooks = exports.Webhooks = function (options) {
  this.jsonAPINames = [ 'webhooks', 'webhook' ];
  Client.call(this, options);
};

// Inherit from Client base object
util.inherits(Webhooks, Client);

// ######################################################## Webhooks
// ====================================== Listing Webhooks
Webhooks.prototype.list = function (cb) {
  return this.requestAll('GET', '/webhooks', cb);//all
};

// ====================================== Viewing Webhooks
Webhooks.prototype.show = function (webhookID, cb) {
  return this.request('GET', `/webhooks/${webhookID}`, cb);
};

// ====================================== Creating Webhooks
Webhooks.prototype.create = function (webhook, cb) {
  return this.request('POST', '/webhooks', webhook,  cb);
};

// ====================================== Updating Webhooks
Webhooks.prototype.update = function (webhookID, webhook, cb) {
  return this.request('PUT', `/webhooks/${webhookID}`, webhook,  cb);
};

// ====================================== Deleting Webhooks
Webhooks.prototype.delete = function (webhookID, cb) {
  return this.request('DELETE', `/webhooks/${webhookID}`,  cb);
};
<|endoftext|>


<commit_before>/** section: scripty2 core
 * class Function
 *
 *  Extensions to the built-in `Function` object.
**/

/**
 *  Function#optionize() -> Function
 *
 *  Given a function whose last parameter is an object
 *  of options, return a function that accepts a variable
 *  number of arguments and always passes the last argument
 *  that is an object to the options parameter. This way,
 *  the function can be called with just options, leaving
 *  the other parameters undefined.
 *
 *      var logOptions = function(a, b, options){
 *        console.log(options);
 *      }.optionize();
 *      logOptions({hello: "world"}) -> logs {hello: "world"}
 *      logOptions(1, {hello: "world"}) -> logs {hello: "world"}
 *      logOptions(1, 2, {hello: "world"}) -> logs {hello: "world"}
 *
 *  But note that providing too many arguments will not work:
 *
 *      logOptions(1,2,3, {hello: "world"}) -> logs 3
**/
Function.prototype.optionize = function(){
  var self = this, argumentNames = self.argumentNames(), optionIndex = this.length - 1;

  var method = function() {
    var args = $A(arguments);

    var options = (typeof args.last() === 'object') ? args.pop() : {};
    var prefilledArgs = [];
    if (optionIndex > 0) {
      prefilledArgs = ((args.length > 0 ? args : [null]).inGroupsOf(
       optionIndex).flatten()).concat(options);
    }

    return self.apply(this, prefilledArgs);
  };
  method.argumentNames = function() { return argumentNames; };
  return method;
};

/** section: scripty2 core
 * class Number
 *
 *  Extensions to the built-in `Number` object.
**/
Object.extend(Number.prototype, {
  /**
   *  Number#constrain(min, max) -> Number
   *
   *  Returns `min` if number is less than `min`, `max` if number is greater
   *  than `max`. Returns itself otherwise.
  **/
  constrain: function(n1, n2) {
    var min = (n1 < n2) ? n1 : n2;
    var max = (n1 < n2) ? n2 : n1;

    var num = Number(this);

    if (num < min) num = min;
    if (num > max) num = max;

    return num;
  },

  /**
   *  Number#nearer(n1, n2) -> Number
   *
   *  Returns either `n1` or `n2` — whichever is closer to the number, in
   *  absolute terms.
  **/
  nearer: function(n1, n2) {
    var num = Number(this);

    var diff1 = Math.abs(num - n1);
    var diff2 = Math.abs(num - n2);

    return (diff1 < diff2) ? n1 : n2;
  },

  /**
   *  Number#tween(target, position) -> Number
   *  - target (Number): tween target
   *  - position (Number): position between 0 (start of tween) and (end of
   *    tween); can also be < 0 and > 1.
   *
   *  Returns the number that is a given percentage between this number and
   *  a target number.
   *
   *      (1).tween(2, 0.5) -> 1.5
   *      (1).tween(2, 0) -> 1
   *      (1).tween(2, 1) -> 2
  **/
  tween: function(target, position) {
    return this + (target-this) * position;
  }
});

/** section: scripty2 core
 * class Object
 *
 *  Extensions to the built-in `Object` object.
**/

/**
 *  Object.propertize(property, object) -> Object
 *  - property (String | Object): item or name of item
 *  - object (Object): namespace in which to look for named item
 *
 *  If `property` is a string, finds it in the provided `object`.
 *  Otherwise returns `property`.
 *
 *      Object.propertize(S2.FX.Transitions.sinusoidal, S2.FX.Transitions) -> S2.FX.Transitions.sinusoidal
 *      Object.propertize('sinusoidal', S2.FX.Transitions) -> S2.FX.Transitions.sinusoidal
 *
**/
Object.propertize = function(property, object){
  return Object.isString(property) ? object[property] : property;
};<commit_msg>Add `Function.ABSTRACT` for abstract methods.<commit_after>/** section: scripty2 core
 * class Function
 *
 *  Extensions to the built-in `Function` object.
**/

/**
 *  Function#optionize() -> Function
 *
 *  Given a function whose last parameter is an object
 *  of options, return a function that accepts a variable
 *  number of arguments and always passes the last argument
 *  that is an object to the options parameter. This way,
 *  the function can be called with just options, leaving
 *  the other parameters undefined.
 *
 *      var logOptions = function(a, b, options){
 *        console.log(options);
 *      }.optionize();
 *      logOptions({hello: "world"}) -> logs {hello: "world"}
 *      logOptions(1, {hello: "world"}) -> logs {hello: "world"}
 *      logOptions(1, 2, {hello: "world"}) -> logs {hello: "world"}
 *
 *  But note that providing too many arguments will not work:
 *
 *      logOptions(1,2,3, {hello: "world"}) -> logs 3
**/
Function.prototype.optionize = function(){
  var self = this, argumentNames = self.argumentNames(), optionIndex = this.length - 1;

  var method = function() {
    var args = $A(arguments);

    var options = (typeof args.last() === 'object') ? args.pop() : {};
    var prefilledArgs = [];
    if (optionIndex > 0) {
      prefilledArgs = ((args.length > 0 ? args : [null]).inGroupsOf(
       optionIndex).flatten()).concat(options);
    }

    return self.apply(this, prefilledArgs);
  };
  method.argumentNames = function() { return argumentNames; };
  return method;
};

Function.ABSTRACT = function() {
  throw "Abstract method. Implement in subclass.";
};

/** section: scripty2 core
 * class Number
 *
 *  Extensions to the built-in `Number` object.
**/
Object.extend(Number.prototype, {
  /**
   *  Number#constrain(min, max) -> Number
   *
   *  Returns `min` if number is less than `min`, `max` if number is greater
   *  than `max`. Returns itself otherwise.
  **/
  constrain: function(n1, n2) {
    var min = (n1 < n2) ? n1 : n2;
    var max = (n1 < n2) ? n2 : n1;

    var num = Number(this);

    if (num < min) num = min;
    if (num > max) num = max;

    return num;
  },

  /**
   *  Number#nearer(n1, n2) -> Number
   *
   *  Returns either `n1` or `n2` — whichever is closer to the number, in
   *  absolute terms.
  **/
  nearer: function(n1, n2) {
    var num = Number(this);

    var diff1 = Math.abs(num - n1);
    var diff2 = Math.abs(num - n2);

    return (diff1 < diff2) ? n1 : n2;
  },

  /**
   *  Number#tween(target, position) -> Number
   *  - target (Number): tween target
   *  - position (Number): position between 0 (start of tween) and (end of
   *    tween); can also be < 0 and > 1.
   *
   *  Returns the number that is a given percentage between this number and
   *  a target number.
   *
   *      (1).tween(2, 0.5) -> 1.5
   *      (1).tween(2, 0) -> 1
   *      (1).tween(2, 1) -> 2
  **/
  tween: function(target, position) {
    return this + (target-this) * position;
  }
});

/** section: scripty2 core
 * class Object
 *
 *  Extensions to the built-in `Object` object.
**/

/**
 *  Object.propertize(property, object) -> Object
 *  - property (String | Object): item or name of item
 *  - object (Object): namespace in which to look for named item
 *
 *  If `property` is a string, finds it in the provided `object`.
 *  Otherwise returns `property`.
 *
 *      Object.propertize(S2.FX.Transitions.sinusoidal, S2.FX.Transitions) -> S2.FX.Transitions.sinusoidal
 *      Object.propertize('sinusoidal', S2.FX.Transitions) -> S2.FX.Transitions.sinusoidal
 *
**/
Object.propertize = function(property, object){
  return Object.isString(property) ? object[property] : property;
};<|endoftext|>


<commit_before>import mkdirp from 'mkdirp';
import rmdir from 'rmdir';
import zipdir from 'zip-dir';
import fs from 'fs';
import path from 'path';
import { instance } from '../instance';
import _ from 'lodash';
import Promise from 'promise';

export function createDir(_owner, action) {
  return new Promise(function (resolve, reject) {
    const _instance = _owner.instance;
    _.forEach(_instance.folders, function(el, index) {
      mkdirp(el)
    });
    if (action.method === 'backup' || _owner.options.theme.startBackup) {
      _.forEach(_instance.assets, function(el, index) {
        rmdir(el.backup, function (err, dirs, files) {
          mkdirp(el.backup);
        });
      });
    }
    resolve();
  });
}

export function reloadDir(_owner, action) {
  return new Promise(function (resolve, reject) {
    const _instance = _owner.instance;
    if (action.method === 'backup') {
      _.forEach(_instance.assets, function(el, index) {
        rmdir(el.backup, function (err, dirs, files) {
          mkdirp(el.backup);
        });
      });
    }
    resolve();
  });
}

export function zippedDir(_owner, _path, _save_to, _filter) {
  return new Promise(function (resolve, reject) {
    var _today = new Date;
    var _date = `${_today.getFullYear()}-${_today.getMonth()}-${_today.getDate()}-${_today.getHours()}-${_today.getMinutes()}`

    console.info(`start zip ${_save_to}-${_date}.zip`);
    const _pathDir = path.normalize(_path);
    const _option = { saveTo: `${_pathDir}/${_save_to}-${_date}.zip` }

    if (_filter) {
      _option['filter'] = function (pathDirs, stat) {
        var _key = _.findKey(_owner.instance.assets, function(o) {
          var _pathNorm = path.normalize(o[_filter]).slice(0, -1);
          return pathDirs.indexOf(_pathNorm) > -1;
        })
        if (_key) {
          return true;
        }else{
          return false;
        }
      }
    }

    zipdir(_pathDir, _option, function (err, buffer) {
      if (err) {
        console.log(err)
      }else{
        console.info(`finish zip ${_save_to}-${_date}.zip`);
      }
      resolve();
    });
  });
}
<commit_msg>Правка даты<commit_after>import mkdirp from 'mkdirp';
import rmdir from 'rmdir';
import zipdir from 'zip-dir';
import fs from 'fs';
import path from 'path';
import { instance } from '../instance';
import _ from 'lodash';
import Promise from 'promise';

export function createDir(_owner, action) {
  return new Promise(function (resolve, reject) {
    const _instance = _owner.instance;
    _.forEach(_instance.folders, function(el, index) {
      mkdirp(el)
    });
    if (action.method === 'backup' || _owner.options.theme.startBackup) {
      _.forEach(_instance.assets, function(el, index) {
        rmdir(el.backup, function (err, dirs, files) {
          mkdirp(el.backup);
        });
      });
    }
    resolve();
  });
}

export function reloadDir(_owner, action) {
  return new Promise(function (resolve, reject) {
    const _instance = _owner.instance;
    if (action.method === 'backup') {
      _.forEach(_instance.assets, function(el, index) {
        rmdir(el.backup, function (err, dirs, files) {
          mkdirp(el.backup);
        });
      });
    }
    resolve();
  });
}

export function zippedDir(_owner, _path, _save_to, _filter) {
  return new Promise(function (resolve, reject) {
    var _today = new Date;
    var _month = _today.getMonth() + 1;
    var _date = `${_today.getFullYear()}-${_month}-${_today.getDate()}-${_today.getHours()}-${_today.getMinutes()}`

    console.info(`start zip ${_save_to}-${_date}.zip`);
    const _pathDir = path.normalize(_path);
    const _option = { saveTo: `${_pathDir}/${_save_to}-${_date}.zip` }

    if (_filter) {
      _option['filter'] = function (pathDirs, stat) {
        var _key = _.findKey(_owner.instance.assets, function(o) {
          var _pathNorm = path.normalize(o[_filter]).slice(0, -1);
          return pathDirs.indexOf(_pathNorm) > -1;
        })
        if (_key) {
          return true;
        }else{
          return false;
        }
      }
    }

    zipdir(_pathDir, _option, function (err, buffer) {
      if (err) {
        console.log(err)
      }else{
        console.info(`finish zip ${_save_to}-${_date}.zip`);
      }
      resolve();
    });
  });
}
<|endoftext|>