text:
package com.gitblit;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.DeepCopier;
import com.gitblit.utils.StringUtils;

/**
 * FileUserService is Gitblit's original default user service implementation.
 *
 * Users and their repository memberships are stored in a simple properties file
 * which is cached and dynamically reloaded when modified.
 *
 * This class was deprecated in Gitblit 0.8.0 in favor of ConfigUserService
 * which is still a human-readable, editable, plain-text file but it is more
 * flexible for storing additional fields.
 *
 * @author James Moger
 *
 */
@Deprecated
public class FileUserService extends FileSettings implements IUserService {

	private final Logger logger = LoggerFactory.getLogger(FileUserService.class);

	private final Map<String, String> cookies = new ConcurrentHashMap<String, String>();

	private final Map<String, TeamModel> teams = new ConcurrentHashMap<String, TeamModel>();

	public FileUserService(File realmFile) {
		super(realmFile.getAbsolutePath());
	}

	/**
	 * Setup the user service.
	 *
	 * @param settings
	 * @since 0.7.0
	 */
	@Override
	public void setup(IStoredSettings settings) {
	}

	/**
	 * Does the user service support changes to credentials?
	 *
	 * @return true or false
	 * @since 1.0.0
	 */
	@Override
	public boolean supportsCredentialChanges() {
		return true;
	}

	/**
	 * Does the user service support changes to user display name?
	 *
	 * @return true or false
	 * @since 1.0.0
	 */
	@Override
	public boolean supportsDisplayNameChanges() {
		return false;
	}

	/**
	 * Does the user service support changes to user email address?
	 *
	 * @return true or false
	 * @since 1.0.0
	 */
	@Override
	public boolean supportsEmailAddressChanges() {
		return false;
	}

	/**
	 * Does the user service support changes to team memberships?
	 *
	 * @return true or false
	 * @since 1.0.0
	 */
	public boolean supportsTeamMembershipChanges() {
		return true;
	}

	/**
	 * Does the user service support cookie authentication?
	 *
	 * @return true or false
	 */
	@Override
	public boolean supportsCookies() {
		return true;
	}

	/**
	 * Returns the cookie value for the specified user.
	 *
	 * @param model
	 * @return cookie value
	 */
	@Override
	public String getCookie(UserModel model) {
		if (!StringUtils.isEmpty(model.cookie)) {
			return model.cookie;
		}
		Properties allUsers = super.read();
		String value = allUsers.getProperty(model.username);
		String[] roles = value.split(",");
		String password = roles[0];
		String cookie = StringUtils.getSHA1(model.username + password);
		return cookie;
	}

	/**
	 * Authenticate a user based on their cookie.
	 *
	 * @param cookie
	 * @return a user object or null
	 */
	@Override
	public UserModel authenticate(char[] cookie) {
		String hash = new String(cookie);
		if (StringUtils.isEmpty(hash)) {
			return null;
		}
		read();
		UserModel model = null;
		if (cookies.containsKey(hash)) {
			String username = cookies.get(hash);
			model = getUserModel(username);
		}
		return model;
	}

	/**
	 * Authenticate a user based on a username and password.
	 *
	 * @param username
	 * @param password
	 * @return a user object or null
	 */
	@Override
	public UserModel authenticate(String username, char[] password) {
		Properties allUsers = read();
		String userInfo = allUsers.getProperty(username);
		if (StringUtils.isEmpty(userInfo)) {
			return null;
		}
		UserModel returnedUser = null;
		UserModel user = getUserModel(username);
		if (user.password.startsWith(StringUtils.MD5_TYPE)) {
			// password digest
			String md5 = StringUtils.MD5_TYPE + StringUtils.getMD5(new String(password));
			if (user.password.equalsIgnoreCase(md5)) {
				returnedUser = user;
			}
		} else if (user.password.startsWith(StringUtils.COMBINED_MD5_TYPE)) {
			// username+password digest
			String md5 = StringUtils.COMBINED_MD5_TYPE
					+ StringUtils.getMD5(username.toLowerCase() + new String(password));
			if (user.password.equalsIgnoreCase(md5)) {
				returnedUser = user;
			}
		} else if (user.password.equals(new String(password))) {
			// plain-text password
			returnedUser = user;
		}
		return returnedUser;
	}

	/**
	 * Logout a user.
	 *
	 * @param user
	 */
	@Override
	public void logout(UserModel user) {
	}

	/**
	 * Retrieve the user object for the specified username.
	 *
	 * @param username
	 * @return a user object or null
	 */
	@Override
	public UserModel getUserModel(String username) {
		Properties allUsers = read();
		String userInfo = allUsers.getProperty(username.toLowerCase());
		if (userInfo == null) {
			return null;
		}
		UserModel model = new UserModel(username.toLowerCase());
		String[] userValues = userInfo.split(",");
		model.password = userValues[0];
		for (int i = 1; i < userValues.length; i++) {
			String role = userValues[i];
			switch (role.charAt(0)) {
			case '#':
				// Permissions
				if (role.equalsIgnoreCase(Constants.ADMIN_ROLE)) {
					model.canAdmin = true;
				} else if (role.equalsIgnoreCase(Constants.FORK_ROLE)) {
					model.canFork = true;
				} else if (role.equalsIgnoreCase(Constants.NOT_FEDERATED_ROLE)) {
					model.excludeFromFederation = true;
				}
				break;
			default:
				model.addRepository(role);
			}
		}
		// set the teams for the user
		for (TeamModel team : teams.values()) {
			if (team.hasUser(username)) {
				model.teams.add(DeepCopier.copy(team));
			}
		}
		return model;
	}

	/**
	 * Updates/writes a complete user object.
	 *
	 * @param model
	 * @return true if update is successful
	 */
	@Override
	public boolean updateUserModel(UserModel model) {
		return updateUserModel(model.username, model);
	}

	/**
	 * Updates/writes and replaces a complete user object keyed by username.
	 * This method allows for renaming a user.
	 *
	 * @param username
	 *            the old username
	 * @param model
	 *            the user object to use for username
	 * @return true if update is successful
	 */
	@Override
	public boolean updateUserModel(String username, UserModel model) {
		try {
			Properties allUsers = read();
			UserModel oldUser = getUserModel(username);
			ArrayList<String> roles = new ArrayList<String>(model.repositories);

			// Permissions
			if (model.canAdmin) {
				roles.add(Constants.ADMIN_ROLE);
			}
			if (model.canFork) {
				roles.add(Constants.FORK_ROLE);
			}
			if (model.excludeFromFederation) {
				roles.add(Constants.NOT_FEDERATED_ROLE);
			}

			StringBuilder sb = new StringBuilder();
			if (!StringUtils.isEmpty(model.password)) {
				sb.append(model.password);
			}
			sb.append(',');
			for (String role : roles) {
				sb.append(role);
				sb.append(',');
			}
			// trim trailing comma
			sb.setLength(sb.length() - 1);
			allUsers.remove(username.toLowerCase());
			allUsers.put(model.username.toLowerCase(), sb.toString());

			// null check on "final" teams because JSON-sourced UserModel
			// can have a null teams object
			if (model.teams != null) {
				// update team cache
				for (TeamModel team : model.teams) {
					TeamModel t = getTeamModel(team.name);
					if (t == null) {
						// new team
						t = team;
					}
					t.removeUser(username);
					t.addUser(model.username);
					updateTeamCache(allUsers, t.name, t);
				}

				// check for implicit team removal
				if (oldUser != null) {
					for (TeamModel team : oldUser.teams) {
						if (!model.isTeamMember(team.name)) {
							team.removeUser(username);
							updateTeamCache(allUsers, team.name, team);
						}
					}
				}
			}

			write(allUsers);
			return true;
		} catch (Throwable t) {
			logger.error(MessageFormat.format("Failed to update user model {0}!", model.username),
					t);
		}
		return false;
	}

	/**
	 * Deletes the user object from the user service.
	 *
	 * @param model
	 * @return true if successful
	 */
	@Override
	public boolean deleteUserModel(UserModel model) {
		return deleteUser(model.username);
	}

	/**
	 * Delete the user object with the specified username
	 *
	 * @param username
	 * @return true if successful
	 */
	@Override
	public boolean deleteUser(String username) {
		try {
			// Read realm file
			Properties allUsers = read();
			UserModel user = getUserModel(username);
			allUsers.remove(username);
			for (TeamModel team : user.teams) {
				TeamModel t = getTeamModel(team.name);
				if (t == null) {
					// new team
					t = team;
				}
				t.removeUser(username);
				updateTeamCache(allUsers, t.name, t);
			}
			write(allUsers);
			return true;
		} catch (Throwable t) {
			logger.error(MessageFormat.format("Failed to delete user {0}!", username), t);
		}
		return false;
	}

	/**
	 * Returns the list of all users available to the login service.
	 *
	 * @return list of all usernames
	 */
	@Override
	public List<String> getAllUsernames() {
		Properties allUsers = read();
		List<String> list = new ArrayList<String>();
		for (String user : allUsers.stringPropertyNames()) {
			if (user.charAt(0) == '@') {
				// skip team user definitions
				continue;
			}
			list.add(user);
		}
		Collections.sort(list);
		return list;
	}

	/**
	 * Returns the list of all users available to the login service.
	 *
	 * @return list of all usernames
	 */
	@Override
	public List<UserModel> getAllUsers() {
		read();
		List<UserModel> list = new ArrayList<UserModel>();
		for (String username : getAllUsernames()) {
			list.add(getUserModel(username));
		}
		Collections.sort(list);
		return list;
	}

	/**
	 * Returns the list of all users who are allowed to bypass the access
	 * restriction placed on the specified repository.
	 *
	 * @param role
	 *            the repository name
	 * @return list of all usernames that can bypass the access restriction
	 */
	@Override
	public List<String> getUsernamesForRepositoryRole(String role) {
		List<String> list = new ArrayList<String>();
		try {
			Properties allUsers = read();
			for (String username : allUsers.stringPropertyNames()) {
				if (username.charAt(0) == '@') {
					continue;
				}
				String value = allUsers.getProperty(username);
				String[] values = value.split(",");
				// skip first value (password)
				for (int i = 1; i < values.length; i++) {
					String r = values[i];
					if (r.equalsIgnoreCase(role)) {
						list.add(username);
						break;
					}
				}
			}
		} catch (Throwable t) {
			logger.error(MessageFormat.format("Failed to get usernames for role {0}!", role), t);
		}
		Collections.sort(list);
		return list;
	}

	/**
	 * Sets the list of all users who are allowed to bypass the access
	 * restriction placed on the specified repository.
	 *
	 * @param role
	 *            the repository name
	 * @param usernames
	 * @return true if successful
	 */
	@Override
	public boolean setUsernamesForRepositoryRole(String role, List<String> usernames) {
		try {
			Set<String> specifiedUsers = new HashSet<String>(usernames);
			Set<String> needsAddRole = new HashSet<String>(specifiedUsers);
			Set<String> needsRemoveRole = new HashSet<String>();

			// identify users which require add and remove role
			Properties allUsers = read();
			for (String username : allUsers.stringPropertyNames()) {
				String value = allUsers.getProperty(username);
				String[] values = value.split(",");
				// skip first value (password)
				for (int i = 1; i < values.length; i++) {
					String r = values[i];
					if (r.equalsIgnoreCase(role)) {
						// user has role, check against revised user list
						if (specifiedUsers.contains(username)) {
							needsAddRole.remove(username);
						} else {
							// remove role from user
							needsRemoveRole.add(username);
						}
						break;
					}
				}
			}

			// add roles to users
			for (String user : needsAddRole) {
				String userValues = allUsers.getProperty(user);
				userValues += "," + role;
				allUsers.put(user, userValues);
			}

			// remove role from user
			for (String user : needsRemoveRole) {
				String[] values = allUsers.getProperty(user).split(",");
				String password = values[0];
				StringBuilder sb = new StringBuilder();
				sb.append(password);
				sb.append(',');

				// skip first value (password)
				for (int i = 1; i < values.length; i++) {
					String value = values[i];
					if (!value.equalsIgnoreCase(role)) {
						sb.append(value);
						sb.append(',');
					}
				}
				sb.setLength(sb.length() - 1);

				// update properties
				allUsers.put(user, sb.toString());
			}

			// persist changes
			write(allUsers);
			return true;
		} catch (Throwable t) {
			logger.error(MessageFormat.format("Failed to set usernames for role {0}!", role), t);
		}
		return false;
	}

	/**
	 * Renames a repository role.
	 *
	 * @param oldRole
	 * @param newRole
	 * @return true if successful
	 */
	@Override
	public boolean renameRepositoryRole(String oldRole, String newRole) {
		try {
			Properties allUsers = read();
			Set<String> needsRenameRole = new HashSet<String>();

			// identify users which require role rename
			for (String username : allUsers.stringPropertyNames()) {
				String value = allUsers.getProperty(username);
				String[] roles = value.split(",");
				// skip first value (password)
				for (int i = 1; i < roles.length; i++) {
					String r = roles[i];
					if (r.equalsIgnoreCase(oldRole)) {
						needsRenameRole.add(username);
						break;
					}
				}
			}

			// rename role for identified users
			for (String user : needsRenameRole) {
				String userValues = allUsers.getProperty(user);
				String[] values = userValues.split(",");
				String password = values[0];
				StringBuilder sb = new StringBuilder();
				sb.append(password);
				sb.append(',');
				sb.append(newRole);
				sb.append(',');

				// skip first value (password)
				for (int i = 1; i < values.length; i++) {
					String value = values[i];
					if (!value.equalsIgnoreCase(oldRole)) {
						sb.append(value);
						sb.append(',');
					}
				}
				sb.setLength(sb.length() - 1);

				// update properties
				allUsers.put(user, sb.toString());
			}

			// persist changes
			write(allUsers);
			return true;
		} catch (Throwable t) {
			logger.error(
					MessageFormat.format("Failed to rename role {0} to {1}!", oldRole, newRole), t);
		}
		return false;
	}

	/**
	 * Removes a repository role from all users.
	 *
	 * @param role
	 * @return true if successful
	 */
	@Override
	public boolean deleteRepositoryRole(String role) {
		try {
			Properties allUsers = read();
			Set<String> needsDeleteRole = new HashSet<String>();

			// identify users which require role rename
			for (String username : allUsers.stringPropertyNames()) {
				String value = allUsers.getProperty(username);
				String[] roles = value.split(",");
				// skip first value (password)
				for (int i = 1; i < roles.length; i++) {
					String r = roles[i];
					if (r.equalsIgnoreCase(role)) {
						needsDeleteRole.add(username);
						break;
					}
				}
			}

			// delete role for identified users
			for (String user : needsDeleteRole) {
				String userValues = allUsers.getProperty(user);
				String[] values = userValues.split(",");
				String password = values[0];
				StringBuilder sb = new StringBuilder();
				sb.append(password);
				sb.append(',');
				// skip first value (password)
				for (int i = 1; i < values.length; i++) {
					String value = values[i];
					if (!value.equalsIgnoreCase(role)) {
						sb.append(value);
						sb.append(',');
					}
				}
				sb.setLength(sb.length() - 1);

				// update properties
				allUsers.put(user, sb.toString());
			}

			// persist changes
			write(allUsers);
			return true;
		} catch (Throwable t) {
			logger.error(MessageFormat.format("Failed to delete role {0}!", role), t);
		}
		return false;
	}

	/**
	 * Writes the properties file.
	 *
	 * @param properties
	 * @throws IOException
	 */
	private void write(Properties properties) throws IOException {
		// Write a temporary copy of the users file
		File realmFileCopy = new File(propertiesFile.getAbsolutePath() + ".tmp");
		FileWriter writer = new FileWriter(realmFileCopy);
		properties
				.store(writer,
						" Gitblit realm file format:\n   username=password,\\#permission,repository1,repository2...\n   @teamname=!username1,!username2,!username3,repository1,repository2...");
		writer.close();
		// If the write is successful, delete the current file and rename
		// the temporary copy to the original filename.
		if (realmFileCopy.exists() && realmFileCopy.length() > 0) {
			if (propertiesFile.exists()) {
				if (!propertiesFile.delete()) {
					throw new IOException(MessageFormat.format("Failed to delete {0}!",
							propertiesFile.getAbsolutePath()));
				}
			}
			if (!realmFileCopy.renameTo(propertiesFile)) {
				throw new IOException(MessageFormat.format("Failed to rename {0} to {1}!",
						realmFileCopy.getAbsolutePath(), propertiesFile.getAbsolutePath()));
			}
		} else {
			throw new IOException(MessageFormat.format("Failed to save {0}!",
					realmFileCopy.getAbsolutePath()));
		}
	}

	/**
	 * Reads the properties file and rebuilds the in-memory cookie lookup table.
	 */
	@Override
	protected synchronized Properties read() {
		long lastRead = lastModified();
		boolean reload = forceReload();
		Properties allUsers = super.read();
		if (reload || (lastRead != lastModified())) {
			// reload hash cache
			cookies.clear();
			teams.clear();

			for (String username : allUsers.stringPropertyNames()) {
				String value = allUsers.getProperty(username);
				String[] roles = value.split(",");
				if (username.charAt(0) == '@') {
					// team definition
					TeamModel team = new TeamModel(username.substring(1));
					List<String> repositories = new ArrayList<String>();
					List<String> users = new ArrayList<String>();
					List<String> mailingLists = new ArrayList<String>();
					List<String> preReceive = new ArrayList<String>();
					List<String> postReceive = new ArrayList<String>();
					for (String role : roles) {
						if (role.charAt(0) == '!') {
							users.add(role.substring(1));
						} else if (role.charAt(0) == '&') {
							mailingLists.add(role.substring(1));
						} else if (role.charAt(0) == '^') {
							preReceive.add(role.substring(1));
						} else if (role.charAt(0) == '%') {
							postReceive.add(role.substring(1));
						} else {
							repositories.add(role);
						}
					}
					team.addRepositories(repositories);
					team.addUsers(users);
					team.addMailingLists(mailingLists);
					team.preReceiveScripts.addAll(preReceive);
					team.postReceiveScripts.addAll(postReceive);
					teams.put(team.name.toLowerCase(), team);
				} else {
					// user definition
					String password = roles[0];
					cookies.put(StringUtils.getSHA1(username.toLowerCase() + password), username.toLowerCase());
				}
			}
		}
		return allUsers;
	}

	@Override
	public String toString() {
		return getClass().getSimpleName() + "(" + propertiesFile.getAbsolutePath() + ")";
	}

	/**
	 * Returns the list of all teams available to the login service.
	 *
	 * @return list of all teams
	 * @since 0.8.0
	 */
	@Override
	public List<String> getAllTeamNames() {
		List<String> list = new ArrayList<String>(teams.keySet());
		Collections.sort(list);
		return list;
	}

	/**
	 * Returns the list of all teams available to the login service.
	 *
	 * @return list of all teams
	 * @since 0.8.0
	 */
	@Override
	public List<TeamModel> getAllTeams() {
		List<TeamModel> list = new ArrayList<TeamModel>(teams.values());
		list = DeepCopier.copy(list);
		Collections.sort(list);
		return list;
	}

	/**
	 * Returns the list of all teams who are allowed to bypass the access
	 * restriction placed on the specified repository.
	 *
	 * @param role
	 *            the repository name
	 * @return list of all teamnames that can bypass the access restriction
	 */
	@Override
	public List<String> getTeamnamesForRepositoryRole(String role) {
		List<String> list = new ArrayList<String>();
		try {
			Properties allUsers = read();
			for (String team : allUsers.stringPropertyNames()) {
				if (team.charAt(0) != '@') {
					// skip users
					continue;
				}
				String value = allUsers.getProperty(team);
				String[] values = value.split(",");
				for (int i = 0; i < values.length; i++) {
					String r = values[i];
					if (r.equalsIgnoreCase(role)) {
						// strip leading @
						list.add(team.substring(1));
						break;
					}
				}
			}
		} catch (Throwable t) {
			logger.error(MessageFormat.format("Failed to get teamnames for role {0}!", role), t);
		}
		Collections.sort(list);
		return list;
	}

	/**
	 * Sets the list of all teams who are allowed to bypass the access
	 * restriction placed on the specified repository.
	 *
	 * @param role
	 *            the repository name
	 * @param teamnames
	 * @return true if successful
	 */
	@Override
	public boolean setTeamnamesForRepositoryRole(String role, List<String> teamnames) {
		try {
			Set<String> specifiedTeams = new HashSet<String>(teamnames);
			Set<String> needsAddRole = new HashSet<String>(specifiedTeams);
			Set<String> needsRemoveRole = new HashSet<String>();

			// identify teams which require add and remove role
			Properties allUsers = read();
			for (String team : allUsers.stringPropertyNames()) {
				if (team.charAt(0) != '@') {
					// skip users
					continue;
				}
				String name = team.substring(1);
				String value = allUsers.getProperty(team);
				String[] values = value.split(",");
				for (int i = 0; i < values.length; i++) {
					String r = values[i];
					if (r.equalsIgnoreCase(role)) {
						// team has role, check against revised team list
						if (specifiedTeams.contains(name)) {
							needsAddRole.remove(name);
						} else {
							// remove role from team
							needsRemoveRole.add(name);
						}
						break;
					}
				}
			}

			// add roles to teams
			for (String name : needsAddRole) {
				String team = "@" + name;
				String teamValues = allUsers.getProperty(team);
				teamValues += "," + role;
				allUsers.put(team, teamValues);
			}

			// remove role from team
			for (String name : needsRemoveRole) {
				String team = "@" + name;
				String[] values = allUsers.getProperty(team).split(",");
				StringBuilder sb = new StringBuilder();
				for (int i = 0; i < values.length; i++) {
					String value = values[i];
					if (!value.equalsIgnoreCase(role)) {
						sb.append(value);
						sb.append(',');
					}
				}
				sb.setLength(sb.length() - 1);

				// update properties
				allUsers.put(team, sb.toString());
			}

			// persist changes
			write(allUsers);
			return true;
		} catch (Throwable t) {
			logger.error(MessageFormat.format("Failed to set teamnames for role {0}!", role), t);
		}
		return false;
	}

	/**
	 * Retrieve the team object for the specified team name.
	 *
	 * @param teamname
	 * @return a team object or null
	 * @since 0.8.0
	 */
	@Override
	public TeamModel getTeamModel(String teamname) {
		read();
		TeamModel team = teams.get(teamname.toLowerCase());
		if (team != null) {
			// clone the model, otherwise all changes to this object are
			// live and unpersisted
			team = DeepCopier.copy(team);
		}
		return team;
	}

	/**
	 * Updates/writes a complete team object.
	 *
	 * @param model
	 * @return true if update is successful
	 * @since 0.8.0
	 */
	@Override
	public boolean updateTeamModel(TeamModel model) {
		return updateTeamModel(model.name, model);
	}

	/**
	 * Updates/writes and replaces a complete team object keyed by teamname.
	 * This method allows for renaming a team.
	 *
	 * @param teamname
	 *            the old teamname
	 * @param model
	 *            the team object to use for teamname
	 * @return true if update is successful
	 * @since 0.8.0
	 */
	@Override
	public boolean updateTeamModel(String teamname, TeamModel model) {
		try {
			Properties allUsers = read();
			updateTeamCache(allUsers, teamname, model);
			write(allUsers);
			return true;
		} catch (Throwable t) {
			logger.error(MessageFormat.format("Failed to update team model {0}!", model.name), t);
		}
		return false;
	}

	private void updateTeamCache(Properties allUsers, String teamname, TeamModel model) {
		StringBuilder sb = new StringBuilder();
		if (!ArrayUtils.isEmpty(model.repositories)) {
			for (String repository : model.repositories) {
				sb.append(repository);
				sb.append(',');
			}
		}
		if (!ArrayUtils.isEmpty(model.users)) {
			for (String user : model.users) {
				sb.append('!');
				sb.append(user);
				sb.append(',');
			}
		}
		if (!ArrayUtils.isEmpty(model.mailingLists)) {
			for (String address : model.mailingLists) {
				sb.append('&');
				sb.append(address);
				sb.append(',');
			}
		}
		if (!ArrayUtils.isEmpty(model.preReceiveScripts)) {
			for (String script : model.preReceiveScripts) {
				sb.append('^');
				sb.append(script);
				sb.append(',');
			}
		}
		if (!ArrayUtils.isEmpty(model.postReceiveScripts)) {
			for (String script : model.postReceiveScripts) {
				sb.append('%');
				sb.append(script);
				sb.append(',');
			}
		}
		// trim trailing comma
		sb.setLength(sb.length() - 1);
		allUsers.remove("@" + teamname);
		allUsers.put("@" + model.name, sb.toString());

		// update team cache
		teams.remove(teamname.toLowerCase());
		teams.put(model.name.toLowerCase(), model);
	}

	/**
	 * Deletes the team object from the user service.
	 *
	 * @param model
	 * @return true if successful
	 * @since 0.8.0
	 */
	@Override
	public boolean deleteTeamModel(TeamModel model) {
		return deleteTeam(model.name);
	}

	/**
	 * Delete the team object with the specified teamname
	 *
	 * @param teamname
	 * @return true if successful
	 * @since 0.8.0
	 */
	@Override
	public boolean deleteTeam(String teamname) {
		Properties allUsers = read();
		teams.remove(teamname.toLowerCase());
		allUsers.remove("@" + teamname);
		try {
			write(allUsers);
			return true;
		} catch (Throwable t) {
			logger.error(MessageFormat.format("Failed to delete team {0}!", teamname), t);
		}
		return false;
	}
}


text:
/*'use strict';

describe('Controller: AdminQuestionsCtrl', function () {

  // load the controller's module
  beforeEach(module('openstorefrontApp'));

  var AdminQuestionsCtrl,
    scope;

  // Initialize the controller and a mock scope
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    AdminQuestionsCtrl = $controller('AdminQuestionsCtrl', {
      $scope: scope
    });
  }));

  it('should have the correct initializations', function () {
    expect(scope.predicate).toEqual([]);
    expect(scope.reverse).toEqual([]);
    expect(scope.statusFilterOptions).toEqual({code: 'A', desc: 'Active'}, {code:'I', desc: 'Inactive'});
  });
  alert('Controller:  AdminQuestionsCtrl; should have the correct initializations = PASS (3 expects)');
});
*/

redpajama_set_name: RedPajamaGithub


text:
'use strict';

var templates = {
};

var controllers = {
  'sample/sample': require('../test/lib/fixture/controllers_5/sample/sample.js')
};

var routes = [
];

module.exports = {
  templates: templates,
  controllers: controllers,
  routes: routes
};


text:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
  <!-- The 'demoBean' below is only used as an example on how to use the debug toolbar from Java.
  It is not required to use the Debug Toolbar -->
  <managed-bean id="demoBean">
    <managed-bean-name>demoBean</managed-bean-name>
    <managed-bean-class>eu.linqed.debugtoolbar.DemoClass</managed-bean-class>
    <managed-bean-scope>view</managed-bean-scope>
  </managed-bean>
  <!--AUTOGEN-START-BUILDER: Automatically generated by IBM Domino Designer. Do not modify.-->
  <!--AUTOGEN-END-BUILDER: End of automatically generated section-->
</faces-config>


text:
package edu.hm.hafner.analysis.parser;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream;
import org.xml.sax.SAXException;

import edu.hm.hafner.analysis.AbstractParser;
import edu.hm.hafner.analysis.Issue;
import edu.hm.hafner.analysis.IssueBuilder;
import edu.hm.hafner.analysis.Issues;
import edu.hm.hafner.analysis.ParsingCanceledException;
import edu.hm.hafner.analysis.ParsingException;

/**
 * Base class for parsers based on {@link JSLintXMLSaxParser}.
 *
 * @author Ullrich Hafner
 */
public abstract class LintParser extends AbstractParser {
    private static final long serialVersionUID = 3341424685245834156L;

    /**
     * Creates a new instance of {@link LintParser}.
     *
     * @param id ID of the parser
     */
    protected LintParser(final String id) {
        super();
    }

    @Override
    public Issues<Issue> parse(final Reader file, final IssueBuilder builder) throws ParsingException, ParsingCanceledException {
        try {
            SAXParserFactory parserFactory = SAXParserFactory.newInstance();

            SAXParser parser = parserFactory.newSAXParser();

            Issues<Issue> issues = new Issues<>();
            parser.parse(new ReaderInputStream(file, Charset
                    .forName("UTF-8")), new JSLintXMLSaxParser(issues));
            return issues;
        }
        catch (IOException | ParserConfigurationException | SAXException e) {
            throw new ParsingException(e);
        }
        finally {
            IOUtils.closeQuietly(file);
        }
    }
}


text:
using UnityEngine;
using System.Collections;

public class MoveEnemy : MonoBehaviour {

	[HideInInspector]
	public GameObject[] waypoints;
	private int currentWaypoint = 0;
	private float lastWaypointSwitchTime;
	public float speed = 1.0f;

	//tällä vihulainen osaa katsoa menosuuntaansa
	private void RotateIntoMoveDirection() {
		Vector3 newStartPosition = waypoints [currentWaypoint].transform.position;
		Vector3 newEndPosition = waypoints [currentWaypoint + 1].transform.position;
		Vector3 newDirection = (newEndPosition - newStartPosition);
		float x = newDirection.x;
		float y = newDirection.y;
		float rotationAngle = Mathf.Atan2 (y, x) * 180 / Mathf.PI;
		GameObject sprite = (GameObject)
			gameObject.transform.FindChild("Sprite").gameObject;
		sprite.transform.rotation =
			Quaternion.AngleAxis(rotationAngle, Vector3.forward);
	}

	//vihulaisen etaisyys maaliin
	public float distanceToGoal() {
		float distance = 0;
		distance += Vector3.Distance(
			gameObject.transform.position,
			waypoints [currentWaypoint + 1].transform.position);
		for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++) {
			Vector3 startPosition = waypoints [i].transform.position;
			Vector3 endPosition = waypoints [i + 1].transform.position;
			distance += Vector3.Distance(startPosition, endPosition);
		}
		return distance;
	}

	// Use this for initialization
	void Start () {

		lastWaypointSwitchTime = Time.time;

	}

	// Update is called once per frame
	void Update () {

		Vector3 startPosition = waypoints [currentWaypoint].transform.position;
		Vector3 endPosition = waypoints [currentWaypoint + 1].transform.position;

		float pathLength = Vector3.Distance (startPosition, endPosition);
		float totalTimeForPath = pathLength / speed;
		float currentTimeOnPath = Time.time - lastWaypointSwitchTime;
		gameObject.transform.position = Vector3.Lerp (startPosition, endPosition, currentTimeOnPath / totalTimeForPath);

		if (gameObject.transform.position.Equals(endPosition)) {
			if (currentWaypoint < waypoints.Length - 2) {

				currentWaypoint++;
				lastWaypointSwitchTime = Time.time;
				RotateIntoMoveDirection();
			} else {

				Destroy(gameObject);

				AudioSource audioSource = gameObject.GetComponent<AudioSource>();
				AudioSource.PlayClipAtPoint(audioSource.clip, transform.position);
				GameManagerBehavior gameManager =
					GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
				gameManager.Health -= 1;
			}
		}

	}
}


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<title>EventTarget (Java Platform SE 7 )</title>
<meta name="date" content="2014-12-18">
<meta name="keywords" content="org.w3c.dom.events.EventTarget interface">
<meta name="keywords" content="addEventListener()">
<meta name="keywords" content="removeEventListener()">
<meta name="keywords" content="dispatchEvent()">
<link rel="stylesheet" type="text/css" href="../../../../stylesheet.css" title="Style">

JavaScript is disabled on your browser.

Overview

Package

Class

Use

Tree

Deprecated

Index

Help

Java™ Platform
Standard Ed. 7

Prev Class

Next Class

Frames

No Frames

All Classes

Summary:

Nested |

Field |

Constr |

Method

Detail:

Field |

Constr |

Method

org.w3c.dom.events

Interface EventTarget

public interface EventTarget

The EventTarget interface is implemented by all
 Nodes in an implementation which supports the DOM Event
 Model. Therefore, this interface can be obtained by using
 binding-specific casting methods on an instance of the Node
 interface. The interface allows registration and removal of
 EventListeners on an EventTarget and dispatch
 of events to that EventTarget.

See also the Document Object Model (DOM) Level 2 Events Specification.

Since:

DOM Level 2

Method Summary

Methods

Modifier and Type
Method and Description

void
addEventListener(String type,
                EventListener listener,
                boolean useCapture)

This method allows the registration of event listeners on the event
 target.

boolean
dispatchEvent(Event evt)

This method allows the dispatch of events into the implementations
 event model.

void
removeEventListener(String type,
                   EventListener listener,
                   boolean useCapture)

This method allows the removal of event listeners from the event
 target.

Method Detail

addEventListener

void addEventListener(String type,
                    EventListener listener,
                    boolean useCapture)

This method allows the registration of event listeners on the event
 target. If an EventListener is added to an
 EventTarget while it is processing an event, it will not
 be triggered by the current actions but may be triggered during a
 later stage of event flow, such as the bubbling phase.

 If multiple identical EventListeners are registered
 on the same EventTarget with the same parameters the
 duplicate instances are discarded. They do not cause the
 EventListener to be called twice and since they are
 discarded they do not need to be removed with the
 removeEventListener method.

Parameters:

type - The event type for which the user is registering

listener - The listener parameter takes an interface
   implemented by the user which contains the methods to be called
   when the event occurs.

useCapture - If true, useCapture indicates that the
   user wishes to initiate capture. After initiating capture, all
   events of the specified type will be dispatched to the registered
   EventListener before being dispatched to any
   EventTargets beneath them in the tree. Events which
   are bubbling upward through the tree will not trigger an
   EventListener designated to use capture.

removeEventListener

void removeEventListener(String type,
                       EventListener listener,
                       boolean useCapture)

This method allows the removal of event listeners from the event
 target. If an EventListener is removed from an
 EventTarget while it is processing an event, it will not
 be triggered by the current actions. EventListeners can
 never be invoked after being removed.

Calling removeEventListener with arguments which do
 not identify any currently registered EventListener on
 the EventTarget has no effect.

Parameters:

type - Specifies the event type of the EventListener
   being removed.

listener - The EventListener parameter indicates the
   EventListener  to be removed.

useCapture - Specifies whether the EventListener
   being removed was registered as a capturing listener or not. If a
   listener was registered twice, one with capture and one without,
   each must be removed separately. Removal of a capturing listener
   does not affect a non-capturing version of the same listener, and
   vice versa.

dispatchEvent

boolean dispatchEvent(Event evt)
                      throws EventException

This method allows the dispatch of events into the implementations
 event model. Events dispatched in this manner will have the same
 capturing and bubbling behavior as events dispatched directly by the
 implementation. The target of the event is the
  EventTarget on which dispatchEvent is
 called.

Parameters:

evt - Specifies the event type, behavior, and contextual
   information to be used in processing the event.

Returns:

The return value of dispatchEvent indicates
   whether any of the listeners which handled the event called
   preventDefault. If preventDefault was
   called the value is false, else the value is true.

Throws:

EventException - UNSPECIFIED_EVENT_TYPE_ERR: Raised if the Event's type
   was not specified by initializing the event before
   dispatchEvent was called. Specification of the
   Event's type as null or an empty string
   will also trigger this exception.

Overview

Package

Class

Use

Tree

Deprecated

Index

Help

Java™ Platform
Standard Ed. 7

Prev Class

Next Class

Frames

No Frames

All Classes

Summary:

Nested |

Field |

Constr |

Method

Detail:

Field |

Constr |

Method

 Submit a bug or feature
For further API reference and developer documentation, see Java SE Documentation. That documentation contains more detailed, developer-targeted descriptions, with conceptual overviews, definitions of terms, workarounds, and working code examples.
 Copyright © 1993, 2015, Oracle and/or its affiliates.  All rights reserved.


text:
package com.hazelcast.spi.partitiongroup;

import com.hazelcast.test.HazelcastParallelClassRunner;
import com.hazelcast.test.HazelcastTestSupport;
import com.hazelcast.test.annotation.ParallelJVMTest;
import com.hazelcast.test.annotation.QuickTest;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;

@RunWith(HazelcastParallelClassRunner.class)
@Category({QuickTest.class, ParallelJVMTest.class})
public class PartitionGroupMetaDataTest extends HazelcastTestSupport {

    @Test
    public void testEnum() {
        assertEnumCoverage(PartitionGroupMetaData.class);
    }
}


text:
layout: tag
title: binary-tree
permalink: /tags/binary-tree/
---


text:
namespace Flourish::Debug
{
	namespace
	{
		bool ignoreAllAsserts = false;
		AssertHandler currentAssertHandler = nullptr;
	}

	void SetAssertHandler(AssertHandler handler)
	{
		currentAssertHandler = handler;
	}

	AssertHandler GetAssertHandler()
	{
		return currentAssertHandler;
	}

	void SetIgnoreAllAsserts(bool value)
	{
		ignoreAllAsserts = value;
	}

	bool ShouldIgnoreAllAsserts()
	{
		return ignoreAllAsserts;
	}

	namespace Internal
	{
		AssertResult DefaultAssertHandler(
			SourceInfo sourceInfo,
			const char* condition,
			const char* message,
			const char* callstack)
		{
			DebugPrintf(
				"\n"
				"------------------------------\n"
				"       ASSERT TRIGGERED       \n"
				"------------------------------\n\n");

			if (message != nullptr && strlen(message) > 0)
			{
				DebugPrintf("Message:      \"%s\"\n\n", message);
			}

			DebugPrintf("File(Line):   %s(%d)\n", sourceInfo.FileName, sourceInfo.Line);
			DebugPrintf("Function:     %s\n\n", sourceInfo.FunctionName);

			DebugPrintf("Failed Cond:  \"%s\"\n", condition);

			if (callstack != nullptr && strlen(callstack) > 0)
			{
				DebugPrintf("\nStack Trace:\n%s", callstack);
			}

			DebugPrintf("\n");

			return AssertResult::Break;
		}

		bool HandleAssert(
			bool& ignoreLine,
			SourceInfo sourceInfo,
			const char* condition,
			const char* message,
			...)
		{
			const size_t bufferSize = 1024;
			char messageBuffer[bufferSize];

			if(message != nullptr)
			{
				va_list args;
				va_start(args, message);
				vsnprintf(messageBuffer, bufferSize, message, args);
				va_end(args);
			}

#if FL_ENABLED(FL_STACK_TRACE_ENABLED)
			const size_t callstackBufferSize = 2048;
			char callstackBuffer[callstackBufferSize];

			//Skip the stack frame of this function so we get a call stack from the assert
			GetStackTrace(2, callstackBuffer, callstackBufferSize);
#else
			char* callstackBuffer = null;
#endif

			AssertHandler handler = (currentAssertHandler == nullptr ? DefaultAssertHandler : currentAssertHandler);

			auto assertResponce = handler(sourceInfo, condition, messageBuffer, callstackBuffer);

			bool shouldBreak = false;

			switch(assertResponce)
			{
			case AssertResult::IgnoreAlways:
				ignoreLine = true;
				break;

			case AssertResult::IgnoreAll:
				SetIgnoreAllAsserts(true);
				break;

			case AssertResult::Break:
				shouldBreak = true;
				break;

			case AssertResult::Abort:
				abort();

			case AssertResult::Ignore:
			default:
				//Do Nothing
				break;

			}

			return shouldBreak;
		}
	}
}


text:
/*
 * Problem 5: Define a class BitArray64 to hold 64 bit values inside an ulong value.
    Implement IEnumerable<int> and Equals(…), GetHashCode(), [], == and !=.
 */

namespace _05._64BitArray
{
    using System;

    public class ArrayTesting
    {
        public static void Main()
        {
            var longNum = new BitArray64();

            longNum[20] = 1;
            longNum[4] = 1;
            longNum[31] = 1;
            longNum[55] = 1;

            Console.WriteLine(longNum);
        }
    }
}


text:
<!DOCTYPE html>
<html lang="en" ng-app="mailTemplate">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>Email manager</title>
    <link rel="stylesheet" href="app/css/main.css">
    <link rel="stylesheet" href="app/css/styles/Bootstrap/css/bootstrap.css">
    <link rel="stylesheet" href="app/css/styles/sweetalert.css">
    <link rel="stylesheet" href="app/css/styles/angular-gridster.min.css">
    <link rel="stylesheet" property="stylesheet" href="app/css/styles/font-awesome/css/font-awesome.css">
  </head>
  <body style="padding-right:  0px">
    <main id="app" ui-view="" class="wrapper container-fluid"></main>
    <script src="app/js/base.js"></script>
    <script src="app/js/app.js"></script>
  </body>
</html>


text:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent" android:layout_height="wrap_content"
    android:layout_margin="5dp"
    android:layout_marginBottom="7dp">

    <ImageView
        android:id="@+id/ivProfileImage"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        app:srcCompat="@android:color/black" />
    <LinearLayout
        android:id="@+id/llButtonRow"
        android:layout_width="wrap_content"
        android:orientation="horizontal"
        android:layout_height="wrap_content"
        android:weightSum="1"
        android:layout_marginTop="5dp"
        android:layout_below="@+id/ivMediaImage"
        android:layout_alignParentEnd="true">

        <ImageButton
            android:id="@+id/ibReply"
            android:backgroundTint="@android:color/transparent"
            android:src="@drawable/noun_74450_cc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_toEndOf="@+id/tvReplyCount"
            android:layout_marginStart="22dp" />

        <TextView
            android:id="@+id/tvReplyCount"
            android:layout_alignParentRight="@+id/ibReply"
            android:layout_alignParentBottom = "@+id/ibReply"
            android:text="0"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <ImageButton
            android:id="@+id/ibRetweet"
            android:backgroundTint="@android:color/transparent"
            android:src="@drawable/ic_vector_retweet_stroke"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignEnd="@+id/tvHandle" />

        <TextView
            android:id="@+id/tvRetweetCount"
            android:layout_alignParentBottom = "@+id/ibRetweet"
            android:layout_alignParentRight="@+id/ibRetweet"
            android:text="0"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <ImageButton
            android:id="@+id/ibLike"
            android:backgroundTint="@android:color/transparent"
            android:src="@drawable/ic_vector_heart_stroke"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_toStartOf="@+id/ibDM" />

        <TextView
            android:id="@+id/tvLikeCount"
            android:layout_alignParentRight="@+id/ibLike"
            android:layout_alignParentBottom = "@+id/ibLike"
            android:text="0"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <ImageButton
            android:id="@+id/ibDM"
            android:backgroundTint="@android:color/transparent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignStart="@+id/tvTimeStamp"
            android:src="@drawable/ic_vector_messages_stroke" />

    </LinearLayout>

    <TextView
        android:id="@+id/tvUserName"
        android:textColor="@color/colorBlack"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:layout_alignParentTop="true"
        android:layout_alignStart="@+id/tvBody" />

    <TextView
        android:id="@+id/tvBody"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:layout_alignBottom="@+id/ivProfileImage"
        android:layout_below="@+id/tvUserName"
        android:layout_toEndOf="@+id/ivProfileImage"
        android:text="TextView" />

    <ImageView
        android:id="@+id/ivMediaImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="@+id/tvBody"
        android:layout_marginLeft="55dp"
        android:layout_marginTop="10dp"
        android:layout_below="@+id/tvBody"
        android:adjustViewBounds="true"/>

    <TextView
        android:id="@+id/tvTimeStamp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:layout_alignParentTop="true"
        android:layout_toEndOf="@+id/tvHandle" />

    <TextView
        android:id="@+id/tvHandle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toEndOf="@+id/tvUserName"
        android:text="TextView" />

    <View
        android:id="@+id/vDivider"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_below="@+id/llButtonRow"
        android:background="@android:color/darker_gray"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"/>
</RelativeLayout>


text:
<?php

namespace Bolt\Extension\BoltAuth\Auth\Storage\Entity;

use Bolt\Storage\Entity\Entity;

class Auth extends Entity
{
    /** @var string */
    protected $guid;
    /** @var string */
    protected $email;
    /** @var \DateTime */
    protected $lastseen;
    /** @var string */
    protected $lastip;
    /** @var string */
    protected $displayname;
    /** @var boolean */
    protected $enabled;
    /** @var boolean */
    protected $verified;
    /** @var array */
    protected $roles;
    /** @var array */
    protected $metaFields = [];

    /**
     * Constructor.
     *
     * @param Account             $account
     * @param AccountMeta[]|false $accountMetas
     */
    public function __construct(Account $account, $accountMetas)
    {
        parent::__construct($account);
        if ($accountMetas === false) {
            return;
        }

        /** @var AccountMeta $accountMeta */
        foreach ($accountMetas as $accountMeta) {
            $meta = $accountMeta->getMeta();
            $value = $accountMeta->getValue();
            $method = 'set' . ucfirst($meta);
            $this->$method($value);

            $this->metaFields[] = $meta;
        }
    }

    /**
     * @return string
     */
    public function getGuid()
    {
        return $this->guid;
    }

    /**
     * @return string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @return \DateTime
     */
    public function getLastseen()
    {
        return $this->lastseen;
    }

    /**
     * @return string
     */
    public function getLastip()
    {
        return $this->lastip;
    }

    /**
     * @return string
     */
    public function getDisplayname()
    {
        return $this->displayname;
    }

    /**
     * @return boolean
     */
    public function isEnabled()
    {
        return $this->enabled;
    }

    /**
     * @return boolean
     */
    public function isVerified()
    {
        return $this->verified;
    }

    /**
     * @return array
     */
    public function getRoles()
    {
        return $this->roles;
    }

    /**
     * @return array
     */
    public function getMetaFields()
    {
        return $this->metaFields;
    }
}


text: AngularPluralsightTutorial


text:
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

type APIDescription struct {
	Doc       string        `json:"doc"`
	Hash      string        `json:"hash"`
	Resources []APIResource `json:"resources"`
}

type APIResource struct {
	Anon *APIHandler `json:"anon,omitempty"`
	Name string      `json:"name"`
	Auth *APIHandler `json:"auth,omitempty"`
}

type apiResourcesByPath []APIResource

func (a apiResourcesByPath) Len() int      { return len(a) }
func (a apiResourcesByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a apiResourcesByPath) Less(i, j int) bool {
	anon1, anon2 := a[i].Anon, a[j].Anon
	hasAnon := anon1 != nil && anon2 != nil
	auth1, auth2 := a[i].Auth, a[j].Auth
	hasAuth := auth1 != nil && auth2 != nil

	switch {
	case hasAnon && !hasAuth:
		return anon1.Path < anon2.Path

	case !hasAnon && hasAuth:
		return auth1.Path < auth2.Path

	case hasAnon && hasAuth:
		return anon1.Path < anon2.Path && auth1.Path < auth2.Path
	}
	return false
}

type APIHandler struct {
	Name    string      `json:"name"`
	Doc     string      `json:"doc"`
	URI     string      `json:"uri"`
	Actions []APIAction `json:"actions"`
	Params  []string    `json:"params"`
	Path    string      `json:"path"`
}

type ActionParam struct {
	Name       string
	Doc        string
	PythonType string
	GoType     reflect.Type
}

func deriveGoTypeFromPythonType(pythonType string) reflect.Type {
	type unknown struct{}
	type object struct{}

	pt := strings.ToLower(pythonType)
	switch {
	case strings.Contains(pt, "ip address"):
		return reflect.TypeOf(net.IP{})
	case strings.HasPrefix(pt, "unicode"), strings.HasPrefix(pt, "string"):
		return reflect.TypeOf("string")
	case strings.HasPrefix(pt, "list of unicode"), strings.HasPrefix(pt, "iterable"):
		return reflect.SliceOf(reflect.TypeOf("string"))
	case strings.Contains(pt, "unicode"): // e.g. base64-encoded unicode
		return reflect.TypeOf("string")
	case strings.HasPrefix(pt, "bool"):
		return reflect.TypeOf(false)
	case strings.HasPrefix(pt, "int"):
		return reflect.TypeOf(int(0))
	case strings.HasPrefix(pt, "float"):
		return reflect.TypeOf(0.5)
	case strings.Contains(pt, "object"):
		return reflect.TypeOf(object{})
	}
	return reflect.TypeOf(unknown{})
}

type APIAction struct {
	RawDoc string `json:"doc"`
	// Doc contains the parsed first line of RawDoc.
	Doc string `json:"-"`
	// DocParams contains the parsed param name to description.
	DocParams map[string]ActionParam `json:"-"`
	// DocReturns contains the parsed HTTP status code to description(s).
	DocReturns map[int][]string `json:"-"`

	Op      *string `json:"op,omitempty"`
	Restful bool    `json:"restful"`
	Method  string  `json:"method"`
	Name    string  `json:"name"`
}

var (
	rawDocParams            = regexp.MustCompile(`(?::param )(?P<param>[^: ]+)(?:: )(?P<doc>(\n|.)+.?)`)
	rawDocParamType         = regexp.MustCompile(`(?::type )(?P<param>[^:]+)(?:: )(?P<type>(\n|.)+)$`)
	rawDocReturns           = regexp.MustCompile(`(?P<first>[Rr])(?:eturns )(?P<code>\d{3})(?: )(?P<doc>(\n|[^\.])+\.)`)
	rawDocExtraSpaces       = regexp.MustCompile(` {2,}`)
	rawDocParamsExtraSpaces = regexp.MustCompile(`( {2,}|\n |\n)`)
)

func (a APIAction) parseRawDoc() (
	doc string,
	docParams map[string]ActionParam,
	docReturns map[int][]string,
	err error,
) {
	// Separate pure doc lines from params and returns.
	rawDoc := a.RawDoc
	rawDocParts := strings.Split(rawDoc, "\n\n")
	rawDoc = ""
	var rawParamsAndReturns string
	for _, part := range rawDocParts {
		if rawDocParams.MatchString(part) || rawDocReturns.MatchString(part) {
			rawParamsAndReturns += part + "\n\n"
			continue
		}
		rawDoc += part + "\n\n"
	}

	// Strip extra whitespace.
	rawDoc = rawDocExtraSpaces.ReplaceAllString(rawDoc, " ")
	rawDoc = strings.TrimSpace(rawDoc)
	rawParamsAndReturns = rawDocParamsExtraSpaces.ReplaceAllString(rawParamsAndReturns, " ")
	rawParamsAndReturns = strings.Replace(rawParamsAndReturns, "  ", " ", -1)

	// Parse and extract all parsable returns.
	lastParamsAndReturns := ""
	for rawDocReturns.MatchString(rawParamsAndReturns) && lastParamsAndReturns != rawParamsAndReturns {
		matches := rawDocReturns.FindStringSubmatch(rawParamsAndReturns)
		if docReturns == nil {
			docReturns = make(map[int][]string)
		}
		firstLetter, code, doc := matches[1], matches[2], matches[3]
		httpCode, err := strconv.Atoi(code)
		if err != nil {
			return "", nil, nil, fmt.Errorf("unexpected HTTP code %q: %v", code, err)
		}
		if existing, ok := docReturns[httpCode]; ok {
			docReturns[httpCode] = append(existing, doc)
		} else {
			docReturns[httpCode] = append([]string(nil), doc)
		}

		rawReturn := fmt.Sprintf("%seturns %d %s", firstLetter, httpCode, doc)
		lastParamsAndReturns = rawParamsAndReturns
		rawParamsAndReturns = strings.Replace(rawParamsAndReturns, rawReturn, "", -1)
	}

	// Unshift all parsable params and their docs into docParams.
	lastParamsAndReturns = ""
	for rawDocParams.MatchString(rawParamsAndReturns) && lastParamsAndReturns != rawParamsAndReturns {
		matches := rawDocParams.FindStringSubmatch(rawParamsAndReturns)
		if docParams == nil {
			docParams = make(map[string]ActionParam)
		}
		param, doc := matches[1], matches[2]
		nextParamIndex := strings.Index(doc, " :param ")
		if nextParamIndex != -1 {
			doc = doc[:nextParamIndex]
		}
		doc = strings.TrimSpace(doc)
		paramName := param
		pythonType := "<unspecified>"
		docWithoutType := doc
		if rawDocParamType.MatchString(doc) {
			matches = rawDocParamType.FindStringSubmatch(doc)
			paramName, pythonType = matches[1], matches[2]
			rawType := fmt.Sprintf(":type %s: %s", paramName, pythonType)
			docWithoutType = strings.Replace(doc, rawType, "", -1)
			docWithoutType = strings.TrimSpace(docWithoutType)
		}
		pythonType = strings.TrimSpace(pythonType)

		docParams[param] = ActionParam{
			Name:       param,
			Doc:        docWithoutType,
			PythonType: pythonType,
			GoType:     deriveGoTypeFromPythonType(pythonType),
		}
		rawParam := fmt.Sprintf(":param %s: %s", param, doc)
		lastParamsAndReturns = rawParamsAndReturns
		rawParamsAndReturns = strings.Replace(rawParamsAndReturns, rawParam, "", -1)
	}

	return rawDoc, docParams, docReturns, nil
}

// GetAPIDescription takes a MAAS API URL prefix (e.g.
// "http://10.10.19.2/MAAS/") and returns the parsed APIDescription and the
// indented raw JSON, or an error.
func GetAPIDescription(apiPrefix string) (*APIDescription, string, error) {
	urlPrefix, err := url.Parse(apiPrefix)
	if err != nil {
		return nil, "", fmt.Errorf("cannot parse URL prefix %q: %v", apiPrefix, err)
	}

	fullURL, err := urlPrefix.Parse("api/1.0/describe/")
	if err != nil {
		return nil, "", fmt.Errorf("cannot parse full URL %q: %v", urlPrefix.String()+"describe/", err)
	}

	response, err := http.Get(fullURL.String())
	if err != nil {
		return nil, "", fmt.Errorf("cannot get API description at %q: %v", fullURL.String(), err)
	}

	defer response.Body.Close()
	bodyData, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, "", fmt.Errorf("cannot read response body: %v", err)
	}

	var apiDescription APIDescription
	if err := json.Unmarshal(bodyData, &apiDescription); err != nil {
		return nil, "", fmt.Errorf("cannot unmarshal response JSON: %v", err)
	}
	var rawJSON map[string]interface{}
	if err := json.Unmarshal(bodyData, &rawJSON); err != nil {
		return nil, "", fmt.Errorf("cannot unmarshal response raw JSON: %v", err)
	}

	for _, resource := range apiDescription.Resources {
		for _, handler := range []*APIHandler{resource.Anon, resource.Auth} {
			if handler != nil {
				for i, action := range handler.Actions {
					doc, docParams, docReturns, err := action.parseRawDoc()
					if err != nil {
						return nil, "", fmt.Errorf("cannot parse action %q doc: %v", action.Name, err)
					}
					handler.Actions[i].Doc = doc
					handler.Actions[i].DocParams = docParams
					handler.Actions[i].DocReturns = docReturns
				}
			}
		}
	}

	rawIndentedJSON, err := json.MarshalIndent(rawJSON, "", "  ")
	if err != nil {
		return nil, "", fmt.Errorf("cannot marshal raw indented JSON: %v", err)
	}
	return &apiDescription, string(rawIndentedJSON), nil
}

func (a *APIDescription) Format() string {
	var output string

	output += fmt.Sprintf("Doc: %q\n", a.Doc)
	output += fmt.Sprintf("Hash: %q\n", a.Hash)
	output += fmt.Sprintf("Resources:\n")
	resourcesByPath := a.Resources
	sort.Sort(apiResourcesByPath(resourcesByPath))
	for _, resource := range resourcesByPath {
		output += resource.Format()
	}

	return output
}

func (a APIResource) Format() string {
	var output string

	output += fmt.Sprintf("  %q:\n", a.Name)
	output += a.Anon.Format("    ", " (Anon)")
	output += a.Auth.Format("    ", " (Auth)")

	return output
}

func (a *APIHandler) Format(prefix, suffix string) string {
	if a == nil {
		return ""
	}

	var output string
	output += fmt.Sprintf("%s%q%s:\n", prefix, a.Name, suffix)
	output += fmt.Sprintf("%s  Doc: %q\n", prefix, a.Doc)
	output += fmt.Sprintf("%s  URI: %q\n", prefix, a.URI)
	output += fmt.Sprintf("%s  Actions:\n", prefix)

	for _, action := range a.Actions {
		output += fmt.Sprintf("%s    Name: %q\n", prefix, action.Name)
		output += fmt.Sprintf("%s    Doc: %q\n", prefix, action.Doc)
		if len(action.DocParams) == 0 {
			output += fmt.Sprintf("%s    DocParams: N/A\n", prefix)
		} else {
			output += fmt.Sprintf("%s    DocParams:\n", prefix)
			for paramName, param := range action.DocParams {
				output += fmt.Sprintf("%s      %q:\n", prefix, paramName)
				output += fmt.Sprintf("%s        Doc: %q\n", prefix, param.Doc)
				output += fmt.Sprintf("%s        PythonType: %v\n", prefix, param.PythonType)
				output += fmt.Sprintf("%s        GoType: %v\n", prefix, param.GoType)
			}
		}

		if len(action.DocReturns) == 0 {
			output += fmt.Sprintf("%s    DocReturns: N/A\n", prefix)
		} else {
			output += fmt.Sprintf("%s    DocReturns:\n", prefix)
			for code, codeDocs := range action.DocReturns {
				if len(codeDocs) == 1 {
					output += fmt.Sprintf("%s      %d: %s\n", prefix, code, codeDocs[0])
				} else {
					output += fmt.Sprintf("%s      %d:\n", prefix, code)
					for _, codeDoc := range codeDocs {
						output += fmt.Sprintf("%s      %s\n", prefix, codeDoc)
					}
				}
			}
		}

		if action.Op != nil {
			output += fmt.Sprintf("%s    Op: %q\n", prefix, *action.Op)
		} else {
			output += fmt.Sprintf("%s    Op: N/A\n", prefix)
		}

		output += fmt.Sprintf("%s    Restful: %v\n", prefix, action.Restful)
		output += fmt.Sprintf("%s    Method: %q\n", prefix, action.Method)
		output += fmt.Sprintf("%s  \n", prefix)
	}

	if len(a.Params) > 0 {
		paramsList := `"` + strings.Join(a.Params, `", "`) + `"`
		output += fmt.Sprintf("%s  Params: %s\n", prefix, paramsList)
	} else {
		output += fmt.Sprintf("%s  Params: N/A\n", prefix)
	}
	output += fmt.Sprintf("%s  Path: %q\n\n", prefix, a.Path)

	return output
}


text:
@interface FTEAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end


text:
package org.apache.phoenix.jdbc;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;

import org.apache.phoenix.compile.BindManager;
import org.apache.phoenix.compile.MutationPlan;
import org.apache.phoenix.compile.QueryPlan;
import org.apache.phoenix.compile.StatementPlan;
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.exception.SQLExceptionInfo;
import org.apache.phoenix.schema.ExecuteQueryNotApplicableException;
import org.apache.phoenix.schema.ExecuteUpdateNotApplicableException;
import org.apache.phoenix.schema.Sequence;
import org.apache.phoenix.schema.types.PDataType;
import org.apache.phoenix.util.SQLCloseable;

/**
 * JDBC PreparedStatement implementation of Phoenix. Currently only the following methods (in addition to the ones
 * supported on {@link PhoenixStatement} are supported: - {@link #executeQuery()} - {@link #setInt(int, int)} -
 * {@link #setShort(int, short)} - {@link #setLong(int, long)} - {@link #setFloat(int, float)} -
 * {@link #setDouble(int, double)} - {@link #setBigDecimal(int, BigDecimal)} - {@link #setString(int, String)} -
 * {@link #setDate(int, Date)} - {@link #setDate(int, Date, Calendar)} - {@link #setTime(int, Time)} -
 * {@link #setTime(int, Time, Calendar)} - {@link #setTimestamp(int, Timestamp)} -
 * {@link #setTimestamp(int, Timestamp, Calendar)} - {@link #setNull(int, int)} - {@link #setNull(int, int, String)} -
 * {@link #setBytes(int, byte[])} - {@link #clearParameters()} - {@link #getMetaData()}
 *
 *
 * @since 0.1
 */
public class PhoenixPreparedStatement extends PhoenixStatement implements PreparedStatement, SQLCloseable {
    private final int parameterCount;
    private final List<Object> parameters;
    private final CompilableStatement statement;

    private final String query;

    public PhoenixPreparedStatement(PhoenixConnection connection, PhoenixStatementParser parser) throws SQLException, IOException {
        super(connection);
        this.statement = parser.nextStatement(new ExecutableNodeFactory());
        if (this.statement == null) { throw new EOFException(); }
        this.query = null; // TODO: add toString on SQLStatement
        this.parameterCount = statement.getBindCount();
        this.parameters = Arrays.asList(new Object[statement.getBindCount()]);
        Collections.fill(parameters, BindManager.UNBOUND_PARAMETER);
    }

    public PhoenixPreparedStatement(PhoenixConnection connection, String query) throws SQLException {
        super(connection);
        this.query = query;
        this.statement = parseStatement(query);
        this.parameterCount = statement.getBindCount();
        this.parameters = Arrays.asList(new Object[statement.getBindCount()]);
        Collections.fill(parameters, BindManager.UNBOUND_PARAMETER);
    }

    public PhoenixPreparedStatement(PhoenixPreparedStatement statement) {
        super(statement.connection);
        this.query = statement.query;
        this.statement = statement.statement;
        this.parameterCount = statement.parameters.size();
        this.parameters = new ArrayList<Object>(statement.parameters);
    }

    @Override
    public void addBatch() throws SQLException {
        throwIfUnboundParameters();
        batch.add(new PhoenixPreparedStatement(this));
    }

    /**
     * Set a bind parameter's value.
     * @param parameterIndex 1-based index of the bind parameter to be set
     * @param value value to be set
     * @throws SQLException if the bind parameter index is invalid
     */
    private void setParameter(int parameterIndex, Object value) throws SQLException {
        if (parameterIndex < 1 || parameterIndex > parameterCount) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.PARAM_INDEX_OUT_OF_BOUND)
                    .setMessage("Can't set parameter at index " + parameterIndex + ", " +
                             parameterCount + " bind parameters are defined")
                    .build().buildException();
        }
        this.parameters.set(parameterIndex - 1, value);
    }

    @Override
    public void clearParameters() throws SQLException {
        Collections.fill(parameters, BindManager.UNBOUND_PARAMETER);
    }

    @Override
    public List<Object> getParameters() {
        return parameters;
    }

    private void throwIfUnboundParameters() throws SQLException {
        int i = 0;
        for (Object param : getParameters()) {
            if (param == BindManager.UNBOUND_PARAMETER) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.PARAM_VALUE_UNBOUND)
                    .setMessage("Parameter " + (i + 1) + " is unbound").build().buildException();
            }
            i++;
        }
    }

    public QueryPlan compileQuery() throws SQLException {
        return compileQuery(statement, query);
    }

    public MutationPlan compileMutation() throws SQLException {
        return compileMutation(statement, query);
    }

    boolean execute(boolean batched) throws SQLException {
        throwIfUnboundParameters();
        if (!batched && statement.getOperation().isMutation() && !batch.isEmpty()) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.EXECUTE_UPDATE_WITH_NON_EMPTY_BATCH)
            .build().buildException();
        }
        if (statement.getOperation().isMutation()) {
            executeMutation(statement, createAuditQueryLogger(statement,query));
            return false;
        }
        executeQuery(statement, createQueryLogger(statement,query));
        return true;

    }

    @Override
    public boolean execute() throws SQLException {
        return execute(false);
    }

    @Override
    public ResultSet executeQuery() throws SQLException {
        throwIfUnboundParameters();
        if (statement.getOperation().isMutation()) {
            throw new ExecuteQueryNotApplicableException(statement.getOperation());
        }

        return executeQuery(statement,createQueryLogger(statement,query));
    }

    @Override
    public int executeUpdate() throws SQLException {
        throwIfUnboundParameters();
        if (!statement.getOperation().isMutation()) {
            throw new ExecuteUpdateNotApplicableException(statement.getOperation());
        }
        if (!batch.isEmpty()) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.EXECUTE_UPDATE_WITH_NON_EMPTY_BATCH)
            .build().buildException();
        }
        return executeMutation(statement, createAuditQueryLogger(statement,query));
    }

    public QueryPlan optimizeQuery() throws SQLException {
        throwIfUnboundParameters();
        return optimizeQuery(statement);
    }

    @Override
    public ResultSetMetaData getMetaData() throws SQLException {
        if (statement.getOperation().isMutation()) {
            return null;
        }
        int paramCount = statement.getBindCount();
        List<Object> params = this.getParameters();
        BitSet unsetParams = new BitSet(statement.getBindCount());
        for (int i = 0; i < paramCount; i++) {
            if ( params.get(i) == BindManager.UNBOUND_PARAMETER) {
                unsetParams.set(i);
                params.set(i, null);
            }
        }
        try {
            // Just compile top level query without optimizing to get ResultSetMetaData
            QueryPlan plan = statement.compilePlan(this, Sequence.ValueOp.NOOP);
            return new PhoenixResultSetMetaData(this.getConnection(), plan.getProjector());
        } finally {
            int lastSetBit = 0;
            while ((lastSetBit = unsetParams.nextSetBit(lastSetBit)) != -1) {
                params.set(lastSetBit, BindManager.UNBOUND_PARAMETER);
                lastSetBit++;
            }
        }
    }

    @Override
    public ParameterMetaData getParameterMetaData() throws SQLException {
        int paramCount = statement.getBindCount();
        List<Object> params = this.getParameters();
        BitSet unsetParams = new BitSet(statement.getBindCount());
        for (int i = 0; i < paramCount; i++) {
            if ( params.get(i) == BindManager.UNBOUND_PARAMETER) {
                unsetParams.set(i);
                params.set(i, null);
            }
        }
        try {
            StatementPlan plan = statement.compilePlan(this, Sequence.ValueOp.NOOP);
            return plan.getParameterMetaData();
        } finally {
            int lastSetBit = 0;
            while ((lastSetBit = unsetParams.nextSetBit(lastSetBit)) != -1) {
                params.set(lastSetBit, BindManager.UNBOUND_PARAMETER);
                lastSetBit++;
            }
        }
    }

    @Override
    public String toString() {
        return query;
    }

    @Override
    public void setArray(int parameterIndex, Array x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setBytes(int parameterIndex, byte[] x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setBlob(int parameterIndex, Blob x) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setBoolean(int parameterIndex, boolean x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setByte(int parameterIndex, byte x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setClob(int parameterIndex, Clob x) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setClob(int parameterIndex, Reader reader) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setDate(int parameterIndex, Date x) throws SQLException {
        if (x != null) { // Since Date is mutable, make a copy
            x = new Date(x.getTime());
        }
        setParameter(parameterIndex, x);
    }

    @Override
    public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
        if (x != null) { // Since Date is mutable, make a copy
            x = new Date(x.getTime());
        }
        cal.setTime(x);
        setParameter(parameterIndex, new Date(cal.getTimeInMillis()));
    }

    @Override
    public void setDouble(int parameterIndex, double x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setFloat(int parameterIndex, float x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setInt(int parameterIndex, int x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setLong(int parameterIndex, long x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setNClob(int parameterIndex, NClob value) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setNClob(int parameterIndex, Reader reader) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setNString(int parameterIndex, String value) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setNull(int parameterIndex, int sqlType) throws SQLException {
        setParameter(parameterIndex, null);
    }

    @Override
    public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
        setParameter(parameterIndex, null);
    }

    @Override
    public void setObject(int parameterIndex, Object o) throws SQLException {
        setParameter(parameterIndex, o);
    }

    @Override
    public void setObject(int parameterIndex, Object o, int targetSqlType) throws SQLException {
        PDataType targetType = PDataType.fromTypeId(targetSqlType);
        if (o != null) {
            PDataType sourceType = PDataType.fromLiteral(o);
            o = targetType.toObject(o, sourceType);
        }
        setParameter(parameterIndex, o);
    }

    @Override
    public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {
        setObject(parameterIndex, x, targetSqlType);
    }

    @Override
    public void setRef(int parameterIndex, Ref x) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setRowId(int parameterIndex, RowId x) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void setShort(int parameterIndex, short x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setString(int parameterIndex, String x) throws SQLException {
        setParameter(parameterIndex, x);
    }

    @Override
    public void setTime(int parameterIndex, Time x) throws SQLException {
        if (x != null) { // Since Time is mutable, make a copy
            x = new Time(x.getTime());
        }
        setParameter(parameterIndex, x);
    }

    @Override
    public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
        if (x != null) { // Since Time is mutable, make a copy
            x = new Time(x.getTime());
        }
        cal.setTime(x);
        setParameter(parameterIndex, new Time(cal.getTimeInMillis()));
    }

    private void setTimestampParameter(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
        if (x != null) { // Since Timestamp is mutable, make a copy
            int nanos = x.getNanos();
            x = new Timestamp(x.getTime());
            x.setNanos(nanos);
        }
        // TODO: deal with Calendar
        setParameter(parameterIndex, x);
    }

    @Override
    public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
        setTimestampParameter(parameterIndex, x, null);
    }

    @Override
    public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
        setTimestampParameter(parameterIndex, x, cal);
    }

    @Override
    public void setURL(int parameterIndex, URL x) throws SQLException {
        setParameter(parameterIndex, x.toExternalForm()); // Just treat as String
    }

    @Override
    public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }
}


text:
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Grid Layout Reference: item [min-|max-]*[width|height] percentages</title>
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">