<commit_before>/**
 * This provides a list of endpoints and client-side validation for any calls
 * to those endpoints.
 */
'use strict';

goog.provide('resources');

goog.require('utils');
goog.require('config');

var resources = { };

/** @enum {number} */
var validationTypes = {
	OBJECT: 0,
	STRING: 1,
	NUMBER: 2,
	ARRAY: 3,
	BOOLEAN: 4
};

/* jshint ignore:start */

/** @typedef {function(string, string, *)} */
var _validator;

/* jshint ignore:end */

/**
 * @param {boolean} required
 * @param {validationTypes|RegExp} type
 * @throws {Error}
 * @return {_validator}
 */
function validator(required, type) {
	return function(endpoint, param, data) {
		// Ignores request validation when tracking is disabled because information will be intentionally missing from requests
		if (utils.userPreferences.trackingDisabled) {
			return false;
		}
		// Ensure data is not a number before doing a !data otherwise the number can't be 0.
		if ((typeof data !== 'number') && !data) {
			if (required) {
				return utils.message(utils.messages.missingParam, [ endpoint, param ]);
			}
		}
		else if (type === validationTypes.OBJECT) {
			if (typeof data !== 'object') {
				return utils.message(utils.messages.invalidType, [ endpoint, param, 'an object' ]);
			}
		}
		else if (type === validationTypes.ARRAY) {
			if (!(data instanceof Array)) {
				return utils.message(utils.messages.invalidType, [ endpoint, param, 'an array' ]);
			}
		}
		else if (type === validationTypes.NUMBER) {
			if (typeof data !== 'number') {
				return utils.message(utils.messages.invalidType, [ endpoint, param, 'a number' ]);
			}
		}
		else if (type === validationTypes.BOOLEAN) {
			if (typeof data !== 'boolean') {
				return utils.message(utils.messages.invalidType, [ endpoint, param, 'a boolean' ]);
			}
		}
		// String or regex validator
		else if (typeof data !== 'string') {
			return utils.message(utils.messages.invalidType, [ endpoint, param, 'a string' ]);
		}
		else if (type !== validationTypes.STRING && !type.test(data)) {
			return utils.message(
				utils.messages.invalidType,
				[ endpoint, param, 'in the proper format' ]
			);
		}

		return false;
	};
}

function defaults(obj) {
	var def = {
		"browser_fingerprint_id": validator(true, validationTypes.STRING),
		"identity_id": validator(true, validationTypes.STRING),
		"sdk": validator(true, validationTypes.STRING),
		"session_id": validator(true, validationTypes.STRING)
	};
	return utils.merge(obj, def);
}

resources.open = {
	destination: config.api_endpoint,
	endpoint: "/v1/open",
	method: utils.httpMethod.POST,
	params: {
		"browser_fingerprint_id": validator(false, validationTypes.STRING),
		"alternative_browser_fingerprint_id": validator(false, validationTypes.STRING),
		"identity_id": validator(false, validationTypes.STRING),
		"link_identifier": validator(false, validationTypes.STRING),
		"sdk": validator(false, validationTypes.STRING),
		"options": validator(false, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"tracking_disabled": validator(false, validationTypes.BOOLEAN),
		"current_url": validator(false, validationTypes.STRING),
		"screen_height": validator(false, validationTypes.NUMBER),
		"screen_width": validator(false, validationTypes.NUMBER),
		"identity": validator(false, validationTypes.STRING)
	}
};

resources._r = {
	destination: config.app_service_endpoint,
	endpoint: "/_r",
	method: utils.httpMethod.GET,
	jsonp: true,
	params: {
		"sdk": validator(true, validationTypes.STRING),
		"_t": validator(false, validationTypes.STRING),
		"branch_key": validator(true, validationTypes.STRING)
	}
};

resources.linkClick = {
	destination: "",
	endpoint: "",
	method: utils.httpMethod.GET,
	queryPart: {
		"link_url": validator(true, validationTypes.STRING)
	},
	params: {
		"click": validator(true, validationTypes.STRING)
	}
};

resources.SMSLinkSend = {
	destination: config.link_service_endpoint,
	endpoint: "/c",
	method: utils.httpMethod.POST,
	queryPart: {
		"link_url": validator(true, validationTypes.STRING)
	},
	params: {
		"sdk": validator(false, validationTypes.STRING),
		"phone": validator(true, validationTypes.STRING)
	}
};

resources.getCode = {
	destination: config.api_endpoint,
	endpoint: "/v1/referralcode",
	method: utils.httpMethod.POST,
	params: defaults({
		"amount": validator(true, validationTypes.NUMBER),
		"bucket": validator(false, validationTypes.STRING),
		"calculation_type": validator(true, validationTypes.NUMBER),
		"creation_source": validator(true, validationTypes.NUMBER),
		"expiration": validator(false, validationTypes.STRING),
		"location": validator(true, validationTypes.NUMBER),
		"prefix": validator(false, validationTypes.STRING),
		"type": validator(true, validationTypes.STRING)
	})
};

resources.validateCode = {
	destination: config.api_endpoint,
	endpoint: "/v1/referralcode",
	method: utils.httpMethod.POST,
	queryPart: {
		"code": validator(true, validationTypes.STRING)
	},
	params: defaults({ })
};

resources.applyCode = {
	destination: config.api_endpoint,
	endpoint: "/v1/applycode",
	method: utils.httpMethod.POST,
	queryPart: {
		"code": validator(true, validationTypes.STRING)
	},
	params: defaults({ })
};

resources.logout = {
	destination: config.api_endpoint,
	endpoint: "/v1/logout",
	method: utils.httpMethod.POST,
	params: defaults({
		"session_id": validator(true, validationTypes.STRING)
	})
};

resources.profile = {
	destination: config.api_endpoint,
	endpoint: "/v1/profile",
	method: utils.httpMethod.POST,
	params: defaults({
		"identity_id": validator(true, validationTypes.STRING),
		"identity": validator(true, validationTypes.STRING)
	})
};

resources.referrals = {
	destination: config.api_endpoint,
	endpoint: "/v1/referrals",
	method: utils.httpMethod.GET,
	queryPart: {
		"identity_id": validator(true, validationTypes.STRING)
	},
	params: defaults({ })
};

resources.creditHistory = {
	destination: config.api_endpoint,
	endpoint: "/v1/credithistory",
	method: utils.httpMethod.GET,
	params: defaults({
		"begin_after_id": validator(false, validationTypes.STRING),
		"bucket": validator(false, validationTypes.STRING),
		"direction": validator(false, validationTypes.NUMBER),
		"length": validator(false, validationTypes.NUMBER),
		"link_click_id": validator(false, validationTypes.STRING)
	})
};

resources.credits = {
	destination: config.api_endpoint,
	endpoint: "/v1/credits",
	method: utils.httpMethod.GET,
	params: defaults({
		"branch_key": validator(true, validationTypes.STRING),
		"identity": validator(true, validationTypes.STRING)
	})
};

resources.redeem = {
	destination: config.api_endpoint,
	endpoint: "/v1/redeem",
	method: utils.httpMethod.POST,
	params: defaults({
		"amount": validator(true, validationTypes.NUMBER),
		"bucket": validator(true, validationTypes.STRING),
		"identity_id": validator(true, validationTypes.STRING)
	})
};

resources.link = {
	destination: config.api_endpoint,
	endpoint: "/v1/url",
	method: utils.httpMethod.POST,
	ref: "obj",
	params: defaults({
		"alias": validator(false, validationTypes.STRING),
		"campaign": validator(false, validationTypes.STRING),
		"channel": validator(false, validationTypes.STRING),
		"data": validator(false, validationTypes.STRING),
		"feature": validator(false, validationTypes.STRING),
		"identity_id": validator(true, validationTypes.STRING),
		"stage": validator(false, validationTypes.STRING),
		"tags": validator(false, validationTypes.ARRAY),
		"type": validator(false, validationTypes.NUMBER),
		"source": validator(false, validationTypes.STRING),
		"instrumentation": validator(false, validationTypes.STRING)
	})
};

resources.deepview = {
	destination: config.api_endpoint,
	endpoint: "/v1/deepview",
	jsonp: true,
	method: utils.httpMethod.POST,
	params: defaults({
		"campaign": validator(false, validationTypes.STRING),
		"_t": validator(false, validationTypes.STRING),
		"channel": validator(false, validationTypes.STRING),
		"data": validator(true, validationTypes.STRING),
		"feature": validator(false, validationTypes.STRING),
		"link_click_id": validator(false, validationTypes.STRING),
		"open_app": validator(false, validationTypes.BOOLEAN),
		"append_deeplink_path": validator(false, validationTypes.BOOLEAN),
		"stage": validator(false, validationTypes.STRING),
		"tags": validator(false, validationTypes.ARRAY),
		"deepview_type": validator(true, validationTypes.STRING),
		"source": validator(true, validationTypes.STRING)
	})
};

resources.hasApp = {
	destination: config.api_endpoint,
	endpoint: "/v1/has-app",
	method: utils.httpMethod.GET,
	params: {
		"browser_fingerprint_id": validator(true, validationTypes.STRING),
		"instrumentation": validator(false, validationTypes.STRING)
	}
};

resources.event = {
	destination: config.api_endpoint,
	endpoint: "/v1/event",
	method: utils.httpMethod.POST,
	params: defaults({
		"event": validator(true, validationTypes.STRING),
		"metadata": validator(true, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"tracking_disabled": validator(false, validationTypes.BOOLEAN)
	})
};

resources.commerceEvent = {
	destination: config.api_endpoint,
	endpoint: "/v1/event",
	method: utils.httpMethod.POST,
	params: defaults({
		"event": validator(true, validationTypes.STRING),
		"metadata": validator(false, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"commerce_data": validator(true, validationTypes.OBJECT)
	})
};

// v2/event endpoints

resources.logStandardEvent = {
	destination: config.api_endpoint,
	endpoint: "/v2/event/standard",
	method: utils.httpMethod.POST,
	params: {
		"name": validator(true, validationTypes.STRING),
		"user_data": validator(true, validationTypes.STRING),
		"custom_data": validator(false, validationTypes.STRING),
		"event_data": validator(false, validationTypes.STRING),
		"content_items": validator(false, validationTypes.STRING),
		"customer_event_alias": validator(false, validationTypes.STRING)
	}
};

resources.logCustomEvent = {
	destination: config.api_endpoint,
	endpoint: "/v2/event/custom",
	method: utils.httpMethod.POST,
	params: {
		"name": validator(true, validationTypes.STRING),
		"user_data": validator(true, validationTypes.STRING),
		"custom_data": validator(false, validationTypes.STRING),
		"content_items": validator(false, validationTypes.STRING),
		"customer_event_alias": validator(false, validationTypes.STRING)
	}
};

resources.pageview = {
	destination: config.api_endpoint,
	endpoint: "/v1/pageview",
	method: utils.httpMethod.POST,
	params: defaults({
		"event": validator(true, validationTypes.STRING),
		"metadata": validator(false, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"tracking_disabled": validator(false, validationTypes.BOOLEAN),
		"branch_view_id": validator(false, validationTypes.STRING),
		"no_journeys": validator(false, validationTypes.BOOLEAN),
		"user_language": validator(false, validationTypes.STRING),
		"open_app": validator(false, validationTypes.BOOLEAN),
		"has_app_websdk": validator(false, validationTypes.BOOLEAN),
		"source": validator(false, validationTypes.STRING),
		"feature": validator(false, validationTypes.STRING),
		"is_iframe": validator(false, validationTypes.BOOLEAN),
		"data": validator(false, validationTypes.OBJECT),
		"callback_string": validator(false, validationTypes.STRING),
		"journey_displayed": validator(false, validationTypes.BOOLEAN),
		"audience_rule_id": validator(false, validationTypes.STRING),
		"journey_dismissals": validator(false, validationTypes.OBJECT),
		"identity": validator(false, validationTypes.STRING)
	})
};

resources.dismiss = {
	destination: config.api_endpoint,
	endpoint: "/v1/dismiss",
	method: utils.httpMethod.POST,
	params: defaults({
		"event": validator(true, validationTypes.STRING),
		"metadata": validator(false, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"tracking_disabled": validator(false, validationTypes.BOOLEAN),
		"branch_view_id": validator(false, validationTypes.STRING),
		"no_journeys": validator(false, validationTypes.BOOLEAN),
		"user_language": validator(false, validationTypes.STRING),
		"open_app": validator(false, validationTypes.BOOLEAN),
		"has_app_websdk": validator(false, validationTypes.BOOLEAN),
		"source": validator(false, validationTypes.STRING),
		"feature": validator(false, validationTypes.STRING),
		"is_iframe": validator(false, validationTypes.BOOLEAN),
		"data": validator(false, validationTypes.OBJECT),
		"callback_string": validator(false, validationTypes.STRING),
		"journey_displayed": validator(false, validationTypes.BOOLEAN),
		"audience_rule_id": validator(false, validationTypes.STRING),
		"journey_dismissals": validator(false, validationTypes.OBJECT),
		"dismissal_source": validator(false, validationTypes.STRING)
	})
};

resources.crossPlatformIds = {
	destination: config.api_endpoint,
	endpoint: "/v1/cpid",
	method: utils.httpMethod.POST,
	params: {
		"user_data": validator(true, validationTypes.STRING)
	}
};

resources.lastAttributedTouchData = {
	destination: config.api_endpoint,
	endpoint: "/v1/cpid/latd",
	method: utils.httpMethod.POST,
	params: {
		"user_data": validator(true, validationTypes.STRING)
	}
};
<commit_msg>Remove identity field from /v1/open requests<commit_after>/**
 * This provides a list of endpoints and client-side validation for any calls
 * to those endpoints.
 */
'use strict';

goog.provide('resources');

goog.require('utils');
goog.require('config');

var resources = { };

/** @enum {number} */
var validationTypes = {
	OBJECT: 0,
	STRING: 1,
	NUMBER: 2,
	ARRAY: 3,
	BOOLEAN: 4
};

/* jshint ignore:start */

/** @typedef {function(string, string, *)} */
var _validator;

/* jshint ignore:end */

/**
 * @param {boolean} required
 * @param {validationTypes|RegExp} type
 * @throws {Error}
 * @return {_validator}
 */
function validator(required, type) {
	return function(endpoint, param, data) {
		// Ignores request validation when tracking is disabled because information will be intentionally missing from requests
		if (utils.userPreferences.trackingDisabled) {
			return false;
		}
		// Ensure data is not a number before doing a !data otherwise the number can't be 0.
		if ((typeof data !== 'number') && !data) {
			if (required) {
				return utils.message(utils.messages.missingParam, [ endpoint, param ]);
			}
		}
		else if (type === validationTypes.OBJECT) {
			if (typeof data !== 'object') {
				return utils.message(utils.messages.invalidType, [ endpoint, param, 'an object' ]);
			}
		}
		else if (type === validationTypes.ARRAY) {
			if (!(data instanceof Array)) {
				return utils.message(utils.messages.invalidType, [ endpoint, param, 'an array' ]);
			}
		}
		else if (type === validationTypes.NUMBER) {
			if (typeof data !== 'number') {
				return utils.message(utils.messages.invalidType, [ endpoint, param, 'a number' ]);
			}
		}
		else if (type === validationTypes.BOOLEAN) {
			if (typeof data !== 'boolean') {
				return utils.message(utils.messages.invalidType, [ endpoint, param, 'a boolean' ]);
			}
		}
		// String or regex validator
		else if (typeof data !== 'string') {
			return utils.message(utils.messages.invalidType, [ endpoint, param, 'a string' ]);
		}
		else if (type !== validationTypes.STRING && !type.test(data)) {
			return utils.message(
				utils.messages.invalidType,
				[ endpoint, param, 'in the proper format' ]
			);
		}

		return false;
	};
}

function defaults(obj) {
	var def = {
		"browser_fingerprint_id": validator(true, validationTypes.STRING),
		"identity_id": validator(true, validationTypes.STRING),
		"sdk": validator(true, validationTypes.STRING),
		"session_id": validator(true, validationTypes.STRING)
	};
	return utils.merge(obj, def);
}

resources.open = {
	destination: config.api_endpoint,
	endpoint: "/v1/open",
	method: utils.httpMethod.POST,
	params: {
		"browser_fingerprint_id": validator(false, validationTypes.STRING),
		"alternative_browser_fingerprint_id": validator(false, validationTypes.STRING),
		"identity_id": validator(false, validationTypes.STRING),
		"link_identifier": validator(false, validationTypes.STRING),
		"sdk": validator(false, validationTypes.STRING),
		"options": validator(false, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"tracking_disabled": validator(false, validationTypes.BOOLEAN),
		"current_url": validator(false, validationTypes.STRING),
		"screen_height": validator(false, validationTypes.NUMBER),
		"screen_width": validator(false, validationTypes.NUMBER)
	}
};

resources._r = {
	destination: config.app_service_endpoint,
	endpoint: "/_r",
	method: utils.httpMethod.GET,
	jsonp: true,
	params: {
		"sdk": validator(true, validationTypes.STRING),
		"_t": validator(false, validationTypes.STRING),
		"branch_key": validator(true, validationTypes.STRING)
	}
};

resources.linkClick = {
	destination: "",
	endpoint: "",
	method: utils.httpMethod.GET,
	queryPart: {
		"link_url": validator(true, validationTypes.STRING)
	},
	params: {
		"click": validator(true, validationTypes.STRING)
	}
};

resources.SMSLinkSend = {
	destination: config.link_service_endpoint,
	endpoint: "/c",
	method: utils.httpMethod.POST,
	queryPart: {
		"link_url": validator(true, validationTypes.STRING)
	},
	params: {
		"sdk": validator(false, validationTypes.STRING),
		"phone": validator(true, validationTypes.STRING)
	}
};

resources.getCode = {
	destination: config.api_endpoint,
	endpoint: "/v1/referralcode",
	method: utils.httpMethod.POST,
	params: defaults({
		"amount": validator(true, validationTypes.NUMBER),
		"bucket": validator(false, validationTypes.STRING),
		"calculation_type": validator(true, validationTypes.NUMBER),
		"creation_source": validator(true, validationTypes.NUMBER),
		"expiration": validator(false, validationTypes.STRING),
		"location": validator(true, validationTypes.NUMBER),
		"prefix": validator(false, validationTypes.STRING),
		"type": validator(true, validationTypes.STRING)
	})
};

resources.validateCode = {
	destination: config.api_endpoint,
	endpoint: "/v1/referralcode",
	method: utils.httpMethod.POST,
	queryPart: {
		"code": validator(true, validationTypes.STRING)
	},
	params: defaults({ })
};

resources.applyCode = {
	destination: config.api_endpoint,
	endpoint: "/v1/applycode",
	method: utils.httpMethod.POST,
	queryPart: {
		"code": validator(true, validationTypes.STRING)
	},
	params: defaults({ })
};

resources.logout = {
	destination: config.api_endpoint,
	endpoint: "/v1/logout",
	method: utils.httpMethod.POST,
	params: defaults({
		"session_id": validator(true, validationTypes.STRING)
	})
};

resources.profile = {
	destination: config.api_endpoint,
	endpoint: "/v1/profile",
	method: utils.httpMethod.POST,
	params: defaults({
		"identity_id": validator(true, validationTypes.STRING),
		"identity": validator(true, validationTypes.STRING)
	})
};

resources.referrals = {
	destination: config.api_endpoint,
	endpoint: "/v1/referrals",
	method: utils.httpMethod.GET,
	queryPart: {
		"identity_id": validator(true, validationTypes.STRING)
	},
	params: defaults({ })
};

resources.creditHistory = {
	destination: config.api_endpoint,
	endpoint: "/v1/credithistory",
	method: utils.httpMethod.GET,
	params: defaults({
		"begin_after_id": validator(false, validationTypes.STRING),
		"bucket": validator(false, validationTypes.STRING),
		"direction": validator(false, validationTypes.NUMBER),
		"length": validator(false, validationTypes.NUMBER),
		"link_click_id": validator(false, validationTypes.STRING)
	})
};

resources.credits = {
	destination: config.api_endpoint,
	endpoint: "/v1/credits",
	method: utils.httpMethod.GET,
	params: defaults({
		"branch_key": validator(true, validationTypes.STRING),
		"identity": validator(true, validationTypes.STRING)
	})
};

resources.redeem = {
	destination: config.api_endpoint,
	endpoint: "/v1/redeem",
	method: utils.httpMethod.POST,
	params: defaults({
		"amount": validator(true, validationTypes.NUMBER),
		"bucket": validator(true, validationTypes.STRING),
		"identity_id": validator(true, validationTypes.STRING)
	})
};

resources.link = {
	destination: config.api_endpoint,
	endpoint: "/v1/url",
	method: utils.httpMethod.POST,
	ref: "obj",
	params: defaults({
		"alias": validator(false, validationTypes.STRING),
		"campaign": validator(false, validationTypes.STRING),
		"channel": validator(false, validationTypes.STRING),
		"data": validator(false, validationTypes.STRING),
		"feature": validator(false, validationTypes.STRING),
		"identity_id": validator(true, validationTypes.STRING),
		"stage": validator(false, validationTypes.STRING),
		"tags": validator(false, validationTypes.ARRAY),
		"type": validator(false, validationTypes.NUMBER),
		"source": validator(false, validationTypes.STRING),
		"instrumentation": validator(false, validationTypes.STRING)
	})
};

resources.deepview = {
	destination: config.api_endpoint,
	endpoint: "/v1/deepview",
	jsonp: true,
	method: utils.httpMethod.POST,
	params: defaults({
		"campaign": validator(false, validationTypes.STRING),
		"_t": validator(false, validationTypes.STRING),
		"channel": validator(false, validationTypes.STRING),
		"data": validator(true, validationTypes.STRING),
		"feature": validator(false, validationTypes.STRING),
		"link_click_id": validator(false, validationTypes.STRING),
		"open_app": validator(false, validationTypes.BOOLEAN),
		"append_deeplink_path": validator(false, validationTypes.BOOLEAN),
		"stage": validator(false, validationTypes.STRING),
		"tags": validator(false, validationTypes.ARRAY),
		"deepview_type": validator(true, validationTypes.STRING),
		"source": validator(true, validationTypes.STRING)
	})
};

resources.hasApp = {
	destination: config.api_endpoint,
	endpoint: "/v1/has-app",
	method: utils.httpMethod.GET,
	params: {
		"browser_fingerprint_id": validator(true, validationTypes.STRING),
		"instrumentation": validator(false, validationTypes.STRING)
	}
};

resources.event = {
	destination: config.api_endpoint,
	endpoint: "/v1/event",
	method: utils.httpMethod.POST,
	params: defaults({
		"event": validator(true, validationTypes.STRING),
		"metadata": validator(true, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"tracking_disabled": validator(false, validationTypes.BOOLEAN)
	})
};

resources.commerceEvent = {
	destination: config.api_endpoint,
	endpoint: "/v1/event",
	method: utils.httpMethod.POST,
	params: defaults({
		"event": validator(true, validationTypes.STRING),
		"metadata": validator(false, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"commerce_data": validator(true, validationTypes.OBJECT)
	})
};

// v2/event endpoints

resources.logStandardEvent = {
	destination: config.api_endpoint,
	endpoint: "/v2/event/standard",
	method: utils.httpMethod.POST,
	params: {
		"name": validator(true, validationTypes.STRING),
		"user_data": validator(true, validationTypes.STRING),
		"custom_data": validator(false, validationTypes.STRING),
		"event_data": validator(false, validationTypes.STRING),
		"content_items": validator(false, validationTypes.STRING),
		"customer_event_alias": validator(false, validationTypes.STRING)
	}
};

resources.logCustomEvent = {
	destination: config.api_endpoint,
	endpoint: "/v2/event/custom",
	method: utils.httpMethod.POST,
	params: {
		"name": validator(true, validationTypes.STRING),
		"user_data": validator(true, validationTypes.STRING),
		"custom_data": validator(false, validationTypes.STRING),
		"content_items": validator(false, validationTypes.STRING),
		"customer_event_alias": validator(false, validationTypes.STRING)
	}
};

resources.pageview = {
	destination: config.api_endpoint,
	endpoint: "/v1/pageview",
	method: utils.httpMethod.POST,
	params: defaults({
		"event": validator(true, validationTypes.STRING),
		"metadata": validator(false, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"tracking_disabled": validator(false, validationTypes.BOOLEAN),
		"branch_view_id": validator(false, validationTypes.STRING),
		"no_journeys": validator(false, validationTypes.BOOLEAN),
		"user_language": validator(false, validationTypes.STRING),
		"open_app": validator(false, validationTypes.BOOLEAN),
		"has_app_websdk": validator(false, validationTypes.BOOLEAN),
		"source": validator(false, validationTypes.STRING),
		"feature": validator(false, validationTypes.STRING),
		"is_iframe": validator(false, validationTypes.BOOLEAN),
		"data": validator(false, validationTypes.OBJECT),
		"callback_string": validator(false, validationTypes.STRING),
		"journey_displayed": validator(false, validationTypes.BOOLEAN),
		"audience_rule_id": validator(false, validationTypes.STRING),
		"journey_dismissals": validator(false, validationTypes.OBJECT),
		"identity": validator(false, validationTypes.STRING)
	})
};

resources.dismiss = {
	destination: config.api_endpoint,
	endpoint: "/v1/dismiss",
	method: utils.httpMethod.POST,
	params: defaults({
		"event": validator(true, validationTypes.STRING),
		"metadata": validator(false, validationTypes.OBJECT),
		"initial_referrer": validator(false, validationTypes.STRING),
		"tracking_disabled": validator(false, validationTypes.BOOLEAN),
		"branch_view_id": validator(false, validationTypes.STRING),
		"no_journeys": validator(false, validationTypes.BOOLEAN),
		"user_language": validator(false, validationTypes.STRING),
		"open_app": validator(false, validationTypes.BOOLEAN),
		"has_app_websdk": validator(false, validationTypes.BOOLEAN),
		"source": validator(false, validationTypes.STRING),
		"feature": validator(false, validationTypes.STRING),
		"is_iframe": validator(false, validationTypes.BOOLEAN),
		"data": validator(false, validationTypes.OBJECT),
		"callback_string": validator(false, validationTypes.STRING),
		"journey_displayed": validator(false, validationTypes.BOOLEAN),
		"audience_rule_id": validator(false, validationTypes.STRING),
		"journey_dismissals": validator(false, validationTypes.OBJECT),
		"dismissal_source": validator(false, validationTypes.STRING)
	})
};

resources.crossPlatformIds = {
	destination: config.api_endpoint,
	endpoint: "/v1/cpid",
	method: utils.httpMethod.POST,
	params: {
		"user_data": validator(true, validationTypes.STRING)
	}
};

resources.lastAttributedTouchData = {
	destination: config.api_endpoint,
	endpoint: "/v1/cpid/latd",
	method: utils.httpMethod.POST,
	params: {
		"user_data": validator(true, validationTypes.STRING)
	}
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name        Be Still, Cody
// @namespace   http://chomperstomp.com
// @version     0.1.0+012
// @description Cut out the useless Chatter
// @author      Christopher McCulloh
// @contributor Chris Corwin
// @match       https://org62.my.salesforce.com/*
// @updateURL   https://raw.githubusercontent.com/cormacmccarthy/be-still-cody/master/headphones.user.js
// @require     http://code.jquery.com/jquery-latest.js
// @grant       none
// ==/UserScript==

// the @require above should take care of this
// var jquery = document.createElement('script');
// jquery.src = "https://code.jquery.com/jquery-latest.js";
// document.getElementsByTagName('head')[0].appendChild(jquery);

// Add dependancies
var addDependancies = function addDependancies() {
	var injectedStyles = [
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
		//, "https:// NEED SOME WAY TO MAKE THIS USER-SPECIFIC AT BUILD TIME /headphones.user.css"
	];

	$.each(injectedStyles, function eachInjectedStyles(index, value) {
		$("head").append('<link href="' + value + '"' + ' rel="stylesheet" type="text/css">');
	});

	var injectedScripts = [
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"
	];

	$.each(injectedScripts, function eachInjectedScripts(index, value) {
		$("head").append('');
	});
}
addDependancies();

var trashBS = function trashBS() {
	// make tabs easier to access by assigning their text as class names
	$('#tabBar li').each(function eachTabBarLi(i, el) {
		var $el = $(el);
		$el.addClass($el.text().toLowerCase());
	});
	// Trash BS
	['.brandZeronaryFgr',// trash logo
		'#Contract_Tab', '#AdvForecast_Tab', '#Opportunity_Tab', '#Contact_Tab', '#Account_Tab', '#Lead_Tab', '#Campaign_Tab', '#Case_Tab', '#Solution_Tab', '#report_Tab', '#Document_Tab', '#Workspace_Tab', '#ContentSearch_Tab', '#File_Tab', '#phHeader .left', '#bodyCell .links', '#presence_widget', '#tabBar .partner.applications', '#tabBar .sales.central', '#tabBar .companies', '.recElement.todoElement',// trash annoyingly bright yellow box thing
		'#section_header',// trash the amazing-space-eating "hide/show feed" button that for some reason needs its own huge bar. Well, trash the whole bar!
		'#ptBody',// trash pointless redundant egotistical feed header
		'.zen-branding',// trash logo
		'a[href^="javascript:openPopupFocusEscapePounds"]',// remove useless links to help docs
		'.chatterUserStatus',// trash redundant profile pic and link in Chatter
		'.headerContent'// trash pointless huge "salesforce.com" text and invisible header bar
	].forEach(function eachBS(el, i, bs) {
		$(el).remove();
	});
}
trashBS();

// Trash BS that loads really slowly
var trashSlowBS = function trashSlowBS() {
	['#presence_widget'].forEach(function eachPresenceWidget(el, i, bs) {
		$(el).remove();
	});

	$('.x-zen-tabMenu').addClass('nav').addClass('nav-pills');

	$('.feedcontainer .feeditemcommentplaceholder input').addClass('feedcontainerFeeditemcommentplaceholderInput');
	$('.feedcontainer .feeditemcommentplaceholder label span').addClass('feedcontainerFeeditemcommentplaceholderLabelSpan');
	$('.feedcontainer .feeditemcommentphoto img').addClass('feedcontainerFeeditemcommentphotoImg');
	$('.mainContentHeader').addClass('zen hidden');
	$('.headerContent').addClass('fade collapse');
	$('.zen-headerTop').addClass('pull-right');
	$('.zen-navViaMenus').addClass('pull-right');

	$('.leftContent ul').addClass('nav').addClass('nav-pills').addClass('nav-stacked');
	$('.selected').addClass('active').removeClass('selected');
	$('.zen-active').addClass('active').removeClass('zen-active');
	$('.zen-assistiveText').addClass('sr-only').removeClass('zen-assistiveText');
	$('.x-zen-assistiveText').addClass('sr-only').removeClass('x-zen-assistiveText');
	$('.brandPrimaryBgr').removeClass('brandPrimaryBgr');
	$('.primaryPalette').removeClass('primaryPalette');
	$('.zen-bodyZen').addClass('panel').addClass('panel-default').removeClass('zen-bodyZen').removeClass('brdPalette').removeClass('brandPrimaryBrd');
	$('.zen-navMenus').addClass('zen');
	$('.zen-bodyInner').addClass('panel-body').removeClass('zen-bodyInner');
	$('.leftContent').addClass('well');
	$('#rightContent').addClass('panel').addClass('panel-default');
	$('#rightContent > div').addClass('panel-body');
	$('html').addClass('fuelux').removeClass('zen');
	$('.zen-page > div > header').addClass('zen well');
	$('.menuButtonRounded').addClass('dropdown').removeClass('menuButtonRounded');
	$('.menuButtonButton').addClass('btn btn-primary dropdown-toggle').removeClass('menuButtonButton');
	$('link[href="/sCSS/33.0/sprites/1423103332000/Theme3/default/gc/zenifiedChatterPageBase.css"').remove();
	$('.feeditem').addClass('panel panel-default').removeClass('feeditem');
	$('.feeditemusericon').parent('a').parent('span').wrap('

');
	$('.feeditemusericon').removeClass('feeditemusericon');
	$('.feeditemcontent').addClass('panel-body').removeClass('feeditemcontent');
	$('.feeditemextras').addClass('well').removeClass('feeditemextras');
	$('.feeditemcomments').removeClass('feeditemcomments');
	$('.feeditemcomment').removeClass('feeditemcomment').addClass('panel panel-info');
	$('.feeditemcommentbody').removeClass('feeditemcommentbody').addClass('panel-body');
	$('.feeditemcommentphoto').addClass('pull-left');
	$('.feeditemcommentplaceholder').addClass('well').removeClass('feeditemcommentplaceholder');
	$('.newCommentContainer').addClass('well');
	$('.headerSearchLeftRoundedCorner').removeClass('headerSearchLeftRoundedCorner');

	window.setTimeout(trashSlowBS, 2000);
}
trashSlowBS();

var betterMuteButton = function betterMuteButton() {
	$('.cxfeeditem')
		.each(function eachFeedItem(i, el) {
			var $el = $(el);
			if ($el.find('.hideFeedItem')
					.length <= 0) {
				var id = $el[0].id;
				$el.find('.preamblecontainer.displayblock')
					.append('hide');
			}
		});
	$('.hideFeedItem')
		.on('click', function onClickHideFeedItem(e) {
			e.preventDefault();
			chatter.getFeed()
				.muteItem(this, $(this)
					.data('id'));
		});
	window.setTimeout(betterMuteButton, 4500);
}

var attachChatterChanges = function attachChatterChanges() {
	console.log('chatter is defined!', chatter, chatter.ext_Feed);

	chatter.ext_Feed.muteItem = function muteItem(element, c) {
		// var b = $(element).closest(".cxfeeditem").data('feedItem').feeditemtype;
		var toolbox = chatter.getToolbox();
		toolbox.mask(Ext.fly(element));
		toolbox.post({
			url: "/feeditems/" + c + "/mute",
			success: function toolboxPostSuccess(b, c) {
				$(element)
					.closest('.cxfeeditem')
					.remove();
			}
		});
		chatter.getEventBus()
			.fireEvent("chatter:feed", "onAfterDeleteFeedItem", {
				el: this
			})
	};

	betterMuteButton();
}
window.setTimeout(attachChatterChanges, 4500);

$('.cxshowmorefeeditemscontainer.showmorefeeditemscontainer a')
	.on('click', function callBetterMuteButton(e) {
		window.setTimeout(betterMuteButton, 4500);
	});

// Add some handy string manipulation stuff to JavaScript itself.
String.prototype.endsWith = function endsWith(value) {
	if (this.length < value.length) {
		return false;
	} else {
		return Boolean(this.substr(this.length - value.length, value.length + 1) === value);
	}
};
String.prototype.contains = function contains(value, caseFlag) {
	if (this.length < value.length) {
		return false;
	} else {
		var regExPattern_value = caseFlag === false ? new RegExp(value, "i") : new RegExp(value);
		return Boolean(this.match(regExPattern_value));
	}
};

String.prototype.beginsWith = function beginsWith(string) {
	return this.indexOf(string) === 0;
};

// Make a jQuery class stripper.
var disableZen = function disableZen(el) {
	prefix = "zen-";
	var $zenElements = $(el);
	$zenElements.each(function disableEachZenElement(i, el) {
		var $thisElement = $(el);

		var oldClassNames = $thisElement.attr("class").split(" ");
		var newClassNames = "";
		$thisElement.attr("data-previous-class-names", $thisElement.attr("class"));
		$.each(oldClassNames, function (index, value) {
			if (value.beginsWith(prefix)) {
				newClassNames = newClassNames + " " + "x-" + value;
				$thisElement.attr( ("data-had-zen-class-" + value), "true");
			}
		});
		el.className = newClassNames;
	});
	return $zenElements;
};
disableZen();

var removeZenPrefix = function removeZenPrefix(el) {
	prefix = "zen-";
	var $zenElements = $(el);
	$zenElements.each(function removeEachZenElement(i, el) {
		var classes = el.className.split(" ").filter(function (c) {
			console.log("c.lastIndexOf( prefix, 0 )", c.lastIndexOf(prefix, 0));
			console.log("c.lastIndexOf( prefix, 0 ) !== 0", c.lastIndexOf(prefix, 0) !== 0);
			return c.lastIndexOf(prefix, 0) !== 0;
		});
		el.className = $.trim(classes.join(" "));
	});
	return $zenElements;
};
removeZenPrefix();
<commit_msg>(master) updates version<commit_after>// ==UserScript==
// @name        Be Still, Cody
// @namespace   http://chomperstomp.com
// @version     0.1.0+013
// @description Cut out the useless Chatter
// @author      Christopher McCulloh
// @contributor Chris Corwin
// @match       https://org62.my.salesforce.com/*
// @updateURL   https://raw.githubusercontent.com/cormacmccarthy/be-still-cody/master/headphones.user.js
// @require     http://code.jquery.com/jquery-latest.js
// @grant       none
// ==/UserScript==

// the @require above should take care of this
// var jquery = document.createElement('script');
// jquery.src = "https://code.jquery.com/jquery-latest.js";
// document.getElementsByTagName('head')[0].appendChild(jquery);

// Add dependancies
var addDependancies = function addDependancies() {
	var injectedStyles = [
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
		//, "https:// NEED SOME WAY TO MAKE THIS USER-SPECIFIC AT BUILD TIME /headphones.user.css"
	];

	$.each(injectedStyles, function eachInjectedStyles(index, value) {
		$("head").append('<link href="' + value + '"' + ' rel="stylesheet" type="text/css">');
	});

	var injectedScripts = [
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"
	];

	$.each(injectedScripts, function eachInjectedScripts(index, value) {
		$("head").append('');
	});
}
addDependancies();

var trashBS = function trashBS() {
	// make tabs easier to access by assigning their text as class names
	$('#tabBar li').each(function eachTabBarLi(i, el) {
		var $el = $(el);
		$el.addClass($el.text().toLowerCase());
	});
	// Trash BS
	['.brandZeronaryFgr',// trash logo
		'#Contract_Tab', '#AdvForecast_Tab', '#Opportunity_Tab', '#Contact_Tab', '#Account_Tab', '#Lead_Tab', '#Campaign_Tab', '#Case_Tab', '#Solution_Tab', '#report_Tab', '#Document_Tab', '#Workspace_Tab', '#ContentSearch_Tab', '#File_Tab', '#phHeader .left', '#bodyCell .links', '#presence_widget', '#tabBar .partner.applications', '#tabBar .sales.central', '#tabBar .companies', '.recElement.todoElement',// trash annoyingly bright yellow box thing
		'#section_header',// trash the amazing-space-eating "hide/show feed" button that for some reason needs its own huge bar. Well, trash the whole bar!
		'#ptBody',// trash pointless redundant egotistical feed header
		'.zen-branding',// trash logo
		'a[href^="javascript:openPopupFocusEscapePounds"]',// remove useless links to help docs
		'.chatterUserStatus',// trash redundant profile pic and link in Chatter
		'.headerContent'// trash pointless huge "salesforce.com" text and invisible header bar
	].forEach(function eachBS(el, i, bs) {
		$(el).remove();
	});
}
trashBS();

// Trash BS that loads really slowly
var trashSlowBS = function trashSlowBS() {
	['#presence_widget'].forEach(function eachPresenceWidget(el, i, bs) {
		$(el).remove();
	});

	$('.x-zen-tabMenu').addClass('nav').addClass('nav-pills');

	$('.feedcontainer .feeditemcommentplaceholder input').addClass('feedcontainerFeeditemcommentplaceholderInput');
	$('.feedcontainer .feeditemcommentplaceholder label span').addClass('feedcontainerFeeditemcommentplaceholderLabelSpan');
	$('.feedcontainer .feeditemcommentphoto img').addClass('feedcontainerFeeditemcommentphotoImg');
	$('.mainContentHeader').addClass('zen hidden');
	$('.headerContent').addClass('fade collapse');
	$('.zen-headerTop').addClass('pull-right');
	$('.zen-navViaMenus').addClass('pull-right');

	$('.leftContent ul').addClass('nav').addClass('nav-pills').addClass('nav-stacked');
	$('.selected').addClass('active').removeClass('selected');
	$('.zen-active').addClass('active').removeClass('zen-active');
	$('.zen-assistiveText').addClass('sr-only').removeClass('zen-assistiveText');
	$('.x-zen-assistiveText').addClass('sr-only').removeClass('x-zen-assistiveText');
	$('.brandPrimaryBgr').removeClass('brandPrimaryBgr');
	$('.primaryPalette').removeClass('primaryPalette');
	$('.zen-bodyZen').addClass('panel').addClass('panel-default').removeClass('zen-bodyZen').removeClass('brdPalette').removeClass('brandPrimaryBrd');
	$('.zen-navMenus').addClass('zen');
	$('.zen-bodyInner').addClass('panel-body').removeClass('zen-bodyInner');
	$('.leftContent').addClass('well');
	$('#rightContent').addClass('panel').addClass('panel-default');
	$('#rightContent > div').addClass('panel-body');
	$('html').addClass('fuelux').removeClass('zen');
	$('.zen-page > div > header').addClass('zen well');
	$('.menuButtonRounded').addClass('dropdown').removeClass('menuButtonRounded');
	$('.menuButtonButton').addClass('btn btn-primary dropdown-toggle').removeClass('menuButtonButton');
	$('link[href="/sCSS/33.0/sprites/1423103332000/Theme3/default/gc/zenifiedChatterPageBase.css"').remove();
	$('.feeditem').addClass('panel panel-default').removeClass('feeditem');
	$('.feeditemusericon').parent('a').parent('span').wrap('

');
	$('.feeditemusericon').removeClass('feeditemusericon');
	$('.feeditemcontent').addClass('panel-body').removeClass('feeditemcontent');
	$('.feeditemextras').addClass('well').removeClass('feeditemextras');
	$('.feeditemcomments').removeClass('feeditemcomments');
	$('.feeditemcomment').removeClass('feeditemcomment').addClass('panel panel-info');
	$('.feeditemcommentbody').removeClass('feeditemcommentbody').addClass('panel-body');
	$('.feeditemcommentphoto').addClass('pull-left');
	$('.feeditemcommentplaceholder').addClass('well').removeClass('feeditemcommentplaceholder');
	$('.newCommentContainer').addClass('well');
	$('.headerSearchLeftRoundedCorner').removeClass('headerSearchLeftRoundedCorner');

	window.setTimeout(trashSlowBS, 2000);
}
trashSlowBS();

var betterMuteButton = function betterMuteButton() {
	$('.cxfeeditem')
		.each(function eachFeedItem(i, el) {
			var $el = $(el);
			if ($el.find('.hideFeedItem')
					.length <= 0) {
				var id = $el[0].id;
				$el.find('.preamblecontainer.displayblock')
					.append('hide');
			}
		});
	$('.hideFeedItem')
		.on('click', function onClickHideFeedItem(e) {
			e.preventDefault();
			chatter.getFeed()
				.muteItem(this, $(this)
					.data('id'));
		});
	window.setTimeout(betterMuteButton, 4500);
}

var attachChatterChanges = function attachChatterChanges() {
	console.log('chatter is defined!', chatter, chatter.ext_Feed);

	chatter.ext_Feed.muteItem = function muteItem(element, c) {
		// var b = $(element).closest(".cxfeeditem").data('feedItem').feeditemtype;
		var toolbox = chatter.getToolbox();
		toolbox.mask(Ext.fly(element));
		toolbox.post({
			url: "/feeditems/" + c + "/mute",
			success: function toolboxPostSuccess(b, c) {
				$(element)
					.closest('.cxfeeditem')
					.remove();
			}
		});
		chatter.getEventBus()
			.fireEvent("chatter:feed", "onAfterDeleteFeedItem", {
				el: this
			})
	};

	betterMuteButton();
}
window.setTimeout(attachChatterChanges, 4500);

$('.cxshowmorefeeditemscontainer.showmorefeeditemscontainer a')
	.on('click', function callBetterMuteButton(e) {
		window.setTimeout(betterMuteButton, 4500);
	});

// Add some handy string manipulation stuff to JavaScript itself.
String.prototype.endsWith = function endsWith(value) {
	if (this.length < value.length) {
		return false;
	} else {
		return Boolean(this.substr(this.length - value.length, value.length + 1) === value);
	}
};
String.prototype.contains = function contains(value, caseFlag) {
	if (this.length < value.length) {
		return false;
	} else {
		var regExPattern_value = caseFlag === false ? new RegExp(value, "i") : new RegExp(value);
		return Boolean(this.match(regExPattern_value));
	}
};

String.prototype.beginsWith = function beginsWith(string) {
	return this.indexOf(string) === 0;
};

// Make a jQuery class stripper.
var disableZen = function disableZen(el) {
	prefix = "zen-";
	var $zenElements = $(el);
	$zenElements.each(function disableEachZenElement(i, el) {
		var $thisElement = $(el);

		var oldClassNames = $thisElement.attr("class").split(" ");
		var newClassNames = "";
		$thisElement.attr("data-previous-class-names", $thisElement.attr("class"));
		$.each(oldClassNames, function (index, value) {
			if (value.beginsWith(prefix)) {
				newClassNames = newClassNames + " " + "x-" + value;
				$thisElement.attr( ("data-had-zen-class-" + value), "true");
			}
		});
		el.className = newClassNames;
	});
	return $zenElements;
};
disableZen();

var removeZenPrefix = function removeZenPrefix(el) {
	prefix = "zen-";
	var $zenElements = $(el);
	$zenElements.each(function removeEachZenElement(i, el) {
		var classes = el.className.split(" ").filter(function (c) {
			console.log("c.lastIndexOf( prefix, 0 )", c.lastIndexOf(prefix, 0));
			console.log("c.lastIndexOf( prefix, 0 ) !== 0", c.lastIndexOf(prefix, 0) !== 0);
			return c.lastIndexOf(prefix, 0) !== 0;
		});
		el.className = $.trim(classes.join(" "));
	});
	return $zenElements;
};
removeZenPrefix();
<|endoftext|>


<commit_before><commit_msg>Tiny commented-out experiment for the thumbnail mentioned in Issue 208<commit_after><|endoftext|>


<commit_before>var gulp = require("gulp"),
    less = require("gulp-less"),
    streamify = require("gulp-streamify"),
    uglify = require("gulp-uglify"),
    rename = require("gulp-rename"),
    minify = require("gulp-minify-css"),
    source = require("vinyl-source-stream"),
    merge = require("merge"),
    browserify = require("browserify"),
    watchify = require("watchify");
    path = require("path");

var paths = {
        styles: ["./assets/styles/*.less"],
        scripts: ["./assets/scripts/*.js"]
};

var b = browserify(merge(watchify.args, {
    entries: [__dirname + "/assets/scripts/index.js"]
    //debug: true
}));

var w = watchify(b);

function logError(err) {
    console.log(err);
    this.emit("end");
}

gulp.task("watch", function() {
    gulp.watch(paths.styles, ["styles"]);
    gulp.watch(paths.scripts, ["scripts"]);
});

gulp.task("styles", function() {
    return gulp.src("./assets/styles/main.less")
        .pipe(less({
            paths: [__dirname + "/assets/styles/", __dirname + "/node_modules/"]
        }))
        .on("error", logError)
        .pipe(minify())
        .pipe(rename("bundle.css"))
        .pipe(gulp.dest("./public/"));
});

gulp.task("scripts", function() {
    return watchify(b).bundle()
        .on("error", logError)
        .pipe(source("bundle.js"))
        .pipe(streamify(uglify()))
        .pipe(rename("bundle.js"))
        .pipe(gulp.dest("./public/"));
});

gulp.on("stop", function() {
    process.exit(0);
});

gulp.task("build", ["styles", "scripts"]);
gulp.task("dev", ["build", "watch"]);
<commit_msg>npm run dev no longer exits once it's finished<commit_after>var gulp = require("gulp"),
    less = require("gulp-less"),
    streamify = require("gulp-streamify"),
    uglify = require("gulp-uglify"),
    rename = require("gulp-rename"),
    minify = require("gulp-minify-css"),
    source = require("vinyl-source-stream"),
    merge = require("merge"),
    browserify = require("browserify"),
    watchify = require("watchify");
    path = require("path");

var paths = {
        styles: ["./assets/styles/*.less"],
        scripts: ["./assets/scripts/*.js"]
};

var b = browserify(merge(watchify.args, {
    entries: [__dirname + "/assets/scripts/index.js"]
    //debug: true
}));

var w = watchify(b);

function logError(err) {
    console.log(err);
    this.emit("end");
}

gulp.task("watch", function() {
    gulp.watch(paths.styles, ["styles"]);
    gulp.watch(paths.scripts, ["scripts"]);
});

gulp.task("styles", function() {
    return gulp.src("./assets/styles/main.less")
        .pipe(less({
            paths: [__dirname + "/assets/styles/", __dirname + "/node_modules/"]
        }))
        .on("error", logError)
        .pipe(minify())
        .pipe(rename("bundle.css"))
        .pipe(gulp.dest("./public/"));
});

gulp.task("scripts", function() {
    return watchify(b).bundle()
        .on("error", logError)
        .pipe(source("bundle.js"))
        .pipe(streamify(uglify()))
        .pipe(rename("bundle.js"))
        .pipe(gulp.dest("./public/"));
});

gulp.task("finish", function() {
    gulp.on("stop", function() {
        process.exit(0);
    });
});

gulp.task("build", ["styles", "scripts", "finish"]);
gulp.task("dev", ["styles", "scripts", "watch"]);
<|endoftext|>


<commit_before>var gulp = require('gulp');

var paths = {
    configMaster: './config.yaml',
    configOwn: '../customconfig.yaml',
    output: '../output'
};

gulp.task('default', ['build']);

gulp.task('watch', function(){
    gulp.watch(paths.configMaster, ['build']);
});

gulp.task('build', function() {
    var YAML = require('yamljs');
    var replace = require('gulp-replace');
    var configOwnObject = YAML.load(paths.configOwn);

    console.log(configOwnObject);

    return gulp.src(paths.configMaster)
        .pipe(replace(/#@.*@/g, function(match){
            var output = match;
            var cleanMatch = match.replace(/@/g, '').replace('#','');
            // console.log(cleanMatch); // TODO remove
            if(configOwnObject.hasOwnProperty(cleanMatch)){
                output = configOwnObject[cleanMatch];
            }
            // console.log(output); // TODO remove
            return output;
        }))
        .pipe(gulp.dest(paths.output));
});<commit_msg>missed a console.log()<commit_after>var gulp = require('gulp');

var paths = {
    configMaster: './config.yaml',
    configOwn: '../customconfig.yaml',
    output: '../output'
};

gulp.task('default', ['build']);

gulp.task('watch', function(){
    gulp.watch(paths.configMaster, ['build']);
});

gulp.task('build', function() {
    var YAML = require('yamljs');
    var replace = require('gulp-replace');
    var configOwnObject = YAML.load(paths.configOwn);

    // console.log(configOwnObject); // TODO remove

    return gulp.src(paths.configMaster)
        .pipe(replace(/#@.*@/g, function(match){
            var output = match;
            var cleanMatch = match.replace(/@/g, '').replace('#','');
            // console.log(cleanMatch); // TODO remove
            if(configOwnObject.hasOwnProperty(cleanMatch)){
                output = configOwnObject[cleanMatch];
            }
            // console.log(output); // TODO remove
            return output;
        }))
        .pipe(gulp.dest(paths.output));
});<|endoftext|>


<commit_before>/* jshint node: true */
"use strict";

var gulp = require("gulp"),
	g = require("gulp-load-plugins")({lazy: false}),
	rimraf = require("rimraf"),
	pkg = require("./package.json"),
	exec = require("child_process").exec;

/**
 * Helpers
 */

function shell(cmd) {
	exec(cmd, function (err, stdout, stderr) {
    if(stdout) {
			console.log(stdout);
		}
    if(stderr) {
			console.log(stderr);
		}
  });
}

/**
 * Scripts
 */
gulp.task("clean", function (done) {
	rimraf("dist/**/*.js", done);
});

gulp.task("scripts", ["clean"], function () {
	return gulp.src([
		"index.js"])
		.pipe(g.umd({
			dependencies: function() {
				return [
					{
						name: "jquery-deferred",
						amd: "jquery-deferred",
						cjs: "jquery-deferred",
						global: "$",
						param: "$"
					},
					{
						name: "lodash",
						amd: "lodash",
						cjs: "lodash",
						global: "_",
						param: "_"
					},
					{
						name: "moment",
						amd: "moment",
						cjs: "moment",
						global: "moment",
						param: "moment"
					}
				];
			},
			exports: function() {
				return "m11n";
			},
			namespace: function() {
				return "m11n";
			}
		}))
		.pipe( gulp.dest("dist/") )
		.pipe(g.uglify())
		.pipe(g.rename({
			suffix: ".min"
		}))
		.pipe( gulp.dest("dist/") );
});

/**
 * Package
 */
gulp.task("package", ["scripts"], function () {
  return gulp.src(["dist/*.js", "package.json", "bower.json"])
    .pipe(g.tar(pkg.name + ".tar"))
    .pipe(g.gzip())
    .pipe(gulp.dest('dist'));
});

/**
 * Release
 */
gulp.task("release", ["package"], function(){
	console.log("PACK: " + JSON.stringify(pkg.repository.url));
	/**
	*/
	gulp.src("./dist/" + pkg.name + ".tar.gz")
  	.pipe(g.githubRelease({
			owner: "vidakovic",
      repo: "develop",
			manifest: require("./package.json")
	 	}));
});

gulp.task("bump-major", function(){

	return gulp.src("./*.json")
		.pipe(g.bump({type:"major"}))
		.pipe(gulp.dest("./"));
});

gulp.task("bump-minor", function(){
	return gulp.src("./*.json")
		.pipe(g.bump({type:"minor"}))
		.pipe(gulp.dest("./"));
});

gulp.task("bump-patch", function(){
	return gulp.src("./*.json")
		.pipe(g.bump({type:"patch"}))
		.pipe(gulp.dest("./"));
});

gulp.task("build", ["package"]);

/**
 * Default task
 */
gulp.task("default", ["build"]);
<commit_msg>fix(build): Fix release configuration<commit_after>/* jshint node: true */
"use strict";

var gulp = require("gulp"),
	g = require("gulp-load-plugins")({lazy: false}),
	rimraf = require("rimraf"),
	pkg = require("./package.json"),
	exec = require("child_process").exec;

/**
 * Helpers
 */

function shell(cmd) {
	exec(cmd, function (err, stdout, stderr) {
    if(stdout) {
			console.log(stdout);
		}
    if(stderr) {
			console.log(stderr);
		}
  });
}

/**
 * Scripts
 */
gulp.task("clean", function (done) {
	rimraf("dist/**/*.js", done);
});

gulp.task("scripts", ["clean"], function () {
	return gulp.src([
		"index.js"])
		.pipe(g.umd({
			dependencies: function() {
				return [
					{
						name: "jquery-deferred",
						amd: "jquery-deferred",
						cjs: "jquery-deferred",
						global: "$",
						param: "$"
					},
					{
						name: "lodash",
						amd: "lodash",
						cjs: "lodash",
						global: "_",
						param: "_"
					},
					{
						name: "moment",
						amd: "moment",
						cjs: "moment",
						global: "moment",
						param: "moment"
					}
				];
			},
			exports: function() {
				return "m11n";
			},
			namespace: function() {
				return "m11n";
			}
		}))
		.pipe( gulp.dest("dist/") )
		.pipe(g.uglify())
		.pipe(g.rename({
			suffix: ".min"
		}))
		.pipe( gulp.dest("dist/") );
});

/**
 * Package
 */
gulp.task("package", ["scripts"], function () {
  return gulp.src(["dist/*.js", "package.json", "bower.json"])
    .pipe(g.tar(pkg.name + ".tar"))
    .pipe(g.gzip())
    .pipe(gulp.dest('dist'));
});

/**
 * Release
 */
gulp.task("release", ["package"], function(){
	console.log("PACK: " + JSON.stringify(pkg.repository.url));
	/**
	*/
	gulp.src("./dist/" + pkg.name + ".tar.gz")
  	.pipe(g.githubRelease({
			owner: "vidakovic",
      repo: pkg.name,
			manifest: pkg
	 	}));
});

gulp.task("bump-major", function(){

	return gulp.src("./*.json")
		.pipe(g.bump({type:"major"}))
		.pipe(gulp.dest("./"));
});

gulp.task("bump-minor", function(){
	return gulp.src("./*.json")
		.pipe(g.bump({type:"minor"}))
		.pipe(gulp.dest("./"));
});

gulp.task("bump-patch", function(){
	return gulp.src("./*.json")
		.pipe(g.bump({type:"patch"}))
		.pipe(gulp.dest("./"));
});

gulp.task("build", ["package"]);

/**
 * Default task
 */
gulp.task("default", ["build"]);
<|endoftext|>


<commit_before>var gulp = require('gulp');
var babel = require("gulp-babel");
var jasmine = require('gulp-jasmine');
var watch = require("gulp-watch");
var gutil = require('gulp-util');
var del = require("del");
var shell = require("gulp-shell");

var SRC = 'src/**/*.js';
var DIST = 'dist';
var SPEC = 'spec/';
var DOC = 'docs/';

gulp.task('cleanDist', function() {
    del(DIST);
});

gulp.task('cleanDocs', function() {
    del(DOC);
});

gulp.task('cleanAll', ['cleanSrc', 'cleanDocs']);

gulp.task('buildDocs', ['cleanDocs'], shell.task(['jsdoc -c conf.json -d docs -t ./node_modules/ink-docstrap/template -R README.md -r .']));

gulp.task('buildDocs:push', shell.task(['git subtree push --prefix docs origin gh-pages']));

gulp.task('buildSrc', ['cleanDist'], function() {
    return gulp.src(SRC)
        .pipe(babel())
        .pipe(gulp.dest(DIST));
});

gulp.task('buildAll', ['buildSrc', 'buildDocs']);

gulp.task('autoBuild', ['buildSrc'], function() {
    return gulp.src(SRC)
        .pipe(watch(SRC).on('change', function(path){
            gutil.log(`File ${path} has been changed`);
        }))
        .pipe(babel())
        .pipe(gulp.dest(DIST));
});

gulp.task('default', ['autoBuild']);

gulp.task('test', ['buildSrc'], function() {
   return gulp.src('spec/*')
        .pipe(jasmine());
});<commit_msg>linter task<commit_after>var gulp = require('gulp');
var babel = require("gulp-babel");
var jasmine = require('gulp-jasmine');
var watch = require("gulp-watch");
var gutil = require('gulp-util');
var del = require("del");
var shell = require("gulp-shell");

var SRC = 'src/**/*.js';
var DIST = 'dist';
var SPEC = 'spec/';
var DOC = 'docs/';

gulp.task('cleanDist', function() {
    del(DIST);
});

gulp.task('cleanDocs', function() {
    del(DOC);
});

gulp.task('cleanAll', ['cleanSrc', 'cleanDocs']);

gulp.task('buildDocs', ['cleanDocs'], shell.task(['jsdoc -c conf.json -d docs -t ./node_modules/ink-docstrap/template -R README.md -r .']));

gulp.task('buildDocs:push', shell.task(['git subtree push --prefix docs origin gh-pages']));

gulp.task('buildSrc', ['cleanDist'], function() {
    return gulp.src(SRC)
        .pipe(babel())
        .pipe(gulp.dest(DIST));
});

gulp.task('buildAll', ['buildSrc', 'buildDocs']);

gulp.task('autoBuild', ['buildSrc'], function() {
    return gulp.src(SRC)
        .pipe(watch(SRC).on('change', function(path){
            gutil.log(`File ${path} has been changed`);
        }))
        .pipe(babel())
        .pipe(gulp.dest(DIST));
});

gulp.task('default', ['autoBuild']);

gulp.task('test', ['buildSrc'], function() {
   return gulp.src('spec/*')
        .pipe(jasmine());
});

gulp.task('lint', function() {

});<|endoftext|>


<commit_before>var buffer			= require('buffer');
var del				= require('del');
var map				= require('map-stream');
var gulp			= require('gulp');
var gulpUglify		= require('gulp-uglify');
var postcss			= require('gulp-postcss');
var sourcemaps		= require('gulp-sourcemaps');
var autoprefixer	= require('autoprefixer');

gulp.task('build', function() {
	return clean().on('end', function() {
		copy().on('end', function() {
			autoprefix();
			bookmarklet();
		});
	});
});
gulp.task('live', function() {
	return copy('!./src/**/app.js').on('end', function() {
		autoprefix();
		bookmarklet();
	});
});
gulp.task('watch',function(){
	gulp.watch('./src/**/*', ['live']);
});
gulp.task('default', ['live', 'watch']);

function autoprefix() {
	return gulp.src('./src/**/*.css')
		.pipe(sourcemaps.init())
		.pipe(postcss([ autoprefixer({ browsers: ['last 3 versions'] }) ]))
		.pipe(sourcemaps.write('.'))
		.pipe(gulp.dest('./dest'));
}

function bookmarklet() {
	var header = new Buffer('javascript:void ');
	return gulp.src('./src/bookmarklet/style-validator.js')
		.pipe(gulpUglify())
		.pipe(map(function (file, cb) {
			file.contents = buffer.Buffer.concat([header, file.contents]);
			cb(null, file);
		}))
		.pipe(gulp.dest('./dest/bookmarklet'));
}

function copy(exceptionSrc) {
	var targetSrc = ['./src/**/*', './src/**/.*'];
	if(typeof exceptionSrc === 'string') {
		targetSrc.push(exceptionSrc);
	}
	return gulp.src(targetSrc)
		.pipe(gulp.dest('./dest'));
}

function clean() {
	return del(['./dest']);
}<commit_msg>fixed task of build<commit_after>var buffer			= require('buffer');
var del				= require('del');
var map				= require('map-stream');
var gulp			= require('gulp');
var gulpUglify		= require('gulp-uglify');
var postcss			= require('gulp-postcss');
var sourcemaps		= require('gulp-sourcemaps');
var autoprefixer	= require('autoprefixer');

gulp.task('clean', clean);
gulp.task('build', ['clean'], function() {
	return copy().on('end', function() {
		autoprefix();
		bookmarklet();
	});
});
gulp.task('live', function() {
	return copy('!./src/**/app.js').on('end', function() {
		autoprefix();
		bookmarklet();
	});
});
gulp.task('watch',function(){
	gulp.watch('./src/**/*', ['live']);
});
gulp.task('default', ['live', 'watch']);

function autoprefix() {
	return gulp.src('./src/**/*.css')
		.pipe(sourcemaps.init())
		.pipe(postcss([ autoprefixer({ browsers: ['last 3 versions'] }) ]))
		.pipe(sourcemaps.write('.'))
		.pipe(gulp.dest('./dest'));
}

function bookmarklet() {
	var header = new Buffer('javascript:void ');
	return gulp.src('./src/bookmarklet/style-validator.js')
		.pipe(gulpUglify())
		.pipe(map(function (file, cb) {
			file.contents = buffer.Buffer.concat([header, file.contents]);
			cb(null, file);
		}))
		.pipe(gulp.dest('./dest/bookmarklet'));
}

function copy(exceptionSrc) {
	var targetSrc = ['./src/**/*', './src/**/.*'];
	if(typeof exceptionSrc === 'string') {
		targetSrc.push(exceptionSrc);
	}
	return gulp.src(targetSrc)
		.pipe(gulp.dest('./dest'));
}

function clean() {
	return del(['./dest']);
}<|endoftext|>


<commit_before>const React = require('react')
import { Map, List, RenderSection, FromInventory, NextChapter} from 'windrift'

export default ({currentSection, inventory}) => {
  const sections = [

Windrift Starter

        Welcome to the Windrift Starter package. Lets try out a few features:

A List of two choices

        You can choose an item, and both items will remain displayed:

{`<List expansions={[["dogs", "cats"], ["dogs", "cats"]}} tag="animal" conjunction="or"/>`}

        Do you prefer <List expansions={[["dogs", "cats"], ["dogs", "cats"]]} tag="animal" conjunction="or"/>?

,

To display the user‘s response, just evaluate the inventory value in the markup directly:

{`<p>Hmm, {inventory.animal}, really?</p>`}

        Hmm, {inventory.animal}, really?

Doing transformations on responses

        If you want to modify the user's response somehow, like by pluralizing it,
        you can use the {`<FromInventory>`}
        component to do so safely (even if the value wasn't yet set by the user):

        One <FromInventory from={inventory.animal} onLoad={(from) => from.substring(0, from.length -1)} />, two{' '}
        {inventory.animal}. <FromInventory from={inventory.animal} onLoad={(from) => from.charAt(0).toUpperCase() + from.slice(1)} /> are great.

        If you expect to do a lot of these transformations, you could make a function or component
        to wrap them:

        YOU MUST REALLY LOVE <AllCaps text={inventory.animal} /> HUH

Expanding in-place for effect:

{`<List expansions={["acceptable", "understandable", "admirable"]} tag="adj1" />`}

        I suppose that's an <List expansions={["acceptable", "understandable", "admirable"]} tag="adj1" /> choice...

,

Pick one, retain the answer

{`<List expansions={[["Vladimir", "Xiùlán", "Ikiaq"], "_last"]} tag="name1" conjunction="or" />`}

        What would you like to name your pet {inventory.animal ? inventory.animal.substring(0, inventory.animal.length -1): null}:{' '}
        <List expansions={[["Vladimir", "Xiùlán", "Ikiaq"], "_last"]} tag="name1" conjunction="or" />

,

Evaluating two different choices

If you had two {inventory.animal}, what would you name the other one:{' '}
      <List expansions={[["Vladimir", "Xiùlán", "Ikiaq"], "_last"]} tag="name2" conjunction="or" />

,

      You can evaluate inventory values in ordinary JavaScript directly:

{`Looks like you'll have two {inventory.animal} named
    { inventory.name1 === inventory.name2 ? "the same" : "differently" }.`}

      Looks like you'll have two {inventory.animal} named { inventory.name1 === inventory.name2 ? "the same" : "differently" }.

Using Maps

      Maps can be used to simply return canned responses to choices:

{`<Map from={inventory.name2} to={{
      vladimir: " that's a fine Russian name",
      xiùlán: " that's a fine Chinese name",
      ikiaq: " that's a fine Inuit name"
    }}/>`}

      {inventory.name2}:
      <Map from={inventory.name2} to={{
        vladimir: " that's a fine Russian name",
        xiùlán: " that's a fine Chinese name",
        ikiaq: " that's a fine Inuit name"
      }}/>.

      But since Maps can return markup themselves, they can also be used to build up further choices:

{`<Map from={inventory.name2} to={{
      vladimir:
Since you like Russian names, why not pick a second one from this set:{' '}
      <List expansions={[["Alexei", "Darya", "Elena"], "_last"]} tag="name3" conjunction="or" />
,
      xiùlán:
Since you like Chinese names, why not pick a second one from this set:{' '}
      <List expansions={[["Li Jing", "Zhang Yan", "Wang Jie"], "_last"]} tag="name3" conjunction="or" />
,
      ikiaq:
Since you like Inuit names, why not pick a second one from this set:{' '}
      <List expansions={[["Naaqtuuq", "Pakak", "Toklo"], "_last"]} tag="name3" conjunction="or" />
,
    }}/>`}

      <Map from={inventory.name2} to={{
        vladimir:
Since you like Russian names, why not pick a second one from this set:{' '}
          <List expansions={[["Alexei", "Darya", "Elena"], "_last"]} tag="name3" conjunction="or" />
,
        xiùlán:
Since you like Chinese names, why not pick a second one from this set:{' '}
          <List expansions={[["Li Jing", "Zhang Yan", "Wang Jie"], "_last"]} tag="name3" conjunction="or" />
,
        ikiaq:
Since you like Inuit names, why not pick a second one from this set:{' '}
          <List expansions={[["Naaqtuuq", "Pakak", "Toklo"], "_last"]} tag="name3" conjunction="or" />
,
      }}/>

,

      For more advanced uses of Maps and Lists, see the Advanced demo and sample code.

      Great, you can now begin your story with your two {inventory.animal}, {inventory.name1} and {inventory.name3}.

    <NextChapter chapter={2}/>

  ]
  return <RenderSection currentSection={currentSection} sections={sections} />
}

const AllCaps = ({text}) => (
  <FromInventory from={text} onLoad={(text) => text.toUpperCase()} />
)
<commit_msg>More text<commit_after>const React = require('react')
import { Map, List, RenderSection, FromInventory, NextChapter} from 'windrift'

export default ({currentSection, inventory}) => {
  const sections = [

Windrift Starter

        Welcome to the starter application for Windrift, a framework
        for writing interactive stories. The source code for this demo is available in
        the windrift-starter repository.

        This page will walk through some of the most common features of a Windrift story,
        and can be used as a way to bootstrap your own story.

A List of two choices

        You can choose an item, and both items will remain displayed:

{`<List expansions={[["dogs", "cats"], ["dogs", "cats"]}} tag="animal" conjunction="or"/>`}

        Do you prefer <List expansions={[["dogs", "cats"], ["dogs", "cats"]]} tag="animal" conjunction="or"/>?

,

To display the user‘s response, just evaluate the inventory value in the markup directly:

{`<p>Hmm, {inventory.animal}, really?</p>`}

        Hmm, {inventory.animal}, really?

Doing transformations on responses

        If you want to modify the user's response somehow, like by pluralizing it,
        you can use the {`<FromInventory>`}
        component to do so safely (even if the value wasn't yet set by the user):

        One <FromInventory from={inventory.animal} onLoad={(from) => from.substring(0, from.length -1)} />, two{' '}
        {inventory.animal}. <FromInventory from={inventory.animal} onLoad={(from) => from.charAt(0).toUpperCase() + from.slice(1)} /> are great.

        If you expect to do a lot of these transformations, you could make a function or component
        to wrap them:

        YOU MUST REALLY LOVE <AllCaps text={inventory.animal} /> HUH

Expanding in-place for effect:

{`<List expansions={["acceptable", "understandable", "admirable"]} tag="adj1" />`}

        I suppose that's an <List expansions={["acceptable", "understandable", "admirable"]} tag="adj1" /> choice...

,

Pick one, retain the answer

{`<List expansions={[["Vladimir", "Xiùlán", "Ikiaq"], "_last"]} tag="name1" conjunction="or" />`}

        What would you like to name your pet {inventory.animal ? inventory.animal.substring(0, inventory.animal.length -1): null}:{' '}
        <List expansions={[["Vladimir", "Xiùlán", "Ikiaq"], "_last"]} tag="name1" conjunction="or" />

,

Evaluating two different choices

If you had two {inventory.animal}, what would you name the other one:{' '}
      <List expansions={[["Vladimir", "Xiùlán", "Ikiaq"], "_last"]} tag="name2" conjunction="or" />

,

      You can evaluate inventory values in ordinary JavaScript directly:

{`Looks like you'll have two {inventory.animal} named
    { inventory.name1 === inventory.name2 ? "the same" : "differently" }.`}

      Looks like you'll have two {inventory.animal} named { inventory.name1 === inventory.name2 ? "the same" : "differently" }.

Using Maps

      Maps can be used to simply return canned responses to choices:

{`<Map from={inventory.name2} to={{
      vladimir: " that's a fine Russian name",
      xiùlán: " that's a fine Chinese name",
      ikiaq: " that's a fine Inuit name"
    }}/>`}

      {inventory.name2}:
      <Map from={inventory.name2} to={{
        vladimir: " that's a fine Russian name",
        xiùlán: " that's a fine Chinese name",
        ikiaq: " that's a fine Inuit name"
      }}/>.

      But since Maps can return markup themselves, they can also be used to build up further choices:

{`<Map from={inventory.name2} to={{
      vladimir:
Since you like Russian names, why not pick a second one from this set:{' '}
      <List expansions={[["Alexei", "Darya", "Elena"], "_last"]} tag="name3" conjunction="or" />
,
      xiùlán:
Since you like Chinese names, why not pick a second one from this set:{' '}
      <List expansions={[["Li Jing", "Zhang Yan", "Wang Jie"], "_last"]} tag="name3" conjunction="or" />
,
      ikiaq:
Since you like Inuit names, why not pick a second one from this set:{' '}
      <List expansions={[["Naaqtuuq", "Pakak", "Toklo"], "_last"]} tag="name3" conjunction="or" />
,
    }}/>`}

      <Map from={inventory.name2} to={{
        vladimir:
Since you like Russian names, why not pick a second one from this set:{' '}
          <List expansions={[["Alexei", "Darya", "Elena"], "_last"]} tag="name3" conjunction="or" />
,
        xiùlán:
Since you like Chinese names, why not pick a second one from this set:{' '}
          <List expansions={[["Li Jing", "Zhang Yan", "Wang Jie"], "_last"]} tag="name3" conjunction="or" />
,
        ikiaq:
Since you like Inuit names, why not pick a second one from this set:{' '}
          <List expansions={[["Naaqtuuq", "Pakak", "Toklo"], "_last"]} tag="name3" conjunction="or" />
,
      }}/>

,

      For more advanced uses of Maps and Lists, see the Advanced demo and sample code.

      Great, you can now begin your story with your two {inventory.animal}, {inventory.name1} and {inventory.name3}.

    <NextChapter chapter={2}/>

  ]
  return <RenderSection currentSection={currentSection} sections={sections} />
}

const AllCaps = ({text}) => (
  <FromInventory from={text} onLoad={(text) => text.toUpperCase()} />
)
<|endoftext|>


<commit_before>var gulp = require('gulp');
var plugins = require('gulp-load-plugins')();

var del = require('del');
var merge = require('merge-stream');

// ============================================================================
// ****************************** CONFIGURATION *******************************
// ============================================================================

var argv = require('yargs')
    .options({
        'community': {
            alias: 'ce',
            describe: 'trigger the Community Edition build',
            type: 'boolean'
        },
        'development': {
            alias: 'dev',
            describe: 'enable Mapplic developer mode (display coordinates of the cursor)',
            type: 'boolean'
        },
        'language': {
            alias: 'lang',
            // Two-letter codes of target languages on Crowdin:
            choices: ['en', 'fr', 'it', 'ru'],
            default: 'en',
            describe: 'set the default language',
            nargs: 1,
            type: 'string'
        }
    })
    .argv;

var path = {
    source: {
        css: 'source/scss/style.scss',
        data: 'source/data/**/*.json',
        fonts: 'source/vendor/font-awesome/fonts/fontawesome-webfont.*',
        html: 'source/templates/**/[^_]*.njk',
        js: 'source/js/*.js',
        images: 'source/images/**/*.*'
    },
    build: {
        css: 'build/storage/css/',
        data: 'build/storage/data/',
        fonts: 'build/storage/fonts/',
        html: 'build/',
        js: 'build/storage/js/',
        images: 'build/storage/images/'
    },
    clean: {
        all: 'build/'
    }
};

var nunjucks = {
    js: {
        path: 'source/vendor/',
        ext: '.js',
        // Exclude jQuery from the Regular build:
        data: {common: {jquery: argv.community ? false : true}}
    },
    html: {
        path: 'source/templates/',
        data: {
            // Configure the layout:
            community: argv.community,
            default_language: argv.language,
            developer_mode: argv.development ? true : false,
            translations_excluded: [],
            analytics_id: argv.community ? false : '31374838',
            base_url: 'http://nether-whisper.ru/rp/planescape/map-of-sigil/',
            robots: argv.community ? 'noindex, nofollow' : 'index, nofollow, noarchive',
            ogp: argv.community ? false : true,
            swiftype: argv.community ? false : true,
            common: {
                jquery: argv.community ? false : '/storage/js/jquery.min.js',
                favicons: argv.community ? false : {
                    dir: '/storage/images/favicons/',
                    size: ['96x96', '32x32', '16x16']
                }
            }
        }
    }
};

// ============================================================================
// ********************************* UTILITIES ********************************
// ============================================================================

// Exclude incomplete and unreleased translations -----------------------------
var exclude_list = argv.community ? ['fr', 'it', 'ru'] : ['it', 'ru'];

if (exclude_list.indexOf(argv.language) > -1) {
    plugins.util.log('This translation is incomplete and cannot be set as default.');
    process.exit(1);
} else {
    function exclude_translations(source) {
        return source.replace('**', '!(' + exclude_list.join('|') + ')');
    };

    path.source.images = exclude_translations(path.source.images);
    path.source.data = exclude_translations(path.source.data);
    path.source.html = exclude_translations(path.source.html);

    nunjucks.html.data.translations_excluded = exclude_list;
};

// Format error messages and force exit code 1 on error -----------------------
var on_error = function(error) {
    plugins.util.log(plugins.util.colors.red('[ERROR]:', error.name, error.message));
    process.exit(1);
};

// Announce the build type: Regular or Community Edition ----------------------
if (argv.community) {
    plugins.util.log('Building the map of Sigil',  '(Community Edition, default language: ' + argv.language + ')');
} else {
    plugins.util.log('Building the map of Sigil',  '(default language: ' + argv.language + ')');
};

// ============================================================================
// ********************************** TASKS ***********************************
// ============================================================================

// Clean the build ------------------------------------------------------------
gulp.task('clean:all', function() {
    return del.sync(path.clean.all);
});

// Back up dependencies to “source/vendor” ====================================

// Shared pipes to fetch the Mapplic package if it’s installed ----------------
var fetch_mapplic_images = gulp.src('node_modules/mapplic/html/mapplic/images/*.*')
    .pipe(plugins.changed('source/vendor/mapplic/images/'))
    .pipe(gulp.dest('source/vendor/mapplic/images/'));

var fetch_mapplic = gulp.src([
    'node_modules/mapplic/html/mapplic/mapplic?(-ie).css',
    'node_modules/mapplic/html/mapplic/mapplic.js',
])
    .pipe(plugins.changed('source/vendor/mapplic/'))
    .pipe(gulp.dest('source/vendor/mapplic/'));

// Fetch all packages ---------------------------------------------------------
gulp.task('fetch:vendor', function() {
    var jquery = gulp.src('node_modules/jquery/dist/jquery.js')
        .pipe(plugins.changed('source/vendor/jquery/'))
        .pipe(gulp.dest('source/vendor/jquery/'));

    var jquery_mousewheel = gulp.src('node_modules/jquery-mousewheel/jquery.mousewheel.js')
        .pipe(plugins.changed('source/vendor/jquery.mousewheel/'))
        .pipe(gulp.dest('source/vendor/jquery.mousewheel/'));

    var hammerjs = gulp.src('node_modules/hammerjs/hammer.js')
        .pipe(plugins.changed('source/vendor/hammer.js/'))
        .pipe(gulp.dest('source/vendor/hammer.js/'));

    var magnific_popup = gulp.src([
        'node_modules/magnific-popup/dist/jquery.magnific-popup.js',
        'node_modules/magnific-popup/dist/magnific-popup.css'
    ])
        .pipe(plugins.changed('source/vendor/magnific-popup/'))
        .pipe(gulp.dest('source/vendor/magnific-popup/'));

    var normalize = gulp.src('node_modules/normalize.css/normalize.css')
        .pipe(plugins.changed('source/vendor/normalize.css/'))
        .pipe(gulp.dest('source/vendor/normalize.css/'));

    var fa_fonts = gulp.src('node_modules/font-awesome/fonts/fontawesome-webfont.*')
        .pipe(plugins.changed('source/vendor/font-awesome/fonts/'))
        .pipe(gulp.dest('source/vendor/font-awesome/fonts/'));

    var fa_css = gulp.src('node_modules/font-awesome/css/font-awesome.css')
        .pipe(plugins.changed('source/vendor/font-awesome/'))
        .pipe(gulp.dest('source/vendor/font-awesome/'));

    return merge(
        jquery,
        jquery_mousewheel,
        hammerjs,
        magnific_popup,
        normalize,
        fa_fonts, fa_css,
        fetch_mapplic_images, fetch_mapplic
    );
});

// Fetch only the Mapplic package ---------------------------------------------
gulp.task('fetch:mapplic', function() {
    return merge(fetch_mapplic_images, fetch_mapplic);
});

// GO, DABUS, GO ==============================================================

// Copy fonts -----------------------------------------------------------------
gulp.task('build:fonts', function() {
    return gulp.src(path.source.fonts)
        .pipe(plugins.changed(path.build.fonts))
        .pipe(gulp.dest(path.build.fonts));
});

// Copy images ----------------------------------------------------------------
gulp.task('build:images', function() {
    function add_pipe(src, dest) {
        return gulp.src(src)
            .pipe(plugins.changed(dest))
            .pipe(gulp.dest(dest));
    };

    var copy_images = add_pipe(path.source.images, path.build.images);
    var copy_mapplic_images = add_pipe(['source/vendor/mapplic/images/**/*.*', '!source/vendor/mapplic/images/alpha{20,50}.png'], path.build.images + 'mapplic/');

    return merge(copy_images, copy_mapplic_images);
});

// Copy map data --------------------------------------------------------------
gulp.task('build:data', function() {
    var token = 'source/data/' + argv.language + '/*.json';

    var build_default = gulp.src(token)
        .pipe(plugins.changed(path.build.data))
        .pipe(plugins.lineEndingCorrector())
        .pipe(gulp.dest(path.build.data + argv.language + '/'));

    var build_other = gulp.src([path.source.data, '!' + token])
        .pipe(plugins.changed(path.build.data))
        .pipe(plugins.replace('storage/images/', '../storage/images/'))
        .pipe(plugins.lineEndingCorrector())
        .pipe(gulp.dest(path.build.data));

    return merge(build_default, build_other);
});

// Process CSS ----------------------------------------------------------------
gulp.task('build:css', function () {
    var processors = [
        require('postcss-import')(),
        require('autoprefixer')({browsers: ['last 2 versions']})
    ];

    return gulp.src(path.source.css)
        .pipe(plugins.sass())
        .on('error', on_error)
        .pipe(plugins.postcss(processors))
        .pipe(plugins.replace('images/', '../images/mapplic/'))
        .pipe(plugins.cleanCss())
        .pipe(plugins.lineEndingCorrector())
        .pipe(plugins.rename({suffix: '.min'}))
        .pipe(gulp.dest(path.build.css));
});

// Process JS -----------------------------------------------------------------
gulp.task('build:js', function() {
    return gulp.src(path.source.js)
        .pipe(plugins.nunjucksRender(nunjucks.js))
        .on('error', on_error)
        .pipe(plugins.uglify())
        .pipe(plugins.lineEndingCorrector())
        .pipe(plugins.rename({suffix: '.min'}))
        .pipe(gulp.dest(path.build.js));
});

// Process page templates -----------------------------------------------------
gulp.task('build:html', function() {
    var token = 'source/templates/' + argv.language + '/[^_]*.njk';

    function add_pipe(src) {
        return gulp.src(src)
            .pipe(plugins.nunjucksRender(nunjucks.html))
            .on('error', on_error)
            .pipe(plugins.lineEndingCorrector())
            .pipe(gulp.dest(path.build.html));
    };

    var build_default = add_pipe(token);
    var build_other = add_pipe([path.source.html, '!' + token]);

    return merge(build_default, build_other);
});

// Put it all together --------------------------------------------------------
gulp.task('build', [
    'build:fonts',
    'build:images',
    'build:data',
    'build:css',
    'build:js',
    'build:html'
]);

gulp.task('default', ['build']);
<commit_msg>Map base URL is HTTPS now<commit_after>var gulp = require('gulp');
var plugins = require('gulp-load-plugins')();

var del = require('del');
var merge = require('merge-stream');

// ============================================================================
// ****************************** CONFIGURATION *******************************
// ============================================================================

var argv = require('yargs')
    .options({
        'community': {
            alias: 'ce',
            describe: 'trigger the Community Edition build',
            type: 'boolean'
        },
        'development': {
            alias: 'dev',
            describe: 'enable Mapplic developer mode (display coordinates of the cursor)',
            type: 'boolean'
        },
        'language': {
            alias: 'lang',
            // Two-letter codes of target languages on Crowdin:
            choices: ['en', 'fr', 'it', 'ru'],
            default: 'en',
            describe: 'set the default language',
            nargs: 1,
            type: 'string'
        }
    })
    .argv;

var path = {
    source: {
        css: 'source/scss/style.scss',
        data: 'source/data/**/*.json',
        fonts: 'source/vendor/font-awesome/fonts/fontawesome-webfont.*',
        html: 'source/templates/**/[^_]*.njk',
        js: 'source/js/*.js',
        images: 'source/images/**/*.*'
    },
    build: {
        css: 'build/storage/css/',
        data: 'build/storage/data/',
        fonts: 'build/storage/fonts/',
        html: 'build/',
        js: 'build/storage/js/',
        images: 'build/storage/images/'
    },
    clean: {
        all: 'build/'
    }
};

var nunjucks = {
    js: {
        path: 'source/vendor/',
        ext: '.js',
        // Exclude jQuery from the Regular build:
        data: {common: {jquery: argv.community ? false : true}}
    },
    html: {
        path: 'source/templates/',
        data: {
            // Configure the layout:
            community: argv.community,
            default_language: argv.language,
            developer_mode: argv.development ? true : false,
            translations_excluded: [],
            analytics_id: argv.community ? false : '31374838',
            base_url: 'https://nether-whisper.ru/rp/planescape/map-of-sigil/',
            robots: argv.community ? 'noindex, nofollow' : 'index, nofollow, noarchive',
            ogp: argv.community ? false : true,
            swiftype: argv.community ? false : true,
            common: {
                jquery: argv.community ? false : '/storage/js/jquery.min.js',
                favicons: argv.community ? false : {
                    dir: '/storage/images/favicons/',
                    size: ['96x96', '32x32', '16x16']
                }
            }
        }
    }
};

// ============================================================================
// ********************************* UTILITIES ********************************
// ============================================================================

// Exclude incomplete and unreleased translations -----------------------------
var exclude_list = argv.community ? ['fr', 'it', 'ru'] : ['it', 'ru'];

if (exclude_list.indexOf(argv.language) > -1) {
    plugins.util.log('This translation is incomplete and cannot be set as default.');
    process.exit(1);
} else {
    function exclude_translations(source) {
        return source.replace('**', '!(' + exclude_list.join('|') + ')');
    };

    path.source.images = exclude_translations(path.source.images);
    path.source.data = exclude_translations(path.source.data);
    path.source.html = exclude_translations(path.source.html);

    nunjucks.html.data.translations_excluded = exclude_list;
};

// Format error messages and force exit code 1 on error -----------------------
var on_error = function(error) {
    plugins.util.log(plugins.util.colors.red('[ERROR]:', error.name, error.message));
    process.exit(1);
};

// Announce the build type: Regular or Community Edition ----------------------
if (argv.community) {
    plugins.util.log('Building the map of Sigil',  '(Community Edition, default language: ' + argv.language + ')');
} else {
    plugins.util.log('Building the map of Sigil',  '(default language: ' + argv.language + ')');
};

// ============================================================================
// ********************************** TASKS ***********************************
// ============================================================================

// Clean the build ------------------------------------------------------------
gulp.task('clean:all', function() {
    return del.sync(path.clean.all);
});

// Back up dependencies to “source/vendor” ====================================

// Shared pipes to fetch the Mapplic package if it’s installed ----------------
var fetch_mapplic_images = gulp.src('node_modules/mapplic/html/mapplic/images/*.*')
    .pipe(plugins.changed('source/vendor/mapplic/images/'))
    .pipe(gulp.dest('source/vendor/mapplic/images/'));

var fetch_mapplic = gulp.src([
    'node_modules/mapplic/html/mapplic/mapplic?(-ie).css',
    'node_modules/mapplic/html/mapplic/mapplic.js',
])
    .pipe(plugins.changed('source/vendor/mapplic/'))
    .pipe(gulp.dest('source/vendor/mapplic/'));

// Fetch all packages ---------------------------------------------------------
gulp.task('fetch:vendor', function() {
    var jquery = gulp.src('node_modules/jquery/dist/jquery.js')
        .pipe(plugins.changed('source/vendor/jquery/'))
        .pipe(gulp.dest('source/vendor/jquery/'));

    var jquery_mousewheel = gulp.src('node_modules/jquery-mousewheel/jquery.mousewheel.js')
        .pipe(plugins.changed('source/vendor/jquery.mousewheel/'))
        .pipe(gulp.dest('source/vendor/jquery.mousewheel/'));

    var hammerjs = gulp.src('node_modules/hammerjs/hammer.js')
        .pipe(plugins.changed('source/vendor/hammer.js/'))
        .pipe(gulp.dest('source/vendor/hammer.js/'));

    var magnific_popup = gulp.src([
        'node_modules/magnific-popup/dist/jquery.magnific-popup.js',
        'node_modules/magnific-popup/dist/magnific-popup.css'
    ])
        .pipe(plugins.changed('source/vendor/magnific-popup/'))
        .pipe(gulp.dest('source/vendor/magnific-popup/'));

    var normalize = gulp.src('node_modules/normalize.css/normalize.css')
        .pipe(plugins.changed('source/vendor/normalize.css/'))
        .pipe(gulp.dest('source/vendor/normalize.css/'));

    var fa_fonts = gulp.src('node_modules/font-awesome/fonts/fontawesome-webfont.*')
        .pipe(plugins.changed('source/vendor/font-awesome/fonts/'))
        .pipe(gulp.dest('source/vendor/font-awesome/fonts/'));

    var fa_css = gulp.src('node_modules/font-awesome/css/font-awesome.css')
        .pipe(plugins.changed('source/vendor/font-awesome/'))
        .pipe(gulp.dest('source/vendor/font-awesome/'));

    return merge(
        jquery,
        jquery_mousewheel,
        hammerjs,
        magnific_popup,
        normalize,
        fa_fonts, fa_css,
        fetch_mapplic_images, fetch_mapplic
    );
});

// Fetch only the Mapplic package ---------------------------------------------
gulp.task('fetch:mapplic', function() {
    return merge(fetch_mapplic_images, fetch_mapplic);
});

// GO, DABUS, GO ==============================================================

// Copy fonts -----------------------------------------------------------------
gulp.task('build:fonts', function() {
    return gulp.src(path.source.fonts)
        .pipe(plugins.changed(path.build.fonts))
        .pipe(gulp.dest(path.build.fonts));
});

// Copy images ----------------------------------------------------------------
gulp.task('build:images', function() {
    function add_pipe(src, dest) {
        return gulp.src(src)
            .pipe(plugins.changed(dest))
            .pipe(gulp.dest(dest));
    };

    var copy_images = add_pipe(path.source.images, path.build.images);
    var copy_mapplic_images = add_pipe(['source/vendor/mapplic/images/**/*.*', '!source/vendor/mapplic/images/alpha{20,50}.png'], path.build.images + 'mapplic/');

    return merge(copy_images, copy_mapplic_images);
});

// Copy map data --------------------------------------------------------------
gulp.task('build:data', function() {
    var token = 'source/data/' + argv.language + '/*.json';

    var build_default = gulp.src(token)
        .pipe(plugins.changed(path.build.data))
        .pipe(plugins.lineEndingCorrector())
        .pipe(gulp.dest(path.build.data + argv.language + '/'));

    var build_other = gulp.src([path.source.data, '!' + token])
        .pipe(plugins.changed(path.build.data))
        .pipe(plugins.replace('storage/images/', '../storage/images/'))
        .pipe(plugins.lineEndingCorrector())
        .pipe(gulp.dest(path.build.data));

    return merge(build_default, build_other);
});

// Process CSS ----------------------------------------------------------------
gulp.task('build:css', function () {
    var processors = [
        require('postcss-import')(),
        require('autoprefixer')({browsers: ['last 2 versions']})
    ];

    return gulp.src(path.source.css)
        .pipe(plugins.sass())
        .on('error', on_error)
        .pipe(plugins.postcss(processors))
        .pipe(plugins.replace('images/', '../images/mapplic/'))
        .pipe(plugins.cleanCss())
        .pipe(plugins.lineEndingCorrector())
        .pipe(plugins.rename({suffix: '.min'}))
        .pipe(gulp.dest(path.build.css));
});

// Process JS -----------------------------------------------------------------
gulp.task('build:js', function() {
    return gulp.src(path.source.js)
        .pipe(plugins.nunjucksRender(nunjucks.js))
        .on('error', on_error)
        .pipe(plugins.uglify())
        .pipe(plugins.lineEndingCorrector())
        .pipe(plugins.rename({suffix: '.min'}))
        .pipe(gulp.dest(path.build.js));
});

// Process page templates -----------------------------------------------------
gulp.task('build:html', function() {
    var token = 'source/templates/' + argv.language + '/[^_]*.njk';

    function add_pipe(src) {
        return gulp.src(src)
            .pipe(plugins.nunjucksRender(nunjucks.html))
            .on('error', on_error)
            .pipe(plugins.lineEndingCorrector())
            .pipe(gulp.dest(path.build.html));
    };

    var build_default = add_pipe(token);
    var build_other = add_pipe([path.source.html, '!' + token]);

    return merge(build_default, build_other);
});

// Put it all together --------------------------------------------------------
gulp.task('build', [
    'build:fonts',
    'build:images',
    'build:data',
    'build:css',
    'build:js',
    'build:html'
]);

gulp.task('default', ['build']);
<|endoftext|>