<commit_before>import Users from "meteor/nova:users";
import Posts from "meteor/nova:posts";
import Comments from "meteor/nova:comments";

/**
 * @summary Vote schema
 * @type {SimpleSchema}
 */
const voteSchema = new SimpleSchema({
  itemId: {
    type: String
  },
  power: {
    type: Number,
    optional: true
  },
  votedAt: {
    type: Date,
    optional: true
  }
});

Users.addField([
  /**
    An array containing comments upvotes
  */
  {
    fieldName: 'upvotedComments',
    fieldSchema: {
      type: [voteSchema],
      publish: false,
      optional: true,
      viewableBy: ['guests'],
      resolveAs: 'upvotedComments: [Vote]',
    }
  },
  /**
    An array containing posts upvotes
  */
  {
    fieldName: 'upvotedPosts',
    fieldSchema: {
      type: [voteSchema],
      publish: false,
      optional: true,
      viewableBy: ['guests'],
      resolveAs: 'upvotedPosts: [Vote]',
    }
  },
  /**
    An array containing comment downvotes
  */
  {
    fieldName: 'downvotedComments',
    fieldSchema: {
      type: [voteSchema],
      publish: false,
      optional: true,
      viewableBy: ['guests'],
      resolveAs: 'downvotedComments: [Vote]',
    }
  },
  /**
    An array containing posts downvotes
  */
  {
    fieldName: 'downvotedPosts',
    fieldSchema: {
      type: [voteSchema],
      publish: false,
      optional: true,
      viewableBy: ['guests'],
      resolveAs: 'downvotedPosts: [Vote]',
    }
  },
]);

Posts.addField([
  /**
    How many upvotes the post has received
  */
  {
    fieldName: "upvotes",
    fieldSchema: {
      type: Number,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    An array containing the `_id`s of the post's upvoters
  */
  {
    fieldName: "upvoters",
    fieldSchema: {
      type: [String],
      optional: true,
      publish: true,
      viewableBy: ['guests'],
      resolveAs: 'upvoters: [User]',
    }
  },
  /**
    How many downvotes the post has received
  */
  {
    fieldName: "downvotes",
    fieldSchema: {
      type: Number,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    An array containing the `_id`s of the post's downvoters
  */
  {
    fieldName: "downvoters",
    fieldSchema: {
      type: [String],
      optional: true,
      publish: true,
      viewableBy: ['guests'],
      resolveAs: 'downvoters: [User]',
    }
  },
  /**
    The post's base score (not factoring in the post's age)
  */
  {
    fieldName: "baseScore",
    fieldSchema: {
      type: Number,
      decimal: true,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    The post's current score (factoring in age)
  */
  {
    fieldName: "score",
    fieldSchema: {
      type: Number,
      decimal: true,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
]);

Comments.addField([
  /**
    The number of upvotes the comment has received
  */
  {
    fieldName: "upvotes",
    fieldSchema: {
      type: Number,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    An array containing the `_id`s of upvoters
  */
  {
    fieldName: "upvoters",
    fieldSchema: {
      type: [String],
      optional: true,
      publish: true,
      viewableBy: ['guests'],
      resolveAs: 'upvoters: [User]',
    }
  },
  /**
    The number of downvotes the comment has received
  */
  {
    fieldName: "downvotes",
    fieldSchema: {
      type: Number,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    An array containing the `_id`s of downvoters
  */
  {
    fieldName: "downvoters",
    fieldSchema: {
      type: [String],
      optional: true,
      publish: true,
      viewableBy: ['guests'],
      resolveAs: 'downvoters: [User]',
    }
  },
  /**
    The comment's base score (not factoring in the comment's age)
  */
  {
    fieldName: "baseScore",
    fieldSchema: {
      type: Number,
      decimal: true,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    The comment's current score (factoring in age)
  */
  {
    fieldName: "score",
    fieldSchema: {
      type: Number,
      decimal: true,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
]);

<commit_msg>Fixed the GraphQL syntax to allow for proper GraphQL types<commit_after>import Users from "meteor/nova:users";
import Posts from "meteor/nova:posts";
import Comments from "meteor/nova:comments";

/**
 * @summary Vote schema
 * @type {SimpleSchema}
 */
const voteSchema = new SimpleSchema({
  itemId: {
    type: String
  },
  power: {
    type: Number,
    optional: true
  },
  votedAt: {
    type: Date,
    optional: true
  }
});

Users.addField([
  /**
    An array containing comments upvotes
  */
  {
    fieldName: 'upvotedComments',
    fieldSchema: {
      type: [voteSchema],
      publish: false,
      optional: true,
      viewableBy: ['guests'],
      resolveAs: 'upvotedComments: [Vote]',
    }
  },
  /**
    An array containing posts upvotes
  */
  {
    fieldName: 'upvotedPosts',
    fieldSchema: {
      type: [voteSchema],
      publish: false,
      optional: true,
      viewableBy: ['guests'],
      resolveAs: 'upvotedPosts: [Vote]',
    }
  },
  /**
    An array containing comment downvotes
  */
  {
    fieldName: 'downvotedComments',
    fieldSchema: {
      type: [voteSchema],
      publish: false,
      optional: true,
      viewableBy: ['guests'],
      resolveAs: 'downvotedComments: [Vote]',
    }
  },
  /**
    An array containing posts downvotes
  */
  {
    fieldName: 'downvotedPosts',
    fieldSchema: {
      type: [voteSchema],
      publish: false,
      optional: true,
      viewableBy: ['guests'],
      resolveAs: 'downvotedPosts: [Vote]',
    }
  },
]);

Posts.addField([
  /**
    How many upvotes the post has received
  */
  {
    fieldName: "upvotes",
    fieldSchema: {
      type: Number,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    An array containing the `_id`s of the post's upvoters
  */
  {
    fieldName: "upvoters",
    fieldSchema: {
      type: [String],
      optional: true,
      publish: true,
      viewableBy: ['guests'],
      resolveAs: 'upvoters: [User]',
    }
  },
  /**
    How many downvotes the post has received
  */
  {
    fieldName: "downvotes",
    fieldSchema: {
      type: Number,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    An array containing the `_id`s of the post's downvoters
  */
  {
    fieldName: "downvoters",
    fieldSchema: {
      type: [String],
      optional: true,
      publish: true,
      viewableBy: ['guests'],
      resolveAs: 'downvoters: [User]',
    }
  },
  /**
    The post's base score (not factoring in the post's age)
  */
  {
    fieldName: "baseScore",
    fieldSchema: {
      type: Number,
      decimal: true,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    The post's current score (factoring in age)
  */
  {
    fieldName: "score",
    fieldSchema: {
      type: Number,
      decimal: true,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
]);

Comments.addField([
  /**
    The number of upvotes the comment has received
  */
  {
    fieldName: "upvotes",
    fieldSchema: {
      type: Number,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    An array containing the `_id`s of upvoters
  */
  {
    fieldName: "upvoters",
    fieldSchema: {
      type: [String],
      optional: true,
      publish: true,
      viewableBy: ['guests'],
      resolveAs: 'upvoters: [User]',
    }
  },
  /**
    The number of downvotes the comment has received
  */
  {
    fieldName: "downvotes",
    fieldSchema: {
      type: Number,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    An array containing the `_id`s of downvoters
  */
  {
    fieldName: "downvoters",
    fieldSchema: {
      type: [String],
      optional: true,
      publish: true,
      viewableBy: ['guests'],
      resolveAs: 'downvoters: [User]',
    }
  },
  /**
    The comment's base score (not factoring in the comment's age)
  */
  {
    fieldName: "baseScore",
    fieldSchema: {
      type: Number,
      decimal: true,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
  /**
    The comment's current score (factoring in age)
  */
  {
    fieldName: "score",
    fieldSchema: {
      type: Number,
      decimal: true,
      optional: true,
      publish: true,
      defaultValue: 0,
      viewableBy: ['guests'],
    }
  },
]);
<|endoftext|>


<commit_before>Package.describe({
  name: 'canotto90:latte',
  version: '0.6.0',
  summary: 'Run mocha-like specs in Meteor, without Velocity\'s overhead.',
  git: 'https://github.com/taromero/latte.git',
  documentation: '../../README.md'
})

Package.onUse(function (api) {
  api.versionsFrom('1.1.0.1')
  api.use('mongo@1.1.0', 'server')
  api.use('nooitaf:colors@0.0.2')
  api.addFiles('latte.js', 'server')
  api.export('T', 'server')
  api.export('describe', 'server')
  api.export('context', 'server')
  api.export('it', 'server')
  api.export('iit', 'server')
  api.export('beforeAll', 'server')
  api.export('beforeEach', 'server')
  api.export('afterAll', 'server')
  api.export('afterEach', 'server')
  api.export('ddescribe', 'server')
  api.export('ccontext', 'server')
})
<commit_msg>Bump version<commit_after>Package.describe({
  name: 'canotto90:latte',
  version: '0.6.1',
  summary: 'Run mocha-like specs in Meteor, without Velocity\'s overhead.',
  git: 'https://github.com/taromero/latte.git',
  documentation: '../../README.md'
})

Package.onUse(function (api) {
  api.versionsFrom('1.1.0.1')
  api.use('mongo@1.1.0', 'server')
  api.use('nooitaf:colors@0.0.2')
  api.addFiles('latte.js', 'server')
  api.export('T', 'server')
  api.export('describe', 'server')
  api.export('context', 'server')
  api.export('it', 'server')
  api.export('iit', 'server')
  api.export('beforeAll', 'server')
  api.export('beforeEach', 'server')
  api.export('afterAll', 'server')
  api.export('afterEach', 'server')
  api.export('ddescribe', 'server')
  api.export('ccontext', 'server')
})
<|endoftext|>


<commit_before>import { BaseError } from 'make-error'
import { noSuchObject } from 'xo-common/api-errors.js'

import { Schedules } from '../models/schedule'
import {
  forEach,
  mapToArray,
  scheduleFn
} from '../utils'

// ===================================================================

const _resolveId = scheduleOrId => scheduleOrId.id || scheduleOrId

export class SchedulerError extends BaseError {}

export class ScheduleOverride extends SchedulerError {
  constructor (scheduleOrId) {
    super('Schedule ID ' + _resolveId(scheduleOrId) + ' is already added')
  }
}

export class ScheduleNotEnabled extends SchedulerError {
  constructor (scheduleOrId) {
    super('Schedule ' + _resolveId(scheduleOrId) + ' is not enabled')
  }
}

export class ScheduleAlreadyEnabled extends SchedulerError {
  constructor (scheduleOrId) {
    super('Schedule ' + _resolveId(scheduleOrId) + ' is already enabled')
  }
}

// ===================================================================

export default class {
  constructor (xo) {
    this.xo = xo
    const schedules = this._redisSchedules = new Schedules({
      connection: xo._redis,
      prefix: 'xo:schedule',
      indexes: ['user_id', 'job']
    })
    this._scheduleTable = undefined

    xo.on('start', () => {
      xo.addConfigManager('schedules',
        () => schedules.get(),
        schedules_ => Promise.all(mapToArray(schedules_, schedule =>
          schedules.save(schedule)
        )),
        [ 'jobs' ]
      )

      return this._loadSchedules()
    })
    xo.on('stop', () => this._disableAll())
  }

  _add (schedule) {
    const id = _resolveId(schedule)
    this._schedules[id] = schedule
    this._scheduleTable[id] = false
    if (schedule.enabled) {
      this._enable(schedule)
    }
  }

  _exists (scheduleOrId) {
    const id_ = _resolveId(scheduleOrId)
    return id_ in this._schedules
  }

  _isEnabled (scheduleOrId) {
    return this._scheduleTable[_resolveId(scheduleOrId)]
  }

  _enable (schedule) {
    const { id } = schedule

    const stopSchedule = scheduleFn(
      schedule.cron,
      () => this.xo.runJobSequence([ schedule.job ]),
      schedule.timezone
    )

    this._cronJobs[id] = stopSchedule
    this._scheduleTable[id] = true
  }

  _disable (scheduleOrId) {
    if (!this._exists(scheduleOrId)) {
      throw noSuchObject(scheduleOrId, 'schedule')
    }
    if (!this._isEnabled(scheduleOrId)) {
      throw new ScheduleNotEnabled(scheduleOrId)
    }
    const id = _resolveId(scheduleOrId)
    this._cronJobs[id]() // Stop cron job.
    delete this._cronJobs[id]
    this._scheduleTable[id] = false
  }

  _disableAll () {
    forEach(this._scheduleTable, (enabled, id) => {
      if (enabled) {
        this._disable(id)
      }
    })
  }

  get scheduleTable () {
    return this._scheduleTable
  }

  async _loadSchedules () {
    this._schedules = {}
    this._scheduleTable = {}
    this._cronJobs = {}

    const schedules = await this.xo.getAllSchedules()

    forEach(schedules, schedule => {
      this._add(schedule)
    })
  }

  async _getSchedule (id) {
    const schedule = await this._redisSchedules.first(id)

    if (!schedule) {
      throw noSuchObject(id, 'schedule')
    }

    return schedule
  }

  async getSchedule (id) {
    return (await this._getSchedule(id)).properties
  }

  async getAllSchedules () {
    return /* await */ this._redisSchedules.get()
  }

  async createSchedule (userId, { job, cron, enabled, name, timezone }) {
    const schedule_ = await this._redisSchedules.create(userId, job, cron, enabled, name, timezone)
    const schedule = schedule_.properties

    this._add(schedule)

    return schedule
  }

  async updateSchedule (id, { job, cron, enabled, name, timezone }) {
    const schedule = await this._getSchedule(id)

    if (job) schedule.set('job', job)
    if (cron) schedule.set('cron', cron)
    if (enabled !== undefined) schedule.set('enabled', enabled)
    if (name !== undefined) schedule.set('name', name)
    if (timezone === null) {
      schedule.set('timezone', undefined) // Remove current timezone
    } else if (timezone !== undefined) {
      schedule.set('timezone', timezone)
    }

    await this._redisSchedules.save(schedule)

    const { properties } = schedule

    if (!this._exists(id)) {
      throw noSuchObject(id, 'schedule')
    }

    if (this._isEnabled(id)) {
      await this._disable(id)
    }

    this._add(properties)
  }

  async removeSchedule (id) {
    await this._redisSchedules.remove(id)

    try {
      this._disable(id)
    } catch (exc) {
      if (!(exc instanceof SchedulerError)) {
        throw exc
      }
    } finally {
      delete this._schedules[id]
      delete this._scheduleTable[id]
    }
  }
}
<commit_msg>chore(Scheduling#updateSchedule): explicit tests<commit_after>import { BaseError } from 'make-error'
import { noSuchObject } from 'xo-common/api-errors.js'

import { Schedules } from '../models/schedule'
import {
  forEach,
  mapToArray,
  scheduleFn
} from '../utils'

// ===================================================================

const _resolveId = scheduleOrId => scheduleOrId.id || scheduleOrId

export class SchedulerError extends BaseError {}

export class ScheduleOverride extends SchedulerError {
  constructor (scheduleOrId) {
    super('Schedule ID ' + _resolveId(scheduleOrId) + ' is already added')
  }
}

export class ScheduleNotEnabled extends SchedulerError {
  constructor (scheduleOrId) {
    super('Schedule ' + _resolveId(scheduleOrId) + ' is not enabled')
  }
}

export class ScheduleAlreadyEnabled extends SchedulerError {
  constructor (scheduleOrId) {
    super('Schedule ' + _resolveId(scheduleOrId) + ' is already enabled')
  }
}

// ===================================================================

export default class {
  constructor (xo) {
    this.xo = xo
    const schedules = this._redisSchedules = new Schedules({
      connection: xo._redis,
      prefix: 'xo:schedule',
      indexes: ['user_id', 'job']
    })
    this._scheduleTable = undefined

    xo.on('start', () => {
      xo.addConfigManager('schedules',
        () => schedules.get(),
        schedules_ => Promise.all(mapToArray(schedules_, schedule =>
          schedules.save(schedule)
        )),
        [ 'jobs' ]
      )

      return this._loadSchedules()
    })
    xo.on('stop', () => this._disableAll())
  }

  _add (schedule) {
    const id = _resolveId(schedule)
    this._schedules[id] = schedule
    this._scheduleTable[id] = false
    if (schedule.enabled) {
      this._enable(schedule)
    }
  }

  _exists (scheduleOrId) {
    const id_ = _resolveId(scheduleOrId)
    return id_ in this._schedules
  }

  _isEnabled (scheduleOrId) {
    return this._scheduleTable[_resolveId(scheduleOrId)]
  }

  _enable (schedule) {
    const { id } = schedule

    const stopSchedule = scheduleFn(
      schedule.cron,
      () => this.xo.runJobSequence([ schedule.job ]),
      schedule.timezone
    )

    this._cronJobs[id] = stopSchedule
    this._scheduleTable[id] = true
  }

  _disable (scheduleOrId) {
    if (!this._exists(scheduleOrId)) {
      throw noSuchObject(scheduleOrId, 'schedule')
    }
    if (!this._isEnabled(scheduleOrId)) {
      throw new ScheduleNotEnabled(scheduleOrId)
    }
    const id = _resolveId(scheduleOrId)
    this._cronJobs[id]() // Stop cron job.
    delete this._cronJobs[id]
    this._scheduleTable[id] = false
  }

  _disableAll () {
    forEach(this._scheduleTable, (enabled, id) => {
      if (enabled) {
        this._disable(id)
      }
    })
  }

  get scheduleTable () {
    return this._scheduleTable
  }

  async _loadSchedules () {
    this._schedules = {}
    this._scheduleTable = {}
    this._cronJobs = {}

    const schedules = await this.xo.getAllSchedules()

    forEach(schedules, schedule => {
      this._add(schedule)
    })
  }

  async _getSchedule (id) {
    const schedule = await this._redisSchedules.first(id)

    if (!schedule) {
      throw noSuchObject(id, 'schedule')
    }

    return schedule
  }

  async getSchedule (id) {
    return (await this._getSchedule(id)).properties
  }

  async getAllSchedules () {
    return /* await */ this._redisSchedules.get()
  }

  async createSchedule (userId, { job, cron, enabled, name, timezone }) {
    const schedule_ = await this._redisSchedules.create(userId, job, cron, enabled, name, timezone)
    const schedule = schedule_.properties

    this._add(schedule)

    return schedule
  }

  async updateSchedule (id, { job, cron, enabled, name, timezone }) {
    const schedule = await this._getSchedule(id)

    if (job !== undefined) schedule.set('job', job)
    if (cron !== undefined) schedule.set('cron', cron)
    if (enabled !== undefined) schedule.set('enabled', enabled)
    if (name !== undefined) schedule.set('name', name)
    if (timezone === null) {
      schedule.set('timezone', undefined) // Remove current timezone
    } else if (timezone !== undefined) {
      schedule.set('timezone', timezone)
    }

    await this._redisSchedules.save(schedule)

    const { properties } = schedule

    if (!this._exists(id)) {
      throw noSuchObject(id, 'schedule')
    }

    if (this._isEnabled(id)) {
      await this._disable(id)
    }

    this._add(properties)
  }

  async removeSchedule (id) {
    await this._redisSchedules.remove(id)

    try {
      this._disable(id)
    } catch (exc) {
      if (!(exc instanceof SchedulerError)) {
        throw exc
      }
    } finally {
      delete this._schedules[id]
      delete this._scheduleTable[id]
    }
  }
}
<|endoftext|>


<commit_before>//= require three.min
//= require Detector
function init() {
	$("body").append("

");
	var styleForOutput = {
		'top': '0px',
		'left': '0px',
		'right': '0px',
		'bottom': '0px',
		'z-index': '-10',
		'position': 'fixed',
		'margin': 0,
		'overflow': 'hidden',
		'filter': 'alpha(opacity=100)',
		'-moz-opacity': '0.4',
		'-khtml-opacity': '0.4',
		'opacity': '0.4'
	};
	$("#WebGL-output").css(styleForOutput);
	if (!Detector.webgl) Detector.addGetWebGLMessage();
	var camera, scene, renderer;
	var cameraCube, sceneCube;
	var mesh, lightMesh, geometry, webGLRenderer;
	var spheres = [];
	var directionalLight, pointLight;
	var mouseX = 0,
		mouseY = 0;
	var windowHalfX = window.innerWidth / 2;
	var windowHalfY = window.innerHeight / 2;
	document.addEventListener('mousemove', onDocumentMouseMove, false);
	camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000);
	camera.position.z = 3200;
	cameraCube = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000);
	scene = new THREE.Scene();
	sceneCube = new THREE.Scene();
	var geometry = new THREE.SphereBufferGeometry(100, 32, 16);
	var path = "images/";
	var format = '.jpg';
	var urls = [
		path + 'px' + format, path + 'nx' + format,
		path + 'py' + format, path + 'ny' + format,
		path + 'pz' + format, path + 'nz' + format
	];
	var textureCube = new THREE.CubeTextureLoader().load(urls);
	textureCube.mapping = THREE.CubeRefractionMapping;
	var material = new THREE.MeshBasicMaterial({
		color: 0xffffff,
		envMap: textureCube,
		refractionRatio: 0.95
	});
	// for (var i = 0; i < 500; i++) {
	// 	var mesh = new THREE.Mesh(geometry, material);
	// 	mesh.position.x = Math.random() * 10000 - 5000;
	// 	mesh.position.y = Math.random() * 10000 - 5000;
	// 	mesh.position.z = Math.random() * 10000 - 5000;
	// 	mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 3 + 1;
	// 	scene.add(mesh);
	// 	spheres.push(mesh);
	// }
	// Skybox
	var shader = THREE.ShaderLib["cube"];
	shader.uniforms["tCube"].value = textureCube;
	var material = new THREE.ShaderMaterial({
			fragmentShader: shader.fragmentShader,
			vertexShader: shader.vertexShader,
			uniforms: shader.uniforms,
			depthWrite: false,
			side: THREE.BackSide
		}),
		mesh = new THREE.Mesh(new THREE.BoxGeometry(100, 100, 100), material);
	sceneCube.add(mesh);
	//
	webGLRenderer = new THREE.WebGLRenderer();
	webGLRenderer.setPixelRatio(window.devicePixelRatio);
	webGLRenderer.setSize(window.innerWidth, window.innerHeight);
	webGLRenderer.autoClear = false;
	document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
	//
	window.addEventListener('resize', onWindowResize, false);
	animate();

	function onWindowResize() {
		windowHalfX = window.innerWidth / 2,
			windowHalfY = window.innerHeight / 2,
			camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		cameraCube.aspect = window.innerWidth / window.innerHeight;
		cameraCube.updateProjectionMatrix();
		renderer.setSize(window.innerWidth, window.innerHeight);
	}

	function onDocumentMouseMove(event) {
		mouseX = (event.clientX - windowHalfX) * 10;
		mouseY = (event.clientY - windowHalfY) * 10;
	}
	//
	function animate() {
		requestAnimationFrame(animate);
		render();
	}

	function render() {
		var timer = 0.0001 * Date.now();
		for (var i = 0, il = spheres.length; i < il; i++) {
			var sphere = spheres[i];
			sphere.position.x = 5000 * Math.cos(timer + i);
			sphere.position.y = 5000 * Math.sin(timer + i * 1.1);
		}
		camera.position.x += (mouseX - camera.position.x) * .05;
		camera.position.y += (-mouseY - camera.position.y) * .05;
		camera.lookAt(scene.position);
		cameraCube.rotation.copy(camera.rotation);
		webGLRenderer.render(sceneCube, cameraCube);
		webGLRenderer.render(scene, camera);
	}
}
window.onload = init;<commit_msg>fix cloud<commit_after>//= require three.min
//= require Detector
function init() {
	$("body").append("

");
	var styleForOutput = {
		'top': '0px',
		'left': '0px',
		'right': '0px',
		'bottom': '0px',
		'z-index': '-10',
		'position': 'fixed',
		'margin': 0,
		'overflow': 'hidden',
		'filter': 'alpha(opacity=100)',
		'-moz-opacity': '0.4',
		'-khtml-opacity': '0.4',
		'opacity': '0.4'
	};
	$("#WebGL-output").css(styleForOutput);
	if (!Detector.webgl) Detector.addGetWebGLMessage();
	var camera, scene, renderer;
	var cameraCube, sceneCube;
	var mesh, lightMesh, geometry, webGLRenderer;
	var spheres = [];
	var directionalLight, pointLight;
	var mouseX = 0,
		mouseY = 0;
	var windowHalfX = window.innerWidth / 2;
	var windowHalfY = window.innerHeight / 2;
	document.addEventListener('mousemove', onDocumentMouseMove, false);
	camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000);
	camera.position.z = 3200;
	cameraCube = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000);
	scene = new THREE.Scene();
	sceneCube = new THREE.Scene();
	var geometry = new THREE.SphereBufferGeometry(100, 32, 16);
	var path = "images/";
	var format = '.jpg';
	var urls = [
		path + 'px' + format, path + 'nx' + format,
		path + 'py' + format, path + 'ny' + format,
		path + 'pz' + format, path + 'nz' + format
	];
	var textureCube = new THREE.CubeTextureLoader().load(urls);
	textureCube.mapping = THREE.CubeRefractionMapping;
	var material = new THREE.MeshBasicMaterial({
		color: 0xffffff,
		envMap: textureCube,
		refractionRatio: 0.95
	});
	// for (var i = 0; i < 500; i++) {
	// 	var mesh = new THREE.Mesh(geometry, material);
	// 	mesh.position.x = Math.random() * 10000 - 5000;
	// 	mesh.position.y = Math.random() * 10000 - 5000;
	// 	mesh.position.z = Math.random() * 10000 - 5000;
	// 	mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 3 + 1;
	// 	scene.add(mesh);
	// 	spheres.push(mesh);
	// }
	// Skybox
	var shader = THREE.ShaderLib["cube"];
	shader.uniforms["tCube"].value = textureCube;
	var material = new THREE.ShaderMaterial({
			fragmentShader: shader.fragmentShader,
			vertexShader: shader.vertexShader,
			uniforms: shader.uniforms,
			depthWrite: false,
			side: THREE.BackSide
		}),
		mesh = new THREE.Mesh(new THREE.BoxGeometry(100, 100, 100), material);
	sceneCube.add(mesh);
	//
	webGLRenderer = new THREE.WebGLRenderer();
	webGLRenderer.setPixelRatio(window.devicePixelRatio);
	webGLRenderer.setSize(window.innerWidth, window.innerHeight);
	webGLRenderer.autoClear = false;
	document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
	//
	window.addEventListener('resize', onWindowResize, false);
	animate();

	function onWindowResize() {
		windowHalfX = window.innerWidth / 2,
			windowHalfY = window.innerHeight / 2,
			camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		cameraCube.aspect = window.innerWidth / window.innerHeight;
		cameraCube.updateProjectionMatrix();
		webGLRenderer.setSize(window.innerWidth, window.innerHeight);
	}

	function onDocumentMouseMove(event) {
		mouseX = (event.clientX - windowHalfX) * 10;
		mouseY = (event.clientY - windowHalfY) * 10;
	}
	//
	function animate() {
		requestAnimationFrame(animate);
		render();
	}

	function render() {
		var timer = 0.0001 * Date.now();
		for (var i = 0, il = spheres.length; i < il; i++) {
			var sphere = spheres[i];
			sphere.position.x = 5000 * Math.cos(timer + i);
			sphere.position.y = 5000 * Math.sin(timer + i * 1.1);
		}
		camera.position.x += (mouseX - camera.position.x) * .05;
		camera.position.y += (-mouseY - camera.position.y) * .05;
		camera.lookAt(scene.position);
		cameraCube.rotation.copy(camera.rotation);
		webGLRenderer.render(sceneCube, cameraCube);
		webGLRenderer.render(scene, camera);
	}
}
window.onload = init;<|endoftext|>


<commit_before>import { ObjectID as objectId } from 'mongodb';
import omit from 'lodash/omit';
import { fromMongoCursor, fromMongo } from './helpers';

export const createCRUDResolvers = ({ getRepository, getLoaders }) => ({
  findOne: (_, { id }, ctx) => getLoaders(ctx).findById.load(id),
  findMany: (_, args, ctx) => getLoaders(ctx).findMany.load({}),
  createOne: async (_, { input }, ctx) => fromMongo(await getRepository(ctx).createOne(input)),
  updateOne: async (_, { id, input }, ctx) => {
    const Repository = getRepository(ctx);
    const item = await Repository.findById(objectId(id));

    if (!item) {
      throw new Error(`Unable to find item with id: ${id}!`);
    }

    await Repository.validate(
      omit(
        {
          ...item,
          ...input,
        },
        ['_id'],
      ),
    );

    return fromMongo(
      await Repository.updateOne({
        query: {
          _id: item._id,
        },
        update: {
          $set: input,
        },
      }),
    );
  },
  deleteOne: async (_, { id }, ctx) => {
    const Repository = getRepository(ctx);
    const item = await Repository.findById(objectId(id));

    if (!item) {
      throw new Error(`Unable to find item with id: ${id}!`);
    }

    return fromMongo(await Repository.deleteOne({ query: { _id: item._id } }));
  },
});

export const createLoaders = Repository => ({
  findById: {
    loader: ids =>
      Repository.findMany({
        query: {
          _id: {
            $in: ids.map(objectId),
          },
        },
      }).then(fromMongoCursor),
    options: {
      cacheKeyFn: key => key.toString(),
    },
  },
  findOne: {
    loader: queries =>
      Promise.all(
        queries.map(query =>
          Repository.findOne({
            query,
          }).then(fromMongo),
        ),
      ),
    options: {
      cacheKeyFn: key => JSON.stringify(key),
    },
  },
  findMany: {
    loader: queries =>
      Promise.all(queries.map((query = {}) => Repository.findMany(query).then(fromMongoCursor))),
    options: {
      cacheKeyFn: key => JSON.stringify(key),
    },
  },
});
<commit_msg>[oors-mongodb] findById loader maps the ids to either db entries or null values<commit_after>import { ObjectID as objectId } from 'mongodb';
import omit from 'lodash/omit';
import { fromMongoCursor, fromMongo } from './helpers';

export const createCRUDResolvers = ({ getRepository, getLoaders }) => ({
  findOne: (_, { id }, ctx) => getLoaders(ctx).findById.load(id),
  findMany: (_, args, ctx) => getLoaders(ctx).findMany.load({}),
  createOne: async (_, { input }, ctx) => fromMongo(await getRepository(ctx).createOne(input)),
  updateOne: async (_, { id, input }, ctx) => {
    const Repository = getRepository(ctx);
    const item = await Repository.findById(objectId(id));

    if (!item) {
      throw new Error(`Unable to find item with id: ${id}!`);
    }

    await Repository.validate(
      omit(
        {
          ...item,
          ...input,
        },
        ['_id'],
      ),
    );

    return fromMongo(
      await Repository.updateOne({
        query: {
          _id: item._id,
        },
        update: {
          $set: input,
        },
      }),
    );
  },
  deleteOne: async (_, { id }, ctx) => {
    const Repository = getRepository(ctx);
    const item = await Repository.findById(objectId(id));

    if (!item) {
      throw new Error(`Unable to find item with id: ${id}!`);
    }

    return fromMongo(await Repository.deleteOne({ query: { _id: item._id } }));
  },
});

export const createLoaders = Repository => ({
  findById: {
    loader: async ids => {
      const items = await Repository.findMany({
        query: {
          _id: {
            $in: ids.map(objectId),
          },
        },
      }).then(fromMongoCursor);

      return ids.map(id => items.find(item => item.id.toString() === id.toString()) || null);
    },
    options: {
      cacheKeyFn: key => key.toString(),
    },
  },
  findOne: {
    loader: queries =>
      Promise.all(
        queries.map(query =>
          Repository.findOne({
            query,
          }).then(fromMongo),
        ),
      ),
    options: {
      cacheKeyFn: key => JSON.stringify(key),
    },
  },
  findMany: {
    loader: queries =>
      Promise.all(queries.map((query = {}) => Repository.findMany(query).then(fromMongoCursor))),
    options: {
      cacheKeyFn: key => JSON.stringify(key),
    },
  },
});
<|endoftext|>


<commit_before>/*
 * This file is part of yoob.js version 0.8
 * Available from https://github.com/catseye/yoob.js/
 * This file is in the public domain.  See http://unlicense.org/ for details.
 */
if (window.yoob === undefined) yoob = {};

/*
 * Functions for creating elements.
 */

yoob.makeCanvas = function(container, width, height) {
    var canvas = document.createElement('canvas');
    if (width) {
        canvas.width = width;
    }
    if (height) {
        canvas.height = height;
    }
    container.appendChild(canvas);
    return canvas;
};

yoob.makeButton = function(container, labelText, fun) {
    var button = document.createElement('button');
    button.innerHTML = labelText;
    container.appendChild(button);
    if (fun) {
        button.onclick = fun;
    }
    return button;
};

yoob.checkBoxNumber = 0;
yoob.makeCheckbox = function(container, checked, labelText, fun) {
    var checkbox = document.createElement('input');
    checkbox.type = "checkbox";
    checkbox.id = 'cfzzzb_' + yoob.checkBoxNumber;
    checkbox.checked = checked;
    var label = document.createElement('label');
    label.htmlFor = 'cfzzzb_' + yoob.checkBoxNumber;
    yoob.checkBoxNumber += 1;
    label.appendChild(document.createTextNode(labelText));

    container.appendChild(checkbox);
    container.appendChild(label);

    if (fun) {
        checkbox.onchange = function(e) {
            fun(checkbox.checked);
        };
    }
    return checkbox;
};

yoob.makeTextInput = function(container, size, value) {
    var input = document.createElement('input');
    input.size = "" + (size || 12);
    input.value = value || "";
    container.appendChild(input);
    return input;
};

yoob.makeSlider = function(container, min, max, value, fun) {
    var slider = document.createElement('input');
    slider.type = "range";
    slider.min = min;
    slider.max = max;
    slider.value = value || 0;
    if (fun) {
        slider.onchange = function(e) {
            fun(parseInt(slider.value, 10));
        };
    }
    container.appendChild(slider);
    return slider;
};

yoob.makeParagraph = function(container, innerHTML) {
    var p = document.createElement('p');
    p.innerHTML = innerHTML || '';
    container.appendChild(p);
    return p;
};

yoob.makeSpan = function(container, innerHTML) {
    var span = document.createElement('span');
    span.innerHTML = innerHTML || '';
    container.appendChild(span);
    return span;
};

yoob.makeDiv = function(container, innerHTML) {
    var div = document.createElement('div');
    div.innerHTML = innerHTML || '';
    container.appendChild(div);
    return div;
};

yoob.makePre = function(container, innerHTML) {
    var elem = document.createElement('pre');
    elem.innerHTML = innerHTML || '';
    container.appendChild(elem);
    return elem;
};

yoob.makePanel = function(container, title, isOpen) {
    isOpen = !!isOpen;
    var panelContainer = document.createElement('div');
    var button = document.createElement('button');
    var innerContainer = document.createElement('div');
    innerContainer.style.display = isOpen ? "block" : "none";

    button.innerHTML = (isOpen ? "∇" : "⊳") + " " + title;
    button.onclick = function(e) {
        isOpen = !isOpen;
        button.innerHTML = (isOpen ? "∇" : "⊳") + " " + title;
        innerContainer.style.display = isOpen ? "block" : "none";
    };

    panelContainer.appendChild(button);
    panelContainer.appendChild(innerContainer);
    container.appendChild(panelContainer);
    return innerContainer;
};

yoob.makeTextArea = function(container, cols, rows, initial) {
    var textarea = document.createElement('textarea');
    textarea.rows = "" + rows;
    textarea.cols = "" + cols;
    if (initial) {
        container.value = initial;
    }
    container.appendChild(textarea);
    return textarea;
};

yoob.makeLineBreak = function(container) {
    var br = document.createElement('br');
    container.appendChild(br);
    return br;
};

yoob.makeSelect = function(container, labelText, optionsArray) {
    var label = document.createElement('label');
    label.innerHTML = labelText;
    container.appendChild(label);

    var select = document.createElement("select");

    for (var i = 0; i < optionsArray.length; i++) {
        var op = document.createElement("option");
        op.value = optionsArray[i][0];
        op.text = optionsArray[i][1];
        if (optionsArray[i].length > 2) {
            op.selected = optionsArray[i][2];
        } else {
            op.selected = false;
        }
        select.options.add(op);
    }

    container.appendChild(select);
    return select;
};

SliderPlusTextInput = function() {
    this.init = function(cfg) {
        this.slider = cfg.slider;
        this.textInput = cfg.textInput;
        this.callback = cfg.callback;
        return this;
    };

    this.set = function(value) {
        this.slider.value = "" + value;
        this.textInput.value = "" + value;
        this.callback(value);
    };
};

yoob.makeSliderPlusTextInput = function(container, label, min_, max_, size, value, fun) {
    yoob.makeSpan(container, label);
    var slider = yoob.makeSlider(container, min_, max_, value);
    var s = "" + value;
    var textInput = yoob.makeTextInput(container, size, s);
    slider.onchange = function(e) {
        textInput.value = slider.value;
        fun(parseInt(slider.value, 10));
    };
    textInput.onchange = function(e) {
        var v = parseInt(textInput.value, 10);
        if (v !== NaN) {
            slider.value = "" + v;
            fun(v);
        }
    };
    return new SliderPlusTextInput().init({
        'slider': slider,
        'textInput': textInput,
        'callback': fun
    });
};

yoob.makeSVG = function(container) {
    var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    /* <svg viewBox = "0 0 200 200" version = "1.1"> */
    container.appendChild(svg);
    return svg;
};

yoob.makeSVGElem = function(svg, tag, cfg) {
    var elem = document.createElementNS(svg.namespaceURI, tag);
    for (var key in cfg) {
        if (cfg.hasOwnProperty(key)) {
            elem.setAttribute(key, cfg[key]);
        }
    }
    svg.appendChild(elem);
    return elem;
};
<commit_msg>Fix bug in makeTextArea and apply proper version to this file.<commit_after>/*
 * This file is part of yoob.js version 0.9-PRE
 * Available from https://github.com/catseye/yoob.js/
 * This file is in the public domain.  See http://unlicense.org/ for details.
 */
if (window.yoob === undefined) yoob = {};

/*
 * Functions for creating elements.
 */

yoob.makeCanvas = function(container, width, height) {
    var canvas = document.createElement('canvas');
    if (width) {
        canvas.width = width;
    }
    if (height) {
        canvas.height = height;
    }
    container.appendChild(canvas);
    return canvas;
};

yoob.makeButton = function(container, labelText, fun) {
    var button = document.createElement('button');
    button.innerHTML = labelText;
    container.appendChild(button);
    if (fun) {
        button.onclick = fun;
    }
    return button;
};

yoob.checkBoxNumber = 0;
yoob.makeCheckbox = function(container, checked, labelText, fun) {
    var checkbox = document.createElement('input');
    checkbox.type = "checkbox";
    checkbox.id = 'cfzzzb_' + yoob.checkBoxNumber;
    checkbox.checked = checked;
    var label = document.createElement('label');
    label.htmlFor = 'cfzzzb_' + yoob.checkBoxNumber;
    yoob.checkBoxNumber += 1;
    label.appendChild(document.createTextNode(labelText));

    container.appendChild(checkbox);
    container.appendChild(label);

    if (fun) {
        checkbox.onchange = function(e) {
            fun(checkbox.checked);
        };
    }
    return checkbox;
};

yoob.makeTextInput = function(container, size, value) {
    var input = document.createElement('input');
    input.size = "" + (size || 12);
    input.value = value || "";
    container.appendChild(input);
    return input;
};

yoob.makeSlider = function(container, min, max, value, fun) {
    var slider = document.createElement('input');
    slider.type = "range";
    slider.min = min;
    slider.max = max;
    slider.value = value || 0;
    if (fun) {
        slider.onchange = function(e) {
            fun(parseInt(slider.value, 10));
        };
    }
    container.appendChild(slider);
    return slider;
};

yoob.makeParagraph = function(container, innerHTML) {
    var p = document.createElement('p');
    p.innerHTML = innerHTML || '';
    container.appendChild(p);
    return p;
};

yoob.makeSpan = function(container, innerHTML) {
    var span = document.createElement('span');
    span.innerHTML = innerHTML || '';
    container.appendChild(span);
    return span;
};

yoob.makeDiv = function(container, innerHTML) {
    var div = document.createElement('div');
    div.innerHTML = innerHTML || '';
    container.appendChild(div);
    return div;
};

yoob.makePre = function(container, innerHTML) {
    var elem = document.createElement('pre');
    elem.innerHTML = innerHTML || '';
    container.appendChild(elem);
    return elem;
};

yoob.makePanel = function(container, title, isOpen) {
    isOpen = !!isOpen;
    var panelContainer = document.createElement('div');
    var button = document.createElement('button');
    var innerContainer = document.createElement('div');
    innerContainer.style.display = isOpen ? "block" : "none";

    button.innerHTML = (isOpen ? "∇" : "⊳") + " " + title;
    button.onclick = function(e) {
        isOpen = !isOpen;
        button.innerHTML = (isOpen ? "∇" : "⊳") + " " + title;
        innerContainer.style.display = isOpen ? "block" : "none";
    };

    panelContainer.appendChild(button);
    panelContainer.appendChild(innerContainer);
    container.appendChild(panelContainer);
    return innerContainer;
};

yoob.makeTextArea = function(container, cols, rows, initial) {
    var textarea = document.createElement('textarea');
    textarea.rows = "" + rows;
    textarea.cols = "" + cols;
    if (initial) {
        textarea.value = initial;
    }
    container.appendChild(textarea);
    return textarea;
};

yoob.makeLineBreak = function(container) {
    var br = document.createElement('br');
    container.appendChild(br);
    return br;
};

yoob.makeSelect = function(container, labelText, optionsArray) {
    var label = document.createElement('label');
    label.innerHTML = labelText;
    container.appendChild(label);

    var select = document.createElement("select");

    for (var i = 0; i < optionsArray.length; i++) {
        var op = document.createElement("option");
        op.value = optionsArray[i][0];
        op.text = optionsArray[i][1];
        if (optionsArray[i].length > 2) {
            op.selected = optionsArray[i][2];
        } else {
            op.selected = false;
        }
        select.options.add(op);
    }

    container.appendChild(select);
    return select;
};

SliderPlusTextInput = function() {
    this.init = function(cfg) {
        this.slider = cfg.slider;
        this.textInput = cfg.textInput;
        this.callback = cfg.callback;
        return this;
    };

    this.set = function(value) {
        this.slider.value = "" + value;
        this.textInput.value = "" + value;
        this.callback(value);
    };
};

yoob.makeSliderPlusTextInput = function(container, label, min_, max_, size, value, fun) {
    yoob.makeSpan(container, label);
    var slider = yoob.makeSlider(container, min_, max_, value);
    var s = "" + value;
    var textInput = yoob.makeTextInput(container, size, s);
    slider.onchange = function(e) {
        textInput.value = slider.value;
        fun(parseInt(slider.value, 10));
    };
    textInput.onchange = function(e) {
        var v = parseInt(textInput.value, 10);
        if (v !== NaN) {
            slider.value = "" + v;
            fun(v);
        }
    };
    return new SliderPlusTextInput().init({
        'slider': slider,
        'textInput': textInput,
        'callback': fun
    });
};

yoob.makeSVG = function(container) {
    var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    /* <svg viewBox = "0 0 200 200" version = "1.1"> */
    container.appendChild(svg);
    return svg;
};

yoob.makeSVGElem = function(svg, tag, cfg) {
    var elem = document.createElementNS(svg.namespaceURI, tag);
    for (var key in cfg) {
        if (cfg.hasOwnProperty(key)) {
            elem.setAttribute(key, cfg[key]);
        }
    }
    svg.appendChild(elem);
    return elem;
};
<|endoftext|>


<commit_before>/* eslint max-lines: [ 'error', { max: 400 } ] */
import { Model as ObjectionModel } from 'objection'

import './Inflect'
import './ModelNotFoundError'
import './RelationSynchronizer'
import './RelationValidator'

const as = require('as-type')

export class Model extends ObjectionModel {
	static descriptiveName = null
	static eager = null
	static eagerFilters = null
	static useTimestamps = true
	static createdAt = 'created_at'
	static updatedAt = 'updated_at'
	static dates = []
	static useIdSafeUpdates = false

	static $$app = null

	static app(app) {
		if (!app.isNil) {
			this.$$app = app
		} else {
			return this.$$app
		}
	}

	$app() {
		return this.constructor.app()
	}

	static findById(id, trx = null) {
		return this.query(trx).findById(id)
	}

	static findByIdOrFail(id, trx = null) {
		return this.findById(id, trx).orFail()
	}

	static findByRouteParameter(value, trx = null) {
		return this.findById(value, trx)
	}

	static routeBind(name, description) {
		description = description || `${name} Value`

		this.app().routes.bind(
			name,
			(value, resolve, reject) => {
				this.findByRouteParameter(value).then(row => {
					if (row.isNil) {
						reject(new ModelNotFoundError(this))
						return
					}

					resolve(row)
				})
			},
			{ swagger: { name, description } },
		)
	}

	static buildRelations() {
		return {}
	}

	static getRelations() {
		if (this.relationMappings.isNil) {
			this.relationMappings = this.buildRelations()
		}

		return super.getRelations()
	}

	static hasOne(modelClass, foreignKey = null, localKey = null) {
		return this._hasOneOrMany(this.HasOneRelation, modelClass, foreignKey, localKey)
	}

	static hasMany(modelClass, foreignKey = null, localKey = null) {
		return this._hasOneOrMany(this.HasManyRelation, modelClass, foreignKey, localKey)
	}

	static _hasOneOrMany(relation, modelClass, foreignKey = null, localKey = null) {
		foreignKey = foreignKey || Inflect.foreignKey(this.name)

		if (localKey.isNil) {
			localKey = this._getFullIdColumn()
		} else {
			localKey = `${this.tableName}.${localKey}`
		}

		return {
			relation: relation,
			modelClass: modelClass,
			join: {
				from: `${modelClass.tableName}.${foreignKey}`,
				to: localKey,
			},
		}
	}

	static belongsTo(modelClass, foreignKey = null, otherKey = null) {
		foreignKey = foreignKey || Inflect.foreignKey(modelClass.name)

		if (otherKey.isNil) {
			otherKey = modelClass._getFullIdColumn()
		} else {
			otherKey = `${modelClass.tableName}.${otherKey}`
		}

		return {
			relation: this.BelongsToOneRelation,
			modelClass: modelClass,
			join: {
				from: `${this.tableName}.${foreignKey}`,
				to: otherKey,
			},
		}
	}

	static belongsToMany(modelClass, tableName = null, foreignKey = null, otherKey = null) {
		tableName = tableName || [this.tableName, modelClass.tableName].sort().join('_')
		foreignKey = foreignKey || Inflect.foreignKey(modelClass.name)
		otherKey = otherKey || Inflect.foreignKey(this.name)

		return {
			relation: this.ManyToManyRelation,
			modelClass: modelClass,
			join: {
				from: this._getFullIdColumn(),
				through: {
					from: `${tableName}.${otherKey}`,
					to: `${tableName}.${foreignKey}`,
				},
				to: modelClass._getFullIdColumn(),
			},
		}
	}

	$sync(relation, ids, trx = null) {
		return new RelationSynchronizer(this, relation).sync(ids, trx)
	}

	$relate(relation, ids, trx = null) {
		return new RelationSynchronizer(this, relation).relate(ids, trx)
	}

	$unrelate(relation, ids, trx = null) {
		return new RelationSynchronizer(this, relation).unrelate(ids, trx)
	}

	$parseDatabaseJson(json) {
		json = super.$parseDatabaseJson(json)

		for (const date of this.constructor.getDates()) {
			if (json[date].isNil) {
				continue
			}

			json[date] = this.constructor.asDate(json[date])
		}

		const schema = this.constructor.jsonSchema

		if (schema.isNil || schema.properties.isNil) {
			return json
		}

		for (const field of Object.keys(schema.properties)) {
			if (json[field].isNil) {
				continue
			}

			if (Number.isNaN(json[field])) {
				json[field] = null
				continue
			}

			const property = schema.properties[field]

			// Boolean values can be converted to JSON as "0"/"1", convert back to boolean
			if (property.type === 'boolean') {
				json[field] = as.boolean(json[field])
			}

			// Number values can be converted to JSON as strings, convert back to numbers
			if (
				property.type === 'number' ||
				property.type === 'float' ||
				property.type === 'double'
			) {
				json[field] = as.float(json[field])
			} else if (property.type === 'integer') {
				json[field] = as.integer(json[field])
			}
		}

		return json
	}

	$formatDatabaseJson(json) {
		json = super.$formatDatabaseJson(json)

		for (const date of this.constructor.getDates()) {
			if (json[date].isNil) {
				continue
			}

			json[date] = this.constructor.asDatabaseDate(json[date])
		}

		return json
	}

	$beforeValidate(jsonSchema, json, opt) {
		const properties = jsonSchema.properties || {}

		for (const field of Object.keys(properties)) {
			const value = json[field]

			if (value.isNil) {
				continue
			}

			const property = properties[field]
			let fieldType = property.type
			let allowsNull = false

			if (!property.anyOf.isNil) {
				fieldType = property.anyOf.map(type => type.type)
			}

			if (Array.isArray(fieldType) && fieldType.length > 1) {
				allowsNull = fieldType.indexOf('null') >= 0
				fieldType = fieldType.filter(type => type !== 'null')[0]
			}

			if (allowsNull && typeof value === 'string' && value.length === 0) {
				json[field] = null
				continue
			}

			if (fieldType === 'boolean') {
				json[field] = as.boolean(json[field])
			} else if (fieldType === 'integer') {
				json[field] = as.integer(json[field])
			} else if (fieldType === 'number' || fieldType === 'float' || fieldType === 'double') {
				json[field] = as.float(json[field])
			}
		}

		return super.$beforeValidate(jsonSchema, json, opt)
	}

	$beforeSave(inserting, queryContext) {
		return new Promise(resolve => {
			if (this.constructor.useTimestamps) {
				const now = new Date()
				this[this.constructor.updatedAt] = now

				if (inserting) {
					this[this.constructor.createdAt] = now
				}
			}

			resolve()
		}).then(() => RelationValidator(this, queryContext))
	}

	$beforeInsert(...args) {
		return this.$beforeSave(true, ...args)
	}

	$beforeUpdate(...args) {
		if (this.constructor.useIdSafeUpdates) {
			const cols = this.constructor.getIdColumnArray()

			if (cols.length === 1) {
				delete this[cols[0]]
			} else {
				for (let i = 0, l = cols.length; i < l; i++) {
					delete this[cols[i]]
				}
			}
		}

		return this.$beforeSave(false, ...args)
	}

	static _getFullIdColumn() {
		// `getFullIdColumn` removed in Objection after 0.6.x
		// however the relation builder uses it, so we’ll restore
		// the functionality privately

		if (Array.isArray(this.idColumn)) {
			return this.idColumn.map(col => `${this.tableName}.${col}`)
		}

		return `${this.tableName}.${this.idColumn}`
	}

	static getDates() {
		if (this.useTimestamps) {
			return [...this.dates, this.createdAt, this.updatedAt]
		}

		return this.dates
	}

	static asDate(value) {
		return new Date(value)
	}

	static asDatabaseDate(value) {
		if (value instanceof Date) {
			return value
		}

		return new Date(value)
	}

	static describe() {
		if (!this.descriptiveName.isNil) {
			return this.descriptiveName
		}

		const name = Inflect.singularize(this.tableName)
		return name.charAt(0).toUpperCase() + name.substring(1)
	}
}
<commit_msg>fix(grind-orm): fixed buildRelations to work with objection 2.0<commit_after>/* eslint max-lines: [ 'error', { max: 400 } ] */
import { Model as ObjectionModel } from 'objection'

import './Inflect'
import './ModelNotFoundError'
import './RelationSynchronizer'
import './RelationValidator'

const as = require('as-type')

export class Model extends ObjectionModel {
	static descriptiveName = null
	static eager = null
	static eagerFilters = null
	static useTimestamps = true
	static createdAt = 'created_at'
	static updatedAt = 'updated_at'
	static dates = []
	static useIdSafeUpdates = false

	static $$app = null

	static app(app) {
		if (!app.isNil) {
			this.$$app = app
		} else {
			return this.$$app
		}
	}

	$app() {
		return this.constructor.app()
	}

	static findById(id, trx = null) {
		return this.query(trx).findById(id)
	}

	static findByIdOrFail(id, trx = null) {
		return this.findById(id, trx).orFail()
	}

	static findByRouteParameter(value, trx = null) {
		return this.findById(value, trx)
	}

	static routeBind(name, description) {
		description = description || `${name} Value`

		this.app().routes.bind(
			name,
			(value, resolve, reject) => {
				this.findByRouteParameter(value).then(row => {
					if (row.isNil) {
						reject(new ModelNotFoundError(this))
						return
					}

					resolve(row)
				})
			},
			{ swagger: { name, description } },
		)
	}

	static buildRelations() {
		return {}
	}

	static relationMappings() {
		if (this._relationMappings.isNil) {
			this._relationMappings = this.buildRelations()
		}

		return this._relationMappings
	}

	static hasOne(modelClass, foreignKey = null, localKey = null) {
		return this._hasOneOrMany(this.HasOneRelation, modelClass, foreignKey, localKey)
	}

	static hasMany(modelClass, foreignKey = null, localKey = null) {
		return this._hasOneOrMany(this.HasManyRelation, modelClass, foreignKey, localKey)
	}

	static _hasOneOrMany(relation, modelClass, foreignKey = null, localKey = null) {
		foreignKey = foreignKey || Inflect.foreignKey(this.name)

		if (localKey.isNil) {
			localKey = this._getFullIdColumn()
		} else {
			localKey = `${this.tableName}.${localKey}`
		}

		return {
			relation: relation,
			modelClass: modelClass,
			join: {
				from: `${modelClass.tableName}.${foreignKey}`,
				to: localKey,
			},
		}
	}

	static belongsTo(modelClass, foreignKey = null, otherKey = null) {
		foreignKey = foreignKey || Inflect.foreignKey(modelClass.name)

		if (otherKey.isNil) {
			otherKey = modelClass._getFullIdColumn()
		} else {
			otherKey = `${modelClass.tableName}.${otherKey}`
		}

		return {
			relation: this.BelongsToOneRelation,
			modelClass: modelClass,
			join: {
				from: `${this.tableName}.${foreignKey}`,
				to: otherKey,
			},
		}
	}

	static belongsToMany(modelClass, tableName = null, foreignKey = null, otherKey = null) {
		tableName = tableName || [this.tableName, modelClass.tableName].sort().join('_')
		foreignKey = foreignKey || Inflect.foreignKey(modelClass.name)
		otherKey = otherKey || Inflect.foreignKey(this.name)

		return {
			relation: this.ManyToManyRelation,
			modelClass: modelClass,
			join: {
				from: this._getFullIdColumn(),
				through: {
					from: `${tableName}.${otherKey}`,
					to: `${tableName}.${foreignKey}`,
				},
				to: modelClass._getFullIdColumn(),
			},
		}
	}

	$sync(relation, ids, trx = null) {
		return new RelationSynchronizer(this, relation).sync(ids, trx)
	}

	$relate(relation, ids, trx = null) {
		return new RelationSynchronizer(this, relation).relate(ids, trx)
	}

	$unrelate(relation, ids, trx = null) {
		return new RelationSynchronizer(this, relation).unrelate(ids, trx)
	}

	$parseDatabaseJson(json) {
		json = super.$parseDatabaseJson(json)

		for (const date of this.constructor.getDates()) {
			if (json[date].isNil) {
				continue
			}

			json[date] = this.constructor.asDate(json[date])
		}

		const schema = this.constructor.jsonSchema

		if (schema.isNil || schema.properties.isNil) {
			return json
		}

		for (const field of Object.keys(schema.properties)) {
			if (json[field].isNil) {
				continue
			}

			if (Number.isNaN(json[field])) {
				json[field] = null
				continue
			}

			const property = schema.properties[field]

			// Boolean values can be converted to JSON as "0"/"1", convert back to boolean
			if (property.type === 'boolean') {
				json[field] = as.boolean(json[field])
			}

			// Number values can be converted to JSON as strings, convert back to numbers
			if (
				property.type === 'number' ||
				property.type === 'float' ||
				property.type === 'double'
			) {
				json[field] = as.float(json[field])
			} else if (property.type === 'integer') {
				json[field] = as.integer(json[field])
			}
		}

		return json
	}

	$formatDatabaseJson(json) {
		json = super.$formatDatabaseJson(json)

		for (const date of this.constructor.getDates()) {
			if (json[date].isNil) {
				continue
			}

			json[date] = this.constructor.asDatabaseDate(json[date])
		}

		return json
	}

	$beforeValidate(jsonSchema, json, opt) {
		const properties = jsonSchema.properties || {}

		for (const field of Object.keys(properties)) {
			const value = json[field]

			if (value.isNil) {
				continue
			}

			const property = properties[field]
			let fieldType = property.type
			let allowsNull = false

			if (!property.anyOf.isNil) {
				fieldType = property.anyOf.map(type => type.type)
			}

			if (Array.isArray(fieldType) && fieldType.length > 1) {
				allowsNull = fieldType.indexOf('null') >= 0
				fieldType = fieldType.filter(type => type !== 'null')[0]
			}

			if (allowsNull && typeof value === 'string' && value.length === 0) {
				json[field] = null
				continue
			}

			if (fieldType === 'boolean') {
				json[field] = as.boolean(json[field])
			} else if (fieldType === 'integer') {
				json[field] = as.integer(json[field])
			} else if (fieldType === 'number' || fieldType === 'float' || fieldType === 'double') {
				json[field] = as.float(json[field])
			}
		}

		return super.$beforeValidate(jsonSchema, json, opt)
	}

	$beforeSave(inserting, queryContext) {
		return new Promise(resolve => {
			if (this.constructor.useTimestamps) {
				const now = new Date()
				this[this.constructor.updatedAt] = now

				if (inserting) {
					this[this.constructor.createdAt] = now
				}
			}

			resolve()
		}).then(() => RelationValidator(this, queryContext))
	}

	$beforeInsert(...args) {
		return this.$beforeSave(true, ...args)
	}

	$beforeUpdate(...args) {
		if (this.constructor.useIdSafeUpdates) {
			const cols = this.constructor.getIdColumnArray()

			if (cols.length === 1) {
				delete this[cols[0]]
			} else {
				for (let i = 0, l = cols.length; i < l; i++) {
					delete this[cols[i]]
				}
			}
		}

		return this.$beforeSave(false, ...args)
	}

	static _getFullIdColumn() {
		// `getFullIdColumn` removed in Objection after 0.6.x
		// however the relation builder uses it, so we’ll restore
		// the functionality privately

		if (Array.isArray(this.idColumn)) {
			return this.idColumn.map(col => `${this.tableName}.${col}`)
		}

		return `${this.tableName}.${this.idColumn}`
	}

	static getDates() {
		if (this.useTimestamps) {
			return [...this.dates, this.createdAt, this.updatedAt]
		}

		return this.dates
	}

	static asDate(value) {
		return new Date(value)
	}

	static asDatabaseDate(value) {
		if (value instanceof Date) {
			return value
		}

		return new Date(value)
	}

	static describe() {
		if (!this.descriptiveName.isNil) {
			return this.descriptiveName
		}

		const name = Inflect.singularize(this.tableName)
		return name.charAt(0).toUpperCase() + name.substring(1)
	}
}
<|endoftext|>


<commit_before>'use strict';
var d  = require('d')
  , generateId = require('time-uuid')
  , resolvePropertyPath = require('dbjs/_setup/utils/resolve-property-path')
  , normalizeOptions = require('es5-ext/object/normalize-options')
  , db = require('mano').db
  , ns = require('mano').domjs.ns;

/*
return object of form:
{
controls: ids || undefined,
legacy: lagacyScript || undefined
}
*/
module.exports = Object.defineProperty(db.FormSectionBase.prototype, 'getLegacy',
	d(function (formId/*, options */) {
		var result, legacyData, options = Object(arguments[1]), self, master;
		master = options.master || this.master;
		result = {};
		result.controls = {};
		options = Object(arguments[1]);
		self = this;
		this.constructor.propertyNames.forEach(function (item, propName) {
			var val, id, resolved, formFieldPath;
			resolved = resolvePropertyPath(this, propName);
			formFieldPath = resolved.object.__id__ + '/' + resolved.key;
			if (self.inputOptions.has(propName)) {
				result.controls[formFieldPath] = self.inputOptions.get(propName);
			}
			val = resolved.object.getDescriptor(db.Object.getApplicablePropName(resolved.key)
				)._value_;
			if (typeof val !== 'function') {
				return;
			}
			if (!legacyData) {
				legacyData = [];
			}
			id = 'input-' + generateId();
			legacyData.push({ id: id, constraint: val, sKeyPath: propName });
			result.controls[formFieldPath] = normalizeOptions(result.controls[formFieldPath], { id: id });
		}, master);
		if (legacyData) {
			result.legacy = ns.legacy('formSectionStateHelper', formId, master.__id__,
				legacyData, options.legacyEntityProto);
		}

		return result;
	}));
<commit_msg>-- cleanup<commit_after>'use strict';
var d  = require('d')
  , generateId = require('time-uuid')
  , resolvePropertyPath = require('dbjs/_setup/utils/resolve-property-path')
  , normalizeOptions = require('es5-ext/object/normalize-options')
  , db = require('mano').db
  , ns = require('mano').domjs.ns;

/*
return object of form:
{
controls: ids || undefined,
legacy: lagacyScript || undefined
}
*/
module.exports = Object.defineProperty(db.FormSectionBase.prototype, 'getLegacy',
	d(function (formId/*, options */) {
		var result, legacyData, options = Object(arguments[1]), self, master;
		master = options.master || this.master;
		result = {};
		result.controls = {};
		self = this;
		this.constructor.propertyNames.forEach(function (item, propName) {
			var val, id, resolved, formFieldPath;
			resolved = resolvePropertyPath(this, propName);
			formFieldPath = resolved.object.__id__ + '/' + resolved.key;
			if (self.inputOptions.has(propName)) {
				result.controls[formFieldPath] = self.inputOptions.get(propName);
			}
			val = resolved.object.getDescriptor(db.Object.getApplicablePropName(resolved.key)
				)._value_;
			if (typeof val !== 'function') {
				return;
			}
			if (!legacyData) {
				legacyData = [];
			}
			id = 'input-' + generateId();
			legacyData.push({ id: id, constraint: val, sKeyPath: propName });
			result.controls[formFieldPath] = normalizeOptions(result.controls[formFieldPath], { id: id });
		}, master);
		if (legacyData) {
			result.legacy = ns.legacy('formSectionStateHelper', formId, master.__id__,
				legacyData, options.legacyEntityProto);
		}

		return result;
	}));
<|endoftext|>


<commit_before>// JavaScript which enables display of this module's content
// to logged-out users belongs here.

// Create Google Map that displays the specified items. Uf mapOptions.center is not
// set to an object with lat and lng properties, the center is
// determined from the items. If there are no items... welcome to Philadelphia!

// id is a separate parameter because it's tough to set a property of an object
// in a nunjucks template, and we generate the id there. You are responsible for
// supplying a div with that id and a suitable width and height

var AposGoogleMap = function(items, id, mapOptions) {
  if (!window.google) {
    apos.log('google maps is not available in the build! Maybe you are running with offline: true in local.js, in which case this is normal.');
    return;
  }
  var self = this;

  // For points not geocoded server side
  var geocoder = new google.maps.Geocoder();

  var mapZoom;
  var mapCenter;

  self.filterBy = mapOptions.filterBy || 'all';

  function filter(filterBy) {
    console.log(filterBy);
    self.filterBy = filterBy;
    forEachItem(function(item) {
      ifMappable(item, function(item) {
        if (item.infoBox) {
          item.infoBox.close();
        }
        item.marker.setVisible(false);
      });
    });
    forEachItem(function(item) {
      ifFiltered(item, function(item) {
        item.marker.setVisible(true);
      });
    });
    if (filterBy == 'all') {
      resetZoom();
      resetCenter();
    } else {
      autoZoom();
      autoCenter();
    }
  }

  function forEachItem(iterator) {
    for (var i in self.items) {
      iterator(self.items[i]);
    }
  }

  function ifMappable(item, callback) {
    if (item.geo) {
      return callback(item);
    }
  }

  function ifFiltered(item, callback) {
    ifMappable(item, function(item) {
      if (self.filterBy === 'all') {
        return callback(item);
      } else {
        var filterBy = (_.isArray(self.filterBy)) ? self.filterBy : [self.filterBy];
        var marker = item.marker;
        if( _.intersection(self.filterBy, item.tags).length ) {
          return callback(item);
        }
      }
    });
  }

  function autoCenter() {
    var valid = 0;
    var lat = 0.0;
    var lng = 0.0;
    forEachItem(function(item) {
      ifMappable(item, function(item) {
        ifFiltered(item, function(item) {
          lat += item.geo.coordinates[1];
          lng += item.geo.coordinates[0];
          valid++;
        });
      });
    });
    var mapCenter;
    if (valid) {
      mapCenter = new google.maps.LatLng(lat / valid, lng / valid);
    } else {
      mapCenter = new google.maps.LatLng(39.952335, -75.163789);
    }
    self.map.setCenter(mapCenter);
  }

  function autoZoom() {
    var bounds;
    // Auto-zoom
    bounds = new google.maps.LatLngBounds();
    var count = 0;
    forEachItem(function(item) {
      ifMappable(item, function(item) {
        ifFiltered(item, function(item) {
          count++;
          bounds.extend(new google.maps.LatLng(item.geo.coordinates[1], item.geo.coordinates[0]));
        });
      });
    });
    if (count > 1) {
      self.map.fitBounds(bounds);
    } else if (count === 1) {
      self.map.setZoom(15);
    }
  }

  // Revert to whatever we had initially (for filtering by "all")
  function resetZoom() {
    if (mapZoom) {
      self.map.setZoom(mapZoom);
    } else {
      autoZoom();
    }
  }

  function resetCenter() {
    if (mapCenter) {
      self.map.setCenter(mapCenter);
    } else {
      autoCenter();
    }
  }

  self.items = items;
  self.mapOptions = mapOptions;

  // Why is this useful? (It's called once but just invokes its callback.)
  self.setup = function(callback) {
    callback();
  };

  // set up the actual map. This works asynchronously if needed to
  // geocode addresses browser-side

  self.googleMap = function() {

    // Geocode an item if needed
    function geocodeOne(i, callback) {
      var item = self.items[i];
      if ((!item.coords) && (item.address)) {
        geocoder.geocode( { 'address': self.items[i].address }, function(results, status) {
          if (status == google.maps.GeocoderStatus.OK) {
            item.coords = { lat: results[0].geometry.location.lat(), lng: results[0].geometry.location.lng() };
            return callback();
          } else {
            return callback();
          }
        });
      } else {
        return callback();
      }
    }

    // Simple async for loop to geocode them all, then invoke 'go'
    var i = 0;
    function geocodeNext() {
      if (i >= self.items.length) {
        return go();
      }
      return geocodeOne(i, function() {
        i++;
        return geocodeNext();
      });
    }

    geocodeNext();

    // Called once we're ready with all of our points
    function go() {
      var lat = 0.0;
      var lng = 0.0;
      if (self.mapOptions.center) {
        var center = self.mapOptions.center;
        mapCenter = new google.maps.LatLng(center.lat, center.lng);
      }

      mapZoom = self.mapOptions.zoom;
      var $mapEl = $('#' + id);
      // For easier targeting
      $mapEl.addClass('apos-map');
      var mapEl = $mapEl[0];

      // reasonable defaults for zoom and center until autoZoom or autoCenter can run
      var zoom = mapZoom || 12;

      var teaser = self.mapOptions.teaser;
      var map = new google.maps.Map(mapEl, {
        minZoom: teaser ? zoom : 0,
        maxZoom: teaser ? zoom : 100,
        zoom: zoom,
        panControl: !teaser,
        zoomControl: !teaser,
        scaleControl: !teaser,
        draggable: !teaser,
        streetViewControl: !teaser,
        center: mapCenter || new google.maps.LatLng(39.952335, -75.163789),
        mapTypeId: google.maps.MapTypeId.ROADMAP
      });

      if (self.mapOptions.teaser) {
        $(mapEl).css('cursor', 'pointer');
      }

      // teaser option: this display of the map is just a teaser to take
      // you to a more suitable page. Helps avoid overhead and scrolling
      // frustration when a map is full width on the homepage
      if (self.mapOptions.teaser) {
        google.maps.event.addListener(map, 'click', function() {
          // document.body.style.cursor = 'wait';
          window.location.href = self.mapOptions.teaser;
        });
      }

      self.map = map;

      var mapStyles = self.mapOptions.styles;

      if(mapStyles) map.setOptions({styles:mapStyles});

      map.setOptions({scrollwheel: false, mapTypeControl: false});

      // loop through the items getting passed in from our template
      // and create a marker / info box for each. To avoid convoluted
      // code just call a nested function in a loop and pass it 'i' so that
      // it's safe to write boring, simple event handlers there that use 'i'

      forEachItem(setUpItem);

      if (!mapZoom) {
        autoZoom();
      }
      if (!mapCenter) {
        autoCenter();
      }

      function setUpItem(item) {
        if (!item.coords) {
          // Ignore ungeocoded points
          return;
        }
        self.generateMarker(item, self.map);

        var selector = '.apos-location[data-location-id="' + item._id + '"]';
        $('.apos-location[data-location-id="' + item._id + '"]').click(function() {
          self.activateInfoBox(item);
          return false;
        });
        // attach a click listener to the marker that opens our info box
        if ((!mapOptions.teaser) && (!mapOptions.noBox)) {
          google.maps.event.addListener(item.marker, 'click', function() {
            self.activateInfoBox(item);
          });
        }
      }

      // Create a jQuery event that can be used to filter by
      // a particular tag or 'all'
      $(mapEl).on('filter', function(e) {
        // grab any arguments after the first (the event object),
        // which represent one or more tags to filter by.
        // we need to do this because calling .trigger('filter', Array)
        // passes the array items as arguments, instead of as an array.
        var filterBy = Array.prototype.slice.call(arguments, 1);
        // if the only argument supplied is the string "all",
        // pass it through as a string.
        if(filterBy.length == 1 && filterBy[0] == 'all') {
          filterBy = 'all';
        }
        return filter(filterBy);
      });
    }
  };

  self.activateInfoBox = function(item) {
    // for BC purposes, if an item has no `showInfoBox` property we'll fall
    // back on the old method of only showing an infoBox when there is no
    // body content.
    if ( ((item.showInfoBox === undefined || item.showInfoBox === null) && !item.descr) || item.showInfoBox === false) {
      // No info boxes for items without rich content, such as those
      // supplied for a plain street address associated with an event
      return;
    }
    forEachItem(function(item) {
      if (item.infoBox) {
        item.infoBox.close();
      }
      if (item.marker) {
        item.marker.content.firstChild.className = item.marker.content.firstChild.className.replace(' active', '');
      }
    });
    if (!item.infoBox) {
      self.generateInfoBox(item, self.map);
    }
    item.infoBox.open(self.map, item.marker);
    item.marker.content.firstChild.className += " active";
  };

  // Find the locType mentioned first in the tags of the item, otherwise
  // the first one defined, otherwise 'general'

  self.getLocType = function(item) {
    // This information was pushed into browserland with apos.pushGlobalData
    var locTypes = apos.data.aposMap.locTypes;
    var locTypeTag = _.find(item.tags || [], function(tag) {
      return _.find(locTypes, function(locType) {
        return locType.value === tag;
      });
    });
    var locType;
    if (locTypeTag) {
      locType = _.find(locTypes, function(locType) {
        return locType.value === locTypeTag;
      });
    }
    if (!locType) {
      locType = locTypes[0];
    }
    if (!locType) {
      locType = { value: 'general', label: 'General' };
    }
    return locType;
  };

  // Return a CSS-friendly version of the locType name

  self.getCssClass = function(item) {
    return apos.cssName(self.getLocType(item).value);
  };

  self.generateMarker = function(item, map)
  {
    var markerHTML = document.createElement('DIV');
        markerHTML.innerHTML = '

';

    var coords;
    // If the address is already a coordinate pair ignore any geocoding result and use it directly
    if (item.address.match(/^[\-\+0-9\.\,\ ]+$/)) {
      var rawCoords = item.address.split(/,\s*/);
      coords = new google.maps.LatLng(parseFloat(rawCoords[0]), parseFloat(rawCoords[1]));
    } else {
      coords = new google.maps.LatLng(item.geo.coordinates[1], item.geo.coordinates[0]);
    }

    var marker = new RichMarker({
      position: coords,
      draggable: false,
      visible: true,
      clickable: true,
      map: map,
      content: markerHTML
    });

    marker.locTypes = item.tags;
    item.marker = marker;
  };

  // IMPORTANT: if you want more properties to be visible here, make sure
  // you override the aposMapPruneLocations function to include them.
  // You can do that in your server-side extension of the map module.
  // See map/index.js for the original. Pruning is necessary to avoid
  // sending a zillion megabytes per page to the browser

  self.generateInfoBox = function(item, map) {
    var $box = apos.fromTemplate('.apos-map-location-info-box');

    var image = apos.getFirstImage(item, 'thumbnail');
    if (image) {
      var url = apos.filePath(image, { size: 'one-third' });
      $box.find('[data-image]').attr('src', url);
    } else {
      // Don't show a broken image
      $box.find('[data-image]').remove();
      $box.addClass('no-img');
    }
    $box.find('[data-loc-type]').text(item.locType);
    $box.find('[data-title]').text(item.title);
    // Do not show the "address" if it is actually a lat,long coordinate pair
    var $address = $box.find('[data-address]');
    if (!item.address.match(/^[\-\+0-9\.\,\ ]+$/)) {
      $address.text(item.address);
    } else {
      $address.hide();
    }
    $box.find('[data-descr]').text(item.descr);
    // $box.find('[data-hours]').text(item.hours);
    if (item.url) {
      $box.find('[data-url]').attr('href', item.url);
    }

    var boxOptions = {
      // Wants the actual DOM element, not jQuery
      content: $box[0],
      disableAutoPan: false,
      pixelOffset: new google.maps.Size(10,-137),
      boxStyle: {
        width: "280px"
       },
      closeBoxMargin: "0px 0px 0px 0px",
      closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif",
      infoBoxClearance: new google.maps.Size(1, 1),
      pane: "floatPane",
      enableEventPropagation: false
    };

    item.infoBox = new InfoBox(boxOptions);
  };

  //call setup and feed it the google map load listener
  self.setup(function() {
    $(function() {
      self.googleMap();
    });
  });
};
<commit_msg>* AposGoogleMap once again on-the-fly geocoding properly for ad-hoc locations with just an address field. This was missed when we upgraded to MongoDB's GeoJSON format<commit_after>// JavaScript which enables display of this module's content
// to logged-out users belongs here.

// Create Google Map that displays the specified items. Uf mapOptions.center is not
// set to an object with lat and lng properties, the center is
// determined from the items. If there are no items... welcome to Philadelphia!

// id is a separate parameter because it's tough to set a property of an object
// in a nunjucks template, and we generate the id there. You are responsible for
// supplying a div with that id and a suitable width and height

var AposGoogleMap = function(items, id, mapOptions) {
  if (!window.google) {
    apos.log('google maps is not available in the build! Maybe you are running with offline: true in local.js, in which case this is normal.');
    return;
  }
  var self = this;

  // For points not geocoded server side
  var geocoder = new google.maps.Geocoder();

  var mapZoom;
  var mapCenter;

  self.filterBy = mapOptions.filterBy || 'all';

  function filter(filterBy) {
    console.log(filterBy);
    self.filterBy = filterBy;
    forEachItem(function(item) {
      ifMappable(item, function(item) {
        if (item.infoBox) {
          item.infoBox.close();
        }
        item.marker.setVisible(false);
      });
    });
    forEachItem(function(item) {
      ifFiltered(item, function(item) {
        item.marker.setVisible(true);
      });
    });
    if (filterBy == 'all') {
      resetZoom();
      resetCenter();
    } else {
      autoZoom();
      autoCenter();
    }
  }

  function forEachItem(iterator) {
    for (var i in self.items) {
      iterator(self.items[i]);
    }
  }

  function ifMappable(item, callback) {
    if (item.geo) {
      return callback(item);
    }
  }

  function ifFiltered(item, callback) {
    ifMappable(item, function(item) {
      if (self.filterBy === 'all') {
        return callback(item);
      } else {
        var filterBy = (_.isArray(self.filterBy)) ? self.filterBy : [self.filterBy];
        var marker = item.marker;
        if( _.intersection(self.filterBy, item.tags).length ) {
          return callback(item);
        }
      }
    });
  }

  function autoCenter() {
    var valid = 0;
    var lat = 0.0;
    var lng = 0.0;
    forEachItem(function(item) {
      ifMappable(item, function(item) {
        ifFiltered(item, function(item) {
          lat += item.geo.coordinates[1];
          lng += item.geo.coordinates[0];
          valid++;
        });
      });
    });
    var mapCenter;
    if (valid) {
      mapCenter = new google.maps.LatLng(lat / valid, lng / valid);
    } else {
      mapCenter = new google.maps.LatLng(39.952335, -75.163789);
    }
    self.map.setCenter(mapCenter);
  }

  function autoZoom() {
    var bounds;
    // Auto-zoom
    bounds = new google.maps.LatLngBounds();
    var count = 0;
    forEachItem(function(item) {
      ifMappable(item, function(item) {
        ifFiltered(item, function(item) {
          count++;
          bounds.extend(new google.maps.LatLng(item.geo.coordinates[1], item.geo.coordinates[0]));
        });
      });
    });
    if (count > 1) {
      self.map.fitBounds(bounds);
    } else if (count === 1) {
      self.map.setZoom(15);
    }
  }

  // Revert to whatever we had initially (for filtering by "all")
  function resetZoom() {
    if (mapZoom) {
      self.map.setZoom(mapZoom);
    } else {
      autoZoom();
    }
  }

  function resetCenter() {
    if (mapCenter) {
      self.map.setCenter(mapCenter);
    } else {
      autoCenter();
    }
  }

  self.items = items;
  self.mapOptions = mapOptions;

  // Why is this useful? (It's called once but just invokes its callback.)
  self.setup = function(callback) {
    callback();
  };

  // set up the actual map. This works asynchronously if needed to
  // geocode addresses browser-side

  self.googleMap = function() {

    // Geocode an item if needed
    function geocodeOne(i, callback) {
      var item = self.items[i];
      if ((!item.geo) && (item.address)) {
        geocoder.geocode( { 'address': self.items[i].address }, function(results, status) {
          if (status == google.maps.GeocoderStatus.OK) {
            item.geo = {
              type: 'Point',
              coordinates: [ results[0].geometry.location.lng(), results[0].geometry.location.lat() ]
            };
            return callback();
          } else {
            return callback();
          }
        });
      } else {
        return callback();
      }
    }

    // Simple async for loop to geocode them all, then invoke 'go'
    var i = 0;
    function geocodeNext() {
      if (i >= self.items.length) {
        return go();
      }
      return geocodeOne(i, function() {
        i++;
        return geocodeNext();
      });
    }

    geocodeNext();

    // Called once we're ready with all of our points
    function go() {
      var lat = 0.0;
      var lng = 0.0;
      if (self.mapOptions.center) {
        var center = self.mapOptions.center;
        mapCenter = new google.maps.LatLng(center.lat, center.lng);
      }

      mapZoom = self.mapOptions.zoom;
      var $mapEl = $('#' + id);
      // For easier targeting
      $mapEl.addClass('apos-map');
      var mapEl = $mapEl[0];

      // reasonable defaults for zoom and center until autoZoom or autoCenter can run
      var zoom = mapZoom || 12;

      var teaser = self.mapOptions.teaser;
      var map = new google.maps.Map(mapEl, {
        minZoom: teaser ? zoom : 0,
        maxZoom: teaser ? zoom : 100,
        zoom: zoom,
        panControl: !teaser,
        zoomControl: !teaser,
        scaleControl: !teaser,
        draggable: !teaser,
        streetViewControl: !teaser,
        center: mapCenter || new google.maps.LatLng(39.952335, -75.163789),
        mapTypeId: google.maps.MapTypeId.ROADMAP
      });

      if (self.mapOptions.teaser) {
        $(mapEl).css('cursor', 'pointer');
      }

      // teaser option: this display of the map is just a teaser to take
      // you to a more suitable page. Helps avoid overhead and scrolling
      // frustration when a map is full width on the homepage
      if (self.mapOptions.teaser) {
        google.maps.event.addListener(map, 'click', function() {
          // document.body.style.cursor = 'wait';
          window.location.href = self.mapOptions.teaser;
        });
      }

      self.map = map;

      var mapStyles = self.mapOptions.styles;

      if(mapStyles) map.setOptions({styles:mapStyles});

      map.setOptions({scrollwheel: false, mapTypeControl: false});

      // loop through the items getting passed in from our template
      // and create a marker / info box for each. To avoid convoluted
      // code just call a nested function in a loop and pass it 'i' so that
      // it's safe to write boring, simple event handlers there that use 'i'

      forEachItem(setUpItem);

      if (!mapZoom) {
        autoZoom();
      }
      if (!mapCenter) {
        autoCenter();
      }

      function setUpItem(item) {
        if (!item.geo) {
          // Ignore ungeocoded points
          return;
        }
        self.generateMarker(item, self.map);

        var selector = '.apos-location[data-location-id="' + item._id + '"]';
        $('.apos-location[data-location-id="' + item._id + '"]').click(function() {
          self.activateInfoBox(item);
          return false;
        });
        // attach a click listener to the marker that opens our info box
        if ((!mapOptions.teaser) && (!mapOptions.noBox)) {
          google.maps.event.addListener(item.marker, 'click', function() {
            self.activateInfoBox(item);
          });
        }
      }

      // Create a jQuery event that can be used to filter by
      // a particular tag or 'all'
      $(mapEl).on('filter', function(e) {
        // grab any arguments after the first (the event object),
        // which represent one or more tags to filter by.
        // we need to do this because calling .trigger('filter', Array)
        // passes the array items as arguments, instead of as an array.
        var filterBy = Array.prototype.slice.call(arguments, 1);
        // if the only argument supplied is the string "all",
        // pass it through as a string.
        if(filterBy.length == 1 && filterBy[0] == 'all') {
          filterBy = 'all';
        }
        return filter(filterBy);
      });
    }
  };

  self.activateInfoBox = function(item) {
    // for BC purposes, if an item has no `showInfoBox` property we'll fall
    // back on the old method of only showing an infoBox when there is no
    // body content.
    if ( ((item.showInfoBox === undefined || item.showInfoBox === null) && !item.descr) || item.showInfoBox === false) {
      // No info boxes for items without rich content, such as those
      // supplied for a plain street address associated with an event
      return;
    }
    forEachItem(function(item) {
      if (item.infoBox) {
        item.infoBox.close();
      }
      if (item.marker) {
        item.marker.content.firstChild.className = item.marker.content.firstChild.className.replace(' active', '');
      }
    });
    if (!item.infoBox) {
      self.generateInfoBox(item, self.map);
    }
    item.infoBox.open(self.map, item.marker);
    item.marker.content.firstChild.className += " active";
  };

  // Find the locType mentioned first in the tags of the item, otherwise
  // the first one defined, otherwise 'general'

  self.getLocType = function(item) {
    // This information was pushed into browserland with apos.pushGlobalData
    var locTypes = apos.data.aposMap.locTypes;
    var locTypeTag = _.find(item.tags || [], function(tag) {
      return _.find(locTypes, function(locType) {
        return locType.value === tag;
      });
    });
    var locType;
    if (locTypeTag) {
      locType = _.find(locTypes, function(locType) {
        return locType.value === locTypeTag;
      });
    }
    if (!locType) {
      locType = locTypes[0];
    }
    if (!locType) {
      locType = { value: 'general', label: 'General' };
    }
    return locType;
  };

  // Return a CSS-friendly version of the locType name

  self.getCssClass = function(item) {
    return apos.cssName(self.getLocType(item).value);
  };

  self.generateMarker = function(item, map)
  {
    var markerHTML = document.createElement('DIV');
        markerHTML.innerHTML = '

';

    var coords;
    // If the address is already a coordinate pair ignore any geocoding result and use it directly
    if (item.address.match(/^[\-\+0-9\.\,\ ]+$/)) {
      var rawCoords = item.address.split(/,\s*/);
      coords = new google.maps.LatLng(parseFloat(rawCoords[0]), parseFloat(rawCoords[1]));
    } else {
      coords = new google.maps.LatLng(item.geo.coordinates[1], item.geo.coordinates[0]);
    }

    var marker = new RichMarker({
      position: coords,
      draggable: false,
      visible: true,
      clickable: true,
      map: map,
      content: markerHTML
    });

    marker.locTypes = item.tags;
    item.marker = marker;
  };

  // IMPORTANT: if you want more properties to be visible here, make sure
  // you override the aposMapPruneLocations function to include them.
  // You can do that in your server-side extension of the map module.
  // See map/index.js for the original. Pruning is necessary to avoid
  // sending a zillion megabytes per page to the browser

  self.generateInfoBox = function(item, map) {
    var $box = apos.fromTemplate('.apos-map-location-info-box');

    var image = apos.getFirstImage(item, 'thumbnail');
    if (image) {
      var url = apos.filePath(image, { size: 'one-third' });
      $box.find('[data-image]').attr('src', url);
    } else {
      // Don't show a broken image
      $box.find('[data-image]').remove();
      $box.addClass('no-img');
    }
    $box.find('[data-loc-type]').text(item.locType);
    $box.find('[data-title]').text(item.title);
    // Do not show the "address" if it is actually a lat,long coordinate pair
    var $address = $box.find('[data-address]');
    if (!item.address.match(/^[\-\+0-9\.\,\ ]+$/)) {
      $address.text(item.address);
    } else {
      $address.hide();
    }
    $box.find('[data-descr]').text(item.descr);
    // $box.find('[data-hours]').text(item.hours);
    if (item.url) {
      $box.find('[data-url]').attr('href', item.url);
    }

    var boxOptions = {
      // Wants the actual DOM element, not jQuery
      content: $box[0],
      disableAutoPan: false,
      pixelOffset: new google.maps.Size(10,-137),
      boxStyle: {
        width: "280px"
       },
      closeBoxMargin: "0px 0px 0px 0px",
      closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif",
      infoBoxClearance: new google.maps.Size(1, 1),
      pane: "floatPane",
      enableEventPropagation: false
    };

    item.infoBox = new InfoBox(boxOptions);
  };

  //call setup and feed it the google map load listener
  self.setup(function() {
    $(function() {
      self.googleMap();
    });
  });
};
<|endoftext|>


<commit_before>import path from 'path';
import dotenv from 'dotenv';
import Config from '../libs/Config';
import * as middlewares from '../middlewares';

dotenv.config();

process.env.NODE_ENV = process.env.NODE_ENV || 'development';

const config = new Config({ envPrefix: 'OORS_SERVER_CONFIG' });

config.add({
  rootDir: '',
  rootURL: config.ref(() => `http://${config.get('hostname')}:${config.get('port')}`),
  isDev: process.env.NODE_ENV === 'development',
  port: 3000,
  hostname: 'localhost',
  cookieSecret: 'THIS_IS_MY_SECRET',
  modules: {
    'oors.express': {
      middlewares: config.ref(() => [
        middlewares.cors,
        middlewares.useragent,
        middlewares.helmet,
        {
          ...middlewares.morgan,
          params: 'dev',
          enabled: config.get('isDev'),
        },
        {
          ...middlewares.compression,
          enabled: !config.get('isDev'),
        },
        {
          ...middlewares.bodyParserJSON,
          params: { limit: '20mb' },
        },
        middlewares.bodyParserURLEncoded,
        {
          ...middlewares.cookieParser,
          params: {
            secret: config.get('cookieSecret'),
          },
        },
        {
          ...middlewares.session,
          params: {
            secret: config.get('cookieSecret'),
            resave: false,
            saveUninitialized: true,
          },
        },
        middlewares.isMethod,
        middlewares.validationErrorHandler,
        {
          ...middlewares.boomErrorHandler,
          params: {
            isDev: config.get('isDev'),
          },
        },
        {
          ...middlewares.errorHandler,
          params: {
            isDev: config.get('isDev'),
          },
        },
      ]),
    },
    'oors.rad': {
      autoload: {
        services: true,
        methods: true,
      },
    },
    'oors.mongodb': {
      connections: [
        {
          name: 'default',
          url: 'mongodb://localhost:27017/oors',
        },
      ],
      logQueries: config.ref('isDev'),
      migrationsDir: config.ref(() => path.resolve(config.get('rootDir'), './migrations')),
      addTimestamps: true,
      autoloadRepositories: false,
    },
    'oors.user': {
      rootURL: config.ref('rootURL'),
      jwtSecret: 'MY_JWT_SECRET',
      jwtConfig: {
        expiresIn: '1d',
      },
      mockUserMiddlewarePivot: {
        before: 'apolloServer',
      },
      passportMiddlewarePivot: {
        after: 'cookieParser',
      },
      jwtMiddlewarePivot: {
        before: 'apolloServer',
      },
      mockUserConfig: {
        enabled: false,
        path: '/graphql',
        params: {}, // no params means an empty query - just load any db user
      },
      passportConfig: {
        enabled: false,
      },
    },
    'oors.mailer': {
      transport: {
        jsonTransport: true,
      },
      saveToDisk: true,
      emailsDir: config.ref(() => path.resolve(config.get('rootDir'), './emails')),
      templatesDir: '',
      middlewarePivot: {
        before: 'isMethod',
      },
    },
    'oors.upload': {
      uploadDir: config.ref(() => path.resolve(config.get('rootDir'), './uploads')),
    },
    'oors.graphql': {
      serverOptions: {
        introspection: config.ref('isDev'),
      },
    },
    'oors.router': {
      middlewarePivot: {
        after: 'isMethod',
      },
    },
    'oors.logger': {
      logsDir: config.ref(() => path.resolve(config.get('rootDir'), './logs')),
    },
    'oors.cache': {
      defaultCache: {
        name: 'cache',
        options: {},
      },
    },
  },
});

export default config;
<commit_msg>better session configuration<commit_after>import path from 'path';
import dotenv from 'dotenv';
import Config from '../libs/Config';
import * as middlewares from '../middlewares';

dotenv.config();

process.env.NODE_ENV = process.env.NODE_ENV || 'development';

const config = new Config({ envPrefix: 'OORS_SERVER_CONFIG' });

config.add({
  rootDir: '',
  rootURL: config.ref(() => `http://${config.get('hostname')}:${config.get('port')}`),
  isDev: process.env.NODE_ENV === 'development',
  port: 3000,
  hostname: 'localhost',
  cookieSecret: 'THIS_IS_MY_SECRET',
  modules: {
    'oors.express': {
      middlewares: config.ref(() => [
        middlewares.cors,
        middlewares.useragent,
        middlewares.helmet,
        {
          ...middlewares.morgan,
          params: 'dev',
          enabled: config.get('isDev'),
        },
        {
          ...middlewares.compression,
          enabled: !config.get('isDev'),
        },
        {
          ...middlewares.bodyParserJSON,
          params: { limit: '20mb' },
        },
        middlewares.bodyParserURLEncoded,
        {
          ...middlewares.cookieParser,
          params: {
            secret: config.get('cookieSecret'),
          },
        },
        {
          ...middlewares.session,
          params: {
            secret: config.get('cookieSecret'),
            resave: false,
            saveUninitialized: false,
          },
        },
        middlewares.isMethod,
        middlewares.validationErrorHandler,
        {
          ...middlewares.boomErrorHandler,
          params: {
            isDev: config.get('isDev'),
          },
        },
        {
          ...middlewares.errorHandler,
          params: {
            isDev: config.get('isDev'),
          },
        },
      ]),
    },
    'oors.rad': {
      autoload: {
        services: true,
        methods: true,
      },
    },
    'oors.mongodb': {
      connections: [
        {
          name: 'default',
          url: 'mongodb://localhost:27017/oors',
        },
      ],
      logQueries: config.ref('isDev'),
      migrationsDir: config.ref(() => path.resolve(config.get('rootDir'), './migrations')),
      addTimestamps: true,
      autoloadRepositories: false,
    },
    'oors.user': {
      rootURL: config.ref('rootURL'),
      jwtSecret: 'MY_JWT_SECRET',
      jwtConfig: {
        expiresIn: '1d',
      },
      mockUserMiddlewarePivot: {
        before: 'apolloServer',
      },
      passportMiddlewarePivot: {
        after: 'cookieParser',
      },
      jwtMiddlewarePivot: {
        before: 'apolloServer',
      },
      mockUserConfig: {
        enabled: false,
        path: '/graphql',
        params: {}, // no params means an empty query - just load any db user
      },
      passportConfig: {
        enabled: false,
      },
    },
    'oors.mailer': {
      transport: {
        jsonTransport: true,
      },
      saveToDisk: true,
      emailsDir: config.ref(() => path.resolve(config.get('rootDir'), './emails')),
      templatesDir: '',
      middlewarePivot: {
        before: 'isMethod',
      },
    },
    'oors.upload': {
      uploadDir: config.ref(() => path.resolve(config.get('rootDir'), './uploads')),
    },
    'oors.graphql': {
      serverOptions: {
        introspection: config.ref('isDev'),
      },
    },
    'oors.router': {
      middlewarePivot: {
        after: 'isMethod',
      },
    },
    'oors.logger': {
      logsDir: config.ref(() => path.resolve(config.get('rootDir'), './logs')),
    },
    'oors.cache': {
      defaultCache: {
        name: 'cache',
        options: {},
      },
    },
  },
});

export default config;
<|endoftext|>