text:
dojo.provide("dojox.data.jsonPathStore");
dojo.require("dojox.jsonPath");
dojo.require("dojo.date");
dojo.require("dojo.date.locale");
dojo.require("dojo.date.stamp");

dojox.data.ASYNC_MODE = 0;
dojox.data.SYNC_MODE = 1;

dojo.declare("dojox.data.jsonPathStore",
        //      summary:
        //              The jsonPathStore implements dojo.data.read, write, notify, and identity api's.  It is a local (in memory) store
	//		and can take a javascript object with any arbitrary format and attach to it to provide a dojo.data interface to that object
	//		data.  It uses jsonPath as the query language to search agains this store.
	null,
	{
		mode: dojox.data.ASYNC_MODE,
		metaLabel: "_meta",
		hideMetaAttributes: false,
		autoIdPrefix: "_auto_",
		autoIdentity: true,
		idAttribute: "_id",
		indexOnLoad: true,
		labelAttribute: "",
		url: "",
		_replaceRegex: /\'\]/gi,

		constructor: function(options){
			//summary:
			//	jsonPathStore constructor, instantiate a new jsonPathStore
			//
			//	Takes a single optional parameter in the form of a Javascript object
			//	containing one or more of the following properties.
			//
			//	data: /*JSON String*/ || /* Javascript Object */,
			//		JSON String or Javascript object this store will control
			//		JSON is converted into an object, and an object passed to
			//		the store will be used directly.  If no data and no url
			//		is provide, an empty object, {}, will be used as the initial
			//		store.
			//
			//	url: /* string url */
			//		Load data from this url in JSON format and use the Object
			//		created from the data as the data source.
			//
			//	indexOnLoad: /* boolean */
			//		Defaults to true, but this may change in the near future.
			//		Parse the data object and set individual objects up as
			//		appropriate.  This will add meta data and assign
			//		id's to objects that dont' have them as defined by the
			//		idAttribute option.  Disabling this option will keep this
			//		parsing from happening until a query is performed at which
			//		time only the top level of an item has meta info stored.
			//		This might work in some situations, but you will almost
			//		always want to indexOnLoad or use another option which
			//		will create an index.  In the future we will support a
			//		generated index that maps by jsonPath allowing the
			//		server to take some of this load for larger data sets.
			//
			//	idAttribute: /* string */
			//		Defaults to '_id'. The name of the attribute that holds an objects id.
			//		This can be a preexisting id provided by the server.
			//		If an ID isn't already provided when an object
			//		is fetched or added to the store, the autoIdentity system
			//		will generate an id for it and add it to the index. There
			//		are utility routines for exporting data from the store
			//		that can clean any generated IDs before exporting and leave
			//		preexisting id's in tact.
			//
			//	metaLabel: /* string */
			//		Defaults to '_meta' overrides the attribute name that is used by the store
			//		for attaching meta information to an object while
			//		in the store's control.  Defaults to '_meta'.
			//
			//	hideMetaAttributes: /* boolean */
			//		Defaults to False.  When enabled, calls to getAttributes() will not
			//		include the meta attribute.
			//
			//	autoIdPrefix: /*string*/
			//		Defaults to "_auto_".  This string is used as the prefix to any
			//		objects which have a generated id. A numeric index is appended
			//		to this string to complete the ID
			//
			//	mode: dojox.data.ASYNC_MODE || dojox.data.SYNC_MODE
			//		Defaults to ASYNC_MODE.  This option sets the default mode for this store.
			//		Sync calls return their data immediately from the calling function
			//		instead of calling the callback functions.  Functions such as
			//		fetchItemByIdentity() and fetch() both accept a string parameter in addtion
			//		to the normal keywordArgs parameter.  When passed this option, SYNC_MODE will
			//		automatically be used even when the default mode of the system is ASYNC_MODE.
			//		A normal request to fetch or fetchItemByIdentity (with kwArgs object) can also
			//		include a mode property to override this setting for that one request.

			//setup a byId alias to the api call
			this.byId=this.fetchItemByIdentity;

			if (options){
				dojo.mixin(this,options);
			}

			this._dirtyItems=[];
			this._autoId=0;
			this._referenceId=0;
			this._references={};
			this._fetchQueue=[];
			this.index={};

			//regex to identify when we're travelling down metaObject (which we don't want to do)
			var expr="("+this.metaLabel+"\'\])";
			this.metaRegex = new RegExp(expr);

			//no data or url, start with an empty object for a store
			if (!this.data && !this.url){
				this.setData({});
			}

			//we have data, but no url, set the store as the data
			if (this.data && !this.url){
				this.setData(this.data);

				//remove the original refernce, we're now using _data from here on out
				delete this.data;
			}

			//given a url, load json data from as the store
			if (this.url){
				dojo.xhrGet({
					url: options.url,
					handleAs: "json",
					load: dojo.hitch(this, "setData"),
					sync: this.mode
				});
			}
		},

		_loadData: function(data){
			// summary:
			//	load data into the store. Index it if appropriate.
			if (this._data){
				delete this._data;
			}

			if (dojo.isString(data)){
				this._data = dojo.fromJson(data);
			}else{
				this._data = data;
			}

			if (this.indexOnLoad){
				this.buildIndex();
			}

			this._updateMeta(this._data, {path: "$"});

			this.onLoadData(this._data);
		},

		onLoadData: function(data){
			// summary
			//	Called after data has been loaded in the store.
			//	If any requests happened while the startup is happening
			//	then process them now.

			while (this._fetchQueue.length>0){
				var req = this._fetchQueue.shift();
				this.fetch(req);
			}

		},

		setData: function(data){
			// summary:
			//	set the stores' data to the supplied object and then
			//	load and/or setup that data with the required meta info
			this._loadData(data);
		},

		buildIndex: function(path, item){
			//summary:
			//	parse the object structure, and turn any objects into
			//	jsonPathStore items. Basically this just does a recursive
			//	series of fetches which itself already examines any items
			//	as they are retrieved and setups up the required meta information.
			//
			//	path: /* string */
			//		jsonPath Query for the starting point of this index construction.

			if (!this.idAttribute){
				throw new Error("buildIndex requires idAttribute for the store");
			}

			item = item || this._data;
			var origPath = path;
			path = path||"$";
			path += "[*]";
			var data = this.fetch({query: path,mode: dojox.data.SYNC_MODE});
			for(var i=0; i<data.length;i++){
				var parts, attribute;
				if(dojo.isObject(data[i])){
					var newPath = data[i][this.metaLabel]["path"];
					if (origPath){
						//console.log("newPath: ", newPath);
						//console.log("origPath: ", origPath);
						//console.log("path: ", path);
						//console.log("data[i]: ", data[i]);
						parts = origPath.split("\[\'");
						attribute = parts[parts.length-1].replace(this._replaceRegex,'');
						//console.log("attribute: ", attribute);
						//console.log("ParentItem: ", item, attribute);
						if (!dojo.isArray(data[i])){
							this._addReference(data[i], {parent: item, attribute:attribute});
							this.buildIndex(newPath, data[i]);
						}else{
							this.buildIndex(newPath,item);
						}
					}else{
						parts = newPath.split("\[\'");
						attribute = parts[parts.length-1].replace(this._replaceRegex,'');
						this._addReference(data[i], {parent: this._data, attribute:attribute});
						this.buildIndex(newPath, data[i]);
					}
				}
			}
		},

		_correctReference: function(item){
			// summary:
			//	make sure we have an reference to the item in the store
			//	and not a clone. Takes an item, matches it to the corresponding
			//	item in the store and if it is the same, returns itself, otherwise
			//	it returns the item from the store.

			if (this.index[item[this.idAttribute]][this.metaLabel]===item[this.metaLabel]){
				return this.index[item[this.idAttribute]];
			}
			return item;
		},

		getValue: function(item, property){
			// summary:
			//	Gets the value of an item's 'property'
			//
			//	item: /* object */
			//	property: /* string */
			//		property to look up value for
			item = this._correctReference(item);
			return item[property];
		},

		getValues: function(item, property){
			// summary:
			//	Gets the value of an item's 'property' and returns
			//	it.  If this value is an array it is just returned,
			//	if not, the value is added to an array and that is returned.
			//
			//	item: /* object */
			//	property: /* string */
			//		property to look up value for

			item = this._correctReference(item);
			return dojo.isArray(item[property]) ? item[property] : [item[property]];
		},

		getAttributes: function(item){
			// summary:
			//	Gets the available attributes of an item's 'property' and returns
			//	it as an array. If the store has 'hideMetaAttributes' set to true
			//	the attributed identified by 'metaLabel' will not be included.
			//
			//	item: /* object */

			item = this._correctReference(item);
			var res = [];
			for (var i in item){
				if (this.hideMetaAttributes && (i==this.metaLabel)){continue;}
				res.push(i);
			}
			return res;
		},

		hasAttribute: function(item,attribute){
			// summary:
			//	Checks to see if item has attribute
			//
			//	item: /* object */
			//	attribute: /* string */

			item = this._correctReference(item);
			if (attribute in item){return true;}
			return false;
		},

		containsValue: function(item, attribute, value){
			// summary:
			//	Checks to see if 'item' has 'value' at 'attribute'
			//
			//	item: /* object */
			//	attribute: /* string */
			//	value: /* anything */
			item = this._correctReference(item);

			if (item[attribute] && item[attribute]==value){return true}
			if (dojo.isObject(item[attribute]) || dojo.isObject(value)){
				if (this._shallowCompare(item[attribute],value)){return true}
			}
			return false;
		},

		_shallowCompare: function(a, b){
			//summary does a simple/shallow compare of properties on an object
			//to the same named properties on the given item. Returns
			//true if all props match. It will not descend into child objects
			//but it will compare child date objects

			if ((dojo.isObject(a) && !dojo.isObject(b))|| (dojo.isObject(b) && !dojo.isObject(a))) {
				return false;
			}

			if ( a["getFullYear"] || b["getFullYear"] ){
				//confirm that both are dates
				if ( (a["getFullYear"] && !b["getFullYear"]) || (b["getFullYear"] && !a["getFullYear"]) ){
					return false;
				}else{
					if (!dojo.date.compare(a,b)){
						return true;
					}
					return false;
       				}
			}

			for (var i in b){
				if (dojo.isObject(b[i])){
					if (!a[i] || !dojo.isObject(a[i])){return false}

					if (b[i]["getFullYear"]){
						if(!a[i]["getFullYear"]){return false}
						if (dojo.date.compare(a,b)){return false}
					}else{
						if (!this._shallowCompare(a[i],b[i])){return false}
					}
				}else{
					if (!b[i] || (a[i]!=b[i])){return false}
				}
			}

			//make sure there werent props on a that aren't on b, if there aren't, then
			//the previous section will have already evaluated things.

			for (var i in a){
				if (!b[i]){return false}
			}

			return true;
		},

		isItem: function(item){
			// summary:
			//	Checks to see if a passed 'item'
			//	is really a jsonPathStore item.  Currently
			//	it only verifies structure.  It does not verify
			//	that it belongs to this store at this time.
			//
			//	item: /* object */
			//	attribute: /* string */

			if (!dojo.isObject(item) || !item[this.metaLabel]){return false}
			if (this.requireId && this._hasId && !item[this._id]){return false}
			return true;
		},

		isItemLoaded: function(item){
			// summary:
			//	returns isItem() :)
			//
			//	item: /* object */

			item = this._correctReference(item);
			return this.isItem(item);
		},

		loadItem: function(item){
			// summary:
			//	returns true. Future implementatins might alter this
			return true;
		},

		_updateMeta: function(item, props){
			// summary:
			//	verifies that 'item' has a meta object attached
			//	and if not it creates it by setting it to 'props'
			//	if the meta attribute already exists, mix 'props'
			//	into it.

			if (item && item[this.metaLabel]){
				dojo.mixin(item[this.metaLabel], props);
				return;
			}

			item[this.metaLabel]=props;
		},

		cleanMeta: function(data, options){
			// summary
			//	Recurses through 'data' and removes an
			//	meta information that has been attached. This
			//	function will also removes any id's that were autogenerated
			//	from objects.  It will not touch id's that were not generated

			data = data || this._data;

			if (data[this.metaLabel]){
				if(data[this.metaLabel]["autoId"]){
					delete data[this.idAttribute];
				}
				delete data[this.metaLabel];
			}

			if (dojo.isArray(data)){
				for(var i=0; i<data.length;i++){
					if(dojo.isObject(data[i]) || dojo.isArray(data[i]) ){
						this.cleanMeta(data[i]);
					}
				}
			} else if (dojo.isObject(data)){
				for (var i in data){
					this.cleanMeta(data[i]);
				}
			}
		},

		fetch: function(args){
			//console.log("fetch() ", args);
			// summary
			//
			//	fetch takes either a string argument or a keywordArgs
			//	object containing the parameters for the search.
			//	If passed a string, fetch will interpret this string
			//	as the query to be performed and will do so in
			//	SYNC_MODE returning the results immediately.
			//	If an object is supplied as 'args', its options will be
			// 	parsed and then contained query executed.
			//
			//	query: /* string or object */
			//		Defaults to "$..*". jsonPath query to be performed
			//		on data store. **note that since some widgets
			//		expect this to be an object, an object in the form
			//		of {query: '$[*'], queryOptions: "someOptions"} is
			//		acceptable
			//
			//	mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE
			//		Override the stores default mode.
			//
			//	queryOptions: /* object */
			//		Options passed on to the underlying jsonPath query
			//		system.
			//
			//	start: /* int */
			//		Starting item in result set
			//
			//	count: /* int */
			//		Maximum number of items to return
			//
			//	sort: /* function */
			//		Not Implemented yet
			//
			//	The following only apply to ASYNC requests (the default)
			//
			//	onBegin: /* function */
			//		called before any results are returned. Parameters
			//		will be the count and the original fetch request
			//
			//	onItem: /*function*/
			//		called for each returned item.  Parameters will be
			//		the item and the fetch request
			//
			//	onComplete: /* function */
			//		called on completion of the request.  Parameters will
			//		be the complete result set and the request
			//
			//	onError: /* function */
			//		colled in the event of an error

			// we're not started yet, add this request to a queue and wait till we do
			if (!this._data){
				this._fetchQueue.push(args);
				return args;
			}
			if(dojo.isString(args)){
					query = args;
					args={query: query, mode: dojox.data.SYNC_MODE};

			}

			var query;
			if (!args || !args.query){
				if (!args){
					var args={};
				}

				if (!args.query){
					args.query="$..*";
					query=args.query;
				}

			}

			if (dojo.isObject(args.query)){
				if (args.query.query){
					query = args.query.query;
				}else{
					query = args.query = "$..*";
				}
				if (args.query.queryOptions){
					args.queryOptions=args.query.queryOptions
				}
			}else{
				query=args.query;
			}

			if (!args.mode) {args.mode = this.mode;}
			if (!args.queryOptions) {args.queryOptions={};}

			args.queryOptions.resultType='BOTH';
			var results = dojox.jsonPath.query(this._data, query, args.queryOptions);
			var tmp=[];
			var count=0;
			for (var i=0; i<results.length; i++){
				if(args.start && i<args.start){continue;}
				if (args.count && (count >= args.count)) { continue; }

				var item = results[i]["value"];
				var path = results[i]["path"];
				if (!dojo.isObject(item)){continue;}
				if(this.metaRegex.exec(path)){continue;}

				//this automatically records the objects path
				this._updateMeta(item,{path: results[i].path});

				//if autoIdentity and no id, generate one and add it to the item
				if(this.autoIdentity && !item[this.idAttribute]){
					var newId = this.autoIdPrefix + this._autoId++;
					item[this.idAttribute]=newId;
					item[this.metaLabel]["autoId"]=true;
				}

				//add item to the item index if appropriate
				if(item[this.idAttribute]){this.index[item[this.idAttribute]]=item}
				count++;
				tmp.push(item);
			}
			results = tmp;
			var scope = args.scope || dojo.global;

			if ("sort" in args){
				console.log("TODO::add support for sorting in the fetch");
			}

			if (args.mode==dojox.data.SYNC_MODE){
				return results;
			};

			if (args.onBegin){
				args["onBegin"].call(scope, results.length, args);
			}

			if (args.onItem){
				for (var i=0; i<results.length;i++){
					args["onItem"].call(scope, results[i], args);
				}
			}

			if (args.onComplete){
				args["onComplete"].call(scope, results, args);
			}

			return args;
		},

		dump: function(options){
			// summary:
			//
			//	exports the store data set. Takes an options
			//	object with a number of parameters
			//
			//	data: /* object */
			//		Defaults to the root of the store.
		 	//		The data to be exported.
			//
			//	clone: /* boolean */
			//		clone the data set before returning it
			//		or modifying it for export
			//
			//	cleanMeta: /* boolean */
			//		clean the meta data off of the data. Note
			//		that this will happen to the actual
			//		store data if !clone. If you want
			//		to continue using the store after
			//		this operation, it is probably better to export
			//		it as a clone if you want it cleaned.
			//
			//	suppressExportMeta: /* boolean */
			//		By default, when data is exported from the store
			//		some information, such as as a timestamp, is
			//		added to the root of exported data.  This
			//		prevents that from happening.  It is mainly used
			//		for making tests easier.
			//
			//	type: "raw" || "json"
			//		Defaults to 'json'. 'json' will convert the data into
			//		json before returning it. 'raw' will just return a
			//		reference to the object

			var options = options || {};
			var d = options.data || this._data;

			if (!options.suppressExportMeta && options.clone){
				data = dojo.clone(d);
				if (data[this.metaLabel]){
					data[this.metaLabel]["clone"]=true;
				}
			}else{
				var data=d;
			}

			if (!options.suppressExportMeta &&  data[this.metaLabel]){
				data[this.metaLabel]["last_export"]=new Date().toString()
			}

			if(options.cleanMeta){
				this.cleanMeta(data);
			}

			//console.log("Exporting: ", options, dojo.toJson(data));
			switch(options.type){
				case "raw":
					return data;
				case "json":
				default:
					return dojo.toJson(data, options.pretty || false);
			}
		},

		getFeatures: function(){
			// summary:
			// 	return the store feature set

			return {
				"dojo.data.api.Read": true,
				"dojo.data.api.Identity": true,
				"dojo.data.api.Write": true,
				"dojo.data.api.Notification": true
			}
		},

		getLabel: function(item){
			// summary
			//	returns the label for an item. The label
			//	is created by setting the store's labelAttribute
			//	property with either an attribute name	or an array
			//	of attribute names.  Developers can also
			//	provide the store with a createLabel function which
			//	will do the actaul work of creating the label.  If not
			//	the default will just concatenate any of the identified
			//	attributes together.
			item = this._correctReference(item);
			var label="";

			if (dojo.isFunction(this.createLabel)){
				return this.createLabel(item);
			}

			if (this.labelAttribute){
				if (dojo.isArray(this.labelAttribute))	{
					for(var i=0; i<this.labelAttribute.length; i++){
						if (i>0) { label+=" ";}
						label += item[this.labelAttribute[i]];
					}
					return label;
				}else{
					return item[this.labelAttribute];
				}
			}
			return item.toString();
		},

		getLabelAttributes: function(item){
			// summary:
			//	returns an array of attributes that are used to create the label of an item
			item = this._correctReference(item);
			return dojo.isArray(this.labelAttribute) ? this.labelAttribute : [this.labelAttribute];
		},

		sort: function(a,b){
			console.log("TODO::implement default sort algo");
		},

		//Identity API Support

		getIdentity: function(item){
			// summary
			//	returns the identity of an item or throws
			//	a not found error.

			if (this.isItem(item)){
				return item[this.idAttribute];
			}
			throw new Error("Id not found for item");
		},

		getIdentityAttributes: function(item){
			// summary:
			//	returns the attributes which are used to make up the
			//	identity of an item.  Basically returns this.idAttribute

			return [this.idAttribute];
		},

		fetchItemByIdentity: function(args){
			// summary:
			//	fetch an item by its identity. This store also provides
			//	a much more finger friendly alias, 'byId' which does the
			//	same thing as this function.  If provided a string
			//	this call will be treated as a SYNC request and will
			//	return the identified item immediatly.  Alternatively it
			// 	takes a object as a set of keywordArgs:
			//
			//	identity: /* string */
			//		the id of the item you want to retrieve
			//
			//	mode: dojox.data.SYNC_MODE || dojox.data.ASYNC_MODE
			//		overrides the default store fetch mode
			//
			//	onItem: /* function */
			//		Result call back.  Passed the fetched item.
			//
			//	onError: /* function */
			//		error callback.
			var id;
			if (dojo.isString(args)){
				id = args;
				args = {identity: id, mode: dojox.data.SYNC_MODE}
			}else{
				if (args){
					id = args["identity"];
				}
				if (!args.mode){args.mode = this.mode}
			}

			if (this.index && (this.index[id] || this.index["identity"])){

				if (args.mode==dojox.data.SYNC_MODE){
					return this.index[id];
				}

				if (args.onItem){
					args["onItem"].call(args.scope || dojo.global, this.index[id], args);
				}

				return args;
			}else{
				if (args.mode==dojox.data.SYNC_MODE){
					return false;
				}
			}

			if(args.onError){
				args["onItem"].call(args.scope || dojo.global, new Error("Item Not Found: " + id), args);
			}

			return args;
		},

		//Write API Support
		newItem: function(data, options){
			// summary:
			//	adds a new item to the store at the specified point.
			//	Takes two parameters, data, and options.
			//
			//	data: /* object */
			//		The data to be added in as an item.  This could be a
			//		new javascript object, or it could be an item that
			//		already exists in the store.  If it already exists in the
			//		store, then this will be added as a reference.
			//
			//	options: /* object */
			//
			//		item: /* item */
			//			reference to an existing store item
			//
			//		attribute: /* string */
			//			attribute to add the item at.  If this is
			//			not provided, the item's id will be used as the
			//			attribute name. If specified attribute is an
			//			array, the new item will be push()d on to the
			//			end of it.
			//		oldValue: /* old value of item[attribute]
			//		newValue: new value item[attribute]

			var meta={};

			//default parent to the store root;
			var pInfo ={item:this._data};

			if (options){
				if (options.parent){
					options.item = options.parent;
				}

				dojo.mixin(pInfo, options);
			}

			if (this.idAttribute && !data[this.idAttribute]){
				if (this.requireId){throw new Error("requireId is enabled, new items must have an id defined to be added");}
				if (this.autoIdentity){
					var newId = this.autoIdPrefix + this._autoId++;
					data[this.idAttribute]=newId;
					meta["autoId"]=true;
				}
			}

			if (!pInfo && !pInfo.attribute && !this.idAttribute && !data[this.idAttribute]){
				throw new Error("Adding a new item requires, at a minumum, either the pInfo information, including the pInfo.attribute, or an id on the item in the field identified by idAttribute");
			}

			//pInfo.parent = this._correctReference(pInfo.parent);
			//if there is no parent info supplied, default to the store root
			//and add to the pInfo.attribute or if that doestn' exist create an
			//attribute with the same name as the new items ID
			if(!pInfo.attribute){pInfo.attribute = data[this.idAttribute]}

			pInfo.oldValue = this._trimItem(pInfo.item[pInfo.attribute]);
			if (dojo.isArray(pInfo.item[pInfo.attribute])){
				this._setDirty(pInfo.item);
				pInfo.item[pInfo.attribute].push(data);
			}else{
				this._setDirty(pInfo.item);
				pInfo.item[pInfo.attribute]=data;
			}

			pInfo.newValue = pInfo.item[pInfo.attribute];

			//add this item to the index
			if(data[this.idAttribute]){this.index[data[this.idAttribute]]=data}

			this._updateMeta(data, meta)

			//keep track of all references in the store so we can delete them as necessary
			this._addReference(data, pInfo);

			//mark this new item as dirty
			this._setDirty(data);

			//Notification API
			this.onNew(data, pInfo);

			//returns the original item, now decorated with some meta info
			return data;
		},

		_addReference: function(item, pInfo){
			// summary
			//	adds meta information to an item containing a reference id
			//	so that references can be deleted as necessary, when passed
			//	only a string, the string for parent info, it will only
			//	it will be treated as a string reference

			//console.log("_addReference: ", item, pInfo);
			var rid = '_ref_' + this._referenceId++;
			if (!item[this.metaLabel]["referenceIds"]){
				item[this.metaLabel]["referenceIds"]=[];
			}

			item[this.metaLabel]["referenceIds"].push(rid);
			this._references[rid] = pInfo;
		},

		deleteItem: function(item){
			// summary
			//	deletes item and any references to that item from the store.
			//	If the desire is to delete only one reference, unsetAttribute or
			//	setValue is the way to go.

			item = this._correctReference(item);
			console.log("Item: ", item);
			if (this.isItem(item)){
				while(item[this.metaLabel]["referenceIds"].length>0){
					console.log("refs map: " , this._references);
					console.log("item to delete: ", item);
					var rid = item[this.metaLabel]["referenceIds"].pop();
					var pInfo = this._references[rid];

					console.log("deleteItem(): ", pInfo, pInfo.parent);
					var parentItem = pInfo.parent;
					var attribute = pInfo.attribute;
					if(parentItem && parentItem[attribute] && !dojo.isArray(parentItem[attribute])){
						this._setDirty(parentItem);
						this.unsetAttribute(parentItem, attribute);
						delete parentItem[attribute];
					}

					if (dojo.isArray(parentItem[attribute])){
						console.log("Parent is array");
						var oldValue = this._trimItem(parentItem[attribute]);
						var found=false;
						for (var i=0; i<parentItem[attribute].length && !found;i++){
							if (parentItem[attribute][i][this.metaLabel]===item[this.metaLabel]){
								found=true;
							}
						}

						if (found){
							this._setDirty(parentItem);
							var del =  parentItem[attribute].splice(i-1,1);
							delete del;
						}

						var newValue = this._trimItem(parentItem[attribute]);
						this.onSet(parentItem,attribute,oldValue,newValue);
					}
					delete this._references[rid];

				}
				this.onDelete(item);
				delete item;
			}
		},

		_setDirty: function(item){
			// summary:
			//	adds an item to the list of dirty items.  This item
			//	contains a reference to the item itself as well as a
			//	cloned and trimmed version of old item for use with
			//	revert.

			//if an item is already in the list of dirty items, don't add it again
			//or it will overwrite the premodification data set.
			for (var i=0; i<this._dirtyItems.length; i++){
				if (item[this.idAttribute]==this._dirtyItems[i][this.idAttribute]){
					return;
				}
			}

			this._dirtyItems.push({item: item, old: this._trimItem(item)});
			this._updateMeta(item, {isDirty: true});
		},

		setValue: function(item, attribute, value){
			// summary:
			//	sets 'attribute' on 'item' to 'value'
			item = this._correctReference(item);

			this._setDirty(item);
			var old = item[attribute] | undefined;
			item[attribute]=value;
			this.onSet(item,attribute,old,value);

		},

		setValues: function(item, attribute, values){
			// summary:
			//	sets 'attribute' on 'item' to 'value' value
			//	must be an array.

			item = this._correctReference(item);
			if (!dojo.isArray(values)){throw new Error("setValues expects to be passed an Array object as its value");}
			this._setDirty(item);
			var old = item[attribute] || null;
			item[attribute]=values
			this.onSet(item,attribute,old,values);
		},

		unsetAttribute: function(item, attribute){
			// summary:
			//	unsets 'attribute' on 'item'

			item = this._correctReference(item);
			this._setDirty(item);
			var old = item[attribute];
			delete item[attribute];
			this.onSet(item,attribute,old,null);
		},

		save: function(kwArgs){
			// summary:
			//	Takes an optional set of keyword Args with
			//	some save options.  Currently only format with options
			//	being "raw" or "json".  This function goes through
			//	the dirty item lists, clones and trims the item down so that
			//	the items children are not part of the data (the children are replaced
			//	with reference objects). This data is compiled into a single array, the dirty objects
			//	are all marked as clean, and the new data is then passed on to the onSave handler.

			var data = [];

			if (!kwArgs){kwArgs={}}
			while (this._dirtyItems.length > 0){
				var item = this._dirtyItems.pop()["item"];
				var t = this._trimItem(item);
				var d;
				switch(kwArgs.format){
					case "json":
						d = dojo.toJson(t);
						break;
					case "raw":
					default:
						d = t;
				}
				data.push(d);
				this._markClean(item);
			}

			this.onSave(data);
		},

		_markClean: function(item){
			// summary
			//	remove this meta information marking an item as "dirty"

			if (item && item[this.metaLabel] && item[this.metaLabel]["isDirty"]){
				delete item[this.metaLabel]["isDirty"];
			}
		},

		revert: function(){
			// summary
			//	returns any modified data to its original state prior to a save();

			while (this._dirtyItems.length>0){
				var d = this._dirtyItems.pop();
				this._mixin(d.item, d.old);
			}
			this.onRevert();
		},

		_mixin: function(target, data){
			// summary:
			//	specialized mixin that hooks up objects in the store where references are identified.
			var mix;

			if (dojo.isObject(data)){
				if (dojo.isArray(data)){
					while(target.length>0){target.pop();}
					for (var i=0; i<data.length;i++){
						if (dojo.isObject(data[i])){
							if (dojo.isArray(data[i])){
								mix=[];
							}else{
								mix={};
								if (data[i][this.metaLabel] && data[i][this.metaLabel]["type"] && data[i][this.metaLabel]["type"]=='reference'){
									target[i]=this.index[data[i][this.idAttribute]];
									continue;
								}
							}

							this._mixin(mix, data[i]);
							target.push(mix);
						}else{
							target.push(data[i]);
						}
					}
				}else{
					for (var i in target){
						if (i in data){continue;}
						delete target[i];
					}

					for (var i in data){
						if (dojo.isObject(data[i])){
							if (dojo.isArray(data[i])){
								mix=[];
							}else{
								if (data[i][this.metaLabel] && data[i][this.metaLabel]["type"] && data[i][this.metaLabel]["type"]=='reference'){
									target[i]=this.index[data[i][this.idAttribute]];
									continue;
								}

								mix={};
							}
							this._mixin(mix, data[i]);
							target[i]=mix;
						}else{
							target[i]=data[i];
						}
					}

				}
			}
		},

		isDirty: function(item){
			// summary
			//	returns true if the item is marked as dirty.

			item = this._correctReference(item);
			return item && item[this.metaLabel] && item[this.metaLabel]["isDirty"];
		},

		_createReference: function(item){
			// summary
			// 	Create a small reference object that can be used to replace
			//	child objects during a trim

			var obj={};
			obj[this.metaLabel]={
				type:'reference'
			};

			obj[this.idAttribute]=item[this.idAttribute];
			return obj;
		},

		_trimItem: function(item){
			//summary:
			// 	copy an item recursively stoppying at other items that have id's
			//	and replace them with a refrence object;
			var copy;
			if (dojo.isArray(item)){
				copy = [];
				for (var i=0; i<item.length;i++){
					if (dojo.isArray(item[i])){
						copy.push(this._trimItem(item[i]))
					}else if (dojo.isObject(item[i])){
						if (item[i]["getFullYear"]){
							copy.push(dojo.date.stamp.toISOString(item[i]));
						}else if (item[i][this.idAttribute]){
							copy.push(this._createReference(item[i]));
						}else{
							copy.push(this._trimItem(item[i]));
						}
					} else {
						copy.push(item[i]);
					}
				}
				return copy;
			}

			if (dojo.isObject(item)){
				copy = {};

				for (var attr in item){
					if (!item[attr]){ copy[attr]=undefined;continue;}
					if (dojo.isArray(item[attr])){
						copy[attr] = this._trimItem(item[attr]);
					}else if (dojo.isObject(item[attr])){
						if (item[attr]["getFullYear"]){
							copy[attr] =  dojo.date.stamp.toISOString(item[attr]);
						}else if(item[attr][this.idAttribute]){
							copy[attr]=this._createReference(item[attr]);
						} else {
							copy[attr]=this._trimItem(item[attr]);
						}
					} else {
						copy[attr]=item[attr];
					}
				}
				return copy;
			}
		},

		//Notifcation Support

		onSet: function(){
		},

		onNew: function(){

		},

		onDelete: function(){

		},

		onSave: function(items){
			// summary:
			//	notification of the save event..not part of the notification api,
			//	but probably should be.
			//console.log("onSave() ", items);
		},

		onRevert: function(){
			// summary:
			//	notification of the revert event..not part of the notification api,
			//	but probably should be.

		}
	}
);

//setup an alias to byId, is there a better way to do this?
dojox.data.jsonPathStore.byId=dojox.data.jsonPathStore.fetchItemByIdentity;


text:
import com.turn.ttorrent.bcodec.BDecoder;
import com.turn.ttorrent.bcodec.InvalidBEncodingException;
import org.testng.annotations.Test;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;

public class BDecoderTest {

  @Test
  public void testDecodeNumbers() throws IOException {

    testNumber(0);
    testNumber(1);
    testNumber(Integer.MAX_VALUE);
    testNumber(1234567);
    testNumber(-1);
    testNumber(-100);
    testNumber(Integer.MIN_VALUE);
    testNumber(Long.MAX_VALUE);
    testNumber(Long.MIN_VALUE);

    //by specification number with lead zero it's incorrect value
    testBadNumber("00");
    testBadNumber("01234");
    testBadNumber("000");
    testBadNumber("0001");

  }

  private void testBadNumber(String number) throws IOException {
    try {
      BDecoder.bdecode(numberToBEPBytes(number));
    } catch (InvalidBEncodingException e) {
      return;
    }
    fail("Value " + number + " is incorrect by BEP specification but is was parsed correctly");
  }

  private void testNumber(long value) throws IOException {
    assertEquals(BDecoder.bdecode(numberToBEPBytes(value)).getLong(), value);
  }

  private ByteBuffer numberToBEPBytes(long value) throws UnsupportedEncodingException {
    return ByteBuffer.wrap(("i" + value + "e").getBytes("ASCII"));
  }

  private ByteBuffer numberToBEPBytes(String value) throws UnsupportedEncodingException {
    return ByteBuffer.wrap(("i" + value + "e").getBytes("ASCII"));
  }

}

redpajama_set_name: RedPajamaGithub


text:
<?php

final class ReleephRequestQuery
  extends PhabricatorCursorPagedPolicyAwareQuery {

  private $requestedCommitPHIDs;
  private $ids;
  private $phids;
  private $severities;
  private $requestorPHIDs;
  private $branchIDs;
  private $requestedObjectPHIDs;

  const STATUS_ALL          = 'status-all';
  const STATUS_OPEN         = 'status-open';
  const STATUS_REQUESTED    = 'status-requested';
  const STATUS_NEEDS_PULL   = 'status-needs-pull';
  const STATUS_REJECTED     = 'status-rejected';
  const STATUS_ABANDONED    = 'status-abandoned';
  const STATUS_PULLED       = 'status-pulled';
  const STATUS_NEEDS_REVERT = 'status-needs-revert';
  const STATUS_REVERTED     = 'status-reverted';

  private $status = self::STATUS_ALL;

  public function withIDs(array $ids) {
    $this->ids = $ids;
    return $this;
  }

  public function withPHIDs(array $phids) {
    $this->phids = $phids;
    return $this;
  }

  public function withBranchIDs(array $branch_ids) {
    $this->branchIDs = $branch_ids;
    return $this;
  }

  public function withStatus($status) {
    $this->status = $status;
    return $this;
  }

  public function withRequestedCommitPHIDs(array $requested_commit_phids) {
    $this->requestedCommitPHIDs = $requested_commit_phids;
    return $this;
  }

  public function withRequestorPHIDs(array $phids) {
    $this->requestorPHIDs = $phids;
    return $this;
  }

  public function withSeverities(array $severities) {
    $this->severities = $severities;
    return $this;
  }

  public function withRequestedObjectPHIDs(array $phids) {
    $this->requestedObjectPHIDs = $phids;
    return $this;
  }

  public function loadPage() {
    $table = new ReleephRequest();
    $conn_r = $table->establishConnection('r');

    $data = queryfx_all(
      $conn_r,
      'SELECT * FROM %T %Q %Q %Q',
      $table->getTableName(),
      $this->buildWhereClause($conn_r),
      $this->buildOrderClause($conn_r),
      $this->buildLimitClause($conn_r));

    return $table->loadAllFromArray($data);
  }

  public function willFilterPage(array $requests) {
    // Load requested objects: you must be able to see an object to see
    // requests for it.
    $object_phids = mpull($requests, 'getRequestedObjectPHID');
    $objects = id(new PhabricatorObjectQuery())
      ->setViewer($this->getViewer())
      ->setParentQuery($this)
      ->withPHIDs($object_phids)
      ->execute();

    foreach ($requests as $key => $request) {
      $object_phid = $request->getRequestedObjectPHID();
      $object = idx($objects, $object_phid);
      if (!$object) {
        unset($requests[$key]);
        continue;
      }
      $request->attachRequestedObject($object);
    }

    if ($this->severities) {
      $severities = array_fuse($this->severities);
      foreach ($requests as $key => $request) {

        // NOTE: Facebook uses a custom field here.
        if (ReleephDefaultFieldSelector::isFacebook()) {
          $severity = $request->getDetail('severity');
        } else {
          $severity = $request->getDetail('releeph:severity');
        }

        if (empty($severities[$severity])) {
          unset($requests[$key]);
        }
      }
    }

    $branch_ids = array_unique(mpull($requests, 'getBranchID'));
    $branches = id(new ReleephBranchQuery())
      ->withIDs($branch_ids)
      ->setViewer($this->getViewer())
      ->execute();
    $branches = mpull($branches, null, 'getID');
    foreach ($requests as $key => $request) {
      $branch = idx($branches, $request->getBranchID());
      if (!$branch) {
        unset($requests[$key]);
        continue;
      }
      $request->attachBranch($branch);
    }

    // TODO: These should be serviced by the query, but are not currently
    // denormalized anywhere. For now, filter them here instead. Note that
    // we must perform this filtering *after* querying and attaching branches,
    // because request status depends on the product.

    $keep_status = array_fuse($this->getKeepStatusConstants());
    if ($keep_status) {
      foreach ($requests as $key => $request) {
        if (empty($keep_status[$request->getStatus()])) {
          unset($requests[$key]);
        }
      }
    }

    return $requests;
  }

  private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
    $where = array();

    if ($this->ids !== null) {
      $where[] = qsprintf(
        $conn_r,
        'id IN (%Ld)',
        $this->ids);
    }

    if ($this->phids !== null) {
      $where[] = qsprintf(
        $conn_r,
        'phid IN (%Ls)',
        $this->phids);
    }

    if ($this->branchIDs !== null) {
      $where[] = qsprintf(
        $conn_r,
        'branchID IN (%Ld)',
        $this->branchIDs);
    }

    if ($this->requestedCommitPHIDs !== null) {
      $where[] = qsprintf(
        $conn_r,
        'requestCommitPHID IN (%Ls)',
        $this->requestedCommitPHIDs);
    }

    if ($this->requestorPHIDs !== null) {
      $where[] = qsprintf(
        $conn_r,
        'requestUserPHID IN (%Ls)',
        $this->requestorPHIDs);
    }

    if ($this->requestedObjectPHIDs !== null) {
      $where[] = qsprintf(
        $conn_r,
        'requestedObjectPHID IN (%Ls)',
        $this->requestedObjectPHIDs);
    }

    $where[] = $this->buildPagingClause($conn_r);

    return $this->formatWhereClause($where);
  }

  private function getKeepStatusConstants() {
    switch ($this->status) {
      case self::STATUS_ALL:
        return array();
      case self::STATUS_OPEN:
        return array(
          ReleephRequestStatus::STATUS_REQUESTED,
          ReleephRequestStatus::STATUS_NEEDS_PICK,
          ReleephRequestStatus::STATUS_NEEDS_REVERT,
        );
      case self::STATUS_REQUESTED:
        return array(
          ReleephRequestStatus::STATUS_REQUESTED,
        );
      case self::STATUS_NEEDS_PULL:
        return array(
          ReleephRequestStatus::STATUS_NEEDS_PICK,
        );
      case self::STATUS_REJECTED:
        return array(
          ReleephRequestStatus::STATUS_REJECTED,
        );
      case self::STATUS_ABANDONED:
        return array(
          ReleephRequestStatus::STATUS_ABANDONED,
        );
      case self::STATUS_PULLED:
        return array(
          ReleephRequestStatus::STATUS_PICKED,
        );
      case self::STATUS_NEEDS_REVERT:
        return array(
          ReleephRequestStatus::NEEDS_REVERT,
        );
      case self::STATUS_REVERTED:
        return array(
          ReleephRequestStatus::REVERTED,
        );
      default:
        throw new Exception("Unknown status '{$this->status}'!");
    }
  }

  public function getQueryApplicationClass() {
    return 'PhabricatorReleephApplication';
  }

}


text:
require 'rails_helper'

RSpec.describe 'OrgAutocomplete' do
  include Helpers::DmptoolHelper

  # Generic Tests for the Org Autocomplete form widget as well as tests for each
  # implementation of it throughout the site
  before do
    mock_blog
    @org = create(:org, :institution, managed: true)
    @funder = create(:org, :funder, managed: true)
    @plan = create(:plan, :creator)
    @user = @plan.owner
    @word = 'Example'

    # rubocop:disable Layout/LineLength
    @warn_with_custom = _('Please select an item from the list or check the box below and provide a name for your institution.')
    # rubocop:enable Layout/LineLength
    @warn_without_custom = _('Please select an item from the list.')

    # Sign in and go to the Edit Project Details page
    sign_in @user
  end

  it 'Setting restrict_orgs flag in config disables custom org entry', js: true do
    Rails.configuration.x.application.restrict_orgs = true
    visit plan_path(@plan)

    within('#funder-org-controls') do
      expect(find('label[for="org_autocomplete_funder_name"]').present?).to be(true)
      expect(find_by_id('org_autocomplete_funder_name').present?).to be(true)
      expect { find_by_id('org_autocomplete_funder_not_in_list') }.to raise_error(Capybara::ElementNotFound)
      expect { find_by_id('org_autocomplete_funder_user_entered_name') }.to raise_error(Capybara::ElementNotFound)
      expect(find('.autocomplete-help').present?).to be(true)

      id = find_by_id('org_autocomplete_funder_name')[:list].split('-').last
      expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
      expect(page).not_to have_text(@warn_without_custom)
      expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

      fill_in 'Funder', with: Faker::Company.unique.name
    end

    # fill in a different field to trigger the validation check
    fill_in 'Project title', with: Faker::Lorem.sentence
    expect(page).to have_text(@warn_without_custom)
  end

  context 'basic autocomplete functionality' do
    before do
      Rails.configuration.x.application.restrict_orgs = false
      sign_out @user
      visit root_path
      fill_in 'Email address', with: Faker::Internet.unique.email
      click_on 'Continue'

      expect(page).to have_text(_('Sign up'))

      @selector = '#sign-up-org'
    end

    it 'User can type in the autocomplete and see suggestions', :js do
      org = create(:org)
      # Fill in the autocomplete and then fill in another field to ensure JS runs
      select_an_org(@selector, org.name, 'Institution')
      fill_in 'First Name', with: Faker::Movies::StarWars.character
      expect(page).not_to have_text(@warn_with_custom)
    end

    it 'User can specify their own custom Org', :js do
      # Fill in the custom name and then fill in another field to ensure JS runs
      enter_custom_org(@selector, Faker::Company.name)
      fill_in 'First Name', with: Faker::Movies::StarWars.character
      expect(page).not_to have_text(@warn_with_custom)
    end

    it 'User cannot enter a custom Org in the autocomplete', :js do
      # Fill in the autocomplete and then fill in another field to ensure JS runs
      fill_in 'Institution', with: Faker::Company.name
      fill_in 'First Name', with: Faker::Movies::StarWars.character
      expect(page).to have_text(@warn_with_custom)
    end

    it 'Clear the custom Org name and unchecks the checkbox if user types in autocomplete', :js do
      # Fill in the custom name and then fill in another field to ensure JS runs
      enter_custom_org(@selector, Faker::Company.name)
      fill_in 'Institution', with: Faker::Company.unique.name
      expect(find_by_id('org_autocomplete_not_in_list', visible: false).value).not_to eql('1')
      expect(find_by_id('org_autocomplete_user_entered_name', visible: false).value).to eql('')
    end

    it 'Clear the entry in the autocomplete when user clicks checkbox', :js do
      org = create(:org)
      # Fill in the autocomplete and then fill in another field to ensure JS runs
      select_an_org(@selector, org.name, 'Institution')
      find('label[for="org_autocomplete_not_in_list"]').click
      expect(find_by_id('org_autocomplete_name').value).to eql('')
    end

    context 'validate that we can save the Org' do
      before do
        # Fill out the rest of the form
        fill_in 'First Name', with: Faker::Movies::StarWars.character.split.first
        fill_in 'Last Name', with: Faker::Movies::StarWars.character.split.last
        fill_in 'Password', with: SecureRandom.uuid
        # Need to use JS to set the accept terms label since dmptool-ui treats the
        # whole thing as a label and theis particular label has a URL so 'clicking' it
        # via Capybara results in going to the URL behind that link :/
        page.execute_script("document.getElementById('user_accept_terms').checked = true;")
      end

      it 'can save a selected name', js: true do
        original_user_count = User.all.count
        select_an_org(@selector, @org.name, 'Institution')
        click_button _('Sign up')
        expect(page).not_to have_errors
        expect(User.all.count).to eql(original_user_count + 1)
        expect(User.last.org.name).to eql(@org.name)
        sign_out User.last
      end

      it 'can save a custom name', js: true do
        original_user_count = User.all.count
        name = Faker::Movies::StarWars.unique.planet
        enter_custom_org(@selector, name)
        click_button _('Sign up')
        expect(page).not_to have_errors
        expect(User.all.count).to eql(original_user_count + 1)
        expect(User.last.org.name.downcase.capitalize).to eql(name.downcase.capitalize)
        sign_out User.last
      end
    end
  end

  context 'Individual implementations of the autocomplete', js: true do
    before do
      Rails.configuration.x.application.restrict_orgs = false
      init_orgs
    end

    context 'Sign up page implementation works' do
      it 'has used the appropriate controls and returns the expected suggestions', :js do
        # The Autocomplete on this page should allow the user to select any Orgs
        # or RegistryOrgs and allow them to create new Orgs
        sign_out @user
        visit root_path
        fill_in 'Email address', with: 'foo@bar.edu'
        click_on 'Continue'
        expect(page).to have_text(_('Sign up'))

        within('#sign-up-org') do
          # Make sure the Autocomplete controls are correct
          expect(find('label[for="org_autocomplete_name"]').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').value).to eql('')
          expect(find_by_id('org_autocomplete_not_in_list', visible: false).present?).to be(true)
          expect(find_by_id('org_autocomplete_user_entered_name', visible: false).present?).to be(true)
          expect(find('.autocomplete-help').present?).to be(true)

          id = find_by_id('org_autocomplete_name')[:list].split('-').last
          expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
          expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

          # Clear the default Org name and replace with our search term
          fill_in _('Institution'), with: ''
          fill_in _('Institution'), with: @word

          # Make sure the correct Orgs are suggested
          expect(suggestion_exists?(@org_managed.name)).to be(true)
          expect(suggestion_exists?(@funder_managed.name)).to be(true)
          expect(suggestion_exists?(@org_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@funder_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@registry_org.name)).to be(true)
          expect(suggestion_exists?(@registry_funder.name)).to be(true)
          expect(suggestion_exists?(@associated_matched.name)).to be(true)
          expect(suggestion_exists?(@associated_matched_funder.name)).to be(true)

          # Make sure the other Orgs are NOT suggested
          unmatched_never_appear?
        end
      end
    end

    context 'Edit Profile page implementation works' do
      it 'has used the appropriate controls and returns the expected suggestions', js: true do
        # The Autocomplete on this page should allow the user to select any Orgs
        # or RegistryOrgs and allow them to create new Orgs
        visit edit_user_registration_path
        expect(page).to have_text(_('Edit Profile'))

        within('#profile-controls') do
          # Make sure the Autocomplete controls are correct
          expect(find('label[for="org_autocomplete_name"]').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').value).to eql(@user.org.name)
          expect(find_by_id('org_autocomplete_not_in_list', visible: false).present?).to be(true)
          expect(find_by_id('org_autocomplete_user_entered_name', visible: false).present?).to be(true)
          expect(find('.autocomplete-help').present?).to be(true)

          id = find_by_id('org_autocomplete_name')[:list].split('-').last
          expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
          expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

          # Clear the default Org name and replace with our search term
          fill_in _('Institution'), with: ''
          fill_in _('Institution'), with: @word
          sleep(1)

          # Make sure the correct Orgs are suggested
          expect(suggestion_exists?(@org_managed.name)).to be(true)
          expect(suggestion_exists?(@funder_managed.name)).to be(true)
          expect(suggestion_exists?(@org_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@funder_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@registry_org.name)).to be(true)
          expect(suggestion_exists?(@registry_funder.name)).to be(true)
          expect(suggestion_exists?(@associated_matched.name)).to be(true)
          expect(suggestion_exists?(@associated_matched_funder.name)).to be(true)

          # Make sure the other Orgs are NOT suggested
          unmatched_never_appear?
        end
      end
    end

    context 'Contributor page implementation (all orgs)' do
      it 'has used the appropriate controls and returns the expected suggestions', js: true do
        @user.update(org_id: @plan.org.id)

        # The Autocomplete on this page should allow the user to select any Orgs
        # or RegistryOrgs and allow them to create new Orgs
        visit new_plan_contributor_path(@plan)
        expect(page).to have_text(_('New contributor'))

        within('#contributor-org-controls') do
          # Make sure the Autocomplete controls are correct
          expect(find('label[for="org_autocomplete_name"]').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').value).to eql(@plan.org.name)
          expect(find_by_id('org_autocomplete_not_in_list', visible: false).present?).to be(true)
          expect(find_by_id('org_autocomplete_user_entered_name', visible: false).present?).to be(true)
          expect(find('.autocomplete-help').present?).to be(true)

          id = find_by_id('org_autocomplete_name')[:list].split('-').last
          expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
          expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

          # Clear the default Org name and replace with our search term
          fill_in _('Affiliation'), with: ''
          fill_in _('Affiliation'), with: @word
          sleep(1)

          # Make sure the correct Orgs are suggested
          expect(suggestion_exists?(@org_managed.name)).to be(true)
          expect(suggestion_exists?(@funder_managed.name)).to be(true)
          expect(suggestion_exists?(@org_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@funder_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@registry_org.name)).to be(true)
          expect(suggestion_exists?(@registry_funder.name)).to be(true)
          expect(suggestion_exists?(@associated_matched.name)).to be(true)
          expect(suggestion_exists?(@associated_matched_funder.name)).to be(true)

          # Make sure the other Orgs are NOT suggested
          unmatched_never_appear?
        end
      end
    end

    context 'Create Plan page implementation (Research Org and Funder)' do
      it 'has the appropriate controls and returns the expected suggestions', js: true do
        # The Autocompletes on this page should:
        #   Research Org: only allow known Orgs (no unassociated RegistryOrgs) and
        #                 no ability to create Orgs
        #   Funder:       only allow funder Orgs and funder RegistryOrgs. Also allow
        #                 the user to create new funders
        visit new_plan_path
        expect(page).to have_text(_('Create a new plan'))

        within('#research-org-controls') do
          # Make sure the Autocomplete controls are correct
          expect(find('label[for="org_autocomplete_name"]').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').value).to eql(@user.org.name)
          expect(find('.autocomplete-help').present?).to be(true)

          id = find_by_id('org_autocomplete_name')[:list].split('-').last
          expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
          expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

          # Clear the default Org name and replace with our search term
          fill_in _('Research organisation'), with: ''
          fill_in _('Research organisation'), with: @word
          sleep(1)

          # Make sure the correct Orgs are suggested
          expect(suggestion_exists?(@org_managed.name)).to be(true)
          expect(suggestion_exists?(@org_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@associated_matched.name)).to be(true)

          # Make sure the funder Orgs are also suggested
          expect(suggestion_exists?(@funder_managed.name)).to be(true)
          expect(suggestion_exists?(@funder_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@associated_matched_funder.name)).to be(true)

          # Make sure that RegistryOrgs with no associated Org are NOT suggested
          expect(suggestion_exists?(@registry_org.name)).to be(false)
          expect(suggestion_exists?(@registry_funder.name)).to be(false)

          # Make sure the other Orgs are NOT suggested
          unmatched_never_appear?
        end

        within('#funder-org-controls') do
          # Make sure the Autocomplete controls are correct
          expect(find('label[for="org_autocomplete_funder_name"]').present?).to be(true)
          expect(find_by_id('org_autocomplete_funder_name').present?).to be(true)
          expect(find_by_id('org_autocomplete_funder_name').value).to eql('')
          expect(find('.autocomplete-help').present?).to be(true)

          id = find_by_id('org_autocomplete_funder_name')[:list].split('-').last
          expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
          expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

          # Clear the default Org name and replace with our search term
          fill_in _('Funder'), with: ''
          fill_in _('Funder'), with: @word

          # Make sure the correct Orgs are suggested
          expect(suggestion_exists?(@funder_managed.name)).to be(true)
          expect(suggestion_exists?(@funder_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@registry_funder.name)).to be(false)
          expect(suggestion_exists?(@associated_matched_funder.name)).to be(true)

          # Make sure the non-funder Orgs are NOT suggested
          expect(suggestion_exists?(@org_managed.name)).to be(false)
          expect(suggestion_exists?(@org_unmanaged.name)).to be(false)
          expect(suggestion_exists?(@registry_org.name)).to be(false)
          expect(suggestion_exists?(@associated_matched.name)).to be(false)

          # Make sure the other Orgs are NOT suggested
          unmatched_never_appear?
        end
      end
    end

    context 'Project Details page implementation (Funder only)' do
      it 'has the appropriate controls and returns the expected suggestions', js: true do
        # The Autocomplete on this page should only allow the selection of funder
        # Org or RegistryOrg records and also allow the user to create funders
        visit plan_path(@plan)
        expect(page).to have_text(_('Project Start'))

        within('#funder-org-controls') do
          # Make sure the Autocomplete controls are correct
          expect(find('label[for="org_autocomplete_funder_name"]').present?).to be(true)
          expect(find_by_id('org_autocomplete_funder_name').present?).to be(true)
          expect(find_by_id('org_autocomplete_funder_name').value).to eql('')
          expect(find_by_id('org_autocomplete_funder_not_in_list', visible: false).present?).to be(true)
          expect(find_by_id('org_autocomplete_funder_user_entered_name', visible: false).present?).to be(true)
          expect(find('.autocomplete-help').present?).to be(true)

          id = find_by_id('org_autocomplete_funder_name')[:list].split('-').last
          expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
          expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

          # Clear the default Org name and replace with our search term
          fill_in _('Funder'), with: ''
          fill_in _('Funder'), with: @word

          # Make sure the correct Orgs are suggested
          expect(suggestion_exists?(@funder_managed.name)).to be(true)
          expect(suggestion_exists?(@funder_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@registry_funder.name)).to be(true)
          expect(suggestion_exists?(@associated_matched_funder.name)).to be(true)

          # Make sure the non-funder Orgs are NOT suggested
          expect(suggestion_exists?(@org_managed.name)).to be(false)
          expect(suggestion_exists?(@org_unmanaged.name)).to be(false)
          expect(suggestion_exists?(@registry_org.name)).to be(false)
          expect(suggestion_exists?(@associated_matched.name)).to be(false)

          # Make sure the other Orgs are NOT suggested
          unmatched_never_appear?
        end
      end
    end

    context 'Templates page for letting SuperAdmin change affiliations' do
      it 'has the appropriate controls and returns the expected suggestions', js: true do
        # The Autocomplete on this page should only allow the SuperAdmin to select
        # known Orgs (no unassociated RegistryOrgs) and no ability to create Orgs
        sign_out @user
        super_admin = create(:user, :super_admin)
        sign_in super_admin
        visit org_admin_templates_path
        expect(page).to have_text(_('Templates'))

        within('#super-admin-switch-org') do
          # Make sure the Autocomplete controls are correct
          expect(find('label[for="org_autocomplete_name"]').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').value).to eql(super_admin.org.name)
          expect { find_by_id('org_autocomplete_not_in_list') }.to raise_error(Capybara::ElementNotFound)
          expect do
            find_by_id('org_autocomplete_user_entered_name', visible: false)
          end.to raise_error(Capybara::ElementNotFound)
          expect(find('.autocomplete-help').present?).to be(true)

          id = find_by_id('org_autocomplete_name')[:list].split('-').last
          expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
          expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

          # Clear the default Org name and replace with our search term
          fill_in _('Affiliation'), with: ''
          fill_in _('Affiliation'), with: @word
          sleep(1)

          # Make sure the correct Orgs are suggested
          expect(suggestion_exists?(@org_managed.name)).to be(true)
          expect(suggestion_exists?(@funder_managed.name)).to be(true)
          expect(suggestion_exists?(@associated_matched.name)).to be(true)
          expect(suggestion_exists?(@associated_matched_funder.name)).to be(true)

          # Make sure that RegistryOrgs with no associated Org are NOT suggested
          expect(suggestion_exists?(@registry_org.name)).to be(false)
          expect(suggestion_exists?(@registry_funder.name)).to be(false)
          expect(suggestion_exists?(@org_unmanaged.name)).to be(false)
          expect(suggestion_exists?(@funder_unmanaged.name)).to be(false)

          # Make sure the other Orgs are NOT suggested
          unmatched_never_appear?
        end
      end
    end

    context 'SuperAdmin Editing a User page implementation works' do
      it 'has used the appropriate controls and returns the expected suggestions', js: true do
        # The Autocomplete on this page should allow the SuperAdmin to select any Orgs
        # or RegistryOrgs and allow them to create new Orgs
        sign_out @user
        super_admin = create(:user, :super_admin)
        sign_in super_admin
        visit edit_super_admin_user_path(@user)
        expect(page).to have_text("#{_('Editing profile for')} #{@user.name(false)}")

        within('#super-admin-user-org-controls') do
          # Make sure the Autocomplete controls are correct
          expect(find('label[for="org_autocomplete_name"]').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').value).to eql(@user.org.name)
          expect(find_by_id('org_autocomplete_not_in_list', visible: false).present?).to be(true)
          expect(find_by_id('org_autocomplete_user_entered_name', visible: false).present?).to be(true)
          expect(find('.autocomplete-help').present?).to be(true)

          id = find_by_id('org_autocomplete_name')[:list].split('-').last
          expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
          expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

          # Clear the default Org name and replace with our search term
          fill_in _('Institution'), with: ''
          fill_in _('Institution'), with: @word
          sleep(1)

          # Make sure the correct Orgs are suggested
          expect(suggestion_exists?(@org_managed.name)).to be(true)
          expect(suggestion_exists?(@funder_managed.name)).to be(true)
          expect(suggestion_exists?(@org_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@funder_unmanaged.name)).to be(true)
          expect(suggestion_exists?(@registry_org.name)).to be(true)
          expect(suggestion_exists?(@registry_funder.name)).to be(true)
          expect(suggestion_exists?(@associated_matched.name)).to be(true)
          expect(suggestion_exists?(@associated_matched_funder.name)).to be(true)

          # Make sure the other Orgs are NOT suggested
          unmatched_never_appear?
        end
      end
    end

    context 'SuperAdmin Create an Organisation page implementation works' do
      it 'has used the appropriate controls and returns the expected suggestions', js: true do
        # The Autocomplete on this page should allow the SuperAdmin to only select
        # unassociated RegistryOrgs OR add a custom Org
        sign_out @user
        super_admin = create(:user, :super_admin)
        sign_in super_admin
        visit new_super_admin_org_path
        expect(page).to have_text(_('New organisation'))

        within('#edit_org_profile_form') do
          # Make sure the Autocomplete controls are correct
          expect(find('label[for="org_autocomplete_name"]').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').present?).to be(true)
          expect(find_by_id('org_autocomplete_name').value).to eql('')
          expect(find_by_id('org_autocomplete_not_in_list', visible: false).present?).to be(true)
          expect(find_by_id('org_autocomplete_user_entered_name', visible: false).present?).to be(true)
          expect(find('.autocomplete-help').present?).to be(true)

          id = find_by_id('org_autocomplete_name')[:list].split('-').last
          expect(find(".autocomplete-warning-#{id}", visible: false).present?).to be(true)
          expect(find("#autocomplete-suggestions-#{id}", visible: false).present?).to be(true)

          # Clear the default Org name and replace with our search term
          fill_in _('Organisation lookup'), with: ''
          fill_in _('Organisation lookup'), with: @word

          # Make sure the correct Orgs are suggested
          expect(suggestion_exists?(@registry_org.name)).to be(true)
          expect(suggestion_exists?(@registry_funder.name)).to be(true)

          # Make sure known Orgs are NOT suggested
          expect(suggestion_exists?(@org_managed.name)).to be(false)
          expect(suggestion_exists?(@funder_managed.name)).to be(false)
          expect(suggestion_exists?(@org_unmanaged.name)).to be(false)
          expect(suggestion_exists?(@funder_unmanaged.name)).to be(false)
          expect(suggestion_exists?(@associated_matched.name)).to be(false)
          expect(suggestion_exists?(@associated_matched_funder.name)).to be(false)

          # Make sure the other Orgs are NOT suggested
          unmatched_never_appear?
        end
      end
    end
  end

  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  def init_orgs
    # Orgs that match the search term and have no associated Registry Org
    @funder_managed = create(:org, :funder, managed: true, name: "#{@word} Managed Funder")
    @funder_unmanaged = create(:org, :funder, managed: false, name: "#{@word} Unmanaged Funder")
    @org_managed = create(:org, managed: true, name: "#{@word} Managed Org")
    @org_unmanaged = create(:org, managed: false, name: "#{@word} Unmanaged Org")

    # RegistryOrgs that matches the search term and have no associated Org
    @registry_funder = create(:registry_org, name: "#{@word} Registry Funder")
    @registry_org = create(:registry_org, fundref_id: nil, name: "#{@word} Registry Org")

    # Orgs that match the search term and have an associated RegistryOrg that does not
    @associated_matched_funder = create(:org, :funder, name: "Matched Assoc Funder #{@word.downcase}")
    @registry_unmatched_funder = create(:registry_org, name: 'Unmatched Assoc Registry Funder',
                                                       org_id: @associated_matched_funder.id)
    @associated_matched = create(:org, name: "Matched Assoc Org #{@word.downcase}")
    @registry_unmatched = create(:registry_org, fundref_id: nil,
                                                name: 'Unmatched Assoc Registry Org',
                                                org_id: @associated_matched.id)

    # Orgs that does not match the search term but has an associated RegistryOrg that does
    @associated_unmatched_funder = create(:org, :funder, name: 'Unmatched Assoc Funder')
    @registry_matched_funder = create(:registry_org, name: "Matched Assoc Registry Funder (#{@word.downcase}.org)",
                                                     org_id: @associated_unmatched_funder.id)
    @associated_unmatched = create(:org, :funder, name: 'Unmatched Assoc Org')
    @registry_matched = create(:registry_org, fundref_id: nil,
                                              name: "Matched Assoc Registry Org (#{@word.downcase}.org)",
                                              org_id: @associated_unmatched.id)

    # Orgs and RegistryOrgs that do not match the search term
    @unmatched_funder = create(:org, managed: true, name: 'Unmatched Funder')
    @unmatched_unmanaged_funder = create(:org, managed: false, name: 'Unmatched Unmanaged Funder')
    @unmatched_registry_funder = create(:org, name: 'Unmatched Registry Funder')
    @unmatched = create(:org, managed: true, name: 'Unmatched Managed Org')
    @unmatched_unmanaged = create(:org, managed: false, name: 'Unmatched Unamanaged Org')
    @unmatched_registry = create(:registry_org, fundref_id: nil, name: 'Unmatched Registry Org')

    # Create templates for the funders
    create(:template, :published, org_id: @funder_managed.id)
    create(:template, :published, org_id: @funder_unmanaged.id)
    create(:template, :published, org_id: @associated_matched_funder.id)
  end
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength

  # Check to ensure that none of the Orgs or RegistryOrgs that do not match the search term
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
  def unmatched_never_appear?
    !suggestion_exists?(@unmatched_funder.name) &&
      !suggestion_exists?(@unmatched_unmanaged_funder.name) &&
      !suggestion_exists?(@unmatched_registry_funder.name) &&
      !suggestion_exists?(@unmatched.name) &&
      !suggestion_exists?(@unmatched_unmanaged.name) &&
      !suggestion_exists?(@unmatched_registry.name) &&
      !suggestion_exists?(@registry_unmatched_funder.name) &&
      !suggestion_exists?(@registry_unmatched.name) &&
      !suggestion_exists?(@associated_unmatched.name) &&
      !suggestion_exists?(@associated_unmatched_funder.name)
  end
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
end


text:
module Jax
  module Generators
    class NamedBase < ::Rails::Generators::NamedBase
      class Error < Thor::Error
      end

      no_tasks do
        def exit(message = "")
          raise Jax::Generators::NamedBase::Error, message
        end
      end

      extend  Jax::Generators::SourceRoot
      include Jax::Generators::CoffeeGenerator
    end
  end
end


text:
<?php

use Fhaculty\Graph\Graph;
use Graphp\Algorithms\Tree\OutTree;

class OutTreeTest extends BaseDirectedTest
{
    protected function createGraphTree()
    {
        // c1 <- root -> c2
        $graph = new Graph();
        $root = $graph->createVertex();

        $c1 = $graph->createVertex();
        $root->createEdgeTo($c1);

        $c2 = $graph->createVertex();
        $root->createEdgeTo($c2);

        return $graph;
    }

    protected function createTreeAlg(Graph $graph)
    {
        return new OutTree($graph);
    }

    protected function createGraphNonTree()
    {
        // v1 -> v3 <- v2 -> v4
        $graph = new Graph();
        $graph->createVertex('v1')->createEdgeTo($graph->createVertex('v3'));
        $graph->createVertex('v2')->createEdgeTo($graph->getVertex('v3'));
        $graph->getVertex('v2')->createEdgeTo($graph->createVertex('v4'));

        return $graph;
    }

    protected function createGraphParallelEdge()
    {
        // v1 -> v2, v1 -> v2
        $graph = new Graph();
        $graph->createVertex('v1')->createEdgeTo($graph->createVertex('v2'));
        $graph->getVertex('v1')->createEdgeTo($graph->getVertex('v2'));

        return $graph;
    }
}


text:
<?php

namespace Doctrine\Bundle\DoctrineCacheBundle\Tests\Functional\Command;

use Symfony\Component\Console\Tester\CommandTester;
use Doctrine\Bundle\DoctrineCacheBundle\Command\FlushCommand;

/**
 * Functional test for delete command.
 *
 * @author Alan Doucette <dragonwize@gmail.com>
 */
class FlushCommandTest extends CommandTestCase
{
    /**
     * @var \Doctrine\Bundle\DoctrineCacheBundle\Command\FlushCommand
     */
    protected $command;

    /**
     * @var \Symfony\Component\Console\Tester\CommandTester
     */
    protected $tester;

    /**
     * {@inheritdoc}
     */
    public function setUp()
    {
        parent::setUp();

        $this->command = new FlushCommand();
        $this->tester  = $this->getTester($this->command);
    }

    /**
     * Tests flushing a cache.
     */
    public function testFlush()
    {
        $this->tester->execute(array(
            'cache-name' => $this->cacheName,
        ));
        $this->assertEquals("Clearing the cache for the {$this->cacheName} provider of type {$this->cacheProviderClass}\n", $this->tester->getDisplay());
    }
}


text:
package loggregator_trafficcontroller
/*
* File Generated by enaml generator
* !!! Please do not edit this file !!!
*/
type TrafficController struct {

	/*Debug - Descr: boolean value to turn on verbose logging for loggregator system (dea agent & loggregator server) Default: false
*/
	Debug interface{} `yaml:"debug,omitempty"`

	/*DisableAccessControl - Descr: Traffic controller bypasses authentication with the UAA and CC Default: false
*/
	DisableAccessControl interface{} `yaml:"disable_access_control,omitempty"`

	/*Zone - Descr: Zone of the loggregator_trafficcontroller Default: <nil>
*/
	Zone interface{} `yaml:"zone,omitempty"`

	/*OutgoingPort - Descr: Port on which the traffic controller listens to for requests Default: 8080
*/
	OutgoingPort interface{} `yaml:"outgoing_port,omitempty"`

}


text:
var c2j = require("../index.js");

c2j("test/foobar", function(success, jconf){
	if(success && jconf["a"] == 33 && jconf.foobar == "raboof" )
		console.log("test success");
	else
		console.log("test failed");
});


text:
FILE=neo-simple.pyxie

cd ../..
export PYTHONPATH=.
./bin/pyxie --profile arduino parse examples/neopixel/$FILE


text:
package org.apache.bookkeeper.client;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.bookkeeper.client.BKException.BKNotEnoughBookiesException;
import org.apache.bookkeeper.conf.Configurable;
import org.apache.bookkeeper.net.CachedDNSToSwitchMapping;
import org.apache.bookkeeper.net.DNSToSwitchMapping;
import org.apache.bookkeeper.net.NetworkTopology;
import org.apache.bookkeeper.net.Node;
import org.apache.bookkeeper.net.NodeBase;
import org.apache.bookkeeper.net.ScriptBasedMapping;
import org.apache.bookkeeper.util.ReflectionUtils;
import org.apache.bookkeeper.util.StringUtils;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Sets;

/**
 * Simple rackware ensemble placement policy.
 *
 * Make most of the class and methods as protected, so it could be extended to implement other algorithms.
 */
public class RackawareEnsemblePlacementPolicy implements EnsemblePlacementPolicy {

    static final Logger LOG = LoggerFactory.getLogger(RackawareEnsemblePlacementPolicy.class);

    public static final String REPP_DNS_RESOLVER_CLASS = "reppDnsResolverClass";

    /**
     * Predicate used when choosing an ensemble.
     */
    protected static interface Predicate {
        boolean apply(BookieNode candidate, Ensemble chosenBookies);
    }

    /**
     * Ensemble used to hold the result of an ensemble selected for placement.
     */
    protected static interface Ensemble {

        /**
         * Append the new bookie node to the ensemble.
         *
         * @param node
         *          new candidate bookie node.
         */
        public void addBookie(BookieNode node);

        /**
         * @return list of addresses representing the ensemble
         */
        public ArrayList<InetSocketAddress> toList();
    }

    protected static class TruePredicate implements Predicate {

        public static final TruePredicate instance = new TruePredicate();

        @Override
        public boolean apply(BookieNode candidate, Ensemble chosenNodes) {
            return true;
        }

    }

    protected static class EnsembleForReplacement implements Ensemble {

        public static final EnsembleForReplacement instance = new EnsembleForReplacement();
        static final ArrayList<InetSocketAddress> EMPTY_LIST = new ArrayList<InetSocketAddress>(0);

        @Override
        public void addBookie(BookieNode node) {
            // do nothing
        }

        @Override
        public ArrayList<InetSocketAddress> toList() {
            return EMPTY_LIST;
        }

    }

    /**
     * A predicate checking the rack coverage for write quorum in {@link RoundRobinDistributionSchedule},
     * which ensures that a write quorum should be covered by at least two racks.
     */
    protected static class RRRackCoverageEnsemble implements Predicate, Ensemble {

        class QuorumCoverageSet {
            Set<String> racks = new HashSet<String>();
            int seenBookies = 0;

            boolean apply(BookieNode candidate) {
                if (seenBookies + 1 == writeQuorumSize) {
                    return racks.size() > (racks.contains(candidate.getNetworkLocation()) ? 1 : 0);
                }
                return true;
            }

            void addBookie(BookieNode candidate) {
                ++seenBookies;
                racks.add(candidate.getNetworkLocation());
            }
        }

        final int ensembleSize;
        final int writeQuorumSize;
        final ArrayList<BookieNode> chosenNodes;
        private final QuorumCoverageSet[] quorums;

        protected RRRackCoverageEnsemble(int ensembleSize, int writeQuorumSize) {
            this.ensembleSize = ensembleSize;
            this.writeQuorumSize = writeQuorumSize;
            this.chosenNodes = new ArrayList<BookieNode>(ensembleSize);
            this.quorums = new QuorumCoverageSet[ensembleSize];
        }

        @Override
        public boolean apply(BookieNode candidate, Ensemble ensemble) {
            if (ensemble != this) {
                return false;
            }
            // candidate position
            int candidatePos = chosenNodes.size();
            int startPos = candidatePos - writeQuorumSize + 1;
            for (int i = startPos; i <= candidatePos; i++) {
                int idx = (i + ensembleSize) % ensembleSize;
                if (null == quorums[idx]) {
                    quorums[idx] = new QuorumCoverageSet();
                }
                if (!quorums[idx].apply(candidate)) {
                    return false;
                }
            }
            return true;
        }

        @Override
        public void addBookie(BookieNode node) {
            int candidatePos = chosenNodes.size();
            int startPos = candidatePos - writeQuorumSize + 1;
            for (int i = startPos; i <= candidatePos; i++) {
                int idx = (i + ensembleSize) % ensembleSize;
                if (null == quorums[idx]) {
                    quorums[idx] = new QuorumCoverageSet();
                }
                quorums[idx].addBookie(node);
            }
            chosenNodes.add(node);
        }

        @Override
        public ArrayList<InetSocketAddress> toList() {
            ArrayList<InetSocketAddress> addresses = new ArrayList<InetSocketAddress>(ensembleSize);
            for (BookieNode bn : chosenNodes) {
                addresses.add(bn.getAddr());
            }
            return addresses;
        }

        @Override
        public String toString() {
            return chosenNodes.toString();
        }

    }

    protected static class BookieNode implements Node {

        private final InetSocketAddress addr; // identifier of a bookie node.

        private int level; // the level in topology tree
        private Node parent; // its parent in topology tree
        private String location = NetworkTopology.DEFAULT_RACK; // its network location
        private final String name;

        BookieNode(InetSocketAddress addr, String networkLoc) {
            this.addr = addr;
            this.name = StringUtils.addrToString(addr);
            setNetworkLocation(networkLoc);
        }

        public InetSocketAddress getAddr() {
            return addr;
        }

        @Override
        public int getLevel() {
            return level;
        }

        @Override
        public void setLevel(int level) {
            this.level = level;
        }

        @Override
        public Node getParent() {
            return parent;
        }

        @Override
        public void setParent(Node parent) {
            this.parent = parent;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public String getNetworkLocation() {
            return location;
        }

        @Override
        public void setNetworkLocation(String location) {
            this.location = location;
        }

        @Override
        public int hashCode() {
            return name.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof BookieNode)) {
                return false;
            }
            BookieNode other = (BookieNode) obj;
            return getName().equals(other.getName());
        }

        @Override
        public String toString() {
            return String.format("<Bookie:%s>", name);
        }

    }

    static class DefaultResolver implements DNSToSwitchMapping {

        @Override
        public List<String> resolve(List<String> names) {
            List<String> rNames = new ArrayList<String>(names.size());
            for (@SuppressWarnings("unused") String name : names) {
                rNames.add(NetworkTopology.DEFAULT_RACK);
            }
            return rNames;
        }

        @Override
        public void reloadCachedMappings() {
            // nop
        }

    };

    // for now, we just maintain the writable bookies' topology
    private final NetworkTopology topology;
    private DNSToSwitchMapping dnsResolver;
    private final Map<InetSocketAddress, BookieNode> knownBookies;
    private BookieNode localNode;
    private final ReentrantReadWriteLock rwLock;

    public RackawareEnsemblePlacementPolicy() {
        topology = new NetworkTopology();
        knownBookies = new HashMap<InetSocketAddress, BookieNode>();

        rwLock = new ReentrantReadWriteLock();
    }

    private BookieNode createBookieNode(InetSocketAddress addr) {
        return new BookieNode(addr, resolveNetworkLocation(addr));
    }

    @Override
    public EnsemblePlacementPolicy initialize(Configuration conf) {
        String dnsResolverName = conf.getString(REPP_DNS_RESOLVER_CLASS, ScriptBasedMapping.class.getName());
        try {
            dnsResolver = ReflectionUtils.newInstance(dnsResolverName, DNSToSwitchMapping.class);
            if (dnsResolver instanceof Configurable) {
                ((Configurable) dnsResolver).setConf(conf);
            }
        } catch (RuntimeException re) {
            LOG.info("Failed to initialize DNS Resolver {}, used default subnet resolver.", dnsResolverName, re);
            dnsResolver = new DefaultResolver();
        }

        BookieNode bn;
        try {
            bn = createBookieNode(new InetSocketAddress(InetAddress.getLocalHost().getHostAddress(), 0));
        } catch (UnknownHostException e) {
            LOG.error("Failed to get local host address : ", e);
            bn = null;
        }
        localNode = bn;
        LOG.info("Initialize rackaware ensemble placement policy @ {} : {}.", localNode,
                dnsResolver.getClass().getName());
        return this;
    }

    @Override
    public void uninitalize() {
        // do nothing
    }

    private String resolveNetworkLocation(InetSocketAddress addr) {
        List<String> names = new ArrayList<String>(1);
        if (dnsResolver instanceof CachedDNSToSwitchMapping) {
            names.add(addr.getAddress().getHostAddress());
        } else {
            names.add(addr.getHostName());
        }
        // resolve network addresses
        List<String> rNames = dnsResolver.resolve(names);
        String netLoc;
        if (null == rNames) {
            LOG.warn("Failed to resolve network location for {}, using default rack for them : {}.", names,
                    NetworkTopology.DEFAULT_RACK);
            netLoc = NetworkTopology.DEFAULT_RACK;
        } else {
            netLoc = rNames.get(0);
        }
        return netLoc;
    }

    @Override
    public Set<InetSocketAddress> onClusterChanged(Set<InetSocketAddress> writableBookies,
            Set<InetSocketAddress> readOnlyBookies) {
        rwLock.writeLock().lock();
        try {
            Set<InetSocketAddress> joinedBookies, leftBookies, deadBookies;
            Set<InetSocketAddress> oldBookieSet = knownBookies.keySet();
            // left bookies : bookies in known bookies, but not in new writable bookie cluster.
            leftBookies = Sets.difference(oldBookieSet, writableBookies);
            // joined bookies : bookies in new writable bookie cluster, but not in known bookies
            joinedBookies = Sets.difference(writableBookies, oldBookieSet);
            // dead bookies.
            deadBookies = Sets.difference(leftBookies, readOnlyBookies);
            if (LOG.isDebugEnabled()) {
                LOG.debug(
                        "Cluster changed : left bookies are {}, joined bookies are {}, while dead bookies are {}.",
                        new Object[] { leftBookies, joinedBookies, deadBookies });
            }

            // node left
            for (InetSocketAddress addr : leftBookies) {
                BookieNode node = knownBookies.remove(addr);
                topology.remove(node);
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Cluster changed : bookie {} left from cluster.", addr);
                }
            }

            // node joined
            for (InetSocketAddress addr : joinedBookies) {
                BookieNode node = createBookieNode(addr);
                topology.add(node);
                knownBookies.put(addr, node);
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Cluster changed : bookie {} joined the cluster.", addr);
                }
            }

            return deadBookies;
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    private Set<Node> convertBookiesToNodes(Set<InetSocketAddress> excludeBookies) {
        Set<Node> nodes = new HashSet<Node>();
        for (InetSocketAddress addr : excludeBookies) {
            BookieNode bn = knownBookies.get(addr);
            if (null == bn) {
                bn = createBookieNode(addr);
            }
            nodes.add(bn);
        }
        return nodes;
    }

    @Override
    public ArrayList<InetSocketAddress> newEnsemble(int ensembleSize, int writeQuorumSize,
            Set<InetSocketAddress> excludeBookies) throws BKNotEnoughBookiesException {
        rwLock.readLock().lock();
        try {
            Set<Node> excludeNodes = convertBookiesToNodes(excludeBookies);
            RRRackCoverageEnsemble ensemble = new RRRackCoverageEnsemble(ensembleSize, writeQuorumSize);
            BookieNode prevNode = null;
            int numRacks = topology.getNumOfRacks();
            // only one rack, use the random algorithm.
            if (numRacks < 2) {
                List<BookieNode> bns = selectRandom(ensembleSize, excludeNodes,
                        EnsembleForReplacement.instance);
                ArrayList<InetSocketAddress> addrs = new ArrayList<InetSocketAddress>(ensembleSize);
                for (BookieNode bn : bns) {
                    addrs.add(bn.addr);
                }
                return addrs;
            }
            // pick nodes by racks, to ensure there is at least two racks per write quorum.
            for (int i = 0; i < ensembleSize; i++) {
                String curRack;
                if (null == prevNode) {
                    if (null == localNode) {
                        curRack = NodeBase.ROOT;
                    } else {
                        curRack = localNode.getNetworkLocation();
                    }
                } else {
                    curRack = "~" + prevNode.getNetworkLocation();
                }
                prevNode = selectFromRack(curRack, excludeNodes, ensemble, ensemble);
            }
            return ensemble.toList();
        } finally {
            rwLock.readLock().unlock();
        }
    }

    @Override
    public InetSocketAddress replaceBookie(InetSocketAddress bookieToReplace,
            Set<InetSocketAddress> excludeBookies) throws BKNotEnoughBookiesException {
        rwLock.readLock().lock();
        try {
            BookieNode bn = knownBookies.get(bookieToReplace);
            if (null == bn) {
                bn = createBookieNode(bookieToReplace);
            }

            Set<Node> excludeNodes = convertBookiesToNodes(excludeBookies);
            // add the bookie to replace in exclude set
            excludeNodes.add(bn);
            if (LOG.isDebugEnabled()) {
                LOG.debug("Try to choose a new bookie to replace {}, excluding {}.", bookieToReplace,
                        excludeNodes);
            }
            // pick a candidate from same rack to replace
            BookieNode candidate = selectFromRack(bn.getNetworkLocation(), excludeNodes,
                    TruePredicate.instance, EnsembleForReplacement.instance);
            if (LOG.isDebugEnabled()) {
                LOG.debug("Bookie {} is chosen to replace bookie {}.", candidate, bn);
            }
            return candidate.addr;
        } finally {
            rwLock.readLock().unlock();
        }
    }

    protected BookieNode selectFromRack(String networkLoc, Set<Node> excludeBookies, Predicate predicate,
            Ensemble ensemble) throws BKNotEnoughBookiesException {
        // select one from local rack
        try {
            return selectRandomFromRack(networkLoc, excludeBookies, predicate, ensemble);
        } catch (BKNotEnoughBookiesException e) {
            LOG.warn("Failed to choose a bookie from {} : "
                     + "excluded {}, fallback to choose bookie randomly from the cluster.",
                     networkLoc, excludeBookies);
            // randomly choose one from whole cluster, ignore the provided predicate.
            return selectRandom(1, excludeBookies, ensemble).get(0);
        }
    }

    protected String getRemoteRack(BookieNode node) {
        return "~" + node.getNetworkLocation();
    }

    /**
     * Choose random node under a given network path.
     *
     * @param netPath
     *          network path
     * @param excludeBookies
     *          exclude bookies
     * @param predicate
     *          predicate to check whether the target is a good target.
     * @param ensemble
     *          ensemble structure
     * @return chosen bookie.
     */
    protected BookieNode selectRandomFromRack(String netPath, Set<Node> excludeBookies, Predicate predicate,
            Ensemble ensemble) throws BKNotEnoughBookiesException {
        List<Node> leaves = new ArrayList<Node>(topology.getLeaves(netPath));
        Collections.shuffle(leaves);
        for (Node n : leaves) {
            if (excludeBookies.contains(n)) {
                continue;
            }
            if (!(n instanceof BookieNode) || !predicate.apply((BookieNode) n, ensemble)) {
                continue;
            }
            BookieNode bn = (BookieNode) n;
            // got a good candidate
            ensemble.addBookie(bn);
            // add the candidate to exclude set
            excludeBookies.add(bn);
            return bn;
        }
        throw new BKNotEnoughBookiesException();
    }

    /**
     * Choose a random node from whole cluster.
     *
     * @param numBookies
     *          number bookies to choose
     * @param excludeBookies
     *          bookies set to exclude.
     * @param ensemble
     *          ensemble to hold the bookie chosen.
     * @return the bookie node chosen.
     * @throws BKNotEnoughBookiesException
     */
    protected List<BookieNode> selectRandom(int numBookies, Set<Node> excludeBookies, Ensemble ensemble)
            throws BKNotEnoughBookiesException {
        List<BookieNode> allBookies = new ArrayList<BookieNode>(knownBookies.values());
        Collections.shuffle(allBookies);
        List<BookieNode> newBookies = new ArrayList<BookieNode>(numBookies);
        for (BookieNode bookie : allBookies) {
            if (excludeBookies.contains(bookie)) {
                continue;
            }
            ensemble.addBookie(bookie);
            excludeBookies.add(bookie);
            newBookies.add(bookie);
            --numBookies;
            if (numBookies == 0) {
                return newBookies;
            }
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Failed to find {} bookies : excludeBookies {}, allBookies {}.", new Object[] {
                    numBookies, excludeBookies, allBookies });
        }
        throw new BKNotEnoughBookiesException();
    }

}


text:
module.exports = require('marko-widgets').defineComponent({
    template: require('./template.marko'),
    getInitialState: function(input) {
        return {
            size: input.size || 'normal',
            variant: input.variant || 'primary',
            className: input['class'],
            disabled: input.disabled,
            type: input.type || 'button',
            attrs: input['*']
        };
    },

    getInitialBody: function(input) {
        return input.label || input.renderBody;
    },
    getTemplateData: function(state, input) {
        var rootAttrs = {};

        var classParts = ['btn'];

        var variant = state.variant;
        if (variant !== 'primary') {
            classParts.push('btn-' + variant);
        }

        var size = state.size;
        if (size !== 'normal') {
            classParts.push('btn-' + size);
        }

        var className = state.className;
        if (className) {
            classParts.push(className);
        }

        var splatAttrs = state.attrs;
        if (splatAttrs) {
            for (var splatAttr in splatAttrs) {
                if (splatAttrs.hasOwnProperty(splatAttr)) {
                    rootAttrs[splatAttr] = splatAttrs[splatAttr];
                }
            }
        }

        rootAttrs['class'] = classParts.join(' ');

        return {
            type: state.type,
            rootAttrs: rootAttrs,
            disabled: state.disabled
        };
    },

    handleClick: function(event) {
        // Every Widget instance is also an EventEmitter instance.
        // We will emit a custom "click" event when a DOM click event
        // is triggered
        this.emit('click', {
            event: event // Pass along the DOM event in case it is helpful to others
        });
    },

    // Add any other methods here
    setVariant: function(variant) {
        this.setState('variant', variant);
    },

    setSize: function(size) {
        this.setState('size', size);
    },

    setDisabled: function(disabled) {
        this.setState('disabled', disabled);
    },

    setLabel: function(label) {
        this.setState('label', label);
    }
});