text:
package org.openprovenance.prov.json;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.datatype.XMLGregorianCalendar;

import org.openprovenance.prov.model.Activity;
import org.openprovenance.prov.model.Entry;
import org.openprovenance.prov.model.QualifiedName;
import org.openprovenance.prov.model.Attribute;
import org.openprovenance.prov.model.DerivedByInsertionFrom;
import org.openprovenance.prov.model.DerivedByRemovalFrom;
import org.openprovenance.prov.model.DictionaryMembership;
import org.openprovenance.prov.model.Document;
import org.openprovenance.prov.model.HadMember;
import org.openprovenance.prov.model.HasOther;
import org.openprovenance.prov.model.HasLabel;
import org.openprovenance.prov.model.HasLocation;
import org.openprovenance.prov.model.HasRole;
import org.openprovenance.prov.model.HasType;
import org.openprovenance.prov.model.HasValue;
import org.openprovenance.prov.model.LangString;
import org.openprovenance.prov.model.Key;
import org.openprovenance.prov.model.Location;
import org.openprovenance.prov.model.Name;
import org.openprovenance.prov.model.Bundle;
import org.openprovenance.prov.model.Namespace;
import org.openprovenance.prov.model.ProvFactory;
import org.openprovenance.prov.model.Role;
import org.openprovenance.prov.model.Statement;
import org.openprovenance.prov.model.StatementOrBundle;
import org.openprovenance.prov.model.Used;
import org.openprovenance.prov.model.ValueConverter;
import org.openprovenance.prov.model.WasAssociatedWith;
import org.openprovenance.prov.model.WasEndedBy;
import org.openprovenance.prov.model.WasGeneratedBy;
import org.openprovenance.prov.model.WasInvalidatedBy;
import org.openprovenance.prov.model.WasStartedBy;

import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

/**
 * A Gson deserializer adapter for PROV-JSON Decode a PROV-JSON structure and
 * produces a {@link Document}
 *
 * @author Trung Dong Huynh <trungdong@donggiang.com>
 *
 */
public class ProvDocumentDeserializer implements JsonDeserializer<Document> {
    Namespace documentNamespace;
    Namespace currentNamespace;

    private static final String PROV_JSON_PREFIX = "prefix";

    private final ProvFactory pf;
    private final Name name;
    private final ValueConverter vconv;

    public ProvDocumentDeserializer(ProvFactory pf) {
	this.pf=pf;
	this.name=pf.getName();
	this.vconv = new ValueConverter(pf);
    }

    @Override
    public Document deserialize(JsonElement json, Type typeOfT,
				JsonDeserializationContext context)
					throws JsonParseException {
	JsonObject provJSONDoc = json.getAsJsonObject();

	// Initialise namespaces
	currentNamespace = decodePrefixes(provJSONDoc);
	documentNamespace = currentNamespace;

	// Decoding structures
	List<StatementOrBundle> statements = decodeBundle(provJSONDoc);

	// Create the document
	Document doc = pf.newDocument();
	doc.setNamespace(currentNamespace);

	doc.getStatementOrBundle().addAll(statements);
	return doc;
    }

    private Namespace decodePrefixes(JsonObject bundleStructure) {
	Namespace ns = new Namespace();
	// prefixes prov and xsd are implicit in prov-json
	ns.addKnownNamespaces();
	JsonObject prefixes = getObjectAndRemove(bundleStructure,
						 PROV_JSON_PREFIX);
	if (prefixes != null) {
	    for (Map.Entry<String, JsonElement> pair : prefixes.entrySet()) {
		String prefix = pair.getKey();
		String uri = pair.getValue().getAsString();
		if (prefix.equals("default")) {
		    ns.registerDefault(uri);
		} else {
		    ns.register(prefix, uri);
		}
	    }
	}
	return ns;
    }

    private List<StatementOrBundle> decodeBundle(JsonObject bundleStructure) {
	List<StatementOrBundle> statements = new ArrayList<StatementOrBundle>();
	for (Map.Entry<String, JsonElement> sPair : bundleStructure.entrySet()) {
	    String statementType = sPair.getKey();
	    JsonObject statementMap = sPair.getValue().getAsJsonObject();
	    statements.addAll(decodeElements(statementType, statementMap));
	}
	return statements;
    }

    private List<StatementOrBundle> decodeElements(String statementType,
						   JsonObject statementMap) {
	List<StatementOrBundle> statements = new ArrayList<StatementOrBundle>();
	for (Map.Entry<String, JsonElement> pair : statementMap.entrySet()) {
	    String idStr = pair.getKey();
	    if (pair.getValue().isJsonArray()) {
		// Multiple elements having the same identifier
		JsonArray elements = pair.getValue().getAsJsonArray();
		Iterator<JsonElement> iter = elements.iterator();
		while (iter.hasNext()) {
		    JsonObject attributeMap = iter.next().getAsJsonObject();
		    StatementOrBundle statement = decodeStatement(statementType,
								  idStr,
								  attributeMap);
		    statements.add(statement);
		}
	    } else {
		JsonObject attributeMap = pair.getValue().getAsJsonObject();
		StatementOrBundle statement = decodeStatement(statementType,
							      idStr,
							      attributeMap);
		statements.add(statement);
	    }
	}
	return statements;
    }

    @SuppressWarnings("unchecked")
    private StatementOrBundle decodeStatement(String statementType,
					      String idStr,
					      JsonObject attributeMap) {
	StatementOrBundle statement;
	QualifiedName id;

	ProvJSONStatement provStatement = ProvJSONStatement.valueOf(statementType);
	switch (provStatement) {
	case bundle: {
	    id=null; //we will deal with it later, when we have setup the namespace for the bundle
	    break;
	}
	default: {
	    if (idStr.startsWith("_:")) {
		// Ignore all blank node IDs
		id = null;
	    } else {
		id = currentNamespace.stringToQualifiedName(idStr, pf);
	    }
	}
	}

	// Decoding attributes
	switch (provStatement) {
	case entity:
	    statement = pf.newEntity(id);
	    break;
	case activity:
	    XMLGregorianCalendar startTime = optionalTime("prov:startTime",
							  attributeMap);
	    XMLGregorianCalendar endTime = optionalTime("prov:endTime",
							attributeMap);
	    Activity a = pf.newActivity(id);
	    if (startTime != null) {
		a.setStartTime(startTime);
	    }
	    if (endTime != null) {
		a.setEndTime(endTime);
	    }
	    statement = a;
	    break;
	case agent:
	    statement = pf.newAgent(id);
	    break;
	case alternateOf:
	    QualifiedName alternate1 = optionalQualifiedName("prov:alternate1", attributeMap);
	    QualifiedName alternate2 = optionalQualifiedName("prov:alternate2", attributeMap);
	    statement = pf.newAlternateOf(alternate2, alternate1);
	    break;
	case wasAssociatedWith:
	    QualifiedName activity = optionalQualifiedName("prov:activity", attributeMap);
	    QualifiedName agent = optionalQualifiedName("prov:agent", attributeMap);
	    QualifiedName plan = optionalQualifiedName("prov:plan", attributeMap);
	    WasAssociatedWith wAW = pf.newWasAssociatedWith(id, activity, agent);
	    if (plan != null)
		wAW.setPlan(plan);
	    statement = wAW;
	    break;
	case wasAttributedTo:
	    QualifiedName entity = optionalQualifiedName("prov:entity", attributeMap);
	    agent = optionalQualifiedName("prov:agent", attributeMap);
	    statement = pf.newWasAttributedTo(id, entity, agent);
	    break;
	case bundle:
	    Namespace ns = decodePrefixes(attributeMap);
	    currentNamespace = ns;
	    currentNamespace.setParent(documentNamespace);
	    // Re-resolve the bundle's id with the bundle's namespace
	    id = currentNamespace.stringToQualifiedName(idStr, pf);
	    @SuppressWarnings("rawtypes")
	    Collection statements = decodeBundle(attributeMap);
	    Bundle namedBundle = pf.getObjectFactory().createNamedBundle();
	    namedBundle.setId(id);
	    namedBundle.setNamespace(ns);
	    namedBundle.getStatement()
		       .addAll((Collection<? extends Statement>) statements);
	    statement = namedBundle;

	    // Restore the document's namespace as the current one
	    currentNamespace = documentNamespace;
	    break;
	case wasInformedBy:
	    QualifiedName informed = optionalQualifiedName("prov:informed", attributeMap);
	    QualifiedName informant = optionalQualifiedName("prov:informant", attributeMap);
	    statement = pf.newWasInformedBy(id, informed, informant);
	    break;
	case actedOnBehalfOf:
	    QualifiedName delegate = optionalQualifiedName("prov:delegate", attributeMap);
	    QualifiedName responsible = optionalQualifiedName("prov:responsible", attributeMap);
	    activity = optionalQualifiedName("prov:activity", attributeMap);
	    statement = pf.newActedOnBehalfOf(id, delegate, responsible,
					      activity);
	    break;
	case wasDerivedFrom:
	    QualifiedName generatedEntity = optionalQualifiedName("prov:generatedEntity",
						  attributeMap);
	    QualifiedName usedEntity = optionalQualifiedName("prov:usedEntity", attributeMap);
	    activity = optionalQualifiedName("prov:activity", attributeMap);
	    QualifiedName generation = optionalQualifiedName("prov:generation", attributeMap);
	    QualifiedName usage = optionalQualifiedName("prov:usage", attributeMap);
	    statement = pf.newWasDerivedFrom(id, generatedEntity, usedEntity,
					     activity, generation, usage,null);
	    break;
	case wasEndedBy:
	    activity = optionalQualifiedName("prov:activity", attributeMap);
	    QualifiedName trigger = optionalQualifiedName("prov:trigger", attributeMap);
	    QualifiedName ender = optionalQualifiedName("prov:ender", attributeMap);
	    XMLGregorianCalendar time = optionalTime("prov:time", attributeMap);
	    WasEndedBy wEB = pf.newWasEndedBy(id, activity, trigger);
	    if (ender != null)
		wEB.setEnder(ender);
	    if (time != null) {
		wEB.setTime(time);
	    }
	    statement = wEB;
	    break;
	case wasGeneratedBy:
	    entity = optionalQualifiedName("prov:entity", attributeMap);
	    activity = optionalQualifiedName("prov:activity", attributeMap);
	    time = optionalTime("prov:time", attributeMap);
	    WasGeneratedBy wGB = pf.newWasGeneratedBy(id);
	    wGB.setEntity(entity);
	    if (activity != null)
		wGB.setActivity(activity);
	    if (time != null) {
		wGB.setTime(time);
	    }
	    statement = wGB;
	    break;
	case wasInfluencedBy:
	    QualifiedName influencee = anyRef("prov:influencee", attributeMap);
	    QualifiedName influencer = anyRef("prov:influencer", attributeMap);
	    statement = pf.newWasInfluencedBy(id, influencee, influencer);
	    break;
	case wasInvalidatedBy:
	    entity = optionalQualifiedName("prov:entity", attributeMap);
	    activity = optionalQualifiedName("prov:activity", attributeMap);
	    time = optionalTime("prov:time", attributeMap);
	    WasInvalidatedBy wIB = pf.newWasInvalidatedBy(id, entity, activity);
	    if (time != null) {
		wIB.setTime(time);
	    }
	    statement = wIB;
	    break;
	case hadMember:
	    QualifiedName collection = optionalQualifiedName("prov:collection", attributeMap);
	    Collection<QualifiedName> entities = optionalQualifiedNames("prov:entity",
							attributeMap);
	    HadMember membership = pf.getObjectFactory().createHadMember();
	    membership.setCollection(collection);
	    if (entities != null)
		membership.getEntity().addAll(entities);
	    statement = membership;
	    break;
	case mentionOf:
	    QualifiedName specificEntity = optionalQualifiedName("prov:specificEntity",
						 attributeMap);
	    QualifiedName generalEntity = optionalQualifiedName("prov:generalEntity",
						attributeMap);
	    QualifiedName bundle = optionalQualifiedName("prov:bundle", attributeMap);
	    statement = pf.newMentionOf(specificEntity, generalEntity, bundle);
	    break;
	case specializationOf:
	    specificEntity = optionalQualifiedName("prov:specificEntity", attributeMap);
	    generalEntity = optionalQualifiedName("prov:generalEntity", attributeMap);
	    statement = pf.newSpecializationOf(specificEntity, generalEntity);
	    break;
	case wasStartedBy:
	    activity = optionalQualifiedName("prov:activity", attributeMap);
	    trigger = optionalQualifiedName("prov:trigger", attributeMap);
	    QualifiedName starter = optionalQualifiedName("prov:starter", attributeMap);
	    time = optionalTime("prov:time", attributeMap);
	    WasStartedBy wSB = pf.newWasStartedBy(id, activity, trigger);
	    if (starter != null)
		wSB.setStarter(starter);
	    if (time != null) {
		wSB.setTime(time);
	    }
	    statement = wSB;
	    break;
	case used:
	    QualifiedName activity2 = optionalQualifiedName("prov:activity", attributeMap);
	    QualifiedName entity2 = optionalQualifiedName("prov:entity", attributeMap);
	    time = optionalTime("prov:time", attributeMap);
	    Used wUB = pf.newUsed(id);
	    wUB.setActivity(activity2);
	    if (entity2 != null)
		wUB.setEntity(entity2);
	    if (time != null) {
		wUB.setTime(time);
	    }
	    statement = wUB;
	    break;
	case derivedByInsertionFrom:
	    QualifiedName before = optionalQualifiedName("prov:before", attributeMap);
	    QualifiedName after = optionalQualifiedName("prov:after", attributeMap);
	    List<Entry> keyEntitySet = optionalEntrySet("prov:key-entity-set",
								   attributeMap);
	    DerivedByInsertionFrom dBIF = pf.newDerivedByInsertionFrom(id,
								       after,
								       before,
								       keyEntitySet,
								       null);
	    statement = dBIF;
	    break;
	case derivedByRemovalFrom:
	    before = optionalQualifiedName("prov:before", attributeMap);
	    after = optionalQualifiedName("prov:after", attributeMap);
	    List<Key> keys = optionalKeySet("prov:key-set", attributeMap);
	    DerivedByRemovalFrom dBRF = pf.newDerivedByRemovalFrom(id, after,
								   before,
								   keys, null);
	    statement = dBRF;
	    break;
	case hadDictionaryMember:
	    QualifiedName dictionary = optionalQualifiedName("prov:dictionary", attributeMap);
	    keyEntitySet = optionalEntrySet("prov:key-entity-set",
						attributeMap);
	    DictionaryMembership hDM = pf.newDictionaryMembership(dictionary,
								  keyEntitySet);
	    statement = hDM;
	    break;
	default:
	    statement = null;
	    break;

	}

	// All the remaining attributes can have multiple values, except
	// prov:value
	// prov:type decoding
	List<JsonElement> values = popMultiValAttribute("prov:type",
							attributeMap);
	if (!values.isEmpty()) {
	    if (statement instanceof HasType) {
		List<org.openprovenance.prov.model.Type> types = ((HasType) statement).getType();
		for (JsonElement value : values) {
		    types.add((org.openprovenance.prov.model.Type) decodeAttributeValue(value,
											name.PROV_TYPE));
		}
	    } else {
		throw new UnsupportedOperationException(
							"prov:type is not allowed in a "
								+ statementType
								+ "statement - id: "
								+ idStr);
	    }
	}
	// prov:label decoding
	values = popMultiValAttribute("prov:label", attributeMap);
	if (!values.isEmpty()) {
	    if (statement instanceof HasLabel) {
		List<LangString> labels = ((HasLabel) statement).getLabel();
		for (JsonElement value : values) {
		    labels.add(decodeInternationalizedString(value));
		}
	    } else {
		throw new UnsupportedOperationException(
							"prov:label is not allowed in a "
								+ statementType
								+ "statement - id: "
								+ idStr);
	    }
	}
	// prov:location decoding
	values = popMultiValAttribute("prov:location", attributeMap);
	if (!values.isEmpty()) {
	    if (statement instanceof HasLocation) {
		List<Location> locations = ((HasLocation) statement).getLocation();
		for (JsonElement value : values) {
		    locations.add((org.openprovenance.prov.model.Location) decodeAttributeValue(value,
												name.PROV_LOCATION));
		}
	    } else {
		throw new UnsupportedOperationException(
							"prov:location is not allowed in a "
								+ statementType
								+ "statement - id: "
								+ idStr);
	    }
	}
	// prov:role decoding
	values = popMultiValAttribute("prov:role", attributeMap);
	if (!values.isEmpty()) {
	    if (statement instanceof HasRole) {
		List<Role> roles = ((HasRole) statement).getRole();
		for (JsonElement value : values) {
		    roles.add((org.openprovenance.prov.model.Role) decodeAttributeValue(value,
											name.PROV_ROLE));
		}
	    } else {
		throw new UnsupportedOperationException(
							"prov:role is not allowed in a "
								+ statementType
								+ "statement - id: "
								+ idStr);
	    }
	}
	// prov:value decoding
	values = popMultiValAttribute("prov:value", attributeMap);
	if (!values.isEmpty()) {
	    if (values.size() > 1) {
		// only one instance allowed
		throw new UnsupportedOperationException(
							"Only one instance of prov:value is allowed in a statement - id: "
								+ idStr);
	    }
	    if (statement instanceof HasValue) {
		((HasValue) statement).setValue((org.openprovenance.prov.model.Value) decodeAttributeValue(values.get(0),
													   name.PROV_VALUE));
	    } else {
		throw new UnsupportedOperationException(
							"prov:value is not allowed in a "
								+ statementType
								+ "statement - id: "
								+ idStr);
	    }
	}

	// arbitrary attribute decoding
	if (provStatement != ProvJSONStatement.bundle
		&& !attributeMap.entrySet().isEmpty()) {
	    if (statement instanceof HasOther) {
		// TODO: to clean up this casting
		@SuppressWarnings("rawtypes")
		List ll = ((HasOther) statement).getOther();
		List<Attribute> attributes = (List<Attribute>) ll;
		for (Map.Entry<String, JsonElement> aPair : attributeMap.entrySet()) {
		    QualifiedName attributeName = currentNamespace.stringToQualifiedName(aPair.getKey(),pf);
		    JsonElement element = aPair.getValue();
		    values = pickMultiValues(element);
		    for (JsonElement value : values) {

			Attribute attr = decodeAttributeValue(value,
							      attributeName);
			attributes.add(attr);
		    }
		}
	    } else {
		throw new UnsupportedOperationException(
							"Arbitrary attributes are not allowed in a "
								+ statementType
								+ "statement - id: "
								+ idStr);
	    }
	}

	return statement;
    }

    private LangString decodeInternationalizedString(JsonElement element) {
	LangString iString = pf.getObjectFactory()
					    .createInternationalizedString();
	if (element.isJsonPrimitive()) {
	    iString.setValue(element.getAsString());
	} else {
	    JsonObject struct = element.getAsJsonObject();
	    String value = struct.get("$").getAsString();
	    iString.setValue(value);
	    if (struct.has("lang")) {
		String lang = struct.get("lang").getAsString();
		iString.setLang(lang);
	    }
	}
	return iString;
    }

    private Attribute decodeAttributeValue(JsonElement element, QualifiedName elementName) {
	if (element.isJsonPrimitive()) {
	    Object o = decodeJSONPrimitive(element.getAsString());
	    QualifiedName type = vconv.getXsdType(o);
	    return pf.newAttribute(elementName, o, type);
	} else {
	    JsonObject struct = element.getAsJsonObject();
	    String value = struct.get("$").getAsString();
	    if (struct.has("lang")) {
		// Internationalized strings
		String lang = struct.get("lang").getAsString();
		LangString iString = pf.getObjectFactory()
			.createInternationalizedString();
		iString.setValue(value);
		iString.setLang(lang);
		return pf.newAttribute(elementName,
				       iString,
				       name.PROV_LANG_STRING);
	    } else if (struct.has("type")) {
		String datatypeAsString = struct.get("type").getAsString();
		QualifiedName xsdType = currentNamespace.stringToQualifiedName(datatypeAsString, pf);
		if (xsdType.equals(name.PROV_QUALIFIED_NAME)) { /* we ignore xsdType.equals(name.FOR_XML_XSD_QNAME)  */
		    return pf.newAttribute(elementName,
					   currentNamespace.stringToQualifiedName(value,pf), xsdType);
		} else {
		    return pf.newAttribute(elementName, value, xsdType);
		}
	    } else {
		// if no type or lang information, decode as an
		// Internationalized string without lang
		LangString iString = pf.getObjectFactory()
						    .createInternationalizedString();
		iString.setValue(value);
		return pf.newAttribute(elementName,
				       iString,
				       name.PROV_LANG_STRING);
	    }
	}
    }

    private Object decodeJSONPrimitive(String value) {
	if (value == "true") {
	    return true;
	} else if (value == "false") {
	    return false;
	}
	try {
	    // Try to parse an integer value first
	    return Integer.parseInt(value);
	} catch (NumberFormatException ex1) {
	    try {
		// Try double next
		return Double.parseDouble(value);
	    } catch (NumberFormatException ex2) {
		// Not a number, return the string
		return value;
	    }
	}
    }

    private List<JsonElement> popMultiValAttribute(String attributeName,
						   JsonObject attributeMap) {
	if (attributeMap.has(attributeName)) {
	    JsonElement element = attributeMap.remove(attributeName);
	    return pickMultiValues(element);
	} else
	    return Collections.emptyList();
    }

    private List<JsonElement> pickMultiValues(JsonElement element) {
	if (element.isJsonArray()) {
	    // Picking multiple values
	    JsonArray array = element.getAsJsonArray();
	    List<JsonElement> elements = new ArrayList<JsonElement>(
								    array.size());
	    Iterator<JsonElement> iter = array.iterator();
	    while (iter.hasNext()) {
		elements.add(iter.next());
	    }
	    return elements;
	} else {
	    // Return a single item list
	    return Collections.singletonList(element);
	}
    }

    private String popString(JsonObject jo, String memberName) {
	return jo.remove(memberName).getAsString();
    }

    private QualifiedName qualifiedName(String attributeName, JsonObject attributeMap) {
	return currentNamespace.stringToQualifiedName(popString(attributeMap,
	                                                        attributeName),
	                                              pf);
    }

    // TODO: this name is legacy, what should it be?
    private QualifiedName anyRef(String attributeName, JsonObject attributeMap) {
	if (attributeMap.has(attributeName))
	    return currentNamespace.stringToQualifiedName(popString(attributeMap,
	                                              attributeName),
	                                              pf);
	else
	    return null;
    }

    private QualifiedName optionalQualifiedName(String attributeName, JsonObject attributeMap) {
	if (attributeMap.has(attributeName))
	    return qualifiedName(attributeName, attributeMap);
	else
	    return null;
    }

    private XMLGregorianCalendar optionalTime(String attributeName,
					      JsonObject attributeMap) {
	if (attributeMap.has(attributeName))
	    return pf.newISOTime(popString(attributeMap, attributeName));
	else
	    return null;
    }

    private Collection<QualifiedName> qualifiedNames(String attributeName,
				     JsonObject attributeMap) {
	List<QualifiedName> results = new ArrayList<QualifiedName>();
	List<JsonElement> elements = popMultiValAttribute(attributeName,
							  attributeMap);
	for (JsonElement element : elements) {
	    results.add(currentNamespace.stringToQualifiedName(element.getAsString(),pf));
	}
	return results;
    }

    private Collection<QualifiedName> optionalQualifiedNames(String attributeName,
					     JsonObject attributeMap) {
	if (attributeMap.has(attributeName))
	    return qualifiedNames(attributeName, attributeMap);
	else
	    return null;
    }

    private List<Entry> entrySet(String attributeName,
					    JsonObject attributeMap) {
	List<Entry> results = new ArrayList<Entry>();
	// check if it is a dictionary or a list
	JsonElement kESElement = attributeMap.remove(attributeName);
	if (kESElement.isJsonArray()) {
	    // decode it as a list of elements
	    List<JsonElement> elements = pickMultiValues(kESElement);
	    for (JsonElement element : elements) {
		JsonObject item = element.getAsJsonObject();
		Entry pair = pf.newEntry((Key) decodeAttributeValue(item.remove("key"),
		                                                    name.PROV_KEY),

		                         currentNamespace.stringToQualifiedName(this.popString(item, "$"),pf));
		results.add(pair);
	    }
	} else if (kESElement.isJsonObject()) {
	    // decode it as a dictionary whose keys are of the same datatype
	    JsonObject dictionary = kESElement.getAsJsonObject();
	    // TODO This does not conform with PROV-JSON !!!
	    String keyDatatype = dictionary.remove("$key-datatype")
					   .getAsString();
	    QualifiedName datatype = currentNamespace.stringToQualifiedName(keyDatatype,pf);
	    for (Map.Entry<String, JsonElement> entry : dictionary.entrySet()) {
		String entryKey = entry.getKey();
		JsonElement entryValue = entry.getValue();

		Entry pair = decodeDictionaryEntry(datatype, entryKey,
						   entryValue);
		results.add(pair);
	    }
	}
	return results;
    }

    public Entry decodeDictionaryEntry(QualifiedName datatype,
				       String entryKey,
				       JsonElement entryValue) {

	Key kk;
	if (datatype.equals(name.PROV_QUALIFIED_NAME)) {
	    kk=(Key) pf.newAttribute(name.PROV_KEY,
	                             currentNamespace.stringToQualifiedName(entryKey,pf), datatype);
	} else {
	    kk=(Key) pf.newAttribute(name.PROV_KEY, entryKey, datatype);
	}

	Entry pair = pf.newEntry(kk,
	                         currentNamespace.stringToQualifiedName(entryValue.getAsString(), pf));
	return pair;
    }

    private List<Entry> optionalEntrySet(String attributeName,
						    JsonObject attributeMap) {
	if (attributeMap.has(attributeName))
	    return entrySet(attributeName, attributeMap);
	else
	    return null;
    }

    private List<Key> keySet(String attributeName, JsonObject attributeMap) {
	List<Key> results = new ArrayList<Key>();
	List<JsonElement> elements = popMultiValAttribute(attributeName,
							  attributeMap);
	for (JsonElement element : elements) {
	    Key key = (Key) decodeAttributeValue(element, name.PROV_KEY);
	    results.add(key);
	}
	return results;
    }

    private List<Key> optionalKeySet(String attributeName,
				     JsonObject attributeMap) {
	if (attributeMap.has(attributeName))
	    return keySet(attributeName, attributeMap);
	else
	    return null;
    }

    private JsonObject getObjectAndRemove(JsonObject jsonObject,
					  String memberName) {
	if (jsonObject.has(memberName)) {
	    JsonObject result = jsonObject.getAsJsonObject(memberName);
	    jsonObject.remove(memberName);
	    return result;
	} else
	    return null;
    }

}


text:
<text>

 WSJ891030-0113
 = 891030
 891030-0113.
 World Markets:
@  London Shares Decline Sharply as Resignation
@  By Lawson, New York Slump Weigh on Market
@  ----
@  A Wall Street Journal News Roundup
 10/30/89
 WALL STREET JOURNAL (J)
 FREST CANDA EUROP JAPAN
 COMMODITY NEWS, FARM PRODUCTS (CMD)
STOCK MARKET, OFFERINGS (STK)
PRECIOUS METALS, STONES, GOLD, SILVER (PCS)

   London share prices closed sharply lower Friday in active trading after Chancellor of the Exchequer Nigel Lawson's resignation slapped the market and Wall Street's rapid initial sell-off knocked it down.

   London shares were depressed initially by overnight losses in New York and by the drop in sterling after Mr. Lawson's resignation.
It showed some early resilience after central bank support firmed sterling, but the weight of Wall Street late in London trading, and signs of further weakness in the British pound, proved a hefty load to bear.
New York stocks recovered some of their losses after the London market closed.

   The Financial Times 100-share index shed 47.3 points to close at 2082.1, down 4.5% from the previous Friday and 6.8% from Oct. 13, when Wall Street's plunge helped spark the current weakness in London.

   The 30-share index settled 42.0 points lower at 1678.5.
Volume was 840.8 million shares, up from 443.6 million Thursday and the week's most active session.

   Dealers said the turnover, largely confined to the 100-share index stocks, partly reflected the flurry of activity typical at the close of a two-week trading account and the start of a new account.
But they said Friday's focus on the top-tier stocks telegraphed active overseas selling and showed the broad-based fears over the status of the U.K. economy and Britain's currency in the wake of the upheaval in Prime Minister Margaret Thatcher's cabinet.

   A senior dealer with Warburg Securities noted British Gas, the most active blue-chip stock at 20 million shares traded, was affected by the political implications of Mr. Lawson's departure and Mrs. Thatcher's cabinet shuffle.

   He attributed the unusually high volume to broad-based selling on fears that the Thatcher government may be in turmoil and Britain's Labor Party positioned to regain control of the government and renew efforts at nationalization.

   British Gas shed 8.5 pence a share to close at 185 pence ($2.90).

   Other dealers added that the blue-chip stocks in general were hit by profit-taking over concerns that London shares will continue posting declines and the uncertainty over sterling given that Mr. Lawson's successor, John Major, had only been in the job one day.

   Besides British Gas, British Steel skidded 1.74 to 123.5 on turnover of 11 million shares.

   British Petroleum fell 5 to 286 on 14 million shares traded.
Dealers said the multinational oil company was pressured by recent brokerage recommendations urging investors to switch into Shell Trading amp Transport.
Shell eased 1 to 416 on turnover of 4.8 million shares.

   Among the other actively traded blue-chip issues, Imperial Chemical Industries dropped 11 to #10.86, Hanson skidded 9.5 to 200.5, and British Telecom fell 10 to 250.

   In Tokyo, stocks closed lower but above intraday lows in active trading.
The Nikkei index was pressured down by profit-taking triggered by sharp advances made through this week and fell 151.20 points to 35527.29.

   In early trading in Tokyo Monday, the Nikkei index fell 148.85 points to 35378.44.

   On Friday, the Tokyo stock price index of first section issues was down 15.82 at 2681.76.
First-section volume was estimated at 1.3 billion shares, up from 886 million shares Thursday.

   An official at Wako Securities said brokerages' excessive expectations about recent advances in Tokyu Group shares and real estate issues were dashed Friday.

   Dealers placed heavy buy orders in the morning to start the first trading day for November transactions.
But they failed to sell these stocks to client investors, who were cautious about the sharp gains these issues made this week, the Wako official said.

   Fund managers said Friday's profittaking was a natural result of the week's "abnormal fever" in buying real estate, shipbuilding, steel and construction shares.

   Frankfurt prices closed lower again Friday, the fourth decline in the past five days and the culmination of a week that saw the DAX index lose 4%.
The DAX dropped 19.69 points Friday to 1462.93.

   Traders said the continued turbulence in other markets, coupled with the drop in London following the Lawson resignation, were responsible.

   Traders said that selling pressure wasn't enormous and that the DAX dropped Friday more on a lack of any substantial buying interest.
They said contributing to the downward drift was the fact that many professional traders had chosen to square positions ahead of the weekend.

   "It's the whole uncertainty about what's happening around us," said Valentin Von Korff, a trader at Credit Suisse First Boston in Frankfurt.
"If you take away the outside influences, the market itself looks very cheap.
What's happening here is n't justified by the fundamentals."

   Traders said the market remains extremely nervous because of the wild swings seen on the New York Stock Exchange last week.
That's leaving small investors with cold feet, they said, and prompting institutions to take a reserved stance on the sidelines as well, at least until the market in New York settles down somewhat.

   Elsewhere, share prices closed lower in Paris, Zurich, Amsterdam, Brussels and Stockholm, and were mixed in Milan.
The British shakeup was widely cited for the declines.

   Share prices also closed lower in Sydney, Hong Kong, Singapore, Taipei, Manila, Wellington and Seoul.
Concern about declines in other markets, especially New York, caused selling pressure.

   Here are price trends on the world's major stock markets, as calculated by Morgan Stanley Capital International Perspective, Geneva.
To make them directly comparable, each index is based on the close of 1969 equaling 100.
The percentage change is since year-end.
@ % This
@ Oct 25 Oct 24 Year
@ U.S. ................... 315.2 316.4 +23.1
@ Britain ................ 646.4 643.1 +18.4
@ Canada ................. 426.9 426.4 +16.3
@ Japan .................. 1547.1 1550.9 + 8.9
@ France ................. 518.6 521.2 +17.1
@ Germany ................ 236.7 241.0 +13.8
@ Hong Kong .............. 2049.2 2068.9 + 1.0
@ Switzerland ............ 212.6 216.5 +23.0
@ Australia .............. 326.0 329.4 +12.3
@ World index ............ 532.4 533.4 + 7.7
@ Weekly Percentage Leaders

   Last week's best and worst performing stocks among those issues that make up 80% of the world's stock market capitalization (in local currency)
@ ISSUE (COUNTRY) CLOSE % CHG
@ WINNING ISSUES

@ Bell Resources (Australia) ....... 1.02 +32.5
@Bond Media (Australia) ........... 0.31 +24.0
@Godo Shusei (Japan) .............. 2380.0 +19.0
@Fonciere Lvonnaise (France) ...... 858.0 +18.8
@Pegasus Gold (Canada) ............ 14.0 +16.7
@Tokyu Corp. (Japan) .............. 2740.0 +15.6
@SAT Telecom (France) ............. 1605.0 +15.5
@Echo Bay Mines (Canada) .......... 18.625 +13.7
@Nippon Express (Japan) ........... 1770.0 +13.5
@UAC (Singapore) .................. 2380.0 +19.0
@ LOSING ISSUES

@MacCarthy amp Stone (England) ...... 0.74 -29.5
@Campeau (Canada) ................. 7.375 -24.4
@Interchase Corp. (Australia) ..... 0.72 -20.0
@LTV (U.S.) ....................... 1.5 -20.0
@Norske Credibank (Norway) ........ 81.0 -18.6
@Laing (John) (England) ........... 1.96 -18.0
@Computer Assoc Intl (U.S.) ....... 12.0 -17.9
@Beverly Enterprises ( U.S.) ...... 5.625 -16.7
@McDermott Intl (U.S.) ............ 19.0 -16.5
@Lex Services (England) ........... 2.41 -16.3

   Source: Morgan Stanley Capital Intl.
Perspective

</text>

redpajama_set_name: RedPajamaGithub


text:
<!DOCTYPE html>

	<title>Login Fuse</title>
		<link rel="shortcut icon" href="../favicon.ico">
		<link rel="stylesheet" type="text/css" href="auth/css/component.css" />
		<link rel="stylesheet" type="text/css" href="auth/css/default.css" />

            {{Form::open(array('url' => 'login', 'method'=>'POST', 'class'=>'cbp-mc-form'))}}

@if(Session::has('global'))
                  {{ Session::get('global') }}
                @endif

					Username
					<input type="text"  name="username" placeholder="Username">

					Password
						<input type="password" name="password" placeholder="********">

  				 {{Form::submit('Login',array('class'=>'btn cbp-mc-submit'))}}

  				 {{Form::token()}}
          {{Form::close()}}


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

<title>HttpSenderFactory (acra 4.11 API)</title>
<meta name="date" content="2018-03-21">
<link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">

JavaScript is disabled on your browser.

Skip navigation links

Overview

Package

Class

Tree

Deprecated

Index

Help

Prev Class

Next Class

Frames

No Frames

All Classes

Summary:

Nested |

Field |

Constr |

Method

Detail:

Field |

Constr |

Method

org.acra.sender

Class HttpSenderFactory

java.lang.Object

org.acra.sender.HttpSenderFactory

All Implemented Interfaces:

ReportSenderFactory

public final class HttpSenderFactory
extends java.lang.Object
implements ReportSenderFactory

Constructs a HttpSender with no report field mappings.

Constructor Summary

Constructors

Constructor and Description

HttpSenderFactory()

Method Summary

All Methods Instance Methods Concrete Methods

Modifier and Type
Method and Description

ReportSender
create(android.content.Context context,
      ACRAConfiguration config)

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructor Detail

HttpSenderFactory

public HttpSenderFactory()

Method Detail

create

@NonNull
public ReportSender create(@NonNull
                                     android.content.Context context,
                                     @NonNull
                                     ACRAConfiguration config)

Specified by:

create in interface ReportSenderFactory

Parameters:

context - Application context.

config - Configuration to use when sending reports.

Returns:

Fully configured instance of the relevant ReportSender.

Skip navigation links

Overview

Package

Class

Tree

Deprecated

Index

Help

Prev Class

Next Class

Frames

No Frames

All Classes

Summary:

Nested |

Field |

Constr |

Method

Detail:

Field |

Constr |

Method


text:
  Ségrie-Fontaine est
       un village
       géographiquement positionné dans le département de l'Orne en Basse-Normandie. Elle comptait 405 habitants en 2008.

Si vous pensez demenager à Ségrie-Fontaine, vous pourrez aisément trouver une maison à acheter.

Le parc de logements, à Ségrie-Fontaine, était réparti en 2011 en quatorze appartements et 224 maisons soit
 un marché relativement équilibré.

À proximité de Ségrie-Fontaine sont localisées les villes de
Le Mesnil-Villement située à 4 km, 286 habitants,
Pont-d'Ouilly localisée à 5 km, 1 040 habitants,
La Carneille située à 5 km, 552 habitants,
Sainte-Honorine-la-Chardonne localisée à 5 km, 681 habitants,
La Forêt-Auvray située à 5 km, 196 habitants,
La Lande-Saint-Siméon à 1 km, 138 habitants,
 entre autres. De plus, Ségrie-Fontaine est située à seulement treize km de Flers.

La commune compte quelques  équipements, elle dispose, entre autres, de un terrain de tennis, un terrain de sport et une base nautique.


text:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistece http://java.sun.com/xml/ns/persistence_2_0.xsd"
	version="2.0">

	<persistence-unit name="punit">

	</persistence-unit>

</persistence>


text:
TOKEN_FILE="$HOME/.gdrive/token_v2.json"
TOKEN="Authorization: Bearer token"
PARENT="forder id"

get() {
  wget -O - -U Mozilla -q --load-cookies cookies.txt --save-cookies cookies.txt --keep-session-cookies $@
}

updateToken() {
  o=$(gdrive list)
  token=$(grep access_token "$TOKEN_FILE")
  token=${token#*access_token\": \"}; token=${token%%\"*}
  TOKEN="Authorization: Bearer $token"
}

copy() {
  id=$1; name="$2"
  curl -X POST -H "$TOKEN" -H "Content-Type: application/json" "https://www.googleapis.com/drive/v3/files/$id/copy" -d "{\"parents\":[\"$PARENT\"],\"name\":\"$name\"}"
}

checkFile() {
  name="$1"
  if [$(wget -q -O - --header "$TOKEN" "https://www.googleapis.com/drive/v3/files?q='$PARENT' in parents and trashed = false and name = '$name'" | wc -l) = 5 ]; then
    echo 0
  else
    echo 1
  fi
}

parseVideo() {
  url=$1

  html=$(get "$url")

  checkAuth=$(echo "$html" | grep guestAuth)
  if [ ! "x" = "x$checkAuth" ]; then
    echo "auth..."
    authUri=${checkAuth#*href=\"}; authUri=${authUri%%\"*}
    auth=$(get "$authUri")
    html=$(get "$url")
  fi

  name=$(echo "$html" | grep "og:title"); name=${name#*content=\'}; name="${name%%\'*}.mp4"
  id=$(echo "$html" | grep drive); id=${id%/preview*}; id=${id#*/d/}

  echo "copy $id $name"
  copy $id "$name"
}

cat list.txt | while read url img name; do
  echo $name
  updateToken
  if [ $(checkFile "$name.mp4") = 1 ]; then
    continue
  fi
  wget -q -O - "$img" | gdrive upload - -p $PARENT "$name.jpg"
  parseVideo "$url"
  sleep 60
done


text:
import * as L from 'leaflet';
declare var require: any;

/**
* Fixes leaflet image loading issue with angular
* @see https://github.com/Leaflet/Leaflet/issues/4968
*/
export const defaultLeafletIconOptions: L.IconOptions = {
  iconUrl: require('leaflet/dist/images/marker-icon.png'),
  shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
  iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34]
}


text:
package org.glyptodon.guacamole.auth.jdbc.connection;

import java.util.Collection;
import org.apache.ibatis.annotations.Param;

/**
 * Mapper for connection parameter objects.
 *
 * @author Michael Jumper
 */
public interface ParameterMapper {

    /**
     * Returns a collection of all parameters associated with the connection
     * having the given identifier.
     *
     * @param identifier
     *     The identifier of the connection whose parameters are to be
     *     retrieved.
     *
     * @return
     *     A collection of all parameters associated with the connection
     *     having the given identifier. This collection will be empty if no
     *     such connection exists.
     */
    Collection<ParameterModel> select(@Param("identifier") String identifier);

    /**
     * Inserts each of the parameter model objects in the given collection as
     * new connection parameters.
     *
     * @param parameters
     *     The connection parameters to insert.
     *
     * @return
     *     The number of rows inserted.
     */
    int insert(@Param("parameters") Collection<ParameterModel> parameters);

    /**
     * Deletes all parameters associated with the connection having the given
     * identifier.
     *
     * @param identifier
     *     The identifier of the connection whose parameters should be
     *     deleted.
     *
     * @return
     *     The number of rows deleted.
     */
    int delete(@Param("identifier") String identifier);

}


text:
module.exports = {

    getNodeByParams: function (nodeParams: Object):string{
        return 'MATCH (node {' + getPropertyString(nodeParams) + '}) RETURN node';
    },
    createRelation: function (scrUriName:string, relationName:string, trgUriName:string):string{
        return 'MATCH (s {uri: {' + scrUriName + '}}),(t {uri: {' + trgUriName + '}}) \
        CREATE (s)-[r:Trace {name: {' + relationName + '}}]->(t) \
        RETURN s,r,t';
    },
    getRelation:function (scrUriName:string, relationName:string, trgUriName:string):string{
        return 'MATCH (s {uri: {' + scrUriName + '}})-[r:Trace {name: {' + relationName + '}}]->(t {uri: {' + trgUriName + '}}) RETURN r';
    },
    getRelationsTo:function (uriName:string):string{
        return 'MATCH (s)-[r:Trace]->(t {uri: {' + uriName + '}}) RETURN s,r,t';
    },
    getRelationsFrom:function (uriName:string):string{
        return 'MATCH (s {uri: {' + uriName + '}})-[r:Trace]->(t) RETURN s,r,t';
    },
    storeNode:function(properties:Object, specifier:string){
        return 'CREATE (node:' + specifier + ' {' + getPropertyString(properties) + '}) RETURN node';
    },
    getNodeByUri:function(uriName:string):string{
        return 'MATCH (node {uri: {' + uriName + '}}) RETURN node';
    },
    modifyNode:function(properties:Object, uriName:string):string{
        var queryString:string = 'MERGE (n {uri: {' + uriName + '}}) ON MATCH SET ';
        for (var key in properties){
            queryString = queryString +  'n.' + key + '= {' + key + '}, ';
        }
        return queryString.substring(0, queryString.length - 2);
    }
}

function getPropertyString(params:Object):string{
    var propertyString = '';
    for (var key in params){
        propertyString = propertyString +  key + ': {' + key + '}, ';
    }
    return propertyString.substring(0, propertyString.length - 2);
}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NDesk.Options;
using Nito.AsyncEx;
using NLog;
using UITS.Box.Collaborations.IO;

namespace UITS.Box.Collaborations
{
    public class Program
    {
        private static Logger Log = LogManager.GetCurrentClassLogger();

        static void Main(string[] args)
        {
            string[] roles = {"owner", "member"};

            string inPath = null;
            string role = null;
            string outPath = null;
            string accesstoken = null;
            string username = null;
            var domains = new string[0];
            bool showHelp = false;

            var p = new OptionSet
            {
                {"t|token=", "Required. A Box Access {TOKEN} with enterprise management capability", t => accesstoken = t},
                {"u|username:", "Required if 'userfile' not set. A single {USERNAME} for which to show Box collaboration information", u => username = u },
                {"i|userfile:", "Required if 'username' not set. A file {PATH} containing a comma- or newline-separated list of usernames for which to show Box collaboration information", i => inPath = i},
                {"o|outpath=", "Required. A destination {PATH} for the collaboration results. If none provided, results will be written to the console.", o => outPath = o},
                {"r|role:", "Optional. Accepted values: owner, member. Default: member. Choosing 'owner' {ROLE} will record the members and folder names of all collaborations for which this user is in the 'owner' role. Choosing 'member' will record the owners and folder names of all collaborations for which this user is in any role other than 'owner'.", r => role = r ?? "member"},
                {"d|domains:", "Optional. Default: all domains. A comma-separated white list of {DOMAINS} for which collaboration members should be recorded.", d => domains = d.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).ToArray()},
                {"h|help", "show this message and exit", h => showHelp = (h != null)},
            };

            try
            {
                p.Parse(args);

                if (showHelp
                    || string.IsNullOrWhiteSpace(accesstoken)
                    || (string.IsNullOrWhiteSpace(inPath) && string.IsNullOrWhiteSpace(username))
                    || !roles.Any(r => r.Equals(role, StringComparison.InvariantCultureIgnoreCase)))
                {
                    Console.Out.WriteLine("showhelp: " + showHelp.ToString());
                    Console.Out.WriteLine("inPath: " + (inPath??"none"));
                    Console.Out.WriteLine("username: " + (username??"none"));
                    Console.Out.WriteLine("role: " + (role??"none"));
                    ShowHelp(p);
                    return;
                }
            }
            catch (OptionException e)
            {
                ShowHelp(p);
                return;
            }

            AsyncContext.Run(() => Do(accesstoken, username, role, inPath, outPath, domains));
        }

        static void ShowHelp(OptionSet p)
        {
            Console.WriteLine("Usage: collaborations -t <token> [-u <username> -i <infile> -o <outfile> -h]");
            Console.WriteLine("Gather ");
            Console.WriteLine("If no message is specified, a generic greeting is used.");
            Console.WriteLine();
            Console.WriteLine("Options:");
            p.WriteOptionDescriptions(Console.Out);
        }

        public static async Task Do(string accessToken, string username, string role, string inPath, string outPath, string[] domainWhitelist)
        {
            try
            {
                // Get a list of logins from the 'inPath' if a 'username' hasn't been specified.
                var allLogins = username == null
                    ? await Parser.GetLoginsFromFile(inPath)
                    : new List<string>() { username };

                var logins = allLogins.Distinct().ToList();

                Log.Info("Gathering collaboration info for {0} logins in the '{1}' role.", logins.Count, role);
                Log.Info("Results will be written to {0}.", outPath);

                await ResultsWriter.WriteHeaderAsync(outPath);
                var boxClient = new BoxClient(accessToken, outPath);
                await boxClient.RecordCollaborationsAsync(outPath, logins, domainWhitelist, role);
            }
            catch (Exception e)
            {
                Log.Fatal("Failed to record collaborations", e);
            }
        }
    }

    internal class AuthorizationExpiredException : Exception
    {
    }
}


text:
#pragma once
#include <aws/ec2/EC2_EXPORTS.h>
#include <aws/ec2/EC2Request.h>
#include <aws/core/utils/memory/stl/AWSString.h>
#include <aws/ec2/model/Storage.h>
#include <utility>

namespace Aws
{
namespace EC2
{
namespace Model
{

  /**
   *
Contains the parameters for BundleInstance.

See Also:
   AWS
   * API Reference

   */
  class AWS_EC2_API BundleInstanceRequest : public EC2Request
  {
  public:
    BundleInstanceRequest();
    Aws::String SerializePayload() const override;

  protected:
    void DumpBodyToUrl(Aws::Http::URI& uri ) const override;

  public:
    /**
     *
Checks whether you have the required permissions for the action, without
     * actually making the request, and provides an error response. If you have the
     * required permissions, the error response is DryRunOperation.
     * Otherwise, it is UnauthorizedOperation.

     */
    inline bool GetDryRun() const{ return m_dryRun; }

    /**
     *
Checks whether you have the required permissions for the action, without
     * actually making the request, and provides an error response. If you have the
     * required permissions, the error response is DryRunOperation.
     * Otherwise, it is UnauthorizedOperation.

     */
    inline void SetDryRun(bool value) { m_dryRunHasBeenSet = true; m_dryRun = value; }

    /**
     *
Checks whether you have the required permissions for the action, without
     * actually making the request, and provides an error response. If you have the
     * required permissions, the error response is DryRunOperation.
     * Otherwise, it is UnauthorizedOperation.

     */
    inline BundleInstanceRequest& WithDryRun(bool value) { SetDryRun(value); return *this;}

    /**
     *
The ID of the instance to bundle.

Type: String

Default:
     * None

Required: Yes

     */
    inline const Aws::String& GetInstanceId() const{ return m_instanceId; }

    /**
     *
The ID of the instance to bundle.

Type: String

Default:
     * None

Required: Yes

     */
    inline void SetInstanceId(const Aws::String& value) { m_instanceIdHasBeenSet = true; m_instanceId = value; }

    /**
     *
The ID of the instance to bundle.

Type: String

Default:
     * None

Required: Yes

     */
    inline void SetInstanceId(Aws::String&& value) { m_instanceIdHasBeenSet = true; m_instanceId = std::move(value); }

    /**
     *
The ID of the instance to bundle.

Type: String

Default:
     * None

Required: Yes

     */
    inline void SetInstanceId(const char* value) { m_instanceIdHasBeenSet = true; m_instanceId.assign(value); }

    /**
     *
The ID of the instance to bundle.

Type: String

Default:
     * None

Required: Yes

     */
    inline BundleInstanceRequest& WithInstanceId(const Aws::String& value) { SetInstanceId(value); return *this;}

    /**
     *
The ID of the instance to bundle.

Type: String

Default:
     * None

Required: Yes

     */
    inline BundleInstanceRequest& WithInstanceId(Aws::String&& value) { SetInstanceId(std::move(value)); return *this;}

    /**
     *
The ID of the instance to bundle.

Type: String

Default:
     * None

Required: Yes

     */
    inline BundleInstanceRequest& WithInstanceId(const char* value) { SetInstanceId(value); return *this;}

    /**
     *
The bucket in which to store the AMI. You can specify a bucket that you
     * already own or a new bucket that Amazon EC2 creates on your behalf. If you
     * specify a bucket that belongs to someone else, Amazon EC2 returns an error.

     */
    inline const Storage& GetStorage() const{ return m_storage; }

    /**
     *
The bucket in which to store the AMI. You can specify a bucket that you
     * already own or a new bucket that Amazon EC2 creates on your behalf. If you
     * specify a bucket that belongs to someone else, Amazon EC2 returns an error.

     */
    inline void SetStorage(const Storage& value) { m_storageHasBeenSet = true; m_storage = value; }

    /**
     *
The bucket in which to store the AMI. You can specify a bucket that you
     * already own or a new bucket that Amazon EC2 creates on your behalf. If you
     * specify a bucket that belongs to someone else, Amazon EC2 returns an error.

     */
    inline void SetStorage(Storage&& value) { m_storageHasBeenSet = true; m_storage = std::move(value); }

    /**
     *
The bucket in which to store the AMI. You can specify a bucket that you
     * already own or a new bucket that Amazon EC2 creates on your behalf. If you
     * specify a bucket that belongs to someone else, Amazon EC2 returns an error.

     */
    inline BundleInstanceRequest& WithStorage(const Storage& value) { SetStorage(value); return *this;}

    /**
     *
The bucket in which to store the AMI. You can specify a bucket that you
     * already own or a new bucket that Amazon EC2 creates on your behalf. If you
     * specify a bucket that belongs to someone else, Amazon EC2 returns an error.

     */
    inline BundleInstanceRequest& WithStorage(Storage&& value) { SetStorage(std::move(value)); return *this;}

  private:
    bool m_dryRun;
    bool m_dryRunHasBeenSet;
    Aws::String m_instanceId;
    bool m_instanceIdHasBeenSet;
    Storage m_storage;
    bool m_storageHasBeenSet;
  };

} // namespace Model
} // namespace EC2
} // namespace Aws


text:
/*
 JSHINT is a global function. It takes two parameters.

     var myResult = JSHINT(source, option);

 The first parameter is either a string or an array of strings. If it is a
 string, it will be split on '\n' or '\r'. If it is an array of strings, it
 is assumed that each string represents one line. The source can be a
 JavaScript text or a JSON text.

 The second parameter is an optional object of options which control the
 operation of JSHINT. Most of the options are booleans: They are all
 optional and have a default value of false. One of the options, predef,
 can be an array of names, which will be used to declare global variables,
 or an object whose keys are used as global names, with a boolean value
 that determines if they are assignable.

 If it checks out, JSHINT returns true. Otherwise, it returns false.

 If false, you can inspect JSHINT.errors to find out the problems.
 JSHINT.errors is an array of objects containing these members:

 {
     line      : The line (relative to 1) at which the lint was found
     character : The character (relative to 1) at which the lint was found
     reason    : The problem
     evidence  : The text line in which the problem occurred
     raw       : The raw message before the details were inserted
     a         : The first detail
     b         : The second detail
     c         : The third detail
     d         : The fourth detail
 }

 If a fatal error was found, a null will be the last element of the
 JSHINT.errors array.

 You can request a data structure which contains JSHint's results.

     var myData = JSHINT.data();

 It returns a structure with this form:

 {
     errors: [
         {
             line: NUMBER,
             character: NUMBER,
             reason: STRING,
             evidence: STRING
         }
     ],
     functions: [
         name: STRING,
         line: NUMBER,
         character: NUMBER,
         last: NUMBER,
         lastcharacter: NUMBER,
         param: [
             STRING
         ],
         closure: [
             STRING
         ],
         var: [
             STRING
         ],
         exception: [
             STRING
         ],
         outer: [
             STRING
         ],
         unused: [
             STRING
         ],
         global: [
             STRING
         ],
         label: [
             STRING
         ]
     ],
     globals: [
         STRING
     ],
     member: {
         STRING: NUMBER
     },
     unused: [
         {
             name: STRING,
             line: NUMBER
         }
     ],
     implieds: [
         {
             name: STRING,
             line: NUMBER
         }
     ],
     urls: [
         STRING
     ],
     json: BOOLEAN
 }

 Empty arrays will not be included.

*/

/*jshint
 evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,
 undef: true, maxlen: 100, indent: 4, quotmark: double, unused: true
*/

/*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
 "(breakage)", "(character)", "(context)", "(error)", "(explicitNewcap)", "(global)",
 "(identifier)", "(last)", "(lastcharacter)", "(line)", "(loopage)", "(metrics)",
 "(name)", "(onevar)", "(params)", "(scope)", "(statement)", "(verb)", "(tokens)", "(catch)",
 "*", "+", "++", "-", "--", "\/", "<", "<=", "==",
 "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,
 __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio,
 Autocompleter, Asset, Boolean, Builder, Buffer, Browser, Blob, COM, CScript, Canvas,
 CustomAnimation, Class, Control, ComplexityCount, Chain, Color, Cookie, Core, DataView, Date,
 Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMEvent, DOMReady, DOMParser,
 Drag, E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,
 Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,
 FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey,
 HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement,
 HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement,
 HTMLDivElement, HTMLDListElement, HTMLFieldSetElement,
 HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement,
 HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement,
 HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement,
 HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement,
 HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement,
 HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement,
 HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement,
 HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement,
 HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement,
 HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement,
 HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement,
 Iframe, IframeShim, Image, importScripts, Int16Array, Int32Array, Int8Array,
 Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,
 MAX_VALUE, MIN_VALUE, Map, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort,
 MoveAnimation, MooTools, MutationObserver, NaN, Native, NEGATIVE_INFINITY, Node, NodeFilter,
 Number, Object, ObjectRange,
 Option, Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype,
 RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation, Set,
 SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,
 ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,
 Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables,
 SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,
 Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL,
 VBArray, WeakMap, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer,
 XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult,
 "\\", a, abs, addEventListener, address, alert, apply, applicationCache, arguments, arity,
 asi, atob, b, basic, basicToken, bitwise, blacklist, block, blur, boolOptions, boss,
 browser, btoa, c, call, callee, caller, camelcase, cases, charAt, charCodeAt, character,
 clearInterval, clearTimeout, close, closed, closure, comment, complexityCount, condition,
 confirm, console, constructor, content, couch, create, css, curly, d, data, datalist, dd, debug,
 decodeURI, decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
 dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent, elem,
 eqeq, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil,
 ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus, forEach,
 forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions,
 g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict,
 hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include,
 indent, indexOf, init, ins, internals, instanceOf, isAlpha, isApplicationRunning, isArray,
 isDigit, isFinite, isNaN, iterator, java, join, jshint,
 JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastcharacter, lastsemic, laxbreak,
 laxcomma, latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
 log, loopfunc, m, match, max, maxcomplexity, maxdepth, maxerr, maxlen, maxstatements, maxparams,
 member, message, meta, module, moveBy, moveTo, mootools, multistr, name, navigator, new, newcap,
 nestedBlockDepth, noarg, node, noempty, nomen, nonew, nonstandard, nud, onbeforeunload, onblur,
 onerror, onevar, onecase, onfocus, onload, onresize, onunload, open, openDatabase, openURL,
 opener, opera, options, outer, param, parent, parseFloat, parseInt, passfail, plusplus,
 postMessage, pop, predef, print, process, prompt, proto, prototype, prototypejs, provides, push,
 quit, quotmark, range, raw, reach, reason, regexp, readFile, readUrl, regexdash,
 removeEventListener, replace, report, require, reserved, resizeBy, resizeTo, resolvePath,
 resumeUpdates, respond, rhino, right, runCommand, scroll, scope, screen, scripturl, scrollBy,
 scrollTo, scrollbar, search, seal, self, send, serialize, sessionStorage, setInterval, setTimeout,
 setter, setterToken, shift, slice, smarttabs, sort, spawn, split, statement, statementCount, stack,
 status, start, strict, sub, substr, supernew, shadow, supplant, sum, sync, test, toLowerCase,
 toString, toUpperCase, toint32, token, tokens, top, trailing, type, typeOf, Uint16Array,
 Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis, value, valueOf, var, vars,
 version, verifyMaxParametersPerFunction, verifyMaxStatementsPerFunction,
 verifyMaxComplexityPerFunction, verifyMaxNestedBlockDepthPerFunction, WebSocket, withstmt, white,
 window, windows, Worker, worker, wsh, yui, YUI, Y, YUI_config*/

/*global exports: false */

// We build the application inside a function so that we produce only a single
// global variable. That function will be invoked immediately, and its return
// value is the JSHINT function itself.

var JSHINT = (function () {
    "use strict";

    var anonname,       // The guessed name for anonymous functions.

// These are operators that should not be used with the ! operator.

        bang = {
            "<"  : true,
            "<=" : true,
            "==" : true,
            "===": true,
            "!==": true,
            "!=" : true,
            ">"  : true,
            ">=" : true,
            "+"  : true,
            "-"  : true,
            "*"  : true,
            "/"  : true,
            "%"  : true
        },

        // These are the JSHint boolean options.
        boolOptions = {
            asi         : true, // if automatic semicolon insertion should be tolerated
            bitwise     : true, // if bitwise operators should not be allowed
            boss        : true, // if advanced usage of assignments should be allowed
            browser     : true, // if the standard browser globals should be predefined
            camelcase   : true, // if identifiers should be required in camel case
            couch       : true, // if CouchDB globals should be predefined
            curly       : true, // if curly braces around all blocks should be required
            debug       : true, // if debugger statements should be allowed
            devel       : true, // if logging globals should be predefined (console,
                                // alert, etc.)
            dojo        : true, // if Dojo Toolkit globals should be predefined
            eqeqeq      : true, // if === should be required
            eqnull      : true, // if == null comparisons should be tolerated
            es5         : true, // if ES5 syntax should be allowed
            esnext      : true, // if es.next specific syntax should be allowed
            evil        : true, // if eval should be allowed
            expr        : true, // if ExpressionStatement should be allowed as Programs
            forin       : true, // if for in statements must filter
            funcscope   : true, // if only function scope should be used for scope tests
            globalstrict: true, // if global "use strict"; should be allowed (also
                                // enables 'strict')
            immed       : true, // if immediate invocations must be wrapped in parens
            iterator    : true, // if the `__iterator__` property should be allowed
            jquery      : true, // if jQuery globals should be predefined
            lastsemic   : true, // if semicolons may be ommitted for the trailing
                                // statements inside of a one-line blocks.
            latedef     : true, // if the use before definition should not be tolerated
            laxbreak    : true, // if line breaks should not be checked
            laxcomma    : true, // if line breaks should not be checked around commas
            loopfunc    : true, // if functions should be allowed to be defined within
                                // loops
            mootools    : true, // if MooTools globals should be predefined
            multistr    : true, // allow multiline strings
            newcap      : true, // if constructor names must be capitalized
            noarg       : true, // if arguments.caller and arguments.callee should be
                                // disallowed
            node        : true, // if the Node.js environment globals should be
                                // predefined
            noempty     : true, // if empty blocks should be disallowed
            nonew       : true, // if using `new` for side-effects should be disallowed
            nonstandard : true, // if non-standard (but widely adopted) globals should
                                // be predefined
            nomen       : true, // if names should be checked
            onevar      : true, // if only one var statement per function should be
                                // allowed
            onecase     : true, // if one case switch statements should be allowed
            passfail    : true, // if the scan should stop on first error
            plusplus    : true, // if increment/decrement should not be allowed
            proto       : true, // if the `__proto__` property should be allowed
            prototypejs : true, // if Prototype and Scriptaculous globals should be
                                // predefined
            regexdash   : true, // if unescaped first/last dash (-) inside brackets
                                // should be tolerated
            regexp      : true, // if the . should not be allowed in regexp literals
            rhino       : true, // if the Rhino environment globals should be predefined
            undef       : true, // if variables should be declared before used
            unused      : true, // if variables should be always used
            scripturl   : true, // if script-targeted URLs should be tolerated
            shadow      : true, // if variable shadowing should be tolerated
            smarttabs   : true, // if smarttabs should be tolerated
                                // (http://www.emacswiki.org/emacs/SmartTabs)
            strict      : true, // require the "use strict"; pragma
            sub         : true, // if all forms of subscript notation are tolerated
            supernew    : true, // if `new function () { ... };` and `new Object;`
                                // should be tolerated
            trailing    : true, // if trailing whitespace rules apply
            validthis   : true, // if 'this' inside a non-constructor function is valid.
                                // This is a function scoped option only.
            withstmt    : true, // if with statements should be allowed
            white       : true, // if strict whitespace rules apply
            worker      : true, // if Web Worker script symbols should be allowed
            wsh         : true, // if the Windows Scripting Host environment globals
                                // should be predefined
            yui         : true  // YUI variables should be predefined
        },

        // These are the JSHint options that can take any value
        // (we use this object to detect invalid options)
        valOptions = {
            maxlen       : false,
            indent       : false,
            maxerr       : false,
            predef       : false,
            quotmark     : false, //'single'|'double'|true
            scope        : false,
            maxstatements: false, // {int} max statements per function
            maxdepth     : false, // {int} max nested block depth per function
            maxparams    : false, // {int} max params per function
            maxcomplexity: false  // {int} max cyclomatic complexity per function
        },

        // These are JSHint boolean options which are shared with JSLint
        // where the definition in JSHint is opposite JSLint
        invertedOptions = {
            bitwise     : true,
            forin       : true,
            newcap      : true,
            nomen       : true,
            plusplus    : true,
            regexp      : true,
            undef       : true,
            white       : true,

            // Inverted and renamed, use JSHint name here
            eqeqeq      : true,
            onevar      : true
        },

        // These are JSHint boolean options which are shared with JSLint
        // where the name has been changed but the effect is unchanged
        renamedOptions = {
            eqeq        : "eqeqeq",
            vars        : "onevar",
            windows     : "wsh"
        },

        // browser contains a set of global names which are commonly provided by a
        // web browser environment.
        browser = {
            ArrayBuffer              :  false,
            ArrayBufferView          :  false,
            Audio                    :  false,
            Blob                     :  false,
            addEventListener         :  false,
            applicationCache         :  false,
            atob


text:
[![build status](https://secure.travis-ci.org/mjackson/expect.png)](http://travis-ci.org/mjackson/expect)

[expect](https://github.com/mjackson/expect) is a thin wrapper around node's [assert](http://nodejs.org/api/assert.html) module that lets you write better assertions.

When you use expect, you write assertions similarly to how you would say them, e.g. "I expect this value to be equal to 3" or "I expect this array to contain 3". When you write assertions in this way, you don't need to remember the order of actual and expected arguments to functions like `assert.equal`, which helps you write better tests.

### Usage

#### expect(object).toBe(value, [message])

Asserts that `object` is strictly equal to `value` using [assert.strictEqual](http://nodejs.org/api/assert.html#assert_assert_strictequal_actual_expected_message).

#### expect(object).toNotBe(value, [message])

Asserts that `object` is not strictly equal to `value` using [assert.notStrictEqual](http://nodejs.org/api/assert.html#assert_assert_notstrictequal_actual_expected_message).

#### expect(object).toEqual(value, [message])

Asserts that the given `object` equals `value` using [assert.equal](http://nodejs.org/api/assert.html#assert_assert_equal_actual_expected_message).

#### expect(object).toNotEqual(value, [message])

Asserts that the given `object` is not equal to `value` using [assert.notEqual](http://nodejs.org/api/assert.html#assert_assert_notequal_actual_expected_message).

#### expect(block).toThrow([error], [message])

Asserts that the given `block` throws an error using [assert.throws](http://nodejs.org/api/assert.html#assert_assert_throws_block_error_message). The `error` argument may be a constructor, `RegExp`, or validation function.

```js
expect(function () {
  throw new Error('boom!');
}).toThrow(/boom/);
```

#### expect(block).toNotThrow([message])

Asserts that the given `block` does not throw using [assert.doesNotThrow](http://nodejs.org/api/assert.html#assert_assert_doesnotthrow_block_message).

#### expect(object).toBeA(constructor, [message])

Asserts the given `object` is an `instanceof constructor`.

```js
expect(new User).toBeA(User);
```

#### expect(string).toMatch(pattern, [message])

Asserts the given `string` matches `pattern`, which must be a `RegExp`.

```js
expect('a string').toMatch(/string/);
```

#### expect(number).toBeLessThan(value, [message])

Asserts the given `number` is less than `value`.

```js
expect(2).toBeLessThan(3);
```

#### expect(number).toBeGreaterThan(value, [message])

Asserts the given `number` is greater than `value`.

```js
expect(3).toBeGreaterThan(2);
```

#### expect(array).toInclude(value, [comparator], [message])

Asserts the given `array` contains `value`. The `comparator` function, if given, should compare two objects and either `return false` or `throw` if they are not equal. It defaults to `assert.deepEqual`.

```js
expect([ 1, 2, 3 ]).toInclude(3);
```

#### expect(array).toExclude(value, [comparator], [message])

Asserts the given `array` does not contain `value`. The `comparator` function, if given, should compare two objects and either `return false` or `throw` if they are not equal. It defaults to `assert.deepEqual`.

```js
expect([ 1, 2, 3 ]).toExclude(4);
```

### Installation

Using [npm](https://www.npmjs.org/):

    $ npm install expect

### Issues

Please file issues on the [issue tracker on GitHub](https://github.com/mjackson/expect/issues).

### Tests

To run the tests in node:

    $ npm install
    $ npm test

### License

[MIT](http://opensource.org/licenses/MIT)


text:
..
   Copyright 2012-2014, Continuuity, Inc.

   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.

.. _guide_admin_toplevel:

=======================
Deployment
=======================

Logical Deployment
===================

.. figure:: logical-deployment.png
    :align: center
    :width: 800px
    :alt: Logical Deployment
    :figclass: align-center


text:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace FiddlerToPostman
{
    public class Utilities
    {
        public static string ToJSONString(object obj)
        {
            string jsonString = "";
            List<string> stringSegments = new List<string>();

            PropertyInfo[] propertyInfoList = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            if (propertyInfoList != null)
            {
                foreach (PropertyInfo propertyInfo in propertyInfoList)
                {
                    if (propertyInfo.DeclaringType != typeof(object))
                    {
                        var propertyValue = propertyInfo.GetValue(obj, null);

                        if (propertyValue != null)
                        {
                            if (propertyInfo.PropertyType.GetInterface("IEnumerable") != null)
                            {
                                if (propertyInfo.PropertyType.Name.ToLower() != "string")
                                {
                                    List<string> listItems = new List<string>();

                                    foreach (object item in (Array)propertyValue)
                                    {
                                        if (item.GetType().Name.ToLower() != "string")
                                        {
                                            if (item.GetType().IsClass)
                                            {
                                                listItems.Add(ToJSONString(item));
                                            }
                                            else
                                            {
                                                listItems.Add(item.ToString());
                                            }
                                        }
                                        else
                                        {
                                            listItems.Add(string.Format("\"{0}\"", item));
                                        }
                                    }

                                    if (listItems.Count > 0)
                                    {
                                        stringSegments.Add(string.Format("\"{0}\":[{1}]", propertyInfo.Name, string.Join(",", listItems.ToArray())));
                                    }
                                }
                                else
                                {
                                    stringSegments.Add(string.Format("\"{0}\":\"{1}\"", propertyInfo.Name, propertyValue.ToString().Replace("\"", "\\\"")));
                                }
                            }
                            else
                            {
                                if (propertyInfo.PropertyType.IsClass)
                                {
                                    stringSegments.Add(string.Format("\"{0}\":{1}", propertyInfo.Name, ToJSONString(propertyValue)));
                                }
                                else
                                {
                                    stringSegments.Add(string.Format("\"{0}\":{1}", propertyInfo.Name, propertyValue.ToString().ToLower()));
                                }
                            }
                        }
                    }
                }

                if (stringSegments.Count > 0)
                {
                    jsonString = "{" + string.Join(",", stringSegments.ToArray()) + "}";
                }
            }

            return jsonString;
        }
    }
}