<commit_before>import R from 'ramda'
import { PAGE_SIZE } from 'config'
import {
  asyncRes,
  asyncErr,
  makeDebugger,
  EVENT,
  ERR,
  TYPE,
  $solver,
  scrollIntoEle,
  countWords,
  dispatchEvent,
  extractMentions,
  errRescue,
} from 'utils'

import SR71 from 'utils/async/sr71'
import S from './schema'

const sr71$ = new SR71()
let sub$ = null
let store = null

/* eslint-disable-next-line */
const debug = makeDebugger('L:Comments')

/* DESC_INSERTED, ASC_INSERTED */
const defaultArgs = {
  fresh: false,
  filter: { page: 1, size: PAGE_SIZE.D, sort: TYPE.ASC_INSERTED },
}

export const loadComents = (args = {}) => {
  // debug('loadComents passed in: ', args)
  args = R.mergeDeepRight(defaultArgs, args)
  args.id = store.viewingData.id
  args.userHasLogin = store.isLogin
  args.thread = store.activeThread

  markLoading(args.fresh)
  store.markState({ filterType: args.filter.sort })

  debug('pagedComments args: ', args)
  sr71$.query(S.pagedComments, args)
}

const markLoading = fresh => {
  if (fresh) {
    return store.markState({ loadingFresh: true })
  }
  return store.markState({ loading: true })
}

export const createComment = () => {
  if (!store.validator('create')) return false

  store.markState({ creating: true })
  const args = {
    id: store.viewingData.id,
    body: store.editContent,
    thread: store.activeThread,
    community: store.curCommunity.raw,
    mentionUsers: R.map(user => ({ id: user.id }), store.referUsersData),
  }

  debug('createComment args: ', args)
  sr71$.mutate(S.createComment, args)
}

export const createCommentPreview = () =>
  store.markState({
    showInputEditor: false,
    showInputPreview: true,
  })

export const backToEditor = () =>
  store.markState({
    showInputEditor: true,
    showInputPreview: false,
  })

export const previewReply = data => {
  debug('previewReply --> : ', data)
}

export const openInputBox = () => {
  if (!store.isLogin) return store.authWarning({ hideToast: true })

  store.markState({
    showInputBox: true,
    showInputEditor: true,
  })
}

export const openCommentEditor = () =>
  store.markState({
    showInputEditor: true,
  })

export const onCommentInputBlur = () =>
  store.markState({
    showInputBox: false,
    showInputPreview: false,
    showInputEditor: false,
  })

export const createReplyComment = () => {
  if (!store.validator('reply')) return false

  if (store.isEdit) {
    return sr71$.mutate(S.updateComment, {
      id: store.editCommentData.id,
      body: store.replyContent,
      thread: store.activeThread,
    })
  }

  sr71$.mutate(S.replyComment, {
    id: store.replyToComment.id,
    body: store.replyContent,
    community: store.curCommunity.raw,
    thread: store.activeThread,
    mentionUsers: R.map(user => ({ id: user.id }), store.referUsersData),
  })
}

export const onCommentInputChange = editContent =>
  store.markState({
    countCurrent: countWords(editContent),
    extractMentions: extractMentions(editContent),
    editContent,
  })

export const onReplyInputChange = replyContent =>
  store.markState({
    countCurrent: countWords(replyContent),
    extractMentions: extractMentions(replyContent),
    replyContent,
  })

export const openUpdateEditor = data =>
  store.markState({
    isEdit: true,
    showReplyBox: true,
    showReplyEditor: true,
    showReplyPreview: false,
    editComment: data,
    replyContent: data.body,
  })

export const openReplyEditor = data =>
  store.markState({
    showReplyBox: true,
    showReplyEditor: true,
    showReplyPreview: false,
    replyToComment: data,
    replyContent: '',
    isEdit: false,
  })

export const replyCommentPreview = () =>
  store.markState({
    showReplyEditor: false,
    showReplyPreview: true,
  })

export const replyBackToEditor = () =>
  store.markState({
    showReplyEditor: true,
    showReplyPreview: false,
  })

export const closeReplyBox = () =>
  store.markState({
    showReplyBox: false,
    showReplyEditor: false,
    showReplyPreview: false,
  })

export const onFilterChange = filterType => {
  store.markState({ filterType })
  loadComents({ filter: { page: 1, sort: filterType } })
}

export const toggleLikeComment = comment => {
  // TODO: check login first
  debug('likeComment: ', comment)

  if (comment.viewerHasLiked) {
    return sr71$.mutate(S.undoLikeComment, {
      id: comment.id,
    })
  }
  return sr71$.mutate(S.likeComment, {
    id: comment.id,
  })
}

export const toggleDislikeComment = comment => {
  // TODO: check login first
  if (comment.viewerHasDisliked) {
    return sr71$.mutate(S.undoDislikeComment, {
      id: comment.id,
    })
  }
  return sr71$.mutate(S.dislikeComment, {
    id: comment.id,
  })
}

export const onUploadImageDone = url =>
  dispatchEvent(EVENT.DRAFT_INSERT_SNIPPET, { data: `![](${url})` })

export const insertQuote = () =>
  dispatchEvent(EVENT.DRAFT_INSERT_SNIPPET, { data: '> ' })

export const insertCode = () => {
  const communityRaw = store.curCommunity.raw
  const data = `\`\`\`${communityRaw}\n\n\`\`\``

  dispatchEvent(EVENT.DRAFT_INSERT_SNIPPET, { data })
}

export const onMention = user => store.addReferUser(user)
export const onMentionSearch = name => {
  if (name && name.length >= 1) {
    sr71$.query(S.searchUsers, { name })
  } else {
    store.updateMentionList([])
  }
}

export const deleteComment = () =>
  sr71$.mutate(S.deleteComment, {
    id: store.tobeDeleteId,
  })

// show delete confirm
export const onDelete = comment =>
  store.markState({
    tobeDeleteId: comment.id,
  })

export const cancleDelete = () =>
  store.markState({
    tobeDeleteId: null,
  })

export const pageChange = (page = 1) => {
  scrollIntoEle('lists-info')
  loadComents({ filter: { page, sort: store.filterType } })
}

const cancelLoading = () =>
  store.markState({ loading: false, loadingFresh: false, creating: false })

// ###############################
// Data & Error handlers
// ###############################
const DataSolver = [
  {
    match: asyncRes('pagedComments'),
    action: ({ pagedComments }) => {
      cancelLoading()
      store.markState({ pagedComments })
    },
  },
  {
    match: asyncRes('createComment'),
    action: () => {
      store.markState({
        showInputBox: false,
        showInputEditor: false,
        editContent: '',
        creating: false,
        loading: false,
      })
      loadComents({
        filter: { page: 1, sort: TYPE.DESC_INSERTED },
        fresh: true,
      })
    },
  },
  {
    match: asyncRes('replyComment'),
    action: () => {
      store.markState({
        showReplyBox: false,
        replyToComment: null,
      })
      scrollIntoEle('lists-info')
      loadComents({ filter: { page: 1 }, fresh: true })
    },
  },
  {
    match: asyncRes('updateComment'),
    action: ({ updateComment: { id, body } }) => {
      store.markState({
        showReplyBox: false,
        isEdit: false,
        editComment: null,
        replyContent: '',
      })
      store.updateOneComment(id, { body })
    },
  },
  {
    match: asyncRes('likeComment'),
    action: ({ likeComment }) =>
      store.updateOneComment(likeComment.id, likeComment),
  },
  {
    match: asyncRes('undoLikeComment'),
    action: ({ undoLikeComment }) =>
      store.updateOneComment(undoLikeComment.id, undoLikeComment),
  },
  {
    match: asyncRes('dislikeComment'),
    action: ({ dislikeComment }) =>
      store.updateOneComment(dislikeComment.id, dislikeComment),
  },
  {
    match: asyncRes('undoDislikeComment'),
    action: ({ undoDislikeComment }) =>
      store.updateOneComment(undoDislikeComment.id, undoDislikeComment),
  },
  {
    match: asyncRes('deleteComment'),
    action: ({ deleteComment }) => {
      debug('deleteComment', deleteComment)
      store.markState({ tobeDeleteId: null })
      scrollIntoEle('lists-info')
      loadComents({ filter: { page: 1 }, fresh: true })
    },
  },
  {
    match: asyncRes('searchUsers'),
    action: ({ searchUsers: { entries } }) => store.updateMentionList(entries),
  },
]

const ErrSolver = [
  {
    match: asyncErr(ERR.GRAPHQL),
    action: () => {},
  },
  {
    match: asyncErr(ERR.TIMEOUT),
    action: ({ details }) => {
      errRescue({ type: ERR.TIMEOUT, details, path: 'Comments' })
    },
  },
  {
    match: asyncErr(ERR.NETWORK),
    action: () => errRescue({ type: ERR.NETWORK, path: 'Comments' }),
  },
]

export const init = (_store, ssr = false) => {
  store = _store
  debug('>>>>>>> init sub$: ', sub$)

  if (sub$) return false
  sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver))

  if (!ssr) return loadComents()
}

export const uninit = () => {
  if (store.loading || store.loadingFresh || !sub$) return false
  debug('===== do uninit')
  sr71$.stop()
  sub$.unsubscribe()
  sub$ = null
}
<commit_msg>chore: merge branch 'dev'<commit_after>import R from 'ramda'
import { PAGE_SIZE } from 'config'
import {
  asyncRes,
  asyncErr,
  makeDebugger,
  EVENT,
  ERR,
  TYPE,
  $solver,
  scrollIntoEle,
  countWords,
  dispatchEvent,
  extractMentions,
  errRescue,
} from 'utils'

import SR71 from 'utils/async/sr71'
import S from './schema'

const sr71$ = new SR71()
let sub$ = null
let store = null

/* eslint-disable-next-line */
const debug = makeDebugger('L:Comments')

/* DESC_INSERTED, ASC_INSERTED */
const defaultArgs = {
  fresh: false,
  filter: { page: 1, size: PAGE_SIZE.D, sort: TYPE.ASC_INSERTED },
}

export const loadComents = (args = {}) => {
  // debug('loadComents passed in: ', args)
  args = R.mergeDeepRight(defaultArgs, args)
  args.id = store.viewingData.id
  args.userHasLogin = store.isLogin
  args.thread = store.activeThread

  markLoading(args.fresh)
  store.markState({ filterType: args.filter.sort })

  debug('pagedComments args: ', args)
  sr71$.query(S.pagedComments, args)
}

const markLoading = fresh => {
  if (fresh) {
    return store.markState({ loadingFresh: true })
  }
  return store.markState({ loading: true })
}

export const createComment = () => {
  if (!store.validator('create')) return false

  store.markState({ creating: true })
  const args = {
    id: store.viewingData.id,
    body: store.editContent,
    thread: store.activeThread,
    community: store.curCommunity.raw,
    mentionUsers: R.map(user => ({ id: user.id }), store.referUsersData),
  }

  debug('createComment args: ', args)
  sr71$.mutate(S.createComment, args)
}

export const createCommentPreview = () =>
  store.markState({
    showInputEditor: false,
    showInputPreview: true,
  })

export const backToEditor = () =>
  store.markState({
    showInputEditor: true,
    showInputPreview: false,
  })

export const previewReply = data => {
  debug('previewReply --> : ', data)
}

export const openInputBox = () => {
  if (!store.isLogin) return store.authWarning({ hideToast: true })

  store.markState({
    showInputBox: true,
    showInputEditor: true,
  })
}

export const openCommentEditor = () =>
  store.markState({
    showInputEditor: true,
  })

export const onCommentInputBlur = () =>
  store.markState({
    showInputBox: false,
    showInputPreview: false,
    showInputEditor: false,
  })

export const createReplyComment = () => {
  if (!store.validator('reply')) return false

  if (store.isEdit) {
    return sr71$.mutate(S.updateComment, {
      id: store.editCommentData.id,
      body: store.replyContent,
      thread: store.activeThread,
    })
  }

  sr71$.mutate(S.replyComment, {
    id: store.replyToComment.id,
    body: store.replyContent,
    community: store.curCommunity.raw,
    thread: store.activeThread,
    mentionUsers: R.map(user => ({ id: user.id }), store.referUsersData),
  })
}

export const onCommentInputChange = editContent =>
  store.markState({
    countCurrent: countWords(editContent),
    extractMentions: extractMentions(editContent),
    editContent,
  })

export const onReplyInputChange = replyContent =>
  store.markState({
    countCurrent: countWords(replyContent),
    extractMentions: extractMentions(replyContent),
    replyContent,
  })

export const openUpdateEditor = data =>
  store.markState({
    isEdit: true,
    showReplyBox: true,
    showReplyEditor: true,
    showReplyPreview: false,
    editComment: data,
    replyContent: data.body,
  })

export const openReplyEditor = data =>
  store.markState({
    showReplyBox: true,
    showReplyEditor: true,
    showReplyPreview: false,
    replyToComment: data,
    replyContent: '',
    isEdit: false,
  })

export const replyCommentPreview = () =>
  store.markState({
    showReplyEditor: false,
    showReplyPreview: true,
  })

export const replyBackToEditor = () =>
  store.markState({
    showReplyEditor: true,
    showReplyPreview: false,
  })

export const closeReplyBox = () =>
  store.markState({
    showReplyBox: false,
    showReplyEditor: false,
    showReplyPreview: false,
  })

export const onFilterChange = filterType => {
  store.markState({ filterType })
  loadComents({ filter: { page: 1, sort: filterType } })
}

export const toggleLikeComment = comment => {
  // TODO: check login first
  debug('likeComment: ', comment)

  if (comment.viewerHasLiked) {
    return sr71$.mutate(S.undoLikeComment, {
      id: comment.id,
    })
  }
  return sr71$.mutate(S.likeComment, {
    id: comment.id,
  })
}

export const toggleDislikeComment = comment => {
  // TODO: check login first
  if (comment.viewerHasDisliked) {
    return sr71$.mutate(S.undoDislikeComment, {
      id: comment.id,
    })
  }
  return sr71$.mutate(S.dislikeComment, {
    id: comment.id,
  })
}

export const onUploadImageDone = url =>
  dispatchEvent(EVENT.DRAFT_INSERT_SNIPPET, { data: `![](${url})` })

export const insertQuote = () =>
  dispatchEvent(EVENT.DRAFT_INSERT_SNIPPET, { data: '> ' })

export const insertCode = () => {
  const communityRaw = store.curCommunity.raw
  const data = `\`\`\`${communityRaw}\n\n\`\`\``

  dispatchEvent(EVENT.DRAFT_INSERT_SNIPPET, { data })
}

export const onMention = user => store.addReferUser(user)
export const onMentionSearch = name => {
  if (name && name.length >= 1) {
    sr71$.query(S.searchUsers, { name })
  } else {
    store.updateMentionList([])
  }
}

export const deleteComment = () =>
  sr71$.mutate(S.deleteComment, {
    id: store.tobeDeleteId,
  })

// show delete confirm
export const onDelete = comment =>
  store.markState({
    tobeDeleteId: comment.id,
  })

export const cancleDelete = () =>
  store.markState({
    tobeDeleteId: null,
  })

export const pageChange = (page = 1) => {
  scrollIntoEle('lists-info')
  loadComents({ filter: { page, sort: store.filterType } })
}

const cancelLoading = () =>
  store.markState({ loading: false, loadingFresh: false, creating: false })

// ###############################
// Data & Error handlers
// ###############################
const DataSolver = [
  {
    match: asyncRes('pagedComments'),
    action: ({ pagedComments }) => {
      cancelLoading()
      store.markState({ pagedComments })
    },
  },
  {
    match: asyncRes('createComment'),
    action: () => {
      store.markState({
        showInputBox: false,
        showInputEditor: false,
        editContent: '',
        creating: false,
        loading: false,
      })
      loadComents({
        filter: { page: 1, sort: TYPE.DESC_INSERTED },
        fresh: true,
      })
    },
  },
  {
    match: asyncRes('replyComment'),
    action: () => {
      store.markState({
        showReplyBox: false,
        replyToComment: null,
      })
      scrollIntoEle('lists-info')
      loadComents({ filter: { page: 1 }, fresh: true })
    },
  },
  {
    match: asyncRes('updateComment'),
    action: ({ updateComment: { id, body } }) => {
      store.markState({
        showReplyBox: false,
        isEdit: false,
        editComment: null,
        replyContent: '',
      })
      store.updateOneComment(id, { body })
    },
  },
  {
    match: asyncRes('likeComment'),
    action: ({ likeComment }) =>
      store.updateOneComment(likeComment.id, likeComment),
  },
  {
    match: asyncRes('undoLikeComment'),
    action: ({ undoLikeComment }) =>
      store.updateOneComment(undoLikeComment.id, undoLikeComment),
  },
  {
    match: asyncRes('dislikeComment'),
    action: ({ dislikeComment }) =>
      store.updateOneComment(dislikeComment.id, dislikeComment),
  },
  {
    match: asyncRes('undoDislikeComment'),
    action: ({ undoDislikeComment }) =>
      store.updateOneComment(undoDislikeComment.id, undoDislikeComment),
  },
  {
    match: asyncRes('deleteComment'),
    action: ({ deleteComment }) => {
      debug('deleteComment', deleteComment)
      store.markState({ tobeDeleteId: null })
      scrollIntoEle('lists-info')
      loadComents({ filter: { page: 1 }, fresh: true })
    },
  },
  {
    match: asyncRes('searchUsers'),
    action: ({ searchUsers: { entries } }) => store.updateMentionList(entries),
  },
]

const ErrSolver = [
  {
    match: asyncErr(ERR.GRAPHQL),
    action: () => {},
  },
  {
    match: asyncErr(ERR.TIMEOUT),
    action: ({ details }) => {
      errRescue({ type: ERR.TIMEOUT, details, path: 'Comments' })
    },
  },
  {
    match: asyncErr(ERR.NETWORK),
    action: () => errRescue({ type: ERR.NETWORK, path: 'Comments' }),
  },
]

export const init = (_store, ssr = false) => {
  store = _store
  debug('>>>>>>> init sub$: ', sub$)

  if (sub$) return false
  sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver))

  if (!ssr) return loadComents({ filter: { sort: TYPE.DESC_INSERTED } })
}

export const uninit = () => {
  if (store.loading || store.loadingFresh || !sub$) return false
  debug('===== do uninit')
  sr71$.stop()
  sub$.unsubscribe()
  sub$ = null
}
<|endoftext|>


<commit_before>module.exports = {
    "extends": ["eslint:recommended", "google"],
    "env": {
      "es6": true,
      "mocha": true
    },
    "rules": {
      "max-len": 0,
      "no-loop-func": 0,
      "require-jsdoc": 0
    }
};
<commit_msg>added node environment to eslint<commit_after>module.exports = {
    "extends": ["eslint:recommended", "google"],
    "env": {
      "es6": true,
      "mocha": true,
      "node": true
    },
    "rules": {
      "max-len": 0,
      "no-loop-func": 0,
      "require-jsdoc": 0,
    }
};
<|endoftext|>


<commit_before>/* eslint-disable import/no-extraneous-dependencies */

const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = config => ({
  devtool: 'eval',
  devServer: {
    hot: true,
    publicPath: '/',
    host: '0.0.0.0',
    port: 3000,
    watchOptions: {
      aggregateTimeout: 300,
      ignored: /node_modules/,
    },
  },
  output: {
    filename: 'bundle.js',
  },
  plugins: config.plugins.concat([
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new ExtractTextPlugin('style.css'),
  ]),
  entry: [
    'react-hot-loader/patch',
  ].concat(config.entry),
});
<commit_msg>use `cheap-module-eval-source-map` for development source map<commit_after>/* eslint-disable import/no-extraneous-dependencies */

const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = config => ({
  devtool: 'cheap-module-eval-source-map',
  devServer: {
    hot: true,
    publicPath: '/',
    host: '0.0.0.0',
    port: 3000,
    watchOptions: {
      aggregateTimeout: 300,
      ignored: /node_modules/,
    },
  },
  output: {
    filename: 'bundle.js',
  },
  plugins: config.plugins.concat([
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new ExtractTextPlugin('style.css'),
  ]),
  entry: [
    'react-hot-loader/patch',
  ].concat(config.entry),
});
<|endoftext|>


<commit_before>// Generated on 2014-10-10 using generator-angular 0.9.8
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

	// Load grunt tasks automatically
	require('load-grunt-tasks')(grunt);

	// Time how long tasks take. Can help when optimizing build times
	require('time-grunt')(grunt);

	// Configurable paths for the application
	var appConfig = {
		app: require('./bower.json').appPath || 'app',
		dist: 'dist'
	};

	// Define the configuration for all the tasks
	grunt.initConfig({

		// Project settings
		yeoman: appConfig,

		// Watches files for changes and runs tasks based on the changed files
		watch: {
			jade: {
				files: ['<%= yeoman.app %>/**/*.jade'],
				tasks: ['jade'],
				options: {
					livereload: '<%= connect.options.livereload %>'
				}
			},
			js: {
				files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
				tasks: ['newer:jshint:all'],
				options: {
					livereload: '<%= connect.options.livereload %>'
				}
			},
			jsTest: {
				files: ['test/spec/{,*/}*.js'],
				tasks: ['newer:jshint:test', 'karma']
			},
			compass: {
				files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
				tasks: ['compass:server', 'autoprefixer']
			},
			gruntfile: {
				files: ['Gruntfile.js']
			},
			livereload: {
				options: {
					livereload: '<%= connect.options.livereload %>'
				},
				files: [
					'<%= yeoman.app %>/{,*/}*.html',
					'.tmp/styles/{,*/}*.css',
					'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
					'<%= yeoman.app %>/texts/*.json'
				]
			}
		},

		// The actual grunt server settings
		connect: {
			options: {
				port: 9000,
				// Change this to '0.0.0.0' to access the server from outside.
				hostname: 'localhost',
				livereload: 35729
			},
			livereload: {
				options: {
					open: true,
					middleware: function (connect) {
						return [
							require('grunt-connect-proxy/lib/utils').proxyRequest,
							connect.static('.tmp'),
							connect().use(
								'/bower_components',
								connect.static('./bower_components')
							),
							connect.static(appConfig.app)
						];
					}
				}
			},
			test: {
				options: {
					port: 9001,
					middleware: function (connect) {
						return [
							connect.static('.tmp'),
							connect.static('test'),
							connect().use(
								'/bower_components',
								connect.static('./bower_components')
							),
							connect.static(appConfig.app)
						];
					}
				}
			},
			dist: {
				options: {
					open: true,
					base: '<%= yeoman.dist %>'
				}
			},
			proxies: [
				{
					context: '/api',
					host: '127.0.0.1',
					port: 8000,
					https: false
				}

			]
		},

		// Make sure code styles are up to par and there are no obvious mistakes
		jshint: {
			options: {
				jshintrc: '.jshintrc',
				reporter: require('jshint-stylish')
			},
			all: {
				src: [
					'Gruntfile.js',
					'<%= yeoman.app %>/scripts/{,*/}*.js'
				]
			},
			test: {
				options: {
					jshintrc: 'test/.jshintrc'
				},
				src: ['test/spec/{,*/}*.js']
			}
		},

		// Empties folders to start fresh
		clean: {
			dist: {
				files: [
					{
						dot: true,
						src: [
							'.tmp',
							'<%= yeoman.dist %>/{,*/}*',
							'!<%= yeoman.dist %>/.git*'
						]
					}
				]
			},
			server: '.tmp'
		},

		// Add vendor prefixed styles
		autoprefixer: {
			options: {
				browsers: ['last 1 version']
			},
			dist: {
				files: [
					{
						expand: true,
						cwd: '.tmp/styles/',
						src: '{,*/}*.css',
						dest: '.tmp/styles/'
					}
				]
			}
		},

		// Compiles Sass to CSS and generates necessary files if requested
		compass: {
			options: {
				sassDir: '<%= yeoman.app %>/styles',
				cssDir: '.tmp/styles',
				generatedImagesDir: '.tmp/images/generated',
				imagesDir: '<%= yeoman.app %>/images',
				javascriptsDir: '<%= yeoman.app %>/scripts',
				fontsDir: '<%= yeoman.app %>/styles/fonts',
				importPath: './bower_components',
				httpImagesPath: '/images',
				httpGeneratedImagesPath: '/images/generated',
				httpFontsPath: '/styles/fonts',
				relativeAssets: false,
				assetCacheBuster: false,
				raw: 'Sass::Script::Number.precision = 10\n'
			},
			dist: {
				options: {
					generatedImagesDir: '<%= yeoman.dist %>/images/generated'
				}
			},
			server: {
				options: {
					debugInfo: true
				}
			}
		},

		// Renames files for browser caching purposes
		filerev: {
			dist: {
				src: [
					'<%= yeoman.dist %>/scripts/{,*/}*.js',
					'<%= yeoman.dist %>/styles/{,*/}*.css',
					'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
					'<%= yeoman.dist %>/styles/fonts/*'
				]
			}
		},

		// Reads HTML for usemin blocks to enable smart builds that automatically
		// concat, minify and revision files. Creates configurations in memory so
		// additional tasks can operate on them
		useminPrepare: {
			html: '.tmp/index.html',
			options: {
				dest: '<%= yeoman.dist %>',
				flow: {
					html: {
						steps: {
							js: ['concat'], // 'uglifyjs'],
							css: ['concat', 'cssmin']
						},
						post: {}
					}
				}
			}
		},

		// Performs rewrites based on filerev and the useminPrepare configuration
		usemin: {
			html: ['.tmp/{,*/}*.html'],
			css: ['.tmp/{,*/}*.css'],
			options: {
				assetsDirs: ['<%= yeoman.dist %>', '<%= yeoman.dist %>/images']
			}
		},

		// The following *-min tasks will produce minified files in the dist folder
		// By default, your `index.html`'s <!-- Usemin block --> will take care of
		// minification. These next options are pre-configured if you do not wish
		// to use the Usemin blocks.
		// cssmin: {
		//   dist: {
		//     files: {
		//       '<%= yeoman.dist %>/styles/main.css': [
		//         '.tmp/styles/{,*/}*.css'
		//       ]
		//     }
		//   }
		// },
		// uglify: {
		//   dist: {
		//     files: {
		//       '<%= yeoman.dist %>/scripts/scripts.js': [
		//         '<%= yeoman.dist %>/scripts/scripts.js'
		//       ]
		//     }
		//   }
		// },
		// concat: {
		//   dist: {}
		// },

		concat: {
			options: {
				separator: ';',
			},
		},

		imagemin: {
			dist: {
				files: [
					{
						expand: true,
						cwd: '<%= yeoman.app %>/images',
						src: '{,*/}*.{png,jpg,jpeg,gif}',
						dest: '<%= yeoman.dist %>/images'
					}
				]
			}
		},

		svgmin: {
			dist: {
				files: [
					{
						expand: true,
						cwd: '<%= yeoman.app %>/images',
						src: '{,*/}*.svg',
						dest: '<%= yeoman.dist %>/images'
					}
				]
			}
		},

		htmlmin: {
			dist: {
				options: {
					collapseWhitespace: true,
					conservativeCollapse: true,
					collapseBooleanAttributes: true,
					removeCommentsFromCDATA: true,
					removeOptionalTags: true
				},
				files: [
					{
						expand: true,
						cwd: '.tmp',
						src: ['*.html', 'views/{,*/}*.html'],
						dest: '<%= yeoman.dist %>'
					}
				]
			}
		},

		// ng-annotate tries to make the code safe for minification automatically
		// by using the Angular long form for dependency injection.
		ngAnnotate: {
			dist: {
				files: [
					{
						expand: true,
						cwd: '.tmp/concat/scripts',
						src: ['*.js', '!oldieshim.js'],
						dest: '.tmp/concat/scripts'
					}
				]
			}
		},

		// Replace Google CDN references
		cdnify: {
			dist: {
				html: ['<%= yeoman.dist %>/*.html']
			}
		},

		// Copies remaining files to places other tasks can use
		copy: {
			dist: {
				files: [
					{
						expand: true,
						dot: true,
						cwd: '<%= yeoman.app %>',
						dest: '<%= yeoman.dist %>',
						src: [
							'*.{ico,png,txt}',
							'.htaccess',
							'*.html',
							'views/{,*/}*.html',
							'images/{,*/}*.{webp}',
							'fonts/*',
							'sitemap.xml'
						]
					},
					{
						expand: true,
						cwd: '.tmp/images',
						dest: '<%= yeoman.dist %>/images',
						src: ['generated/*']
					},
					{
						expand: true,
						cwd: '.',
						src: 'bower_components/ultima/**/*',
						dest: '<%= yeoman.dist %>'
					}
				]
			},
			styles: {
				expand: true,
				cwd: '<%= yeoman.app %>/styles',
				dest: '.tmp/styles/',
				src: '{,*/}*.css'
			}
		},

		// Run some tasks in parallel to speed up the build process
		concurrent: {
			server: [
				'compass:server'
			],
			test: [
				'compass'
			],
			dist: [
				'compass:dist',
				'imagemin',
				'svgmin'
			]
		},

		// Test settings
		karma: {
			unit: {
				configFile: 'test/karma.conf.js',
				singleRun: true
			}
		},

		// Jade template engine
		jade: {
			dist: {
				options: {
					pretty: true
				},
				files: [
					{
						expand: true,
						cwd: '<%= yeoman.app %>',
						dest: '.tmp',
						src: ['*.jade', 'views/**/*.jade'],
						ext: '.html'
					}
				]
			}
		},

		// Deploy via sftp
		// authentication information stored in .ftppass (not under version control)
		'sftp-deploy': {
			staging: {
				auth: {
					host: 'desec.io',
					port: 22,
					authKey: 'desec-io'
				},
				src: '<%= yeoman.dist %>',
				dest: '/var/www/webclient',
				exclusions: [],
				serverSep: '/',
				concurrency: 4,
				progress: true
			}
		},
	});

	grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
		if (target === 'dist') {
			return grunt.task.run(['build', 'connect:dist:keepalive']);
		}

		grunt.task.run([
			'clean:server',
			'configureProxies:server',
			'concurrent:server',
			'autoprefixer',
			'jade',
			'connect:livereload',
			'watch'
		]);
	});

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

	grunt.registerTask('test', [
		'clean:server',
		'concurrent:test',
		'autoprefixer',
		'jade',
		'connect:test',
		'karma'
	]);

	grunt.registerTask('build', [
		'clean:dist',
		'jade',
		'compass',
		'useminPrepare',
		'concat',
		'concurrent:dist',
		'autoprefixer',
		'ngAnnotate',
		'copy:dist',
		'cssmin',
		//'uglify',
		//'filerev',
		'usemin',
		'htmlmin'
	]);

	grunt.registerTask('deploy', [
		'build',
		'sftp-deploy'
	]);

	grunt.registerTask('default', [
		'newer:jshint',
		'test',
		'build'
	]);
};
<commit_msg>fix(Grunt): grunt now also deploy texts<commit_after>// Generated on 2014-10-10 using generator-angular 0.9.8
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

	// Load grunt tasks automatically
	require('load-grunt-tasks')(grunt);

	// Time how long tasks take. Can help when optimizing build times
	require('time-grunt')(grunt);

	// Configurable paths for the application
	var appConfig = {
		app: require('./bower.json').appPath || 'app',
		dist: 'dist'
	};

	// Define the configuration for all the tasks
	grunt.initConfig({

		// Project settings
		yeoman: appConfig,

		// Watches files for changes and runs tasks based on the changed files
		watch: {
			jade: {
				files: ['<%= yeoman.app %>/**/*.jade'],
				tasks: ['jade'],
				options: {
					livereload: '<%= connect.options.livereload %>'
				}
			},
			js: {
				files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
				tasks: ['newer:jshint:all'],
				options: {
					livereload: '<%= connect.options.livereload %>'
				}
			},
			jsTest: {
				files: ['test/spec/{,*/}*.js'],
				tasks: ['newer:jshint:test', 'karma']
			},
			compass: {
				files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
				tasks: ['compass:server', 'autoprefixer']
			},
			gruntfile: {
				files: ['Gruntfile.js']
			},
			livereload: {
				options: {
					livereload: '<%= connect.options.livereload %>'
				},
				files: [
					'<%= yeoman.app %>/{,*/}*.html',
					'.tmp/styles/{,*/}*.css',
					'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
					'<%= yeoman.app %>/texts/*.json'
				]
			}
		},

		// The actual grunt server settings
		connect: {
			options: {
				port: 9000,
				// Change this to '0.0.0.0' to access the server from outside.
				hostname: 'localhost',
				livereload: 35729
			},
			livereload: {
				options: {
					open: true,
					middleware: function (connect) {
						return [
							require('grunt-connect-proxy/lib/utils').proxyRequest,
							connect.static('.tmp'),
							connect().use(
								'/bower_components',
								connect.static('./bower_components')
							),
							connect.static(appConfig.app)
						];
					}
				}
			},
			test: {
				options: {
					port: 9001,
					middleware: function (connect) {
						return [
							connect.static('.tmp'),
							connect.static('test'),
							connect().use(
								'/bower_components',
								connect.static('./bower_components')
							),
							connect.static(appConfig.app)
						];
					}
				}
			},
			dist: {
				options: {
					open: true,
					base: '<%= yeoman.dist %>'
				}
			},
			proxies: [
				{
					context: '/api',
					host: '127.0.0.1',
					port: 8000,
					https: false
				}

			]
		},

		// Make sure code styles are up to par and there are no obvious mistakes
		jshint: {
			options: {
				jshintrc: '.jshintrc',
				reporter: require('jshint-stylish')
			},
			all: {
				src: [
					'Gruntfile.js',
					'<%= yeoman.app %>/scripts/{,*/}*.js'
				]
			},
			test: {
				options: {
					jshintrc: 'test/.jshintrc'
				},
				src: ['test/spec/{,*/}*.js']
			}
		},

		// Empties folders to start fresh
		clean: {
			dist: {
				files: [
					{
						dot: true,
						src: [
							'.tmp',
							'<%= yeoman.dist %>/{,*/}*',
							'!<%= yeoman.dist %>/.git*'
						]
					}
				]
			},
			server: '.tmp'
		},

		// Add vendor prefixed styles
		autoprefixer: {
			options: {
				browsers: ['last 1 version']
			},
			dist: {
				files: [
					{
						expand: true,
						cwd: '.tmp/styles/',
						src: '{,*/}*.css',
						dest: '.tmp/styles/'
					}
				]
			}
		},

		// Compiles Sass to CSS and generates necessary files if requested
		compass: {
			options: {
				sassDir: '<%= yeoman.app %>/styles',
				cssDir: '.tmp/styles',
				generatedImagesDir: '.tmp/images/generated',
				imagesDir: '<%= yeoman.app %>/images',
				javascriptsDir: '<%= yeoman.app %>/scripts',
				fontsDir: '<%= yeoman.app %>/styles/fonts',
				importPath: './bower_components',
				httpImagesPath: '/images',
				httpGeneratedImagesPath: '/images/generated',
				httpFontsPath: '/styles/fonts',
				relativeAssets: false,
				assetCacheBuster: false,
				raw: 'Sass::Script::Number.precision = 10\n'
			},
			dist: {
				options: {
					generatedImagesDir: '<%= yeoman.dist %>/images/generated'
				}
			},
			server: {
				options: {
					debugInfo: true
				}
			}
		},

		// Renames files for browser caching purposes
		filerev: {
			dist: {
				src: [
					'<%= yeoman.dist %>/scripts/{,*/}*.js',
					'<%= yeoman.dist %>/styles/{,*/}*.css',
					'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
					'<%= yeoman.dist %>/styles/fonts/*'
				]
			}
		},

		// Reads HTML for usemin blocks to enable smart builds that automatically
		// concat, minify and revision files. Creates configurations in memory so
		// additional tasks can operate on them
		useminPrepare: {
			html: '.tmp/index.html',
			options: {
				dest: '<%= yeoman.dist %>',
				flow: {
					html: {
						steps: {
							js: ['concat'], // 'uglifyjs'],
							css: ['concat', 'cssmin']
						},
						post: {}
					}
				}
			}
		},

		// Performs rewrites based on filerev and the useminPrepare configuration
		usemin: {
			html: ['.tmp/{,*/}*.html'],
			css: ['.tmp/{,*/}*.css'],
			options: {
				assetsDirs: ['<%= yeoman.dist %>', '<%= yeoman.dist %>/images']
			}
		},

		// The following *-min tasks will produce minified files in the dist folder
		// By default, your `index.html`'s <!-- Usemin block --> will take care of
		// minification. These next options are pre-configured if you do not wish
		// to use the Usemin blocks.
		// cssmin: {
		//   dist: {
		//     files: {
		//       '<%= yeoman.dist %>/styles/main.css': [
		//         '.tmp/styles/{,*/}*.css'
		//       ]
		//     }
		//   }
		// },
		// uglify: {
		//   dist: {
		//     files: {
		//       '<%= yeoman.dist %>/scripts/scripts.js': [
		//         '<%= yeoman.dist %>/scripts/scripts.js'
		//       ]
		//     }
		//   }
		// },
		// concat: {
		//   dist: {}
		// },

		concat: {
			options: {
				separator: ';',
			},
		},

		imagemin: {
			dist: {
				files: [
					{
						expand: true,
						cwd: '<%= yeoman.app %>/images',
						src: '{,*/}*.{png,jpg,jpeg,gif}',
						dest: '<%= yeoman.dist %>/images'
					}
				]
			}
		},

		svgmin: {
			dist: {
				files: [
					{
						expand: true,
						cwd: '<%= yeoman.app %>/images',
						src: '{,*/}*.svg',
						dest: '<%= yeoman.dist %>/images'
					}
				]
			}
		},

		htmlmin: {
			dist: {
				options: {
					collapseWhitespace: true,
					conservativeCollapse: true,
					collapseBooleanAttributes: true,
					removeCommentsFromCDATA: true,
					removeOptionalTags: true
				},
				files: [
					{
						expand: true,
						cwd: '.tmp',
						src: ['*.html', 'views/{,*/}*.html'],
						dest: '<%= yeoman.dist %>'
					}
				]
			}
		},

		// ng-annotate tries to make the code safe for minification automatically
		// by using the Angular long form for dependency injection.
		ngAnnotate: {
			dist: {
				files: [
					{
						expand: true,
						cwd: '.tmp/concat/scripts',
						src: ['*.js', '!oldieshim.js'],
						dest: '.tmp/concat/scripts'
					}
				]
			}
		},

		// Replace Google CDN references
		cdnify: {
			dist: {
				html: ['<%= yeoman.dist %>/*.html']
			}
		},

		// Copies remaining files to places other tasks can use
		copy: {
			dist: {
				files: [
					{
						expand: true,
						dot: true,
						cwd: '<%= yeoman.app %>',
						dest: '<%= yeoman.dist %>',
						src: [
							'*.{ico,png,txt}',
							'.htaccess',
							'*.html',
							'views/{,*/}*.html',
							'images/{,*/}*.{webp}',
							'fonts/*',
							'sitemap.xml',
							'texts/*'
						]
					},
					{
						expand: true,
						cwd: '.tmp/images',
						dest: '<%= yeoman.dist %>/images',
						src: ['generated/*']
					},
					{
						expand: true,
						cwd: '.',
						src: 'bower_components/ultima/**/*',
						dest: '<%= yeoman.dist %>'
					}
				]
			},
			styles: {
				expand: true,
				cwd: '<%= yeoman.app %>/styles',
				dest: '.tmp/styles/',
				src: '{,*/}*.css'
			}
		},

		// Run some tasks in parallel to speed up the build process
		concurrent: {
			server: [
				'compass:server'
			],
			test: [
				'compass'
			],
			dist: [
				'compass:dist',
				'imagemin',
				'svgmin'
			]
		},

		// Test settings
		karma: {
			unit: {
				configFile: 'test/karma.conf.js',
				singleRun: true
			}
		},

		// Jade template engine
		jade: {
			dist: {
				options: {
					pretty: true
				},
				files: [
					{
						expand: true,
						cwd: '<%= yeoman.app %>',
						dest: '.tmp',
						src: ['*.jade', 'views/**/*.jade'],
						ext: '.html'
					}
				]
			}
		},

		// Deploy via sftp
		// authentication information stored in .ftppass (not under version control)
		'sftp-deploy': {
			staging: {
				auth: {
					host: 'desec.io',
					port: 22,
					authKey: 'desec-io'
				},
				src: '<%= yeoman.dist %>',
				dest: '/var/www/webclient',
				exclusions: [],
				serverSep: '/',
				concurrency: 4,
				progress: true
			}
		},
	});

	grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
		if (target === 'dist') {
			return grunt.task.run(['build', 'connect:dist:keepalive']);
		}

		grunt.task.run([
			'clean:server',
			'configureProxies:server',
			'concurrent:server',
			'autoprefixer',
			'jade',
			'connect:livereload',
			'watch'
		]);
	});

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

	grunt.registerTask('test', [
		'clean:server',
		'concurrent:test',
		'autoprefixer',
		'jade',
		'connect:test',
		'karma'
	]);

	grunt.registerTask('build', [
		'clean:dist',
		'jade',
		'compass',
		'useminPrepare',
		'concat',
		'concurrent:dist',
		'autoprefixer',
		'ngAnnotate',
		'copy:dist',
		'cssmin',
		//'uglify',
		//'filerev',
		'usemin',
		'htmlmin'
	]);

	grunt.registerTask('deploy', [
		'build',
		'sftp-deploy'
	]);

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


<commit_before>var idmap = {};
var guests = 0;

module.exports = function (io) {
	io.sockets.on('connection', function (socket) {
		socket.on('announce_join', function (data) {
			idmap[socket.id] = data.nickname;
			console.log(data.nickname + ' joined ' + data.radioid + '.');
			io.sockets.in('radio_' + data.radioid).emit('update_chat', {
				message: {
					sender: '[SERVER]',
					body: data.nickname + ' is now listening. There are currently ' + guests + ' people listening to this radio'
				}
			});
		});

		socket.on('join_radio', function (data) {
			socket.join('radio_' + data.radioid);
			console.log(socket.id + ' connected to ' + data.radioid);
			guests+=1;
		});

		socket.on('broadcast_player_status', function (data) {
			io.sockets.in('radio_' + data.radioId).emit('update_player_status', data);
		});

		socket.on('send_message', function (data) {
			io.sockets.in('radio_' + data.radioid).emit('update_chat', {
				message: {
					sender: data.nickname,
					body: data.message
				}
			});
		});

		socket.on('disconnect', function (data) {
			console.log('Socket: ' + socket.id + ' disconnected from server.');
			delete idmap[socket.id];
			console.log(idmap);
			guests-=1;
			io.sockets.in('radio_' + data.radioid).emit('update_chat', {
				message: {
					sender: '[SERVER]',
					body: data.nickname + ' has left. There are currently ' + guests + ' people listening to this radio'
				}
			});
			/* Will need to create a socket.id to nickname map, etc */
			//io.sockets.in('radio_' + data.radioid).emit('update_chat', {
			//    message: {
			//        sender: '[SERVER]',
			//        body: data.nickname + ' has left.'
			//    }
			//});
		});
	});
}<commit_msg>implement radioMap from socketID to radioID and send message when an user has left<commit_after>var idMap = {};
var radioMap = {};
var guests = 0;

module.exports = function (io) {
	io.sockets.on('connection', function (socket) {
		socket.on('announce_join', function (data) {
			idMap[socket.id] = data.nickname;
			radioMap[socket.id] = data.radioid;
			console.log(data.nickname + ' joined ' + data.radioid + '.');
			// console.log(data);
			io.sockets.in('radio_' + data.radioid).emit('update_chat', {
				message: {
					sender: '[SERVER]',
					body: data.nickname + ' is now listening. There are currently ' + guests + ' people listening to this radio'
				}
			});
		});

		socket.on('join_radio', function (data) {
			socket.join('radio_' + data.radioid);
			console.log(socket.id + ' connected to ' + data.radioid);
			guests+=1;
		});

		socket.on('broadcast_player_status', function (data) {
			io.sockets.in('radio_' + data.radioId).emit('update_player_status', data);
		});

		socket.on('send_message', function (data) {
			io.sockets.in('radio_' + data.radioid).emit('update_chat', {
				message: {
					sender: data.nickname,
					body: data.message
				}
			});
		});

		socket.on('disconnect', function (data) {
			console.log('Socket: ' + socket.id + ' disconnected from server.');
			console.log("Data: " + JSON.stringify(data));
			guests-=1;
			io.sockets.in('radio_' + radioMap[socket.id]).emit('update_chat', {
				message: {
					sender: '[SERVER]',
					body: idMap[socket.id] + ' has left. There are currently ' + guests + ' people listening to this radio'
				}
			});
			delete idMap[socket.id];
		});
	});
}<|endoftext|>


<commit_before>function Floating2DText(w, h, text) {
    this.__init__(w, h, text)
}

Floating2DText.prototype = {
    text: null,
    width: null,
    height: null,
    material: null,
    dynamic_texture: null,

    object3d: null,

    active: null,

    __init__: function(w, h, text) {
        this.width    = w
        this.height   = h

        this.text     = text

        this.active   = false
    },

    update_text: function(text) {
        if (this.current_text !== text) {
            this.dynamic_texture.clear().drawText(text, 0, 20, 'black')
            this.current_text = text
            this.dynamic_texture.needsUpdate = true
        }
    },

    create: function(scene) {
        this.object3d = new THREE.Object3D()
        // PlaneGeometry takes in a width, height, optionalWidthSegments (default 1), optionalHeightSegments (default 1)
        this.geometry = new THREE.PlaneGeometry(this.width, this.height)
        this.dynamic_texture = new THREEx.DynamicTexture(this.width * 2, this.height * 2)
        //this.dynamic_texture.context.font = 'Bold 20px Arial'
        this.dynamic_texture.context.font = '16px Arial'
        //this.dynamic_texture.texture.anisotropy = renderer_api.renderer.capabilities.getMaxAnisotropy()
        this.update_text(this.text)
        this.material = new THREE.MeshBasicMaterial({
            map	: this.dynamic_texture.texture
        })
        this.material.transparent = true
        // TODO : Make this only 1 sided
        this.material.side = THREE.DoubleSide

        // Adds the edge colorings.
        this.mesh = new THREE.Mesh(this.geometry, this.material)
        var geo = new THREE.EdgesGeometry( this.mesh.geometry ) // or WireframeGeometry
        var mat = new THREE.LineBasicMaterial( { color: 0xFFC0CB, linewidth: 3 } )
        var wireframe = new THREE.LineSegments( geo, mat )
        this.mesh.add(wireframe)

        this.object3d.add(this.mesh)

        scene.add(this.object3d)
    },

    update_position_and_look_at: function(position_vector, look_at_position) {
        this.object3d.position.x = position_vector.x
        this.object3d.position.y = position_vector.y
        this.object3d.position.z = position_vector.z
        this.object3d.lookAt(look_at_position)
    },

    add_character: function(character) {
        this.text = this.text + character
        this.update_text(this.text)
    },

    add_keycode: function(keycode) {
        this.add_character(String.fromCharCode((96 <= key && key <= 105) ? key-48 : key))
    }
}
<commit_msg>general updating 10.<commit_after>function Floating2DText(w, h, text) {
    this.__init__(w, h, text)
}

Floating2DText.prototype = {
    text: null,
    width: null,
    height: null,
    material: null,
    dynamic_texture: null,

    object3d: null,

    active: null,

    __init__: function(w, h, text) {
        this.width    = w
        this.height   = h

        this.text     = text

        this.active   = false
    },

    update_text: function(text) {
        if (this.current_text !== text) {
            this.dynamic_texture.clear().drawText(text, 0, 20, 'black')
            this.current_text = text
            this.dynamic_texture.needsUpdate = true
        }
    },

    create: function(scene) {
        this.object3d = new THREE.Object3D()
        // PlaneGeometry takes in a width, height, optionalWidthSegments (default 1), optionalHeightSegments (default 1)
        this.geometry = new THREE.PlaneGeometry(this.width, this.height)
        this.dynamic_texture = new THREEx.DynamicTexture(this.width * 2, this.height * 2)
        //this.dynamic_texture.context.font = 'Bold 20px Arial'
        this.dynamic_texture.context.font = '16px Arial'
        //this.dynamic_texture.texture.anisotropy = renderer_api.renderer.capabilities.getMaxAnisotropy()
        this.update_text(this.text)
        this.material = new THREE.MeshBasicMaterial({
            map	: this.dynamic_texture.texture
        })
        this.material.transparent = true
        // TODO : Make this only 1 sided
        this.material.side = THREE.DoubleSide

        // Adds the edge colorings.
        this.mesh = new THREE.Mesh(this.geometry, this.material)
        var geo = new THREE.EdgesGeometry( this.mesh.geometry ) // or WireframeGeometry
        var mat = new THREE.LineBasicMaterial( { color: 0xFFC0CB, linewidth: 3 } )
        var wireframe = new THREE.LineSegments( geo, mat )
        this.mesh.add(wireframe)

        this.object3d.add(this.mesh)

        scene.add(this.object3d)
    },

    update_position_and_look_at: function(position_vector, look_at_position) {
        this.object3d.position.x = position_vector.x
        this.object3d.position.y = position_vector.y
        this.object3d.position.z = position_vector.z
        this.object3d.lookAt(look_at_position)
    },

    add_character: function(character) {
        this.text = this.text + character
        this.update_text(this.text)
    }

}
<|endoftext|>


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

importClass(java.io.File);
importClass(java.io.FileInputStream);

importClass(Packages.org.efaps.db.Checkin);
importClass(Packages.org.efaps.db.Insert);
importClass(Packages.org.efaps.db.Instance);
importClass(Packages.org.efaps.db.SearchQuery);

/**
 * The class represents images used e.g. for type icons or for user interfaces.
 */
function Image(_name)  {
  var query = new SearchQuery();
  query.setQueryTypes(Shell.getContext(), "Admin_UI_Image");
  query.addWhereExprEqValue(Shell.getContext(), "Name", _name);
  query.addSelect(Shell.getContext(), "OID");
  query.execute(Shell.getContext());

  if (query.next())  {
    var oid = query.get(Shell.getContext(), "OID");
    this.instance = new Instance(Shell.getContext(), oid);
  } else  {
    this.instance = null;
  }
  query.close();

  this.object = new EFapsInstance("Admin_UI_Image", _name);

  // add helper methods for getter and setter
  this._setAttrValue      = Abstract.prototype._setAttrValue;
  this._getAttrValue      = Abstract.prototype._getAttrValue;

  // add getter and setter methods
  this.getInstance        = Abstract.prototype.getInstance;
  this.getId              = Abstract.prototype.getId;
  this.getOid             = Abstract.prototype.getOid;
  this.getType            = Abstract.prototype.getType;
  this.getName            = Abstract.prototype.getName;
  this.getRevision        = Abstract.prototype.getRevision;
  this.setRevision        = Abstract.prototype.setRevision;
}

///////////////////////////////////////////////////////////////////////////////
// instance variables

/**
 * Prefix of script file names.
 */
Image.prototype.FILE_PREFIX = new Packages.java.lang.String("IMAGE_");

///////////////////////////////////////////////////////////////////////////////
// common methods

/**
 * Updates current image in eFaps with image of file. If the image in eFaps
 * does not exists, the image is created.
 *
 * @param _fileName (String)  name of the update file
 * @param _objName  (String)  name of the object
 */
Image.prototype.update = function(_fileName, _objName)  {
  if (this.getOid()==null || this.getOid()=="" || this.getOid()=="0")  {
    print("  - create");
    var insert = new Insert(Shell.getContext(), "Admin_UI_Image");
    insert.add(Shell.getContext(), "Name", _objName);
    insert.execute(Shell.getContext());
    this.instance = insert.getInstance();
  } else  {
    print("  - update");
  }
  this.checkin(_fileName);
}

/**
 * The file with the name '_fileName' is checked in the object. The file could
 * be accessable via the class patch or normal system path (method first
 * searches inside the classpath, than in the system path).
 *
 * @param _fileName name of the file to checkin
 */
Image.prototype.checkin = function(_fileName)  {
  var context = Packages.org.mozilla.javascript.Context.enter();
  var reader;
  try  {
    var stream = _eFapsClassLoader.getResourceAsStream(_fileName);
    if (stream==null)  {
      stream = new FileInputStream(new File(_fileName));
    }

    var checkin = new Checkin(Shell.getContext(), this.getInstance());
    checkin.execute(Shell.getContext(), _fileName, stream, stream.available());

    stream.close();
  } catch (e)  {
print(e);
    context.reportError(e.toString());
  } finally  {
    try  {reader.close();} catch(f) {}
  }
}

///////////////////////////////////////////////////////////////////////////////
// static functions

/**
 * One image file with the given name is imported.
 *
 * @param _fileName   file to import
 */
function importImage(_fileName)  {
  var file = new Packages.java.io.File(_fileName);
  var fileName = new Packages.java.lang.String(file.getName());
  if (fileName.startsWith(Image.prototype.FILE_PREFIX) && fileName.endsWith(".gif"))  {
    var objName = new String(fileName.substring(Image.prototype.FILE_PREFIX.length(), fileName.length()-4));
    print("Import Image '"+objName+"'");
    var imp = new Image(objName);
    imp.update(_fileName, objName);
  }
}

/**
 * A list of Image Definition files is imported.
 *
 * @param _fileList (Array) array with list of files
 */
function importImages(_fileList)  {
  print("");
  print("Import Images");
  print("~~~~~~~~~~~~~");
  for (indx in _fileList)  {
    importImage(_fileList[indx]);
  }
  print("");
}

/**
 * Creates all Images in the given path matching given match.
 *
 * @param _path   (String) path to write all images in
 * @param _match  (String) match for menu names
 */
function createScriptImages(_path, _match)  {
  var query = new SearchQuery();
  query.setQueryTypes(Shell.getContext(), "Admin_UI_Image");
  query.addWhereExprEqValue(Shell.getContext(), "Name", _match);
  query.addSelect(Shell.getContext(), "Name");

  query.execute(Shell.getContext());

  print("Create Images:");
  print("~~~~~~~~~~~~~~");
  while (query.next())  {
    var name = query.get(Shell.getContext(), "Name");
    print("  - '"+  name  +"'");
    var image = new Image(name);
    image.object.checkout("File", _path+"/"+name);
  }

  query.close();
}
<commit_msg>- extension .png is also detected (together with .gif)<commit_after>/*
 * Copyright 2006 The eFaps Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author:          tmo
 * Revision:        $Rev$
 * Last Changed:    $Date$
 * Last Changed By: $Author$
 */

importClass(java.io.File);
importClass(java.io.FileInputStream);

importClass(Packages.org.efaps.db.Checkin);
importClass(Packages.org.efaps.db.Insert);
importClass(Packages.org.efaps.db.Instance);
importClass(Packages.org.efaps.db.SearchQuery);

/**
 * The class represents images used e.g. for type icons or for user interfaces.
 */
function Image(_name)  {
  var query = new SearchQuery();
  query.setQueryTypes(Shell.getContext(), "Admin_UI_Image");
  query.addWhereExprEqValue(Shell.getContext(), "Name", _name);
  query.addSelect(Shell.getContext(), "OID");
  query.execute(Shell.getContext());

  if (query.next())  {
    var oid = query.get(Shell.getContext(), "OID");
    this.instance = new Instance(Shell.getContext(), oid);
  } else  {
    this.instance = null;
  }
  query.close();

  this.object = new EFapsInstance("Admin_UI_Image", _name);

  // add helper methods for getter and setter
  this._setAttrValue      = Abstract.prototype._setAttrValue;
  this._getAttrValue      = Abstract.prototype._getAttrValue;

  // add getter and setter methods
  this.getInstance        = Abstract.prototype.getInstance;
  this.getId              = Abstract.prototype.getId;
  this.getOid             = Abstract.prototype.getOid;
  this.getType            = Abstract.prototype.getType;
  this.getName            = Abstract.prototype.getName;
  this.getRevision        = Abstract.prototype.getRevision;
  this.setRevision        = Abstract.prototype.setRevision;
}

///////////////////////////////////////////////////////////////////////////////
// instance variables

/**
 * Prefix of script file names.
 */
Image.prototype.FILE_PREFIX = new Packages.java.lang.String("IMAGE_");

///////////////////////////////////////////////////////////////////////////////
// common methods

/**
 * Updates current image in eFaps with image of file. If the image in eFaps
 * does not exists, the image is created.
 *
 * @param _fileName (String)  name of the update file
 * @param _objName  (String)  name of the object
 */
Image.prototype.update = function(_fileName, _objName)  {
  if (this.getOid()==null || this.getOid()=="" || this.getOid()=="0")  {
    print("  - create");
    var insert = new Insert(Shell.getContext(), "Admin_UI_Image");
    insert.add(Shell.getContext(), "Name", _objName);
    insert.execute(Shell.getContext());
    this.instance = insert.getInstance();
  } else  {
    print("  - update");
  }
  this.checkin(_fileName);
}

/**
 * The file with the name '_fileName' is checked in the object. The file could
 * be accessable via the class patch or normal system path (method first
 * searches inside the classpath, than in the system path).
 *
 * @param _fileName name of the file to checkin
 */
Image.prototype.checkin = function(_fileName)  {
  var context = Packages.org.mozilla.javascript.Context.enter();
  var reader;
  try  {
    var stream = _eFapsClassLoader.getResourceAsStream(_fileName);
    if (stream==null)  {
      stream = new FileInputStream(new File(_fileName));
    }

    var checkin = new Checkin(Shell.getContext(), this.getInstance());
    checkin.execute(Shell.getContext(), _fileName, stream, stream.available());

    stream.close();
  } catch (e)  {
print(e);
    context.reportError(e.toString());
  } finally  {
    try  {reader.close();} catch(f) {}
  }
}

///////////////////////////////////////////////////////////////////////////////
// static functions

/**
 * One image file with the given name is imported.
 *
 * @param _fileName   file to import
 */
function importImage(_fileName)  {
  var file = new Packages.java.io.File(_fileName);
  var fileName = new Packages.java.lang.String(file.getName());
  if (fileName.startsWith(Image.prototype.FILE_PREFIX) && (fileName.endsWith(".gif") || fileName.endsWith(".png")))  {
    var objName = new String(fileName.substring(Image.prototype.FILE_PREFIX.length(), fileName.length()-4));
    print("Import Image '"+objName+"'");
    var imp = new Image(objName);
    imp.update(_fileName, objName);
  }
}

/**
 * A list of Image Definition files is imported.
 *
 * @param _fileList (Array) array with list of files
 */
function importImages(_fileList)  {
  print("");
  print("Import Images");
  print("~~~~~~~~~~~~~");
  for (indx in _fileList)  {
    importImage(_fileList[indx]);
  }
  print("");
}

/**
 * Creates all Images in the given path matching given match.
 *
 * @param _path   (String) path to write all images in
 * @param _match  (String) match for menu names
 */
function createScriptImages(_path, _match)  {
  var query = new SearchQuery();
  query.setQueryTypes(Shell.getContext(), "Admin_UI_Image");
  query.addWhereExprEqValue(Shell.getContext(), "Name", _match);
  query.addSelect(Shell.getContext(), "Name");

  query.execute(Shell.getContext());

  print("Create Images:");
  print("~~~~~~~~~~~~~~");
  while (query.next())  {
    var name = query.get(Shell.getContext(), "Name");
    print("  - '"+  name  +"'");
    var image = new Image(name);
    image.object.checkout("File", _path+"/"+name);
  }

  query.close();
}
<|endoftext|>


<commit_before>import { mapGetters, mapActions} from 'vuex';

export default {
  computed: {
    ...mapGetters(['jwttoken', 'subject', 'principal', 'audience', 'baseUrl', 'authenticated'])
  },
  methods: {
    ...mapActions(['saveJwtToken']),
    $post(apiname, body) {
      let options = this.$httpOptions();

      return this.$http.post(this.$httpUrl(apiname), body, options);
    },
    $httpOptions(options) {
      let httpOpts = options ? options : {};

      if (this.jwttoken) {
        httpOpts['headers'] = {
          'Auth-Token': this.jwttoken
        };
      }
      return httpOpts;
    },
    $httpUrl(url) {

      return this.baseUrl + url;
    }
  }
};
<commit_msg>add mapGetters in rpc common<commit_after>import { mapGetters, mapActions} from 'vuex';

export default {
  computed: {
    ...mapGetters(['jwttoken', 'subject', 'principal', 'parseToken', 'baseUrl', 'authenticated'])
  },
  methods: {
    ...mapActions(['saveJwtToken']),
    $post(apiname, body) {
      let options = this.$httpOptions();

      return this.$http.post(this.$httpUrl(apiname), body, options);
    },
    $httpOptions(options) {
      let httpOpts = options ? options : {};

      if (this.jwttoken) {
        httpOpts['headers'] = {
          'Auth-Token': this.jwttoken
        };
      }
      return httpOpts;
    },
    $httpUrl(url) {

      return this.baseUrl + url;
    }
  }
};
<|endoftext|>


<commit_before>/* Milesian Seasons - Dates of tropical events for a given Milesian year
	Character set is UTF-8
Required (directly)
	Lunar: getDeltaT
Contents
	The externally used function is tropicEvent
*/
/* Version M2020-12-29 Adapted to new Chronos and Lunar
	M2020-01-12 : strict mode implementation
	M2019-08-22: first version, extracted from a Fourmilab package
*/
/* Copyright Miletus 2019-2020 - Louis A. de Fouquières
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
1. The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
2. Changes with respect to any former version shall be documented.

The software is provided "as is", without warranty of any kind,
express of implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose and noninfringement.
In no event shall the authors of copyright holders be liable for any
claim, damages or other liability, whether in an action of contract,
tort or otherwise, arising from, out of or in connection with the software
or the use or other dealings in the software.
Inquiries: www.calendriermilesien.org

These functions implement Jean Meeus' method for computing tropical events.
The code derives from Fourmilab's astro.js file (2015)
Code has been modified in order to conform with strict mode
*/
"use strict";
const Seasons = {
	/* Part 1 - utilities
	*/
	LOWER_YEAR : -3000,	// The lower year for seasons' computations
	UPPER_YEAR : +6000,	// The upper year for seasons' computations
	/** Convert degrees to radians
	 * @param {number} an angle in degrees
	 * @return {number} the corresponding angle in radians
	*/
	dtr(d) {return (d * Math.PI) / 180.0;},

	/** Cosinus of an angle in degrees
	 * @param {number} the angle in degrees
	 * @return {number} the cosinus of the angle
	*/
	dcos(d) {return Math.cos(this.dtr(d));},

	/* Part 2 - Function equinox, implements Jean Meeus' method
	for calculating equinox and solstices of a year
	Extracted from Fourmilab astro functions
	*/

	/** The Julian Day of a tropical event (equinox or solstice) of a given year
	 * @param {number} year: the Gregorian year
	 * @param {number} which: 0->March, 1->June, 2->September, 3->December, any other value -> Error
	 * @return {number} the date of the event in Julian Day, Terrestrial Time
	*/
	equinox(year, which) {

		//  Periodic terms to obtain true time

		var EquinoxpTerms = new Array(
			485, 324.96,   1934.136,
			203, 337.23,  32964.467,
			199, 342.08,     20.186,
			182,  27.85, 445267.112,
			156,  73.14,  45036.886,
			136, 171.52,  22518.443,
			 77, 222.54,  65928.934,
			 74, 296.72,   3034.906,
			 70, 243.58,   9037.513,
			 58, 119.81,  33718.147,
			 52, 297.17,    150.678,
			 50,  21.02,   2281.226,
			 45, 247.54,  29929.562,
			 44, 325.15,  31555.956,
			 29,  60.93,   4443.417,
			 18, 155.12,  67555.328,
			 17, 288.79,   4562.452,
			 16, 198.04,  62894.029,
			 14, 199.76,  31436.921,
			 12,  95.39,  14577.848,
			 12, 287.11,  31931.756,
			 12, 320.81,  34777.259,
			  9, 227.73,   1222.114,
			  8,  15.45,  16859.074
									),

		JDE0tab1000 = new Array(
		   new Array(1721139.29189, 365242.13740,  0.06134,  0.00111, -0.00071),
		   new Array(1721233.25401, 365241.72562, -0.05323,  0.00907,  0.00025),
		   new Array(1721325.70455, 365242.49558, -0.11677, -0.00297,  0.00074),
		   new Array(1721414.39987, 365242.88257, -0.00769, -0.00933, -0.00006)
								),

		JDE0tab2000 = new Array(	// Meeus, ch. 18 (up to 3rd degree)
		   new Array(2451623.80984, 365242.37404,  0.05169, -0.00411, -0.00057),
		   new Array(2451716.56767, 365241.62603,  0.00325,  0.00888, -0.00030),
		   new Array(2451810.21715, 365242.01767, -0.11575,  0.00337,  0.00078),
		   new Array(2451900.05952, 365242.74049, -0.06223, -0.00823,  0.00032)
							);
		var deltaL, i, j, JDE0, JDE0tab, S, T, W, Y;
		if (!Number.isInteger(which) || which < 0 || which > 3) throw "Invalid parameter";

		/*  Initialise terms for mean equinox and solstices.
		We have two sets:
			one for years prior to 1000
			and a second for subsequent years.  */

		if (year < 1000) {
			JDE0tab = JDE0tab1000;
			Y = year / 1000;
		} else {
			JDE0tab = JDE0tab2000;
			Y = (year - 2000) / 1000;
		}

		JDE0 =  JDE0tab[which][0] +
			   (JDE0tab[which][1] * Y) +
			   (JDE0tab[which][2] * Y * Y) +
			   (JDE0tab[which][3] * Y * Y * Y) +
			   (JDE0tab[which][4] * Y * Y * Y * Y);
		T = (JDE0 - 2451545.0) / 36525;	// JDE0 expressed in Julian centuries from 1/1/2000 - Meeus 13-1
		W = (35999.373 * T) - 2.47;		// M, Mean solar anomaly, Meeus ch. 16, without 2nd order term
		deltaL = 1 + (0.0334 * this.dcos(W)) + (0.0007 * this.dcos(2 * W));
		//  Sum the periodic terms for time T
		S = 0;
		for (i = j = 0; i < 24; i++) {
			S += EquinoxpTerms[j] * this.dcos(EquinoxpTerms[j + 1] + (EquinoxpTerms[j + 2] * T));
			j += 3;
		}
		return JDE0 + ((S * 0.00001) / deltaL);
	},
	/* Part 3 - the tropicEvent function - Result in ms from Posix Epoch
	*/
	/** Compute the tropical event of a Milesian year, result as an ExtDate element.
	 * @param {number} year: the Milesian year
	 * @param {number} which: 0->Winter solstice at beginning of year, 1->Spring equinox, 2->Summer solstice, 3->Autumn equinox, 4->Winter solstice at end of year any other value -> Error
	 * @return {ExtDate} the date of the event (correction with a Delta T estimate).
	*/
	tropicEvent (year, which) {
		var JDE;
		if (!Number.isInteger(which) || which < 0 || which > 4) throw RangeError("Invalid value for season parameter");
		if (year < this.LOWER_YEAR || year > this.UPPER_YEAR) throw RangeError ("Year outside seasons' computation capabilities");
		if (which == 0) JDE = this.equinox (year-1,3)
			else JDE = this.equinox(year, which-1);
		let wdate = new Date(Math.round((JDE - 2440587.5)*86400000));
		return new ExtDate (milesian, wdate.valueOf() - Lunar.getDeltaT(wdate));
	}
}
// export (Seasons)
<commit_msg>Comment<commit_after>/* Milesian Seasons - Dates of tropical events for a given Milesian year
	Character set is UTF-8
Required (directly)
	Lunar: getDeltaT
Contents
	The externally used function is tropicEvent
*/
/* Version M2020-12-29 Adapted to new Chronos and Lunar
	M2020-01-12 : strict mode implementation
	M2019-08-22: first version, extracted from a Fourmilab package
*/
/* Copyright Miletus 2019-2020 - Louis A. de Fouquières
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
1. The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
2. Changes with respect to any former version shall be documented.

The software is provided "as is", without warranty of any kind,
express of implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose and noninfringement.
In no event shall the authors of copyright holders be liable for any
claim, damages or other liability, whether in an action of contract,
tort or otherwise, arising from, out of or in connection with the software
or the use or other dealings in the software.
Inquiries: www.calendriermilesien.org

These functions implement Jean Meeus' method for computing tropical events.
The code derives from Fourmilab's astro.js file (2015)
Code has been modified in order to conform with strict mode
*/
"use strict";
const Seasons = {
	/* Part 1 - utilities
	*/
	LOWER_YEAR : -3000,	// The lower year for seasons' computations
	UPPER_YEAR : +6000,	// The upper year for seasons' computations
	/** Convert degrees to radians
	 * @param {number} an angle in degrees
	 * @return {number} the corresponding angle in radians
	*/
	dtr(d) {return (d * Math.PI) / 180.0;},

	/** Cosinus of an angle in degrees
	 * @param {number} the angle in degrees
	 * @return {number} the cosinus of the angle
	*/
	dcos(d) {return Math.cos(this.dtr(d));},

	/* Part 2 - Function equinox, implements Jean Meeus' method
	for calculating equinox and solstices of a year
	Extracted from Fourmilab astro functions
	*/

	/** The Julian Day of a tropical event (equinox or solstice) of a given year
	 * @param {number} year: the Gregorian year
	 * @param {number} which: 0->March, 1->June, 2->September, 3->December, any other value -> Error
	 * @return {number} the date of the event in Julian Day, Terrestrial Time
	*/
	equinox(year, which) {

		//  Periodic terms to obtain true time

		var EquinoxpTerms = new Array(
			485, 324.96,   1934.136,
			203, 337.23,  32964.467,
			199, 342.08,     20.186,
			182,  27.85, 445267.112,
			156,  73.14,  45036.886,
			136, 171.52,  22518.443,
			 77, 222.54,  65928.934,
			 74, 296.72,   3034.906,
			 70, 243.58,   9037.513,
			 58, 119.81,  33718.147,
			 52, 297.17,    150.678,
			 50,  21.02,   2281.226,
			 45, 247.54,  29929.562,
			 44, 325.15,  31555.956,
			 29,  60.93,   4443.417,
			 18, 155.12,  67555.328,
			 17, 288.79,   4562.452,
			 16, 198.04,  62894.029,
			 14, 199.76,  31436.921,
			 12,  95.39,  14577.848,
			 12, 287.11,  31931.756,
			 12, 320.81,  34777.259,
			  9, 227.73,   1222.114,
			  8,  15.45,  16859.074
									),

		JDE0tab1000 = new Array(
		   new Array(1721139.29189, 365242.13740,  0.06134,  0.00111, -0.00071),
		   new Array(1721233.25401, 365241.72562, -0.05323,  0.00907,  0.00025),
		   new Array(1721325.70455, 365242.49558, -0.11677, -0.00297,  0.00074),
		   new Array(1721414.39987, 365242.88257, -0.00769, -0.00933, -0.00006)
								),

		JDE0tab2000 = new Array(	// Meeus, ch. 18 (up to 3rd degree)
		   new Array(2451623.80984, 365242.37404,  0.05169, -0.00411, -0.00057),
		   new Array(2451716.56767, 365241.62603,  0.00325,  0.00888, -0.00030),
		   new Array(2451810.21715, 365242.01767, -0.11575,  0.00337,  0.00078),
		   new Array(2451900.05952, 365242.74049, -0.06223, -0.00823,  0.00032)
							);
		var deltaL, i, j, JDE0, JDE0tab, S, T, W, Y;
		if (!Number.isInteger(which) || which < 0 || which > 3) throw "Invalid parameter";

		/*  Initialise terms for mean equinox and solstices.
		We have two sets:
			one for years prior to 1000
			and a second for subsequent years.  */

		if (year < 1000) {
			JDE0tab = JDE0tab1000;
			Y = year / 1000;
		} else {
			JDE0tab = JDE0tab2000;
			Y = (year - 2000) / 1000;
		}

		JDE0 =  JDE0tab[which][0] +
			   (JDE0tab[which][1] * Y) +
			   (JDE0tab[which][2] * Y * Y) +
			   (JDE0tab[which][3] * Y * Y * Y) +
			   (JDE0tab[which][4] * Y * Y * Y * Y);
		T = (JDE0 - 2451545.0) / 36525;	// JDE0 expressed in Julian centuries from 1/1/2000 - Meeus 13-1
		W = (35999.373 * T) - 2.47;		// M, Mean solar anomaly, Meeus ch. 16, without 2nd order term
		deltaL = 1 + (0.0334 * this.dcos(W)) + (0.0007 * this.dcos(2 * W));
		//  Sum the periodic terms for time T
		S = 0;
		for (i = j = 0; i < 24; i++) {
			S += EquinoxpTerms[j] * this.dcos(EquinoxpTerms[j + 1] + (EquinoxpTerms[j + 2] * T));
			j += 3;
		}
		return JDE0 + ((S * 0.00001) / deltaL);
	},
	/* Part 3 - the tropicEvent function: dates of solstices and equinoxes of a given year, from winter to winter.
	*/
	/** Compute the tropical event of a Milesian year, result as an ExtDate element.
	 * @param {number} year: the Milesian year
	 * @param {number} which: 0->Winter solstice at beginning of year, 1->Spring equinox, 2->Summer solstice, 3->Autumn equinox, 4->Winter solstice at end of year any other value -> Error
	 * @return {ExtDate} the date of the event (correction with a Delta T estimate).
	*/
	tropicEvent (year, which) {
		var JDE;
		if (!Number.isInteger(which) || which < 0 || which > 4) throw RangeError("Invalid value for season parameter");
		if (year < this.LOWER_YEAR || year > this.UPPER_YEAR) throw RangeError ("Year outside seasons' computation capabilities");
		if (which == 0) JDE = this.equinox (year-1,3)
			else JDE = this.equinox(year, which-1);
		let wdate = new Date(Math.round((JDE - 2440587.5)*86400000));
		return new ExtDate (milesian, wdate.valueOf() - Lunar.getDeltaT(wdate));
	}
}
// export (Seasons)
<|endoftext|>


<commit_before>import SPELLS from 'common/SPELLS';
import CoreAbilities from 'parser/core/modules/Abilities';

class Abilities extends CoreAbilities {
  spellbook() {
    const combatant = this.selectedCombatant;

    const standardGcd = combatant => 1000 * (1 - (combatant.hasBuff(SPELLS.ADRENALINE_RUSH.id) ? 0.2 : 0));

    return [
      // Rotational
      {
        spell: SPELLS.AMBUSH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.DISPATCH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.ROLL_THE_BONES,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
        enabled: !combatant.hasTalent(SPELLS.SLICE_AND_DICE_TALENT.id),
      },
      {
        spell: SPELLS.SLICE_AND_DICE_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
        enabled: combatant.hasTalent(SPELLS.SLICE_AND_DICE_TALENT.id),
      },
      {
        spell: SPELLS.SINISTER_STRIKE,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.MARKED_FOR_DEATH_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: 60,
        gcd: null,
        castEfficiency: {
          suggestion: true,
        },
        enabled: combatant.hasTalent(SPELLS.MARKED_FOR_DEATH_TALENT.id),
      },
      {
        spell: SPELLS.GHOSTLY_STRIKE_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: 35,
        gcd: {
          static: standardGcd,
        },
        castEfficiency: {
          suggestion: true,
        },
        enabled: combatant.hasTalent(SPELLS.GHOSTLY_STRIKE_TALENT.id),
      },
      // Rotational (AOE)
      {
        spell: SPELLS.BLADE_FLURRY,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL_AOE,
        cooldown: 25,
        charges: 2,
        gcd: {
          static: standardGcd,
        },
      },
      // Cooldowns
      {
        spell: SPELLS.ADRENALINE_RUSH,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 180,
        gcd: {
          static: standardGcd,
        },
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.VANISH,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 120,
        gcd: null,
        castEfficiency: {
          suggestion: false,
        },
      },
      {
        spell: SPELLS.BLADE_RUSH_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 45,
        gcd: {
          static: standardGcd,
        },
        castEfficiency: {
          suggestion: true,
        },
        enabled: combatant.hasTalent(SPELLS.BLADE_RUSH_TALENT.id),
      },
      {
        spell: SPELLS.KILLING_SPREE_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 120,
        gcd: {
          static: standardGcd,
        },
        castEfficiency: {
          suggestion: true,
        },
        enabled: combatant.hasTalent(SPELLS.KILLING_SPREE_TALENT.id),
      },
      // Defensive
      {
        spell: SPELLS.CLOAK_OF_SHADOWS,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 120,
        gcd: null,
      },
      {
        spell: SPELLS.CRIMSON_VIAL,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 30,
        gcd: {
          base: 1000, // Adrenaline Rush doesn't decrease this, but Haste does
        },
      },
      {
        spell: SPELLS.FEINT,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        buffSpellId: SPELLS.FEINT.id,
        cooldown: 15,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.RIPOSTE,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        buffSpellId: SPELLS.RIPOSTE.id,
        cooldown: 120,
        gcd: null,
      },
      // Others
      {
        spell: SPELLS.BETWEEN_THE_EYES,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        cooldown: 30,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.PISTOL_SHOT,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          static: standardGcd,
        },
      },
      // Utility
      {
        spell: SPELLS.GRAPPLING_HOOK,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 60 - (combatant.hasTalent(SPELLS.RETRACTABLE_HOOK_TALENT.id) ? 30 : 0),
        gcd: null,
      },
      {
        spell: SPELLS.SPRINT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 60,
        gcd: null,
      },
      {
        spell: SPELLS.TRICKS_OF_THE_TRADE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 30,
        gcd: null,
      },
      {
        spell: SPELLS.STEALTH,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 2,
        gcd: null,
      },
      {
        spell: SPELLS.KICK,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 15,
        gcd: null,
      },
      {
        spell: SPELLS.BLIND,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 120 - (combatant.hasTalent(SPELLS.BLINDING_POWDER_TALENT.id) ? 30 : 0),
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.CHEAP_SHOT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.DISTRACT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 30,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.GOUGE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 15,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.SHROUD_OF_CONCEALMENT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 6 * 60,
        gcd: {
          base: 1000,
        },
      },
      {
        spell: SPELLS.SAP,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
      },
      {
        spell: SPELLS.PICK_LOCK,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
      },
      {
        spell: SPELLS.PICK_POCKET,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        // While this actually has a 0.5s CD, it shows up weird in the Abilities tab if we set that
      },
    ];
  }
}

export default Abilities;
<commit_msg>Reviewed the Abilities.js for completeness/accuracy<commit_after>import SPELLS from 'common/SPELLS';
import CoreAbilities from 'parser/core/modules/Abilities';

class Abilities extends CoreAbilities {
  spellbook() {
    const combatant = this.selectedCombatant;

    const standardGcd = combatant => 1000 * (1 - (combatant.hasBuff(SPELLS.ADRENALINE_RUSH.id) ? 0.2 : 0));

    return [
      // Rotational
      {
        spell: SPELLS.AMBUSH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.DISPATCH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.ROLL_THE_BONES,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
        enabled: !combatant.hasTalent(SPELLS.SLICE_AND_DICE_TALENT.id),
      },
      {
        spell: SPELLS.SLICE_AND_DICE_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
        enabled: combatant.hasTalent(SPELLS.SLICE_AND_DICE_TALENT.id),
      },
      {
        spell: SPELLS.SINISTER_STRIKE,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.MARKED_FOR_DEATH_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: 60,
        gcd: null,
        castEfficiency: {
          suggestion: true,
        },
        enabled: combatant.hasTalent(SPELLS.MARKED_FOR_DEATH_TALENT.id),
      },
      {
        spell: SPELLS.GHOSTLY_STRIKE_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: 35,
        gcd: {
          static: standardGcd,
        },
        castEfficiency: {
          suggestion: true,
        },
        enabled: combatant.hasTalent(SPELLS.GHOSTLY_STRIKE_TALENT.id),
      },
      {
        spell: SPELLS.BETWEEN_THE_EYES,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: 30,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.PISTOL_SHOT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          static: standardGcd,
        },
      },
      // Rotational (AOE)
      {
        spell: SPELLS.BLADE_FLURRY,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL_AOE,
        cooldown: 25,
        charges: 2,
        gcd: {
          static: standardGcd,
        },
      },
      // Cooldowns
      {
        spell: SPELLS.ADRENALINE_RUSH,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 180,
        gcd: {
          static: standardGcd,
        },
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.BLADE_RUSH_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 45,
        gcd: {
          static: standardGcd,
        },
        castEfficiency: {
          suggestion: true,
        },
        enabled: combatant.hasTalent(SPELLS.BLADE_RUSH_TALENT.id),
      },
      {
        spell: SPELLS.KILLING_SPREE_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 120,
        gcd: {
          static: standardGcd,
        },
        castEfficiency: {
          suggestion: true,
        },
        enabled: combatant.hasTalent(SPELLS.KILLING_SPREE_TALENT.id),
      },
      // Defensive
      {
        spell: SPELLS.CLOAK_OF_SHADOWS,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 120,
        gcd: null,
      },
      {
        spell: SPELLS.CRIMSON_VIAL,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 30,
        gcd: {
          base: 1000, // Adrenaline Rush doesn't decrease this, but Haste does
        },
      },
      {
        spell: SPELLS.FEINT,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        buffSpellId: SPELLS.FEINT.id,
        cooldown: 15,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.RIPOSTE,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        buffSpellId: SPELLS.RIPOSTE.id,
        cooldown: 120,
        gcd: null,
      },
      // Others
      {
        spell: SPELLS.PICK_LOCK,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
      },
      {
        spell: SPELLS.PICK_POCKET,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        // While this actually has a 0.5s CD, it shows up weird in the Abilities tab if we set that
      },
      // Utility
      {
        spell: SPELLS.VANISH,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 120,
        gcd: null,
        castEfficiency: {
          suggestion: false,
        },
      },
      {
        spell: SPELLS.GRAPPLING_HOOK,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 60 - (combatant.hasTalent(SPELLS.RETRACTABLE_HOOK_TALENT.id) ? 30 : 0),
        gcd: null,
      },
      {
        spell: SPELLS.SPRINT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 60,
        gcd: null,
      },
      {
        spell: SPELLS.TRICKS_OF_THE_TRADE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 30,
        gcd: null,
      },
      {
        spell: SPELLS.STEALTH,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 2,
        gcd: null,
      },
      {
        spell: SPELLS.KICK,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 15,
        gcd: null,
      },
      {
        spell: SPELLS.BLIND,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 120 - (combatant.hasTalent(SPELLS.BLINDING_POWDER_TALENT.id) ? 30 : 0),
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.CHEAP_SHOT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.DISTRACT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 30,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.GOUGE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 15,
        gcd: {
          static: standardGcd,
        },
      },
      {
        spell: SPELLS.SHROUD_OF_CONCEALMENT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 6 * 60,
        gcd: {
          base: 1000,
        },
      },
      {
        spell: SPELLS.SAP,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
      },
    ];
  }
}

export default Abilities;
<|endoftext|>


<commit_before>import Leaf from "./leaf";

export default function(point) {
  if (isNaN(x = point[0]) || isNaN(y = point[1])) return; // ignore invalid points

  var point0,
      node = this._root,
      parent,
      grandparent,
      x,
      y,
      xm,
      ym,
      x0 = this._x0,
      y0 = this._y0,
      x1 = this._x1,
      y1 = this._y1,
      right,
      bottom,
      i,
      i0;

  // If the tree is empty, initialize the root as a leaf.
  if (!node) {
    this._root = new Leaf(point);
    this._x0 = this._x1 = x;
    this._y0 = this._y1 = y;
    return;
  }

  // Expand the tree to cover the new point, if necessary.
  if (x0 > x || x > x1 || y0 > y || y > y1) {
    xm = x0 === x1 ? Math.max(Math.abs(x0 - x), Math.abs(y0 - y)) : (x1 - x0) * 2;
    switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
      case 0: do parent = new Array(4), parent[i] = node, node = parent, x1 = x0 + xm, y1 = y0 + xm, xm *= 2; while (x > x1 || y > y1); break;
      case 1: do parent = new Array(4), parent[i] = node, node = parent, x0 = x1 - xm, y1 = y0 + xm, xm *= 2; while (x0 > x || y > y1); break;
      case 2: do parent = new Array(4), parent[i] = node, node = parent, x1 = x0 + xm, y0 = y1 - xm, xm *= 2; while (x > x1 || y0 > y); break;
      case 3: do parent = new Array(4), parent[i] = node, node = parent, x0 = x1 - xm, y0 = y1 - xm, xm *= 2; while (x0 > x || y0 > y); break;
    }
    this._root = node;
    this._x0 = x0, this._x1 = x1;
    this._y0 = y0, this._y1 = y1;
  }

  // Find the appropriate leaf node for the new point.
  do {
    if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
    if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
    grandparent = parent, parent = node, node = node[i0 = i, i = bottom << 1 | right];
  } while (node);

  // If the new point is in an empty node, just add it.
  if (!(point0 = parent.point)) return void (parent[i] = new Leaf(point));

  // If the new point is exactly coincident with the specified point, add it.
  if (x === point0[0] && y === point0[1]) {
    point.next = point0;
    parent.point = point;
    return;
  }

  // Otherwise, split the leaf node until the old and new point are separated.
  parent = grandparent[i0] = new Array(4);
  while (i === (i0 = (point0[1] >= ym) << 1 | (point0[0] >= xm))) {
    parent = parent[i] = new Array(4);
    if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
    if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
    i = bottom << 1 | right;
  }

  parent[i0] = new Leaf(point0);
  parent[i] = new Leaf(point);
}
<commit_msg>Don’t create a new leaf when splitting.<commit_after>import Leaf from "./leaf";

export default function(point) {
  if (isNaN(x = point[0]) || isNaN(y = point[1])) return; // ignore invalid points

  var point0,
      node = this._root,
      parent,
      grandparent,
      x, y,
      xm, ym,
      xp, yp,
      x0 = this._x0, y0 = this._y0,
      x1 = this._x1, y1 = this._y1,
      right,
      bottom,
      i,
      j;

  // If the tree is empty, initialize the root as a leaf.
  if (!node) {
    this._root = new Leaf(point);
    this._x0 = this._x1 = x;
    this._y0 = this._y1 = y;
    return;
  }

  // Expand the tree to cover the new point, if necessary.
  if (x0 > x || x > x1 || y0 > y || y > y1) {
    xm = x0 === x1 ? Math.max(Math.abs(x0 - x), Math.abs(y0 - y)) : (x1 - x0) * 2;
    switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
      case 0: do parent = new Array(4), parent[i] = node, node = parent, x1 = x0 + xm, y1 = y0 + xm, xm *= 2; while (x > x1 || y > y1); break;
      case 1: do parent = new Array(4), parent[i] = node, node = parent, x0 = x1 - xm, y1 = y0 + xm, xm *= 2; while (x0 > x || y > y1); break;
      case 2: do parent = new Array(4), parent[i] = node, node = parent, x1 = x0 + xm, y0 = y1 - xm, xm *= 2; while (x > x1 || y0 > y); break;
      case 3: do parent = new Array(4), parent[i] = node, node = parent, x0 = x1 - xm, y0 = y1 - xm, xm *= 2; while (x0 > x || y0 > y); break;
    }
    this._root = node;
    this._x0 = x0, this._x1 = x1;
    this._y0 = y0, this._y1 = y1;
  }

  // Find the appropriate leaf node for the new point.
  do {
    if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
    if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
  } while (grandparent = parent, parent = node, node = node[j = i, i = bottom << 1 | right]);

  // If the new point is in an empty node, just add it.
  if (!(point0 = parent.point)) {
    parent[i] = new Leaf(point);
    return;
  }

  // If the new point is exactly coincident with the specified point, add it.
  if (xp = point0[0], yp = point0[1], x === xp && y === yp) {
    point.next = point0;
    parent.point = point;
    return;
  }

  // Otherwise, split the leaf node until the old and new point are separated.
  node = parent, parent = grandparent[j] = new Array(4);
  while (i === (j = (yp >= ym) << 1 | (xp >= xm))) {
    parent = parent[i] = new Array(4);
    if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
    if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
    i = bottom << 1 | right;
  }

  parent[i] = new Leaf(point);
  parent[j] = node;
}
<|endoftext|>


<commit_before>'use strict';

var backendRequestAuth = require('./backend').backendRequestAuth;
var getToken = require('./auth').getToken;
var pp = browser.params;

exports.resetApp = resetApp;
exports.post = post;

function resetApp(callback) {
    backendRequestAuth({
        uri: '/prepopulate',
        method: 'POST',
        json: {
            'profile': 'app_prepopulate_data'
        }
    }, function(e, r, j) {
        // @TODO: remove it
        console.log(e);
        console.log(j);
        // </it>
        pp.token = null;
        callback(e, r, j);
    });
}

function post(params, callback) {
    if (!pp.token) {
        getToken(function() { post(params, callback); });
        return;
    }
    params.method = 'POST';
    backendRequestAuth(params, callback);
}
<commit_msg>remove debug line<commit_after>'use strict';

var backendRequestAuth = require('./backend').backendRequestAuth;
var getToken = require('./auth').getToken;
var pp = browser.params;

exports.resetApp = resetApp;
exports.post = post;

function resetApp(callback) {
    backendRequestAuth({
        uri: '/prepopulate',
        method: 'POST',
        json: {
            'profile': 'app_prepopulate_data'
        }
    }, function(e, r, j) {
        pp.token = null;
        callback(e, r, j);
    });
}

function post(params, callback) {
    if (!pp.token) {
        getToken(function() { post(params, callback); });
        return;
    }
    params.method = 'POST';
    backendRequestAuth(params, callback);
}
<|endoftext|>