<commit_before>var features = {};

features.eatApple = function(person, apples) {
  score++;
  apples.kill();

  if (score === MAX_SCORE) {
    features.gameOver("Player 1");
  }
}

features.cherry = function(person, cherry) {
  cherry.kill();
  person.cherry = true;
  setTimeout(function(){person.cherry = false}, 5000);
}

features.speedUp = function(character, speedUp) {
  speedUp.kill();
  character.speedMultiplyer = 1.5;
  setTimeout(function(){character.speedMultiplyer = 1}, 5000);
}

features.slowDown = function(character, slowDown) {
  slowDown.kill();
  character.speedMultiplyer = 0.5;
  setTimeout(function(){character.speedMultiplyer = 1}, 5000);
}

features.teleportOne = function(person, starOne) {
  person.kill();
  person.reset(790,353);
  person.body.velocity.x = -200;
};

features.teleportTwo = function(person, starTwo) {
  person.kill();
  person.reset(40,353);
  person.body.velocity.x = 200;
};

features.pacMeetsGhost = function(person, ghost) {
  if (person.cherry === true){
    features.eatGhost(person, ghost);
  }
  else {
    features.loseLife(person, ghost);
  }
}

features.eatGhost = function(person, ghost) {
  ghost.kill();
  ghost.reset(Math.random() * CANVAS_WIDTH, Math.random() * CANVAS_HEIGHT);
};

features.loseLife = function(person) {
  lives--;
  person.kill();

  if (lives === 0) {
    features.gameOver("Player 2");
  } else {
    person.reset(CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2);
  }
};

features.gameOver = function(winner) {
  alert("Game Over. " + winner + " wins!");
  location.reload();
};
<commit_msg>attempt to reset after game over<commit_after>var features = {};

features.eatApple = function(person, apples) {
  score++;
  apples.kill();

  if (score === MAX_SCORE) {
    features.gameOver("Player 1");
  }
}

features.cherry = function(person, cherry) {
  cherry.kill();
  person.cherry = true;
  setTimeout(function(){person.cherry = false}, 5000);
}

features.speedUp = function(character, speedUp) {
  speedUp.kill();
  character.speedMultiplyer = 1.5;
  setTimeout(function(){character.speedMultiplyer = 1}, 5000);
}

features.slowDown = function(character, slowDown) {
  slowDown.kill();
  character.speedMultiplyer = 0.5;
  setTimeout(function(){character.speedMultiplyer = 1}, 5000);
}

features.teleportOne = function(person, starOne) {
  person.kill();
  person.reset(790,353);
  person.body.velocity.x = -200;
};

features.teleportTwo = function(person, starTwo) {
  person.kill();
  person.reset(40,353);
  person.body.velocity.x = 200;
};

features.pacMeetsGhost = function(person, ghost) {
  if (person.cherry === true){
    features.eatGhost(person, ghost);
  }
  else {
    features.loseLife(person, ghost);
  }
}

features.eatGhost = function(person, ghost) {
  ghost.kill();
  ghost.reset(Math.random() * CANVAS_WIDTH, Math.random() * CANVAS_HEIGHT);
};

features.loseLife = function(person) {
  lives--;
  person.kill();

  if (lives === 0) {
    features.gameOver("Player 2");
  } else {
    person.reset(CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2);
  }
};

features.gameOver = function(winner) {
  features.reset();
  alert("Game Over. " + winner + " wins!");
  location.reload();
};

features.reset = function() {
  fb.ghost.set({
    x : Math.random() * CANVAS_WIDTH,
    y : Math.random() * CANVAS_HEIGHT
  });

  fb.person.set({
    x : Math.random() * CANVAS_WIDTH,
    y : Math.random() * CANVAS_HEIGHT
  });

  fb.pause.set(true);
  fb.player1.set(true);
  fb.player2.set(true);
}
<|endoftext|>


<commit_before>import Constants from 'expo-constants';
import * as Linking from 'expo-linking';
import * as MailComposer from 'expo-mail-composer';
import * as SecureStorage from 'expo-secure-store';
import React from 'react';
import config from './config';

export function useMounted() {
  const isMounted = React.useRef(true);
  React.useEffect(() => {
    return () => {
      isMounted.current = false;
    };
  }, []);
  return isMounted;
}

export function useSecureState(key) {
  // state will be undefined until is has been initialized,
  // then it will be the value or null
  const [state, setInternalState] = React.useState();

  React.useEffect(() => {
    const init = async () => {
      const value = await SecureStorage.getItemAsync(key);

      try {
        setInternalState(JSON.parse(value));
      } catch (e) {
        setInternalState(value);
      }
    };

    init();
  }, []);

  const setState = (value) => {
    // value could be string or object
    setInternalState(value);
    SecureStorage.setItemAsync(key, typeof value === 'object' ? JSON.stringify(value) : value);
  };

  return [state, setState];
}

// https://github.com/facebook/react/issues/14981#issuecomment-468460187
export function useAsyncError() {
  const [_, setError] = React.useState(null);
  const throwAsyncError = React.useCallback(
    (error) => {
      setError(() => {
        throw error;
      });
    },
    [setError]
  );

  return throwAsyncError;
}

export function isTokenExpired(token) {
  if (typeof token === 'string') {
    throw new Error('token must be an object, did you forget to decode it?');
  }

  if (!token?.exp) {
    return true;
  }

  const expireTime = token.exp * 1000;

  return expireTime < Date.now();
}

export async function clearStorage() {
  await SecureStorage.deleteItemAsync(config.USER_STORE_KEY);
  await SecureStorage.deleteItemAsync(config.USER_TYPE_KEY);
}

export async function sendEmailToSupport() {
  const subject = `${Constants.manifest.name} - Support`;

  if (await MailComposer.isAvailableAsync()) {
    return await MailComposer.composeAsync({
      subject,
      recipients: [config.SUPPORT_EMAIL],
    });
  }

  Linking.openURL(`mailto:${config.SUPPORT_EMAIL}`);
}

export function wrapAsyncWithDelay(action, preAction, postAction, delay) {
  const timeoutHandler = setTimeout(() => {
    console.log('preAction');
    preAction();
  }, delay);
  const applyPostAction = () => {
    console.log('postAction');
    clearTimeout(timeoutHandler);
    postAction();
  };

  return action().catch(applyPostAction).finally(applyPostAction);
}
<commit_msg>chore(front): remove unnecessary log statements<commit_after>import Constants from 'expo-constants';
import * as Linking from 'expo-linking';
import * as MailComposer from 'expo-mail-composer';
import * as SecureStorage from 'expo-secure-store';
import React from 'react';
import config from './config';

export function useMounted() {
  const isMounted = React.useRef(true);
  React.useEffect(() => {
    return () => {
      isMounted.current = false;
    };
  }, []);
  return isMounted;
}

export function useSecureState(key) {
  // state will be undefined until is has been initialized,
  // then it will be the value or null
  const [state, setInternalState] = React.useState();

  React.useEffect(() => {
    const init = async () => {
      const value = await SecureStorage.getItemAsync(key);

      try {
        setInternalState(JSON.parse(value));
      } catch (e) {
        setInternalState(value);
      }
    };

    init();
  }, []);

  const setState = (value) => {
    // value could be string or object
    setInternalState(value);
    SecureStorage.setItemAsync(key, typeof value === 'object' ? JSON.stringify(value) : value);
  };

  return [state, setState];
}

// https://github.com/facebook/react/issues/14981#issuecomment-468460187
export function useAsyncError() {
  const [_, setError] = React.useState(null);
  const throwAsyncError = React.useCallback(
    (error) => {
      setError(() => {
        throw error;
      });
    },
    [setError]
  );

  return throwAsyncError;
}

export function isTokenExpired(token) {
  if (typeof token === 'string') {
    throw new Error('token must be an object, did you forget to decode it?');
  }

  if (!token?.exp) {
    return true;
  }

  const expireTime = token.exp * 1000;

  return expireTime < Date.now();
}

export async function clearStorage() {
  await SecureStorage.deleteItemAsync(config.USER_STORE_KEY);
  await SecureStorage.deleteItemAsync(config.USER_TYPE_KEY);
}

export async function sendEmailToSupport() {
  const subject = `${Constants.manifest.name} - Support`;

  if (await MailComposer.isAvailableAsync()) {
    return await MailComposer.composeAsync({
      subject,
      recipients: [config.SUPPORT_EMAIL],
    });
  }

  Linking.openURL(`mailto:${config.SUPPORT_EMAIL}`);
}

export function wrapAsyncWithDelay(action, preAction, postAction, delay) {
  const timeoutHandler = setTimeout(() => {
    preAction();
  }, delay);
  const applyPostAction = () => {
    clearTimeout(timeoutHandler);
    postAction();
  };

  return action().catch(applyPostAction).finally(applyPostAction);
}
<|endoftext|>


<commit_before>var keystone = require('keystone'),
	Types = keystone.Field.Types;

// Create model
var Child = new keystone.List('Child', {
	track: true,
	autokey: { path: 'key', from: 'registrationNumber', unique: true },
	map: { name: 'name.full' },
	defaultSort: 'name.full'
});

// Create fields
Child.add('Display Options', {

	siteVisibility: { type: Types.Select, label: 'child is visible to', options: 'everyone, registered social workers and families', required: true, initial: true }

}, 'Child Information', {

	registrationNumber: { type: Number, label: 'registration number', format: false, required: true, initial: true },
	registrationDate: { type: Types.Date, label: 'registration date', format: 'MM/DD/YYYY', required: true, initial: true },

	video: { type: Types.Url, label: 'Video' },

	name: {
		first: { type: Types.Text, label: 'first name', required: true, initial: true },
		middle: { type: Types.Text, label: 'middle name', initial: true },
		last: { type: Types.Text, label: 'last name', required: true, initial: true },
		alias: { type: Types.Text, label: 'alias', initial: true },
		nickName: { type: Types.Text, label: 'nickname', initial: true },
		full: { type: Types.Text, label: 'name', hidden: true, noedit: true, initial: false }
	},

	birthDate: { type: Types.Date, label: 'date of birth', format: 'MM/DD/YYYY', required: true, initial: true },
	language: { type: Types.Relationship, label: 'language', ref: 'Language', many: true, required: true, initial: true },
	statusChangeDate: { type: Types.Date, label: 'status change date', format: 'MM/DD/YYYY', initial: true }, // TODO: Logic needed, see line 14 of https://docs.google.com/spreadsheets/d/1Opb9qziX2enTehJx5K1J9KAT7v-j2yAdqwyQUMSsFwc/edit#gid=1235141373
	status: { type: Types.Relationship, label: 'status', ref: 'Child Status', required: true, initial: true },
	gender: { type: Types.Relationship, label: 'gender', ref: 'Gender', required: true, initial: true },
	race: { type: Types.Relationship, label: 'race', ref: 'Race', many: true, required: true, initial: true },
	legalStatus: { type: Types.Relationship, label: 'legal status', ref: 'Legal Status', required: true, initial: true },
	yearEnteredCare: { type: Types.Text, label: 'year entered care', note: 'yyyy', initial: true },

	hasContactWithSiblings: { type: Types.Boolean, label: 'has contact with siblings?', initial: true },
	siblingTypeOfContact: { type: Types.Text, label: 'type of contact', initial: true },
	siblingContacts: { type: Types.Relationship, label: 'siblings to be placed together (comma separated)', ref: 'Child', many: true, initial: true },
	hasContactWithBirthFamily: { type: Types.Boolean, label: 'has contact with birth family?', initial: true },
	birthFamilyTypeOfContact: { type: Types.Text, label: 'type of contact', initial: true },

	residence: { type: Types.Relationship, label: 'where does the child presently live?', ref: 'Residence', initial: true },
	city: { type: Types.Relationship, label: 'city/town of child\'s current location', ref: 'City or Town', initial: true },
	careFacilityName: { type: Types.Text, label: 'name of residential/group care facility', initial: true },
	dateMovedToResidence: { type: Types.Date, label: 'date moved to current residence', format: 'MM/DD/YYYY', required: true, initial: true }

}, 'Special Needs', {

	physicalNeeds: { type: Types.Select, label: 'physical needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	physicalNeedsDescription: { type: Types.Textarea, label: 'description of physical needs', dependsOn: { physicalNeeds: ['mild', 'moderate', 'severe'] }, initial: true },
	emotionalNeeds: { type: Types.Select, label: 'emotional needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	emotionalNeedsDescription: { type: Types.Textarea, label: 'description of emotional needs', dependsOn: { emotionalNeeds: ['mild', 'moderate', 'severe'] }, initial: true },
	intellectualNeeds: { type: Types.Select, label: 'intellectual needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	intellectualNeedsDescription: { type: Types.Textarea, label: 'description of intellectual needs', dependsOn: { intellectualNeeds: ['mild', 'moderate', 'severe'] }, initial: true },

	disabilities: { type: Types.Relationship, label: 'disabilities', ref: 'Disability', many: true, initial: true },

	specialNeedsNotes: { type: Types.Textarea, label: 'notes', dependsOn: { physicalNeeds: ['mild', 'moderate', 'severe'], emotionalNeeds: ['mild', 'moderate', 'severe'], intellectualNeeds: ['mild', 'moderate', 'severe'] }, initial: true }

}, 'Placement Considerations', {

	recommendedFamilyConstellation: { type: Types.Relationship, label: 'recommended family constellations', ref: 'Family Constellation', many: true, required: true, initial: true },
	otherFamilyConstellationConsideration: { type: Types.Relationship, label: 'other family constellation consideration', ref: 'Other Family Constellation Consideration', many: true, initial: true },
	otherConsiderations: { type: Types.Relationship, label: 'other considerations', ref: 'Other Consideration', many: true, initial: true }

}, 'Agency Information', {

	registeredBy: { type: Types.Select, label: 'registered by', options: 'unknown, adoption worker, recruitment worker', required: true, initial: true },
	adoptionWorker: { type: Types.Relationship, label: 'adoption worker', ref: 'Social Worker', filters: { position: 'adoption worker' }, initial: true },
	recruitmentWorker: { type: Types.Relationship, label: 'recruitment worker', ref: 'Social Worker', filters: { position: 'recruitment worker' }, initial: true },
	region: { type: Types.Relationship, label: 'region', ref: 'Region', initial: true }

}, 'Photolisting Information', {

	profile: {
		part1: { type: Types.Textarea, label: 'let me tell you more about myself...', required: true, initial: true },
		part2: { type: Types.Textarea, label: 'and here\'s what others say...', required: true, initial: true },
		part3: { type: Types.Textarea, label: 'if I could have my own special wish...', required: true, initial: true }
	},

	hasPhotolistingWriteup: { type: Types.Boolean, label: 'photolisting writeup', initial: true },
	photolistingWriteupDate: { type: Types.Date, label: 'date of photolisting writeup', format: 'MM/DD/YYYY', dependsOn: { hasPhotolistingWriteup: true }, initial: true },
	hasPhotolistingPhoto: { type: Types.Boolean, label: 'photolisting photo', initial: true },
	photolistingPhotoDate: { type: Types.Date, label: 'date of photolisting photo', format: 'MM/DD/YYYY', dependsOn: { hasPhotolistingPhoto: true }, initial: true },
	photolistingPageNumber: { type: Number, label: 'photolisting page', format: false, initial: true },
	previousPhotolistingPageNumber: { type: Number, label: 'previous photolisting page', format: false, initial: true },

	image: { type: Types.CloudinaryImage, folder: 'children/', selectPrefix: 'children/', publicID: 'fileName', autoCleanup: true },
	galleryImage: {type: Types.Url, hidden: true },
	detailImage: {type: Types.Url, hidden: true },
	extranetUrl: { type: Types.Url, label: 'extranet and related profile url', initial: true } // Since this is redudant as this just points the the url where the photo exists (the child's page), we may hide this field.  This must be kept in as it will help us track down the child information in the old system in the event of an issue.

}, 'Recruitment Options', {

	hasVideoSnapshot: { type: Types.Boolean, label: 'video snapshot', initial: true },
	videoSnapshotDate: { type: Types.Date, label: 'date of video snapshot', format: 'MM/DD/YYYY', dependsOn: { hasVideoSnapshot: true }, initial: true },

	onMAREWebsite: { type: Types.Boolean, label: 'MARE website', initial: true },
	onMAREWebsiteDate: { type: Types.Date, label: 'date on MARE website', format: 'MM/DD/YYYY', dependsOn: { onMAREWebsite: true }, initial: true },

	onAdoptuskids: { type: Types.Boolean, label: 'Adoptuskids website', initial: true },
	onAdoptuskidsDate: { type: Types.Date, label: 'date on Adoptuskids', format: 'MM/DD/YYYY', dependsOn: { onAdoptuskids: true }, initial: true },

	onOnlineMatching: { type: Types.Boolean, label: 'online matching website', initial: true },
	onOnlineMatchingDate: { type: Types.Date, label: 'date on online matching', format: 'MM/DD/YYYY', dependsOn: { onOnlineMatching: true }, initial: true },

	wednesdaysChild: { type: Types.Boolean, label: 'Wednesday\'s Child?', initial: true },
	wednesdaysChildDate: { type: Types.Date, label: 'date of Wednesday\'s Child', format: 'MM/DD/YYYY', dependsOn: { wednesdaysChild: true }, initial: true },

	coalitionMeeting: { type: Types.Boolean, label: 'coalition meeting', initial: true },
	coalitionMeetingDate: { type: Types.Date, label: 'date of coalition meeting', format: 'MM/DD/YYYY', dependsOn: { coalitionMeeting: true }, initial: true },

	matchingEvent: { type: Types.Boolean, label: 'matching event', initial: true },
	matchingEventDate: { type: Types.Date, label: 'date of matching event', format: 'MM/DD/YYYY', dependsOn: { matchingEvent: true }, initial: true },

	adoptionParties: { type: Types.Relationship, label: 'adoption parties', ref: 'Event', filters: { type: 'adoption party' }, many: true, initial: true },

	mediaEligibility: { type: Types.Relationship, label: 'media eligibility', ref: 'Media Eligibility', many: true, initial: true },
	otherMediaDescription: { type: Types.Textarea, label: 'description', dependsOn: { mediaEligibility: 'Other' }, initial: true } // THIS DOESN'T WORK, MAKE IT WORK!

}, 'Attachments', {

	photolistingPage: {
		type: Types.S3File,
		s3path: '/child/photolisting-pages',
		filename: function(item, filename){
			// prefix file name with registration number and the user's name for easier identification
			return fileName;
		}
	},

	otherAttachement: {
		type: Types.S3File,
		s3path: '/child/other',
		filename: function(item, filename){
			// prefix file name with registration number and name for easier identification
			return fileName;
		}
	}
/* Container for all system fields (add a heading if any are meant to be visible through the admin UI) */
}, {

	// system field to store an appropriate file prefix
	fileName: { type: Types.Text, hidden: true }

});

// Set up relationship values to show up at the bottom of the model if any exist
Child.relationship({ ref: 'Child', refPath: 'siblingContacts', path: 'children', label: 'children' });
// Child.relationship({ path: 'siblings', ref: 'Sibling', refPath: 'child1' });
Child.relationship({ ref: 'Placement', refPath: 'child', path: 'placements', label: 'placements' });
Child.relationship({ ref: 'Inquiry', refPath: 'child', path: 'inquiries', label: 'inquiries' });
Child.relationship({ ref: 'Family', refPath: 'bookmarkedChildren', path: 'families', label: 'bookmarked by families' });
Child.relationship({ ref: 'Social Worker', refPath: 'bookmarkedChildren', path: 'social-workers', label: 'bookmarked by social workers' });
Child.relationship({ ref: 'Event', refPath: 'childAttendees', path: 'events', label: 'events' });
Child.relationship({ ref: 'Internal Note', refPath: 'child', path: 'internal-notes', label: 'internal notes' });

// Pre Save
Child.schema.pre('save', function(next) {
	'use strict';

	// TODO: Play with lowering quality to 0 and doubling the image size as an optimization technique
	this.galleryImage = this._.image.thumbnail(430,430,{ quality: 60 });
	this.detailImage = this._.image.thumbnail(200,200,{ quality: 60 });

	// Build the name string for better identification when linking through Relationship field types
	var firstName	= this.name.first,
		middleName	= (this.name.middle && this.name.middle.length > 0) ? ' ' + this.name.middle : '',
		lastName	= (this.name.last && this.name.last.length > 0) ? ' ' + this.name.last : ''

	this.name.full = firstName + middleName + lastName;
	// Create an identifying name for file uploads
	this.fileName = this.registrationNumber + '_' + this.name.first.toLowerCase();

	// TODO: Assign a registration number if one isn't assigned
	next();
});

// Define default columns in the admin interface and register the model
Child.defaultColumns = 'registrationNumber, name.full, ethnicity, legalStatus, gender';
Child.register();
<commit_msg>#35 | add new fields to the child model<commit_after>var keystone = require('keystone'),
	Types = keystone.Field.Types;

// Create model
var Child = new keystone.List('Child', {
	track: true,
	autokey: { path: 'key', from: 'registrationNumber', unique: true },
	map: { name: 'name.full' },
	defaultSort: 'name.full'
});

// Create fields
Child.add('Display Options', {

	siteVisibility: { type: Types.Select, label: 'child is visible to', options: 'everyone, registered social workers and families', required: true, initial: true }

}, 'Child Information', {

	registrationNumber: { type: Number, label: 'registration number', format: false, required: true, initial: true },
	registrationDate: { type: Types.Date, label: 'registration date', format: 'MM/DD/YYYY', required: true, initial: true },

	video: { type: Types.Url, label: 'Video' },

	name: {
		first: { type: Types.Text, label: 'first name', required: true, initial: true },
		middle: { type: Types.Text, label: 'middle name', initial: true },
		last: { type: Types.Text, label: 'last name', required: true, initial: true },
		alias: { type: Types.Text, label: 'alias', initial: true },
		nickName: { type: Types.Text, label: 'nickname', initial: true },
		full: { type: Types.Text, label: 'name', hidden: true, noedit: true, initial: false }
	},

	birthDate: { type: Types.Date, label: 'date of birth', format: 'MM/DD/YYYY', required: true, initial: true },
	language: { type: Types.Relationship, label: 'language', ref: 'Language', many: true, required: true, initial: true },
	statusChangeDate: { type: Types.Date, label: 'status change date', format: 'MM/DD/YYYY', initial: true }, // TODO: Logic needed, see line 14 of https://docs.google.com/spreadsheets/d/1Opb9qziX2enTehJx5K1J9KAT7v-j2yAdqwyQUMSsFwc/edit#gid=1235141373
	status: { type: Types.Relationship, label: 'status', ref: 'Child Status', required: true, initial: true },
	gender: { type: Types.Relationship, label: 'gender', ref: 'Gender', required: true, initial: true },
	race: { type: Types.Relationship, label: 'race', ref: 'Race', many: true, required: true, initial: true },
	legalStatus: { type: Types.Relationship, label: 'legal status', ref: 'Legal Status', required: true, initial: true },
	yearEnteredCare: { type: Types.Text, label: 'year entered care', note: 'yyyy', initial: true },

	hasContactWithSiblings: { type: Types.Boolean, label: 'has contact with siblings?', initial: true },
	siblingTypeOfContact: { type: Types.Text, label: 'type of contact', initial: true },
	siblingContacts: { type: Types.Relationship, label: 'siblings to be placed together (comma separated)', ref: 'Child', many: true, initial: true },
	hasContactWithBirthFamily: { type: Types.Boolean, label: 'has contact with birth family?', initial: true },
	birthFamilyTypeOfContact: { type: Types.Text, label: 'type of contact', initial: true },

	residence: { type: Types.Relationship, label: 'where does the child presently live?', ref: 'Residence', initial: true },
	city: { type: Types.Relationship, label: 'city/town of child\'s current location', ref: 'City or Town', initial: true },
	careFacilityName: { type: Types.Text, label: 'name of residential/group care facility', initial: true },
	dateMovedToResidence: { type: Types.Date, label: 'date moved to current residence', format: 'MM/DD/YYYY', required: true, initial: true }

}, 'Special Needs', {

	physicalNeeds: { type: Types.Select, label: 'physical needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	physicalNeedsDescription: { type: Types.Textarea, label: 'description of physical needs', dependsOn: { physicalNeeds: ['mild', 'moderate', 'severe'] }, initial: true },
	emotionalNeeds: { type: Types.Select, label: 'emotional needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	emotionalNeedsDescription: { type: Types.Textarea, label: 'description of emotional needs', dependsOn: { emotionalNeeds: ['mild', 'moderate', 'severe'] }, initial: true },
	intellectualNeeds: { type: Types.Select, label: 'intellectual needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	intellectualNeedsDescription: { type: Types.Textarea, label: 'description of intellectual needs', dependsOn: { intellectualNeeds: ['mild', 'moderate', 'severe'] }, initial: true },

	disabilities: { type: Types.Relationship, label: 'disabilities', ref: 'Disability', many: true, initial: true },

	specialNeedsNotes: { type: Types.Textarea, label: 'notes', dependsOn: { physicalNeeds: ['mild', 'moderate', 'severe'], emotionalNeeds: ['mild', 'moderate', 'severe'], intellectualNeeds: ['mild', 'moderate', 'severe'] }, initial: true }

}, 'Placement Considerations', {

	recommendedFamilyConstellation: { type: Types.Relationship, label: 'recommended family constellations', ref: 'Family Constellation', many: true, required: true, initial: true },
	otherFamilyConstellationConsideration: { type: Types.Relationship, label: 'other family constellation consideration', ref: 'Other Family Constellation Consideration', many: true, initial: true },
	otherConsiderations: { type: Types.Relationship, label: 'other considerations', ref: 'Other Consideration', many: true, initial: true }

}, 'Agency Information', {

	registeredBy: { type: Types.Select, label: 'registered by', options: 'unknown, adoption worker, recruitment worker', required: true, initial: true },
	adoptionWorker: { type: Types.Relationship, label: 'adoption worker', ref: 'Social Worker', filters: { position: 'adoption worker' }, initial: true },
	recruitmentWorker: { type: Types.Relationship, label: 'recruitment worker', ref: 'Social Worker', filters: { position: 'recruitment worker' }, initial: true },
	region: { type: Types.Relationship, label: 'region', ref: 'Region', initial: true }

}, 'Photolisting Information', {

	profile: {
		part1: { type: Types.Textarea, label: 'let me tell you more about myself...', required: true, initial: true },
		part2: { type: Types.Textarea, label: 'and here\'s what others say...', required: true, initial: true },
		part3: { type: Types.Textarea, label: 'if I could have my own special wish...', required: true, initial: true }
	},

	hasPhotolistingWriteup: { type: Types.Boolean, label: 'photolisting writeup', initial: true },
	photolistingWriteupDate: { type: Types.Date, label: 'date of photolisting writeup', format: 'MM/DD/YYYY', dependsOn: { hasPhotolistingWriteup: true }, initial: true },
	hasPhotolistingPhoto: { type: Types.Boolean, label: 'photolisting photo', initial: true },
	photolistingPhotoDate: { type: Types.Date, label: 'date of photolisting photo', format: 'MM/DD/YYYY', dependsOn: { hasPhotolistingPhoto: true }, initial: true },
	isCurrentlyInPhotoListing: { type: Types.Boolean, label: 'currently in photolisting', initial: true },
	inPhotoListingDate_WIP: { type: Types.Date, label: 'LISA NEEDS TO PICK THE LABEL', format: 'MM/DD/YYYY', dependsOn: {isCurrentlyInPhotoListing: true }, initial: true },
	photolistingPageNumber: { type: Number, label: 'photolisting page', format: false, initial: true },
	previousPhotolistingPageNumber: { type: Number, label: 'previous photolisting page', format: false, initial: true },

	image: { type: Types.CloudinaryImage, folder: 'children/', selectPrefix: 'children/', publicID: 'fileName', autoCleanup: true },
	galleryImage: {type: Types.Url, hidden: true },
	detailImage: {type: Types.Url, hidden: true },
	extranetUrl: { type: Types.Url, label: 'extranet and related profile url', initial: true } // Since this is redudant as this just points the the url where the photo exists (the child's page), we may hide this field.  This must be kept in as it will help us track down the child information in the old system in the event of an issue.

}, 'Recruitment Options', {

	hasVideoSnapshot: { type: Types.Boolean, label: 'video snapshot', initial: true },
	videoSnapshotDate: { type: Types.Date, label: 'date of video snapshot', format: 'MM/DD/YYYY', dependsOn: { hasVideoSnapshot: true }, initial: true },

	onMAREWebsite: { type: Types.Boolean, label: 'MARE website', initial: true },
	onMAREWebsiteDate: { type: Types.Date, label: 'date on MARE website', format: 'MM/DD/YYYY', dependsOn: { onMAREWebsite: true }, initial: true },

	onAdoptuskids: { type: Types.Boolean, label: 'Adoptuskids website', initial: true },
	onAdoptuskidsDate: { type: Types.Date, label: 'date on Adoptuskids', format: 'MM/DD/YYYY', dependsOn: { onAdoptuskids: true }, initial: true },

	onOnlineMatching: { type: Types.Boolean, label: 'online matching website', initial: true },
	onOnlineMatchingDate: { type: Types.Date, label: 'date on online matching', format: 'MM/DD/YYYY', dependsOn: { onOnlineMatching: true }, initial: true },

	wednesdaysChild: { type: Types.Boolean, label: 'Wednesday\'s Child?', initial: true },
	wednesdaysChildDate: { type: Types.Date, label: 'date of Wednesday\'s Child', format: 'MM/DD/YYYY', dependsOn: { wednesdaysChild: true }, initial: true },

	coalitionMeeting: { type: Types.Boolean, label: 'coalition meeting', initial: true },
	coalitionMeetingDate: { type: Types.Date, label: 'date of coalition meeting', format: 'MM/DD/YYYY', dependsOn: { coalitionMeeting: true }, initial: true },

	matchingEvent: { type: Types.Boolean, label: 'matching event', initial: true },
	matchingEventDate: { type: Types.Date, label: 'date of matching event', format: 'MM/DD/YYYY', dependsOn: { matchingEvent: true }, initial: true },

	adoptionParties: { type: Types.Relationship, label: 'adoption parties', ref: 'Event', filters: { type: 'adoption party' }, many: true, initial: true },

	mediaEligibility: { type: Types.Relationship, label: 'media eligibility', ref: 'Media Eligibility', many: true, initial: true },
	otherMediaDescription: { type: Types.Textarea, label: 'description', dependsOn: { mediaEligibility: 'Other' }, initial: true }, // THIS DOESN'T WORK BECAUSE IT REFERENCES A RELATIONSHIP FIELD SO ALL WE HAVE IS THE _id, MAKE IT WORK!

	locationAlert: { type: Types.Boolean, label: 'location alert', initial: true },
	place: { type: Types.Text, label: 'place', initial: true, dependsOn: { locationAlert: true } }

}, 'Attachments', {

	photolistingPage: {
		type: Types.S3File,
		s3path: '/child/photolisting-pages',
		filename: function(item, filename){
			// prefix file name with registration number and the user's name for easier identification
			return fileName;
		}
	},

	otherAttachement: {
		type: Types.S3File,
		s3path: '/child/other',
		filename: function(item, filename){
			// prefix file name with registration number and name for easier identification
			return fileName;
		}
	}
/* Container for all system fields (add a heading if any are meant to be visible through the admin UI) */
}, {

	// system field to store an appropriate file prefix
	fileName: { type: Types.Text, hidden: true }

});

// Set up relationship values to show up at the bottom of the model if any exist
Child.relationship({ ref: 'Child', refPath: 'siblingContacts', path: 'children', label: 'children' });
// Child.relationship({ path: 'siblings', ref: 'Sibling', refPath: 'child1' });
Child.relationship({ ref: 'Placement', refPath: 'child', path: 'placements', label: 'placements' });
Child.relationship({ ref: 'Inquiry', refPath: 'child', path: 'inquiries', label: 'inquiries' });
Child.relationship({ ref: 'Family', refPath: 'bookmarkedChildren', path: 'families', label: 'bookmarked by families' });
Child.relationship({ ref: 'Social Worker', refPath: 'bookmarkedChildren', path: 'social-workers', label: 'bookmarked by social workers' });
Child.relationship({ ref: 'Event', refPath: 'childAttendees', path: 'events', label: 'events' });
Child.relationship({ ref: 'Internal Note', refPath: 'child', path: 'internal-notes', label: 'internal notes' });

// Pre Save
Child.schema.pre('save', function(next) {
	'use strict';

	// TODO: Play with lowering quality to 0 and doubling the image size as an optimization technique
	this.galleryImage = this._.image.thumbnail(430,430,{ quality: 60 });
	this.detailImage = this._.image.thumbnail(200,200,{ quality: 60 });

	// Build the name string for better identification when linking through Relationship field types
	var firstName	= this.name.first,
		middleName	= (this.name.middle && this.name.middle.length > 0) ? ' ' + this.name.middle : '',
		lastName	= (this.name.last && this.name.last.length > 0) ? ' ' + this.name.last : ''

	this.name.full = firstName + middleName + lastName;
	// Create an identifying name for file uploads
	this.fileName = this.registrationNumber + '_' + this.name.first.toLowerCase();

	// TODO: Assign a registration number if one isn't assigned
	next();
});

// Define default columns in the admin interface and register the model
Child.defaultColumns = 'registrationNumber, name.full, ethnicity, legalStatus, gender';
Child.register();
<|endoftext|>


<commit_before>module.exports = {
  apps: [{
    name: 'davidpuerto.com',
    script: './index.js'
  }],
  deploy: {
    production: {
      user: 'ec2-user',
      host: 'ec2-35-163-175-145.us-west-2.compute.amazonaws.com',
      key: '~/.ssh/dap.pem',
      ref: 'origin/master',
      repo: 'git@github.com:dapinitial/davidpuerto.com.git',
      path: '',
      'post-deploy': 'npm install && pm2 startOrRestart ecosystem.config.js'
    }
  }
}
<commit_msg>updating path in ecosytem for ec2-user<commit_after>module.exports = {
  apps: [{
    name: 'davidpuerto.com',
    script: './index.js'
  }],
  deploy: {
    production: {
      user: 'ec2-user',
      host: 'ec2-35-163-175-145.us-west-2.compute.amazonaws.com',
      key: '~/.ssh/dap.pem',
      ref: 'origin/master',
      repo: 'git@github.com:dapinitial/davidpuerto.com.git',
      path: '~/',
      'post-deploy': 'npm install && pm2 startOrRestart ecosystem.config.js'
    }
  }
}
<|endoftext|>


<commit_before>import DS from 'ember-data';

export default DS.Model.extend({

	name: DS.attr('string'),
	video: DS.attr('string'),
	photo_jpg : DS.attr('string'),
	video_mp4 : DS.attr('string'),
	video_webm : DS.attr('string'),
	cta_url : DS.attr('string'),
	logo_svg : DS.attr('string'),

});
<commit_msg>tagline<commit_after>import DS from 'ember-data';

export default DS.Model.extend({

	name: DS.attr('string'),
	video: DS.attr('string'),
	photo_jpg : DS.attr('string'),
	video_mp4 : DS.attr('string'),
	video_webm : DS.attr('string'),
	cta_url : DS.attr('string'),
	logo_svg : DS.attr('string'),
	tagline_svg : DS.attr('string'),
	hasTagline : DS.attr('boolean', { defaultValue: false } ),

});
<|endoftext|>


<commit_before>var fs = require('fs'),
    mkdirp = require('mkdirp'),
    rimraf = require('rimraf'),
    path = require('path'),
    _ = require('lodash'),
    async = require('async'),
    GIFEncoder = require('gifencoder'),
    pngFileStream = require('png-file-stream'),
    sharp = require('sharp');

var VALID_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif'];
var RESIZED_IMAGE_BACKGROUND_COLOR = {
    r: 0,
    g: 0,
    b: 0,
    a: 1
};

function findSourceImages(sourceImageDir) {
    var imageFileNames = fs.readdirSync(sourceImageDir);
    imageFileNames = _.remove(imageFileNames, function(imagePath) {
        return _.contains(VALID_EXTENSIONS, path.extname(imagePath));
    });
    return imageFileNames;
}

/**
 * Resize and pre-process all source images.
 * For gif processing, we need all images to be the same size.
 * Also, to make everything easier, we turn them all into pngs.
 */
function preprocessImages(tempDir, sourceImageDir, imageFileNames, gifParams, onFinished) {
    var works = [];

    _.forEach(imageFileNames, function(imageFileName) {
        var fromImagePath = path.join(sourceImageDir, imageFileName);

        // Trim the extension from the file name.
        var ext = path.extname(imageFileName);
        var baseName = imageFileName.substring(0, imageFileName.length - ext.length);
        var toImagePath = path.join(tempDir, baseName + '.png');

        // Resize.
        works.push(function(cb) {
            sharp(fromImagePath)
                .embed() // preserve aspect ration
                .background(RESIZED_IMAGE_BACKGROUND_COLOR)
                .resize(gifParams.sizeX, gifParams.sizeY)
                .toFile(toImagePath, function(err) {
                    cb(err);
                });
        });

        console.log('Preprocessing image: ' + fromImagePath + ' -> ' + toImagePath);
    });

    async.parallel(works, function(err) {
        onFinished(err);
    });
}

function generateGif(tempDir, gifParams) {
    var gifOptions = {
        repeat: gifParams.repeat,
        delay: gifParams.delay,
        quality: gifParams.quality
    };

    console.log('Generating gif: ' + gifParams.path);

    var encoder = new GIFEncoder(gifParams.sizeX, gifParams.sizeY);
    pngFileStream(path.join(tempDir, '?.png'))
        .pipe(encoder.createWriteStream(gifOptions))
        .pipe(fs.createWriteStream(gifParams.path));
}

function defaultParam(param, defaultValue) {
    return typeof param !== 'undefined' ? param : defaultValue;
}

module.exports = {
    /*
        Generate a GIF image using all images in sourceImageDir as
        the input. Returns true on success.
     */
    makeGif: function(sourceImageDir, gifParams) {
        if (typeof gifParams.path === 'undefined') {
            console.error('Output gif path must be specified.');
            return false;
        }

        gifParams.sizeX = defaultParam(gifParams.sizeX, 64);
        gifParams.sizeY = defaultParam(gifParams.sizeY, 64);
        gifParams.delay = defaultParam(gifParams.delay, 500);
        gifParams.quality = defaultParam(gifParams.quality, 10);
        gifParams.repeat = defaultParam(gifParams.repeat, 0); // repeat by default

        var imageFileNames = findSourceImages(sourceImageDir);

        if (imageFileNames.length === 0) {
            console.warn('No input images found.');
            return true;
        }

        // Make temp directory for our resized files.
        var tempDir = path.join(sourceImageDir, '/temp');
        mkdirp.sync(tempDir);

        preprocessImages(tempDir, sourceImageDir, imageFileNames, gifParams, function(err) {
            if (err) {
                console.error('Error during preprocessing images: ' + err.message);
                return false;
            }

            generateGif(tempDir, gifParams);

            // Delete temp dir + contents.
            // rimraf.sync(tempDir );

            return true;
        });
    }
};
<commit_msg>Not using this right now - comment out.<commit_after>var fs = require('fs'),
    mkdirp = require('mkdirp'),
    // rimraf = require('rimraf'),
    path = require('path'),
    _ = require('lodash'),
    async = require('async'),
    GIFEncoder = require('gifencoder'),
    pngFileStream = require('png-file-stream'),
    sharp = require('sharp');

var VALID_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif'];
var RESIZED_IMAGE_BACKGROUND_COLOR = {
    r: 0,
    g: 0,
    b: 0,
    a: 1
};

function findSourceImages(sourceImageDir) {
    var imageFileNames = fs.readdirSync(sourceImageDir);
    imageFileNames = _.remove(imageFileNames, function(imagePath) {
        return _.contains(VALID_EXTENSIONS, path.extname(imagePath));
    });
    return imageFileNames;
}

/**
 * Resize and pre-process all source images.
 * For gif processing, we need all images to be the same size.
 * Also, to make everything easier, we turn them all into pngs.
 */
function preprocessImages(tempDir, sourceImageDir, imageFileNames, gifParams, onFinished) {
    var works = [];

    _.forEach(imageFileNames, function(imageFileName) {
        var fromImagePath = path.join(sourceImageDir, imageFileName);

        // Trim the extension from the file name.
        var ext = path.extname(imageFileName);
        var baseName = imageFileName.substring(0, imageFileName.length - ext.length);
        var toImagePath = path.join(tempDir, baseName + '.png');

        // Resize.
        works.push(function(cb) {
            sharp(fromImagePath)
                .embed() // preserve aspect ration
                .background(RESIZED_IMAGE_BACKGROUND_COLOR)
                .resize(gifParams.sizeX, gifParams.sizeY)
                .toFile(toImagePath, function(err) {
                    cb(err);
                });
        });

        console.log('Preprocessing image: ' + fromImagePath + ' -> ' + toImagePath);
    });

    async.parallel(works, function(err) {
        onFinished(err);
    });
}

function generateGif(tempDir, gifParams) {
    var gifOptions = {
        repeat: gifParams.repeat,
        delay: gifParams.delay,
        quality: gifParams.quality
    };

    console.log('Generating gif: ' + gifParams.path);

    var encoder = new GIFEncoder(gifParams.sizeX, gifParams.sizeY);
    pngFileStream(path.join(tempDir, '?.png'))
        .pipe(encoder.createWriteStream(gifOptions))
        .pipe(fs.createWriteStream(gifParams.path));
}

function defaultParam(param, defaultValue) {
    return typeof param !== 'undefined' ? param : defaultValue;
}

module.exports = {
    /*
        Generate a GIF image using all images in sourceImageDir as
        the input. Returns true on success.
     */
    makeGif: function(sourceImageDir, gifParams) {
        if (typeof gifParams.path === 'undefined') {
            console.error('Output gif path must be specified.');
            return false;
        }

        gifParams.sizeX = defaultParam(gifParams.sizeX, 64);
        gifParams.sizeY = defaultParam(gifParams.sizeY, 64);
        gifParams.delay = defaultParam(gifParams.delay, 500);
        gifParams.quality = defaultParam(gifParams.quality, 10);
        gifParams.repeat = defaultParam(gifParams.repeat, 0); // repeat by default

        var imageFileNames = findSourceImages(sourceImageDir);

        if (imageFileNames.length === 0) {
            console.warn('No input images found.');
            return true;
        }

        // Make temp directory for our resized files.
        var tempDir = path.join(sourceImageDir, '/temp');
        mkdirp.sync(tempDir);

        preprocessImages(tempDir, sourceImageDir, imageFileNames, gifParams, function(err) {
            if (err) {
                console.error('Error during preprocessing images: ' + err.message);
                return false;
            }

            generateGif(tempDir, gifParams);

            // Delete temp dir + contents.
            // rimraf.sync(tempDir );

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


<commit_before>Brooklyn.jsTree = (function(parent) {

    var currentTree;

    function typeTest(a, b) {
        return (typeof a == typeof b)
    }

    function testEquivalent(a, b) {
        var result = true;
        if (!typeTest(a, b)) return false;
        if (typeof a == 'object') {
            for (var p in a) {
                result = testEquivalent(a[p], b[p]);
                if (!result) return false;
            }
            return result;
        }
        return (a == b);
    }

    function getLatestTree(){
        $.getJSON("jstree?name=" + $("#search-input").val().toLowerCase(), refreshTreeIfChanged).error(
            function() {$(Brooklyn.eventBus).trigger('update_failed', "Could not get new entity data.");}
        );
    }

    function refreshTreeIfChanged(json){
        if (currentTree == undefined || !testEquivalent(json, currentTree)){
            currentTree = json;
            loadJstree();
        }
    }

    function loadJstree() {
        $("#jstree").jstree({
                "plugins" : [ "themes", "json_data", "ui" ],
                "json_data" : {
                    data : currentTree
                }
            }).bind('select_node.jstree',
                    function(e, data){
                        var entity_id = $(data.rslt.obj).data('id')
                        $(Brooklyn.eventBus).trigger('entity_selected', entity_id);
                    });
    }

    function init() {
        $('#search-input').keyup(getLatestTree);
        $("#search-input").corner();
        $(Brooklyn.eventBus).bind("update", getLatestTree);
        getLatestTree();
    }

    return {
        init: init
    };

}(Brooklyn || {}));

$(document).ready(Brooklyn.jsTree.init);
<commit_msg>ENGR-1734: tree now bring back no results correctly<commit_after>Brooklyn.jsTree = (function(parent) {

    var currentTree;

    function typeTest(a, b) {
        return (typeof a == typeof b)
    }

    function testEquivalent(a, b) {
        var result = true;
        if (!typeTest(a, b)) return false;
        if (typeof a == 'object') {
            for (var p in a) {
                result = testEquivalent(a[p], b[p]);
                if (!result) return false;
            }
            return result;
        }
        return (a == b);
    }

    function getLatestTree(){
        $.getJSON("jstree?name=" + $("#search-input").val().toLowerCase(), refreshTreeIfChanged).error(
            function() {$(Brooklyn.eventBus).trigger('update_failed', "Could not get new entity data.");}
        );
    }

    function refreshTreeIfChanged(json){
        if (currentTree == undefined || json[0][0] == undefined || !testEquivalent(json, currentTree)){
            currentTree = json;
            loadJstree();
        }
    }

    function loadJstree() {
        $("#jstree").jstree({
                "plugins" : [ "themes", "json_data", "ui" ],
                "json_data" : {
                    data : currentTree
                }
            }).bind('select_node.jstree',
                    function(e, data){
                        var entity_id = $(data.rslt.obj).data('id')
                        $(Brooklyn.eventBus).trigger('entity_selected', entity_id);
                    });
    }

    function init() {
        $('#search-input').keyup(getLatestTree);
        $("#search-input").corner();
        $(Brooklyn.eventBus).bind("update", getLatestTree);
        getLatestTree();
    }

    return {
        init: init
    };

}(Brooklyn || {}));

$(document).ready(Brooklyn.jsTree.init);
<|endoftext|>


<commit_before>var keystone = require('keystone'),
	Types = keystone.Field.Types;

// Create model
var Child = new keystone.List('Child', {
	track: true,
	autokey: { path: 'key', from: 'registrationNumber', unique: true },
	map: { name: 'name.full' },
	defaultSort: 'name.full'
});

// Create fields
Child.add('Display Options', {

	siteVisibility: { type: Types.Select, label: 'child is visible to', options: 'everyone, registered social workers and families', required: true, initial: true }

}, 'Child Information', {

	registrationNumber: { type: Number, label: 'registration number', format: false, required: true, initial: true },
	registrationDate: { type: Types.Date, label: 'registration date', format: 'MM/DD/YYYY', required: true, initial: true },

	video: { type: Types.Url, label: 'Video' },

	name: {
		first: { type: Types.Text, label: 'first name', required: true, initial: true },
		middle: { type: Types.Text, label: 'middle name', initial: true },
		last: { type: Types.Text, label: 'last name', required: true, initial: true },
		alias: { type: Types.Text, label: 'alias', initial: true },
		nickName: { type: Types.Text, label: 'nickname', initial: true },
		full: { type: Types.Text, label: 'name', hidden: true, noedit: true, initial: false }
	},

	birthDate: { type: Types.Date, label: 'date of birth', format: 'MM/DD/YYYY', required: true, initial: true },
	language: { type: Types.Relationship, label: 'language', ref: 'Language', many: true, required: true, initial: true },
	statusChangeDate: { type: Types.Date, label: 'status change date', format: 'MM/DD/YYYY', initial: true }, // TODO: Logic needed, see line 14 of https://docs.google.com/spreadsheets/d/1Opb9qziX2enTehJx5K1J9KAT7v-j2yAdqwyQUMSsFwc/edit#gid=1235141373
	status: { type: Types.Relationship, label: 'status', ref: 'Child Status', required: true, initial: true },
	gender: { type: Types.Relationship, label: 'gender', ref: 'Gender', required: true, initial: true },
	race: { type: Types.Relationship, label: 'race', ref: 'Race', many: true, required: true, initial: true },
	legalStatus: { type: Types.Relationship, label: 'legal status', ref: 'Legal Status', required: true, initial: true },
	yearEnteredCare: { type: Types.Text, label: 'year entered care', note: 'yyyy', initial: true },

	hasContactWithSiblings: { type: Types.Boolean, label: 'has contact with siblings?', initial: true },
	siblingTypeOfContact: { type: Types.Text, label: 'type of contact', initial: true },
	siblingContacts: { type: Types.Relationship, label: 'siblings to be placed together (comma separated)', ref: 'Child', many: true, initial: true },
	hasContactWithBirthFamily: { type: Types.Boolean, label: 'has contact with birth family?', initial: true },
	birthFamilyTypeOfContact: { type: Types.Text, label: 'type of contact', initial: true },

	residence: { type: Types.Relationship, label: 'where does the child presently live?', ref: 'Residence', initial: true },
	city: { type: Types.Relationship, label: 'city/town of child\'s current location', ref: 'City or Town', initial: true },
	careFacilityName: { type: Types.Text, label: 'name of residential/group care facility', initial: true },
	dateMovedToResidence: { type: Types.Date, label: 'date moved to current residence', format: 'MM/DD/YYYY', required: true, initial: true }

}, 'Special Needs', {

	physicalNeeds: { type: Types.Select, label: 'physical needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	physicalNeedsDescription: { type: Types.Textarea, label: 'description of physical needs', dependsOn: { physicalNeeds: ['mild', 'moderate', 'severe'] }, initial: true },
	emotionalNeeds: { type: Types.Select, label: 'emotional needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	emotionalNeedsDescription: { type: Types.Textarea, label: 'description of emotional needs', dependsOn: { emotionalNeeds: ['mild', 'moderate', 'severe'] }, initial: true },
	intellectualNeeds: { type: Types.Select, label: 'intellectual needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	intellectualNeedsDescription: { type: Types.Textarea, label: 'description of intellectual needs', dependsOn: { intellectualNeeds: ['mild', 'moderate', 'severe'] }, initial: true },

	disabilities: { type: Types.Relationship, label: 'disabilities', ref: 'Disability', many: true, initial: true },

	specialNeedsNotes: { type: Types.Textarea, label: 'notes', dependsOn: { physicalNeeds: ['mild', 'moderate', 'severe'], emotionalNeeds: ['mild', 'moderate', 'severe'], intellectualNeeds: ['mild', 'moderate', 'severe'] }, initial: true }

}, 'Placement Considerations', {

	recommendedFamilyConstellation: { type: Types.Relationship, label: 'recommended family constellations', ref: 'Family Constellation', many: true, required: true, initial: true },
	otherFamilyConstellationConsideration: { type: Types.Relationship, label: 'other family constellation consideration', ref: 'Other Family Constellation Consideration', many: true, initial: true },
	otherConsiderations: { type: Types.Relationship, label: 'other considerations', ref: 'Other Consideration', many: true, initial: true }

}, 'Agency Information', {

	registeredBy: { type: Types.Select, label: 'registered by', options: 'unknown, adoption worker, recruitment worker', required: true, initial: true },
	adoptionWorker: { type: Types.Relationship, label: 'adoption worker', ref: 'Social Worker', filters: { position: 'adoption worker' }, initial: true },
	recruitmentWorker: { type: Types.Relationship, label: 'recruitment worker', ref: 'Social Worker', filters: { position: 'recruitment worker' }, initial: true },
	region: { type: Types.Relationship, label: 'region', ref: 'Region', initial: true }

}, 'Photolisting Information', {

	profile: {
		part1: { type: Types.Textarea, label: 'let me tell you more about myself...', required: true, initial: true },
		part2: { type: Types.Textarea, label: 'and here\'s what others say...', required: true, initial: true },
		part3: { type: Types.Textarea, label: 'if I could have my own special wish...', required: true, initial: true }
	},

	hasPhotolistingWriteup: { type: Types.Boolean, label: 'photolisting writeup', initial: true },
	photolistingWriteupDate: { type: Types.Date, label: 'date of photolisting writeup', format: 'MM/DD/YYYY', dependsOn: { hasPhotolistingWriteup: true }, initial: true },
	hasPhotolistingPhoto: { type: Types.Boolean, label: 'photolisting photo', initial: true },
	photolistingPhotoDate: { type: Types.Date, label: 'date of photolisting photo', format: 'MM/DD/YYYY', dependsOn: { hasPhotolistingPhoto: true }, initial: true },
	isCurrentlyInPhotoListing: { type: Types.Boolean, label: 'currently in photolisting', initial: true },
	inPhotoListingDate_WIP: { type: Types.Date, label: 'LISA NEEDS TO PICK THE LABEL', format: 'MM/DD/YYYY', dependsOn: {isCurrentlyInPhotoListing: true }, initial: true },
	photolistingPageNumber: { type: Number, label: 'photolisting page', format: false, initial: true },
	previousPhotolistingPageNumber: { type: Number, label: 'previous photolisting page', format: false, initial: true },

	image: { type: Types.CloudinaryImage, folder: 'children/', selectPrefix: 'children/', publicID: 'fileName', autoCleanup: true },
	galleryImage: {type: Types.Url, hidden: true },
	detailImage: {type: Types.Url, hidden: true },
	extranetUrl: { type: Types.Url, label: 'extranet and related profile url', initial: true } // Since this is redudant as this just points the the url where the photo exists (the child's page), we may hide this field.  This must be kept in as it will help us track down the child information in the old system in the event of an issue.

}, 'Recruitment Options', {

	hasVideoSnapshot: { type: Types.Boolean, label: 'video snapshot', initial: true },
	videoSnapshotDate: { type: Types.Date, label: 'date of video snapshot', format: 'MM/DD/YYYY', dependsOn: { hasVideoSnapshot: true }, initial: true },

	onMAREWebsite: { type: Types.Boolean, label: 'MARE website', initial: true },
	onMAREWebsiteDate: { type: Types.Date, label: 'date on MARE website', format: 'MM/DD/YYYY', dependsOn: { onMAREWebsite: true }, initial: true },

	onAdoptuskids: { type: Types.Boolean, label: 'Adoptuskids website', initial: true },
	onAdoptuskidsDate: { type: Types.Date, label: 'date on Adoptuskids', format: 'MM/DD/YYYY', dependsOn: { onAdoptuskids: true }, initial: true },

	onOnlineMatching: { type: Types.Boolean, label: 'online matching website', initial: true },
	onOnlineMatchingDate: { type: Types.Date, label: 'date on online matching', format: 'MM/DD/YYYY', dependsOn: { onOnlineMatching: true }, initial: true },

	wednesdaysChild: { type: Types.Boolean, label: 'Wednesday\'s Child?', initial: true },
	wednesdaysChildDate: { type: Types.Date, label: 'date of Wednesday\'s Child', format: 'MM/DD/YYYY', dependsOn: { wednesdaysChild: true }, initial: true },

	coalitionMeeting: { type: Types.Boolean, label: 'coalition meeting', initial: true },
	coalitionMeetingDate: { type: Types.Date, label: 'date of coalition meeting', format: 'MM/DD/YYYY', dependsOn: { coalitionMeeting: true }, initial: true },

	matchingEvent: { type: Types.Boolean, label: 'matching event', initial: true },
	matchingEventDate: { type: Types.Date, label: 'date of matching event', format: 'MM/DD/YYYY', dependsOn: { matchingEvent: true }, initial: true },

	adoptionParties: { type: Types.Relationship, label: 'adoption parties', ref: 'Event', filters: { type: 'adoption party' }, many: true, initial: true },

	mediaEligibility: { type: Types.Relationship, label: 'media eligibility', ref: 'Media Eligibility', many: true, initial: true },
	otherMediaDescription: { type: Types.Textarea, label: 'description', dependsOn: { mediaEligibility: 'Other' }, initial: true }, // THIS DOESN'T WORK BECAUSE IT REFERENCES A RELATIONSHIP FIELD SO ALL WE HAVE IS THE _id, MAKE IT WORK!

	locationAlert: { type: Types.Boolean, label: 'location alert', initial: true },
	place: { type: Types.Text, label: 'place', initial: true, dependsOn: { locationAlert: true } }

}, 'Attachments', {

	photolistingPage: {
		type: Types.S3File,
		s3path: '/child/photolisting-pages',
		filename: function(item, filename){
			// prefix file name with registration number and the user's name for easier identification
			return fileName;
		}
	},

	otherAttachement: {
		type: Types.S3File,
		s3path: '/child/other',
		filename: function(item, filename){
			// prefix file name with registration number and name for easier identification
			return fileName;
		}
	}
/* Container for all system fields (add a heading if any are meant to be visible through the admin UI) */
}, {

	// system field to store an appropriate file prefix
	fileName: { type: Types.Text, hidden: true }

});

// Set up relationship values to show up at the bottom of the model if any exist
Child.relationship({ ref: 'Child', refPath: 'siblingContacts', path: 'children', label: 'children' });
// Child.relationship({ path: 'siblings', ref: 'Sibling', refPath: 'child1' });
Child.relationship({ ref: 'Placement', refPath: 'child', path: 'placements', label: 'placements' });
Child.relationship({ ref: 'Inquiry', refPath: 'child', path: 'inquiries', label: 'inquiries' });
Child.relationship({ ref: 'Family', refPath: 'bookmarkedChildren', path: 'families', label: 'bookmarked by families' });
Child.relationship({ ref: 'Social Worker', refPath: 'bookmarkedChildren', path: 'social-workers', label: 'bookmarked by social workers' });
Child.relationship({ ref: 'Event', refPath: 'childAttendees', path: 'events', label: 'events' });
Child.relationship({ ref: 'Internal Note', refPath: 'child', path: 'internal-notes', label: 'internal notes' });

// Pre Save
Child.schema.pre('save', function(next) {
	'use strict';

	// TODO: Play with lowering quality to 0 and doubling the image size as an optimization technique
	this.galleryImage = this._.image.thumbnail(430,430,{ quality: 60 });
	this.detailImage = this._.image.thumbnail(200,200,{ quality: 60 });

	// Build the name string for better identification when linking through Relationship field types
	var firstName	= this.name.first,
		middleName	= (this.name.middle && this.name.middle.length > 0) ? ' ' + this.name.middle : '',
		lastName	= (this.name.last && this.name.last.length > 0) ? ' ' + this.name.last : ''

	this.name.full = firstName + middleName + lastName;
	// Create an identifying name for file uploads
	this.fileName = this.registrationNumber + '_' + this.name.first.toLowerCase();

	// TODO: Assign a registration number if one isn't assigned
	next();
});

// Define default columns in the admin interface and register the model
Child.defaultColumns = 'registrationNumber, name.full, ethnicity, legalStatus, gender';
Child.register();
<commit_msg>#35 | add date of last photolisting field<commit_after>var keystone = require('keystone'),
	Types = keystone.Field.Types;

// Create model
var Child = new keystone.List('Child', {
	track: true,
	autokey: { path: 'key', from: 'registrationNumber', unique: true },
	map: { name: 'name.full' },
	defaultSort: 'name.full'
});

// Create fields
Child.add('Display Options', {

	siteVisibility: { type: Types.Select, label: 'child is visible to', options: 'everyone, registered social workers and families', required: true, initial: true }

}, 'Child Information', {

	registrationNumber: { type: Number, label: 'registration number', format: false, required: true, initial: true },
	registrationDate: { type: Types.Date, label: 'registration date', format: 'MM/DD/YYYY', required: true, initial: true },

	video: { type: Types.Url, label: 'Video' },

	name: {
		first: { type: Types.Text, label: 'first name', required: true, initial: true },
		middle: { type: Types.Text, label: 'middle name', initial: true },
		last: { type: Types.Text, label: 'last name', required: true, initial: true },
		alias: { type: Types.Text, label: 'alias', initial: true },
		nickName: { type: Types.Text, label: 'nickname', initial: true },
		full: { type: Types.Text, label: 'name', hidden: true, noedit: true, initial: false }
	},

	birthDate: { type: Types.Date, label: 'date of birth', format: 'MM/DD/YYYY', required: true, initial: true },
	language: { type: Types.Relationship, label: 'language', ref: 'Language', many: true, required: true, initial: true },
	statusChangeDate: { type: Types.Date, label: 'status change date', format: 'MM/DD/YYYY', initial: true }, // TODO: Logic needed, see line 14 of https://docs.google.com/spreadsheets/d/1Opb9qziX2enTehJx5K1J9KAT7v-j2yAdqwyQUMSsFwc/edit#gid=1235141373
	status: { type: Types.Relationship, label: 'status', ref: 'Child Status', required: true, initial: true },
	gender: { type: Types.Relationship, label: 'gender', ref: 'Gender', required: true, initial: true },
	race: { type: Types.Relationship, label: 'race', ref: 'Race', many: true, required: true, initial: true },
	legalStatus: { type: Types.Relationship, label: 'legal status', ref: 'Legal Status', required: true, initial: true },
	yearEnteredCare: { type: Types.Text, label: 'year entered care', note: 'yyyy', initial: true },

	hasContactWithSiblings: { type: Types.Boolean, label: 'has contact with siblings?', initial: true },
	siblingTypeOfContact: { type: Types.Text, label: 'type of contact', initial: true },
	siblingContacts: { type: Types.Relationship, label: 'siblings to be placed together (comma separated)', ref: 'Child', many: true, initial: true },
	hasContactWithBirthFamily: { type: Types.Boolean, label: 'has contact with birth family?', initial: true },
	birthFamilyTypeOfContact: { type: Types.Text, label: 'type of contact', initial: true },

	residence: { type: Types.Relationship, label: 'where does the child presently live?', ref: 'Residence', initial: true },
	city: { type: Types.Relationship, label: 'city/town of child\'s current location', ref: 'City or Town', initial: true },
	careFacilityName: { type: Types.Text, label: 'name of residential/group care facility', initial: true },
	dateMovedToResidence: { type: Types.Date, label: 'date moved to current residence', format: 'MM/DD/YYYY', required: true, initial: true }

}, 'Special Needs', {

	physicalNeeds: { type: Types.Select, label: 'physical needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	physicalNeedsDescription: { type: Types.Textarea, label: 'description of physical needs', dependsOn: { physicalNeeds: ['mild', 'moderate', 'severe'] }, initial: true },
	emotionalNeeds: { type: Types.Select, label: 'emotional needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	emotionalNeedsDescription: { type: Types.Textarea, label: 'description of emotional needs', dependsOn: { emotionalNeeds: ['mild', 'moderate', 'severe'] }, initial: true },
	intellectualNeeds: { type: Types.Select, label: 'intellectual needs', options: 'none, mild, moderate, severe', required: true, initial: true },
	intellectualNeedsDescription: { type: Types.Textarea, label: 'description of intellectual needs', dependsOn: { intellectualNeeds: ['mild', 'moderate', 'severe'] }, initial: true },

	disabilities: { type: Types.Relationship, label: 'disabilities', ref: 'Disability', many: true, initial: true },

	specialNeedsNotes: { type: Types.Textarea, label: 'notes', dependsOn: { physicalNeeds: ['mild', 'moderate', 'severe'], emotionalNeeds: ['mild', 'moderate', 'severe'], intellectualNeeds: ['mild', 'moderate', 'severe'] }, initial: true }

}, 'Placement Considerations', {

	recommendedFamilyConstellation: { type: Types.Relationship, label: 'recommended family constellations', ref: 'Family Constellation', many: true, required: true, initial: true },
	otherFamilyConstellationConsideration: { type: Types.Relationship, label: 'other family constellation consideration', ref: 'Other Family Constellation Consideration', many: true, initial: true },
	otherConsiderations: { type: Types.Relationship, label: 'other considerations', ref: 'Other Consideration', many: true, initial: true }

}, 'Agency Information', {

	registeredBy: { type: Types.Select, label: 'registered by', options: 'unknown, adoption worker, recruitment worker', required: true, initial: true },
	adoptionWorker: { type: Types.Relationship, label: 'adoption worker', ref: 'Social Worker', filters: { position: 'adoption worker' }, initial: true },
	recruitmentWorker: { type: Types.Relationship, label: 'recruitment worker', ref: 'Social Worker', filters: { position: 'recruitment worker' }, initial: true },
	region: { type: Types.Relationship, label: 'region', ref: 'Region', initial: true }

}, 'Photolisting Information', {

	profile: {
		part1: { type: Types.Textarea, label: 'let me tell you more about myself...', required: true, initial: true },
		part2: { type: Types.Textarea, label: 'and here\'s what others say...', required: true, initial: true },
		part3: { type: Types.Textarea, label: 'if I could have my own special wish...', required: true, initial: true }
	},

	hasPhotolistingWriteup: { type: Types.Boolean, label: 'photolisting writeup', initial: true },
	photolistingWriteupDate: { type: Types.Date, label: 'date of photolisting writeup', format: 'MM/DD/YYYY', dependsOn: { hasPhotolistingWriteup: true }, initial: true },
	hasPhotolistingPhoto: { type: Types.Boolean, label: 'photolisting photo', initial: true },
	photolistingPhotoDate: { type: Types.Date, label: 'date of photolisting photo', format: 'MM/DD/YYYY', dependsOn: { hasPhotolistingPhoto: true }, initial: true },
	isCurrentlyInPhotoListing: { type: Types.Boolean, label: 'currently in photolisting', initial: true },
	dateOfLastPhotoListing: { type: Types.Date, label: 'date of last photolisting', format: 'MM/DD/YYYY', dependsOn: {isCurrentlyInPhotoListing: true }, initial: true },
	photolistingPageNumber: { type: Number, label: 'photolisting page', format: false, initial: true },
	previousPhotolistingPageNumber: { type: Number, label: 'previous photolisting page', format: false, initial: true },

	image: { type: Types.CloudinaryImage, folder: 'children/', selectPrefix: 'children/', publicID: 'fileName', autoCleanup: true },
	galleryImage: {type: Types.Url, hidden: true },
	detailImage: {type: Types.Url, hidden: true },
	extranetUrl: { type: Types.Url, label: 'extranet and related profile url', initial: true } // Since this is redundant as this just points the the url where the photo exists (the child's page), we may hide this field.  This must be kept in as it will help us track down the child information in the old system in the event of an issue.

}, 'Recruitment Options', {

	hasVideoSnapshot: { type: Types.Boolean, label: 'video snapshot', initial: true },
	videoSnapshotDate: { type: Types.Date, label: 'date of video snapshot', format: 'MM/DD/YYYY', dependsOn: { hasVideoSnapshot: true }, initial: true },

	onMAREWebsite: { type: Types.Boolean, label: 'MARE website', initial: true },
	onMAREWebsiteDate: { type: Types.Date, label: 'date on MARE website', format: 'MM/DD/YYYY', dependsOn: { onMAREWebsite: true }, initial: true },

	onAdoptuskids: { type: Types.Boolean, label: 'Adoptuskids website', initial: true },
	onAdoptuskidsDate: { type: Types.Date, label: 'date on Adoptuskids', format: 'MM/DD/YYYY', dependsOn: { onAdoptuskids: true }, initial: true },

	onOnlineMatching: { type: Types.Boolean, label: 'online matching website', initial: true },
	onOnlineMatchingDate: { type: Types.Date, label: 'date on online matching', format: 'MM/DD/YYYY', dependsOn: { onOnlineMatching: true }, initial: true },

	wednesdaysChild: { type: Types.Boolean, label: 'Wednesday\'s Child?', initial: true },
	wednesdaysChildDate: { type: Types.Date, label: 'date of Wednesday\'s Child', format: 'MM/DD/YYYY', dependsOn: { wednesdaysChild: true }, initial: true },

	coalitionMeeting: { type: Types.Boolean, label: 'coalition meeting', initial: true },
	coalitionMeetingDate: { type: Types.Date, label: 'date of coalition meeting', format: 'MM/DD/YYYY', dependsOn: { coalitionMeeting: true }, initial: true },

	matchingEvent: { type: Types.Boolean, label: 'matching event', initial: true },
	matchingEventDate: { type: Types.Date, label: 'date of matching event', format: 'MM/DD/YYYY', dependsOn: { matchingEvent: true }, initial: true },

	adoptionParties: { type: Types.Relationship, label: 'adoption parties', ref: 'Event', filters: { type: 'adoption party' }, many: true, initial: true },

	mediaEligibility: { type: Types.Relationship, label: 'media eligibility', ref: 'Media Eligibility', many: true, initial: true },
	otherMediaDescription: { type: Types.Textarea, label: 'description', dependsOn: { mediaEligibility: 'Other' }, initial: true }, // THIS DOESN'T WORK BECAUSE IT REFERENCES A RELATIONSHIP FIELD SO ALL WE HAVE IS THE _id, MAKE IT WORK!

	locationAlert: { type: Types.Boolean, label: 'location alert', initial: true },
	place: { type: Types.Text, label: 'place', initial: true, dependsOn: { locationAlert: true } }

}, 'Attachments', {

	photolistingPage: {
		type: Types.S3File,
		s3path: '/child/photolisting-pages',
		filename: function(item, filename){
			// prefix file name with registration number and the user's name for easier identification
			return fileName;
		}
	},

	otherAttachement: {
		type: Types.S3File,
		s3path: '/child/other',
		filename: function(item, filename){
			// prefix file name with registration number and name for easier identification
			return fileName;
		}
	}
/* Container for all system fields (add a heading if any are meant to be visible through the admin UI) */
}, {

	// system field to store an appropriate file prefix
	fileName: { type: Types.Text, hidden: true }

});

// Set up relationship values to show up at the bottom of the model if any exist
Child.relationship({ ref: 'Child', refPath: 'siblingContacts', path: 'children', label: 'children' });
// Child.relationship({ path: 'siblings', ref: 'Sibling', refPath: 'child1' });
Child.relationship({ ref: 'Placement', refPath: 'child', path: 'placements', label: 'placements' });
Child.relationship({ ref: 'Inquiry', refPath: 'child', path: 'inquiries', label: 'inquiries' });
Child.relationship({ ref: 'Family', refPath: 'bookmarkedChildren', path: 'families', label: 'bookmarked by families' });
Child.relationship({ ref: 'Social Worker', refPath: 'bookmarkedChildren', path: 'social-workers', label: 'bookmarked by social workers' });
Child.relationship({ ref: 'Event', refPath: 'childAttendees', path: 'events', label: 'events' });
Child.relationship({ ref: 'Internal Note', refPath: 'child', path: 'internal-notes', label: 'internal notes' });

// Pre Save
Child.schema.pre('save', function(next) {
	'use strict';

	// TODO: Play with lowering quality to 0 and doubling the image size as an optimization technique
	this.galleryImage = this._.image.thumbnail(430,430,{ quality: 60 });
	this.detailImage = this._.image.thumbnail(200,200,{ quality: 60 });

	// Build the name string for better identification when linking through Relationship field types
	var firstName	= this.name.first,
		middleName	= (this.name.middle && this.name.middle.length > 0) ? ' ' + this.name.middle : '',
		lastName	= (this.name.last && this.name.last.length > 0) ? ' ' + this.name.last : ''

	this.name.full = firstName + middleName + lastName;
	// Create an identifying name for file uploads
	this.fileName = this.registrationNumber + '_' + this.name.first.toLowerCase();

	// TODO: Assign a registration number if one isn't assigned
	next();
});

// Define default columns in the admin interface and register the model
Child.defaultColumns = 'registrationNumber, name.full, ethnicity, legalStatus, gender';
Child.register();
<|endoftext|>


<commit_before>module.exports = {
  apps: [{
    name: 'davidpuerto.com',
    script: './app/build/index.js',
    watch: true,
    env: {
      'NODE_ENV': 'development',
    },
    env_production : {
       'NODE_ENV': 'production'
    }
  }],
  deploy: {
    production: {
      user: 'ec2-user',
      host: 'ec2-35-163-175-145.us-west-2.compute.amazonaws.com',
      key: '~/.ssh/dap.pem',
      ref: 'origin/master',
      repo: 'git@github.com:dapinitial/davidpuerto.com.git',
      path: '/home/ec2-user/davidpuerto.com',
      'post-deploy': 'npm install;npm run build;pm2 stop davidpuerto.com;npm run dev;pm2 startOrReload davidpuerto.com ecosystem.config.js'
    }
  }
}
<commit_msg>getting crafty with my post-deply ecosystem.config.js<commit_after>module.exports = {
  apps: [{
    name: 'davidpuerto.com',
    script: './app/build/index.js',
    watch: true,
    env: {
      'NODE_ENV': 'development',
    },
    env_production : {
       'NODE_ENV': 'production'
    }
  }],
  deploy: {
    production: {
      user: 'ec2-user',
      host: 'ec2-35-163-175-145.us-west-2.compute.amazonaws.com',
      key: '~/.ssh/dap.pem',
      ref: 'origin/master',
      repo: 'git@github.com:dapinitial/davidpuerto.com.git',
      path: '/home/ec2-user/davidpuerto.com',
      'post-deploy': 'npm install;npm run build;pm2 stop;killall -9 node;npm run dev;pm2 startOrReload ecosystem.config.js'
    }
  }
}
<|endoftext|>


<commit_before>const choo = require("choo");
const html = require("choo/html");
const http = require("choo/http");

const narrowsSchema = require("./narrows-schema").schema;
const model = require("prosemirror/dist/model"),
      Node = model.Node;
const extend = require("./extend");
const editor = require("./editor");

const MAX_BLURRINESS = 10;

const app = choo();

function getFragmentIdFromUrl(urlPath) {
    return urlPath.
        replace("/read/", "").
        replace(new RegExp("/.*"), "");
}
function getCharacterTokenFromUrl(urlPath) {
    return urlPath.
        replace(new RegExp("/$"), "").
        replace(new RegExp(".*/"), "");
}

function bumpVolume(audioEl) {
    audioEl.volume = Math.min(1, audioEl.volume + 0.02);

    if (audioEl.volume < 1) {
        setTimeout(function() {
            bumpVolume(audioEl);
        }, 100);
    }
}

app.model({
    state: {
        fragmentId: getFragmentIdFromUrl(location.pathname),
        fragment: null,
        characterToken: getCharacterTokenFromUrl(location.pathname),
        backgroundMusic: true,

        banner: null
    },
    reducers: {
        receiveFragmentData: (fragmentData, state) => {
            return extend(state, { fragment: fragmentData });
        },

        markNarrationAsStarted: (data, state) => {
            return extend(state, {
                started: true,
                musicPlaying: state.backgroundMusic
            });
        },

        pageScrolled: (data, state) => {
            const blurriness = Math.min(window.scrollY / 40,
                                        MAX_BLURRINESS);

            return extend(state, { backgroundBlurriness: blurriness });
        },

        updateReactionText: (data, state) => {
            return extend(state, { reaction: data.value });
        },

        toggleBackgroundMusic: (data, state) => {
            return extend(state, { backgroundMusic: !state.backgroundMusic });
        },

        toggleMusicPlaying: (data, state) => {
            return extend(state, { musicPlaying: !state.musicPlaying });
        },

        reactionSendingProblem: (data, state) => {
            return extend(
                state,
                { banner: {
                    type: "error",
                    text: "There was a problem sending your reaction!\n" +
                        "Maybe save the text somewhere just in case..."
                } }
            );
        },

        reactionSendingSuccess: (data, state) => {
            return extend(state, { banner: { type: "success",
                                             text: "Reaction registered"},
                                   reaction: "",
                                   reactionSent: true });
        }
    },
    effects: {
        getFragment: (data, state, send, done) => {
            http("/api/fragments/" + state.fragmentId + "/" + state.characterToken, (err, res, body) => {
                const response = JSON.parse(body);

                send("receiveFragmentData",
                     {title: response.title,
                      text: editor.importText(response.text),
                      audio: response.audio,
                      backgroundImage: response.backgroundImage},
                     done);
            });
        },

        startNarration: (data, state, send, done) => {
            if (state.backgroundMusic) {
                const audioEl = document.getElementById("background-music");
                audioEl.volume = 0;
                audioEl.play();
                bumpVolume(audioEl);
            }

            // First we need to make it appear on screen at all
            // (remove the "invisible" classname, which sets "display:
            // none") and then we'll remove the "transparent"
            // classname, which sets "opacity: 0". If we remove both
            // CSS properties at the same time, the opacity is not
            // animated.
            const fragmentContainer = document.getElementById("fragment-container");
            fragmentContainer.className = "transparent";

            send("markNarrationAsStarted", {}, done);
        },

        playPauseMusic: (data, state, send, done) => {
            const audioEl = document.getElementById("background-music");
            if (audioEl.paused) {
                audioEl.play();
            } else {
                audioEl.pause();
            }
            send("toggleMusicPlaying", {}, done);
        },

        sendReaction: (data, state, send, done) => {
            const url = "/api/reactions/" + state.fragmentId + "/" +
                      state.characterToken;

            if (!state.reaction) {
                done();
                return;
            }

            const xhr = new XMLHttpRequest();
            xhr.open("POST", url);
            xhr.setRequestHeader("Content-Type", "application/json");
            xhr.addEventListener("load", function() {
                const response = JSON.parse(this.responseText);
                if (this.status >= 400) {
                    send("reactionSendingProblem", {response: this}, done);
                    return;
                }

                send("reactionSendingSuccess", {}, done);
            });
            xhr.send(JSON.stringify({ text: state.reaction }));
        }
    },

    subscriptions: [
        (send, done) => {
            document.addEventListener("scroll", function(evt) {
                send("pageScrolled", window.scrollY, done);
            }, false);
        }
    ]
});

const loaderView = (state, prev, send) => html`

        ${state.fragment ? "" : "Loading…"}

        <button onclick=${() => send("startNarration")}>Start</button>

        <input id="music"
               type="checkbox"
               checked="${ state.backgroundMusic ? "checked" : "false" }"
               onclick=${ () => send("toggleBackgroundMusic") } />
        Background music

`;

function backgroundImageStyle(state) {
    const imageUrl = state.fragment ?
              ("/static/narrations/3/" + state.fragment.backgroundImage) : '';
    const filter = `blur(${ state.backgroundBlurriness || 0 }px)`;

    return `background-image: url(${ imageUrl }); ` +
        `-webkit-filter: ${ filter }; ` +
        `-moz-filter: ${ filter }; ` +
        `filter: ${ filter }`;
}

const bannerView = (banner) => html`

    ${ banner.text }

`;

const fragmentView = (state, prev, send) => html`

        ${ state.fragment ? state.fragment.title : 'Untitled' }

       { send("playPauseMusic"); }} />
      <audio id="background-music"
             src="${ state.fragment ? ("/static/narrations/3/" + state.fragment.audio) : '' }"
             loop="true"
             preload="${ state.backgroundMusic ? "auto" : "none" }"></audio>

        ${ state.fragment ? state.fragment.text.content.toDOM() : "" }

      ${ state.banner ? bannerView(state.banner) : "" }

        <textarea
           placeholder="How do you react? Try to consider several possibilities…"
           cols="80"
           rows="10"
           oninput=${ e => { send("updateReactionText", { value: e.target.value }); } }>${ state.reaction }</textarea>
        <button onclick=${ () => send("sendReaction") }>Send</button>

`;

const mainView = (state, prev, send) => html`
   send("getFragment")}>
    ${ state.started ? "" : loaderView(state, prev, send) }

    ${ fragmentView(state, prev, send) }

`;

app.router((route) => [
  route('/', mainView)
]);

const tree = app.start();
document.body.appendChild(tree);
<commit_msg>Add proper error messages when the fragment doesn't exist<commit_after>const choo = require("choo");
const html = require("choo/html");
const http = require("choo/http");

const narrowsSchema = require("./narrows-schema").schema;
const model = require("prosemirror/dist/model"),
      Node = model.Node;
const extend = require("./extend");
const editor = require("./editor");

const MAX_BLURRINESS = 10;

const app = choo();

function getFragmentIdFromUrl(urlPath) {
    return urlPath.
        replace("/read/", "").
        replace(new RegExp("/.*"), "");
}
function getCharacterTokenFromUrl(urlPath) {
    return urlPath.
        replace(new RegExp("/$"), "").
        replace(new RegExp(".*/"), "");
}

function bumpVolume(audioEl) {
    audioEl.volume = Math.min(1, audioEl.volume + 0.02);

    if (audioEl.volume < 1) {
        setTimeout(function() {
            bumpVolume(audioEl);
        }, 100);
    }
}

app.model({
    state: {
        fragmentId: getFragmentIdFromUrl(location.pathname),
        fragment: null,
        characterToken: getCharacterTokenFromUrl(location.pathname),
        backgroundMusic: true,

        banner: null
    },
    reducers: {
        receiveFragmentData: (fragmentData, state) => {
            return extend(state, { fragment: fragmentData });
        },

        fragmentDataFailure: (info, state) => {
            return extend(state, { error: `Failed fetching fragment, status code: ${ info.statusCode }` });
        },

        markNarrationAsStarted: (data, state) => {
            return extend(state, {
                started: true,
                musicPlaying: state.backgroundMusic
            });
        },

        pageScrolled: (data, state) => {
            const blurriness = Math.min(window.scrollY / 40,
                                        MAX_BLURRINESS);

            return extend(state, { backgroundBlurriness: blurriness });
        },

        updateReactionText: (data, state) => {
            return extend(state, { reaction: data.value });
        },

        toggleBackgroundMusic: (data, state) => {
            return extend(state, { backgroundMusic: !state.backgroundMusic });
        },

        toggleMusicPlaying: (data, state) => {
            return extend(state, { musicPlaying: !state.musicPlaying });
        },

        reactionSendingProblem: (data, state) => {
            return extend(
                state,
                { banner: {
                    type: "error",
                    text: "There was a problem sending your reaction!\n" +
                        "Maybe save the text somewhere just in case..."
                } }
            );
        },

        reactionSendingSuccess: (data, state) => {
            return extend(state, { banner: { type: "success",
                                             text: "Reaction registered"},
                                   reaction: "",
                                   reactionSent: true });
        }
    },
    effects: {
        getFragment: (data, state, send, done) => {
            http("/api/fragments/" + state.fragmentId + "/" + state.characterToken, (err, res, body) => {
                if (res.statusCode >= 400) {
                    send("fragmentDataFailure",
                         { statusCode: res.statusCode },
                         done);
                    return;
                }

                const response = JSON.parse(body);

                send("receiveFragmentData",
                     {title: response.title,
                      text: editor.importText(response.text),
                      audio: response.audio,
                      backgroundImage: response.backgroundImage},
                     done);
            });
        },

        startNarration: (data, state, send, done) => {
            if (state.backgroundMusic) {
                const audioEl = document.getElementById("background-music");
                audioEl.volume = 0;
                audioEl.play();
                bumpVolume(audioEl);
            }

            // First we need to make it appear on screen at all
            // (remove the "invisible" classname, which sets "display:
            // none") and then we'll remove the "transparent"
            // classname, which sets "opacity: 0". If we remove both
            // CSS properties at the same time, the opacity is not
            // animated.
            const fragmentContainer = document.getElementById("fragment-container");
            fragmentContainer.className = "transparent";

            send("markNarrationAsStarted", {}, done);
        },

        playPauseMusic: (data, state, send, done) => {
            const audioEl = document.getElementById("background-music");
            if (audioEl.paused) {
                audioEl.play();
            } else {
                audioEl.pause();
            }
            send("toggleMusicPlaying", {}, done);
        },

        sendReaction: (data, state, send, done) => {
            const url = "/api/reactions/" + state.fragmentId + "/" +
                      state.characterToken;

            if (!state.reaction) {
                done();
                return;
            }

            const xhr = new XMLHttpRequest();
            xhr.open("POST", url);
            xhr.setRequestHeader("Content-Type", "application/json");
            xhr.addEventListener("load", function() {
                const response = JSON.parse(this.responseText);
                if (this.status >= 400) {
                    send("reactionSendingProblem", {response: this}, done);
                    return;
                }

                send("reactionSendingSuccess", {}, done);
            });
            xhr.send(JSON.stringify({ text: state.reaction }));
        }
    },

    subscriptions: [
        (send, done) => {
            document.addEventListener("scroll", function(evt) {
                send("pageScrolled", window.scrollY, done);
            }, false);
        }
    ]
});

const loadingView = () => html`

Loading…

`;

const loadedView = (state, send) => html`

    <button onclick=${ () => send("startNarration") }>Start</button>

    <input id="music"
           type="checkbox"
           checked="${ state.backgroundMusic ? "checked" : "false" }"
           onclick=${ () => send("toggleBackgroundMusic") } />
    Background music

`;

const loaderView = (state, prev, send) => html`

      ${ state.fragment ? loadedView(state, send) : loadingView() }

`;

const errorView = (error, send) => html`

    ${ error }

`;

function backgroundImageStyle(state) {
    const imageUrl = state.fragment ?
              ("/static/narrations/3/" + state.fragment.backgroundImage) : '';
    const filter = `blur(${ state.backgroundBlurriness || 0 }px)`;

    return `background-image: url(${ imageUrl }); ` +
        `-webkit-filter: ${ filter }; ` +
        `-moz-filter: ${ filter }; ` +
        `filter: ${ filter }`;
}

const bannerView = (banner) => html`

    ${ banner.text }

`;

const fragmentView = (state, prev, send) => html`

        ${ state.fragment ? state.fragment.title : 'Untitled' }

       { send("playPauseMusic"); }} />
      <audio id="background-music"
             src="${ state.fragment ? ("/static/narrations/3/" + state.fragment.audio) : '' }"
             loop="true"
             preload="${ state.backgroundMusic ? "auto" : "none" }"></audio>

        ${ state.fragment ? state.fragment.text.content.toDOM() : "" }

      ${ state.banner ? bannerView(state.banner) : "" }

        <textarea
           placeholder="How do you react? Try to consider several possibilities…"
           cols="80"
           rows="10"
           oninput=${ e => { send("updateReactionText", { value: e.target.value }); } }>${ state.reaction }</textarea>
        <button onclick=${ () => send("sendReaction") }>Send</button>

`;

const mainView = (state, prev, send) => html`
   send("getFragment")}>
    ${ (!state.started && !state.error) ? loaderView(state, prev, send) : "" }
    ${ state.error ? errorView(state.error, send) : "" }

    ${ fragmentView(state, prev, send) }

`;

app.router((route) => [
  route('/', mainView)
]);

const tree = app.start();
document.body.appendChild(tree);
<|endoftext|>


<commit_before>const __extends = (this && this.__extends) || function (d, b) {
  for (const p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  function __() { this.constructor = d; }
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
const modal = require('./modal');

const Server = class Server {
  constructor(kind) {
    this.kind = kind;
    this.params = { kind };
    this.ajax = new AjaxSet.Resources('server_status');
    this.ajax.add_member('start', 'POST', 'kind');
    this.ajax.add_member('stop', 'POST', 'kind');
    this.ajax.add_member('status', 'POST', 'kind');
  }

  static is_inprogress(state) {
    return !(state === 'running' || state === 'stopped');
  }

  msgs() {
    return t(`js.server_status.${this.kind}`);
  }

  start() {
    this.ajax.start(this.params);
  }

  stop() {
    this.ajax.stop(this.params);
  }

  status(background) {
    const p = Object.assign({ background }, this.params);
    return this.ajax.status(p);
  }

  watch(callback) {
    const ws = ws_connector('server_status', this.kind);
    ws.onmessage = (msg) => {
      callback(msg.data);
    };
  }
};

const App = (function (_super) {
  __extends(App, _super);
  function App(model, el) {
    _super.call(this);
    this.model = model;
    this._init({
      el,
      data: { state: this.state },
      template: App.TEMPLATE_ID,
      methods: {
        start() {
          const _this = this;
          modal.Confirm(this.model.msgs().title, this.model.msgs().confirm_start).done(() => {
            _this.model.start();
          });
        },
        stop() {
          const _this = this;
          modal.Confirm(this.model.msgs().title, this.model.msgs().confirm_stop).done(() => {
            _this.model.stop();
          });
        },
        status(background) {
          const _this = this;
          this.model.status(background).done((state) => {
            _this.state = state;
            if (background || _this.is_inprogress) {
              _this.model.watch((w_state) => {
                _this.state = w_state;
              });
            }
          });
        },
        toggle() {
          if (this.running) {
            this.stop();
          } else if (this.stopped) {
            this.start();
          }
        },
      },
      computed: {
        running() { return this.state === 'running'; },
        stopped() { return this.state === 'stopped'; },
        is_inprogress() { return Server.is_inprogress(this.state); },
        status_text() {
          let res = `${_.capitalize(this.model.kind)} Server `;
          if (this.running) {
            res += `is ${this.state}.`;
          } else if (this.stopped) {
            res += `was ${this.state}.`;
          } else if (this.is_inprogress) {
            res += `${this.state}...`;
          }
          return res;
        },
        btn_class() {
          if (this.running) {
            return 'btn-success';
          }
          if (this.stopped) {
            return 'btn-default';
          } if (this.is_inprogress) {
            return 'btn-warning';
          }
        },
        tooltip() {
          if (this.is_inprogress) {
            return '';
          }
          return this.model.msgs().tooltip;
        },
      },
      created() {
        console.log(this);
        this.status(true);
      },
    });
  }
  App.TEMPLATE_ID = '#toggle-button-template';
  return App;
}(Vue));
function Build(kind) {
  const el = document.createElement('div');
  const parent = document.querySelector(App.TEMPLATE_ID).parentElement;
  parent.appendChild(el);
  parent.appendChild(document.createTextNode('\n'));
  new App(new Server(kind), el);
}
function Available() {
  return !!document.querySelector(App.TEMPLATE_ID);
}
function Do() {
  if (!Available()) {
    return;
  }
  Build('zabbix');
}
exports.Do = Do;
<commit_msg>Fix: server_status.jsをリファクタリング<commit_after>const __extends = (this && this.__extends) || function (d, b) {
  for (const p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  function __() { this.constructor = d; }
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
const modal = require('./modal');

const Server = class Server {
  constructor(kind) {
    this.kind = kind;
    this.params = { kind };
    this.ajax = new AjaxSet.Resources('server_status');
    this.ajax.add_member('start', 'POST', 'kind');
    this.ajax.add_member('stop', 'POST', 'kind');
    this.ajax.add_member('status', 'POST', 'kind');
  }

  static isInprogress(state) {
    return !(state === 'running' || state === 'stopped');
  }

  msgs() {
    return t(`js.server_status.${this.kind}`);
  }

  start() {
    this.ajax.start(this.params);
  }

  stop() {
    this.ajax.stop(this.params);
  }

  status(background) {
    const p = Object.assign({ background }, this.params);
    return this.ajax.status(p);
  }

  watch(callback) {
    const ws = ws_connector('server_status', this.kind);
    ws.onmessage = (msg) => {
      callback(msg.data);
    };
  }
};

const App = ((_super) => {
  __extends(App, _super);
  function App(model, el) {
    _super.call(this);
    this.model = model;
    this._init({
      el,
      data: { state: this.state },
      template: App.TEMPLATE_ID,
      methods: {
        start() {
          const self = this;
          modal.Confirm(this.model.msgs().title, this.model.msgs().confirm_start).done(() => {
            self.model.start();
          });
        },
        stop() {
          const self = this;
          modal.Confirm(this.model.msgs().title, this.model.msgs().confirm_stop).done(() => {
            self.model.stop();
          });
        },
        status(background) {
          const self = this;
          this.model.status(background).done((state) => {
            self.state = state;
            if (background || self.is_inprogress) {
              self.model.watch((wState) => {
                self.state = wState;
              });
            }
          });
        },
        toggle() {
          if (this.running) {
            this.stop();
          } else if (this.stopped) {
            this.start();
          }
        },
        serviceName() {
          const { kind } = this.model;
          return kind.charAt(0).toUpperCase() + kind.slice(1);
        },
      },
      computed: {
        running() { return this.state === 'running'; },
        stopped() { return this.state === 'stopped'; },
        is_inprogress() { return Server.isInprogress(this.state); },
        status_text() {
          let res = `${this.serviceName()} Server `;
          if (this.running) {
            res += `is ${this.state}.`;
          } else if (this.stopped) {
            res += `was ${this.state}.`;
          } else if (this.is_inprogress) {
            res += `${this.state}...`;
          }
          return res;
        },
        btn_class() {
          if (this.running) {
            return 'btn-success';
          }
          if (this.stopped) {
            return 'btn-default';
          } if (this.is_inprogress) {
            return 'btn-warning';
          }
        },
        tooltip() {
          if (this.is_inprogress) {
            return '';
          }
          return this.model.msgs().tooltip;
        },
      },
      created() {
        console.log(this);
        this.status(true);
      },
    });
  }
  App.TEMPLATE_ID = '#toggle-button-template';
  return App;
})(Vue);
function Build(kind) {
  const el = document.createElement('div');
  const parent = document.querySelector(App.TEMPLATE_ID).parentElement;
  parent.appendChild(el);
  parent.appendChild(document.createTextNode('\n'));
  new App(new Server(kind), el);
}
function Available() {
  return !!document.querySelector(App.TEMPLATE_ID);
}
function Do() {
  if (!Available()) {
    return;
  }
  Build('zabbix');
}
exports.Do = Do;
<|endoftext|>