<commit_before>/* globals LinkPreview, LastRead, _ */
/* eslint-disable camelcase */
import { filter, isNull, omitBy, uniqBy } from 'lodash/fp'
import { flatten } from 'lodash'
import { normalizePost } from '../../lib/util/normalize'
import { pushToSockets } from '../services/Websockets'
import { addFollowers } from './post/util'
import { fulfillRequest, unfulfillRequest } from './post/request'
import EnsureLoad from './mixins/EnsureLoad'

const normalize = post => {
  const data = {communities: [], people: []}
  normalizePost(post, data, true)
  return Object.assign(data, post)
}

module.exports = bookshelf.Model.extend(Object.assign({
  // Instance Methods

  tableName: 'posts',

  user: function () {
    return this.belongsTo(User)
  },

  communities: function () {
    return this.belongsToMany(Community).through(PostMembership)
    .query({where: {'communities.active': true}})
  },

  followers: function () {
    return this.belongsToMany(User).through(Follow).withPivot('added_by_id')
  },

  contributions: function () {
    return this.hasMany(Contribution, 'post_id')
  },

  comments: function () {
    return this.hasMany(Comment, 'post_id').query({where: {active: true}})
  },

  lastReads: function () {
    return this.hasMany(LastRead)
  },

  media: function () {
    return this.hasMany(Media)
  },

  votes: function () {
    return this.hasMany(Vote)
  },

  responders: function () {
    return this.belongsToMany(User).through(EventResponse)
  },

  userVote: function (userId) {
    return this.votes().query({where: {user_id: userId}}).fetchOne()
  },

  relatedUsers: function () {
    return this.belongsToMany(User, 'posts_about_users')
  },

  tags: function () {
    return this.belongsToMany(Tag).through(PostTag).withPivot('selected')
  },

  // should only be one of these per post
  selectedTags: function () {
    return this.belongsToMany(Tag).through(PostTag).withPivot('selected')
    .query({where: {selected: true}})
  },

  children: function () {
    return this.hasMany(Post, 'parent_post_id')
    .query({where: {active: true}})
  },

  parent: function () {
    return this.belongsTo(Post, 'parent_post_id')
  },

  activities: function () {
    return this.hasMany(Activity)
  },

  linkPreview: function () {
    return this.belongsTo(LinkPreview)
  },

  getTagsInComments: function (opts) {
    // this is part of the 'taggable' interface, shared with Comment
    return this.load('comments.tags', opts)
    .then(() =>
      uniqBy('id', flatten(this.relations.comments.map(c => c.relations.tags.models))))
  },

  addFollowers: function (userIds, addedById, opts = {}) {
    return addFollowers(this, null, userIds, addedById, opts)
  },

  removeFollower: function (user_id, opts = {}) {
    return Follow.where({user_id, post_id: this.id}).destroy()
    .tap(() => this.isProject() && this.load(['selectedTags', 'communities'])
      .then(() => {
        const tag = this.relations.selectedTags.first()
        if (!tag) return
        return Promise.each(this.relations.communities.models, community =>
          TagFollow.remove(tag, user_id, community))
      }))
    .tap(() => opts.createActivity && Activity.forUnfollow(this, user_id).save()
      .then(activity => activity.createNotifications()))
  },

  isPublic: function () {
    return this.get('visibility') === Post.Visibility.PUBLIC_READABLE
  },

  isWelcome: function () {
    return this.get('type') === Post.Type.WELCOME
  },

  isProject: function () {
    return this.get('type') === Post.Type.PROJECT
  },

  isThread: function () {
    return this.get('type') === Post.Type.THREAD
  },

  pushCommentToSockets: function (comment) {
    var postId = this.id
    return pushToSockets(`posts/${postId}`, 'commentAdded', {comment})
  },

  pushMessageToSockets: function (message, userIds) {
    var postId = this.id
    const excludingSender = userIds.filter(id => id !== message.user_id.toString())
    if (this.get('num_comments') === 0) {
      return Promise.map(excludingSender, id => this.pushSelfToSocket(id))
    } else {
      return Promise.map(excludingSender, id =>
        pushToSockets(`users/${id}`, 'messageAdded', {postId, message}))
    }
  },

  pushTypingToSockets: function (userId, userName, isTyping, socketToExclude) {
    var postId = this.id
    pushToSockets(`posts/${postId}`, 'userTyping', {userId, userName, isTyping}, socketToExclude)
  },

  pushSelfToSocket: function (userId) {
    const opts = {withComments: 'all'}
    return this.load(PostPresenter.relations(userId, opts))
    .then(post => PostPresenter.present(post, userId, opts))
    .then(normalize)
    .then(post => pushToSockets(`users/${userId}`, 'newThread', post))
  },

  copy: function (attrs) {
    var that = this.clone()
    _.merge(that.attributes, Post.newPostAttrs(), attrs)
    delete that.id
    delete that.attributes.id
    that._previousAttributes = {}
    that.changed = {}
    return that
  },

  createActivities: function (trx) {
    return this.load(['communities', 'communities.users', 'tags'], {transacting: trx})
    .then(() =>
      TagFollow.query(qb => {
        qb.whereIn('tag_id', this.relations.tags.map('id'))
        qb.whereIn('community_id', this.relations.communities.map('id'))
      })
      .fetchAll({withRelated: ['tag'], transacting: trx})
    )
    .then(tagFollows => {
      const tagFollowers = tagFollows.map(tagFollow => ({
        reader_id: tagFollow.get('user_id'),
        post_id: this.id,
        actor_id: this.get('user_id'),
        community_id: tagFollow.get('community_id'),
        reason: `tag: ${tagFollow.relations.tag.get('name')}`
      }))
      const mentioned = RichText.getUserMentions(this.get('description')).map(userId => ({
        reader_id: userId,
        post_id: this.id,
        actor_id: this.get('user_id'),
        reason: 'mention'
      }))
      const members = flatten(this.relations.communities.map(community =>
        community.relations.users.map(user => ({
          reader_id: user.id,
          post_id: this.id,
          actor_id: this.get('user_id'),
          community_id: community.id,
          reason: `newPost: ${community.id}`
        }))))
      const readers = filter(r => r.reader_id !== this.get('user_id'),
        mentioned.concat(members).concat(tagFollowers))
      return Activity.saveForReasons(readers, trx)
    })
  },

  fulfillRequest,

  unfulfillRequest

}, EnsureLoad), {
  // Class Methods

  Type: {
    WELCOME: 'welcome',
    EVENT: 'event',
    PROJECT: 'project',
    THREAD: 'thread'
  },

  Visibility: {
    DEFAULT: 0,
    PUBLIC_READABLE: 1
  },

  countForUser: function (user, type) {
    const attrs = {user_id: user.id, active: true}
    if (type) attrs.type = type
    return this.query().count().where(attrs).then(rows => rows[0].count)
  },

  groupedCountForUser: function (user) {
    return this.query(q => {
      q.join('posts_tags', 'posts.id', 'posts_tags.post_id')
      q.join('tags', 'tags.id', 'posts_tags.tag_id')
      q.whereIn('tags.name', ['request', 'offer'])
      q.groupBy('tags.name')
      q.where({user_id: user.id, active: true})
      q.select('tags.name')
    }).query().count()
    .then(rows => rows.reduce((m, n) => {
      m[n.name] = n.count
      return m
    }, {}))
  },

  isVisibleToUser: function (postId, userId) {
    if (!postId || !userId) return Promise.resolve(false)
    var pcids

    return Post.find(postId)
    // is the post public?
    .then(post => post.isPublic() ||
      Post.isVisibleToUser(post.get('parent_post_id'), userId))
    .then(success =>
      // or is the user:
      success || Promise.join(
        PostMembership.query().where({post_id: postId}),
        Membership.query().where({user_id: userId, active: true})
      )
      .spread((postMships, userMships) => {
        // in one of the post's communities?
        pcids = postMships.map(m => m.community_id)
        return _.intersection(pcids, userMships.map(m => m.community_id)).length > 0
      }))
    .then(success =>
      // or following the post?
      success || Follow.exists(userId, postId))
    .then(success =>
      // or in one of the post's communities' networks?
      success || Community.query().whereIn('id', pcids).pluck('network_id')
      .then(networkIds =>
        Promise.map(_.compact(_.uniq(networkIds)), id =>
          Network.containsUser(id, userId)))
      .then(results => _.some(results)))
  },

  find: function (id, options) {
    return Post.where({id, active: true}).fetch(options)
  },

  createdInTimeRange: function (collection, startTime, endTime) {
    if (endTime === undefined) {
      endTime = startTime
      startTime = collection
      collection = Post
    }
    return collection.query(function (qb) {
      qb.whereRaw('posts.created_at between ? and ?', [startTime, endTime])
      qb.where('posts.active', true)
    })
  },

  createWelcomePost: function (userId, communityId, trx) {
    var attrs = _.merge(Post.newPostAttrs(), {
      type: 'welcome'
    })

    return new Post(attrs).save({}, {transacting: trx})
    .tap(post => Promise.join(
      post.relatedUsers().attach(userId, {transacting: trx}),
      post.communities().attach(communityId, {transacting: trx}),
      Follow.create(userId, post.id, null, {transacting: trx})
    ))
  },

  newPostAttrs: () => ({
    created_at: new Date(),
    updated_at: new Date(),
    active: true,
    num_comments: 0,
    num_votes: 0
  }),

  create: function (attrs, opts) {
    return Post.forge(_.merge(Post.newPostAttrs(), attrs))
    .save(null, _.pick(opts, 'transacting'))
  },

  updateFromNewComment: ({ postId, commentId }) => {
    const where = {post_id: postId, active: true}
    const now = new Date()
    const select = (model, id, column) =>
      model.where('id', id).query().select(column)

    return Comment.query()
    .where(where)
    .orderBy('created_at', 'desc')
    .limit(2)
    .pluck('id')
    .then(ids => Promise.all([
      Comment.query().where('id', 'in', ids).update('recent', true),
      Comment.query().where('id', 'not in', ids)
      .where({recent: true, post_id: postId})
      .update('recent', false),

      // update num_comments and updated_at (only update the latter when
      // creating a comment, not deleting one)
      Aggregate.count(Comment.where(where)).then(count =>
        Post.query().where('id', postId).update(omitBy(isNull, {
          num_comments: count,
          updated_at: commentId ? now : null
        }))),

      // when creating a comment, set updated_at in parent post if it exists,
      // and set last_read_at for the commenter
      commentId && Promise.join(
        Post.query().whereIn('id', select(Post, postId, 'parent_post_id'))
        .update({updated_at: now}),

        LastRead.query().where({
          post_id: postId,
          user_id: select(Comment, commentId, 'user_id')
        })
        .update({last_read_at: now})
      )
    ]))
  },

  deactivate: postId =>
    bookshelf.transaction(trx =>
      Promise.join(
        Activity.removeForPost(postId, trx),
        Post.where('id', postId).query().update({active: false}).transacting(trx)
      )),

  createActivities: (opts) =>
    Post.find(opts.postId).then(post =>
      bookshelf.transaction(trx => post.createActivities(trx))),

  fixTypedPosts: () =>
    bookshelf.transaction(transacting =>
      Tag.where('name', 'in', ['request', 'offer', 'intention'])
      .fetchAll({transacting})
      .then(tags => Post.query(q => {
        q.where('type', 'in', ['request', 'offer', 'intention'])
      }).fetchAll({withRelated: ['selectedTags', 'tags'], transacting})
      .then(posts => Promise.each(posts.models, post => {
        const untype = () => post.save({type: null}, {patch: true, transacting})
        if (post.relations.selectedTags.first()) return untype()

        const matches = t => t.get('name') === post.get('type')
        const existingTag = post.relations.tags.find(matches)
        if (existingTag) {
          return PostTag.query()
          .where({post_id: post.id, tag_id: existingTag.id})
          .update({selected: true}).transacting(transacting)
          .then(untype)
        }

        return post.selectedTags().attach(tags.find(matches).id, {transacting})
        .then(untype)
      }))
      .then(promises => promises.length))),

  notifySlack: ({ postId }) =>
    Post.find(postId, {withRelated: ['communities', 'user', 'relatedUsers']})
    .then(post => {
      const slackCommunities = post.relations.communities.filter(c => c.get('slack_hook_url'))
      return Promise.map(slackCommunities, c => Community.notifySlack(c.id, post))
    })
})
<commit_msg>re-add request and offer as post types<commit_after>/* globals LinkPreview, LastRead, _ */
/* eslint-disable camelcase */
import { filter, isNull, omitBy, uniqBy } from 'lodash/fp'
import { flatten } from 'lodash'
import { normalizePost } from '../../lib/util/normalize'
import { pushToSockets } from '../services/Websockets'
import { addFollowers } from './post/util'
import { fulfillRequest, unfulfillRequest } from './post/request'
import EnsureLoad from './mixins/EnsureLoad'

const normalize = post => {
  const data = {communities: [], people: []}
  normalizePost(post, data, true)
  return Object.assign(data, post)
}

module.exports = bookshelf.Model.extend(Object.assign({
  // Instance Methods

  tableName: 'posts',

  user: function () {
    return this.belongsTo(User)
  },

  communities: function () {
    return this.belongsToMany(Community).through(PostMembership)
    .query({where: {'communities.active': true}})
  },

  followers: function () {
    return this.belongsToMany(User).through(Follow).withPivot('added_by_id')
  },

  contributions: function () {
    return this.hasMany(Contribution, 'post_id')
  },

  comments: function () {
    return this.hasMany(Comment, 'post_id').query({where: {active: true}})
  },

  lastReads: function () {
    return this.hasMany(LastRead)
  },

  media: function () {
    return this.hasMany(Media)
  },

  votes: function () {
    return this.hasMany(Vote)
  },

  responders: function () {
    return this.belongsToMany(User).through(EventResponse)
  },

  userVote: function (userId) {
    return this.votes().query({where: {user_id: userId}}).fetchOne()
  },

  relatedUsers: function () {
    return this.belongsToMany(User, 'posts_about_users')
  },

  tags: function () {
    return this.belongsToMany(Tag).through(PostTag).withPivot('selected')
  },

  // should only be one of these per post
  selectedTags: function () {
    return this.belongsToMany(Tag).through(PostTag).withPivot('selected')
    .query({where: {selected: true}})
  },

  children: function () {
    return this.hasMany(Post, 'parent_post_id')
    .query({where: {active: true}})
  },

  parent: function () {
    return this.belongsTo(Post, 'parent_post_id')
  },

  activities: function () {
    return this.hasMany(Activity)
  },

  linkPreview: function () {
    return this.belongsTo(LinkPreview)
  },

  getTagsInComments: function (opts) {
    // this is part of the 'taggable' interface, shared with Comment
    return this.load('comments.tags', opts)
    .then(() =>
      uniqBy('id', flatten(this.relations.comments.map(c => c.relations.tags.models))))
  },

  addFollowers: function (userIds, addedById, opts = {}) {
    return addFollowers(this, null, userIds, addedById, opts)
  },

  removeFollower: function (user_id, opts = {}) {
    return Follow.where({user_id, post_id: this.id}).destroy()
    .tap(() => this.isProject() && this.load(['selectedTags', 'communities'])
      .then(() => {
        const tag = this.relations.selectedTags.first()
        if (!tag) return
        return Promise.each(this.relations.communities.models, community =>
          TagFollow.remove(tag, user_id, community))
      }))
    .tap(() => opts.createActivity && Activity.forUnfollow(this, user_id).save()
      .then(activity => activity.createNotifications()))
  },

  isPublic: function () {
    return this.get('visibility') === Post.Visibility.PUBLIC_READABLE
  },

  isWelcome: function () {
    return this.get('type') === Post.Type.WELCOME
  },

  isProject: function () {
    return this.get('type') === Post.Type.PROJECT
  },

  isThread: function () {
    return this.get('type') === Post.Type.THREAD
  },

  pushCommentToSockets: function (comment) {
    var postId = this.id
    return pushToSockets(`posts/${postId}`, 'commentAdded', {comment})
  },

  pushMessageToSockets: function (message, userIds) {
    var postId = this.id
    const excludingSender = userIds.filter(id => id !== message.user_id.toString())
    if (this.get('num_comments') === 0) {
      return Promise.map(excludingSender, id => this.pushSelfToSocket(id))
    } else {
      return Promise.map(excludingSender, id =>
        pushToSockets(`users/${id}`, 'messageAdded', {postId, message}))
    }
  },

  pushTypingToSockets: function (userId, userName, isTyping, socketToExclude) {
    var postId = this.id
    pushToSockets(`posts/${postId}`, 'userTyping', {userId, userName, isTyping}, socketToExclude)
  },

  pushSelfToSocket: function (userId) {
    const opts = {withComments: 'all'}
    return this.load(PostPresenter.relations(userId, opts))
    .then(post => PostPresenter.present(post, userId, opts))
    .then(normalize)
    .then(post => pushToSockets(`users/${userId}`, 'newThread', post))
  },

  copy: function (attrs) {
    var that = this.clone()
    _.merge(that.attributes, Post.newPostAttrs(), attrs)
    delete that.id
    delete that.attributes.id
    that._previousAttributes = {}
    that.changed = {}
    return that
  },

  createActivities: function (trx) {
    return this.load(['communities', 'communities.users', 'tags'], {transacting: trx})
    .then(() =>
      TagFollow.query(qb => {
        qb.whereIn('tag_id', this.relations.tags.map('id'))
        qb.whereIn('community_id', this.relations.communities.map('id'))
      })
      .fetchAll({withRelated: ['tag'], transacting: trx})
    )
    .then(tagFollows => {
      const tagFollowers = tagFollows.map(tagFollow => ({
        reader_id: tagFollow.get('user_id'),
        post_id: this.id,
        actor_id: this.get('user_id'),
        community_id: tagFollow.get('community_id'),
        reason: `tag: ${tagFollow.relations.tag.get('name')}`
      }))
      const mentioned = RichText.getUserMentions(this.get('description')).map(userId => ({
        reader_id: userId,
        post_id: this.id,
        actor_id: this.get('user_id'),
        reason: 'mention'
      }))
      const members = flatten(this.relations.communities.map(community =>
        community.relations.users.map(user => ({
          reader_id: user.id,
          post_id: this.id,
          actor_id: this.get('user_id'),
          community_id: community.id,
          reason: `newPost: ${community.id}`
        }))))
      const readers = filter(r => r.reader_id !== this.get('user_id'),
        mentioned.concat(members).concat(tagFollowers))
      return Activity.saveForReasons(readers, trx)
    })
  },

  fulfillRequest,

  unfulfillRequest

}, EnsureLoad), {
  // Class Methods

  Type: {
    WELCOME: 'welcome',
    REQUEST: 'request',
    OFFER: 'offer',
    EVENT: 'event',
    PROJECT: 'project',
    THREAD: 'thread'
  },

  Visibility: {
    DEFAULT: 0,
    PUBLIC_READABLE: 1
  },

  countForUser: function (user, type) {
    const attrs = {user_id: user.id, active: true}
    if (type) attrs.type = type
    return this.query().count().where(attrs).then(rows => rows[0].count)
  },

  groupedCountForUser: function (user) {
    return this.query(q => {
      q.join('posts_tags', 'posts.id', 'posts_tags.post_id')
      q.join('tags', 'tags.id', 'posts_tags.tag_id')
      q.whereIn('tags.name', ['request', 'offer'])
      q.groupBy('tags.name')
      q.where({user_id: user.id, active: true})
      q.select('tags.name')
    }).query().count()
    .then(rows => rows.reduce((m, n) => {
      m[n.name] = n.count
      return m
    }, {}))
  },

  isVisibleToUser: function (postId, userId) {
    if (!postId || !userId) return Promise.resolve(false)
    var pcids

    return Post.find(postId)
    // is the post public?
    .then(post => post.isPublic() ||
      Post.isVisibleToUser(post.get('parent_post_id'), userId))
    .then(success =>
      // or is the user:
      success || Promise.join(
        PostMembership.query().where({post_id: postId}),
        Membership.query().where({user_id: userId, active: true})
      )
      .spread((postMships, userMships) => {
        // in one of the post's communities?
        pcids = postMships.map(m => m.community_id)
        return _.intersection(pcids, userMships.map(m => m.community_id)).length > 0
      }))
    .then(success =>
      // or following the post?
      success || Follow.exists(userId, postId))
    .then(success =>
      // or in one of the post's communities' networks?
      success || Community.query().whereIn('id', pcids).pluck('network_id')
      .then(networkIds =>
        Promise.map(_.compact(_.uniq(networkIds)), id =>
          Network.containsUser(id, userId)))
      .then(results => _.some(results)))
  },

  find: function (id, options) {
    return Post.where({id, active: true}).fetch(options)
  },

  createdInTimeRange: function (collection, startTime, endTime) {
    if (endTime === undefined) {
      endTime = startTime
      startTime = collection
      collection = Post
    }
    return collection.query(function (qb) {
      qb.whereRaw('posts.created_at between ? and ?', [startTime, endTime])
      qb.where('posts.active', true)
    })
  },

  createWelcomePost: function (userId, communityId, trx) {
    var attrs = _.merge(Post.newPostAttrs(), {
      type: 'welcome'
    })

    return new Post(attrs).save({}, {transacting: trx})
    .tap(post => Promise.join(
      post.relatedUsers().attach(userId, {transacting: trx}),
      post.communities().attach(communityId, {transacting: trx}),
      Follow.create(userId, post.id, null, {transacting: trx})
    ))
  },

  newPostAttrs: () => ({
    created_at: new Date(),
    updated_at: new Date(),
    active: true,
    num_comments: 0,
    num_votes: 0
  }),

  create: function (attrs, opts) {
    return Post.forge(_.merge(Post.newPostAttrs(), attrs))
    .save(null, _.pick(opts, 'transacting'))
  },

  updateFromNewComment: ({ postId, commentId }) => {
    const where = {post_id: postId, active: true}
    const now = new Date()
    const select = (model, id, column) =>
      model.where('id', id).query().select(column)

    return Comment.query()
    .where(where)
    .orderBy('created_at', 'desc')
    .limit(2)
    .pluck('id')
    .then(ids => Promise.all([
      Comment.query().where('id', 'in', ids).update('recent', true),
      Comment.query().where('id', 'not in', ids)
      .where({recent: true, post_id: postId})
      .update('recent', false),

      // update num_comments and updated_at (only update the latter when
      // creating a comment, not deleting one)
      Aggregate.count(Comment.where(where)).then(count =>
        Post.query().where('id', postId).update(omitBy(isNull, {
          num_comments: count,
          updated_at: commentId ? now : null
        }))),

      // when creating a comment, set updated_at in parent post if it exists,
      // and set last_read_at for the commenter
      commentId && Promise.join(
        Post.query().whereIn('id', select(Post, postId, 'parent_post_id'))
        .update({updated_at: now}),

        LastRead.query().where({
          post_id: postId,
          user_id: select(Comment, commentId, 'user_id')
        })
        .update({last_read_at: now})
      )
    ]))
  },

  deactivate: postId =>
    bookshelf.transaction(trx =>
      Promise.join(
        Activity.removeForPost(postId, trx),
        Post.where('id', postId).query().update({active: false}).transacting(trx)
      )),

  createActivities: (opts) =>
    Post.find(opts.postId).then(post =>
      bookshelf.transaction(trx => post.createActivities(trx))),

  fixTypedPosts: () =>
    bookshelf.transaction(transacting =>
      Tag.where('name', 'in', ['request', 'offer', 'intention'])
      .fetchAll({transacting})
      .then(tags => Post.query(q => {
        q.where('type', 'in', ['request', 'offer', 'intention'])
      }).fetchAll({withRelated: ['selectedTags', 'tags'], transacting})
      .then(posts => Promise.each(posts.models, post => {
        const untype = () => post.save({type: null}, {patch: true, transacting})
        if (post.relations.selectedTags.first()) return untype()

        const matches = t => t.get('name') === post.get('type')
        const existingTag = post.relations.tags.find(matches)
        if (existingTag) {
          return PostTag.query()
          .where({post_id: post.id, tag_id: existingTag.id})
          .update({selected: true}).transacting(transacting)
          .then(untype)
        }

        return post.selectedTags().attach(tags.find(matches).id, {transacting})
        .then(untype)
      }))
      .then(promises => promises.length))),

  notifySlack: ({ postId }) =>
    Post.find(postId, {withRelated: ['communities', 'user', 'relatedUsers']})
    .then(post => {
      const slackCommunities = post.relations.communities.filter(c => c.get('slack_hook_url'))
      return Promise.map(slackCommunities, c => Community.notifySlack(c.id, post))
    })
})
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';
import Title from 'react-title-component';
import MarkdownElement from '../../MarkdownElement';
import muiThemeable from 'material-ui/styles/muiThemeable';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import withWidth, {MEDIUM} from 'material-ui/utils/withWidth';
import typography from 'material-ui/styles/typography';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import themesText from './themes.md';
import ClearFix from 'material-ui/internal/ClearFix';

import {
  Checkbox,
  DatePicker,
  Dialog,
  DropDownMenu,
  FlatButton,
  FloatingActionButton,
  Drawer,
  MenuItem,
  Paper,
  RadioButton,
  RadioButtonGroup,
  RaisedButton,
  Snackbar,
  Slider,
  Tabs,
  Tab,
  TextField,
  Toggle,
} from 'material-ui';

const markdownText = `
## Themes

### Examples

You can use the tabs to change the theme. The changes will be applied to the whole
documentation.
`;

class ThemesPage extends Component {
  static propTypes = {
    muiTheme: PropTypes.object,
    onChangeMuiTheme: PropTypes.func,
    width: PropTypes.number.isRequired,
  };

  state = {
    dialogOpen: false,
    snackbarOpen: false,
    drawerOpen: false,
  };

  componentWillMount() {
    this.setState({
      valueTabs: this.props.muiTheme.name || 'light',
    });
  }

  getStyles() {
    const canvasColor = this.props.muiTheme.baseTheme.palette.canvasColor;
    const borderColor = this.props.muiTheme.baseTheme.palette.borderColor;
    const styles = {
      group: {
        float: 'left',
        width: '100%',
        marginTop: '16px',
        padding: '0 50px',
        boxSizing: 'border-box',
      },
      groupSlider: {
        marginTop: '0px',
        width: '100%',
      },
      container: {
        marginBottom: '16px',
        minHeight: '24px',
        textAlign: 'left',
      },
      containerCentered: {
        textAlign: 'center',
      },
      paper: {
        height: '100px',
        width: '100px',
        margin: '0 auto',
        marginBottom: '64px',
      },
      textfield: {
        width: '100%',
      },
      slider: {
        marginTop: '0px',
        marginBottom: '0px',
      },
      title: {
        fontSize: '20px',
        lineHeight: '28px',
        paddingTop: '19px',
        marginBottom: '13px',
        letterSpacing: '0',
        fontWeight: typography.fontWeightMedium,
        color: typography.textDarkBlack,
      },
      liveExamplePaper: {
        backgroundColor: canvasColor,
        marginBottom: 32,
        overflow: 'hidden',
      },
      bottomBorderWrapper: {
        borderBottom: `1px solid ${borderColor}`,
        paddingBottom: '10px',
      },
    };

    if (this.props.width === MEDIUM) {
      styles.group.width = '33%';
    }

    styles.containerCentered = Object.assign({}, styles.container, styles.containerCentered);
    styles.groupSlider = Object.assign({}, styles.group, styles.groupSlider);

    return styles;
  }

  getComponentGroup() {
    const styles = this.getStyles();

    return (
      <ClearFix>

            <FloatingActionButton iconClassName="muidocs-icon-action-grade" disabled={true} />

            <RaisedButton label="Secondary" secondary={true} />

            <RaisedButton label="Primary" primary={true} />

            <RaisedButton label="Default" />

            <Checkbox
              name="checkboxName1"
              value="checkboxValue1"
              label="checkbox"
            />
            <Checkbox
              name="checkboxName2"
              value="checkboxValue2"
              label="disabled checkbox"
              disabled={true}
            />

            <RadioButtonGroup
              name="shipSpeed"
              defaultSelected="usd"
            >
              <RadioButton
                value="usd"
                label="USD"
              />
              <RadioButton
                value="euro"
                label="Euro"
              />
              <RadioButton
                value="mxn"
                label="MXN"
                disabled={true}
              />
            </RadioButtonGroup>

            <Toggle
              name="toggleName1"
              label="toggle"
            />
            <Toggle
              name="toggleName2"
              label="disabled toggle"
              defaultToggled={true}
              disabled={true}
            />

            <TextField
              style={styles.textfield}
              hintText="TextField"
            />

            <DatePicker
              hintText="Landscape Dialog"
              mode="landscape"
              style={{width: '100%'}}
            />

            <DropDownMenu value={3} style={{width: '100%'}}>
              <MenuItem value={1} primaryText={'Never'} />
              <MenuItem value={2} primaryText={'Every Night'} />
              <MenuItem value={3} primaryText={'Weeknights'} />
              <MenuItem value={4} primaryText={'Weekends'} />
              <MenuItem value={5} primaryText={'Weekly'} />
            </DropDownMenu>

          <Slider style={styles.slider} name="slider2" defaultValue={0.5} />

            <FlatButton label="View Dialog" onTouchTap={this.handleTouchTapDialog} />
            <Dialog
              open={this.state.dialogOpen}
              title="Dialog With Standard Actions"
              actions={[
                <FlatButton
                  label="Cancel"
                  keyboardFocus={true}
                  onTouchTap={this.handleRequestCloseDialog}
                  primary={true}
                />,
                <FlatButton
                  label="Submit"
                  onTouchTap={this.handleRequestCloseDialog}
                  primary={true}
                />,
              ]}
              onRequestClose={this.handleRequestCloseDialog}
            >
              The actions in this window are created from tan array of element's that's passed in.
            </Dialog>

            <FlatButton
              onTouchTap={this.handleTouchTapDrawer}
              label="View Drawer"
            />
            <Drawer
              open={this.state.drawerOpen} docked={false}
              onRequestChange={this.handleRequestChangeDrawer}
            >
              <MenuItem index={0}>Menu Item</MenuItem>
              <MenuItem index={1}>Menu Item 2</MenuItem>
            </Drawer>

            <FlatButton
              onTouchTap={this.handleTouchTapSnackbar}
              label="View Snackbar"
            />

          <Snackbar
            open={this.state.snackbarOpen}
            onRequestClose={this.handleRequestCloseSnackbar}
            message="This is a snackbar"
            action="Got It!"
            onActionTouchTap={this.handleRequestCloseSnackbar}
          />

      </ClearFix>
    );
  }

  handleChangeTabs = (valueTabs) => {
    let newMuiTheme = null;

    if (valueTabs === 'light') {
      newMuiTheme = getMuiTheme();
    } else {
      newMuiTheme = getMuiTheme(darkBaseTheme);
    }

    newMuiTheme.name = valueTabs;

    this.setState({
      valueTabs: valueTabs,
    });

    this.props.onChangeMuiTheme(newMuiTheme);
  };

  getThemeExamples() {
    return (

        <Tabs
          value={this.state.valueTabs}
          onChange={this.handleChangeTabs}
        >
          <Tab
            label="Light Theme (Default)"
            value="light"
          />
          <Tab
            label="Dark Theme"
            value="dark"
          />
        </Tabs>
        {this.getComponentGroup()}

    );
  }

  handleTouchTapDrawer = () => {
    this.setState({
      drawerOpen: true,
    });
  };

  handleRequestChangeDrawer = (open) => {
    this.setState({
      drawerOpen: open,
    });
  };

  handleTouchTapDialog = () => {
    this.setState({
      dialogOpen: true,
    });
  };

  handleRequestCloseDialog = () => {
    this.setState({
      dialogOpen: false,
    });
  };

  handleTouchTapSnackbar = () => {
    this.setState({
      snackbarOpen: true,
    });
  };

  handleRequestCloseSnackbar = () => {
    this.setState({
      snackbarOpen: false,
    });
  };

  render() {
    const styles = this.getStyles();

    return (

        <Title render={(previousTitle) => `Themes - ${previousTitle}`} />
        <MarkdownElement text={markdownText} />
        <Paper style={styles.liveExamplePaper}>
          <ClearFix style={styles.liveExampleBlock}>{this.getThemeExamples()}</ClearFix>
        </Paper>

          <MarkdownElement text={themesText} />

    );
  }
}

export default muiThemeable()(withWidth()(ThemesPage));
<commit_msg>[Docs] Fix layout broken for Themes example<commit_after>import React, {Component, PropTypes} from 'react';
import Title from 'react-title-component';
import MarkdownElement from '../../MarkdownElement';
import muiThemeable from 'material-ui/styles/muiThemeable';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import withWidth, {SMALL} from 'material-ui/utils/withWidth';
import typography from 'material-ui/styles/typography';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import themesText from './themes.md';
import ClearFix from 'material-ui/internal/ClearFix';

import {
  Checkbox,
  DatePicker,
  Dialog,
  DropDownMenu,
  FlatButton,
  FloatingActionButton,
  Drawer,
  MenuItem,
  Paper,
  RadioButton,
  RadioButtonGroup,
  RaisedButton,
  Snackbar,
  Slider,
  Tabs,
  Tab,
  TextField,
  Toggle,
} from 'material-ui';

const markdownText = `
## Themes

### Examples

You can use the tabs to change the theme. The changes will be applied to the whole
documentation.
`;

class ThemesPage extends Component {
  static propTypes = {
    muiTheme: PropTypes.object,
    onChangeMuiTheme: PropTypes.func,
    width: PropTypes.number.isRequired,
  };

  state = {
    dialogOpen: false,
    snackbarOpen: false,
    drawerOpen: false,
  };

  componentWillMount() {
    this.setState({
      valueTabs: this.props.muiTheme.name || 'light',
    });
  }

  getStyles() {
    const {
      muiTheme,
      width,
    } = this.props;

    const canvasColor = muiTheme.baseTheme.palette.canvasColor;
    const borderColor = muiTheme.baseTheme.palette.borderColor;
    const styles = {
      group: {
        float: 'left',
        width: width === SMALL ? '100%' : '33%',
        marginTop: '16px',
        padding: '0 50px',
        boxSizing: 'border-box',
      },
      groupSlider: {
        marginTop: '0px',
        width: '100%',
      },
      container: {
        marginBottom: '16px',
        minHeight: '24px',
        textAlign: 'left',
      },
      containerCentered: {
        textAlign: 'center',
      },
      paper: {
        height: '100px',
        width: '100px',
        margin: '0 auto',
        marginBottom: '64px',
      },
      textfield: {
        width: '100%',
      },
      slider: {
        marginTop: '0px',
        marginBottom: '0px',
      },
      title: {
        fontSize: '20px',
        lineHeight: '28px',
        paddingTop: '19px',
        marginBottom: '13px',
        letterSpacing: '0',
        fontWeight: typography.fontWeightMedium,
        color: typography.textDarkBlack,
      },
      liveExamplePaper: {
        backgroundColor: canvasColor,
        marginBottom: 32,
        overflow: 'hidden',
      },
      bottomBorderWrapper: {
        borderBottom: `1px solid ${borderColor}`,
        paddingBottom: '10px',
      },
    };

    styles.containerCentered = Object.assign({}, styles.container, styles.containerCentered);
    styles.groupSlider = Object.assign({}, styles.group, styles.groupSlider);

    return styles;
  }

  getComponentGroup() {
    const styles = this.getStyles();

    return (
      <ClearFix>

            <FloatingActionButton iconClassName="muidocs-icon-action-grade" disabled={true} />

            <RaisedButton label="Secondary" secondary={true} />

            <RaisedButton label="Primary" primary={true} />

            <RaisedButton label="Default" />

            <Checkbox
              name="checkboxName1"
              value="checkboxValue1"
              label="checkbox"
            />
            <Checkbox
              name="checkboxName2"
              value="checkboxValue2"
              label="disabled checkbox"
              disabled={true}
            />

            <RadioButtonGroup
              name="shipSpeed"
              defaultSelected="usd"
            >
              <RadioButton
                value="usd"
                label="USD"
              />
              <RadioButton
                value="euro"
                label="Euro"
              />
              <RadioButton
                value="mxn"
                label="MXN"
                disabled={true}
              />
            </RadioButtonGroup>

            <Toggle
              name="toggleName1"
              label="toggle"
            />
            <Toggle
              name="toggleName2"
              label="disabled toggle"
              defaultToggled={true}
              disabled={true}
            />

            <TextField
              style={styles.textfield}
              hintText="TextField"
            />

            <DatePicker
              hintText="Landscape Dialog"
              mode="landscape"
              style={{width: '100%'}}
            />

            <DropDownMenu value={3} style={{width: '100%'}}>
              <MenuItem value={1} primaryText={'Never'} />
              <MenuItem value={2} primaryText={'Every Night'} />
              <MenuItem value={3} primaryText={'Weeknights'} />
              <MenuItem value={4} primaryText={'Weekends'} />
              <MenuItem value={5} primaryText={'Weekly'} />
            </DropDownMenu>

          <Slider style={styles.slider} name="slider2" defaultValue={0.5} />

            <FlatButton label="View Dialog" onTouchTap={this.handleTouchTapDialog} />
            <Dialog
              open={this.state.dialogOpen}
              title="Dialog With Standard Actions"
              actions={[
                <FlatButton
                  label="Cancel"
                  keyboardFocus={true}
                  onTouchTap={this.handleRequestCloseDialog}
                  primary={true}
                />,
                <FlatButton
                  label="Submit"
                  onTouchTap={this.handleRequestCloseDialog}
                  primary={true}
                />,
              ]}
              onRequestClose={this.handleRequestCloseDialog}
            >
              The actions in this window are created from tan array of element's that's passed in.
            </Dialog>

            <FlatButton
              onTouchTap={this.handleTouchTapDrawer}
              label="View Drawer"
            />
            <Drawer
              open={this.state.drawerOpen} docked={false}
              onRequestChange={this.handleRequestChangeDrawer}
            >
              <MenuItem index={0}>Menu Item</MenuItem>
              <MenuItem index={1}>Menu Item 2</MenuItem>
            </Drawer>

            <FlatButton
              onTouchTap={this.handleTouchTapSnackbar}
              label="View Snackbar"
            />

          <Snackbar
            open={this.state.snackbarOpen}
            onRequestClose={this.handleRequestCloseSnackbar}
            message="This is a snackbar"
            action="Got It!"
            onActionTouchTap={this.handleRequestCloseSnackbar}
          />

      </ClearFix>
    );
  }

  handleChangeTabs = (valueTabs) => {
    let newMuiTheme = null;

    if (valueTabs === 'light') {
      newMuiTheme = getMuiTheme();
    } else {
      newMuiTheme = getMuiTheme(darkBaseTheme);
    }

    newMuiTheme.name = valueTabs;

    this.setState({
      valueTabs: valueTabs,
    });

    this.props.onChangeMuiTheme(newMuiTheme);
  };

  getThemeExamples() {
    return (

        <Tabs
          value={this.state.valueTabs}
          onChange={this.handleChangeTabs}
        >
          <Tab
            label="Light Theme (Default)"
            value="light"
          />
          <Tab
            label="Dark Theme"
            value="dark"
          />
        </Tabs>
        {this.getComponentGroup()}

    );
  }

  handleTouchTapDrawer = () => {
    this.setState({
      drawerOpen: true,
    });
  };

  handleRequestChangeDrawer = (open) => {
    this.setState({
      drawerOpen: open,
    });
  };

  handleTouchTapDialog = () => {
    this.setState({
      dialogOpen: true,
    });
  };

  handleRequestCloseDialog = () => {
    this.setState({
      dialogOpen: false,
    });
  };

  handleTouchTapSnackbar = () => {
    this.setState({
      snackbarOpen: true,
    });
  };

  handleRequestCloseSnackbar = () => {
    this.setState({
      snackbarOpen: false,
    });
  };

  render() {
    const styles = this.getStyles();

    return (

        <Title render={(previousTitle) => `Themes - ${previousTitle}`} />
        <MarkdownElement text={markdownText} />
        <Paper style={styles.liveExamplePaper}>
          <ClearFix style={styles.liveExampleBlock}>{this.getThemeExamples()}</ClearFix>
        </Paper>

          <MarkdownElement text={themesText} />

    );
  }
}

export default muiThemeable()(withWidth()(ThemesPage));
<|endoftext|>


<commit_before>const fse = require('fs-extra');
const path = require('path');
const _ = require('lodash');

/**
 * link all the files in .serverless/requirements to the service directory root
 * @return {undefined}
 */
function linkRequirements() {
  const requirementsDir = path.join(this.servicePath, '.serverless/requirements');
  if (!_.get(this.serverless.service, 'package.include'))
    _.set(this.serverless.service, ['package', 'include'], []);
  if (!this.options.zip && fse.existsSync(requirementsDir)) {
    this.serverless.cli.log('Linking required Python packages...');
    const noDeploy = new Set(this.options.noDeploy || []);
    fse.readdirSync(requirementsDir).map((file) => {
      if (noDeploy.has(file))
        return;
      this.serverless.service.package.include.push(file);
      this.serverless.service.package.include.push(`${file}/**`);
      try {
        fse.symlinkSync(`${requirementsDir}/${file}`, `./${file}`);
      } catch (exception) {
        let linkDest = null;
        try {
          linkDest = fse.readlinkSync(`./${file}`);
        } catch (e) {
          if (linkDest !== `${requirementsDir}/${file}`) {
            const errorMessage = `Unable to link dependency '${file}' ` +
              'because a file by the same name exists in this service';
            throw new Error(errorMessage);
          }
        }
      }
    });
  }
}

/**
 * unlink all the files in .serverless/requirements from the service directory root
 * @return {undefined}
 */
function unlinkRequirements() {
  const requirementsDir = path.join(this.servicePath, '.serverless/requirements');
  if (!this.options.zip && fse.existsSync(requirementsDir)) {
    this.serverless.cli.log('Unlinking required Python packages...');
    const noDeploy = new Set(this.options.noDeploy || []);
    fse.readdirSync(requirementsDir).map((file) => {
      if (noDeploy.has(file))
        return;
      fse.unlinkSync(file);
    });
  }
}

module.exports = {linkRequirements, unlinkRequirements};
<commit_msg>Only add Python requirements to python function `include`s when `individually=True`<commit_after>const fse = require('fs-extra');
const path = require('path');
const _ = require('lodash');

/**
 * link all the files in .serverless/requirements to the service directory root
 * @return {undefined}
 */
function linkRequirements() {
  const requirementsDir = path.join(this.servicePath, '.serverless/requirements');
  if (!_.get(this.serverless.service, 'package.include'))
    _.set(this.serverless.service, ['package', 'include'], []);
  if (!this.options.zip && fse.existsSync(requirementsDir)) {
    this.serverless.cli.log('Linking required Python packages...');
    const noDeploy = new Set(this.options.noDeploy || []);
    fse.readdirSync(requirementsDir).map((file) => {
      if (noDeploy.has(file))
        return;
      if (this.serverless.service.package.individually) {
        // don't include python deps in non-python functions
        _.each(
          _.filter(
            this.serverless.service.functions,
            (f) => { return (f.runtime || this.serverless.service.provider.runtime).match(/^python.*/) }
          ),
          (f) => {
            if (!_.get(f, 'package.include'))
              _.set(f, ['package', 'include'], []);
            f.package.include.push(file)
            f.package.include.push(`${file}/**`)
          }
        );
      } else {
        this.serverless.service.package.include.push(file);
        this.serverless.service.package.include.push(`${file}/**`);
      }
      try {
        fse.symlinkSync(`${requirementsDir}/${file}`, `./${file}`);
      } catch (exception) {
        let linkDest = null;
        try {
          linkDest = fse.readlinkSync(`./${file}`);
        } catch (e) {
          if (linkDest !== `${requirementsDir}/${file}`) {
            const errorMessage = `Unable to link dependency '${file}' ` +
              'because a file by the same name exists in this service';
            throw new Error(errorMessage);
          }
        }
      }
    });
  }
}

/**
 * unlink all the files in .serverless/requirements from the service directory root
 * @return {undefined}
 */
function unlinkRequirements() {
  const requirementsDir = path.join(this.servicePath, '.serverless/requirements');
  if (!this.options.zip && fse.existsSync(requirementsDir)) {
    this.serverless.cli.log('Unlinking required Python packages...');
    const noDeploy = new Set(this.options.noDeploy || []);
    fse.readdirSync(requirementsDir).map((file) => {
      if (noDeploy.has(file))
        return;
      fse.unlinkSync(file);
    });
  }
}

module.exports = {linkRequirements, unlinkRequirements};
<|endoftext|>


<commit_before>
// link the supplied folder to .npm/{name}/{version}/package

var npm = require("../npm")
  , chain = require("./utils/chain")
  , log = require("./utils/log")
  , fs = require("fs")
  , readJson = require("./utils/read-json")
  , rm = require("./utils/rm-rf")
  , mkdir = require("./utils/mkdir-p")
  , path = require("path")
  , crypto

try {
  crypto = process.binding("crypto") && require("crypto")
} catch (ex) {}

module.exports = link

function link (args, cb) {
  if (!crypto) return cb(new Error(
    "You must compile node with ssl support to use the link feature"))
  var folder = args.shift() || "."
  // folder's root MUST contain a package.json
  // read that for package info, then link it in, clobbering if necessary.
  if (folder.charAt(0) !== "/") folder = path.join(process.cwd(), folder)
  var pkg = {}
    , jsonFile = path.join(folder, "package.json")
  log(folder, "link")
  chain
    ( function (cb) { fs.stat(folder, function (er, stats) {
        if (er) return cb(er)
        if (!stats.isDirectory()) {
          return cb(new Error("npm link requires a directory"))
        }
        log(folder+" is a directory", "link")
        cb()
      })}
    , [log, "reading "+jsonFile, "link"]
    , function (cb) { readJson
        ( jsonFile
        , "-LINK-"+(
            crypto.createHash("sha1").update(folder).digest("hex").substr(0,8)
          )
        , function (er, data) {
            if (er) return cb(er)
            log(data.name+" "+data.version, "link")
            pkg._data = data
            cb()
          }
        )
      }
    , [link_, folder, pkg]
    , [npm.commands, "build", [pkg]]
    , cb
    )
}

function link_ (folder, pkg, cb) {
  pkg = pkg && pkg._data || pkg
  if (!pkg) cb(new Error(
    "Invalid package data"))
  var pkgRoot = path.join(npm.dir, pkg.name, pkg.version)
    , pkgDir = path.join(pkgRoot, "package")
  chain
    ( [rm, pkgDir]
    , [mkdir, pkgRoot]
    , [fs, "symlink", folder, pkgDir]
    , [log, "created symlink: "+pkgDir, "link"]
    , cb
    )
}
<commit_msg>Make link packages > their normal counterparts, since they're generally newer anyhow.<commit_after>
// link the supplied folder to .npm/{name}/{version}/package

var npm = require("../npm")
  , chain = require("./utils/chain")
  , log = require("./utils/log")
  , fs = require("fs")
  , readJson = require("./utils/read-json")
  , rm = require("./utils/rm-rf")
  , mkdir = require("./utils/mkdir-p")
  , path = require("path")
  , crypto

try {
  crypto = process.binding("crypto") && require("crypto")
} catch (ex) {}

module.exports = link

function link (args, cb) {
  if (!crypto) return cb(new Error(
    "You must compile node with ssl support to use the link feature"))
  var folder = args.shift() || "."
  // folder's root MUST contain a package.json
  // read that for package info, then link it in, clobbering if necessary.
  if (folder.charAt(0) !== "/") folder = path.join(process.cwd(), folder)
  var pkg = {}
    , jsonFile = path.join(folder, "package.json")
  log(folder, "link")
  chain
    ( function (cb) { fs.stat(folder, function (er, stats) {
        if (er) return cb(er)
        if (!stats.isDirectory()) {
          return cb(new Error("npm link requires a directory"))
        }
        log(folder+" is a directory", "link")
        cb()
      })}
    , [log, "reading "+jsonFile, "link"]
    , function (cb) { readJson
        ( jsonFile
        , "-1-LINK-"+(
            crypto.createHash("sha1").update(folder).digest("hex").substr(0,8)
          )
        , function (er, data) {
            if (er) return cb(er)
            log(data.name+" "+data.version, "link")
            pkg._data = data
            cb()
          }
        )
      }
    , [link_, folder, pkg]
    , [npm.commands, "build", [pkg]]
    , cb
    )
}

function link_ (folder, pkg, cb) {
  pkg = pkg && pkg._data || pkg
  if (!pkg) cb(new Error(
    "Invalid package data"))
  var pkgRoot = path.join(npm.dir, pkg.name, pkg.version)
    , pkgDir = path.join(pkgRoot, "package")
  chain
    ( [rm, pkgDir]
    , [mkdir, pkgRoot]
    , [fs, "symlink", folder, pkgDir]
    , [log, "created symlink: "+pkgDir, "link"]
    , cb
    )
}
<|endoftext|>


<commit_before>
// link with no args: symlink the folder to the global location
// link with package arg: symlink the global to the local

var npm = require("../npm")
  , symlink = require("./utils/link")
  , fs = require("./utils/graceful-fs")
  , log = require("./utils/log")
  , asyncMap = require("./utils/async-map")
  , chain = require("./utils/chain")
  , path = require("path")
  , relativize = require("./utils/relativize")
  , rm = require("./utils/rm-rf")
  , output = require("./utils/output")

module.exports = link

link.usage = "npm link (in package dir)"
           + "\nnpm link <pkg> (link global into local)"

link.completion = function (opts, cb) {
  var dir = path.join(npm.config.get("prefix"), "node_modules")
  fs.readdir(dir, function (er, files) {
    cb(er, files.filter(function (f) {
      return f.charAt(0) !== "."
    }))
  })
}

function link (args, cb) {
  if (npm.config.get("global")) {
    return cb(new Error("link should never be --global."))
  }
  if (args.length) return linkInstall(args, cb)
  linkPkg(npm.prefix, cb)
}

function linkInstall (pkgs, cb) {
  var gp = npm.config.get("prefix")
  asyncMap(pkgs, function (pkg, cb) {
    var pp = path.resolve(gp, "node_modules", pkg)
      , rp = null
      , target = path.resolve(npm.dir, pkg)
    fs.lstat(pp, function (er, st) {
      if (er) {
        log.error(pkg, "not installed globally")
        next()
      } else if (!st.isSymbolicLink()) {
        log.warn(pkg, "not a symbolic link")
        rp = pp
        next()
      } else {
        return fs.realpath(pp, function (er, real) {
          if (er) log.warn(pkg, "invalid symbolic link")
          else rp = real
          next()
        })
      }
    })

    function next () {
      chain
        ( [npm.commands, "unbuild", [target]]
        , [symlink, pp, target]
        , rp && [npm.commands, "build", [target]]
        , [ resultPrinter, pkg, pp, target, rp ]
        , cb )
    }
  }, cb)
}

function linkPkg (folder, cb) {
  var gp = npm.config.get("prefix")
    , me = npm.prefix
    , target = path.resolve(gp, "node_modules", path.basename(me))
  rm(target, function (er) {
    if (er) return cb(er)
    symlink(me, target, function (er) {
      if (er) return cb(er)
      npm.commands.build([target], function (er) {
        if (er) return cb(er)
        resultPrinter(path.basename(me), me, target, cb)
      })
    })
  })
}

function resultPrinter (pkg, src, dest, rp, cb) {
  if (typeof cb !== "function") cb = rp, rp = null
  var where = relativize(dest, path.resolve(process.cwd(),"x"))
  rp = (rp || "").trim()
  src = (src || "").trim()
  if (rp === src) rp = null
  output.write(where+"@ -> "+(src.trim())
              +(rp ? "@ -> "+rp: ""), cb)
}
<commit_msg>link based on package name, not folder name<commit_after>
// link with no args: symlink the folder to the global location
// link with package arg: symlink the global to the local

var npm = require("../npm")
  , symlink = require("./utils/link")
  , fs = require("./utils/graceful-fs")
  , log = require("./utils/log")
  , asyncMap = require("./utils/async-map")
  , chain = require("./utils/chain")
  , path = require("path")
  , relativize = require("./utils/relativize")
  , rm = require("./utils/rm-rf")
  , output = require("./utils/output")

module.exports = link

link.usage = "npm link (in package dir)"
           + "\nnpm link <pkg> (link global into local)"

link.completion = function (opts, cb) {
  var dir = path.join(npm.config.get("prefix"), "node_modules")
  fs.readdir(dir, function (er, files) {
    cb(er, files.filter(function (f) {
      return f.charAt(0) !== "."
    }))
  })
}

function link (args, cb) {
  if (npm.config.get("global")) {
    return cb(new Error("link should never be --global."))
  }
  if (args.length) return linkInstall(args, cb)
  linkPkg(npm.prefix, cb)
}

function linkInstall (pkgs, cb) {
  var gp = npm.config.get("prefix")
  asyncMap(pkgs, function (pkg, cb) {
    var pp = path.resolve(gp, "node_modules", pkg)
      , rp = null
      , target = path.resolve(npm.dir, pkg)
    fs.lstat(pp, function (er, st) {
      if (er) {
        log.error(pkg, "not installed globally")
        next()
      } else if (!st.isSymbolicLink()) {
        log.warn(pkg, "not a symbolic link")
        rp = pp
        next()
      } else {
        return fs.realpath(pp, function (er, real) {
          if (er) log.warn(pkg, "invalid symbolic link")
          else rp = real
          next()
        })
      }
    })

    function next () {
      chain
        ( [npm.commands, "unbuild", [target]]
        , [symlink, pp, target]
        , rp && [npm.commands, "build", [target]]
        , [ resultPrinter, pkg, pp, target, rp ]
        , cb )
    }
  }, cb)
}

function linkPkg (folder, cb) {
  var gp = npm.config.get("prefix")
    , me = npm.prefix
    , readJson = require("./utils/read-json")
  readJson(path.resolve(folder, "package.json"), function (er, d) {
    if (er) return cb(er)
    var target = path.resolve(gp, "node_modules", d.name)
    rm(target, function (er) {
      if (er) return cb(er)
      symlink(me, target, function (er) {
        if (er) return cb(er)
        npm.commands.build([target], function (er) {
          if (er) return cb(er)
          resultPrinter(path.basename(me), me, target, cb)
        })
      })
    })
  })
}

function resultPrinter (pkg, src, dest, rp, cb) {
  if (typeof cb !== "function") cb = rp, rp = null
  var where = relativize(dest, path.resolve(process.cwd(),"x"))
  rp = (rp || "").trim()
  src = (src || "").trim()
  if (rp === src) rp = null
  output.write(where+"@ -> "+(src.trim())
              +(rp ? "@ -> "+rp: ""), cb)
}
<|endoftext|>


<commit_before>"use strict";
var _ = require('lodash');

module.exports = class Linq {

    constructor(injecttor, id, type) {
        this.injecttor = injecttor;
        this.definition = {
            type: type,
            inject: [],
            alias: [],
            aliasFactory: [],
            args: []
        };

        injecttor.addDefinition(id, this.definition)
    }

    type(type){
        this.definition.type = type;
    }

    singleton() {
        this.definition.singleton = true;
        return this
    }

    inject(name, inject) {

        if (_.isArray(name)) {
            this.definition.inject.push.apply(this.definition.inject, name)
        } else if (_.isObject(name)) {
            this.definition.inject.push(name)
        }

        else if (_.toArray(arguments).length == 1 && _.isString(name)) {
            this.definition.inject.push({name: name, ref: name})
        } else if (_.toArray(arguments).length == 2 && _.isString(name)) {
            this.definition.inject.push({name: name, ref: inject})
        }

        return this;
    }

    injectFactoryMethod(name, factoryMethod) {
        return this.inject({
            name: name,
            factoryMethod: factoryMethod
        })
    }

    injectAlias(name, alias) {
        return this.inject({
            name: name,
            alias: alias
        })
    }

    injectAliasFactory(name, alias) {
        return this.inject({
            name: name,
            aliasFactory: alias
        })
    }

    injectArray(name, arr) {
        return this.inject({
            name: name,
            array: arr
        })
    }

    injectDictionary(name, dic) {
        return this.inject({
            name: name,
            dictionary: dic
        })
    }

    injectFactory(name, factory) {
        return this.inject({
            name: name,
            factory: factory
        })
    }

    injectObjectProperty(name, object,propertyName) {
        return this.inject({
            name: name,
            objectProperty: {
                object:object,
                property:propertyName
            }
        })
    }

    injectorValue(name, value) {
        return this.inject({
            name: name,
            value: value
        })
    }

    alias(alias) {
        if (_.isArray(alias)) {
            this.definition.alias.push.apply(this.definition.alias, alias)
        } else {
            this.definition.alias.push(alias)
        }

        return this;
    }

    initMethod(initMethod) {
        this.definition.initMethod = initMethod || "initialize";
        return this;
    }

    injectorAware() {
        this.definition.injectorAware = true;
        return this;
    }

    aliasFactory(aliasFactory) {
        if (_.isArray(aliasFactory)) {
            this.definition.aliasFactory.push.apply(this.definition.aliasFactory, aliasFactory)
        } else {
            this.definition.aliasFactory.push(aliasFactory)
        }

        return this;
    }

    args(args) {
        if (_.isArray(args)) {
            this.definition.args.push.apply(this.definition.args, args)
        } else {
            this.definition.args.push(args)
        }
        return this;
    }

    define(id, type) {
        return this.injecttor.define(id, type)
    }

    initialize() {
        return this.injecttor.initialize()
    }

}<commit_msg>new linq syntax<commit_after>"use strict";
var _ = require('lodash');

module.exports = class Linq {

    constructor(injecttor, id, type) {
        this.injecttor = injecttor;
        this.definition = {
            type: type,
            inject: [],
            alias: [],
            aliasFactory: [],
            args: []
        };

        injecttor.addDefinition(id, this.definition)
    }

    type(type){
        this.definition.type = type;

        return this;
    }

    singleton() {
        this.definition.singleton = true;
        return this
    }

    inject(name, inject) {

        if (_.isArray(name)) {
            this.definition.inject.push.apply(this.definition.inject, name)
        } else if (_.isObject(name)) {
            this.definition.inject.push(name)
        }

        else if (_.toArray(arguments).length == 1 && _.isString(name)) {
            this.definition.inject.push({name: name, ref: name})
        } else if (_.toArray(arguments).length == 2 && _.isString(name)) {
            this.definition.inject.push({name: name, ref: inject})
        }

        return this;
    }

    injectFactoryMethod(name, factoryMethod) {
        return this.inject({
            name: name,
            factoryMethod: factoryMethod
        })
    }

    injectAlias(name, alias) {
        return this.inject({
            name: name,
            alias: alias
        })
    }

    injectAliasFactory(name, alias) {
        return this.inject({
            name: name,
            aliasFactory: alias
        })
    }

    injectArray(name, arr) {
        return this.inject({
            name: name,
            array: arr
        })
    }

    injectDictionary(name, dic) {
        return this.inject({
            name: name,
            dictionary: dic
        })
    }

    injectFactory(name, factory) {
        return this.inject({
            name: name,
            factory: factory
        })
    }

    injectObjectProperty(name, object,propertyName) {
        return this.inject({
            name: name,
            objectProperty: {
                object:object,
                property:propertyName
            }
        })
    }

    injectorValue(name, value) {
        return this.inject({
            name: name,
            value: value
        })
    }

    alias(alias) {
        if (_.isArray(alias)) {
            this.definition.alias.push.apply(this.definition.alias, alias)
        } else {
            this.definition.alias.push(alias)
        }

        return this;
    }

    initMethod(initMethod) {
        this.definition.initMethod = initMethod || "initialize";
        return this;
    }

    injectorAware() {
        this.definition.injectorAware = true;
        return this;
    }

    aliasFactory(aliasFactory) {
        if (_.isArray(aliasFactory)) {
            this.definition.aliasFactory.push.apply(this.definition.aliasFactory, aliasFactory)
        } else {
            this.definition.aliasFactory.push(aliasFactory)
        }

        return this;
    }

    args(args) {
        if (_.isArray(args)) {
            this.definition.args.push.apply(this.definition.args, args)
        } else {
            this.definition.args.push(args)
        }
        return this;
    }

    define(id, type) {
        return this.injecttor.define(id, type)
    }

    initialize() {
        return this.injecttor.initialize()
    }

}<|endoftext|>


<commit_before>const { sqldb, sqlLoader } = require('@prairielearn/prairielib');
const logger = require('./logger');
const config = require('./config').config;
const sql = sqlLoader.loadSqlEquiv(__filename);

var initialized = false;
var currentJobs, maxJobs, lastEstimateTimeMS, lastIncrementTimeMS, integratedLoad;

module.exports = {
    init(newMaxJobs) {
        maxJobs = newMaxJobs;
        const nowMS = Date.now();
        lastEstimateTimeMS = nowMS;
        lastIncrementTimeMS = nowMS;
        integratedLoad = 0;
        currentJobs = 0;
        maxJobs = newMaxJobs;
        initialized = true;
        this._reportLoad();
    },

    startJob() {
        if (!initialized) return;
        this._addIntegratedLoad();
        currentJobs++;
        if (currentJobs > maxJobs) throw new Error('startJob(): currentJobs > maxJobs');
    },

    endJob() {
        if (!initialized) return;
        this._addIntegratedLoad();
        currentJobs--;
        if (currentJobs < 0) throw new Error('startJob(): currentJobs < 0');
    },

    _getAndResetLoadEstimate() {
        this._addIntegratedLoad();
        const nowMS = Date.now();
        const deltaSeconds = Math.max(1, nowMS - lastEstimateTimeMS) / 1000;
        const loadEstimate = integratedLoad / deltaSeconds;

        // reset stats
        lastEstimateTimeMS = nowMS;
        lastIncrementTimeMS = nowMS;
        integratedLoad = 0;

        return loadEstimate;
    },

    _addIntegratedLoad() {
        const nowMS = Date.now();
        const delta = Math.max(1, nowMS - lastIncrementTimeMS) / 1000;
        integratedLoad += delta * currentJobs;
        lastIncrementTimeMS = nowMS;
    },

    _reportLoad() {
        var params = {
            instance_id: config.instanceId,
            queue_name: config.queueName,
            average_jobs: this._getAndResetLoadEstimate(),
            max_jobs: maxJobs,
        };
        sqldb.query(sql.insert_load, params, (err) => {
            if (err) logger.error('Error reporting load: ' + String(err));
            setTimeout(this._reportLoad.bind(this), config.reportIntervalSec * 1000);
        });
    },
};
<commit_msg>Fix load reporting for new queue names (#42)<commit_after>const { sqldb, sqlLoader } = require('@prairielearn/prairielib');
const logger = require('./logger');
const config = require('./config').config;
const sql = sqlLoader.loadSqlEquiv(__filename);

var initialized = false;
var currentJobs, maxJobs, lastEstimateTimeMS, lastIncrementTimeMS, integratedLoad;

module.exports = {
    init(newMaxJobs) {
        maxJobs = newMaxJobs;
        const nowMS = Date.now();
        lastEstimateTimeMS = nowMS;
        lastIncrementTimeMS = nowMS;
        integratedLoad = 0;
        currentJobs = 0;
        maxJobs = newMaxJobs;
        initialized = true;
        this._reportLoad();
    },

    startJob() {
        if (!initialized) return;
        this._addIntegratedLoad();
        currentJobs++;
        if (currentJobs > maxJobs) throw new Error('startJob(): currentJobs > maxJobs');
    },

    endJob() {
        if (!initialized) return;
        this._addIntegratedLoad();
        currentJobs--;
        if (currentJobs < 0) throw new Error('startJob(): currentJobs < 0');
    },

    _getAndResetLoadEstimate() {
        this._addIntegratedLoad();
        const nowMS = Date.now();
        const deltaSeconds = Math.max(1, nowMS - lastEstimateTimeMS) / 1000;
        const loadEstimate = integratedLoad / deltaSeconds;

        // reset stats
        lastEstimateTimeMS = nowMS;
        lastIncrementTimeMS = nowMS;
        integratedLoad = 0;

        return loadEstimate;
    },

    _addIntegratedLoad() {
        const nowMS = Date.now();
        const delta = Math.max(1, nowMS - lastIncrementTimeMS) / 1000;
        integratedLoad += delta * currentJobs;
        lastIncrementTimeMS = nowMS;
    },

    _reportLoad() {
        var params = {
            instance_id: config.instanceId,
            queue_name: config.jobsQueueName,
            average_jobs: this._getAndResetLoadEstimate(),
            max_jobs: maxJobs,
        };
        sqldb.query(sql.insert_load, params, (err) => {
            if (err) logger.error('Error reporting load: ' + String(err));
            setTimeout(this._reportLoad.bind(this), config.reportIntervalSec * 1000);
        });
    },
};
<|endoftext|>


<commit_before>/**
 * This library calculates the current phase of the moon
 * as well as finds the dates of the recent moon phases.
 *
 * Ported from python version found here:
 * https://bazaar.launchpad.net/~keturn/py-moon-phase/trunk/annotate/head:/moon.py
 *
 * Author: Ryan Seys (https://github.com/ryanseys)
 */

'use strict'

const julian = require('./julian')

// Phases of the moon & precision
const NEW = 0
const FIRST = 1
const FULL = 2
const LAST = 3

// Astronomical Constants
// JDN stands for Julian Day Number
// Angles here are in degrees
// 1980 January 0.0 in JDN
// XXX: DateTime(1980).jdn yields 2444239.5 -- which one is right?
// XXX: even though 2444239.5 is correct for the 1 Jan 1980, 2444238.5 gives
// better accuracy results... possibly somebody chose all of the below
// constants based on the wrong epoch?
const EPOCH = 2444238.5

// Ecliptic longitude of the Sun at epoch 1980.0
const ECLIPTIC_LONGITUDE_EPOCH = 278.833540

// Ecliptic longitude of the Sun at perigee
const ECLIPTIC_LONGITUDE_PERIGEE = 282.596403

// Eccentricity of Earth's orbit
const ECCENTRICITY = 0.016718

// Semi-major axis of Earth's orbit, in kilometers
const SUN_SMAXIS = 1.49585e8

// Sun's angular size, in degrees, at semi-major axis distance
const SUN_ANGULAR_SIZE_SMAXIS = 0.533128

// Elements of the Moon's orbit, epoch 1980.0
// Moon's mean longitude at the epoch
const MOON_MEAN_LONGITUDE_EPOCH = 64.975464

// Mean longitude of the perigee at the epoch
const MOON_MEAN_PERIGEE_EPOCH = 349.383063

// Eccentricity of the Moon's orbit
const MOON_ECCENTRICITY = 0.054900

// Moon's angular size at distance a from Earth
const MOON_ANGULAR_SIZE = 0.5181

// Semi-mojor axis of the Moon's orbit, in kilometers
const MOON_SMAXIS = 384401.0

// Synodic month (new Moon to new Moon), in days
const SYNODIC_MONTH = 29.53058868

function fixangle (a) {
  return a - 360.0 * Math.floor(a / 360.0)
}

/**
 * Convert degrees to radians
 * @param  {Number} d Angle in degrees
 * @return {Number}   Angle in radians
 */
function torad (d) {
  return (Math.PI / 180.0) * d
}

/**
 * Convert radians to degrees
 * @param  {Number} r Angle in radians
 * @return {Number}   Angle in degrees
 */
function todeg (r) {
  return (180.0 / Math.PI) * r
}

function dsin (d) {
  return Math.sin(torad(d))
}

function dcos (d) {
  return Math.cos(torad(d))
}

/**
 * Solve the equation of Kepler.
 */
function kepler (m, ecc) {
  const epsilon = 1e-6

  m = torad(m)
  let e = m
  while (1) {
    const delta = e - ecc * Math.sin(e) - m
    e -= delta / (1.0 - ecc * Math.cos(e))

    if (Math.abs(delta) <= epsilon) {
      break
    }
  }

  return e
}

/**
 * Finds the phase information for specific date.
 * @param  {Date} phase_date Date to get phase information of.
 * @return {Object}          Phase data
 */
function phase (phase_date) {
  if (!phase_date) {
    phase_date = new Date()
  }
  phase_date = julian.fromDate(phase_date)

  const day = phase_date - EPOCH

  // Mean anomaly of the Sun
  // XXX: capital vars should only be used for local constants
  const N = fixangle((360 / 365.2422) * day)

  // Convert from perigee coordinates to epoch 1980
  // XXX: capital vars should only be used for local constants
  const M = fixangle(N + ECLIPTIC_LONGITUDE_EPOCH - ECLIPTIC_LONGITUDE_PERIGEE)

  // Solve Kepler's equation
  // True anomaly
  // XXX: capital vars should only be used for local constants
  let Ec = kepler(M, ECCENTRICITY)
  Ec = Math.sqrt((1 + ECCENTRICITY) / (1 - ECCENTRICITY)) * Math.tan(Ec / 2)
  Ec = 2 * todeg(Math.atan(Ec))

  // Suns's geometric ecliptic longuitude
  const lambda_sun = fixangle(Ec + ECLIPTIC_LONGITUDE_PERIGEE)

  // Orbital distance factor
  // XXX: capital vars should only be used for local constants
  const F = ((1 + ECCENTRICITY * dcos(Ec)) / (1 - ECCENTRICITY * ECCENTRICITY))

  // Distance to Sun in km
  const sun_dist = SUN_SMAXIS / F
  const sun_angular_diameter = F * SUN_ANGULAR_SIZE_SMAXIS

  // Calculation of the Moon's position

  // Moon's mean longitude
  const moon_longitude = fixangle(13.1763966 * day + MOON_MEAN_LONGITUDE_EPOCH)

  // Moon's mean anomaly
  // XXX: capital vars should only be used for local constants
  const MM = fixangle(moon_longitude - 0.1114041 * day - MOON_MEAN_PERIGEE_EPOCH)

  const evection = 1.2739 * dsin(2 * (moon_longitude - lambda_sun) - MM)

  // Annual equation
  const annual_eq = 0.1858 * dsin(M)

  // Correction term
  // XXX: capital vars should only be used for local constants
  const A3 = 0.37 * dsin(M)

  // XXX: capital vars should only be used for local constants
  const MmP = MM + evection - annual_eq - A3

  // Correction for the equation of the centre
  const mEc = 6.2886 * dsin(MmP)

  // Another correction term
  // XXX: capital vars should only be used for local constants
  const A4 = 0.214 * dsin(2 * MmP)

  // Corrected longitude
  const lP = moon_longitude + evection + mEc - annual_eq + A4

  // Variation
  const variation = 0.6583 * dsin(2 * (lP - lambda_sun))

  // True longitude
  const lPP = lP + variation

  // Calculation of the phase of the Moon

  // Age of the Moon, in degrees
  const moon_age = lPP - lambda_sun

  // Phase of the Moon
  const moon_phase = (1 - dcos(moon_age)) / 2.0

  // Calculate distance of Moon from the centre of the Earth
  const moon_dist = (MOON_SMAXIS * (1 - MOON_ECCENTRICITY * MOON_ECCENTRICITY)) / (1 + MOON_ECCENTRICITY * dcos(MmP + mEc))

  // Calculate Moon's angular diameter
  const moon_diam_frac = moon_dist / MOON_SMAXIS
  const moon_angular_diameter = MOON_ANGULAR_SIZE / moon_diam_frac

  return {
    phase: fixangle(moon_age) / 360.0,
    illuminated: moon_phase,
    age: SYNODIC_MONTH * fixangle(moon_age) / 360.0,
    distance: moon_dist,
    angular_diameter: moon_angular_diameter,
    sun_distance: sun_dist,
    sun_angular_diameter: sun_angular_diameter
  }
}

/**
 * Calculates time of the mean new Moon for a given base date.
 * This argument K to this function is the precomputed synodic month
 * index, given by:
 *   K = (year - 1900) * 12.3685
 * where year is expressed as a year and fractional year.
 * @param  {Date} sdate   Start date
 * @param  {[type]} k     [description]
 * @return {[type]}       [description]
 */
function meanphase (sdate, k) {
  // Time in Julian centuries from 1900 January 12 noon UTC
  const delta_t = (sdate - -2208945600000.0) / 86400000.0
  const t = delta_t / 36525
  return 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)
}

/**
 * Given a K value used to determine the mean phase of the new
 * moon, and a phase selector (0.0, 0.25, 0.5, 0.75), obtain the
 * true, corrected phase time.
 * @param  {[type]} k      [description]
 * @param  {[type]} tphase [description]
 * @return {[type]}        [description]
 */
function truephase (k, tphase) {
  // add phase to new moon time
  k = k + 0.25 * tphase

  // Time in Julian centuries from 1900 January 0.5
  const t = k / 1236.85

  // Mean time of phase
  let pt = 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)

  // Sun's mean anomaly
  const m = 359.2242 + 29.10535608 * k - (0.0000333 - 0.00000347 * t) * t * t

  // Moon's mean anomaly
  const mprime = 306.0253 + 385.81691806 * k + (0.0107306 + 0.00001236 * t) * t * t

  // Moon's argument of latitude
  const f = 21.2964 + 390.67050646 * k - (0.0016528 - 0.00000239 * t) * t * t

  switch (tphase & 3) {
    case NEW:
    case FULL:
      pt += (0.1734 - 0.000393 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.4068 * dsin(mprime) +
        0.0161 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0104 * dsin(2 * f) -
        0.0051 * dsin(m + mprime) -
        0.0074 * dsin(m - mprime) +
        0.0004 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0010 * dsin(2 * f - mprime) +
        0.0005 * dsin(m + 2 * mprime)
      break

    case FIRST:
    case LAST:
      pt += (0.1721 - 0.0004 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.6280 * dsin(mprime) +
        0.0089 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0079 * dsin(2 * f) -
        0.0119 * dsin(m + mprime) -
        0.0047 * dsin(m - mprime) +
        0.0003 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0021 * dsin(2 * f - mprime) +
        0.0003 * dsin(m + 2 * mprime) +
        0.0004 * dsin(m - 2 * mprime) -
        0.0003 * dsin(2 * m + mprime)

      switch (tphase & 1) {
        case (FIRST & 1):
          pt += 0.0028 - 0.0004 * dcos(m) + 0.0003 * dcos(mprime)
          break

        case (LAST & 1):
          pt += -0.0028 + 0.0004 * dcos(m) - 0.0003 * dcos(mprime)
          break
      }
      break
  }

  return julian.toDate(pt)
}

/**
 * Find time of phases of the moon which surround the current date.
 * Five phases are found, starting and ending with the new moons
 * which bound the current lunation.
 * @param  {Date} sdate Date to start hunting from (defaults to current date)
 * @return {Object}     Object containing recent past and future phases
 */
function phase_hunt (sdate) {
  if (!sdate) {
    sdate = new Date()
  }

  let adate = new Date(sdate.getTime() - (45 * 86400000)) // 45 days prior
  let k1 = Math.floor(12.3685 * (adate.getFullYear() + ((1.0 / 12.0) * adate.getMonth()) - 1900))
  let nt1 = meanphase(adate.getTime(), k1)

  sdate = julian.fromDate(sdate)
  adate = nt1

  let k2
  let nt2
  while (1) {
    adate = adate + SYNODIC_MONTH
    k2 = k1 + 1
    nt2 = meanphase(adate, k2)
    if (nt1 <= sdate && sdate < nt2) {
      break
    }
    nt1 = nt2
    k1 = k2
  }

  return {
    new_date: truephase(k1, NEW),
    q1_date: truephase(k1, FIRST),
    full_date: truephase(k1, FULL),
    q3_date: truephase(k1, LAST),
    nextnew_date: truephase(k2, NEW)
  }
}

exports.phase = phase
exports.phase_hunt = phase_hunt
<commit_msg>Cleared out some of the weird variable names.<commit_after>/**
 * This library calculates the current phase of the moon
 * as well as finds the dates of the recent moon phases.
 *
 * Ported from python version found here:
 * https://bazaar.launchpad.net/~keturn/py-moon-phase/trunk/annotate/head:/moon.py
 *
 * Author: Ryan Seys (https://github.com/ryanseys)
 */

'use strict'

const julian = require('./julian')

// Phases of the moon & precision
const NEW = 0
const FIRST = 1
const FULL = 2
const LAST = 3

// Astronomical Constants
// JDN stands for Julian Day Number
// Angles here are in degrees
// 1980 January 0.0 in JDN
// XXX: DateTime(1980).jdn yields 2444239.5 -- which one is right?
// XXX: even though 2444239.5 is correct for the 1 Jan 1980, 2444238.5 gives
// better accuracy results... possibly somebody chose all of the below
// constants based on the wrong epoch?
const EPOCH = 2444238.5

// Ecliptic longitude of the Sun at epoch 1980.0
const ECLIPTIC_LONGITUDE_EPOCH = 278.833540

// Ecliptic longitude of the Sun at perigee
const ECLIPTIC_LONGITUDE_PERIGEE = 282.596403

// Eccentricity of Earth's orbit
const ECCENTRICITY = 0.016718

// Semi-major axis of Earth's orbit, in kilometers
const SUN_SMAXIS = 1.49585e8

// Sun's angular size, in degrees, at semi-major axis distance
const SUN_ANGULAR_SIZE_SMAXIS = 0.533128

// Elements of the Moon's orbit, epoch 1980.0
// Moon's mean longitude at the epoch
const MOON_MEAN_LONGITUDE_EPOCH = 64.975464

// Mean longitude of the perigee at the epoch
const MOON_MEAN_PERIGEE_EPOCH = 349.383063

// Eccentricity of the Moon's orbit
const MOON_ECCENTRICITY = 0.054900

// Moon's angular size at distance a from Earth
const MOON_ANGULAR_SIZE = 0.5181

// Semi-mojor axis of the Moon's orbit, in kilometers
const MOON_SMAXIS = 384401.0

// Synodic month (new Moon to new Moon), in days
const SYNODIC_MONTH = 29.53058868

function fixangle (a) {
  return a - 360.0 * Math.floor(a / 360.0)
}

/**
 * Convert degrees to radians
 * @param  {Number} d Angle in degrees
 * @return {Number}   Angle in radians
 */
function torad (d) {
  return (Math.PI / 180.0) * d
}

/**
 * Convert radians to degrees
 * @param  {Number} r Angle in radians
 * @return {Number}   Angle in degrees
 */
function todeg (r) {
  return (180.0 / Math.PI) * r
}

function dsin (d) {
  return Math.sin(torad(d))
}

function dcos (d) {
  return Math.cos(torad(d))
}

/**
 * Solve the equation of Kepler.
 */
function kepler (m, ecc) {
  const epsilon = 1e-6

  m = torad(m)
  let e = m
  while (1) {
    const delta = e - ecc * Math.sin(e) - m
    e -= delta / (1.0 - ecc * Math.cos(e))

    if (Math.abs(delta) <= epsilon) {
      break
    }
  }

  return e
}

/**
 * Finds the phase information for specific date.
 * @param  {Date} phase_date Date to get phase information of.
 * @return {Object}          Phase data
 */
function phase (phase_date) {
  if (!phase_date) {
    phase_date = new Date()
  }
  phase_date = julian.fromDate(phase_date)

  const day = phase_date - EPOCH

  // Mean anomaly of the Sun
  // Convert from perigee coordinates to epoch 1980
  const sun_mean_anomaly = fixangle((360 / 365.2422) * day + ECLIPTIC_LONGITUDE_EPOCH - ECLIPTIC_LONGITUDE_PERIGEE)

  // Solve Kepler's equation
  // True anomaly
  const sun_true_anomaly = 2 * todeg(Math.atan(Math.sqrt((1 + ECCENTRICITY) / (1 - ECCENTRICITY)) * Math.tan(0.5 * kepler(sun_mean_anomaly, ECCENTRICITY))))

  // Suns's geometric ecliptic longuitude
  const sun_ecliptic_longitude = fixangle(sun_true_anomaly + ECLIPTIC_LONGITUDE_PERIGEE)

  // Orbital distance factor
  // XXX: capital vars should only be used for local constants
  const sun_orbital_distance_factor = ((1 + ECCENTRICITY * dcos(sun_true_anomaly)) / (1 - ECCENTRICITY * ECCENTRICITY))

  // Calculation of the Moon's position

  // Moon's mean longitude
  const moon_longitude = fixangle(13.1763966 * day + MOON_MEAN_LONGITUDE_EPOCH)

  // Moon's mean anomaly
  // XXX: capital vars should only be used for local constants
  const MM = fixangle(moon_longitude - 0.1114041 * day - MOON_MEAN_PERIGEE_EPOCH)

  const evection = 1.2739 * dsin(2 * (moon_longitude - sun_ecliptic_longitude) - MM)

  // Annual equation
  const annual_eq = 0.1858 * dsin(sun_mean_anomaly)

  // Correction term
  // XXX: capital vars should only be used for local constants
  const A3 = 0.37 * dsin(sun_mean_anomaly)

  // XXX: capital vars should only be used for local constants
  const MmP = MM + evection - annual_eq - A3

  // Correction for the equation of the centre
  const mEc = 6.2886 * dsin(MmP)

  // Another correction term
  // XXX: capital vars should only be used for local constants
  const A4 = 0.214 * dsin(2 * MmP)

  // Corrected longitude
  const lP = moon_longitude + evection + mEc - annual_eq + A4

  // Variation
  const variation = 0.6583 * dsin(2 * (lP - sun_ecliptic_longitude))

  // True longitude
  const lPP = lP + variation

  // Calculation of the phase of the Moon

  // Age of the Moon, in degrees
  const moon_age = fixangle(lPP - sun_ecliptic_longitude)

  // Calculate distance of Moon from the centre of the Earth
  const moon_distance = (MOON_SMAXIS * (1 - MOON_ECCENTRICITY * MOON_ECCENTRICITY)) / (1 + MOON_ECCENTRICITY * dcos(MmP + mEc))

  return {
    phase: (1.0 / 360.0) * moon_age,
    illuminated: 0.5 * (1.0 - dcos(moon_age)),
    age: (SYNODIC_MONTH / 360.0) * moon_age,
    distance: moon_distance,
    angular_diameter: MOON_ANGULAR_SIZE * MOON_SMAXIS / moon_distance,
    sun_distance: SUN_SMAXIS / sun_orbital_distance_factor,
    sun_angular_diameter: SUN_ANGULAR_SIZE_SMAXIS * sun_orbital_distance_factor
  }
}

/**
 * Calculates time of the mean new Moon for a given base date.
 * This argument K to this function is the precomputed synodic month
 * index, given by:
 *   K = (year - 1900) * 12.3685
 * where year is expressed as a year and fractional year.
 * @param  {Date} sdate   Start date
 * @param  {[type]} k     [description]
 * @return {[type]}       [description]
 */
function meanphase (sdate, k) {
  // Time in Julian centuries from 1900 January 12 noon UTC
  const delta_t = (sdate - -2208945600000.0) / 86400000.0
  const t = delta_t / 36525
  return 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)
}

/**
 * Given a K value used to determine the mean phase of the new
 * moon, and a phase selector (0.0, 0.25, 0.5, 0.75), obtain the
 * true, corrected phase time.
 * @param  {[type]} k      [description]
 * @param  {[type]} tphase [description]
 * @return {[type]}        [description]
 */
function truephase (k, tphase) {
  // add phase to new moon time
  k = k + 0.25 * tphase

  // Time in Julian centuries from 1900 January 0.5
  const t = k / 1236.85

  // Mean time of phase
  let pt = 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)

  // Sun's mean anomaly
  const m = 359.2242 + 29.10535608 * k - (0.0000333 - 0.00000347 * t) * t * t

  // Moon's mean anomaly
  const mprime = 306.0253 + 385.81691806 * k + (0.0107306 + 0.00001236 * t) * t * t

  // Moon's argument of latitude
  const f = 21.2964 + 390.67050646 * k - (0.0016528 - 0.00000239 * t) * t * t

  switch (tphase & 3) {
    case NEW:
    case FULL:
      pt += (0.1734 - 0.000393 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.4068 * dsin(mprime) +
        0.0161 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0104 * dsin(2 * f) -
        0.0051 * dsin(m + mprime) -
        0.0074 * dsin(m - mprime) +
        0.0004 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0010 * dsin(2 * f - mprime) +
        0.0005 * dsin(m + 2 * mprime)
      break

    case FIRST:
    case LAST:
      pt += (0.1721 - 0.0004 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.6280 * dsin(mprime) +
        0.0089 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0079 * dsin(2 * f) -
        0.0119 * dsin(m + mprime) -
        0.0047 * dsin(m - mprime) +
        0.0003 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0021 * dsin(2 * f - mprime) +
        0.0003 * dsin(m + 2 * mprime) +
        0.0004 * dsin(m - 2 * mprime) -
        0.0003 * dsin(2 * m + mprime)

      switch (tphase & 1) {
        case (FIRST & 1):
          pt += 0.0028 - 0.0004 * dcos(m) + 0.0003 * dcos(mprime)
          break

        case (LAST & 1):
          pt += -0.0028 + 0.0004 * dcos(m) - 0.0003 * dcos(mprime)
          break
      }
      break
  }

  return julian.toDate(pt)
}

/**
 * Find time of phases of the moon which surround the current date.
 * Five phases are found, starting and ending with the new moons
 * which bound the current lunation.
 * @param  {Date} sdate Date to start hunting from (defaults to current date)
 * @return {Object}     Object containing recent past and future phases
 */
function phase_hunt (sdate) {
  if (!sdate) {
    sdate = new Date()
  }

  let adate = new Date(sdate.getTime() - (45 * 86400000)) // 45 days prior
  let k1 = Math.floor(12.3685 * (adate.getFullYear() + ((1.0 / 12.0) * adate.getMonth()) - 1900))
  let nt1 = meanphase(adate.getTime(), k1)

  sdate = julian.fromDate(sdate)
  adate = nt1

  let k2
  let nt2
  while (1) {
    adate = adate + SYNODIC_MONTH
    k2 = k1 + 1
    nt2 = meanphase(adate, k2)
    if (nt1 <= sdate && sdate < nt2) {
      break
    }
    nt1 = nt2
    k1 = k2
  }

  return {
    new_date: truephase(k1, NEW),
    q1_date: truephase(k1, FIRST),
    full_date: truephase(k1, FULL),
    q3_date: truephase(k1, LAST),
    nextnew_date: truephase(k2, NEW)
  }
}

exports.phase = phase
exports.phase_hunt = phase_hunt
<|endoftext|>


<commit_before>window.onload = () => {
    let Engine = Matter.Engine,
        Render = Matter.Render,
        Runner = Matter.Runner,
        Composites = Matter.Composites,
        Common = Matter.Common,
        MouseConstraint = Matter.MouseConstraint,
        Mouse = Matter.Mouse,
        World = Matter.World,
        Bodies = Matter.Bodies;

    // create engine
    let engine = Engine.create(),
        world = engine.world;

    // create renderer
    let render = Render.create({
        element: document.body,
        engine: engine,
        options: {
            width: Math.min(document.documentElement.clientWidth, 1920),
            height: Math.min(document.documentElement.clientHeight, 1080),
            background: './img/back.png',
            showAngleIndicator: false,
            wireframes: false
        }
    });

    Render.run(render);

    // create runner
    let runner = Runner.create();
    Runner.run(runner, engine);

    // add bodies
    let offset = 10,
        options = {
            isStatic: true
        };

    world.bodies = [];

    // these static walls will not be rendered in this sprites example, see options
    World.add(world, [
        Bodies.rectangle(400, 600, 800, 50, options),
        Bodies.rectangle(800 + offset, 300, 50.5, 600.5 + 2 * offset, options),
        Bodies.rectangle(-offset, 300, 50.5, 600.5 + 2 * offset, options)
    ]);

    let jiro = Composites.stack(230, 538, 1, 1, 0, 0, function(x, y) {
      return Bodies.rectangle(x, y, 340, 140, {
        frictionAir: 0.25,
        friction: 0.7,
        render: {
          sprite: {
            texture: './img/don.png'
          },
        }
      })
    });

    World.add(world, jiro);

    // add mouse control
    let mouse = Mouse.create(render.canvas),
        mouseConstraint = MouseConstraint.create(engine, {
            mouse: mouse,
            constraint: {
                stiffness: 0.2,
                render: {
                    visible: false
                }
            }
        });

    World.add(world, mouseConstraint);

    // keep the mouse in sync with rendering
    render.mouse = mouse;

    // fit the render viewport to the scene
    Render.lookAt(render, {
        min: { x: 0, y: 0 },
        max: { x: 800, y: 600 }
    });

    // context for MatterTools.Demo
    return {
        engine: engine,
        runner: runner,
        render: render,
        canvas: render.canvas,
        stop: function() {
            Matter.Render.stop(render);
            Matter.Runner.stop(runner);
        }
    };
};
<commit_msg>マージしたら死んだので修正<commit_after>window.onload = () => {
    let Engine = Matter.Engine,
        Render = Matter.Render,
        Runner = Matter.Runner,
        Composites = Matter.Composites,
        Common = Matter.Common,
        MouseConstraint = Matter.MouseConstraint,
        Mouse = Matter.Mouse,
        World = Matter.World,
        Bodies = Matter.Bodies;

    // create engine
    let engine = Engine.create(),
        world = engine.world;

    // create renderer
    let render = Render.create({
        element: document.body,
        engine: engine,
        options: {
            width: Math.min(document.documentElement.clientWidth, 1920),
            height: Math.min(document.documentElement.clientHeight, 1080),
            background: './img/back.png',
            showAngleIndicator: false,
            wireframes: false
        }
    });

    Render.run(render);

    // create runner
    let runner = Runner.create();
    Runner.run(runner, engine);

    // add bodies
    let offset = 10,
        options = {
            isStatic: true
        };

    world.bodies = [];

    // these static walls will not be rendered in this sprites example, see options
    World.add(world, [
        Bodies.rectangle(400, 600, 800, 50, options),
        Bodies.rectangle(800 + offset, 300, 50.5, 600.5 + 2 * offset, options),
        Bodies.rectangle(-offset, 300, 50.5, 600.5 + 2 * offset, options)
    ]);

    let jiro = Composites.stack(230, 525, 1, 1, 0, 0, function(x, y) {
      return Bodies.rectangle(x, y, 340, 140, {
        frictionAir: 0.25,
        friction: 0.7,
        render: {
          sprite: {
            texture: './img/don.png'
          },
        }
      })
    });

    World.add(world, jiro);

    // add mouse control
    let mouse = Mouse.create(render.canvas),
        mouseConstraint = MouseConstraint.create(engine, {
            mouse: mouse,
            constraint: {
                stiffness: 0.2,
                render: {
                    visible: false
                }
            }
        });

    World.add(world, mouseConstraint);

    // keep the mouse in sync with rendering
    render.mouse = mouse;

    // fit the render viewport to the scene
    Render.lookAt(render, {
        min: { x: 0, y: 0 },
        max: { x: 800, y: 600 }
    });

    // context for MatterTools.Demo
    return {
        engine: engine,
        runner: runner,
        render: render,
        canvas: render.canvas,
        stop: function() {
            Matter.Render.stop(render);
            Matter.Runner.stop(runner);
        }
    };
};
<|endoftext|>