<commit_before>/**
 * @flow
 */

import {
	getLocalToken,
	resetLocalToken
} from 'api/LocalStorageCookiesSvc'
import _ from 'lodash'

/**
 * Create request wrapper for certain method
 * @param  {String} method - Request method
 * @return {Function}
 */
const requestWrapper = (
	method: 'GET' | 'POST' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'PUT' | 'PATCH'
) => {
	/**
	 * Creates request to `url` with `data`
	 * @param  {String} 	url        				Request URL
	 * @param  {Object} 	[data= null]			Data for Request
	 * @param  {Object} 	[options= {}]			Additional options
	 * @param  {Function} [cb = (a) => a]		Transform request before it will be sent
	 * @return {Object}             				Request response
	 */
	return async (
		url: string,
		data: Object | null = null,
		options: Object = {},
		cb: (request: Object) => Object = a => a
	) => {
		// get decorated url and request params
		const {URL, request} = decorateRequest({method, url, data, options, cb})
		// create request!
		return fetch(URL, request)
			.then(checkStatus)
			.then(parseJSON)
			.catch((err: string) => {
				console.error(err)
				return err
			})
	}
}

/**
 * middlewares
 * 1. parse response
 * 2. add "ok" property to result
 * 3. return request result
 * @param  {Object} res - Response from resource
 * @return {Object} response result with "ok" property
 */
async function parseJSON (res: Response): Object {
	let json: Object
	try {
		json = await res.json()
	} catch (e) {
		if (res.status === 204) {
			return {ok: true, data: {}}
		}
		return {ok: false}
	}
	if (!res.ok) {
		return {data: json, ok: false}
	}
	return {data: json, ok: true}
}

/**
 * Checks response status
 * @param  {Object} response - Response
 * @return {Object}          - Response
 */
function checkStatus (response: Response): Response {
	const {status} = response
	if (status >= 200 && status < 300) {
		// Everything is ok
	} else if (status >= 300 && status < 400) {
		// 300 Multiple Choices
		// 301 - Moved Permanently,
		// 302 - Found, Moved Temporarily
		// 304 - not modified
		// 307 - Temporary Redirect
	} else if (status === 400) {
		// Probably is a validation error
	} else if (status === 403 || status === 401) {
		// 401 - Forbidden
		// 403 - Unauthorized
		// remove local token in this case
		resetLocalToken()
	} else if (status === 404) {
		// Not Found
	} else if (status >= 500) {
		// Server error
	}
	return response
}

/**
 * Create
 * @param  {String} method 			 -	Request method
 * @param  {String} url 				 -  Request URL
 * @param  {Object} [data= null] -	Data for Request
 * @return {Object}        			 - 	Decorated request params
 */
function decorateRequest ({method, url, data, options, cb}): Object {
	// Default params for fetch = method + (Content-Type)
	const defaults = {
		method,
		headers: {}
	}
	const token: string | null = getLocalToken()
	const isRequestToExternalResource = /(http|https):\/\//.test(url)
	const URL = isRequestToExternalResource ? url : process.env.BASE_API + url

	const requestAuthDecoration =
		!isRequestToExternalResource && token
			? {headers: {Authorization: `JWT ${token}`}}
			: {}

	const requestHeadersDataDecoration = getHeaderDataDecoration(data)

	const request = _.merge(
		{},
		defaults,
		requestAuthDecoration,
		requestHeadersDataDecoration
	)

	if (!isRequestToExternalResource) {
		console.log(`Request ${url} was sent to our domain`, request)
	} else {
		console.log(`Request ${url} was sent to external domain`, request)
	}

	return {
		request,
		URL
	}
}

function getHeaderDataDecoration (data): Object {
	const requesDataDecoration = data ? {body: JSON.stringify(data)} : {}

	const requestContentTypeDecoration =
		data instanceof FormData
			? {}
			: {headers: {'Content-Type': 'application/json; charset=UTF-8'}}

	return {...requesDataDecoration, ...requestContentTypeDecoration}
}

export const get = requestWrapper('GET')
export const post = requestWrapper('POST')
export const put = requestWrapper('PUT')
export const patch = requestWrapper('PATCH')
export const del = requestWrapper('DELETE')

// USAGE:
// get('https://www.google.com', options)
//
// post('https://www.google.com', data, options)
<commit_msg>chore(xhr_wrapper): add comment<commit_after>/**
 * @flow
 */

import {
	getLocalToken,
	resetLocalToken
} from 'api/LocalStorageCookiesSvc'
import _ from 'lodash'

/**
 * Create request wrapper for certain method
 * @param  {String} method - Request method
 * @return {Function}
 */
const requestWrapper = (
	method: 'GET' | 'POST' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'PUT' | 'PATCH'
) => {
	/**
	 * Creates request to `url` with `data`
	 * @param  {String} 	url        				Request URL
	 * @param  {Object} 	[data= null]			Data for Request
	 * @param  {Object} 	[options= {}]			Additional options
	 * @param  {Function} [cb = (a) => a]		Transform request before it will be sent
	 * @return {Object}             				Request response
	 */
	return async (
		url: string,
		data: Object | null = null,
		options: Object = {},
		cb: (request: Object) => Object = a => a
	) => {
		// get decorated url and request params
		const {URL, request} = decorateRequest({method, url, data, options, cb})
		// create request!
		return fetch(URL, request)
			.then(checkStatus)
			.then(parseJSON)
			.catch((err: string) => {
				console.error(err)
				return err
			})
	}
}

/**
 * middlewares
 * 1. parse response
 * 2. add "ok" property to result
 * 3. return request result
 * @param  {Object} res - Response from resource
 * @return {Object} response result with "ok" property
 */
async function parseJSON (res: Response): Object {
	let json: Object
	// status response field in return object
	try {
		json = await res.json()
	} catch (e) {
		if (res.status === 204) {
			return {ok: true, data: {}}
		}
		return {ok: false}
	}
	if (!res.ok) {
		return {data: json, ok: false}
	}
	return {data: json, ok: true}
}

/**
 * Checks response status
 * @param  {Object} response - Response
 * @return {Object}          - Response
 */
function checkStatus (response: Response): Response {
	const {status} = response
	if (status >= 200 && status < 300) {
		// Everything is ok
	} else if (status >= 300 && status < 400) {
		// 300 Multiple Choices
		// 301 - Moved Permanently,
		// 302 - Found, Moved Temporarily
		// 304 - not modified
		// 307 - Temporary Redirect
	} else if (status === 400) {
		// Probably is a validation error
	} else if (status === 403 || status === 401) {
		// 401 - Forbidden
		// 403 - Unauthorized
		// remove local token in this case
		resetLocalToken()
	} else if (status === 404) {
		// Not Found
	} else if (status >= 500) {
		// Server error
	}
	return response
}

/**
 * Create
 * @param  {String} method 			 -	Request method
 * @param  {String} url 				 -  Request URL
 * @param  {Object} [data= null] -	Data for Request
 * @return {Object}        			 - 	Decorated request params
 */
function decorateRequest ({method, url, data, options, cb}): Object {
	// Default params for fetch = method + (Content-Type)
	const defaults = {
		method,
		headers: {}
	}
	const token: string | null = getLocalToken()
	const isRequestToExternalResource = /(http|https):\/\//.test(url)
	const URL = isRequestToExternalResource ? url : process.env.BASE_API + url

	const requestAuthDecoration =
		!isRequestToExternalResource && token
			? {headers: {Authorization: `JWT ${token}`}}
			: {}

	const requestHeadersDataDecoration = getHeaderDataDecoration(data)

	const request = _.merge(
		{},
		defaults,
		requestAuthDecoration,
		requestHeadersDataDecoration
	)

	if (!isRequestToExternalResource) {
		console.log(`Request ${url} was sent to our domain`, request)
	} else {
		console.log(`Request ${url} was sent to external domain`, request)
	}

	return {
		request,
		URL
	}
}

function getHeaderDataDecoration (data): Object {
	const requesDataDecoration = data ? {body: JSON.stringify(data)} : {}

	const requestContentTypeDecoration =
		data instanceof FormData
			? {}
			: {headers: {'Content-Type': 'application/json; charset=UTF-8'}}

	return {...requesDataDecoration, ...requestContentTypeDecoration}
}

export const get = requestWrapper('GET')
export const post = requestWrapper('POST')
export const put = requestWrapper('PUT')
export const patch = requestWrapper('PATCH')
export const del = requestWrapper('DELETE')

// USAGE:
// get('https://www.google.com', options)
//
// post('https://www.google.com', data, options)
<|endoftext|>


<commit_before>import {
  isExisty,
} from '../lib/helpers';
import gravity from '../lib/loaders/gravity';
import cached from './fields/cached';
import date from './fields/date';
import markdown from './fields/markdown';
import Artist from './artist';
import Partner from './partner';
import Fair from './fair';
import Artwork from './artwork';
import Location from './location';
import Image from './image';
import PartnerShowEventType from './partner_show_event';
import {
  GraphQLObjectType,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInt,
  GraphQLBoolean,
} from 'graphql';

const kind = ({ artists, fair }) => {
  if (isExisty(fair)) return 'fair';
  if (artists.length > 1) return 'group';
  if (artists.length === 1) return 'solo';
};

const PartnerShowType = new GraphQLObjectType({
  name: 'PartnerShow',
  fields: () => ({
    cached,
    _id: {
      type: GraphQLString,
    },
    id: {
      type: GraphQLString,
    },
    href: {
      type: GraphQLString,
      resolve: ({ id }) => `/show/${id}`,
    },
    kind: {
      type: GraphQLString,
      resolve: (show) => {
        if (show.artists) return kind(show);
        return gravity(`partner/${show.partner.id}/show/${show.id}`).then(kind);
      },
    },
    name: {
      type: GraphQLString,
      description: 'The exhibition title',
    },
    description: {
      type: GraphQLString,
    },
    displayable: {
      type: GraphQLBoolean,
    },
    press_release: markdown(),
    start_at: date,
    end_at: date,
    artists: {
      type: new GraphQLList(Artist.type),
      resolve: ({ artists }) => artists,
    },
    partner: {
      type: Partner.type,
      resolve: ({ partner }) => partner,
    },
    fair: {
      type: Fair.type,
      resolve: ({ fair }) => fair,
    },
    location: {
      type: Location.type,
      resolve: ({ location, fair_location }) => location || fair_location,
    },
    status: {
      type: GraphQLString,
    },
    events: {
      type: new GraphQLList(PartnerShowEventType),
      resolve: ({ events }) => events,
    },
    artworks: {
      type: new GraphQLList(Artwork.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of artworks to return',
        },
        published: {
          type: GraphQLBoolean,
          defaultValue: true,
        },
        page: {
          type: GraphQLInt,
        },
      },
      resolve: (show, options) => {
        return gravity(`partner/${show.partner.id}/show/${show.id}/artworks`, options);
      },
    },
    cover_image: {
      type: Image.type,
      resolve: ({ image_versions, image_url }) => Image.resolve({ image_versions, image_url }),
    },
    images: {
      type: new GraphQLList(Image.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of images to return',
        },
        default: {
          type: GraphQLBoolean,
          description: 'Pass true/false to include cover or not',
        },
        page: {
          type: GraphQLInt,
        },
      },
      resolve: ({ id }, options) => {
        return gravity(`partner_show/${id}/images`, options)
          .then(Image.resolve);
      },
    },
  }),
});

const PartnerShow = {
  type: PartnerShowType,
  description: 'A Partner Show',
  args: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The slug or ID of the PartnerShow',
    },
  },
  resolve: (root, { id }) => {
    return gravity(`show/${id}`)
      .then(show => {
        if (!show.displayable) return new Error('Show Not Found');
        return show;
      });
  },
};

export default PartnerShow;
<commit_msg>fallback partnershow cover image to artwork image<commit_after>import {
  isExisty,
} from '../lib/helpers';
import _ from 'lodash';
import gravity from '../lib/loaders/gravity';
import cached from './fields/cached';
import date from './fields/date';
import markdown from './fields/markdown';
import Artist from './artist';
import Partner from './partner';
import Fair from './fair';
import Artwork from './artwork';
import Location from './location';
import Image from './image';
import PartnerShowEventType from './partner_show_event';
import {
  GraphQLObjectType,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInt,
  GraphQLBoolean,
} from 'graphql';

const kind = ({ artists, fair }) => {
  if (isExisty(fair)) return 'fair';
  if (artists.length > 1) return 'group';
  if (artists.length === 1) return 'solo';
};

const PartnerShowType = new GraphQLObjectType({
  name: 'PartnerShow',
  fields: () => ({
    cached,
    _id: {
      type: GraphQLString,
    },
    id: {
      type: GraphQLString,
    },
    href: {
      type: GraphQLString,
      resolve: ({ id }) => `/show/${id}`,
    },
    kind: {
      type: GraphQLString,
      resolve: (show) => {
        if (show.artists) return kind(show);
        return gravity(`partner/${show.partner.id}/show/${show.id}`).then(kind);
      },
    },
    name: {
      type: GraphQLString,
      description: 'The exhibition title',
    },
    description: {
      type: GraphQLString,
    },
    displayable: {
      type: GraphQLBoolean,
    },
    press_release: markdown(),
    start_at: date,
    end_at: date,
    artists: {
      type: new GraphQLList(Artist.type),
      resolve: ({ artists }) => artists,
    },
    partner: {
      type: Partner.type,
      resolve: ({ partner }) => partner,
    },
    fair: {
      type: Fair.type,
      resolve: ({ fair }) => fair,
    },
    location: {
      type: Location.type,
      resolve: ({ location, fair_location }) => location || fair_location,
    },
    status: {
      type: GraphQLString,
    },
    events: {
      type: new GraphQLList(PartnerShowEventType),
      resolve: ({ events }) => events,
    },
    artworks: {
      type: new GraphQLList(Artwork.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of artworks to return',
        },
        published: {
          type: GraphQLBoolean,
          defaultValue: true,
        },
        page: {
          type: GraphQLInt,
        },
      },
      resolve: (show, options) => {
        return gravity(`partner/${show.partner.id}/show/${show.id}/artworks`, options);
      },
    },
    cover_image: {
      type: Image.type,
      resolve: ({ id, partner, image_versions, image_url }) => {
        if (image_versions && image_versions.length && image_url) {
          return Image.resolve({ image_versions, image_url });
        }
        return gravity(`partner/${partner.id}/show/${id}/artworks`, { size: 1, published: true })
          .then(artworks => {
            const { images } = artworks[0];
            return Image.resolve(_.find(images, { is_default: true }) || _.first(images));
          });
      },
    },
    images: {
      type: new GraphQLList(Image.type),
      args: {
        size: {
          type: GraphQLInt,
          description: 'Number of images to return',
        },
        default: {
          type: GraphQLBoolean,
          description: 'Pass true/false to include cover or not',
        },
        page: {
          type: GraphQLInt,
        },
      },
      resolve: ({ id }, options) => {
        return gravity(`partner_show/${id}/images`, options)
          .then(Image.resolve);
      },
    },
  }),
});

const PartnerShow = {
  type: PartnerShowType,
  description: 'A Partner Show',
  args: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The slug or ID of the PartnerShow',
    },
  },
  resolve: (root, { id }) => {
    return gravity(`show/${id}`)
      .then(show => {
        if (!show.displayable) return new Error('Show Not Found');
        return show;
      });
  },
};

export default PartnerShow;
<|endoftext|>


<commit_before>'use strict';

module.exports = {
    '.ams.aam.ExConversationChangeNotification': (msg, agent) => {
        msg.type = 'cqm.ExConversationChangeNotification';
        msg.body.changes.forEach(c => {
            delete c.result.effectiveTTR;
            delete c.result.lastUpdateTime;
            delete c.result.numberOfunreadMessages;
            let cd = c.result.conversationDetails;
            delete cd.convId;
            delete cd.dialogs;
            delete cd.note;
            delete cd.brandId;
            delete cd.firstConversation;
            delete cd.groupId;
            delete cd.csatRate;
            Object.keys(cd.participants).forEach(role =>
                cd.participants[role].filter(id => id === agent.__oldAgentId).forEach(() =>
                    cd.__myRole = role));
            // getMyRole is deprecated. Please use sdk.agentId
            cd.getMyRole = () => cd.__myRole;
            cd.participants = [];
            Object.keys(cd.participantsPId).forEach(role =>
                cd.participantsPId[role].forEach(id =>
                    cd.participants.push({id: id, role: role})));
            delete cd.participantsPId;
        });
        return msg;
    },
    '.ams.routing.SetAgentState': (msg, agent) => {
        msg.body.channels = ['MESSAGING'];
        msg.body.agentUserId = agent.__oldAgentId;
        return msg;
    },
    '.ams.cm.UpdateConversationField': (msg, agent) => {
        msg.body.conversationField.forEach(f => {
            if (f.field === 'ParticipantsChange') {
                f.userId = agent.__oldAgentId;
            }
        });
        return msg;
    },
    '.ams.routing.SubscribeRoutingTasks': (msg, agent) => {
        msg.body.channelType = 'MESSAGING';
        msg.body.agentId = agent.__oldAgentId;
        msg.body.brandId = agent.accountId;
        return msg;
    },
    '.ams.routing.RingUpdated': (msg) => {
        msg.type = 'deprecated';
        delete msg.body; // deprecated notification
        return msg;
    },
    '.ams.aam.SubscribeExConversations': (msg, agent) => {
        msg.body.agentIds = msg.body.agentIds ? msg.body.agentIds
                .map(id => id === agent.agentId ? agent.__oldAgentId : id) : undefined;
        return msg;
    },
    '.ams.routing.RoutingTaskNotification': (msg) => {
        msg.body.changes.forEach(c => {
            delete c.result.routingTaskId;
            delete c.result.assignedAgentId;
            delete c.result.brandId;
            c.result.ringsDetails.forEach(rd => {
                delete rd.brandId;
                delete rd.convId;
                delete rd.consumerId;
                delete rd.skillId;
            });
        });
        msg.type = 'routing.RoutingTaskNotification';
        return msg;
    },
    '.ams.userprofile.GetUserProfile$Response': (msg) => {
        let SDEs = [];
        let authData = msg.body.authenticatedData;
        let privateData = msg.body.privateData || {};
        if (authData && authData.lp_sdes) {
            msg.body.authenticatedData.lp_sdes.forEach(sde => {
                sde.auth = {};
                SDEs.push(sde);
            });
        }
        let ctmrinfo = {
            type: 'ctmrinfo',
            info: {}
        };
        if (privateData.mobileNum) {
            ctmrinfo.info.imei = privateData.mobileNum;
        }
        if (privateData.userId) {
            ctmrinfo.info.customerId = privateData.userId;
        }
        if (Object.keys(ctmrinfo.info).length > 0) {
            SDEs.push(ctmrinfo);
        }

        let personalInfo = {
            type: 'personal',
            personal: {}
        };
        if (msg.body.firstName) {
            personalInfo.personal.firstname = msg.body.firstName;
        }
        if (msg.body.lastName) {
            personalInfo.personal.lastname = msg.body.lastName;
        }
        if (privateData.email || privateData.mobileNum) {
            personalInfo.personal.contacts = [{
                    email: privateData.email,
                    phone: privateData.mobileNum
                }];
        }
        if (Object.keys(personalInfo.personal).length > 0) {
            SDEs.push(personalInfo);
        }

        delete msg.body;
        msg.body = SDEs;
        return msg;
    },
    'ms.SubscribeMessagingEvents': (msg) => {
        // TODO: recored subscribed conversations.
        // agent.subscribed = agent.subscribed || {};
        // agent.subscribed[msg.body.dialogId] = true;
        msg.type = '.ams.ms.QueryMessages';
        msg.body.newerThanSequence = msg.fromSeq || 0;
        return msg;
    },
    '.ams.ms.QueryMessages$Response': (msg, agent) => {
        if (msg.body.length > 0) {
            const dialogId = msg.body[0].dialogId;
            msg.body.forEach(c => {
                c.__isMe = c.originatorId === agent.__oldAgentId;
                // isMe is deprecated. Please use sdk.agentId
                c.isMe = () => c.__isMe;
                c.originatorId = c.originatorPId;
                delete c.originatorPId;
            });
            agent._handleNotification({
                kind: 'notification',
                type: 'ms.MessagingEventNotification',
                body: {dialogId: dialogId, changes: msg.body}
            });
        }
        delete msg.body;
        msg.type = 'GenericSubscribeResponse';
        return msg;
    },
    '.ams.ms.OnlineEventDistribution': (msg, agent) => {
        // TODO: filter non subscribed notifications.
        msg.type = 'ms.MessagingEventNotification';
        msg.body.__isMe = msg.body.originatorId === agent.__oldAgentId;
        msg.body.originatorId = msg.body.originatorPId;
        delete msg.body.originatorPId;
        msg.body = {dialogId: msg.body.dialogId, changes: [msg.body]};
        const c = msg.body.changes[0];
        c.isMe = () => c.__isMe;
        return msg;
    },
    '.ams.cm.AgentRequestConversation': (msg) => {
        msg.body.channelType = 'MESSAGING';
        return msg;
    },
    '.ams.routing.SubscribeAgentsState': (msg, agent) => {
        msg.body.brandId = agent.accountId;
        msg.body.agentId = agent.__oldAgentId;
        return msg;
    },
    '.ams.routing.AgentStateNotification': (msg) => {
        msg.type = 'routing.AgentStateNotification';
        msg.body.changes.forEach(c => {
            delete c.result.agentUserId; // remove old id. Still don't have new uuid.
        });
        return msg;
    }
};
<commit_msg>exposed firstConversation - will be deprecated<commit_after>'use strict';

module.exports = {
    '.ams.aam.ExConversationChangeNotification': (msg, agent) => {
        msg.type = 'cqm.ExConversationChangeNotification';
        msg.body.changes.forEach(c => {
            delete c.result.effectiveTTR;
            delete c.result.lastUpdateTime;
            delete c.result.numberOfunreadMessages;
            let cd = c.result.conversationDetails;
            delete cd.convId;
            delete cd.dialogs;
            delete cd.note;
            delete cd.brandId;
            // delete cd.firstConversation;
            delete cd.groupId;
            delete cd.csatRate;
            Object.keys(cd.participants).forEach(role =>
                cd.participants[role].filter(id => id === agent.__oldAgentId).forEach(() =>
                    cd.__myRole = role));
            // getMyRole is deprecated. Please use sdk.agentId
            cd.getMyRole = () => cd.__myRole;
            cd.participants = [];
            Object.keys(cd.participantsPId).forEach(role =>
                cd.participantsPId[role].forEach(id =>
                    cd.participants.push({id: id, role: role})));
            delete cd.participantsPId;
        });
        return msg;
    },
    '.ams.routing.SetAgentState': (msg, agent) => {
        msg.body.channels = ['MESSAGING'];
        msg.body.agentUserId = agent.__oldAgentId;
        return msg;
    },
    '.ams.cm.UpdateConversationField': (msg, agent) => {
        msg.body.conversationField.forEach(f => {
            if (f.field === 'ParticipantsChange') {
                f.userId = agent.__oldAgentId;
            }
        });
        return msg;
    },
    '.ams.routing.SubscribeRoutingTasks': (msg, agent) => {
        msg.body.channelType = 'MESSAGING';
        msg.body.agentId = agent.__oldAgentId;
        msg.body.brandId = agent.accountId;
        return msg;
    },
    '.ams.routing.RingUpdated': (msg) => {
        msg.type = 'deprecated';
        delete msg.body; // deprecated notification
        return msg;
    },
    '.ams.aam.SubscribeExConversations': (msg, agent) => {
        msg.body.agentIds = msg.body.agentIds ? msg.body.agentIds
                .map(id => id === agent.agentId ? agent.__oldAgentId : id) : undefined;
        return msg;
    },
    '.ams.routing.RoutingTaskNotification': (msg) => {
        msg.body.changes.forEach(c => {
            delete c.result.routingTaskId;
            delete c.result.assignedAgentId;
            delete c.result.brandId;
            c.result.ringsDetails.forEach(rd => {
                delete rd.brandId;
                delete rd.convId;
                delete rd.consumerId;
                delete rd.skillId;
            });
        });
        msg.type = 'routing.RoutingTaskNotification';
        return msg;
    },
    '.ams.userprofile.GetUserProfile$Response': (msg) => {
        let SDEs = [];
        let authData = msg.body.authenticatedData;
        let privateData = msg.body.privateData || {};
        if (authData && authData.lp_sdes) {
            msg.body.authenticatedData.lp_sdes.forEach(sde => {
                sde.auth = {};
                SDEs.push(sde);
            });
        }
        let ctmrinfo = {
            type: 'ctmrinfo',
            info: {}
        };
        if (privateData.mobileNum) {
            ctmrinfo.info.imei = privateData.mobileNum;
        }
        if (privateData.userId) {
            ctmrinfo.info.customerId = privateData.userId;
        }
        if (Object.keys(ctmrinfo.info).length > 0) {
            SDEs.push(ctmrinfo);
        }

        let personalInfo = {
            type: 'personal',
            personal: {}
        };
        if (msg.body.firstName) {
            personalInfo.personal.firstname = msg.body.firstName;
        }
        if (msg.body.lastName) {
            personalInfo.personal.lastname = msg.body.lastName;
        }
        if (privateData.email || privateData.mobileNum) {
            personalInfo.personal.contacts = [{
                    email: privateData.email,
                    phone: privateData.mobileNum
                }];
        }
        if (Object.keys(personalInfo.personal).length > 0) {
            SDEs.push(personalInfo);
        }

        delete msg.body;
        msg.body = SDEs;
        return msg;
    },
    'ms.SubscribeMessagingEvents': (msg) => {
        // TODO: recored subscribed conversations.
        // agent.subscribed = agent.subscribed || {};
        // agent.subscribed[msg.body.dialogId] = true;
        msg.type = '.ams.ms.QueryMessages';
        msg.body.newerThanSequence = msg.fromSeq || 0;
        return msg;
    },
    '.ams.ms.QueryMessages$Response': (msg, agent) => {
        if (msg.body.length > 0) {
            const dialogId = msg.body[0].dialogId;
            msg.body.forEach(c => {
                c.__isMe = c.originatorId === agent.__oldAgentId;
                // isMe is deprecated. Please use sdk.agentId
                c.isMe = () => c.__isMe;
                c.originatorId = c.originatorPId;
                delete c.originatorPId;
            });
            agent._handleNotification({
                kind: 'notification',
                type: 'ms.MessagingEventNotification',
                body: {dialogId: dialogId, changes: msg.body}
            });
        }
        delete msg.body;
        msg.type = 'GenericSubscribeResponse';
        return msg;
    },
    '.ams.ms.OnlineEventDistribution': (msg, agent) => {
        // TODO: filter non subscribed notifications.
        msg.type = 'ms.MessagingEventNotification';
        msg.body.__isMe = msg.body.originatorId === agent.__oldAgentId;
        msg.body.originatorId = msg.body.originatorPId;
        delete msg.body.originatorPId;
        msg.body = {dialogId: msg.body.dialogId, changes: [msg.body]};
        const c = msg.body.changes[0];
        c.isMe = () => c.__isMe;
        return msg;
    },
    '.ams.cm.AgentRequestConversation': (msg) => {
        msg.body.channelType = 'MESSAGING';
        return msg;
    },
    '.ams.routing.SubscribeAgentsState': (msg, agent) => {
        msg.body.brandId = agent.accountId;
        msg.body.agentId = agent.__oldAgentId;
        return msg;
    },
    '.ams.routing.AgentStateNotification': (msg) => {
        msg.type = 'routing.AgentStateNotification';
        msg.body.changes.forEach(c => {
            delete c.result.agentUserId; // remove old id. Still don't have new uuid.
        });
        return msg;
    }
};
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

Ext.define('Traccar.view.Map', {
    extend: 'Ext.form.Panel',
    xtype: 'mapView',

    requires: [
        'Traccar.view.MapController'
    ],

    controller: 'map',

    title: Strings.mapTitle,
    layout: 'fit',

    getMap: function () {
        return this.map;
    },

    getMapView: function () {
        return this.mapView;
    },

    getVectorSource: function () {
        return this.vectorSource;
    },

    listeners: {
        afterrender: function () {
            var user, server, layer, type, bingKey, vectorLayer, lat, lon, zoom;

            user = Traccar.app.getUser();
            server = Traccar.app.getServer();

            type = user.get('map') || server.get('map');
            bingKey = server.get('bingKey');

            if (type === 'custom') {
                layer = new ol.layer.Tile({
                    source: new ol.source.XYZ({
                        url: server.get('mapUrl')
                    })
                });
            } else if (type === 'bingRoad') {
                layer = new ol.layer.Tile({
                    source: new ol.source.BingMaps({
                        key: bingKey,
                        imagerySet: 'Road'
                    })
                });
            } else if (type === 'bingAerial') {
                layer = new ol.layer.Tile({
                    source: new ol.source.BingMaps({
                        key: bingKey,
                        imagerySet: 'Aerial'
                    })
                });
            } else {
                layer = new ol.layer.Tile({
                    source: new ol.source.OSM({})
                });
            }

            this.vectorSource = new ol.source.Vector({});
            vectorLayer = new ol.layer.Vector({
                source: this.vectorSource
            });

            lat = user.get('latitude') || server.get('latitude') || Traccar.Style.mapDefaultLat;
            lon = user.get('longitude') || server.get('longitude') || Traccar.Style.mapDefaultLon;
            zoom = user.get('zoom') || server.get('zoom') || Traccar.Style.mapDefaultZoom;

            this.mapView = new ol.View({
                center: ol.proj.fromLonLat([lon, lat]),
                zoom: zoom,
                maxZoom: Traccar.Style.mapMaxZoom
            });

            this.map = new ol.Map({
                target: this.body.dom.id,
                layers: [layer, vectorLayer],
                view: this.mapView,
                controls: ol.control.defaults({ attribution: false })
            });

            this.map.on('click', function (e) {
                this.map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
                    this.fireEvent('selectFeature', feature);
                }, this);
            }, this);
        },

        resize: function () {
            this.map.updateSize();
        }
    }
});
<commit_msg>Implement attribution for custom map<commit_after>/*
 * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

Ext.define('Traccar.view.Map', {
    extend: 'Ext.form.Panel',
    xtype: 'mapView',

    requires: [
        'Traccar.view.MapController'
    ],

    controller: 'map',

    title: Strings.mapTitle,
    layout: 'fit',

    getMap: function () {
        return this.map;
    },

    getMapView: function () {
        return this.mapView;
    },

    getVectorSource: function () {
        return this.vectorSource;
    },

    listeners: {
        afterrender: function () {
            var user, server, layer, type, bingKey, vectorLayer, lat, lon, zoom;

            user = Traccar.app.getUser();
            server = Traccar.app.getServer();

            type = user.get('map') || server.get('map');
            bingKey = server.get('bingKey');

            if (type === 'custom') {
                layer = new ol.layer.Tile({
                    source: new ol.source.XYZ({
                        url: server.get('mapUrl'),
                        attributions: [new ol.Attribution({
                            html: ''
                        })]
                    })
                });
            } else if (type === 'bingRoad') {
                layer = new ol.layer.Tile({
                    source: new ol.source.BingMaps({
                        key: bingKey,
                        imagerySet: 'Road'
                    })
                });
            } else if (type === 'bingAerial') {
                layer = new ol.layer.Tile({
                    source: new ol.source.BingMaps({
                        key: bingKey,
                        imagerySet: 'Aerial'
                    })
                });
            } else {
                layer = new ol.layer.Tile({
                    source: new ol.source.OSM({})
                });
            }

            this.vectorSource = new ol.source.Vector({});
            vectorLayer = new ol.layer.Vector({
                source: this.vectorSource
            });

            lat = user.get('latitude') || server.get('latitude') || Traccar.Style.mapDefaultLat;
            lon = user.get('longitude') || server.get('longitude') || Traccar.Style.mapDefaultLon;
            zoom = user.get('zoom') || server.get('zoom') || Traccar.Style.mapDefaultZoom;

            this.mapView = new ol.View({
                center: ol.proj.fromLonLat([lon, lat]),
                zoom: zoom,
                maxZoom: Traccar.Style.mapMaxZoom
            });

            this.map = new ol.Map({
                target: this.body.dom.id,
                layers: [layer, vectorLayer],
                view: this.mapView
            });

            this.map.on('click', function (e) {
                this.map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
                    this.fireEvent('selectFeature', feature);
                }, this);
            }, this);
        },

        resize: function () {
            this.map.updateSize();
        }
    }
});
<|endoftext|>


<commit_before>var SUPPORTED_IMAGE_TYPES = ['jpg','jpeg','png','gif'];

var Semver = function(ver) {
  var segs = ver.split('.');
  return { major: (segs[0] || 0), minor: (segs[1] || 0), patch: (segs[2] || 0), version: ver };
};

var isValidFileType = function(extension) {
  return SUPPORTED_IMAGE_TYPES.indexOf(extension) >= 0;
};

var getOrCreateAssetInput = function() {
  if (document.getElementById('asset-input')) {
    return document.getElementById('asset-input');
  }

  var assetInput = document.createElement('input');

  assetInput.type = 'file';
  assetInput.style.display = 'none';
  assetInput.id = 'asset-input';

  // Stop event propagation to make sure we don't set editable state to false
  //  - when we click on the input[type="file"]
  assetInput.onclick = function(event) {
    event.stopPropagation();
  };

  return assetInput;
};

var getOrCreateLoadingOverlay = function() {
  var loadingOverlay;
  if (document.querySelector('.asset-loading-overlay')) {
    loadingOverlay = document.querySelector('.asset-loading-overlay');
  } else {
    var loadingOverlay = document.createElement('div');
    loadingOverlay.className = 'asset-loading-overlay';
    loadingOverlay.innerHTML = '
Loading...
';

    loadingOverlay.className = 'asset-loading-overlay hidden';
  }
  return loadingOverlay;
};

var postAsset = function(url, sessionId, assetData, callback) {
  var request = new XMLHttpRequest();

  var formData = new FormData();
  Object.keys(assetData).forEach(function(key) {
    if (key === 'tags') {
      formData.append(key, JSON.stringify(assetData[key]));
    } else {
      formData.append(key, assetData[key]);
    }
  });

  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      if (request.status == 201) {
        return callback(null, JSON.parse(request.responseText));
      } else {
        return callback(new Error('Something went wrong when uploading an asset. please try again'));
      }
    }
  };

  request.open('POST', url + '/assets', true);
  request.setRequestHeader('SID', sessionId);
  request.send(formData);
};

var serializeFile = function(file) {
  var fileNameSplit = file.name.split('.'),
      extension     = fileNameSplit[fileNameSplit.length - 1],
      contentType   = file.type || 'image/x-' + extension;

  if (!isValidFileType(extension)) {
    return console.warn('invalid file type:', extension);
  }

  var attributes = {
    title:        'New File',
    type:         'image',
    tags:         ['image'],
    content:      file,
    contentType:  contentType
  };

  return attributes;
};

var patch = function(to, from) {
  if(from) {
    Object.keys(from).forEach(function(key){
      to[key] = from[key];
      if (to[key] === null) {
        delete to[key];
      }
    });
  }
  return to;
};

var isNullish = function(obj) {
  return obj == null; // jshint ignore:line
};

var JSONDeepEquals = function(o1, o2) {
  if (typeof o1 !== "object" || typeof o1 !== typeof o2 || isNullish(o1) || isNullish(o2)) {
    return o1 === o2;
  }

  var k1 = Object.keys(o1).sort();
  var k2 = Object.keys(o2).sort();
  if (k1.length != k2.length) return false;

  for (var i=0; i<k1.length; i++) {
    if (!JSONDeepEquals(o1[k1[i]], o2[k2[i]])) return false;
  }
  return true;
};

var prototype = Object.create(HTMLElement.prototype, {
  src: {
    get: function(){ return this.getAttribute('src') || 'about:blank'; }
  },

  editable: {
    get: function(){ return this.getAttribute('editable') == 'true'; }
  },

  env: {
    get: function(){ return this.readAttributeAsJson('data-environment'); }
  },

  config: {
    get: function(){ return this.readAttributeAsJson('data-config'); }
  },

  userstate: {
    get: function(){ return this.readAttributeAsJson('data-userstate'); }
  },

  debug: {
    get: function(){ return this.hasAttribute('debug'); }
  },

  apiVersion: {
    get: function(){
      if(!this._apiVersion) {
        this._apiVersion = new Semver(this.getAttribute('data-api-version') || '0.0.0');
      }
      return this._apiVersion;
    }
  }
});

prototype.readAttributeAsJson = function(name) {
  if(!this.hasAttribute(name)) { return {}; }
  return JSON.parse(this.getAttribute(name));
};

prototype.log = function(dir, event, data) {
  if(this.debug) { console.log(dir, event, data); }
};

prototype.createdCallback = function() {
  this._previousMessages = {};
};

prototype.attachedCallback = function(){
  this.iframe = document.createElement('iframe');
  this.iframe.src = this.src;
  this.iframe.addEventListener('message', this.handleMessage.bind(this));
  this.iframe.setAttribute('allowfullscreen', 'allowfullscreen');

  this.appendChild(this.iframe);

  this.assetInput      = getOrCreateAssetInput();
  this.loadingOverlay  = getOrCreateLoadingOverlay();

  this.appendChild(this.assetInput);
  this.appendChild(this.loadingOverlay);
};

prototype.detachedCallback = function(){
  this.removeChild(this.iframe);
  this.removeChild(this.assetInput);
  this.removeChild(this.loadingOverlay);
  this._reset();
};

prototype._reset = function(){
  this._previousMessages = {};
  window.clearTimeout(this._attributesChangedTimeout);
  window.clearTimeout(this._learnerStateChangedTimeout);
};

prototype.attributeChangedCallback = function(name, oldAttribute, newAttribute){
  switch(name) {
    case 'editable':
      this.sendMessage('editableChanged', { editable: this.editable });
      if(this.apiVersion.minor < 1) {
        this.sendMessage('setEditable', { editable: this.editable });
      }
      break;

    case 'data-config':
      window.clearTimeout(this._attributesChangedTimeout);
      this._attributesChangedTimeout = window.setTimeout((function() {
        this.sendMessage('attributesChanged', this.config);
      }).bind(this));
      break;

    case 'data-userstate':
      window.clearTimeout(this._learnerStateChangedTimeout);
      this._learnerStateChangedTimeout = window.setTimeout((function() {
        this.sendMessage('learnerStateChanged', this.userstate);
      }).bind(this));
      break;
  }
};

prototype.handleMessage = function(event) {
  if(event.detail.event) {
    var eventName = event.detail.event;
    var data = event.detail.data;

    this.log('↖', eventName, data);

    var handler = this.messageHandlers[eventName];
    if(handler) {
      handler.call(this, data);
    } else {
      console.error('Unknown event received: ' + eventName);
      this.error({message: 'Unknown event received: ' + eventName});
    }
  }
};

prototype.sendMessage = function(eventName, data) {
  if (!this._listening) return;
  if (JSONDeepEquals(this._previousMessages[eventName], data)) return;

  var message = { event: eventName };
  if(data) { message.data = data; }
  if(this.iframe && this.iframe.contentWindow) {
    this.iframe.contentWindow.postMessage(message, '*');
    this.log('↘', message.event, message.data);
    this._previousMessages[eventName] = data;
  }
};

prototype.fireCustomEvent = function(eventName, data, options) {
  options = options || {};
  var evt = new CustomEvent(eventName, { detail: data, bubbles: options.bubbles || false });
  this.dispatchEvent(evt);
};

prototype.uploadAssetAndSetAttributes = function(data, file) {
  var apiUrl      = this.env.apiUrl,
      sessionId   = this.env.sessionId,
      serializedFile = serializeFile(file);

  if (!serializedFile) { return; }

  this.loadingOverlay.className = 'asset-loading-overlay';

  postAsset(apiUrl, sessionId, serializedFile, function(error, assetJson) {
    this.loadingOverlay.className = 'asset-loading-overlay hidden';
    if (error) {
      return alert(error.message);
    }

    var assetAttributes = {};
    assetAttributes[data.attribute] = assetJson;

    var config = this.readAttributeAsJson('data-config');
    patch(config, data);
    this.setAttribute('data-config', JSON.stringify(config));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setAttributes', config);
  }.bind(this));
};

prototype.messageHandlers = {
  startListening: function(){
    this._reset();
    this._listening = true;
    this.sendMessage('environmentChanged', this.env);
    this.sendMessage('attributesChanged', this.config);
    this.sendMessage('learnerStateChanged', this.userstate);
    this.sendMessage('editableChanged', { editable: this.editable });
  },

  setHeight: function(data){
    this.iframe.style.height = data.pixels + 'px';
    if (!this._firedRendered) {
      this._firedRendered = true;
      this.fireCustomEvent('rendered');
    }
  },

  setAttributes: function(data){
    if(!this.editable) {
      console.warn('Unable to setAttributes in the read-only state');
      return;
    }
    var config = this.readAttributeAsJson('data-config');
    patch(config, data);
    this.setAttribute('data-config', JSON.stringify(config));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setAttributes', config);
  },

  setLearnerState: function(data) {
    var userstate = this.readAttributeAsJson('data-userstate');
    patch(userstate, data);
    this.setAttribute('data-userstate', JSON.stringify(userstate));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setLearnerState', userstate);
  },

  getPath: function(data) {
    console.warn('getPath/setPath are obsolete');
    var assetUrlTemplate = this.env && this.env.assetUrlTemplate;
    if(assetUrlTemplate) {
      var url = assetUrlTemplate.replace('<%= id %>', data.assetId );
      this.sendMessage('setPath', { url: url});
    }
  },

  setPropertySheetAttributes: function(data) { this.fireCustomEvent('setPropertySheetAttributes', data); },
  track: function(data) { this.fireCustomEvent('track', data, {bubbles: true}); },
  error: function(data) { this.fireCustomEvent('error', data, {bubbles: true}); },
  requestAsset: function(data) {
    // TODO support other updload types
    if (data.type == 'video') {
      return this.fireCustomEvent('requestAsset', data);
    }

    this.assetInput.click();
    this.assetInput.onchange = function(e) {
      if (e && e.target && e.target.files && e.target.files[0]) {
        this.uploadAssetAndSetAttributes(data, e.target.files[0]);
      }
    }.bind(this);
  },

  // Soon to be deprecated in favour of in-iframe APIs
  // E.g. https://github.com/Versal/challenges-js-api/
  setEmpty: function(data) { this.fireCustomEvent('setEmpty', data); },
  changeBlocking: function(data) { this.fireCustomEvent('changeBlocking', data); }
};

window.addEventListener('message', function(event){
  var iframes = document.querySelectorAll('versal-iframe-launcher > iframe');
  Array.prototype.forEach.call(iframes, function(iframe){
    if(iframe.contentWindow == event.source) {
      iframe.dispatchEvent(new CustomEvent('message', { detail: event.data }));
    }
  });
});

document.registerElement('versal-iframe-launcher', { prototype: prototype });
<commit_msg>don't find elements first since they are better organized in lifecycle<commit_after>var SUPPORTED_IMAGE_TYPES = ['jpg','jpeg','png','gif'];

var Semver = function(ver) {
  var segs = ver.split('.');
  return { major: (segs[0] || 0), minor: (segs[1] || 0), patch: (segs[2] || 0), version: ver };
};

var isValidFileType = function(extension) {
  return SUPPORTED_IMAGE_TYPES.indexOf(extension) >= 0;
};

var createAssetInput = function() {
  var assetInput = document.createElement('input');

  assetInput.type = 'file';
  assetInput.style.display = 'none';
  assetInput.id = 'asset-input';

  // Stop event propagation to make sure we don't set editable state to false
  //  - when we click on the input[type="file"]
  assetInput.onclick = function(event) {
    event.stopPropagation();
  };

  return assetInput;
};

var createLoadingOverlay = function() {
  var loadingOverlay = document.createElement('div');
  loadingOverlay.className = 'asset-loading-overlay';
  loadingOverlay.innerHTML = '
Loading...
';

  loadingOverlay.className = 'asset-loading-overlay hidden';
  return loadingOverlay;
};

var postAsset = function(url, sessionId, assetData, callback) {
  var request = new XMLHttpRequest();

  var formData = new FormData();
  Object.keys(assetData).forEach(function(key) {
    if (key === 'tags') {
      formData.append(key, JSON.stringify(assetData[key]));
    } else {
      formData.append(key, assetData[key]);
    }
  });

  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      if (request.status == 201) {
        return callback(null, JSON.parse(request.responseText));
      } else {
        return callback(new Error('Something went wrong when uploading an asset. please try again'));
      }
    }
  };

  request.open('POST', url + '/assets', true);
  request.setRequestHeader('SID', sessionId);
  request.send(formData);
};

var serializeFile = function(file) {
  var fileNameSplit = file.name.split('.'),
      extension     = fileNameSplit[fileNameSplit.length - 1],
      contentType   = file.type || 'image/x-' + extension;

  if (!isValidFileType(extension)) {
    return console.warn('invalid file type:', extension);
  }

  var attributes = {
    title:        'New File',
    type:         'image',
    tags:         ['image'],
    content:      file,
    contentType:  contentType
  };

  return attributes;
};

var patch = function(to, from) {
  if(from) {
    Object.keys(from).forEach(function(key){
      to[key] = from[key];
      if (to[key] === null) {
        delete to[key];
      }
    });
  }
  return to;
};

var isNullish = function(obj) {
  return obj == null; // jshint ignore:line
};

var JSONDeepEquals = function(o1, o2) {
  if (typeof o1 !== "object" || typeof o1 !== typeof o2 || isNullish(o1) || isNullish(o2)) {
    return o1 === o2;
  }

  var k1 = Object.keys(o1).sort();
  var k2 = Object.keys(o2).sort();
  if (k1.length != k2.length) return false;

  for (var i=0; i<k1.length; i++) {
    if (!JSONDeepEquals(o1[k1[i]], o2[k2[i]])) return false;
  }
  return true;
};

var prototype = Object.create(HTMLElement.prototype, {
  src: {
    get: function(){ return this.getAttribute('src') || 'about:blank'; }
  },

  editable: {
    get: function(){ return this.getAttribute('editable') == 'true'; }
  },

  env: {
    get: function(){ return this.readAttributeAsJson('data-environment'); }
  },

  config: {
    get: function(){ return this.readAttributeAsJson('data-config'); }
  },

  userstate: {
    get: function(){ return this.readAttributeAsJson('data-userstate'); }
  },

  debug: {
    get: function(){ return this.hasAttribute('debug'); }
  },

  apiVersion: {
    get: function(){
      if(!this._apiVersion) {
        this._apiVersion = new Semver(this.getAttribute('data-api-version') || '0.0.0');
      }
      return this._apiVersion;
    }
  }
});

prototype.readAttributeAsJson = function(name) {
  if(!this.hasAttribute(name)) { return {}; }
  return JSON.parse(this.getAttribute(name));
};

prototype.log = function(dir, event, data) {
  if(this.debug) { console.log(dir, event, data); }
};

prototype.createdCallback = function() {
  this._previousMessages = {};
};

prototype.attachedCallback = function(){
  this.iframe = document.createElement('iframe');
  this.iframe.src = this.src;
  this.iframe.addEventListener('message', this.handleMessage.bind(this));
  this.iframe.setAttribute('allowfullscreen', 'allowfullscreen');

  this.appendChild(this.iframe);

  this.assetInput      = createAssetInput();
  this.loadingOverlay  = createLoadingOverlay();

  this.appendChild(this.assetInput);
  this.appendChild(this.loadingOverlay);
};

prototype.detachedCallback = function(){
  this.removeChild(this.iframe);
  this.removeChild(this.assetInput);
  this.removeChild(this.loadingOverlay);
  this._reset();
};

prototype._reset = function(){
  this._previousMessages = {};
  window.clearTimeout(this._attributesChangedTimeout);
  window.clearTimeout(this._learnerStateChangedTimeout);
};

prototype.attributeChangedCallback = function(name, oldAttribute, newAttribute){
  switch(name) {
    case 'editable':
      this.sendMessage('editableChanged', { editable: this.editable });
      if(this.apiVersion.minor < 1) {
        this.sendMessage('setEditable', { editable: this.editable });
      }
      break;

    case 'data-config':
      window.clearTimeout(this._attributesChangedTimeout);
      this._attributesChangedTimeout = window.setTimeout((function() {
        this.sendMessage('attributesChanged', this.config);
      }).bind(this));
      break;

    case 'data-userstate':
      window.clearTimeout(this._learnerStateChangedTimeout);
      this._learnerStateChangedTimeout = window.setTimeout((function() {
        this.sendMessage('learnerStateChanged', this.userstate);
      }).bind(this));
      break;
  }
};

prototype.handleMessage = function(event) {
  if(event.detail.event) {
    var eventName = event.detail.event;
    var data = event.detail.data;

    this.log('↖', eventName, data);

    var handler = this.messageHandlers[eventName];
    if(handler) {
      handler.call(this, data);
    } else {
      console.error('Unknown event received: ' + eventName);
      this.error({message: 'Unknown event received: ' + eventName});
    }
  }
};

prototype.sendMessage = function(eventName, data) {
  if (!this._listening) return;
  if (JSONDeepEquals(this._previousMessages[eventName], data)) return;

  var message = { event: eventName };
  if(data) { message.data = data; }
  if(this.iframe && this.iframe.contentWindow) {
    this.iframe.contentWindow.postMessage(message, '*');
    this.log('↘', message.event, message.data);
    this._previousMessages[eventName] = data;
  }
};

prototype.fireCustomEvent = function(eventName, data, options) {
  options = options || {};
  var evt = new CustomEvent(eventName, { detail: data, bubbles: options.bubbles || false });
  this.dispatchEvent(evt);
};

prototype.uploadAssetAndSetAttributes = function(data, file) {
  var apiUrl      = this.env.apiUrl,
      sessionId   = this.env.sessionId,
      serializedFile = serializeFile(file);

  if (!serializedFile) { return; }

  this.loadingOverlay.className = 'asset-loading-overlay';

  postAsset(apiUrl, sessionId, serializedFile, function(error, assetJson) {
    this.loadingOverlay.className = 'asset-loading-overlay hidden';
    if (error) {
      return alert(error.message);
    }

    var assetAttributes = {};
    assetAttributes[data.attribute] = assetJson;

    var config = this.readAttributeAsJson('data-config');
    patch(config, data);
    this.setAttribute('data-config', JSON.stringify(config));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setAttributes', config);
  }.bind(this));
};

prototype.messageHandlers = {
  startListening: function(){
    this._reset();
    this._listening = true;
    this.sendMessage('environmentChanged', this.env);
    this.sendMessage('attributesChanged', this.config);
    this.sendMessage('learnerStateChanged', this.userstate);
    this.sendMessage('editableChanged', { editable: this.editable });
  },

  setHeight: function(data){
    this.iframe.style.height = data.pixels + 'px';
    if (!this._firedRendered) {
      this._firedRendered = true;
      this.fireCustomEvent('rendered');
    }
  },

  setAttributes: function(data){
    if(!this.editable) {
      console.warn('Unable to setAttributes in the read-only state');
      return;
    }
    var config = this.readAttributeAsJson('data-config');
    patch(config, data);
    this.setAttribute('data-config', JSON.stringify(config));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setAttributes', config);
  },

  setLearnerState: function(data) {
    var userstate = this.readAttributeAsJson('data-userstate');
    patch(userstate, data);
    this.setAttribute('data-userstate', JSON.stringify(userstate));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setLearnerState', userstate);
  },

  getPath: function(data) {
    console.warn('getPath/setPath are obsolete');
    var assetUrlTemplate = this.env && this.env.assetUrlTemplate;
    if(assetUrlTemplate) {
      var url = assetUrlTemplate.replace('<%= id %>', data.assetId );
      this.sendMessage('setPath', { url: url});
    }
  },

  setPropertySheetAttributes: function(data) { this.fireCustomEvent('setPropertySheetAttributes', data); },
  track: function(data) { this.fireCustomEvent('track', data, {bubbles: true}); },
  error: function(data) { this.fireCustomEvent('error', data, {bubbles: true}); },
  requestAsset: function(data) {
    // TODO support other updload types
    if (data.type == 'video') {
      return this.fireCustomEvent('requestAsset', data);
    }

    this.assetInput.click();
    this.assetInput.onchange = function(e) {
      if (e && e.target && e.target.files && e.target.files[0]) {
        this.uploadAssetAndSetAttributes(data, e.target.files[0]);
      }
    }.bind(this);
  },

  // Soon to be deprecated in favour of in-iframe APIs
  // E.g. https://github.com/Versal/challenges-js-api/
  setEmpty: function(data) { this.fireCustomEvent('setEmpty', data); },
  changeBlocking: function(data) { this.fireCustomEvent('changeBlocking', data); }
};

window.addEventListener('message', function(event){
  var iframes = document.querySelectorAll('versal-iframe-launcher > iframe');
  Array.prototype.forEach.call(iframes, function(iframe){
    if(iframe.contentWindow == event.source) {
      iframe.dispatchEvent(new CustomEvent('message', { detail: event.data }));
    }
  });
});

document.registerElement('versal-iframe-launcher', { prototype: prototype });
<|endoftext|>


<commit_before>class Button extends spritejs.Label {
  connect(parent, zOrder) {
    super.connect(parent, zOrder);

    this.on('mouseenter', (evt) => {
      this.attr({
        color: '#635d47',
        bgcolor: '#00e15e',
      });
    });

    this.on('mousedown', (evt) => {
      this.attr({
        scale: 0.95,
      });
    });

    this.on('mouseup', (evt) => {
      this.attr({
        scale: 1,
      });
    });

    this.on('mouseleave', (evt) => {
      this.attr({
        color: '#00e15e',
        bgcolor: '',
      });
    });
  }
}

(async function () {
  const paper = new spritejs.Scene('#paper', {
      viewport: ['auto', 'auto'],
      resolution: [1600, 1200],
      stickMode: 'width',
      // stickExtend: true,
    }),
    {Sprite, Group, Path} = spritejs;

  await paper.preload([
    'https://p5.ssl.qhimg.com/t01f47a319aebf27174.png',
    'https://s3.ssl.qhres.com/static/a6a7509c33a290a6.json',
  ]);

  const bglayer = paper.layer('bg'),
    fglayer = paper.layer('fg', {
      handleEvent: false,
      evaluateFPS: true,
      renderMode: 'repaintAll',
    });

  bglayer.canvas.style.backgroundColor = '#635D47';

  const wall = new Sprite();
  wall.attr({
    size: [10, 740],
    pos: [940, 250],
    bgcolor: '#CFC441',
  });
  fglayer.append(wall);

  function randomBirds(i) {
    const pos = [100, 350 + 60 * i];
    const duration = Math.round(200 + 300 * Math.random());

    const g = new Group();
    g.attr({
      anchor: [0.5, 0.5],
      pos,
      zIndex: 200,
    });

    const s = new Sprite('huanhuan.png');
    s.attr({scale: 0.4});

    g.appendChild(s);

    g.animate([
      {x: 100},
      {x: 900},
      {x: 100},
    ], {
      duration: duration * 20,
      iterations: Infinity,
      easing: 'ease-in-out',
      fill: 'both',
    });

    g.animate([
      {transform: {rotate: 30, scale: [1, 1]}},
      {transform: {rotate: -30, scale: [-1, 1]}},
      {transform: {rotate: 30, scale: [1, 1]}},
    ], {
      duration: duration * 20,
      iterations: Infinity,
      easing: 'step-end',
      fill: 'both',
    });

    const outerFireD = 'M19.8173,24.1766 L5.3273,32.9936 C4.6293,33.4186 3.7183,33.1976 3.2943,32.4996 C3.1953,32.3376 3.1313,32.1596 3.1003,31.9836 L0.1953,15.2736 C-1.0387,8.1796 3.7123,1.4286 10.8073,0.1946 C17.9013,-1.0394 24.6523,3.7116 25.8853,10.8056 C26.8283,16.2296 24.2443,21.4666 19.8173,24.1766';

    const outerFire = new Path();
    outerFire.attr({
      path: {d: outerFireD},
      pos: [22, 90],
      fillColor: 'rgb(253,88,45)',
      zIndex: -1,
    });
    g.append(outerFire);

    const innerFireD = 'M15.9906,13.766 L8.4096,26.718 C8.0486,27.335 7.2706,27.521 6.6726,27.133 C6.4296,26.976 6.2536,26.748 6.1536,26.491 L0.6356,12.223 C-1.1554,7.594 0.9666,2.393 5.3746,0.605 C9.7826,-1.182 14.8076,1.122 16.5976,5.752 C17.6546,8.483 17.3236,11.455 15.9906,13.766';

    const innerFire = new Path();
    innerFire.attr({
      path: {d: innerFireD},
      pos: [30, 90],
      rotate: 15,
      fillColor: 'rgb(254,222,9)',
      zIndex: -1,
    });
    g.append(innerFire);

    fglayer.append(g);

    return g;
  }

  for(let i = 0; i < 10; i++) {
    randomBirds(i);
  }

  const [speedupBtn, slowdownBtn, pauseBtn, playBtn]
    = ['Speed up', 'Slow down', 'Pause', 'Play'].map((type, i) => {
      const button = new Button(type);

      button.attr({
        anchor: [0.5, 0.5],
        pos: [1300, 400 + 150 * i],
        size: [170, 50],
        font: '36px Arial',
        lineHeight: 50,
        textAlign: 'center',
        color: '#00e15e',
        border: [3, '#00e15e'],
        borderRadius: 25,
        padding: 30,
      });
      bglayer.appendChild(button);

      return button;
    });

  speedupBtn.id = 'speedUp';
  speedupBtn.on('click', (evt) => {
    fglayer.timeline.playbackRate += 0.2;
  });

  slowdownBtn.on('click', (evt) => {
    fglayer.timeline.playbackRate -= 0.2;
  });

  pauseBtn.on('click', (evt) => {
    fglayer.timeline.playbackRate = 0;
  });

  playBtn.on('click', (evt) => {
    fglayer.timeline.playbackRate = 1;
  });

  const birdCountLabel = new spritejs.Label();
  birdCountLabel.attr({
    pos: [60, 80],
    font: '36px Arial',
    color: 'white',
  });

  bglayer.appendChild(birdCountLabel);

  setInterval(() => {
    birdCountLabel.text = `fps: ${fglayer.fps}`
      + ` | rate: ${fglayer.timeline.playbackRate.toFixed(2)}`;
  }, 100);
}());<commit_msg>:memo:update doc<commit_after>class Button extends spritejs.Label {
  connect(parent, zOrder) {
    super.connect(parent, zOrder);

    this.on('mouseenter', (evt) => {
      this.attr({
        color: '#635d47',
        bgcolor: '#00e15e',
      });
    });

    this.on('mousedown', (evt) => {
      this.attr({
        scale: 0.95,
      });
    });

    this.on('mouseup', (evt) => {
      this.attr({
        scale: 1,
      });
    });

    this.on('mouseleave', (evt) => {
      this.attr({
        color: '#00e15e',
        bgcolor: '',
      });
    });
  }
}

(async function () {
  const paper = new spritejs.Scene('#paper', {
      viewport: ['auto', 'auto'],
      resolution: [1600, 1200],
      stickMode: 'width',
      stickExtend: true,
    }),
    {Sprite, Group, Path} = spritejs;

  await paper.preload([
    'https://p5.ssl.qhimg.com/t01f47a319aebf27174.png',
    'https://s3.ssl.qhres.com/static/a6a7509c33a290a6.json',
  ]);

  const bglayer = paper.layer('bg'),
    fglayer = paper.layer('fg', {
      handleEvent: false,
      evaluateFPS: true,
      renderMode: 'repaintAll',
    });

  bglayer.canvas.style.backgroundColor = '#635D47';

  const wall = new Sprite();
  wall.attr({
    size: [10, 740],
    pos: [940, 250],
    bgcolor: '#CFC441',
  });
  fglayer.append(wall);

  function randomBirds(i) {
    const pos = [100, 350 + 60 * i];
    const duration = Math.round(200 + 300 * Math.random());

    const g = new Group();
    g.attr({
      anchor: [0.5, 0.5],
      pos,
      zIndex: 200,
    });

    const s = new Sprite('huanhuan.png');
    s.attr({scale: 0.4});

    g.appendChild(s);

    g.animate([
      {x: 100},
      {x: 900},
      {x: 100},
    ], {
      duration: duration * 20,
      iterations: Infinity,
      easing: 'ease-in-out',
      fill: 'both',
    });

    g.animate([
      {transform: {rotate: 30, scale: [1, 1]}},
      {transform: {rotate: -30, scale: [-1, 1]}},
      {transform: {rotate: 30, scale: [1, 1]}},
    ], {
      duration: duration * 20,
      iterations: Infinity,
      easing: 'step-end',
      fill: 'both',
    });

    const outerFireD = 'M19.8173,24.1766 L5.3273,32.9936 C4.6293,33.4186 3.7183,33.1976 3.2943,32.4996 C3.1953,32.3376 3.1313,32.1596 3.1003,31.9836 L0.1953,15.2736 C-1.0387,8.1796 3.7123,1.4286 10.8073,0.1946 C17.9013,-1.0394 24.6523,3.7116 25.8853,10.8056 C26.8283,16.2296 24.2443,21.4666 19.8173,24.1766';

    const outerFire = new Path();
    outerFire.attr({
      path: {d: outerFireD},
      pos: [22, 90],
      fillColor: 'rgb(253,88,45)',
      zIndex: -1,
    });
    g.append(outerFire);

    const innerFireD = 'M15.9906,13.766 L8.4096,26.718 C8.0486,27.335 7.2706,27.521 6.6726,27.133 C6.4296,26.976 6.2536,26.748 6.1536,26.491 L0.6356,12.223 C-1.1554,7.594 0.9666,2.393 5.3746,0.605 C9.7826,-1.182 14.8076,1.122 16.5976,5.752 C17.6546,8.483 17.3236,11.455 15.9906,13.766';

    const innerFire = new Path();
    innerFire.attr({
      path: {d: innerFireD},
      pos: [30, 90],
      rotate: 15,
      fillColor: 'rgb(254,222,9)',
      zIndex: -1,
    });
    g.append(innerFire);

    fglayer.append(g);

    return g;
  }

  for(let i = 0; i < 10; i++) {
    randomBirds(i);
  }

  const [speedupBtn, slowdownBtn, pauseBtn, playBtn]
    = ['Speed up', 'Slow down', 'Pause', 'Play'].map((type, i) => {
      const button = new Button(type);

      button.attr({
        anchor: [0.5, 0.5],
        pos: [1300, 400 + 150 * i],
        size: [170, 50],
        font: '36px Arial',
        lineHeight: 50,
        textAlign: 'center',
        color: '#00e15e',
        border: [3, '#00e15e'],
        borderRadius: 25,
        padding: 30,
      });
      bglayer.appendChild(button);

      return button;
    });

  speedupBtn.id = 'speedUp';
  speedupBtn.on('click', (evt) => {
    fglayer.timeline.playbackRate += 0.2;
  });

  slowdownBtn.on('click', (evt) => {
    fglayer.timeline.playbackRate -= 0.2;
  });

  pauseBtn.on('click', (evt) => {
    fglayer.timeline.playbackRate = 0;
  });

  playBtn.on('click', (evt) => {
    fglayer.timeline.playbackRate = 1;
  });

  const birdCountLabel = new spritejs.Label();
  birdCountLabel.attr({
    pos: [60, 80],
    font: '36px Arial',
    color: 'white',
  });

  bglayer.appendChild(birdCountLabel);

  setInterval(() => {
    birdCountLabel.text = `fps: ${fglayer.fps}`
      + ` | rate: ${fglayer.timeline.playbackRate.toFixed(2)}`;
  }, 100);
}());<|endoftext|>


<commit_before>AST = null

function run_SA(){
  AST = generateAST(CST);
  writeOutput("AST generated.");
}

function generateAST(cst){
  // The first node will be a program node with only a single block child.
  if(CST.children[0].val != "Block") raiseFatalError("Horrible things happened");
  var root = new TreeNode("root");
  generateBlockAST(root, CST.getChild(0));
  root = root.getChild(0); // Root only exists as a place holder.
  return root;
}

function generateBlockAST(ast_node, block_node){
  ast_node = generateNewChild(ast_node, "Block");
  // Ignoring the first and last children because they are braces.
  for(var i = 1; i < block_node.children.length - 1; i++){
    generateStmtListAST(ast_node, block_node.getChild(i));
  }
}

function generateStmtListAST(ast_node, stmt_list_node){
  if(stmt_list_node.children.length === 2) {
    generateStmtAST(ast_node, stmt_list_node.getChild(0));
    generateStmtListAST(ast_node, stmt_list_node.getChild(1));
  }
  else{
    // Epsilons are not added to the AST.
  }
}

function generateStmtAST(ast_node, stmt_node){
  var type = stmt_node.getChild(0).val;
  if(type == "Block") generateBlockAST(ast_node, stmt_node.getChild(0));
  else if(type == "VarDecl") generateVarDeclAST(ast_node, stmt_node.getChild(0));
  else if(type == "AssignStmt") generateAssignAST(ast_node, stmt_node.getChild(0));
  else {
    return;
  }
}

function generateVarDeclAST(ast_node, var_decl_node){
  ast_node = generateNewChild(ast_node, "VarDecl");
  ast_node.addChild(getTypeAST(var_decl_node.getChild(0)));
  ast_node.addChild(getIDAST(var_decl_node.getChild(1)));
}

function generateAssignAST(ast_node, assign_node){
  ast_node = generateNewChild(ast_node, "Assign");
  ast_node.addChild(getIDAST(assign_node.getChild(0)));
  generateExprAST(ast_node, assign_node.getChild(2));
}

function generateExprAST(ast_node, expr_node){
  var type = expr_node.getChild(0).val;
  if(type == "IntExpr") generateIntExprAST(ast_node, expr_node.getChild(0));
  else if(type == "StringExpr") generateStringExprAST(ast_node, expr_node.getChild(0));
  //else if(type == "BooleanExpr") ;
  else ast_node.addChild(getIDAST(expr_node.getChild(0)));
}

function generateIntExprAST(ast_node, int_expr_node){
  if(int_expr_node.children.length == 1) ast_node.addChild(getDigitAST(int_expr_node.getChild(0)));
  else{
    ast_node = generateNewChild(ast_node, getIntOpAST(int_expr_node.getChild(1)));
    ast_node.addChild(getDigitAST(int_expr_node.getChild(0)));
    generateExprAST(ast_node, int_expr_node.getChild(2));
  }
}

function generateStringExprAST(ast_node, string_expr_node){
  ast_node.addChild(new TreeNode(charListToString(string_expr_node.getChild(1))));
}

function charListToString(char_list_node){
  var temp = "\\\"";
  while(char_list_node.children.length != 1){
    temp += char_list_node.getChild(0).getChild(0).val;
    char_list_node = char_list_node.getChild(1);
  }
  return temp + "\\\"";
}

function getTypeAST(node){
  return node.getChild(0);
}

function getIDAST(node){
  return node.getChild(0).getChild(0);
}

function getDigitAST(node){
  return node.getChild(0);
}

function getIntOpAST(node){
  return node.getChild(0).val;
}<commit_msg>all Expr production working<commit_after>AST = null

function run_SA(){
  AST = generateAST(CST);
  writeOutput("AST generated.");
}

function generateAST(cst){
  // The first node will be a program node with only a single block child.
  if(CST.children[0].val != "Block") raiseFatalError("Horrible things happened");
  var root = new TreeNode("root");
  generateBlockAST(root, CST.getChild(0));
  root = root.getChild(0); // Root only exists as a place holder.
  return root;
}

function generateBlockAST(ast_node, block_node){
  ast_node = generateNewChild(ast_node, "Block");
  // Ignoring the first and last children because they are braces.
  for(var i = 1; i < block_node.children.length - 1; i++){
    generateStmtListAST(ast_node, block_node.getChild(i));
  }
}

function generateStmtListAST(ast_node, stmt_list_node){
  if(stmt_list_node.children.length === 2) {
    generateStmtAST(ast_node, stmt_list_node.getChild(0));
    generateStmtListAST(ast_node, stmt_list_node.getChild(1));
  }
  else{
    // Epsilons are not added to the AST.
  }
}

function generateStmtAST(ast_node, stmt_node){
  var type = stmt_node.getChild(0).val;
  if(type == "Block") generateBlockAST(ast_node, stmt_node.getChild(0));
  else if(type == "VarDecl") generateVarDeclAST(ast_node, stmt_node.getChild(0));
  else if(type == "AssignStmt") generateAssignAST(ast_node, stmt_node.getChild(0));
  else {
    return;
  }
}

function generateVarDeclAST(ast_node, var_decl_node){
  ast_node = generateNewChild(ast_node, "VarDecl");
  ast_node.addChild(getTypeAST(var_decl_node.getChild(0)));
  ast_node.addChild(getIDAST(var_decl_node.getChild(1)));
}

function generateAssignAST(ast_node, assign_node){
  ast_node = generateNewChild(ast_node, "Assign");
  ast_node.addChild(getIDAST(assign_node.getChild(0)));
  generateExprAST(ast_node, assign_node.getChild(2));
}

function generateExprAST(ast_node, expr_node){
  var type = expr_node.getChild(0).val;
  if(type == "IntExpr") generateIntExprAST(ast_node, expr_node.getChild(0));
  else if(type == "StringExpr") generateStringExprAST(ast_node, expr_node.getChild(0));
  else if(type == "BoolExpr") generateBooleanExprAST(ast_node, expr_node.getChild(0));
  else ast_node.addChild(getIDAST(expr_node.getChild(0)));
}

function generateIntExprAST(ast_node, int_expr_node){
  if(int_expr_node.children.length == 1) ast_node.addChild(getDigitAST(int_expr_node.getChild(0)));
  else{
    ast_node = generateNewChild(ast_node, getIntOpAST(int_expr_node.getChild(1)));
    ast_node.addChild(getDigitAST(int_expr_node.getChild(0)));
    generateExprAST(ast_node, int_expr_node.getChild(2));
  }
}

function generateStringExprAST(ast_node, string_expr_node){
  ast_node.addChild(new TreeNode(charListToString(string_expr_node.getChild(1))));
}

function generateBooleanExprAST(ast_node, bool_expr_node){
  if(bool_expr_node.children.length == 1) ast_node.addChild(getBoolValAST(bool_expr_node.getChild(0)));
  else{
    ast_node = generateNewChild(ast_node, getBoolOpAST(bool_expr_node.getChild(2)));
    generateExprAST(ast_node, bool_expr_node.getChild(1));
    generateExprAST(ast_node, bool_expr_node.getChild(3));
  }
}

function charListToString(char_list_node){
  var temp = "\\\"";
  while(char_list_node.children.length != 1){
    temp += char_list_node.getChild(0).getChild(0).val;
    char_list_node = char_list_node.getChild(1);
  }
  return temp + "\\\"";
}

function getTypeAST(node){
  return node.getChild(0);
}

function getIDAST(node){
  return node.getChild(0).getChild(0);
}

function getDigitAST(node){
  return node.getChild(0);
}

function getIntOpAST(node){
  return node.getChild(0).val;
}

function getBoolValAST(node){
  return node.getChild(0);
}

function getBoolOpAST(node){
  return node.getChild(0).val;
}<|endoftext|>


<commit_before>import React from 'react';
import ActionLock from 'material-ui/svg-icons/action/lock';
import Avatar from 'material-ui/Avatar';
import NavigationMenu from 'material-ui/svg-icons/navigation/menu';
import RaisedButton from 'material-ui/RaisedButton';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { fullWhite, lightBlue900 } from 'material-ui/styles/colors';
import { Link } from 'react-router';

import theme from '../theme';

class Navigation extends React.Component {
    constructor(props) {
        super(props);
        this.handleOpen = this.handleOpen.bind(this);
        this.handleClose = this.handleClose.bind(this);
        this.handleToggle = this.handleToggle.bind(this);
        this.state = {
            open: false,
        };
    }

    getChildContext() {
        return { muiTheme: getMuiTheme(theme) };
    }

    handleToggle() {
        this.setState({
            open: !this.state.open,
        });
    }

    handleOpen(state) {
        this.setState({
            open: state,
        });
    }

    handleClose() {
        this.setState({
            open: false,
        });
    }

    render() {
        const viewer = this.props.viewer;
        const logo = (
            <Link
                to="/"
                onClick={this.handleClose}
                style={{
                    padding: '19px 10px 20px 9px',
                }}
            >

            </Link>
        );

        return (

                            {logo}

                            <Link to="about" style={{ color: 'white' }}>
                                Om oss
                            </Link>
                            <Link to="/projects" style={{ color: 'white' }}>
                                Konserter
                            </Link>

                                Medlemmer

                                Støtt oss

                            {viewer ?
                                <a href={`/users/${viewer.username}`} style={{ display: 1, display: 'flex', alignItems: 'center', margin: '-5px 0', color: 'white' }}>
                                    <Avatar src={viewer.profile_picture_path} style={{ margin: '0 5px' }} />
                                    {viewer.name}

                                :
                                <Link to="/login" style={{ padding: 0, margin: '12px 15px 12px 10px' }}>
                                    <RaisedButton
                                        label="Logg inn"
                                        icon={<ActionLock />}
                                    />
                                </Link>
                            }

                    {logo}
                    <button
                        className="flex-menu-handler"
                        onClick={this.handleToggle}
                        style={{
                            position: 'absolute',
                            top: 0,
                            right: 0,
                            padding: '16px 15px 15px 1rem',
                            outline: 'none',
                            backgroundColor: lightBlue900,
                            margin: 0,
                        }}
                    >
                        <NavigationMenu color={fullWhite} />
                    </button>
                    {this.state.open ?

                                <Link to="about" style={{ color: 'white' }} onClick={this.handleClose}>
                                    Om oss
                                </Link>
                                <Link to="/projects" style={{ color: 'white' }} onClick={this.handleClose}>
                                    Konserter
                                </Link>

                                    Medlemmer

                                    Støtt oss

                                {this.props.viewer ?
                                    <a href={`/users/${viewer.username}`} style={{ lineHeight: 1 }}>
                                        <Avatar src={viewer.profile_picture_path} style={{ margin: '-10px 5px -20px 0' }} />
                                        {viewer.name}

                                    :

                                        <RaisedButton
                                            label="Logg inn"
                                            icon={<ActionLock />}
                                        />

                                }

                        : null
                    }

        );
    }
}

Navigation.propTypes = {
    viewer: React.PropTypes.object,
    organization: React.PropTypes.object,
    socket: React.PropTypes.object,
};

Navigation.childContextTypes = {
    muiTheme: React.PropTypes.object.isRequired,
};

export default Navigation;
<commit_msg>Navigation use Link for /members<commit_after>import React from 'react';
import ActionLock from 'material-ui/svg-icons/action/lock';
import Avatar from 'material-ui/Avatar';
import NavigationMenu from 'material-ui/svg-icons/navigation/menu';
import RaisedButton from 'material-ui/RaisedButton';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { fullWhite, lightBlue900 } from 'material-ui/styles/colors';
import { Link } from 'react-router';

import theme from '../theme';

class Navigation extends React.Component {
    constructor(props) {
        super(props);
        this.handleOpen = this.handleOpen.bind(this);
        this.handleClose = this.handleClose.bind(this);
        this.handleToggle = this.handleToggle.bind(this);
        this.state = {
            open: false,
        };
    }

    getChildContext() {
        return { muiTheme: getMuiTheme(theme) };
    }

    handleToggle() {
        this.setState({
            open: !this.state.open,
        });
    }

    handleOpen(state) {
        this.setState({
            open: state,
        });
    }

    handleClose() {
        this.setState({
            open: false,
        });
    }

    render() {
        const viewer = this.props.viewer;
        const logo = (
            <Link
                to="/"
                onClick={this.handleClose}
                style={{
                    padding: '19px 10px 20px 9px',
                }}
            >

            </Link>
        );

        return (

                            {logo}

                            <Link to="about" style={{ color: 'white' }}>
                                Om oss
                            </Link>
                            <Link to="/projects" style={{ color: 'white' }}>
                                Konserter
                            </Link>
                            <Link to="/members" style={{ color: 'white' }}>
                                Medlemmer
                            </Link>

                                Støtt oss

                            {viewer ?
                                <a href={`/users/${viewer.username}`} style={{ display: 1, display: 'flex', alignItems: 'center', margin: '-5px 0', color: 'white' }}>
                                    <Avatar src={viewer.profile_picture_path} style={{ margin: '0 5px' }} />
                                    {viewer.name}

                                :
                                <Link to="/login" style={{ padding: 0, margin: '12px 15px 12px 10px' }}>
                                    <RaisedButton
                                        label="Logg inn"
                                        icon={<ActionLock />}
                                    />
                                </Link>
                            }

                    {logo}
                    <button
                        className="flex-menu-handler"
                        onClick={this.handleToggle}
                        style={{
                            position: 'absolute',
                            top: 0,
                            right: 0,
                            padding: '16px 15px 15px 1rem',
                            outline: 'none',
                            backgroundColor: lightBlue900,
                            margin: 0,
                        }}
                    >
                        <NavigationMenu color={fullWhite} />
                    </button>
                    {this.state.open ?

                                <Link to="about" style={{ color: 'white' }} onClick={this.handleClose}>
                                    Om oss
                                </Link>
                                <Link to="/projects" style={{ color: 'white' }} onClick={this.handleClose}>
                                    Konserter
                                </Link>
                                <Link to="/members" style={{ color: 'white' }} onClick={this.handleClose}>
                                    Medlemmer
                                </Link>

                                    Støtt oss

                                {this.props.viewer ?
                                    <a href={`/users/${viewer.username}`} style={{ lineHeight: 1 }}>
                                        <Avatar src={viewer.profile_picture_path} style={{ margin: '-10px 5px -20px 0' }} />
                                        {viewer.name}

                                    :

                                        <RaisedButton
                                            label="Logg inn"
                                            icon={<ActionLock />}
                                        />

                                }

                        : null
                    }

        );
    }
}

Navigation.propTypes = {
    viewer: React.PropTypes.object,
    organization: React.PropTypes.object,
    socket: React.PropTypes.object,
};

Navigation.childContextTypes = {
    muiTheme: React.PropTypes.object.isRequired,
};

export default Navigation;
<|endoftext|>


<commit_before>var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var app = express();
var schedule = require('node-schedule');
var mongoose = require('mongoose');
var moment = require('moment');
var titleHelper = require('./TitleHelper');

var baseMarvelURL = 'http://marvel.com';
var baseImageURL = 'http://imagecomics.com';
var baseDCURL = 'http://www.dccomics.com';

var db = mongoose.connection;

db.on('error', console.error);
db.once('open', function() {
    console.log("We have a database");
    var comicSchema = new mongoose.Schema({
        title: {  type: String },
        issue: String,
        release_date: Date,
        publisher: String,
        link : String
    });

    var Comic = mongoose.model('Comic', comicSchema);

    var marvelScrape = schedule.scheduleJob({hour: 7, dayOfWeek: new schedule.Range(1, 5)}, function(){
        var scrapeMarvelComics = function scrapeMarvelComics(month){
            var now = month || moment();
            var url = baseMarvelURL + '/comics/calendar/month/'+now.format("YYYY-MM-01");

            request(url, function(error, response, html){
                if(!error){

                    var $ = cheerio.load(html);

                    var domComics = $('.comic-item h5');
                    if(domComics.length === 0){
                        return;
                    }

                    domComics.each(function(){
                        var fullTitle = $(this).text().trim();
                        var link = baseMarvelURL + $(this).find('a').attr('href');
                        //TODO: Fetch date from each page
                        var title = titleHelper.getTitle(fullTitle);
                        var issue = titleHelper.getIssue(fullTitle);

                        var newComic = {
                            title: title,
                            issue: issue,
                            release_date: undefined,
                            publisher: 'Marvel',
                            link : link
                        };

                        Comic.update({ title : newComic.title, publisher: newComic.publisher}, {$set: newComic}, {upsert:true}, function(err, newComic){
                            if (err) return console.error(err);
                        });
                    });
                    now.add(1, 'months');
                    scrapeMarvelComics(now);
                }
            });
        };
        scrapeMarvelComics();
    });

    var imageScrape = schedule.scheduleJob({hour: 6, dayOfWeek: new schedule.Range(1, 5)}, function(){
        console.log("About to scrape Image comics");
        var scrapeImageComics = function scrapeImageComics(month){
            var now = month || moment();
            var url = baseImageURL + '/comics/upcoming-releases/'+now.format("YYYY/M");
            console.log("Scraping "+url);
            request(url, function(error, response, html){
                if(error) console.error(error);
                if(!error){
                    console.log("Got a response");

                    var $ = cheerio.load(html);

                    var releases = [];

                    var domComics = $('.release_box .right');
                    if(domComics.length === 0){
                        console.log("Done for now");
                        return;
                    }

                    domComics.each(function(){

                        var fullTitle = $(this).find('h1').text().trim();
                        var link = baseImageURL + $(this).find('h1').find('a').attr('href');
                        var date = moment($(this).find('.pub_date').text());
                        var title = titleHelper.getTitle(fullTitle);
                        var issue = titleHelper.getIssue(fullTitle);

                        var newComic = {
                            title: title,
                            issue: issue,
                            release_date: date,
                            publisher: 'Image',
                            link : link
                        };

                        Comic.update({ title : newComic.title, publisher: newComic.publisher}, {$set: newComic}, {upsert:true}, function(err, newComic){
                            if (err) return console.error(err);
                        });
                    });
                    now.add(1, 'months');
                    scrapeImageComics(now);
                }
            });
        };
        scrapeImageComics();
    });

    var dcScrape = schedule.scheduleJob({hour: 5, dayOfWeek: new schedule.Range(1, 5)}, function(){
        console.log("About to scrape DC comics");
        var scrapeDCComics = function scrapeDCComics(month){
            var now = month || moment();
            var lastDayOfMonth = now.add(1, 'months').date(0);
            var url = baseDCURL + '/browse?content_type=comic&date='+now.format("MM")+'/01/'+now.format("YYYY")+'&date_end='+now.format("MM")+'/'+lastDayOfMonth.format("DD")+'/'+now.format("YYYY");
            console.log("Scraping "+url);
            request(url, function(error, response, html){
                if(error) console.error(error);
                if(!error){
                    console.log("Got a response");

                    //TODO: Need to find some way of loading all results
                    var $ = cheerio.load(html);

                    var releases = [];

                    var domComics = $('li .title');
                    if(domComics.length === 0){
                        console.log("Done for now");
                        return;
                    }

                    domComics.each(function(){

                        var fullTitle = $(this).find('a').text().trim();
                        var link = baseImageURL + $(this).find('a').attr('href');
                        var title = titleHelper.getTitle(fullTitle);
                        var issue = titleHelper.getIssue(fullTitle);
                        var date = $(this).find('.onsale').text();
                        date = date.substring(date.lastIndexOf(' ')).trim() + '/2014';
                        date = moment(date);

                        var newComic = {
                            title: title,
                            issue: issue,
                            release_date: date,
                            publisher: 'DC',
                            link : link
                        };

                        Comic.update({ title : newComic.title, publisher: newComic.publisher}, {$set: newComic}, {upsert:true}, function(err, newComic){
                            if (err) return console.error(err);
                        });
                    });
                    now.add(1, 'months');
                    scrapeDCComics(now);
                }
            });
        };
        scrapeDCComics();
    });
});

mongoose.connect('mongodb://localhost/UpComics');

exports = module.exports = app;<commit_msg>Removed unused libraries<commit_after>var request = require('request');
var cheerio = require('cheerio');
var schedule = require('node-schedule');
var mongoose = require('mongoose');
var moment = require('moment');
var titleHelper = require('./TitleHelper');

var baseMarvelURL = 'http://marvel.com';
var baseImageURL = 'http://imagecomics.com';
var baseDCURL = 'http://www.dccomics.com';

var db = mongoose.connection;

db.on('error', console.error);
db.once('open', function() {
    console.log("We have a database");
    var comicSchema = new mongoose.Schema({
        title: {  type: String },
        issue: String,
        release_date: Date,
        publisher: String,
        link : String
    });

    var Comic = mongoose.model('Comic', comicSchema);

    var marvelScrape = schedule.scheduleJob({hour: 7, dayOfWeek: new schedule.Range(1, 5)}, function(){
        var scrapeMarvelComics = function scrapeMarvelComics(month){
            var now = month || moment();
            var url = baseMarvelURL + '/comics/calendar/month/'+now.format("YYYY-MM-01");

            request(url, function(error, response, html){
                if(!error){

                    var $ = cheerio.load(html);

                    var domComics = $('.comic-item h5');
                    if(domComics.length === 0){
                        return;
                    }

                    domComics.each(function(){
                        var fullTitle = $(this).text().trim();
                        var link = baseMarvelURL + $(this).find('a').attr('href');
                        //TODO: Fetch date from each page
                        var title = titleHelper.getTitle(fullTitle);
                        var issue = titleHelper.getIssue(fullTitle);

                        var newComic = {
                            title: title,
                            issue: issue,
                            release_date: undefined,
                            publisher: 'Marvel',
                            link : link
                        };

                        Comic.update({ title : newComic.title, publisher: newComic.publisher}, {$set: newComic}, {upsert:true}, function(err, newComic){
                            if (err) return console.error(err);
                        });
                    });
                    now.add(1, 'months');
                    scrapeMarvelComics(now);
                }
            });
        };
        scrapeMarvelComics();
    });

    var imageScrape = schedule.scheduleJob({hour: 6, dayOfWeek: new schedule.Range(1, 5)}, function(){
        console.log("About to scrape Image comics");
        var scrapeImageComics = function scrapeImageComics(month){
            var now = month || moment();
            var url = baseImageURL + '/comics/upcoming-releases/'+now.format("YYYY/M");
            console.log("Scraping "+url);
            request(url, function(error, response, html){
                if(error) console.error(error);
                if(!error){
                    console.log("Got a response");

                    var $ = cheerio.load(html);

                    var releases = [];

                    var domComics = $('.release_box .right');
                    if(domComics.length === 0){
                        console.log("Done for now");
                        return;
                    }

                    domComics.each(function(){

                        var fullTitle = $(this).find('h1').text().trim();
                        var link = baseImageURL + $(this).find('h1').find('a').attr('href');
                        var date = moment($(this).find('.pub_date').text());
                        var title = titleHelper.getTitle(fullTitle);
                        var issue = titleHelper.getIssue(fullTitle);

                        var newComic = {
                            title: title,
                            issue: issue,
                            release_date: date,
                            publisher: 'Image',
                            link : link
                        };

                        Comic.update({ title : newComic.title, publisher: newComic.publisher}, {$set: newComic}, {upsert:true}, function(err, newComic){
                            if (err) return console.error(err);
                        });
                    });
                    now.add(1, 'months');
                    scrapeImageComics(now);
                }
            });
        };
        scrapeImageComics();
    });

    var dcScrape = schedule.scheduleJob({hour: 5, dayOfWeek: new schedule.Range(1, 5)}, function(){
        console.log("About to scrape DC comics");
        var scrapeDCComics = function scrapeDCComics(month){
            var now = month || moment();
            var lastDayOfMonth = now.add(1, 'months').date(0);
            var url = baseDCURL + '/browse?content_type=comic&date='+now.format("MM")+'/01/'+now.format("YYYY")+'&date_end='+now.format("MM")+'/'+lastDayOfMonth.format("DD")+'/'+now.format("YYYY");
            console.log("Scraping "+url);
            request(url, function(error, response, html){
                if(error) console.error(error);
                if(!error){
                    console.log("Got a response");

                    //TODO: Need to find some way of loading all results
                    var $ = cheerio.load(html);

                    var releases = [];

                    var domComics = $('li .title');
                    if(domComics.length === 0){
                        console.log("Done for now");
                        return;
                    }

                    domComics.each(function(){

                        var fullTitle = $(this).find('a').text().trim();
                        var link = baseImageURL + $(this).find('a').attr('href');
                        var title = titleHelper.getTitle(fullTitle);
                        var issue = titleHelper.getIssue(fullTitle);
                        var date = $(this).find('.onsale').text();
                        date = date.substring(date.lastIndexOf(' ')).trim() + '/2014';
                        date = moment(date);

                        var newComic = {
                            title: title,
                            issue: issue,
                            release_date: date,
                            publisher: 'DC',
                            link : link
                        };

                        Comic.update({ title : newComic.title, publisher: newComic.publisher}, {$set: newComic}, {upsert:true}, function(err, newComic){
                            if (err) return console.error(err);
                        });
                    });
                    now.add(1, 'months');
                    scrapeDCComics(now);
                }
            });
        };
        scrapeDCComics();
    });
});

mongoose.connect('mongodb://localhost/UpComics');<|endoftext|>


<commit_before>function layoutLogCheck(f)
{
	if (f.id.value == '')
	{
		alert('아이디나 이메일주소를 입력해 주세요.');
		f.id.focus();
		return false;
	}
	if (f.pw.value == '')
	{
		alert('패스워드를 입력해 주세요.');
		f.pw.focus();
		return false;
	}
	getIframeForAction(f);
	return true;
}
<commit_msg>update<commit_after><|endoftext|>