text:
package org.sagebionetworks.repo.web.controller;

import static org.sagebionetworks.repo.model.oauth.OAuthScope.download;
import static org.sagebionetworks.repo.model.oauth.OAuthScope.modify;
import static org.sagebionetworks.repo.model.oauth.OAuthScope.view;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import org.sagebionetworks.reflection.model.PaginatedResults;
import org.sagebionetworks.repo.model.AuthorizationConstants;
import org.sagebionetworks.repo.model.DatastoreException;
import org.sagebionetworks.repo.model.ObjectType;
import org.sagebionetworks.repo.model.ServiceConstants;
import org.sagebionetworks.repo.model.dao.WikiPageKeyHelper;
import org.sagebionetworks.repo.model.file.FileHandleResults;
import org.sagebionetworks.repo.model.v2.wiki.V2WikiHeader;
import org.sagebionetworks.repo.model.v2.wiki.V2WikiHistorySnapshot;
import org.sagebionetworks.repo.model.v2.wiki.V2WikiOrderHint;
import org.sagebionetworks.repo.model.v2.wiki.V2WikiPage;
import org.sagebionetworks.repo.web.NotFoundException;
import org.sagebionetworks.repo.web.RequiredScope;
import org.sagebionetworks.repo.web.UrlHelpers;
import org.sagebionetworks.repo.web.rest.doc.ControllerInfo;
import org.sagebionetworks.repo.web.service.ServiceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
 *

 * The Synapse V2WikiPage model
 * object contains the data needed to render an end-user crafted web page. The
 * Synapse Web Client will dynamically render a WikiPage into a combination of
 * HTML, CSS and Javascript which is then finally rendered as a web page in the
 * client's web browser.
 *

 *

 * These services provide support for creating, reading, updating, and
 * deleting (CRUD) the WikiPage model objects.
 *

 *

 * WikiPages are composed of two major parts; a file that contains the markdown text
 * and a list of file attachments. For example, to embed an image from an end-user's
 * machine into a WikiPage, the image file must first be uploaded to Synapse as FileHandle (see
 * File
 * Services). The FileHandle ID can then be added to a
 * WikiPage.attachmentFileHandleIds list. See www.synapse.org for details on the
 * supported markdown syntax. The markdown text is similarly uploaded as a
 * FileHandle and its FileHandle ID is tracked by the WikiPage.
 *

 *
 *

 * WikiPages are not stand-alone objects, instead they are a component of
 * another object such as an Entity or Evaluation. For example, when a WikiPage
 * is created for an Entity, the Entity becomes the "owner" of the WikiPage.
 * Access to the WikiPage is always tied to its owner. For example, to GET a
 * WikiPage of an Entity, the caller must have read permission on the Entity.
 *

 *

 * To navigate the hierarchy of WikiPages associated with an owner use the GET
 * /entity/{ownerId}/wikiheadertree2 method. The returned list of V2WikiHeaders can
 * be used to construct a full wiki hierarchy tree for that owner.
 *

 *

 * To view a timeline of changes made to a WikiPage, use the
 * GET/entity/{ownerId}
 * /wiki2/{wikiId}/wikihistory method. The returned list of V2WikiHistorySnapshots
 *  contain information about who modified the WikiPage and when the changes were made.
 *

 *

 * Note: WikiPages can be nested to created a hierarchy of sub-pages. However,
 * there can only be one root WikiPage per owner object, and all sub-pages are
 * considered to be owned by the same object as the root page.
 *

 */
@ControllerInfo(displayName = "WikiPage Services 2", path = "repo/v1")
@Controller
@RequestMapping(UrlHelpers.REPO_PATH)
public class V2WikiController {
	@Autowired
	ServiceProvider serviceProvider;

	/**
	 * Create a WikiPage with an Entity as an owner.
	 *
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.CREATE permission on the owner.
	 *

	 *

	 * If the passed WikiPage is a root (parentWikiId = null) and the owner
	 * already has a root WikiPage, an error will be returned.
	 *

	 *
	 * @param userId
	 *            The user's id.
	 * @param ownerId
	 *            The ID of the owner Entity.
	 * @param toCreate
	 *            The WikiPage to create.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.CREATED)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_V2, method = RequestMethod.POST)
	public @ResponseBody
	V2WikiPage createEntityWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @RequestBody V2WikiPage toCreate)
			throws DatastoreException, NotFoundException {
		return serviceProvider.getV2WikiService().createWikiPage(userId, ownerId,
				ObjectType.ENTITY, toCreate);
	}

	/**
	 * Create a WikiPage with an AccessRequirement as an owner.
	 *
	 *

	 * Note: The caller must be a member of the Synapse Access and Compliance Team.
	 *

	 *

	 * If the passed WikiPage is a root (parentWikiId = null) and the owner
	 * already has a root WikiPage, an error will be returned.
	 *

	 *
	 * @param userId
	 *            The user's id.
	 * @param ownerId
	 *            The ID of the owner AccessRequirement.
	 * @param toCreate
	 *            The WikiPage to create.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.CREATED)
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_V2, method = RequestMethod.POST)
	public @ResponseBody
	V2WikiPage createAccessRequirementWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @RequestBody V2WikiPage toCreate)
			throws DatastoreException, NotFoundException {
		return serviceProvider.getV2WikiService().createWikiPage(userId, ownerId,
				ObjectType.ACCESS_REQUIREMENT, toCreate);
	}

	/**
	 * Create a WikiPage with an Evaluation as an owner.
	 *
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.CREATE permission on the owner.
	 *

	 *

	 * If the passed WikiPage is a root (parentWikiId = null) and the owner
	 * already has a root WikiPage, an error will be returned.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owner Evaluation.
	 * @param toCreate
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.CREATED)
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_V2, method = RequestMethod.POST)
	public @ResponseBody
	V2WikiPage createCompetitionWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @RequestBody V2WikiPage toCreate)
			throws DatastoreException, NotFoundException {
		return serviceProvider.getV2WikiService().createWikiPage(userId, ownerId,
				ObjectType.EVALUATION, toCreate);
	}

	/**
	 * Get the root WikiPage for an Entity.
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_V2, method = RequestMethod.GET)
	public @ResponseBody
	V2WikiPage getEntityRootWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getRootWikiPage(userId,
				ownerId, ObjectType.ENTITY);
	}

	/**
	 * Get the root WikiPage for an AccessRequirement.
	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning AccessRequirement.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_V2, method = RequestMethod.GET)
	public @ResponseBody
	V2WikiPage getAccessRequirementRootWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getRootWikiPage(userId,
				ownerId, ObjectType.ACCESS_REQUIREMENT);
	}

	/**
	 * Get the root WikiPage for an Evaluation.
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Evaluation.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_V2, method = RequestMethod.GET)
	public @ResponseBody
	V2WikiPage getCompetitionRootWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getRootWikiPage(userId,
				ownerId, ObjectType.EVALUATION);
	}

	/**
	 * Get a specific WikiPage of an Entity.
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @param wikiId
	 *            The ID of the WikiPage to get.
	 * @param wikiVersion When included returns a specific version of a wiki.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_ID_V2, method = RequestMethod.GET)
	public @ResponseBody
	V2WikiPage getEntityWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = false) Long wikiVersion)
			throws DatastoreException, NotFoundException {
		return serviceProvider.getV2WikiService().getWikiPage(userId,
				WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ENTITY, wikiId), wikiVersion);
	}

	/**
	 * Get a specific WikiPage of an Access Requirement.
	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Access Requirement.
	 * @param wikiId
	 *            The ID of the WikiPage to get.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_ID_V2, method = RequestMethod.GET)
	public @ResponseBody
	V2WikiPage getAccessRequirementWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = false) Long wikiVersion)
			throws DatastoreException, NotFoundException {
		return serviceProvider.getV2WikiService().getWikiPage(userId,
				WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ACCESS_REQUIREMENT, wikiId), wikiVersion);
	}

	/**
	 * Get a specific WikiPage of an Evaluation.
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Evaluation.
	 * @param wikiId
	 *            The ID of the WikiPage to get.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_ID_V2, method = RequestMethod.GET)
	public @ResponseBody
	V2WikiPage getCompetitionWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = false) Long wikiVersion)
			throws DatastoreException, NotFoundException {
		return serviceProvider.getV2WikiService().getWikiPage(userId,
				WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.EVALUATION, wikiId), wikiVersion);
	}

	// Update methods.
	/**
	 * Update a specific WikiPage of an Entity. This adds a new entry
	 * to the history of changes made to this specific WikiPage.
	 *

	 * Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
	 * concurrent updates. Each time a WikiPage is updated a new etag will be
	 * issued to the WikiPage. When an update is requested, Synapse will compare
	 * the etag of the passed WikiPage with the current etag of the WikiPage. If
	 * the etags do not match, then the update will be rejected with a
	 * PRECONDITION_FAILED (412) response. When this occurs the caller should
	 * get the latest copy of the WikiPage and re-apply any changes to the
	 * object, then re-attempt the update. This ensures the caller has all
	 * changes applied by other users before applying their own changes.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.UPDATE permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @param wikiId
	 *            The ID of the WikiPage to update.
	 * @param toUpdate
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_ID_V2, method = RequestMethod.PUT)
	public @ResponseBody
	V2WikiPage updateEntityWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestBody V2WikiPage toUpdate) throws DatastoreException,
			NotFoundException {
		validateUpateArguments(wikiId, toUpdate);
		return serviceProvider.getV2WikiService().updateWikiPage(userId, ownerId,
				ObjectType.ENTITY, toUpdate);
	}

	/**
	 * Update an order hint that corresponds to the given owner Entity.
	 *

	 * Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
	 * concurrent updates. Each time an WikiOrderHint is updated a new etag will be
	 * issued to the WikiOrderHint. When an update is requested, Synapse will compare
	 * the etag of the passed WikiOrderHint with the current etag of the WikiOrderHint. If
	 * the etags do not match, then the update will be rejected with a
	 * PRECONDITION_FAILED (412) response. When this occurs the caller should
	 * get the latest copy of the WikiOrderHint and re-apply any changes to the
	 * object, then re-attempt the update. This ensures the caller has all
	 * changes applied by other users before applying their own changes.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.UPDATE permission on the owner.
	 *

	 *
	 *
	 * @param userId
	 * @param ownerId
	 * @param wikiId
	 * @param toUpdate
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_V2_ORDER_HINT, method = RequestMethod.PUT)
	public @ResponseBody
	V2WikiOrderHint updateEntityWikiOrderHint(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @RequestBody V2WikiOrderHint toUpdate)
			throws DatastoreException, NotFoundException {
		if (toUpdate == null) throw new IllegalArgumentException("OrderHint cannot be null.");
		return serviceProvider.getV2WikiService().updateWikiOrderHint(userId, toUpdate);
	}

	/**
	 * Update a specific WikiPage of an Access Requirement. This adds a new entry
	 * to the history of changes made to this specific WikiPage.
	 *

	 * Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
	 * concurrent updates. Each time a WikiPage is updated a new etag will be
	 * issued to the WikiPage. When an update is requested, Synapse will compare
	 * the etag of the passed WikiPage with the current etag of the WikiPage. If
	 * the etags do not match, then the update will be rejected with a
	 * PRECONDITION_FAILED (412) response. When this occurs the caller should
	 * get the latest copy of the WikiPage and re-apply any changes to the
	 * object, then re-attempt the update. This ensures the caller has all
	 * changes applied by other users before applying their own changes.
	 *

	 *

	 * Note: The caller must be a member of the Synapse Access and Compliance Team.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Access Requirement.
	 * @param wikiId
	 *            The ID of the WikiPage to update.
	 * @param toUpdate
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_ID_V2, method = RequestMethod.PUT)
	public @ResponseBody
	V2WikiPage updateAcessRequirementWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestBody V2WikiPage toUpdate) throws DatastoreException,
			NotFoundException {
		validateUpateArguments(wikiId, toUpdate);
		return serviceProvider.getV2WikiService().updateWikiPage(userId, ownerId,
				ObjectType.ACCESS_REQUIREMENT, toUpdate);
	}

	/**
	 * Update a specific WikiPage of an Evaluation. This adds a new entry
	 * to the history of changes made to this specific WikiPage.
	 *

	 * Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
	 * concurrent updates. Each time a WikiPage is updated a new etag will be
	 * issued to the WikiPage. When an update is request, Synapse will compare
	 * the etag of the passed WikiPage with the current etag of the WikiPage. If
	 * the etags do not match, then the update will be rejected with a
	 * PRECONDITION_FAILED (412) response. When this occurs the caller should
	 * get the latest copy of the WikiPage and re-apply any changes to the
	 * object, then re-attempt the update. This ensures the caller has all
	 * changes applied by other users before applying their own changes.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.UPDATE permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Evaluation.
	 * @param wikiId
	 *            The ID of the WikiPage to update.
	 * @param toUpdate
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_ID_V2, method = RequestMethod.PUT)
	public @ResponseBody
	V2WikiPage updateCompetitionWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestBody V2WikiPage toUpdate) throws DatastoreException,
			NotFoundException {
		validateUpateArguments(wikiId, toUpdate);
		return serviceProvider.getV2WikiService().updateWikiPage(userId, ownerId,
				ObjectType.EVALUATION, toUpdate);
	}

	/**
	 * Helper to validate update arguments.
	 *
	 * @param wikiId
	 * @param wikiPage
	 */
	private static void validateUpateArguments(String wikiId, V2WikiPage wikiPage) {
		if (wikiPage == null)
			throw new IllegalArgumentException("WikiPage cannot be null");
		if (!wikiId.equals(wikiPage.getId())) {
			throw new IllegalArgumentException(
					"Path variable wikiId does not match the ID of the passed WikiPage");
		}
	}

	// Restore methods
	/**
	 * For a specific WikiPage of an Entity, restore a version of the WikiPage's content.
	 *

	 * Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
	 * concurrent updates. Each time a WikiPage is updated a new etag will be
	 * issued to the WikiPage. When an update is requested, Synapse will compare
	 * the etag of the passed WikiPage with the current etag of the WikiPage. If
	 * the etags do not match, then the update will be rejected with a
	 * PRECONDITION_FAILED (412) response. When this occurs the caller should
	 * get the latest copy of the WikiPage and re-apply any changes to the
	 * object, then re-attempt the update. This ensures the caller has all
	 * changes applied by other users before applying their own changes.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.UPDATE permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @param wikiId
	 *            The ID of the WikiPage to update.
	 * @param toUpdate
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_ID_AND_VERSION_V2, method = RequestMethod.PUT)
	public @ResponseBody
	V2WikiPage restoreEntityWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable Long wikiVersion,
			@PathVariable String ownerId, @PathVariable String wikiId)
			throws DatastoreException, NotFoundException {
		return serviceProvider.getV2WikiService().restoreWikipage(userId, ownerId, ObjectType.ENTITY, wikiId, wikiVersion);
	}

	/**
	 * For a specific WikiPage of an Access Requirement, restore a version of the WikiPage's content.
	 *

	 * Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
	 * concurrent updates. Each time a WikiPage is updated a new etag will be
	 * issued to the WikiPage. When an update is requested, Synapse will compare
	 * the etag of the passed WikiPage with the current etag of the WikiPage. If
	 * the etags do not match, then the update will be rejected with a
	 * PRECONDITION_FAILED (412) response. When this occurs the caller should
	 * get the latest copy of the WikiPage and re-apply any changes to the
	 * object, then re-attempt the update. This ensures the caller has all
	 * changes applied by other users before applying their own changes.
	 *

	 *

	 * Note: The caller must be a member of the Synapse Access and Compliance Team.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Access Requirement.
	 * @param wikiId
	 *            The ID of the WikiPage to update.
	 * @param toUpdate
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_ID_AND_VERSION_V2, method = RequestMethod.PUT)
	public @ResponseBody
	V2WikiPage restoreAccessRequirementWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable Long wikiVersion,
			@PathVariable String ownerId, @PathVariable String wikiId)
			throws DatastoreException, NotFoundException {
		return serviceProvider.getV2WikiService().restoreWikipage(userId, ownerId, ObjectType.ACCESS_REQUIREMENT, wikiId, wikiVersion);
	}

	/**
	 * For a specific WikiPage of an Evaluation, restore a version of the WikiPage's content.
	 *

	 * Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
	 * concurrent updates. Each time a WikiPage is updated a new etag will be
	 * issued to the WikiPage. When an update is requested, Synapse will compare
	 * the etag of the passed WikiPage with the current etag of the WikiPage. If
	 * the etags do not match, then the update will be rejected with a
	 * PRECONDITION_FAILED (412) response. When this occurs the caller should
	 * get the latest copy of the WikiPage and re-apply any changes to the
	 * object, then re-attempt the update. This ensures the caller has all
	 * changes applied by other users before applying their own changes.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.UPDATE permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @param wikiId
	 *            The ID of the WikiPage to update.
	 * @param toUpdate
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view,modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_ID_AND_VERSION_V2, method = RequestMethod.PUT)
	public @ResponseBody
	V2WikiPage restoreCompetitionWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable Long wikiVersion,
			@PathVariable String ownerId, @PathVariable String wikiId)
			throws DatastoreException, NotFoundException {
		return serviceProvider.getV2WikiService().restoreWikipage(userId, ownerId, ObjectType.EVALUATION, wikiId, wikiVersion);
	}

	// Delete methods
	/**
	 * Delete a specific WikiPage of an Entity.
	 *

	 * Note: When a WikiPage is deleted, the delete will cascade to all children
	 * WikiPages (recursively) of the deleted WikiPage.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.DELETE permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @param wikiId
	 *            The ID of the WikiPage to delete.
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_ID_V2, method = RequestMethod.DELETE)
	public void deleteEntityWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId)
			throws DatastoreException, NotFoundException {
		serviceProvider.getV2WikiService().deleteWikiPage(userId,
				WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ENTITY, wikiId));
	}

	/**
	 * Delete a specific WikiPage of an Access Requirement.
	 *

	 * Note: When a WikiPage is deleted, the delete will cascade to all children
	 * WikiPages (recursively) of the deleted WikiPage.
	 *

	 *

	 * Note: The caller must be a member of the Synapse Access and Compliance Team.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Access Requirement.
	 * @param wikiId
	 *            The ID of the WikiPage to delete.
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_ID_V2, method = RequestMethod.DELETE)
	public void deleteAccessRequirementWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId)
			throws DatastoreException, NotFoundException {
		serviceProvider.getV2WikiService().deleteWikiPage(userId,
				WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ACCESS_REQUIREMENT, wikiId));
	}

	/**
	 * Delete a specific WikiPage of an Evaluation.
	 *

	 * Note: When a WikiPage is deleted, the delete will cascade to all children
	 * WikiPages (recursively) of the deleted WikiPage.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.DELETE permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Evaluations.
	 * @param wikiId
	 *            The ID of the WikiPage to delete.
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({modify})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_ID_V2, method = RequestMethod.DELETE)
	public void deleteCompetitionWikiPage(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId)
			throws DatastoreException, NotFoundException {
		serviceProvider.getV2WikiService().deleteWikiPage(userId,
				WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.EVALUATION, wikiId));
	}

	// Get Wiki Hierarchy
	/**
	 * Get a paginated list of all V2WikiHeaders
	 * that belong to the given owner Entity. The resulting list can be used to
	 * build a tree of the WikiPages for this owner. The first WikiHeader will
	 * be for the root WikiPage (parentWikiId = null).
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param offset
	 *            The index of the pagination offset. For a page size of 10, the
	 *            first page would be at offset = 0, and the second page would
	 *            be at offset = 10.
	 * @param limit
	 *            Limits the size of the page returned. For example, a page size
	 *            of 10 require limit = 10. Limit must be 50 or less.
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_TREE_V2, method = RequestMethod.GET)
	public @ResponseBody
	PaginatedResults<V2WikiHeader> getEntityWikiHeaderTree(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@RequestParam(value = ServiceConstants.PAGINATION_OFFSET_PARAM, required = false) Long offset,
			@RequestParam(value = ServiceConstants.PAGINATION_LIMIT_PARAM, required = false) Long limit,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getWikiHeaderTree(userId,
				ownerId, ObjectType.ENTITY, limit, offset);
	}

	/**
	 *
	 * Get an order hint
	 * that corresponds to the given owner Entity. The resulting hint can be used to
	 * establish a relative ordering for the subwikis in
	 * a tree of the WikiPages for this owner.
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_V2_ORDER_HINT, method = RequestMethod.GET)
	public @ResponseBody
	V2WikiOrderHint getEntityWikiOrderHint(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getWikiOrderHint(userId, ownerId, ObjectType.ENTITY);
	}

	/**
	 * Get a paginated list of all V2WikiHeaders
	 * that belong to the given owner Access Requirement. The resulting list can be used to
	 * build a tree of the WikiPages for this owner. The first WikiHeader will
	 * be for the root WikiPage (parentWikiId = null).
	 *
	 * @param userId
	 * @param offset
	 *            The index of the pagination offset. For a page size of 10, the
	 *            first page would be at offset = 0, and the second page would
	 *            be at offset = 10.
	 * @param limit
	 *            Limits the size of the page returned. For example, a page size
	 *            of 10 require limit = 10.
	 * @param ownerId
	 *            The ID of the owning Access Requirement.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_TREE_V2, method = RequestMethod.GET)
	public @ResponseBody
	PaginatedResults<V2WikiHeader> getAccessRequirementWikiHeaderTree(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@RequestParam(value = ServiceConstants.PAGINATION_OFFSET_PARAM, required = false) Long offset,
			@RequestParam(value = ServiceConstants.PAGINATION_LIMIT_PARAM, required = false) Long limit,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getWikiHeaderTree(userId,
				ownerId, ObjectType.ACCESS_REQUIREMENT, limit, offset);
	}

	/**
	 * Get a paginated list of all V2WikiHeaders
	 * that belong to the given owner Evaluation. The resulting list can be used
	 * to build a tree of the WikiPages for this owner. The first WikiHeader
	 * will be for the root WikiPage (parentWikiId = null).
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param offset
	 *            The index of the pagination offset. For a page size of 10, the
	 *            first page would be at offset = 0, and the second page would
	 *            be at offset = 10.
	 * @param limit
	 *            Limits the size of the page returned. For example, a page size
	 *            of 10 require limit = 10.
	 * @param ownerId
	 *            The ID of the owning Evaluation.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_TREE_V2, method = RequestMethod.GET)
	public @ResponseBody
	PaginatedResults<V2WikiHeader> getCompetitionWikiHeaderTree(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@RequestParam(value = ServiceConstants.PAGINATION_OFFSET_PARAM, required = false) Long offset,
			@RequestParam(value = ServiceConstants.PAGINATION_LIMIT_PARAM, required = false) Long limit,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getWikiHeaderTree(userId,
				ownerId, ObjectType.EVALUATION, limit, offset);
	}

	// Wiki History
	/**
	 * Get a paginated list of all V2WikiHistorySnapshot
	 * that belong to a specific WikiPage, which belong to the given owner Entity. The resulting list
	 * can be used to display a timeline of changes to the specific WikiPage for this owner.
	 * The first V2WikiHistorySnapshot describes the most recent change or update to the WikiPage.
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param offset
	 *            The index of the pagination offset. For a page size of 10, the
	 *            first page would be at offset = 0, and the second page would
	 *            be at offset = 10.
	 * @param limit
	 *            Limits the size of the page returned. For example, a page size
	 *            of 10 require limit = 10. Limit must be 50 or less.
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @param wikiId
	 * 			  The ID of the WikiPage.
	 *
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_HISTORY_V2, method = RequestMethod.GET)
	public @ResponseBody
	PaginatedResults<V2WikiHistorySnapshot> getEntityWikiHistory(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@RequestParam(ServiceConstants.PAGINATION_OFFSET_PARAM) Long offset,
			@RequestParam(ServiceConstants.PAGINATION_LIMIT_PARAM) Long limit,
			@PathVariable String wikiId,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getWikiHistory(userId, ownerId, ObjectType.ENTITY,
				limit, offset, WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ENTITY, wikiId));

	}

	/**
	 * Get a paginated list of all V2WikiHistorySnapshot
	 * that belong to a specific WikiPage, which belong to the given owner Access Requirement. The resulting list
	 * can be used to display a timeline of changes to the specific WikiPage for this owner.
	 * The first V2WikiHistorySnapshot describes the most recent change or update to the WikiPage.
	 *
	 * @param userId
	 * @param offset
	 *            The index of the pagination offset. For a page size of 10, the
	 *            first page would be at offset = 0, and the second page would
	 *            be at offset = 10.
	 * @param limit
	 *            Limits the size of the page returned. For example, a page size
	 *            of 10 require limit = 10.
	 * @param ownerId
	 *            The ID of the owning Access Requirement.
	 * @param wikiId
	 * 			  The ID of the WikiPage.
	 *
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_HISTORY_V2, method = RequestMethod.GET)
	public @ResponseBody
	PaginatedResults<V2WikiHistorySnapshot> getAccessRequirementWikiHistory(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@RequestParam(ServiceConstants.PAGINATION_OFFSET_PARAM) Long offset,
			@RequestParam(ServiceConstants.PAGINATION_LIMIT_PARAM) Long limit,
			@PathVariable String wikiId,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getWikiHistory(userId, ownerId, ObjectType.ACCESS_REQUIREMENT,
				limit, offset, WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ACCESS_REQUIREMENT, wikiId));

	}

	/**
	 * Get a paginated list of all V2WikiHistorySnapshot
	 * that belong to a specific WikiPage, which belong to the given owner Evaluation. The resulting list
	 * can be used to display a timeline of changes to the specific WikiPage for this owner.
	 * The first V2WikiHistorySnapshot describes the most recent change or update to the WikiPage.
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param offset
	 *            The index of the pagination offset. For a page size of 10, the
	 *            first page would be at offset = 0, and the second page would
	 *            be at offset = 10.
	 * @param limit
	 *            Limits the size of the page returned. For example, a page size
	 *            of 10 require limit = 10.
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @param wikiId
	 * 			  The ID of the WikiPage.
	 *
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_HISTORY_V2, method = RequestMethod.GET)
	public @ResponseBody
	PaginatedResults<V2WikiHistorySnapshot> getCompetitionWikiHistory(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@RequestParam(ServiceConstants.PAGINATION_OFFSET_PARAM) Long offset,
			@RequestParam(ServiceConstants.PAGINATION_LIMIT_PARAM) Long limit,
			@PathVariable String wikiId,
			@PathVariable String ownerId) throws DatastoreException,
			NotFoundException {
		return serviceProvider.getV2WikiService().getWikiHistory(userId, ownerId, ObjectType.EVALUATION,
				limit, offset, WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.EVALUATION, wikiId));

	}

	// Handles
	/**
	 * Get the list of FileHandles for all file attachments of a specific
	 * WikiPage for a given owning Entity. This list will include Previews if
	 * they exist and will provide information about file sizes, content types
	 * and names.
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity.
	 * @param wikiId
	 *            The ID of the WikiPage.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_ID_ATTCHMENT_HANDLE_V2, method = RequestMethod.GET)
	public @ResponseBody
	FileHandleResults getEntityWikiAttachmenthHandles(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = false) Long wikiVersion)
			throws DatastoreException, NotFoundException {
		// Get the redirect url
		return serviceProvider.getV2WikiService().getAttachmentFileHandles(
				userId, WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ENTITY, wikiId), wikiVersion);
	}

	/**
	 * Get the list of FileHandles for all file attachments of a specific
	 * WikiPage for a given owning Access Requirement. This list will include Previews if
	 * they exist and will provide information about file sizes, content types
	 * and names.
	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Access Requirement.
	 * @param wikiId
	 *            The ID of the WikiPage.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_ID_ATTCHMENT_HANDLE_V2, method = RequestMethod.GET)
	public @ResponseBody
	FileHandleResults getAccessRequirementWikiAttachmenthHandles(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = false) Long wikiVersion)
			throws DatastoreException, NotFoundException {
		// Get the redirect url
		return serviceProvider.getV2WikiService().getAttachmentFileHandles(
				userId, WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ACCESS_REQUIREMENT, wikiId), wikiVersion);
	}

	/**
	 * Get the list of FileHandles for all file attachments of a specific
	 * WikiPage for a given owning Evaluation. This list will include Previews
	 * if they exist and will provide information about file sizes, content
	 * types and names.
	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Evaluation.
	 * @param wikiId
	 *            The ID of the WikiPage.
	 * @return
	 * @throws DatastoreException
	 * @throws NotFoundException
	 */
	@RequiredScope({view})
	@ResponseStatus(HttpStatus.OK)
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_ID_ATTCHMENT_HANDLE_V2, method = RequestMethod.GET)
	public @ResponseBody
	FileHandleResults getCompetitionWikiAttachmenthHandles(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = false) Long wikiVersion)
			throws DatastoreException, NotFoundException {
		// Get the redirect url
		return serviceProvider
				.getV2WikiService()
				.getAttachmentFileHandles(userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.EVALUATION, wikiId), wikiVersion);
	}

	// Files
	/**
	 * Get a URL that can be used to download a file for a given WikiPage file
	 * attachment.
	 *

	 * Note: This call will result in a HTTP temporary redirect (307), to the
	 * actual file URL if the caller meets all of the download requirements.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity
	 * @param wikiId
	 *            The ID of the WikiPage
	 * @param fileName
	 *            The name of the file to get. The file names can be found in
	 *            the FileHandles from the GET
	 *            /entity/{ownerId}/wiki/{wikiId}/attachmenthandles method.
	 * @param redirect
	 *            When set to false, the URL will be returned as text/plain
	 *            instead of redirecting.
	 * @param response
	 * @throws DatastoreException
	 * @throws NotFoundException
	 * @throws IOException
	 */
	@RequiredScope({download})
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_ID_ATTCHMENT_FILE_V2, method = RequestMethod.GET)
	public void getEntityWikiAttachmentFile(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = true)  String fileName,
			@RequestParam(required = false) Boolean redirect,
			HttpServletResponse response,
			@RequestParam(required = false) Long wikiVersion) throws DatastoreException,
			NotFoundException, IOException {
		// Get the redirect url
		String redirectUrl = serviceProvider.getV2WikiService()
				.getAttachmentRedirectURL(userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ENTITY, wikiId),
						fileName, wikiVersion);
		RedirectUtils.handleRedirect(redirect, redirectUrl, response);
	}

	/**
	 * Get a URL that can be used to download a file for a given WikiPage file
	 * attachment.
	 *

	 * Note: This call will result in a HTTP temporary redirect (307), to the
	 * actual file URL if the caller meets all of the download requirements.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Access Requirement
	 * @param wikiId
	 *            The ID of the WikiPage
	 * @param fileName
	 *            The name of the file to get. The file names can be found in
	 *            the FileHandles from the GET
	 *            /accessRequirement/{ownerId}/wiki/{wikiId}/attachmenthandles method.
	 * @param redirect
	 *            When set to false, the URL will be returned as text/plain
	 *            instead of redirecting.
	 * @param response
	 * @throws DatastoreException
	 * @throws NotFoundException
	 * @throws IOException
	 */
	@RequiredScope({download})
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_ID_ATTCHMENT_FILE_V2, method = RequestMethod.GET)
	public void getAccessRequirementWikiAttachmentFile(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = true)  String fileName,
			@RequestParam(required = false) Boolean redirect,
			HttpServletResponse response,
			@RequestParam(required = false) Long wikiVersion) throws DatastoreException,
			NotFoundException, IOException {
		// Get the redirect url
		String redirectUrl = serviceProvider.getV2WikiService()
				.getAttachmentRedirectURL(userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ACCESS_REQUIREMENT, wikiId),
						fileName, wikiVersion);
		RedirectUtils.handleRedirect(redirect, redirectUrl, response);
	}

	/**
	 * Get a URL that can be used to download a file for a given WikiPage file
	 * attachment.
	 *

	 * Note: This call will result in a HTTP temporary redirect (307), to the
	 * actual file URL if the caller meets all of the download requirements.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Evaluation
	 * @param wikiId
	 *            The ID of the WikiPage
	 * @param fileName
	 *            The name of the file to get. The file names can be found in
	 *            the FileHandles from the GET /evaluation/{ownerId}/wiki/{wikiId}/attachmenthandles
	 *            method.
	 * @param redirect
	 *            When set to false, the URL will be returned as text/plain
	 *            instead of redirecting.
	 * @param response
	 * @throws DatastoreException
	 * @throws NotFoundException
	 * @throws IOException
	 */
	@RequiredScope({download})
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_ID_ATTCHMENT_FILE_V2, method = RequestMethod.GET)
	public void getCompetitionAttachmentFile(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = true) String fileName,
			@RequestParam(required = false) Boolean redirect,
			HttpServletResponse response,
			@RequestParam(required = false) Long wikiVersion) throws DatastoreException,
			NotFoundException, IOException {
		// Get the redirect url
		String redirectUrl = serviceProvider
				.getV2WikiService()
				.getAttachmentRedirectURL(
						userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.EVALUATION, wikiId),
						fileName, wikiVersion);
		RedirectUtils.handleRedirect(redirect, redirectUrl, response);
	}

	/**
	 * Get a URL that can be used to download a preview file for a given
	 * WikiPage file attachment.
	 *

	 * Note: This call will result in a HTTP temporary redirect (307), to the
	 * actual file URL if the caller meets all of the download requirements.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Entity
	 * @param wikiId
	 *            The ID of the WikiPage
	 * @param fileName
	 *            The name of the file to get. The file names can be found in
	 *            the FileHandles from the GET
	 *            /entity/{ownerId}/wiki/{wikiId}/attachmenthandles method.
	 * @param redirect
	 *            When set to false, the URL will be returned as text/plain
	 *            instead of redirecting.
	 * @param response
	 * @throws DatastoreException
	 * @throws NotFoundException
	 * @throws IOException
	 */
	@RequiredScope({download})
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_ID_ATTCHMENT_FILE_PREVIEW_V2, method = RequestMethod.GET)
	public void getEntityWikiAttachmenPreviewFile(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = true) String fileName,
			@RequestParam(required = false) Boolean redirect,
			HttpServletResponse response,
			@RequestParam(required = false) Long wikiVersion) throws DatastoreException,
			NotFoundException, IOException {
		// Get the redirect url
		String redirectUrl = serviceProvider.getV2WikiService()
				.getAttachmentPreviewRedirectURL(userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ENTITY, wikiId),
						fileName, wikiVersion);
		RedirectUtils.handleRedirect(redirect, redirectUrl, response);
	}

	/**
	 * Get a URL that can be used to download a preview file for a given
	 * WikiPage file attachment.
	 *

	 * Note: This call will result in a HTTP temporary redirect (307), to the
	 * actual file URL if the caller meets all of the download requirements.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Access Requirement
	 * @param wikiId
	 *            The ID of the WikiPage
	 * @param fileName
	 *            The name of the file to get. The file names can be found in
	 *            the FileHandles from the GET
	 *            /accessRequirement/{ownerId}/wiki/{wikiId}/attachmenthandles method.
	 * @param redirect
	 *            When set to false, the URL will be returned as text/plain
	 *            instead of redirecting.
	 * @param response
	 * @throws DatastoreException
	 * @throws NotFoundException
	 * @throws IOException
	 */
	@RequiredScope({download})
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_ID_ATTCHMENT_FILE_PREVIEW_V2, method = RequestMethod.GET)
	public @ResponseBody
	void getAccessRequirementWikiAttachmenPreviewFile(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = true) String fileName,
			@RequestParam(required = false) Boolean redirect,
			HttpServletResponse response,
			@RequestParam(required = false) Long wikiVersion) throws DatastoreException,
			NotFoundException, IOException {
		// Get the redirect url
		String redirectUrl = serviceProvider.getV2WikiService()
				.getAttachmentPreviewRedirectURL(userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ACCESS_REQUIREMENT, wikiId),
						fileName, wikiVersion);
		RedirectUtils.handleRedirect(redirect, redirectUrl, response);
	}

	/**
	 * Get a URL that can be used to download a preview file for a given
	 * WikiPage file attachment.
	 *

	 * Note: This call will result in a HTTP temporary redirect (307), to the
	 * actual file URL if the caller meets all of the download requirements.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 *            The ID of the owning Evaluation
	 * @param wikiId
	 *            The ID of the WikiPage
	 * @param fileName
	 *            The name of the file to get. The file names can be found in
	 *            the FileHandles from the GET /evaluation/{ownerId}/wiki/{wikiId}/attachmenthandles
	 *            method.
	 * @param redirect
	 *            When set to false, the URL will be returned as text/plain
	 *            instead of redirecting.
	 * @param response
	 * @throws DatastoreException
	 * @throws NotFoundException
	 * @throws IOException
	 */
	@RequiredScope({download})
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_ID_ATTCHMENT_FILE_PREVIEW_V2, method = RequestMethod.GET)
	public void getCompetitionAttachmenthPreviewFile(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = true) String fileName,
			@RequestParam(required = false) Boolean redirect,
			HttpServletResponse response,
			@RequestParam(required = false) Long wikiVersion) throws DatastoreException,
			NotFoundException, IOException {
		// Get the redirect url
		String redirectUrl = serviceProvider
				.getV2WikiService()
				.getAttachmentPreviewRedirectURL(
						userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.EVALUATION, wikiId),
						fileName, wikiVersion);
		RedirectUtils.handleRedirect(redirect, redirectUrl, response);
	}

	/**
	 * Get a URL that can be used to download the markdown file for a given
	 * WikiPage.
	 *
	 *

	 * Note: This call will result in a HTTP temporary redirect (307), to the
	 * actual file URL if the caller meets all of the download requirements.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 * @param wikiId
	 * @param redirect
	 * @param response
	 * @throws DatastoreException
	 * @throws NotFoundException
	 * @throws IOException
	 */
	@RequiredScope({download})
	@RequestMapping(value = UrlHelpers.ENTITY_WIKI_ID_MARKDOWN_FILE_V2, method = RequestMethod.GET)
	public void getEntityWikiMarkdownFile(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = false) Boolean redirect,
			@RequestParam(required = false) Long wikiVersion,
			HttpServletResponse response) throws DatastoreException,
			NotFoundException, IOException {
		// Get the redirect url
		String redirectUrl = serviceProvider.getV2WikiService()
				.getMarkdownRedirectURL(userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ENTITY, wikiId), wikiVersion);
		RedirectUtils.handleRedirect(redirect, redirectUrl, response);
	}

	/**
	 * Get a URL that can be used to download the markdown file for a given
	 * WikiPage.
	 *
	 *

	 * Note: This call will result in a HTTP temporary redirect (307), to the
	 * actual file URL if the caller meets all of the download requirements.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 * @param wikiId
	 * @param redirect
	 * @param response
	 * @throws DatastoreException
	 * @throws NotFoundException
	 * @throws IOException
	 */
	@RequiredScope({download})
	@RequestMapping(value = UrlHelpers.ACCESS_REQUIREMENT_WIKI_ID_MARKDOWN_FILE_V2, method = RequestMethod.GET)
	public void getAccessRequirementWikiMarkdownFile(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = false) Boolean redirect,
			@RequestParam(required = false) Long wikiVersion,
			HttpServletResponse response) throws DatastoreException,
			NotFoundException, IOException {
		// Get the redirect url
		String redirectUrl = serviceProvider.getV2WikiService()
				.getMarkdownRedirectURL(userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.ACCESS_REQUIREMENT, wikiId), wikiVersion);
		RedirectUtils.handleRedirect(redirect, redirectUrl, response);
	}

	/**
	 * Get a URL that can be used to download the markdown file for a given
	 * WikiPage.
	 *
	 *

	 * Note: This call will result in a HTTP temporary redirect (307), to the
	 * actual file URL if the caller meets all of the download requirements.
	 *

	 *

	 * Note: The caller must be granted the ACCESS_TYPE.READ permission on the owner.
	 *

	 *
	 * @param userId
	 * @param ownerId
	 * @param wikiId
	 * @param redirect
	 * @param response
	 * @throws DatastoreException
	 * @throws NotFoundException
	 * @throws IOException
	 */
	@RequiredScope({download})
	@RequestMapping(value = UrlHelpers.EVALUATION_WIKI_ID_MARKDOWN_FILE_V2, method = RequestMethod.GET)
	public void getEvaluationWikiMarkdownFile(
			@RequestParam(value = AuthorizationConstants.USER_ID_PARAM) Long userId,
			@PathVariable String ownerId, @PathVariable String wikiId,
			@RequestParam(required = false) Boolean redirect,
			@RequestParam(required = false) Long wikiVersion,
			HttpServletResponse response) throws DatastoreException,
			NotFoundException, IOException {
		// Get the redirect url
		String redirectUrl = serviceProvider.getV2WikiService()
				.getMarkdownRedirectURL(userId,
						WikiPageKeyHelper.createWikiPageKey(ownerId, ObjectType.EVALUATION, wikiId), wikiVersion);
		RedirectUtils.handleRedirect(redirect, redirectUrl, response);
	}

}


text:
from __future__ import print_function

import getpass
import os
import sys

from six.moves import input
from six.moves.configparser import ConfigParser

from flag_bearer import utils

def plant(conf):
    resp = utils.get_user(conf)

    team = None
    red = resp['profile']['is_red']
    admin = resp['is_superuser']
    if red or admin:
        print("Which team do you want to get flags for?")
        try:
            team = int(input("> "))
        except ValueError:
            print("Retreiving flags for all teams")

    resp = utils.get_flags(conf, team)
    flags = {i: x for i, x in enumerate(resp)}

    print("Pick the flag to place")
    for flag_id, flag in flags.items():
        # Admins can see both blue and red flags, tell them which is which
        if admin:
            print("{}. {} ({})".format(flag_id, flag['name'], flag['type']))
        else:
            print("{}. {}".format(flag_id, flag['name']))

    flag = int(input("> "))

    if flag not in flags:
        print("[!!] Invalid selection")
        sys.exit(1)

    flag = flags[flag]

    save = conf.has_option('iscore', 'force_save') if red or admin else True
    if save or (not red and not admin):
        print("Where should I put the flag?")
        location = input("(./) > ")

        if not location:
            location = "./"

        print("Placing {} flag in {}".format(flag['name'], location))
        with open(os.path.join(location, flag['filename']), 'w') as fp:
            fp.write(flag['data'])
            fp.write("\n")
    else:
        print("Flag: {}".format(flag['data']))

def download(conf):
    resp = utils.get_user(conf)

    team = None
    red = resp['profile']['is_red']
    admin = resp['is_superuser']
    if red or admin:
        print("Which team to you want to download flags for (blank for all)?")
        try:
            team = int(input("> "))
        except ValueError:
            print("Retreiving flags for all teams")

    resp = utils.get_flags(conf, team)
    flags = {i: x for i, x in enumerate(resp)}
    utils.save_flags(flags)
    print("Flags saved")

def login(conf):
    if conf.cli_args.token:
        token = conf.cli_args.token
    else:
        token = getpass.getpass('Token: ')
    flagrc_path = os.path.join(os.path.expanduser(conf.cli_args.config))

    print("Writing token to {}".format(flagrc_path))
    flagrc = ConfigParser()
    flagrc.read(flagrc_path)

    if not flagrc.has_section('iscore'):
        flagrc.add_section('iscore')

    flagrc.set('iscore', 'api_token', token)
    with open(flagrc_path, 'w') as fp:
        flagrc.write(fp)

redpajama_set_name: RedPajamaGithub


text:
static const char *lines[] = {
    "-cmd1 foo", "bar",       "'abcd'",    "\"efg\"", "hi'x'",
    "'\\jkl'",   "\"\\xyz\"", "\"\\\"0\"", "cont\\",  "inue x",
};

// Tokens that the tokenizer is expected to return from the
// indirect file above:
static const char *expected_tokens[] = {
    "-cmd1", "foo",   "bar", "abcd",     "efg", "hix",
    "\\jkl", "\\xyz", "\"0", "continue", "x",
};

// Simple '-foo -bar' command line.
TEST(TokenStreamTest, SimpleArgs) {
  const char *args[] = {"-foo", "-bar"};
  ArgTokenStream token_stream(ARRAY_SIZE(args), args);
  EXPECT_EQ("-foo", token_stream.token());
  bool flag_foo = false;
  EXPECT_FALSE(token_stream.MatchAndSet("-bar", &flag_foo));
  ASSERT_TRUE(token_stream.MatchAndSet("-foo", &flag_foo));
  EXPECT_TRUE(flag_foo);
  bool flag_bar = false;
  ASSERT_TRUE(token_stream.MatchAndSet("-bar", &flag_bar));
  EXPECT_TRUE(flag_bar);
  EXPECT_TRUE(token_stream.AtEnd());
}

// '-foo @commandfile -bar' command line.
TEST(TokenStreamTest, CommandFile) {
  const char *tempdir = getenv("TEST_TMPDIR");
  ASSERT_NE(nullptr, tempdir);
  std::string command_file_path = singlejar_test_util::OutputFilePath("tokens");
  FILE *fp = fopen(command_file_path.c_str(), "w");
  ASSERT_NE(nullptr, fp);
  for (size_t i = 0; i < ARRAY_SIZE(lines); ++i) {
    fprintf(fp, "%s\n", lines[i]);
  }
  fclose(fp);

  std::string command_file_arg = std::string("@") + command_file_path;
  const char *args[] = {"-before_file", "", "-after_file"};
  args[1] = command_file_arg.c_str();
  ArgTokenStream token_stream(ARRAY_SIZE(args), args);
  bool flag = false;
  ASSERT_TRUE(token_stream.MatchAndSet("-before_file", &flag));
  EXPECT_TRUE(flag);
  for (size_t i = 0; i < ARRAY_SIZE(expected_tokens); ++i) {
    flag = false;
    ASSERT_TRUE(token_stream.MatchAndSet(expected_tokens[i], &flag));
    EXPECT_TRUE(flag);
  }
  ASSERT_TRUE(token_stream.MatchAndSet("-after_file", &flag));
  EXPECT_TRUE(flag);
  EXPECT_TRUE(token_stream.AtEnd());
}

#ifdef _WIN32
// '-foo @commandfile -bar' command line.
TEST(TokenStreamTest, CommandFileLongPath) {
  const char *tempdir = getenv("TEST_TMPDIR");
  ASSERT_NE(nullptr, tempdir);

  std::wstring wpath;
  std::string error;
  std::string command_file_path =
      singlejar_test_util::OutputFilePath(std::string(251, 'a'));
  command_file_path += ".aaa\\";
  ASSERT_TRUE(
      blaze_util::AsAbsoluteWindowsPath(command_file_path, &wpath, &error))
      << error;
  ASSERT_EQ(0, _wmkdir(wpath.c_str()));

  command_file_path += std::string(251, 'b');
  command_file_path += ".bbb\\";
  ASSERT_TRUE(
      blaze_util::AsAbsoluteWindowsPath(command_file_path, &wpath, &error))
      << error;
  ASSERT_EQ(0, _wmkdir(wpath.c_str()));

  command_file_path += std::string(251, 'c');
  command_file_path += ".ccc";

  ASSERT_TRUE(
      blaze_util::AsAbsoluteWindowsPath(command_file_path, &wpath, &error))
      << error;

  FILE *fp = _wfopen(wpath.c_str(), L"w");
  ASSERT_NE(nullptr, fp);
  for (size_t i = 0; i < ARRAY_SIZE(lines); ++i) {
    fprintf(fp, "%s\n", lines[i]);
  }
  fclose(fp);

  std::string command_file_arg = std::string("@") + command_file_path;
  const char *args[] = {"-before_file", "", "-after_file"};
  args[1] = command_file_arg.c_str();
  ArgTokenStream token_stream(ARRAY_SIZE(args), args);
  bool flag = false;
  ASSERT_TRUE(token_stream.MatchAndSet("-before_file", &flag));
  EXPECT_TRUE(flag);
  for (size_t i = 0; i < ARRAY_SIZE(expected_tokens); ++i) {
    flag = false;
    ASSERT_TRUE(token_stream.MatchAndSet(expected_tokens[i], &flag));
    EXPECT_TRUE(flag);
  }
  ASSERT_TRUE(token_stream.MatchAndSet("-after_file", &flag));
  EXPECT_TRUE(flag);
  EXPECT_TRUE(token_stream.AtEnd());
}
#endif

// '--arg1 optval1 --arg2' command line.
TEST(TokenStreamTest, OptargOne) {
  const char *args[] = {"--arg1", "optval1", "--arg2", "--arg3", "optval3"};
  ArgTokenStream token_stream(ARRAY_SIZE(args), args);
  std::string optval;
  EXPECT_FALSE(token_stream.MatchAndSet("--foo", &optval));
  ASSERT_TRUE(token_stream.MatchAndSet("--arg1", &optval));
  EXPECT_EQ("optval1", optval);
  bool flag = true;
  ASSERT_TRUE(token_stream.MatchAndSet("--arg2", &flag));
  EXPECT_TRUE(flag);
  ASSERT_TRUE(token_stream.MatchAndSet("--arg3", &optval));
  EXPECT_EQ("optval3", optval);
  EXPECT_TRUE(token_stream.AtEnd());
}

// '--arg1 value1 value2 --arg2' command line.
TEST(TokenStreamTest, OptargMulti) {
  const char *args[] = {"--arg1", "value11", "value12",
                        "--arg2", "value21", "value22"};
  ArgTokenStream token_stream(ARRAY_SIZE(args), args);
  std::vector<std::string> optvals1;
  EXPECT_FALSE(token_stream.MatchAndSet("--arg2", &optvals1));
  ASSERT_TRUE(token_stream.MatchAndSet("--arg1", &optvals1));
  ASSERT_EQ(2UL, optvals1.size());
  EXPECT_EQ("value11", optvals1[0]);
  EXPECT_EQ("value12", optvals1[1]);

  std::vector<std::string> optvals2;
  ASSERT_TRUE(token_stream.MatchAndSet("--arg2", &optvals2));
  ASSERT_EQ(2UL, optvals2.size());
  EXPECT_EQ("value21", optvals2[0]);
  EXPECT_EQ("value22", optvals2[1]);

  EXPECT_TRUE(token_stream.AtEnd());
}

// '--arg1 optval1,optsuff1 optval2,optstuff2 --arg2' command line.
TEST(TokenStreamTest, OptargMultiSplit) {
  const char *args[] = {"--arg1", "optval1,optsuff1", "optval2,optsuff2",
                        "optvalnosuff"};
  ArgTokenStream token_stream(ARRAY_SIZE(args), args);
  std::vector<std::pair<std::string, std::string> > optvals1;

  EXPECT_FALSE(token_stream.MatchAndSet("--foo", &optvals1));
  ASSERT_TRUE(token_stream.MatchAndSet("--arg1", &optvals1));

  ASSERT_EQ(3UL, optvals1.size());
  EXPECT_EQ("optval1", optvals1[0].first);
  EXPECT_EQ("optsuff1", optvals1[0].second);
  EXPECT_EQ("optval2", optvals1[1].first);
  EXPECT_EQ("optsuff2", optvals1[1].second);
  EXPECT_EQ("optvalnosuff", optvals1[2].first);
  EXPECT_EQ("", optvals1[2].second);
}


text:
SYNONYM

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
British Stem- and Leaf-Fungi (Coelomycetes) (Cambridge) 2: 241 (1937)

#### Original name
Colletotrichum lineola Corda, 1832

### Remarks
null


text:
# DEPRECATED

Don't use this. The Maps v3 SDK [handles markers](https://developers.google.com/maps/articles/toomanymarkers). That with a few other [cool utilities](http://googlegeodevelopers.blogspot.com/2014/02/marker-clustering-and-heatmaps-new.html) make this library obsolete!

# Clusterkraf

A clustering library for the Google Maps Android API v2.

If you're using the [Polaris v2](https://github.com/cyrilmottier/Polaris2) library, check out our [pleiades](https://github.com/twotoasters/clusterkraf/tree/pleiades) branch.

## Features

- Clustering based on pixel proximity, not grid membership
- Animated cluster transitions
- Supports Android v2.2 (Froyo) and higher

## Setup

### Gradle

If you are using Gradle just add the following to your build.gradle file:

```groovy
dependencies {
    compile 'com.twotoasters.clusterkraf:library:1.0.+'
}
```

### Maven

If you are using maven add the following to your pom file:
```xml
<dependency>
    <groupId>com.twotoasters.clusterkraf</groupId>
    <artifactId>library</artifactId>
    <version>1.0.2</version>
</dependency>
```

### Eclipse
It's easy to add Clusterkraf to your app. Add the Clusterkraf library folder as an Android project to your Eclipse/ADT workspace, and reference it from your app as a library project. Also, we assume you have a data object that holds latitude and longitude coordinates of each point you want plotted on the map similar to this:

```java
public class YourMapPointModel {
    public LatLng latLng;
    public YourMapPointModel(LatLng latLng) {
        this.latLng = latLng;
    }
    // encapsulation omitted for brevity
}
```

Clusterkraf provides an `InputPoint` class which holds a `LatLng` position and an `Object` tag. You just need to construct an `ArrayList<InputPoint>` object based on your model objects similar to this example. In this example, we provide the model as the `Object` tag for the `InputPoint` so that we can later pass them back to you in callbacks as the `ClusterPoint` object's pointsInCluster list; see `MarkerOptionsChooser`, `OnInfoWindowClickDownstreamListener`, and `OnMarkerClickDownstreamListener`.

```java
public class YourActivity extends FragmentActivity {
    YourMapPointModel[] yourMapPointModels = new YourMapPointModel[] { new YourMapPointModel(new LatLng(0d, 1d) /* etc */ ) };
    ArrayList<InputPoint> inputPoints;

    private void buildInputPoints() {
        this.inputPoints = new ArrayList<InputPoint>(yourMapPointModels.length);
        for (YourMapPointModel model : this.yourMapPointModels) {
            this.inputPoints.add(new InputPoint(model.latLng, model));
        }
    }
}
```

When your `GoogleMap` is initialized and your `ArrayList<InputPoint>` is built, you can then initialize Clusterkraf.

```java
    // YourActivity

    Clusterkraf clusterkraf;

    private void initClusterkraf() {
        if (this.map != null && this.inputPoints != null && this.inputPoints.size() > 0) {
    		com.twotoasters.clusterkraf.Options options = new com.twotoasters.clusterkraf.Options();
    		// customize the options before you construct a Clusterkraf instance
    		this.clusterkraf = new Clusterkraf(this.map, this.options, this.inputPoints);
    	}
    }
```

You've added a really sweet clustered map to your Android app.

For a more detailed example, take a look at the included sample app's source code.

## Sample App

The sample app demonstrates Activity lifecycle, custom marker icons, click handling, and Clusterkraf's options. You can build it from source, or install it from https://play.google.com/store/apps/details?id=com.twotoasters.clusterkraf.sample.

### Building the Sample App

1. In your local checkout of the Clusterkraf git repo, do `git submodule init` and `git submodule update`.
2. Add sample/ as a new Android project from existing source.
3. Add sample/libs/ViewPagerIndicator as a new Android project from existing source.
4. Authorize com.twotoasters.clusterkraf.sample built with your key of choice to your Google Maps for Android v2 API account.
5. Create a new Values file `private_strings.xml` in sample/res/values/ and create a string named `maps_api_key` with your Google Maps for Android v2 API key.

## License

    Copyright 2013 Two Toasters

    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.


text:
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2010 Klaus Spanderen

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <quantlib-dev@lists.sf.net>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
#include <ql/methods/finitedifferences/stepconditions/fdmsimpleswingcondition.hpp>

namespace QuantLib {

    FdmSimpleSwingCondition::FdmSimpleSwingCondition(
            const std::vector<Time> & exerciseTimes,
            const boost::shared_ptr<FdmMesher>& mesher,
            const boost::shared_ptr<FdmInnerValueCalculator>& calculator,
            Size swingDirection)
    : exerciseTimes_ (exerciseTimes),
      mesher_        (mesher),
      calculator_    (calculator),
      swingDirection_(swingDirection) {
    }

    void FdmSimpleSwingCondition::applyTo(Array& a, Time t) const {
        const std::vector<Time>::const_iterator iter
            = std::find(exerciseTimes_.begin(), exerciseTimes_.end(), t);

        if (iter != exerciseTimes_.end()) {
            Array retVal= a;

            const Size d = std::distance(iter, exerciseTimes_.end());

            const boost::shared_ptr<FdmLinearOpLayout> layout=mesher_->layout();
            const FdmLinearOpIterator endIter = layout->end();

            for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
                 ++iter) {

                const std::vector<Size>& coor = iter.coordinates();

                const Size exerciseValue = coor[swingDirection_];

                if (exerciseValue > 0) {
                    const Real cashflow = calculator_->innerValue(iter, t);
                    const Real currentValue = a[iter.index()];
                    const Real valueMinusOneExRight
                         = a[layout->neighbourhood(iter, swingDirection_, -1)];

                    if (   currentValue < cashflow + valueMinusOneExRight
                        || exerciseValue >= d ) {
                        retVal[iter.index()] = cashflow + valueMinusOneExRight;
                    }
                }
            }
            a = retVal;
        }
    }
}


text:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:description="Base Page Template is the inherited base for all site templates. It contains the header and footer"
    jcr:primaryType="cq:Component"
    jcr:title="Base Page Template"
    sling:resourceSuperType="wcm/foundation/components/page"
    componentGroup=".hidden"/>


text:
.. _background:

Background
==========

Theory
------

Osprey is designed to optimize the hyperparameters of machine learning models
by maximizing a cross-validation score. As an optimization problem, the key
factors here are

  - very expensive objective function evaluations (minutes to hours, or more)
  - no gradient information is available
  - tension between exploration of parameter space and local optimization (explore / exploit dilemma)

A good, if somewhat dated overview of this problem setting can be found in
Jones, Schonlau, Welch (1998) [#f1]_. The key idea is that we can procede by
fitting a **surrogate function** or **response surface**. This surrogate function needs to provide both our best guess of the function as well as our
degree of belief -- our uncertainty in the parts of parameter space that we
haven't yet explored. Does the maxima lie over there? Then at each iteration,
a new point can be selected by maximizing the **expected improvement** over
our current best solution, by maximize the expected **entropy reduction in the distribution of maxima**, [#f3]_ or a similar so-called acquisition function.

``osprey`` supports multiple :ref:`search strategies <strategy>` for choosing
the next set of hyperparameters to evaluate your model at. The most
theoretically elegant of the supported methods, Gaussian process expected improvement, attacks this problem directly by modeling
the objective function as a draw from a `Gaussian process <http://en.wikipedia.org/wiki/Gaussian_process>`_.

References
----------

.. raw:: html

   <style>
   .wy-table-responsive {
       margin-bottom:0px;
   }
   </style>

.. [#f1] Jones, D. R., M. Schonlau, and W. J. Welch. `"Efficient global optimization of expensive black-box functions." <http://link.springer.com/article/10.1023/A:1008306431147>`_ *J. Global Optim.* 13.4 (1998): 455-492.
.. [#f2] Bergstra, James S., et al. `"Algorithms for hyper-parameter optimization." <http://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization>`_ NIPS. 2011.
.. [#f3] Hennig, P., and C. J. Schuler. `"Entropy search for information-efficient global optimization." <http://jmlr.org/papers/volume13/hennig12a/hennig12a.pdf>`_ *JMLR* 98888.1 (2012): 1809-1837.
.. [#f4] Snoek, J., H. Larochelle, and R. P. Adams. `"Practical Bayesian optimization of machine learning algorithms." <http://papers.nips.cc/paper/4522-practical-bayesian-optimization-of-machine-learning-algorithms>`_ *NIPS* 2012.


text:
package BronzeAndFaith.Map;
import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;

import BronzeAndFaith.Game.HeightPathFinder;
import BronzeAndFaith.Game.PathFinder;

public class River {

	private static PathFinder pf;
	private ArrayList<Point> path;
	public ArrayList<Point> river(){return path;}

	public River(Point start, Point end, int maxTries, HashMap<Point, Float>heightMap) {
		pf = new HeightPathFinder(heightMap);
		path = pf.findPath(start, end, maxTries);
	}

}


text:
//The MIT License(MIT)

//Copyright(c) 2015 Alberto Rodriguez

//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using LiveCharts.Charts;
using LiveCharts.Tooltip;

namespace LiveCharts
{
    public class ScatterChart : Chart, ILine
    {
        public ScatterChart()
        {
            PrimaryAxis = new Axis();
            SecondaryAxis = new Axis();
            Hoverable = true;
            ShapeHoverBehavior = ShapeHoverBehavior.Dot;
            AnimatesNewPoints = true;
            AreaOpacity = 0.2;
            LineType = LineChartLineType.Bezier;
            DataToolTip = new ScatterTooltip();
        }

        public LineChartLineType LineType { get; set; }

        protected override bool ScaleChanged
        {
            get
            {
                return GetMax() != Max ||
                       GetMin() != Min;
            }
        }

        private Point GetMax()
        {
            var p = new Point(
                SecondaryAxis.MaxValue ??
                Series.Cast<ScatterSeries>().Select(x => x.SecondaryValues.DefaultIfEmpty(0).Max()).DefaultIfEmpty(0).Max(),
                PrimaryAxis.MaxValue ??
				Series.Select(x => x.PrimaryValues.DefaultIfEmpty(0).Max()).DefaultIfEmpty(0).Max());
            p.X = SecondaryAxis.MaxValue ?? p.X;
            p.Y = PrimaryAxis.MaxValue ?? p.Y;
            return p;
        }

        private Point GetMin()
        {
            var p = new Point(
                Series.Cast<ScatterSeries>().Select(x => x.SecondaryValues.DefaultIfEmpty(0).Min()).DefaultIfEmpty(0).Min(),
				Series.Select(x => x.PrimaryValues.DefaultIfEmpty(0).Min()).DefaultIfEmpty(0).Min());
            p.X = SecondaryAxis.MinValue ?? p.X;
            p.Y = PrimaryAxis.MinValue ?? p.Y;
            return p;
        }

        private Point GetS()
        {
            return new Point(
                SecondaryAxis.Separator.Step ?? CalculateSeparator(Max.X - Min.X, AxisTags.X),
                PrimaryAxis.Separator.Step ?? CalculateSeparator(Max.Y - Min.Y, AxisTags.Y));
        }

        protected override void Scale()
        {
            Max = GetMax();
            Min = GetMin();
            S = GetS();

            Max.Y = PrimaryAxis.MaxValue ?? (Math.Truncate(Max.Y / S.Y) + 1) * S.Y;
            Min.Y = PrimaryAxis.MinValue ?? (Math.Truncate(Min.Y / S.Y) - 1) * S.Y;

            Max.X = SecondaryAxis.MaxValue ?? (Math.Truncate(Max.X / S.X) + 1) * S.X;
            Min.X = SecondaryAxis.MinValue ?? (Math.Truncate(Min.X / S.X) - 1) * S.X;

            DrawAxis();
        }

        protected override void DrawAxis()
        {
            S = GetS();

            Canvas.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            var lastLabelX = Math.Truncate((Max.X - Min.X) / S.X) * S.X;
            var longestYLabelSize = GetLongestLabelSize(PrimaryAxis);
            var firstXLabelSize = GetLabelSize(SecondaryAxis, Min.X);
            var lastXLabelSize = GetLabelSize(SecondaryAxis, lastLabelX);

            const int padding = 5;

            PlotArea.X = padding * 2 + (longestYLabelSize.X > firstXLabelSize.X * .5 ? longestYLabelSize.X : firstXLabelSize.X * .5);
            PlotArea.Y = longestYLabelSize.Y * .5 + padding;
            PlotArea.Height = Math.Max(0, Canvas.DesiredSize.Height - (padding * 2 + firstXLabelSize.Y) - PlotArea.Y);
            PlotArea.Width = Math.Max(0, Canvas.DesiredSize.Width - PlotArea.X - padding);
            var distanceToEnd = ToPlotArea(Max.X - lastLabelX, AxisTags.X) - PlotArea.X;
            var change = lastXLabelSize.X * .5 - distanceToEnd > 0 ? lastXLabelSize.X * .5 - distanceToEnd : 0;
            if (change <= PlotArea.Width)
                PlotArea.Width -= change;

            base.DrawAxis();
        }

        public override void DataMouseEnter(object sender, MouseEventArgs e)
        {
            if (DataToolTip == null) return;

            DataToolTip.Visibility = Visibility.Visible;
            TooltipTimer.Stop();

            var senderShape = HoverableShapes.FirstOrDefault(s => Equals(s.Shape, sender));
            if (senderShape == null) return;

            senderShape.Target.Stroke = senderShape.Series.Stroke;
            senderShape.Target.Fill = new SolidColorBrush { Color = PointHoverColor };

	        var scatterToolTip = DataToolTip as ScatterTooltip;

	        if (scatterToolTip != null)
	        {
		        scatterToolTip.PrimaryAxisTitle = PrimaryAxis.Title;
		        scatterToolTip.PrimaryValue = PrimaryAxis.LabelFormatter == null
			                                      ? senderShape.Value.Y.ToString(CultureInfo.InvariantCulture)
			                                      : PrimaryAxis.LabelFormatter(senderShape.Value.Y);
		        scatterToolTip.SecondaryAxisTitle = SecondaryAxis.Title;
		        scatterToolTip.SecondaryValue = SecondaryAxis.LabelFormatter == null
			                                        ? senderShape.Value.X.ToString(CultureInfo.InvariantCulture)
			                                        : SecondaryAxis.LabelFormatter(senderShape.Value.X);
	        }
	        var p = GetToolTipPosition(senderShape, null);

            DataToolTip.BeginAnimation(Canvas.LeftProperty, new DoubleAnimation
            {
                To = p.X,
                Duration = TimeSpan.FromMilliseconds(200)
            });
            DataToolTip.BeginAnimation(Canvas.TopProperty, new DoubleAnimation
            {
                To = p.Y,
                Duration = TimeSpan.FromMilliseconds(200)
            });
        }

        public override void DataMouseLeave(object sender, MouseEventArgs e)
        {
            var s = sender as Shape;
            if (s == null) return;

            var shape = HoverableShapes.FirstOrDefault(x => Equals(x.Shape, s));
            if (shape == null) return;

            shape.Target.Fill = shape.Series.Stroke;
            shape.Target.Stroke = new SolidColorBrush { Color = PointHoverColor };

            TooltipTimer.Stop();
            TooltipTimer.Start();
        }

        protected override Point GetToolTipPosition(HoverableShape sender, List<HoverableShape> sibilings)
        {
            DataToolTip.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            var x = sender.Value.X > (Min.X + Max.X) / 2
                ? ToPlotArea(sender.Value.X, AxisTags.X) - 10 - DataToolTip.DesiredSize.Width
                : ToPlotArea(sender.Value.X, AxisTags.X) + 10;
            var y = sender.Value.Y > (Min.Y + Max.Y) / 2
                ? ToPlotArea(sender.Value.Y, AxisTags.Y) + 10
                : ToPlotArea(sender.Value.Y, AxisTags.Y) - 10 - DataToolTip.DesiredSize.Height;
            return new Point(x, y);
        }
    }
}


text:
package org.guvnor.common.services.project.backend.server.utils;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import javax.enterprise.context.Dependent;

import org.apache.maven.model.Build;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Repository;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.guvnor.common.services.project.model.GAV;
import org.guvnor.common.services.project.model.POM;

@Dependent
public class POMContentHandler {

    public POMContentHandler() {
        // Weld needs this for proxying.
    }

    public String toString(final POM pomModel)
            throws IOException {
        return toString(pomModel,
                        new Model());
    }

    private String toString(final POM pom,
                            final Model model) throws IOException {
        model.setName(pom.getName());
        model.setDescription(pom.getDescription());
        model.setArtifactId(pom.getGav().getArtifactId());
        model.setModelVersion(pom.getModelVersion());

        model.setGroupId(pom.getGav().getGroupId());
        model.setVersion(pom.getGav().getVersion());

        model.setPackaging(pom.getPackaging());

        model.setParent(getParent(pom));
        model.setBuild(getBuild(pom,
                                model));
        model.setModules(getModules(pom));
        model.setRepositories(getRepositories(pom));
        new DependencyUpdater(model.getDependencies()).updateDependencies(pom.getDependencies());

        StringWriter stringWriter = new StringWriter();
        new MavenXpp3Writer().write(stringWriter,
                                    model);
        return stringWriter.toString();
    }

    private Build getBuild(final POM pom,
                           final Model model) {
        return new BuildContentHandler().update(pom.getBuild(),
                                                model.getBuild());
    }

    private ArrayList<Repository> getRepositories(final POM pom) {
        ArrayList<Repository> result = new ArrayList<Repository>();
        for (org.guvnor.common.services.project.model.Repository repository : pom.getRepositories()) {
            result.add(fromClientModelToPom(repository));
        }
        return result;
    }

    private ArrayList<String> getModules(final POM pom) {
        ArrayList<String> result = new ArrayList<String>();
        if (pom.getModules() != null) {
            for (String module : pom.getModules()) {
                result.add(module);
            }
        }
        return result;
    }

    private Parent getParent(final POM pom) {
        if (pom.getParent() == null) {
            return null;
        } else {
            Parent parent = new Parent();
            parent.setGroupId(pom.getParent().getGroupId());
            parent.setArtifactId(pom.getParent().getArtifactId());
            parent.setVersion(pom.getParent().getVersion());
            return parent;
        }
    }

    /**
     * @param gavModel The model that is saved
     * @param originalPomAsText The original pom in text form, since the guvnor POM model does not cover all the pom.xml features.
     * @return pom.xml for saving, The original pom.xml with the fields edited in gavModel replaced.
     * @throws IOException
     */
    public String toString(final POM gavModel,
                           final String originalPomAsText) throws IOException, XmlPullParserException {

        return toString(gavModel,
                        new MavenXpp3Reader().read(new StringReader(originalPomAsText)));
    }

    private Repository fromClientModelToPom(final org.guvnor.common.services.project.model.Repository from) {
        Repository to = new Repository();
        to.setId(from.getId());
        to.setName(from.getName());
        to.setUrl(from.getUrl());

        return to;
    }

    public POM toModel(final String pomAsString) throws IOException, XmlPullParserException {
        Model model = new MavenXpp3Reader().read(new StringReader(pomAsString));

        POM pomModel = new POM(
                model.getName(),
                model.getDescription(),
                new GAV(
                        (model.getGroupId() == null ? model.getParent().getGroupId() : model.getGroupId()),
                        (model.getArtifactId() == null ? model.getParent().getArtifactId() : model.getArtifactId()),
                        (model.getVersion() == null ? model.getParent().getVersion() : model.getVersion())
                )
        );

        pomModel.setPackaging(model.getPackaging());

        if (model.getParent() != null) {
            pomModel.setParent(new GAV(model.getParent().getGroupId(),
                                       model.getParent().getArtifactId(),
                                       model.getParent().getVersion()));
        }

        pomModel.getModules().clear();
        for (String module : model.getModules()) {
            pomModel.getModules().add(module);
            pomModel.setPackaging("pom");
        }
        for (Repository repository : model.getRepositories()) {
            pomModel.addRepository(fromPomModelToClientModel(repository));
        }

        pomModel.setDependencies(new DependencyContentHandler().fromPomModelToClientModel(model.getDependencies()));

        pomModel.setBuild(new BuildContentHandler().fromPomModelToClientModel(model.getBuild()));

        return pomModel;
    }

    private org.guvnor.common.services.project.model.Repository fromPomModelToClientModel(final Repository from) {
        org.guvnor.common.services.project.model.Repository to = new org.guvnor.common.services.project.model.Repository();

        to.setId(from.getId());
        to.setName(from.getName());
        to.setUrl(from.getUrl());

        return to;
    }
}


text:
    <meta http-equiv="Content-Type" content="text/html; charset=Windows-1252" />
    <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5" />
    <title>StandardAnalyzer.GetMaxTokenLength Method</title>
    <xml>
    </xml>
    <link rel="stylesheet" type="text/css" href="MSDN.css" />

            Apache Lucene.Net 2.4.0 Class Library API

StandardAnalyzer.GetMaxTokenLength Method

public virtual int GetMaxTokenLength();

See Also

        StandardAnalyzer Class | Lucene.Net.Analysis.Standard Namespace | setMaxTokenLength

      <object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e" viewastext="true" style="display: none;">
        <param name="Keyword" value="GetMaxTokenLength method">
        </param>
        <param name="Keyword" value="GetMaxTokenLength method, StandardAnalyzer class">
        </param>
        <param name="Keyword" value="StandardAnalyzer.GetMaxTokenLength method">
        </param>
      </object>

Generated from assembly Lucene.Net [2.4.0.2]


text:
import { timestamp, deepAccess, getOrigin } from '../src/utils.js';
import { config } from '../src/config.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
const BIDDER_CODE = 'resetdigital';

export const spec = {
  code: BIDDER_CODE,
  supportedMediaTypes: [ 'banner', 'video' ],
  isBidRequestValid: function(bid) {
    return (!!(bid.params.pubId || bid.params.zoneId));
  },
  buildRequests: function(validBidRequests, bidderRequest) {
    let stack = (bidderRequest.refererInfo &&
      bidderRequest.refererInfo.stack ? bidderRequest.refererInfo.stack
      : [])

    let spb = (config.getConfig('userSync') && config.getConfig('userSync').syncsPerBidder)
      ? config.getConfig('userSync').syncsPerBidder : 5

    const payload = {
      start_time: timestamp(),
      language: window.navigator.userLanguage || window.navigator.language,
      site: {
        domain: getOrigin(),
        iframe: !bidderRequest.refererInfo.reachedTop,
        url: stack && stack.length > 0 ? [stack.length - 1] : null,
        https: (window.location.protocol === 'https:'),
        referrer: bidderRequest.refererInfo.referer
      },
      imps: [],
      user_ids: validBidRequests[0].userId,
      sync_limit: spb
    };

    if (bidderRequest && bidderRequest.gdprConsent) {
      payload.gdpr = {
        applies: bidderRequest.gdprConsent.gdprApplies,
        consent: bidderRequest.gdprConsent.consentString
      };
    }

    for (let x = 0; x < validBidRequests.length; x++) {
      let req = validBidRequests[x]

      payload.imps.push({
        pub_id: req.params.pubId,
        zone_id: req.params.zoneId,
        bid_id: req.bidId,
        imp_id: req.transactionId,
        sizes: req.sizes,
        force_bid: req.params.forceBid,
        media_types: deepAccess(req, 'mediaTypes')
      });
    }

    let params = validBidRequests[0].params
    let url = params.endpoint ? params.endpoint : '//ads.resetsrv.com'
    return {
      method: 'POST',
      url: url,
      data: JSON.stringify(payload)
    };
  },
  interpretResponse: function(serverResponse, bidRequest) {
    const bidResponses = [];
    if (!serverResponse || !serverResponse.body) {
      return bidResponses
    }

    let res = serverResponse.body;
    if (!res.bids || !res.bids.length) {
      return []
    }

    for (let x = 0; x < serverResponse.body.bids.length; x++) {
      let bid = serverResponse.body.bids[x]

      bidResponses.push({
        requestId: bid.bid_id,
        cpm: bid.cpm,
        width: bid.w,
        height: bid.h,
        ad: bid.html,
        vastUrl: bid.vast_url,
        vastXml: bid.vast_xml,
        mediaType: bid.html ? 'banner' : 'video',
        ttl: 120,
        creativeId: bid.crid,
        dealId: bid.deal_id,
        netRevenue: true,
        currency: 'USD',
        meta: {
          advertiserDomains: bid.adomain
        }
      })
    }

    return bidResponses;
  },
  getUserSyncs: function(syncOptions, serverResponses, gdprConsent) {
    const syncs = []

    if (!serverResponses.length || !serverResponses[0].body) {
      return syncs
    }

    let pixels = serverResponses[0].body.pixels
    if (!pixels || !pixels.length) {
      return syncs
    }

    let gdprParams = null
    if (gdprConsent) {
      if (typeof gdprConsent.gdprApplies === 'boolean') {
        gdprParams = `gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`
      } else {
        gdprParams = `gdpr_consent=${gdprConsent.consentString}`
      }
    }

    for (let x = 0; x < pixels.length; x++) {
      let pixel = pixels[x]

      if ((pixel.type === 'iframe' && syncOptions.iframeEnabled) ||
        (pixel.type === 'image' && syncOptions.pixelEnabled)) {
        if (gdprParams && gdprParams.length) {
          pixel = (pixel.indexOf('?') === -1 ? '?' : '&') + gdprParams
        }
        syncs.push(pixel)
      }
    }
    return syncs;
  }
};

registerBidder(spec);


text:
module Puree

  module REST

    # Requests for the Prize resource
    #
    class Prize < Puree::REST::Base

      private

      def collection
        'prizes'
      end

    end

  end

end