text:
define([
	"jquery",
	"xan/helpers/util",
	"xan/helpers/places/markerwithlabel"
	//"http://maps.googleapis.com/maps/api/js?libraries=places&sensor=true&key=AIzaSyDA_6ZZn5BxBWfFGcLylrkSxXGpgVw9ahg"
], function($,util,mlabel){

	var places = {

		//position
		position: null, /*Geoposition Object*/
		positionLatLng: null, /*google.maps.LatLng Object*/
		lat: null,
		lon: null,

		//options
		options: null,
		xanData: null,
		xanAggregateData: null,
		xanOptions: null,

		lastResult: null,
		lastProvider: null,

		_map: null,
		_autocomplete: null,
		lastAutocomplete: null,
		_timeout: 20000,

	    _xanRadius: 20, /* km */
	    _xanLimit: 20,

		//_markers: null,

		/**
		 * Init position (browser object navigator.geolocation.getCurrentPosition)
		 */
		getPosition: function(okCallback,errCallback){
			if(this.position != null)
				return okCallback(this.position);

			if (navigator.geolocation)
			{
				var self = this;
				navigator.geolocation.getCurrentPosition(
						function (position) {
							self.position = position;//cache
							self.lat = self.position.coords.latitude;
							self.lon = self.position.coords.longitude;
							self.positionLatLng = new google.maps.LatLng(self.lat, self.lon);
							console.log("SET NEW POSITION lat="+self.lat+"lon="+self.lon);

							return okCallback(position);
						},
						// next function is the error callback
						function (error)
						{
							switch(error.code)
							{
								case error.TIMEOUT:
									alert ('Timeout');
									break;
								case error.POSITION_UNAVAILABLE:
									alert ('Position unavailable');
									break;
								case error.PERMISSION_DENIED:
									alert ('Permission denied');
									break;
								case error.UNKNOWN_ERROR:
									alert ('Unknown error');
									break;
							}
							return errCallback(error);
						}
					);
			}
			else{
				alert ('client is not compliant with geolocation');
			}

		},

		setPosition: function(latLng){
			this.positionLatLng = latLng;
			this.lat = latLng.lat();
			this.lon = latLng.lng();
			this.position = { coords: {latitude:this.lat, longitude:this.lon} }; //fake Geoposition Object
			console.log("SET NEW POSITION lat="+this.lat+"lon="+this.lon);

		},

		clearPosition: function(){
			this.position = null;
			this.lat = null;
			this.lon = null;
			this.positionLatLng = null;
		},

	    refreshPosition: function(okCallback,errCallback){
			this.clearPosition();
			this.clearData();
			this.getPosition(okCallback,errCallback);
	    },

		setFoursquareOptions: function(options){
			this.options = options;
		},

		loadFoursquareData: function(okCallback,errCallback){
		    var url = 'https://api.foursquare.com/v2/venues/search?oauth_token=3TM5ZFWDHOSXXDIG4KLCF4S4AY0OTZZZEE503CGX3L4HIV&v=20120205';
		    //https://developer.foursquare.com/docs/venues/search
		    //https://developer.foursquare.com/docs/explore#req=venues/categories
		    //4d4b7105d754a06377d81259=spazi aperti 4bf58dd8d48988d162941735=strade
			if(this.lastResult != null && this.lastProvider=='foursquare')
				return okCallback(this.lastResult);//from cache

		    var self = this;

		    this.getPosition(function(pos){
			    $.ajax({
			     url: url,
			     dataType: 'jsonp',
			     type: 'GET',
			     //crossDomain: true,
			     data:  {
			       ll: self.lat+','+self.lon,
			       llAcc: 10,
			       query: self.options.search || undefined,
			       intent: 'checkin',
			       radius: self.options.radius || 200,
			       categoryId: self.options.largespace ? '4d4b7105d754a06377d81259,4bf58dd8d48988d162941735':undefined,
			       limit: self.options.limit || 20
			       },

			     // on success
			     success: function(data, textStatus, jqXHR){
			    	self.lastResult = data.response.venues;//cache
			    	self.lastProvider = "foursquare";
					return okCallback(data.response.venues);
			     },

			     // on failure
			     error: function (jqXHR, textStatus, errorThrown){
			      console.log(jqXHR);
			      console.log(textStatus);
			      console.log(errorThrown);
			      if(errCallback)
			    	  return errCallback(textStatus,errorThrown);
			     }
			     });

		    });
		},

		setxanOptions: function(options){
			this.xanOptions = options;
		},

		loadxanData: function(okCallback,errCallback){

			//always refresh data
//			if(this.xanData != null)
//				return okCallback(this.xanData);

		    var self = this;
		    //this.setxanOptions({url: url });

		    this.getPosition(function(pos){
			    $.ajax({
			     url: self.xanOptions.url,
			     dataType: 'json',
			     type: 'GET',
			     //crossDomain: true,
			     data:  {
			       lat: self.lat,
			       lon: self.lon,
			       sex: self.xanOptions.sex || 'female',
			       keyword: self.xanOptions.keyword || undefined,
			       placeId: self.xanOptions.placeId || undefined,
			       radius: self.xanOptions.radius || self._xanRadius,
			       limit: self.xanOptions.limit || self._xanLimit
			       },

			     // on success
			     success: function(data, textStatus, jqXHR){
			    	//https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array
			    	//http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/
			    	//http://stackoverflow.com/questions/4246980/how-to-create-a-simple-map-using-javascript-jquery
			    	self.xanData = data.length > 0 ? new Object() : null;
			    	self.xanAggregateData = data.length > 0 ? new Object() : null;

			    	$.each(data,function(index,value){
			    		if(index==0){
			    			self.xanAggregateData = value;
			    		}else{
				    		var uniqueName = $("
").html(value.uniqueKey).text();
				    		self.xanData[uniqueName] = value;
			    		}
			    	});
			    	console.log("xan DATA NEW lat="+self.lat+"lon="+self.lon);

					return okCallback(self.xanData);
			     },

			     // on failure
			     error: function (jqXHR, textStatus, errorThrown){
			      console.log(jqXHR);
			      console.log(textStatus);
			      console.log(errorThrown);
			      if(errCallback)
			    	  return errCallback(textStatus,errorThrown);
			     }

			    });

		    });
		},
		/**
		 * @param place googleObject places
		 * @return xanobject || null
		 */
		existxanObject: function(place){
			var uniqueName = place.name+'#'+place.lat.toFixed(2)+'#'+place.lon.toFixed(2);//name#44.12#45.12
			return places.xanData ? places.xanData[uniqueName] : null;
		},

		clearxanData: function(){
			this.xanData = null;
		},

		/**
		 * init google request options
		 */
		setGoogleOptions: function(options){
			this.options = options;
		},

		rebuildGoogleMap: function(options){

			var self = this;
			//recreate map
			var map = new google.maps.Map(self.options.divMap, {
		          mapTypeId: google.maps.MapTypeId.ROADMAP,
		          draggable: true,
		          //panControl: true,
		          //panControlOptions: {position: google.maps.ControlPosition.BOTTOM_LEFT },
		          //scaleControl: true,
		          zoom: options.zoom || 14,
		          minZoom: 8, //avoid overview zoom
		          //maxZoom: 8,
		          zoomControl: true,
		          zoomControlOptions: {
		        		  position: google.maps.ControlPosition.TOP_LEFT,
		        		  style: google.maps.ZoomControlStyle.DEFAULT
		          },
		          streetViewControl: false,
		          mapTypeControl: false,
		          styles:[{
		              featureType:"poi",
		              elementType:"labels",
		              stylers:[{
		                  visibility:"off"
		              }]
		          }]
		        });

			self.addMapListener(map, null);

			self._map = map;
			self.getPosition(function(pos){
				var currentPos = new google.maps.LatLng(self.lat, self.lon);
				map.setCenter(currentPos);
			});
		},

		getMap: function(){
			return this._map;
		},

		addMapListener: function(map,cb){
	        var self = this;
			google.maps.event.addListener(map, 'idle', function() {
	        	console.log('bounds_changed');
	        	self.setPosition(map.getCenter());
	        	//cb('bounds_changed');
	        	//options.onBoundsChanged();
	        	$.Topic( "placesMapBoundChanged" ).publish();
	          });
//	        google.maps.event.addListener(places.getMap(), 'zoom_changed', function() {
//	        	console.log('zoom_changed');
//	        	cb('zoom_changed');
//	          });

		},

		/**
		 * get google places data (from cache if possible)
		 * lastResult $$ _map
		 *
		 */
		loadGoogleData: function(okCallback,errCallback){
			//http://code.google.com/intl/it-IT/apis/maps/documentation/javascript/examples/index.html
			//http://code.google.com/intl/it-IT/apis/maps/documentation/javascript/reference.html
			//http://code.google.com/intl/it-IT/apis/maps/documentation/places/supported_types.html
			//http://code.google.com/intl/it-IT/apis/maps/documentation/javascript/examples/places-autocomplete.html

			var self = this;
			//recreate map
			var map = new google.maps.Map(self.options.divMap, {
		          mapTypeId: google.maps.MapTypeId.ROADMAP,
		          disableDefaultUI: self.options.disableMapUI,
		          draggable: self.options.draggable,
		          zoom: 14,
		          maxZoom: 8,
		          zoomControl: true,
		          zoomControlOptions: {
	        		  position: google.maps.ControlPosition.TOP_LEFT,
	        		  style: google.maps.ZoomControlStyle.DEFAULT
	          	  },
		          streetViewControl: false,
		          mapTypeControl: false,
		          styles:[{
		              featureType:"poi",
		              elementType:"labels",
		              stylers:[{
		                  visibility:"off"
		              }]
		          }]
		        });
			self._map = map;

			//cache ?
			if(this.lastResult != null && this.lastProvider=='google'){
				console.log("GOOGLE DATA from cache lat="+self.lat+"lon="+self.lon);
				return okCallback(this.lastResult);
			}

			this.getPosition(function(pos){
				var currentPos = new google.maps.LatLng(self.lat, self.lon);

				map.setCenter(currentPos);

		        var request = {
		          location: currentPos,
		          radius: self.options.radius || 2000,
		          types: self.options.types || undefined, //['route|political'],
		          keyword: self.options.keyword || undefined
		        };
		        //infowindow = new google.maps.InfoWindow();

		        var timeoutFired = false;
		        var timeout = function(){
		        	timeoutFired = true;
		        	console.log("TIMEOUT GOOGLE DATA");
					if(errCallback)
						return errCallback("timeout");
		        };
		        var timeoutTimerId = setTimeout ( timeout, self.options.timeout || self._timeout );

				var callback = function(results, status){
					if(timeoutFired)
						return okCallback(null);

					if (status == google.maps.places.PlacesServiceStatus.OK) {
						clearTimeout ( timeoutTimerId );
						self.lastResult = results;//cache
				    	self.lastProvider = "google";
				    	console.log("GOOGLE DATA NEW lat="+self.lat+"lon="+self.lon);

				    	return okCallback(results);
					}
					if(errCallback)
						return errCallback(status);

				};

				var service = new google.maps.places.PlacesService(map);
				service.search(request, callback);

			});
		},

		/**
		 * crea Marker from place in _map
		 * @param place googleObject || xanObject
		 *
		 * utility  http://code.google.com/p/google-maps-utility-library-v3/wiki/Libraries
		 * label
		 * http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerwithlabel/
		 *
		 * cluster
		 * http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/
		 *
		 */
		createMarker: function(place,options) {

			var options = options || {};
			var self = this;
			var placePos = place.geometry ? place.geometry.location : new google.maps.LatLng(place.lat, place.lon);

			var markerImg = null;
			if(options.iconUrl){
				markerImg = self._createMarkerImage( options.iconUrl );
			}

			//clickable shape
			var shape = {
				      coord: [1, 1, 1, 32, 32, 32, 32 , 1],
				      type: 'poly'
				  };

			var realRate = place.real_rating ? " "+place.real_rating : " ";
			var title = options.title || place.name+realRate;

            //create marker
			//var marker = new google.maps.Marker({
			var marker = new MarkerWithLabel({
		        map: self._map,
		        position: placePos,
		        icon: markerImg,
		        /*shadow: shadow,*/
		        //shape: shape,
		        title: options.title || title,
		        //zIndex: options.zIndex || null,
		        //markerWithLabel
		        draggable: false,
		        raiseOnDrag: false,
		        labelContent: ""+parseFloat(realRate).toFixed(1)+"",
		        //labelAnchor: new google.maps.Point(8, 10),
		        labelAnchor: new google.maps.Point(8, -10),
		        labelClass: "labels", // the CSS class for the label
		        labelStyle: { opacity: 1.0},
		        labelInBackground: false
		    });

		      //marker click event ?
			if(options.clickCallback && options.infoWindowCnt){
				  var infowindow = new google.maps.InfoWindow();

				  google.maps.event.addListener(marker, 'click', function() {
			    	infowindow.setContent(options.infoWindowCnt);

			        infowindow.open(self._map, this);
			        options.clickCallback(this);//callback with this
			      });
			}
			return marker;

		 },

		 _createMarkerImage: function(urlImage,urlShadow){
			  // Marker sizes are expressed as a Size of X,Y
			  // where the origin of the image (0,0) is located
			  // in the top left of the image.

			  // Origins, anchor positions and coordinates of the marker
			  // increase in the X direction to the right and in
			  // the Y direction down.
			  var image = new google.maps.MarkerImage(urlImage,
			      // This marker is 20 pixels wide by 32 pixels tall.
			      new google.maps.Size(32, 32),
			      // The origin for this image is 0,0.
			      new google.maps.Point(0,0),
			      // The anchor for this image is the base of the flagpole at 0,32.
			      new google.maps.Point(16, 16)
			  );

			  /*var shadow = new google.maps.MarkerImage(urlShadow,
			      // The shadow image is larger in the horizontal dimension
			      // while the position and offset are the same as for the main image.
			      new google.maps.Size(37, 32),
			      new google.maps.Point(0,0),
			      new google.maps.Point(0, 32));*/

			      // Shapes define the clickable region of the icon.
			      // The type defines an HTML <area> element 'poly' which
			      // traces out a polygon as a series of X,Y points. The final
			      // coordinate closes the poly by connecting to the first
			      // coordinate.

			  return image;
		 },

		 /**
		  * SetCenter place in _map
		  * @param place googleObject || xanObject
		  * @param zoom int 1 (high)  17 (close)
		  */
		centeringMap: function(place,zoom){
			 var self = this;
			 //center place in map
            if (place.geometry && place.geometry.viewport) {
            	self._map.fitBounds(place.geometry.viewport);
            }
            var placePos = place.geometry ? place.geometry.location : new google.maps.LatLng(place.lat, place.lon);

            self._map.setCenter(placePos);

            self._map.setZoom(zoom || 15);

		 },

		 /**
		  * Place Detail Request Results Different From Autocomplete Text
		  * http://groups.google.com/group/google-places-api/browse_thread/thread/187375f42b558785
		  *
		  * places.setGoogleOptions({searchField:inputDomNode,  divMap: mapDomNode, types:['geocode'] });
		  *
		  * places.setGoogleOptions({searchField:inputDomNode,  divMap: mapDomNode, types:['geocode'] });
		  */
		 initGoogleAutocomplete: function(params){

 		 var self = this;
         var currentPos = new google.maps.LatLng(self.lat, self.lon);//init with currentPos

         var map = new google.maps.Map(params.divMap, {
		          mapTypeId: google.maps.MapTypeId.ROADMAP,
		          center: currentPos,
		          zoom: 15,
		          zoomControl: false,
		          streetViewControl: false,
		          mapTypeControl: false
		        });

		 // separate autocomplete _map ?
		 self._map = map;

          var input = params.searchField;
          var autocomplete = new google.maps.places.Autocomplete(input);

          //automatic bindTo ?
          params.autoBind = params.autoBind ? params.autoBind : true;
          if(params.autoBind)
        	  autocomplete.bindTo('bounds', map);

          autocomplete.setTypes(params.types);
          self._autocomplete = autocomplete;

//          var infowindow = new google.maps.InfoWindow();
//          var marker = new google.maps.Marker({
//            map: map
//          });

          google.maps.event.addListener(autocomplete, 'place_changed', function() {
            //infowindow.close();
            var place = autocomplete.getPlace();
            self.lastAutocomplete = place;

            /* set currentPos to autocomplete place result ?*/
            self.setPosition(place.geometry.location);

            //set Place as lastResult ?
//			self.lastResult = [place];//cache
//	    	self.lastProvider = "google";

            if (place.geometry.viewport) {
              self._map.fitBounds(place.geometry.viewport);
            } else {
              self._map.setCenter(place.geometry.location);
              self._map.setZoom(17);  // Why 17? Because it looks good.
            }

//            var image = new google.maps.MarkerImage(
//                place.icon,
//                new google.maps.Size(71, 71),
//                new google.maps.Point(0, 0),
//                new google.maps.Point(17, 34),
//                new google.maps.Size(35, 35));
//            marker.setIcon(image);
//            marker.setPosition(place.geometry.location);
//
//            var address = '';
//            if (place.address_components) {
//              address = [(place.address_components[0] &&
//                          place.address_components[0].short_name || ''),
//                         (place.address_components[1] &&
//                          place.address_components[1].short_name || ''),
//                         (place.address_components[2] &&
//                          place.address_components[2].short_name || '')
//                        ].join(' ');
//            }
//
//            infowindow.setContent('
' + place.name + '
' + address);
//            infowindow.open(map, marker);
          });

		 },

		getGooglePlaceDetails: function(okCallback,errCallback){
		},

		/**
		 * get lastResult (any provider) only from cache
		 */
		getData: function(okCallback,errCallback){
			if(this.lastResult != null)
				return okCallback(this.lastResult);//from cache
		},
		clearData: function(){
			this.lastResult = null;
			this.lastProvider = null;
		},

		/**
		 * parse foursquare place object in generic place object
		 * @param foursquare Object
		 * @return Object
		 */
		_parseFoursquarePlace: function(place){
			var obj = {};
			var icon = place.categories[0] ? place.categories[0].icon : null;
			var iconName = icon ? icon.prefix+icon.sizes[0]+icon.name : 'https://foursquare.com/img/categories/travel/highway_32.png';

			obj.icon = iconName;
			obj.id = place.id;
			obj.reference = "";
			obj.name = place.name;
			obj.address = place.location.address;
			obj.city = place.location.city;
			obj.country = place.location.country;
			obj.state = place.location.state;
			obj.distance = place.location.distance;
			obj.lat = place.location.lat;
			obj.lon = place.location.lng;
			obj.provider = "foursquare";
			obj.source = place;

			return obj;
		},

		geo: new google.maps.Geocoder(),

		/**
		 * parse google place object in generic place object
		 * @param googlePlace Object
		 * @return Object
		 */
		_parseGooglePlace: function(place,options,cb){
			//http://stackoverflow.com/questions/5346392/trying-to-find-the-distance-between-two-latlng-objects-using-googlemaps-api-and
			//google.maps.geometry.spherical.computeDistanceBetween(from:LatLng, to:LatLng, radius?:number)

			var dist = google.maps.geometry.spherical.computeDistanceBetween(this.positionLatLng, place.geometry.location);

			var country = "";
			var city = "";
			var state = ""; //province

			var createObj = function(){
				var obj = {};
				obj.icon = place.icon;
				obj.id = place.id;
				obj.reference = place.reference;
				obj.name = place.name;
				obj.address = place.vicinity || "" ;
				obj.city = city;
				obj.country = country;
				obj.state = state; //province
				obj.distance = dist.toFixed(2) || "";
				obj.lat = place.geometry.location.lat();
				obj.lon = place.geometry.location.lng();
				obj.provider = "google";
				obj.source = place;

				return cb(obj);

			};

			if(options.geocode == true){

				this.geo.geocode({location: place.geometry.location},function(results,status){
					if (status == google.maps.GeocoderStatus.OK) {
						for (i=0; i<results[0].address_components.length; i++){

							for (j=0;j<results[0].address_components[i].types.length; j++){

								if(results[0].address_components[i].types[j]=="country")
						          country = results[0].address_components[i].short_name;

								if(results[0].address_components[i].types[j]=="locality")
									city = results[0].address_components[i].short_name;

								if(results[0].address_components[i].types[j]=="administrative_area_level_2")
									state = results[0].address_components[i].short_name;
						    }
						}
					}
					createObj();

				});
			}else{
				createObj();
			}

		},

		/**
		 * get place object
		 * @param index
		 * @return Object place (generic)
		 */
		getItem: function(index,options,cb){
			var place =  this.lastResult ? this.lastResult[index] : null;
			if(!place)
				return null;

			switch(this.lastProvider)
			{
				case "foursquare":
					return this._parseFoursquarePlace(place,options,cb);

				case "google":
					return this._parseGooglePlace(place,options,cb);

			}
		}

	};

	//singleton pattern dojox/mobile/ProgressIndicator
//	AjaxService._instance = null;
//	AjaxService.getInstance = function(){
//		if(!AjaxService._instance){
//			AjaxService._instance = new AjaxService();
//		}
//		return AjaxService._instance;
//	};

	return places;

});


text:
namespace base {
class FilePath;
}

class MetadataParserJpegFactory : public MetadataParserFactory {
 public:
  MetadataParserJpegFactory();

  // Implementation of MetadataParserFactory
  virtual bool CanParse(const base::FilePath& path,
                        char* bytes,
                        int bytes_size) OVERRIDE;
  virtual MetadataParser* CreateParser(const base::FilePath& path) OVERRIDE;

 private:
  DISALLOW_COPY_AND_ASSIGN(MetadataParserJpegFactory);
};

#endif  // CHROME_BROWSER_PARSERS_METADATA_PARSER_JPEG_FACTORY_H_

redpajama_set_name: RedPajamaGithub


text:
package za.org.grassroot.webapp.controller.ussd;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import za.org.grassroot.core.domain.*;
import za.org.grassroot.core.enums.TodoCompletionConfirmType;
import za.org.grassroot.integration.LearningService;
import za.org.grassroot.integration.exception.SeloApiCallFailure;
import za.org.grassroot.integration.exception.SeloParseDateTimeFailure;
import za.org.grassroot.services.PermissionBroker;
import za.org.grassroot.services.exception.AccountLimitExceededException;
import za.org.grassroot.services.task.TodoBroker;
import za.org.grassroot.services.task.TodoRequestBroker;
import za.org.grassroot.webapp.controller.ussd.menus.USSDMenu;
import za.org.grassroot.webapp.enums.USSDSection;
import za.org.grassroot.webapp.model.ussd.AAT.Request;
import za.org.grassroot.webapp.util.USSDGroupUtil;

import java.net.URISyntaxException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import static za.org.grassroot.core.enums.TodoCompletionConfirmType.COMPLETED;
import static za.org.grassroot.core.enums.TodoCompletionConfirmType.NOT_COMPLETED;
import static za.org.grassroot.core.util.DateTimeUtil.*;
import static za.org.grassroot.webapp.util.USSDUrlUtil.*;

/**
 * Created by luke on 2015/12/15.
 */
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_XML_VALUE)
@RestController
public class USSDTodoController extends USSDController {

    private static final Logger log = LoggerFactory.getLogger(USSDTodoController.class);

    @Value("${grassroot.todos.completion.threshold:20}") // defaults to 20 percent
    private double COMPLETION_PERCENTAGE_BOUNDARY;

    @Value("${grassroot.ussd.location.enabled:false}")
    private boolean locationRequestEnabled;

    @Autowired
    private PermissionBroker permissionBroker;

    @Autowired
    private TodoBroker todoBroker;

    @Autowired
    private TodoRequestBroker todoRequestBroker;

    @Autowired
    private LearningService learningService;

    private static final USSDSection thisSection = USSDSection.TODO;
    private static final String path = homePath + todoMenus;

    private static final String groupMenu = "group",
            subjectMenu = "subject",
            instantMenu = "instant",
            dueDateMenu = "due_date",
            pickUserMenu = "pick_user",
            confirmMenu = "confirm",
            send = "send";

    private static final String
            incompleteEntries = "incomplete",
            listEntriesMenu = "list",
            viewEntryMenu = "view",
            viewAssignment = "view_assigned",
            setCompleteMenu = "complete",
            changeEntry = "change",
            alterSubject = "subject_change",
            alterDate = "date_change",
            cancelTodo = "cancel";

    private static final String todoUidParam = "todoUid";
    private static final String todoUrlSuffix = "?" + todoUidParam + "=";
    private static final String priorMenuSuffix = "&" + previousMenu + "=";

    private static final int PAGE_LENGTH = 3;
    private static final int stdHour =13, stdMinute = 0;

    private String menuPrompt(String menu, User user) {
        return getMessage(thisSection, menu, promptKey, user);
    }

    private String returnUrl(String nextMenu, String todoUid) {
        return todoMenus + nextMenu + todoUrlSuffix + todoUid;
    }

    private String nextOrConfirmUrl(String thisMenu, String nextMenu, String todoUid, boolean revising) {
        return revising ? returnUrl(confirmMenu, todoUid) + priorMenuSuffix + thisMenu :
                returnUrl(nextMenu, todoUid);
    }

    private String backUrl(String menu, String todoUid) {
        return returnUrl(menu, todoUid) + "&" + revisingFlag + "=1";
    }

    @RequestMapping(path + startMenu)
    @ResponseBody
    public Request askNewOld(@RequestParam(value = phoneNumber) String inputNumber) throws URISyntaxException {
        User user = userManager.findByInputNumber(inputNumber);
        USSDMenu thisMenu;

        if (permissionBroker.countActiveGroupsWithPermission(user, Permission.GROUP_PERMISSION_CREATE_LOGBOOK_ENTRY) == 0) {
            thisMenu = new USSDMenu(getMessage(thisSection, startMenu, promptKey + ".nocreate", user));
        } else {
            thisMenu = new USSDMenu(getMessage(thisSection, startMenu, promptKey, user));
            thisMenu.addMenuOption(todoMenus + groupMenu + "?new=true", getMessage(thisSection, startMenu, optionsKey + "new", user));
        }

        if (todoBroker.userHasIncompleteActionsToView(user.getUid())) {
            thisMenu.addMenuOption(todoMenus + incompleteEntries + "?pageNumber=0", getMessage(thisSection, startMenu, optionsKey + incompleteEntries, user));
        }

        if (permissionBroker.countActiveGroupsWithPermission(user, null) != 0) {
            thisMenu.addMenuOption(todoMenus + groupMenu + "?new=false", getMessage(thisSection, startMenu, optionsKey + "old", user));
        }

        thisMenu.addMenuOption(startMenu, getMessage(thisSection,startMenu,optionsKey+"back", user));
        return menuBuilder(thisMenu);
    }

    @RequestMapping(path + groupMenu)
    @ResponseBody
    public Request groupList(@RequestParam(value = phoneNumber) String inputNumber,
                             @RequestParam(value = "new") boolean newEntry) throws URISyntaxException {
        User user = userManager.findByInputNumber(inputNumber);
        int countGroups = permissionBroker.countActiveGroupsWithPermission(user, Permission.GROUP_PERMISSION_CREATE_LOGBOOK_ENTRY);
        if (newEntry) {
            return menuBuilder(initiateNewAction(user, countGroups));
        } else {
            if (countGroups == 1) {
                Group group = permissionBroker.getActiveGroupsWithPermission(user, Permission.GROUP_PERMISSION_CREATE_LOGBOOK_ENTRY).iterator().next();
                return listCompleteEntriesForGroup(user.getPhoneNumber(), 0, group.getUid());
            } else {
                return menuBuilder(ussdGroupUtil.askForGroup(new USSDGroupUtil.GroupMenuBuilder(user, thisSection)
                        .urlForExistingGroup(listEntriesMenu + "?pageNumber=0")
                        .messageKey("history")
                        .numberOfGroups(countGroups)));
            }
        }
    }

    private USSDMenu initiateNewAction(User user, int groupCount) throws URISyntaxException {
        if (groupCount == 1) {
            Group group = permissionBroker.getActiveGroupsWithPermission(user, Permission.GROUP_PERMISSION_CREATE_LOGBOOK_ENTRY).iterator().next();
            final String prompt = getMessage(thisSection, subjectMenu, promptKey + ".skipped", group.getName(""), user);
            return setActionGroupAndInitiateRequest(null, group.getUid(), prompt, false, user);
        } else {
            return ussdGroupUtil.askForGroup(new USSDGroupUtil.GroupMenuBuilder(user, thisSection)
                    .urlForExistingGroup(subjectMenu)
                    .messageKey("new")
                    .numberOfGroups(groupCount));
        }
    }

    @RequestMapping(path + subjectMenu)
    @ResponseBody
    public Request askForSubject(@RequestParam(value = phoneNumber) String inputNumber,
                                 @RequestParam(value = groupUidParam, required = false) String groupUid,
                                 @RequestParam(value = revisingFlag, required = false) boolean revising,
                                 @RequestParam(value = todoUidParam, required = false) String passedTodoUid) throws URISyntaxException {

        User user = userManager.findByInputNumber(inputNumber);
        final String prompt = getMessage(thisSection, subjectMenu, promptKey, user);
        return menuBuilder(setActionGroupAndInitiateRequest(passedTodoUid, groupUid, prompt, revising, user));
    }

    private USSDMenu setActionGroupAndInitiateRequest(final String passedTodoUid, final String groupUid, final String prompt,
                                                      final boolean revising, User user) {
        try {
            final String todoUid = passedTodoUid != null ? passedTodoUid : todoRequestBroker.create(user.getUid(), groupUid).getUid();
            cacheManager.putUssdMenuForUser(user.getPhoneNumber(), saveToDoMenu(subjectMenu, todoUid));
            return new USSDMenu(prompt, nextOrConfirmUrl(subjectMenu, instantMenu, todoUid, revising));
        } catch (AccountLimitExceededException e) {
            final String newPrompt = getMessage(thisSection, "new", promptKey + ".exceeded", user);
            cacheManager.clearUssdMenuForUser(user.getPhoneNumber());
            return new USSDMenu(newPrompt, optionsHomeExit(user, false));
        }
    }

    @RequestMapping(path + instantMenu)
    @ResponseBody
    public Request askIfActionInstant(@RequestParam(value = phoneNumber) String inputNumber,
                                      @RequestParam(value = userInputParam) String passedInput,
                                      @RequestParam(value = todoUidParam) String todoUid,
                                      @RequestParam(value = revisingFlag, required = false) boolean revising,
                                      @RequestParam(value = interruptedFlag, required = false) boolean interrupted,
                                      @RequestParam(value = interruptedInput, required = false) String priorInput) throws URISyntaxException {
        final String userInput = (interrupted) ? priorInput : passedInput;
        User user = userManager.findByInputNumber(inputNumber, saveToDoMenu(instantMenu, todoUid, userInput));
        if (!revising) todoRequestBroker.updateMessage(user.getUid(), todoUid, userInput);

        USSDMenu menu = new USSDMenu(menuPrompt(instantMenu, user));
        // first option goes to the deadline menu
        menu.addMenuOption(nextOrConfirmUrl(instantMenu, dueDateMenu, todoUid, revising),
                getMessage(thisSection, instantMenu, optionsKey + "no", user));
        // second option marks the action as done and proceeds
        menu.addMenuOption(nextOrConfirmUrl(instantMenu, confirmMenu, todoUid, true),
                getMessage(thisSection, instantMenu, optionsKey + "yes", user));
        return menuBuilder(menu);
    }

    @RequestMapping(path + dueDateMenu)
    @ResponseBody
    public Request askForDueDate(@RequestParam(value = phoneNumber) String inputNumber,
                                 @RequestParam(value = userInputParam) String passedInput,
                                 @RequestParam(value = todoUidParam) String todoUid,
                                 @RequestParam(value = revisingFlag, required = false) boolean revising,
                                 @RequestParam(value = interruptedFlag, required = false) boolean interrupted,
                                 @RequestParam(value = interruptedInput, required = false) String priorInput) throws URISyntaxException {

        final String userInput = (interrupted) ? priorInput : passedInput;
        User user = userManager.findByInputNumber(inputNumber, saveToDoMenu(dueDateMenu, todoUid, userInput));
        return menuBuilder(new USSDMenu(menuPrompt(dueDateMenu, user),
                                        nextOrConfirmUrl(dueDateMenu, confirmMenu, todoUid, true)));
    }

    @RequestMapping(path + confirmMenu)
    @ResponseBody
    public Request confirmActionTodo(@RequestParam(value = phoneNumber) String inputNumber,
                                     @RequestParam(value = todoUidParam) String todoUid,
                                     @RequestParam(value = userInputParam) String passedUserInput,
                                     @RequestParam(value = previousMenu, required = false) String passedPriorMenu,
                                     @RequestParam(value = interruptedFlag, required = false) boolean interrupted,
                                     @RequestParam(value = interruptedInput, required = false) String priorInput) throws URISyntaxException {

        final String userInput = (priorInput !=null) ? priorInput : passedUserInput;
        final String priorMenu = (passedPriorMenu != null) ? passedPriorMenu: "";

        String urlToSave = saveToDoMenu(confirmMenu, todoUid, priorMenu, userInput, !interrupted);

        User user = userManager.findByInputNumber(inputNumber, urlToSave);

        if (!interrupted) {
            updateTodoRequest(user.getUid(), todoUid, priorMenu, userInput);
        }

        TodoRequest todoRequest = todoRequestBroker.load(todoUid);
        Group group = (Group) todoRequest.getParent();

        String prompt;
        boolean isInstant = todoRequest.getActionByDate() == null;
        boolean isInFuture;

        if (!isInstant) {
            isInFuture = todoRequest.getActionByDate().isAfter(Instant.now());
            String formattedDueDate = dateFormat.format(convertToUserTimeZone(todoRequest.getActionByDate(), getSAST()));
            String[] promptFields = new String[]{todoRequest.getMessage(), group.getName(""), formattedDueDate};
            prompt = isInFuture ? getMessage(thisSection, confirmMenu, promptKey + ".unassigned", promptFields, user)
                    : getMessage(thisSection, confirmMenu, promptKey + ".err.past", formattedDueDate, user);
        } else {
            isInFuture = true;
            prompt = getMessage(thisSection, confirmMenu, promptKey + ".instant", new String[]{ todoRequest.getMessage(), group.getName() }, user);
        }

        USSDMenu menu = new USSDMenu(prompt);
        if (isInFuture) {
            menu.addMenuOption(returnUrl(send, todoUid) + "&" + instantMenu + "=" + isInstant,
                    getMessage(thisSection, confirmMenu, optionsKey + "send", user));
        }
        menu.addMenuOption(backUrl(subjectMenu, todoUid), getMessage(thisSection, confirmMenu, optionsKey + "subject", user));
        menu.addMenuOption(backUrl(isInstant ? instantMenu : dueDateMenu, todoUid), getMessage(thisSection, confirmMenu, optionsKey + "duedate", user));
        return menuBuilder(menu);
    }

    @RequestMapping(path + send)
    @ResponseBody
    public Request finishTodoEntry(@RequestParam(value = phoneNumber) String inputNumber,
                                   @RequestParam(value = todoUidParam) String todoUid,
                                   @RequestParam(value = instantMenu, required = false) boolean isInstant) throws URISyntaxException {

        User user = userManager.findByInputNumber(inputNumber, null);
        todoRequestBroker.finish(todoUid);
        return menuBuilder(new USSDMenu(menuPrompt(send + (isInstant ? ("." + instantMenu) : ""), user), optionsHomeExit(user, false)));
    }

    /**
     * SECTION: Select and view prior logbook entries
     */

    @RequestMapping(path + incompleteEntries)
    @ResponseBody
    public Request listIncompleteActions(@RequestParam String msisdn,
                                         @RequestParam int pageNumber) throws URISyntaxException {
        final User user = userManager.findByInputNumber(msisdn, todoMenus + incompleteEntries + "?pageNumber=" + pageNumber);
        final Page<Todo> incompleteTodos = todoBroker.fetchIncompleteActionsToView(user.getUid(),
                new PageRequest(pageNumber, PAGE_LENGTH, new Sort(Sort.Direction.DESC, "actionByDate")));
        final String viewUrl = todoMenus + viewEntryMenu + todoUrlSuffix + "%s&back=" + incompleteEntries + "?pageNumber=" + pageNumber;

        USSDMenu menu = new USSDMenu(getMessage(thisSection, listEntriesMenu, promptKey, user));
        incompleteTodos.getContent()
                .forEach(t -> menu.addMenuOption(String.format(viewUrl, t.getUid()), truncateEntryDescription(t, user)));
        if (incompleteTodos.hasNext()) {
            menu.addMenuOption(todoMenus + incompleteEntries + "?pageNumber=" + (pageNumber + 1), getMessage("options.more", user));
        }
        if (incompleteTodos.hasPrevious()) {
            menu.addMenuOption(todoMenus + incompleteEntries + "?pageNumber=" + (pageNumber - 1), getMessage("options.back", user));
        } else {
            menu.addMenuOption(todoMenus + startMenu, getMessage("options.back", user));
        }
        return menuBuilder(menu);
    }

    @RequestMapping(path + listEntriesMenu)
    @ResponseBody
    public Request listCompleteEntriesForGroup(@RequestParam String msisdn,
                                               @RequestParam int pageNumber,
                                               @RequestParam String groupUid) throws URISyntaxException {

        // major todo : in future, adjust menus to strip out groups with nothing to view
        final User user = userManager.findByInputNumber(msisdn, todosViewGroupCompleteEntries(listEntriesMenu, groupUid, pageNumber));
        final Group group = groupBroker.load(groupUid);
        final String urlBase = todoMenus + viewEntryMenu + todoUrlSuffix;
        final String urlSuffix = "&back=" + encodeParameter(listEntriesMenu + "?groupUid=" + groupUid + "&pageNumber=" + pageNumber);

        final Page<Todo> entries = todoBroker.fetchPageOfTodosForGroup(user.getUid(), groupUid,
                new PageRequest(pageNumber, PAGE_LENGTH, new Sort(Sort.Direction.DESC, "actionByDate")));
        // for controlling if option to jump to record todos appears
        boolean canRecordTodo = permissionBroker.isGroupPermissionAvailable(user, group, Permission.GROUP_PERMISSION_CREATE_LOGBOOK_ENTRY);
        // for controlling back behaviour
        boolean hasMultipleGroups = permissionBroker.countActiveGroupsWithPermission(user, Permission.GROUP_PERMISSION_CREATE_LOGBOOK_ENTRY) > 1;
        String backUrl = hasMultipleGroups ? todoMenus + groupMenu + "?new=false" : todoMenus + startMenu;

        USSDMenu menu;
        if (!entries.hasContent()) {
            menu = new USSDMenu(getMessage(thisSection, listEntriesMenu, "complete.noentry", group.getName(), user));
            if (canRecordTodo) {
                menu.addMenuOption(todoMenus + subjectMenu + groupUidUrlSuffix + groupUid, getMessage(thisSection, listEntriesMenu, optionsKey + "create", user));
            }
            menu.addMenuOption(backUrl, getMessage(thisSection, listEntriesMenu, optionsKey + "back", user));
            menu.addMenuOptions(optionsHomeExit(user, false));
        } else {
            menu = new USSDMenu(getMessage(thisSection, listEntriesMenu, promptKey, user));
            entries.forEach(t -> menu.addMenuOption(urlBase + t.getUid() + urlSuffix, truncateEntryDescription(t, user)));
            final String pagingUrl = todoMenus + listEntriesMenu + groupUidUrlSuffix + groupUid + "&pageNumber=";
            if (entries.hasNext()) {
                menu.addMenuOption(pagingUrl + (pageNumber + 1), getMessage("options.more", user));
            }
            if (entries.hasPrevious()) {
                menu.addMenuOption(pagingUrl + (pageNumber - 1), getMessage("options.back", user));
            } else {
                menu.addMenuOption(backUrl, getMessage("options.back", user));
            }
            if (canRecordTodo && menu.getMenuCharLength() < 140)
                menu.addMenuOption(todoMenus + subjectMenu + groupUidUrlSuffix + groupUid, getMessage(thisSection, listEntriesMenu, optionsKey + "create", user));
        }
        return menuBuilder(menu);
    }

    private String truncateEntryDescription(final Todo entry, final User user) {
        final StringBuilder sb = new StringBuilder();
        int maxLength = 30;
        final String[] words = entry.getMessage().split(" ");
        for (String word : words) {
            if ((sb.length() + word.length() + 1) > maxLength)
                break;
            else
                sb.append(word).append(" ");
        }
        return getMessage(thisSection, listEntriesMenu, "entry.format",
                new String[] { sb.toString(), shortDateFormat.format(entry.getActionByDateAtSAST()) }, user);
    }

    @RequestMapping(path + viewEntryMenu)
    @ResponseBody
    public Request viewEntryMenu(@RequestParam(value = phoneNumber) String inputNumber,
                                 @RequestParam(value = todoUidParam) String todoUid,
                                 @RequestParam(value = "back", required = false) String backPath) throws URISyntaxException {

        final User user = userManager.findByInputNumber(inputNumber, saveToDoMenu(viewEntryMenu, todoUid));
        final Todo todo = todoBroker.load(todoUid);

        final boolean userMarkedDone = todo.isCompletionConfirmedByMember(user);
        final boolean userAssigned = todo.isAllGroupMembersAssigned() || todo.getAssignedMembers().contains(user);

        final String baseDescription = getMessage(thisSection, viewEntryMenu, promptKey + ".desc",
                new String[] { todo.getMessage(), todo.getParent().getName(), shortDateFormat.format(todo.getActionByDateAtSAST()) }, user);
        final String confirmCount = todo.countCompletions() == 0 ? getMessage(thisSection, viewEntryMenu, promptKey + ".marked.none", user)
                : getMessage(thisSection, viewEntryMenu, promptKey + ".marked.some", String.valueOf(todo.countCompletions()), user);
        final String userResponse = userMarkedDone ? getMessage(thisSection, viewEntryMenu, promptKey + ".user.confirmed", user)
                : getMessage(thisSection, viewEntryMenu, promptKey + ".user.not_conf", user);

        USSDMenu menu = new USSDMenu(String.join(" ", baseDescription, confirmCount, userResponse));
        if (!userMarkedDone && userAssigned) { // note: will need to revisit whether non-assigned members can set entry complete (may want to allow)
            menu.addMenuOption(todoMenus + setCompleteMenu + todoUrlSuffix + todoUid, getMessage(thisSection, viewEntryMenu, optionsKey + "confirm", user));
        }

        if (todo.getCreatedByUser().equals(user)) {
            menu.addMenuOption(todoMenus + changeEntry + todoUrlSuffix + todoUid, getMessage(thisSection, viewEntryMenu, optionsKey + "change", user));
        }

        if (!todo.isAllGroupMembersAssigned()) {
            menu.addMenuOption(todoMenus + viewAssignment + todoUrlSuffix + todoUid, getMessage(thisSection, viewEntryMenu, optionsKey + "assigned", user));
        }

        menu.addMenuOption(todoMenus + (backPath != null ? backPath : startMenu), getMessage("options.back", user));

        return menuBuilder(menu);
    }

    @RequestMapping(path + setCompleteMenu)
    @ResponseBody
    public Request setActionTodoAsComplete(@RequestParam(value = phoneNumber) String inputNumber,
                                           @RequestParam(value = todoUidParam) String todoUid) throws URISyntaxException {

        User user = userManager.findByInputNumber(inputNumber, saveToDoMenu(setCompleteMenu, todoUid));
        Todo todo = todoBroker.load(todoUid);

        final String prompt = todo.getCreatedByUser().equals(user) ? getMessage(thisSection, setCompleteMenu, promptKey + ".creator", todo.getName(), user)
                : todo.isAllGroupMembersAssigned() ? getMessage(thisSection, setCompleteMenu, promptKey + ".unassigned", todo.getName(), user)
                : getMessage(thisSection, setCompleteMenu, promptKey + ".assigned", new String[] { todo.getName(), String.valueOf(todo.getAssignedMembers().size()) }, user);

        USSDMenu menu = new USSDMenu(prompt);

        String urlEnd = todoUrlSuffix + todoUid;
        menu.addMenuOption(todoMenus + setCompleteMenu + doSuffix + urlEnd,
                getMessage(thisSection, setCompleteMenu, optionsKey + "confirm", user));
        menu.addMenuOption(todoMenus + setCompleteMenu + doSuffix + urlEnd + "&prior_input=" + NOT_COMPLETED.name(),
                getMessage(thisSection, setCompleteMenu, optionsKey + "notsure", user));
        menu.addMenuOption(todoMenus + viewEntryMenu + urlEnd, getMessage("options.back", user));

        return menuBuilder(menu);
    }

    @RequestMapping(path + setCompleteMenu + doSuffix)
    @ResponseBody
    public Request confirmActionTodoComplete(@RequestParam(value = phoneNumber) String inputNumber,
                                             @RequestParam(value = todoUidParam) String todoUid,
                                             @RequestParam(value = "prior_input", required = false) TodoCompletionConfirmType type) throws URISyntaxException {

        TodoCompletionConfirmType confirmType = (type == null) ? COMPLETED : type;
        User user = userManager.findByInputNumber(inputNumber, null);

        boolean crossedThreshold = todoBroker.confirmCompletion(user.getUid(), todoUid, confirmType, LocalDateTime.now());
        Todo todo = todoBroker.load(todoUid);

        final String prompt = crossedThreshold ? getMessage(thisSection, setCompleteMenu, "done.changed", user)
                : getMessage(thisSection, setCompleteMenu, "done.unchanged", String.valueOf((int) todo.getCompletionPercentage()), user);
        USSDMenu menu = new USSDMenu(prompt);
        if (todoBroker.userHasIncompleteActionsToView(user.getUid())) {
            menu.addMenuOption(todoMenus + "incomplete?pageNumber=0", getMessage(thisSection, setCompleteMenu, optionsKey + "listinc", user));
        }
        menu.addMenuOptions(optionsHomeExit(user, false));
        return menuBuilder(menu);
    }

    @RequestMapping(path + viewAssignment)
    @ResponseBody
    public Request viewTodoAssignments(@RequestParam(value = phoneNumber) String inputNumber,
                                       @RequestParam(value = todoUidParam) String todoUid) throws URISyntaxException {

        User user = userManager.findByInputNumber(inputNumber, saveToDoMenu(viewAssignment, todoUid));
        Todo todo = todoBroker.load(todoUid);

        List<User> assignedMembers = new ArrayList<>(todo.getAssignedMembers());
        Collections.sort(assignedMembers);
        StringBuilder sb = new StringBuilder(assignedMembers.get(0).nameToDisplay());

        switch(assignedMembers.size()) {
            case 1:
                break;
            case 2:
                sb.append(" and ").append(assignedMembers.get(1).nameToDisplay());
                break;
            case 3:
                sb.append(", ").append(assignedMembers.get(1).nameToDisplay()).append(" and ")
                        .append(assignedMembers.get(2).nameToDisplay());
                break;
            default:
                sb.append(" and ").append(assignedMembers.size() - 1).append(" others"); // todo :i18n for these little phrases
        }

        USSDMenu menu = new USSDMenu(getMessage(thisSection, viewAssignment, promptKey,
                new String[] { sb.toString(), shortDateFormat.format(todo.getActionByDateAtSAST()) }, user));
        menu.addMenuOption(todoMenus + viewEntryMenu + todoUrlSuffix + todoUid, getMessage(optionsKey + "back", user));
        menu.addMenuOptions(optionsHomeExit(user, false));
        return menuBuilder(menu);
    }

    @RequestMapping(path + changeEntry)
    @ResponseBody
    public Request alterTodoMenu(@RequestParam String msisdn, @RequestParam String todoUid) throws URISyntaxException {
        User user = userManager.findByInputNumber(msisdn, saveToDoMenu(changeEntry, todoUid));
        Todo todo = todoBroker.load(todoUid);
        USSDMenu menu = new USSDMenu(getMessage(thisSection, changeEntry, promptKey, todo.getName(), user));
        menu.addMenuOption(todoMenus + alterSubject + todoUrlSuffix + todoUid, getMessage(thisSection, changeEntry, optionsKey + "subject", user));
        menu.addMenuOption(todoMenus + alterDate + todoUrlSuffix + todoUid, getMessage(thisSection, changeEntry, optionsKey + "duedate", user));
        menu.addMenuOption(todoMenus + cancelTodo + todoUrlSuffix + todoUid, getMessage(thisSection, changeEntry, optionsKey + "cancel", user));
        menu.addMenuOption(todoMenus + viewEntryMenu + todoUrlSuffix + todoUid, getMessage(optionsKey + "back", user));
        return menuBuilder(menu);
    }

    @RequestMapping(path + alterSubject)
    @ResponseBody
    public Request alterTodoSubject(@RequestParam String msisdn, @RequestParam String todoUid) throws URISyntaxException {
        User user = userManager.findByInputNumber(msisdn, saveToDoMenu(alterSubject, todoUid));
        Todo todo = todoBroker.load(todoUid);
        USSDMenu menu = new USSDMenu(getMessage(thisSection, changeEntry, promptKey, todo.getName(), user),
                todoMenus + changeEntry + doSuffix + todoUrlSuffix + todoUid + "&field=" + alterSubject);
        return menuBuilder(menu);
    }

    @RequestMapping(path + alterDate)
    @ResponseBody
    public Request alterTodoDate(@RequestParam String msisdn, @RequestParam String todoUid) throws URISyntaxException {
        User user = userManager.findByInputNumber(msisdn, saveToDoMenu(alterDate, todoUid));
        Todo todo = todoBroker.load(todoUid);
        USSDMenu menu = new USSDMenu(getMessage(thisSection, changeEntry, promptKey, dateFormat.format(todo.getActionByDateAtSAST()), user),
                todoMenus + alterDate + "-confirm" + todoUrlSuffix + todoUid);
        return menuBuilder(menu);
    }

    @RequestMapping(path + alterDate + "-confirm")
    @ResponseBody
    public Request alterDateConfirm(@RequestParam String msisdn, @RequestParam String todoUid,
                                    @RequestParam(value = userInputParam) String userInput,
                                    @RequestParam(value = "prior_input", required = false) String priorInput) throws URISyntaxException {
        final String enteredValue = priorInput == null ? userInput : priorInput;
        User user = userManager.findByInputNumber(msisdn, saveToDoMenu(alterDate + "-confirm", todoUid, enteredValue));
        LocalDateTime parsedDateTime = handleUserDateTimeInput(enteredValue);
        USSDMenu menu = new USSDMenu(getMessage(thisSection, alterDate + "-confirm", promptKey, dateFormat.format(parsedDateTime), user));
        final String confirmUrl = todoMenus + changeEntry + doSuffix + todoUrlSuffix + todoUid + "&field=" + alterDate
                + "&isoDate=" + DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(parsedDateTime);
        menu.addMenuOptions(optionsYesNo(user, confirmUrl, todoMenus + viewEntryMenu + todoUrlSuffix + todoUid));
        return menuBuilder(menu);
    }

    @RequestMapping(path + changeEntry + doSuffix)
    @ResponseBody
    public Request changeEntryConfirmed(@RequestParam String msisdn, @RequestParam String todoUid,
                                        @RequestParam(value = "field") String field,
                                        @RequestParam(value = userInputParam) String userInput,
                                        @RequestParam(value = "isoDate", required = false) String newActionByDate) throws URISyntaxException {
        User user = userManager.findByInputNumber(msisdn, null);
        USSDMenu menu = new USSDMenu(getMessage(thisSection, changeEntry + doSuffix, promptKey, user));
        if (alterSubject.equals(field)) {
            todoBroker.updateSubject(user.getUid(), todoUid, userInput);
            menu.addMenuOption(todoMenus + alterDate + todoUrlSuffix + todoUid, getMessage(thisSection, changeEntry + doSuffix, optionsKey + "date", user));
        } else if (alterDate.equals(field)) {
            todoBroker.updateActionByDate(user.getUid(), todoUid, LocalDateTime.parse(newActionByDate, DateTimeFormatter.ISO_LOCAL_DATE_TIME));
            menu.addMenuOption(todoMenus + alterSubject + todoUrlSuffix + todoUid, getMessage(thisSection, changeEntry + doSuffix, optionsKey + "subject", user));
        } else {
            throw new UnsupportedOperationException("Error! Field must be one of subject or date");
        }
        menu.addMenuOption(todoMenus + viewEntryMenu + todoUrlSuffix + todoUid, getMessage(thisSection, changeEntry + doSuffix, optionsKey + "view", user));
        menu.addMenuOption(todoMenus + startMenu, getMessage(thisSection, changeEntry + doSuffix, optionsKey + "back", user));
        menu.addMenuOption(startMenu + "_force", getMessage(thisSection, changeEntry + doSuffix, optionsKey + "home", user));
        return menuBuilder(menu);
    }

    @RequestMapping(path + cancelTodo)
    @ResponseBody
    public Request cancelTodo(@RequestParam String msisdn, @RequestParam String todoUid) throws URISyntaxException {
        User user = userManager.findByInputNumber(msisdn, saveToDoMenu(cancelTodo, todoUid));
        Todo todo = todoBroker.load(todoUid);
        USSDMenu menu = new USSDMenu(getMessage(thisSection, cancelTodo, promptKey, todo.getName(), user));
        menu.addMenuOptions(optionsYesNo(user, todoMenus + cancelTodo + doSuffix + todoUrlSuffix + todoUid));
        return menuBuilder(menu);
    }

    @RequestMapping(path + cancelTodo + doSuffix)
    @ResponseBody
    public Request cancelTodoConfirmed(@RequestParam String msisdn, @RequestParam String todoUid,
                                       @RequestParam(value = yesOrNoParam) boolean confirmed) throws URISyntaxException {
        User user = userManager.findByInputNumber(msisdn, null);
        if (confirmed) {
            todoBroker.cancel(user.getUid(), todoUid);
            USSDMenu menu = new USSDMenu(getMessage(thisSection, cancelTodo + doSuffix, promptKey, user));
            menu.addMenuOption(todoMenus + startMenu, getMessage(thisSection, cancelTodo + doSuffix, optionsKey + "todos", user));
            return menuBuilder(menu);
        } else {
            return viewEntryMenu(msisdn, todoUid, startMenu);
        }
    }

    private void updateTodoRequest(String userUid, String logBookRequestUid, String field, String value) {
        if (subjectMenu.equals(field)) {
            todoRequestBroker.updateMessage(userUid, logBookRequestUid, value);
        } else if (instantMenu.equals(field)) {
            todoRequestBroker.updateDueDate(userUid, logBookRequestUid, null);
        } else if (dueDateMenu.equals(field)) {
            todoRequestBroker.updateDueDate(userUid, logBookRequestUid, handleUserDateTimeInput(value));
        }
    }

    private LocalDateTime handleUserDateTimeInput(String userInput) {
        String formattedDateString =  reformatDateInput(userInput);
        LocalDateTime dueDateTime; // try process as regex, if fail, hand over to Selo, and if that fails, default to 1 week
        try {
            dueDateTime = convertDateStringToLocalDateTime(formattedDateString, stdHour, stdMinute);
        } catch (IllegalArgumentException e) {
            try {
                dueDateTime = learningService.parse(formattedDateString);
            } catch (SeloParseDateTimeFailure|SeloApiCallFailure t) {
                dueDateTime = LocalDateTime.now().plus(1, ChronoUnit.WEEKS);
            }
        }
        return dueDateTime;
    }

    // major todo: restore this (assignment of users in USSD)
    private USSDMenu pickUserFromGroup(String todoUid, String userInput, String nextMenu, String backMenu, User user) {
        USSDMenu menu;
        Todo todo = todoBroker.load(todoUid);
        Group parent = (Group) todo.getParent();
        List<User> possibleUsers = userManager.searchByGroupAndNameNumber(parent.getUid(), userInput);

        if (!possibleUsers.isEmpty()) {
            menu = new USSDMenu(getMessage(thisSection, pickUserMenu, promptKey, user));
            Iterator<User> iterator = possibleUsers.iterator();
            while (menu.getMenuCharLength() < 100 && iterator.hasNext()) {
                User possibleUser = iterator.next();
                menu.addMenuOption(returnUrl(nextMenu, todoUid) + "&assignUserUid=" + possibleUser.getUid(),
                        possibleUser.nameToDisplay());
            }
        } else {
            menu = new USSDMenu(getMessage(thisSection, pickUserMenu, promptKey + ".no-users", user));
        }

        menu.addMenuOption(returnUrl(backMenu, todoUid), getMessage(thisSection, pickUserMenu, optionsKey + "back", user));
        menu.addMenuOption(returnUrl(nextMenu, todoUid), getMessage(thisSection, pickUserMenu, optionsKey + "none", user));

        return menu;
    }
}


text:
// Copyright (c) Microsoft Corporation.  All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information.

interface Object {
    [key: string]: any;
}

interface IStyleEquivalents {
    cssName: string;
    scriptName: string;
}

interface IStyleEquivalentsMap {
    [key: string]: IStyleEquivalents;
}

interface IOpenCloseMachine {
    _state: { name: string; }
}

declare module WinJS {

    interface IPosition {
        left: number;
        top: number;
        width: number;
        height: number;
    }

    class _Signal<T> {
        constructor(oncancel?: Function);
        promise: Promise<T>;
        cancel();
        complete(value?: T);
        error(value?: any);
        progress(value?: any);
    }

    module Utilities {
        function _bubbleEvent(element: HTMLElement, type: string, eventObject: any): void;
        function _setImmediate(func: () => any): void;
        export function _getPositionRelativeTo(element: HTMLElement, ancestor: HTMLElement): IPosition;

        module _resizeNotifier {
            function subscribe(element: HTMLElement, handler): void;
            function unsubscribe(element: HTMLElement, handler): void;
            function _handleResize(): void;
        }

        var _browserStyleEquivalents: IStyleEquivalentsMap;

        function _setActive(element: HTMLElement, scroller?: HTMLElement);
        function _trySetActive(element: HTMLElement, scroller?: HTMLElement);
        function _setActiveFirstFocusableElement(rootEl: HTMLElement, scroller?: HTMLElement);
        function _setActiveLastFocusableElement(rootEl: HTMLElement, scroller?: HTMLElement);

        function _traceAsyncOperationStarting();
        function _traceAsyncOperationCompleted();
        function _traceAsyncCallbackStarting();
        function _traceAsyncCallbackCompleted();

        function _require(dep: string, callback);
        function _require(deps: string[], callback);
        function _uniqueID(e: HTMLElement): string;
        function _isDOMElement(e: HTMLElement): boolean;

        function _yieldForEvents(handler: Function);
        function _merge(a: any, b: any): any;
        function _mergeAll(list: any): any;
        var _isiOS;
        function _setIsiOS(isiOS: boolean);

        class _PointerEventProxy {
            constructor(eventObject, overrideProperties);
        }

        function _linkedListMixin(name: string);

        module Scheduler {
            var _usingWwaScheduler: boolean;
            var _MSApp;
            var _isEmpty;
            var _TIME_SLICE: number;
        }

        function _now();

        function _setHasWinRT(value: boolean);
        var _selectionPartsSelector;

        function _writeProfilerMark(mark: string);

        var _browserEventEquivalents: { [key: string]: string };

        var _DOMWeakRefTable_sweepPeriod: number;
        var _DOMWeakRefTable_timeout: number;
        var _DOMWeakRefTable_noTimeoutUnderDebugger: boolean;
        function _createWeakRef(element, id: string);
        function _getWeakRefElement(id: string): any;
        var _DOMWeakRefTable_tableSize: number;

        function _matchesSelector(element, selector: string): boolean;

        var _MutationObserver;
        function _isSelectionRendered(itemBox): boolean;
        var _getHighestTabIndexInList;
        var _getLowestTabIndexInList;
        var _MSPointerEvent;
        var _supportsSnapPoints: boolean;

        function _convertToPrecisePixels(value: string): number;
        function _getPreciseTotalHeight(element: HTMLElement): number;
        function _getPreciseTotalWidth(element: HTMLElement): number;
        function _getPreciseContentHeight(element: HTMLElement): number;
        function _getPreciseContentWidth(element: HTMLElement): number;
        function _getPreciseMargins(element: HTMLElement): { top: number; right: number; bottom: number; left: number; };

    }

    module Resources {
        function _getWinJSString(resourceId: string): { value: string; empty?: boolean; lang?: string; };
        function _getStringJS(resourceId: string): { value: string; empty?: boolean; lang?: string; };
    }

    module Application {
        var _terminateApp: (data: any, e: any) => void;
        function _dispatchEvent(eventRecord: any): void;
        function _loadState(e: any);
    }

    module UI {
        var _optionsLexer;
        var optionsParser;
        var _optionsParser;
        var _CallExpression;
        var _IdentifierExpression;
        var _GroupFocusCache;

        module _LightDismissService {
            interface ILightDismissInfo {
                reason: string;
                active: boolean;
                stopPropagation(): void;
                preventDefault(): void;
            }

            interface ILightDismissable {
                setZIndex(zIndex: string): void;
                getZIndexCount(): number;
                containsElement(element: HTMLElement): boolean;
                onActivate(): void;
                onFocus(element: HTMLElement): void;
                onHide(): void;
                onShouldLightDismiss(info: ILightDismissInfo): boolean;
                onLightDismiss(info: ILightDismissInfo): void;
            }

            function shown(client: ILightDismissable): void;
            function hidden(client: ILightDismissable): void;
            function isShown(client: ILightDismissable): boolean;
            function isTopmost(client: ILightDismissable): boolean;
            function _clickEaterTapped(): void;
        }

        class _ParallelWorkQueue {
            constructor(maxRunning: number);
            sort(sortFunc: (a: any, b: any) => number);
            queue(f: () => WinJS.Promise<any>, data?: any, first?: boolean);
        }

        class PrivateToggleSwitch extends WinJS.UI.ToggleSwitch {
            _pointerDownHandler(ev: any);
            _pointerUpHandler(ev: any);
            _pointerMoveHandler(ev: any);
        }

        class PrivateTabContainer extends WinJS.UI.TabContainer {
            _elementTabHelper;
            _hasMoreElementsInTabOrder;
        }

        class PrivateTooltip extends WinJS.UI.Tooltip {
            _disposed: boolean;
            _domElement: HTMLElement;

            static _DELAY_INITIAL_TOUCH_SHORT: number;
            static _DELAY_INITIAL_TOUCH_LONG: number;
            static _DEFAULT_MOUSE_HOVER_TIME: number;
            static _DEFAULT_MESSAGE_DURATION: number;
            static _DELAY_RESHOW_NONINFOTIP_TOUCH: number;
            static _DELAY_RESHOW_NONINFOTIP_NONTOUCH: number;
            static _DELAY_RESHOW_INFOTIP_TOUCH: number;
            static _DELAY_RESHOW_INFOTIP_NONTOUCH: number;
            static _RESHOW_THRESHOLD: number;
        }

        interface IContentDialogDom {
            root: HTMLElement;
            backgroundOverlay: HTMLElement;
            startBodyTab: HTMLElement;
            dialog: HTMLElement;
            title: HTMLElement;
            scroller: HTMLElement;
            commandContainer: HTMLElement;
            commands: HTMLElement;
            endBodyTab: HTMLElement;
            content: HTMLElement;
        }

        class PrivateContentDialog extends WinJS.UI.ContentDialog {
            static _ClassNames: any;
            _playEntranceAnimation(): Promise<any>;
            _playExitAnimation(): Promise<any>;
            _disposed: boolean;
            _state: any;
            _dom: IContentDialogDom;
            _updateTabIndices();
            _updateTabIndicesImpl();
        }

        class PrivateSplitView extends WinJS.UI.SplitView {
            static _ClassNames: {
                splitView: string;
                pane: string;
                content: string;
                // closed/opened
                paneOpened: string;
                paneClosed: string;
            }

            _playShowAnimation(): Promise<any>;
            _playHideAnimation(): Promise<any>;
            _prepareAnimation(paneRect: any, contentRect: any): void;
            _clearAnimation(): void;
            _disposed: boolean;
            _machine: IOpenCloseMachine
        }

        interface ISelect {
            value;
            index: number;
            _domElement;
        }

        interface ITimePicker extends WinJS.UI.TimePicker {
            _domElement: HTMLElement;
            _disposed: boolean;
            _ampmControl: ISelect;
            _ampmElement: HTMLSelectElement;
            _hourControl: ISelect;
            _hourElement: HTMLSelectElement;
            _minuteControl: ISelect;
            _minuteElement: HTMLSelectElement;
        }

        interface ISemanticZoom extends WinJS.UI.SemanticZoom {
            _showSemanticZoomButton();
            _onMouseWheel(evt);
            _pinching: boolean;
            _viewportIn;
            _viewportOut;
            _canvasIn;
            _canvasOut;
            _disposed;
        }

        var _listViewClass: string;
        var _viewportClass: string;
        var _horizontalClass: string;
        var _verticalClass: string;
        var _scrollableClass: string;
        var _containerClass: string;
        var _headerContainerClass: string;

        module _ListViewAnimationHelper {
            function fadeInElement(element): Promise<any>;
            function fadeOutElement(element): Promise<any>;
            function animateEntrance(canvas, firstEntrance): Promise<any>;
        }

        module _VirtualizeContentsView {
            var _maxTimePerCreateContainers;
            var _chunkSize;
            var _disableCustomPagesPrefetch;
            var _defaultPagesToPrefetch;
            var _createContainersJobTimeslice;
            var _startupChunkSize;
            var _iOSMaxLeadingPages;
            var _iOSMaxTrailingPages;
        }

        class PrivateAutoSuggestBox extends WinJS.UI.AutoSuggestBox {
            _disposed: boolean;
            _inputElement: HTMLInputElement;
            _isFlyoutPointerDown: boolean;
            _flyoutElement: HTMLDivElement;
            _lastKeyPressLanguage: string;
            _repeater: WinJS.UI.Repeater;
            _repeaterElement: HTMLDivElement;

            _inputOrImeChangeHandler(eventArg: Event);
            _tryGetInputContext(): MSInputMethodContext;

            static _sortAndMergeHits(hitsProvided?);
            static _EventNames: {
                querychanged;
                querysubmitted;
                resultsuggestionchosen;
                suggestionsrequested;
            };
        }

        class PrivateDatePicker extends DatePicker {
            _domElement;
            _disposed: boolean;
            static _getInformationJS;
            static _getInformationWinRT;
            static getInformation;
        }

        class PrivateFlipView<T> extends FlipView<T> {
            _pageManager;
            _animating: boolean;
        }

        class PrivateSemanticZoom extends SemanticZoom {
        }

        interface IPrivateSelection<T> extends ISelection<T> {
            _isIncluded(i: number): boolean;
            _pivot;
            _selected;
        }

        interface IPrivateListDataSource<T> extends IListDataSource<T> {
            list?: WinJS.Binding.List<T>;
            _list?: WinJS.Binding.List<T>;
        }

        interface IListViewEntity {
            type: WinJS.UI.ObjectType;
            index: number;
        }

        class PrivateListView<T> extends ListView<T> {
            _onMSElementResize();
            _animationsDisabled;
            _view;
            _ariaStartMarker;
            _ariaEndMarker;
            selection: IPrivateSelection<T>
            itemDataSource: IPrivateListDataSource<T>;
            _canvas;
            _viewport;
            _getViewportLength;
            _groups;
            _raiseViewLoading;
            _element;
            _horizontal(): boolean;
            _updateLayout;
            _affectedRange;
            _onFocusOut;
            _onFocusIn;
            _selection;
            _tabManager;
            _layout;
            _deleteWrapper;
            _mode;
            _itemsManager;
            _raiseViewComplete;
            _changeFocus;
            _keyboardFocusInbound: boolean;
            _currentMode;
            _dispose;
            _onMSManipulationStateChanged;
            _beginZoom;
            _endZoom;
            _versionManager;
            _scrollLength;
            _onPropertyChange;

            ensureVisible(itemIndex: number): void;
            ensureVisible(itemIndex: IListViewEntity): void;
            maxTrailingPages: number;
            maxLeadingPages: number;
        }

        class PrivateListLayout extends ListLayout {
            static _numberOfItemsPerItemsBlock: number;
            _itemsPerBar;
            initialize();
            initialize(layout, groupsEnabled);
            layout(tree: any, changedRange: any, modifiedItems: any, modifiedGroups: any): any;
            itemsFromRange(firstPixel: number, lastPixel: number): any;
            _measuringPromise;
            _envInfo;
            _sizes;
        }

        class PrivateGridLayout extends GridLayout {
            initialize();
            initialize(layout, groupsEnabled);
            layout(tree: any, changedRange: any, modifiedItems: any, modifiedGroups: any): any;
            itemsFromRange(firstPixel: number, lastPixel: number): any;
            _itemsPerBar;
            _measuringPromise;
            _envInfo;
            _sizes;
            _lastItemFromRange;
            _firstItemFromRange;
            _measureElements;
        }

        class PrivateCellSpanningLayout extends CellSpanningLayout {
            initialize();
            initialize(layout, groupsEnabled);
            layout(tree: any, changedRange: any, modifiedItems: any, modifiedGroups: any): any;
            itemsFromRange(firstPixel: number, lastPixel: number): any;
            _itemsPerBar;
            _measuringPromise;
            _envInfo;
            _sizes;
        }

        class PrivateCommandingSurface extends WinJS.UI._CommandingSurface {
            _disposed: boolean;
            _primaryCommands: PrivateCommand[];
            _secondaryCommands: PrivateCommand[];
            _getCommandWidth(command: ICommand): number;
            _contentFlyout: WinJS.UI.Flyout;
            _contentFlyoutInterior: HTMLElement;
            _dom: {
                root: HTMLElement;
                actionArea: HTMLElement;
                actionAreaContainer: HTMLElement;
                spacer: HTMLDivElement;
                overflowButton: HTMLButtonElement;
                overflowArea: HTMLElement;
                overflowAreaContainer: HTMLElement;
            };
            _machine: IOpenCloseMachine;
            _layoutCompleteCallback(): any;
            _menuCommandProjections: PrivateMenuCommand[];
        }

        class PrivateAppBar extends WinJS.UI.AppBar {
            _disposed: boolean;
            _dom: {
                root: HTMLElement;
                commandingSurfaceEl: HTMLElement;
            };
            _commandingSurface: WinJS.UI.PrivateCommandingSurface;
            _shouldAdjustForShowingKeyboard: () => boolean;
            _handleShowingKeyboard: () => Promise<any>;
            _handleHidingKeyboard: () => void;
            _updateDomImpl_renderedState: {
                adjustedOffsets: { top: string; bottom: string; };
            }
            _dismissable: _LightDismissService.ILightDismissable;
        }

        class PrivateToolBar extends WinJS.UI.ToolBar {
            _disposed: boolean;
            _dom: {
                root: HTMLElement;
                commandingSurfaceEl: HTMLElement;
                placeHolder: HTMLElement;
            };
            _commandingSurface: WinJS.UI.PrivateCommandingSurface;
            _dismissable: _LightDismissService.ILightDismissable;
            _handleShowingKeyboard: () => void;
        }

        export interface AppBarCommandPropertyMutatedEventObj {
            detail: {
                command: ICommand;
                oldValue: any;
                newValue: any;
                propertyName: string;
            };
        }

        class PrivateCommand extends WinJS.UI.AppBarCommand {
            winControl: ICommand;
            _commandBarIconButton;
            _disposed;
            _tooltipControl;
            _lastElementFocus;
            _propertyMutations: {
                bind(callback:any): void;
                unbind(callback:any): void;
                dispatchEvent(type: string, eventProperties: any): boolean;
            }
        }

        /**
        * Remnants of the previous implementation of the AppBar control, contains limited functionality.
          Currently only used by NavBar and is planned to be replaced by a new implementation.
        **/
        class _LegacyAppBar {
            constructor(element?: HTMLElement, options?: any);
            onafterclose(eventInfo: Event): void;
            onafteropen(eventInfo: Event): void;
            onbeforeclose(eventInfo: Event): void;
            onbeforeopen(eventInfo: Event): void;
            addEventListener(type: string, listener: Function, useCapture?: boolean): void;
            dispatchEvent(type: string, eventProperties: any): boolean;
            dispose(): void;
            getCommandById(id: string): AppBarCommand;
            close(): void;
            hideCommands(commands: any[], immediate?: boolean): void;
            removeEventListener(type: string, listener: Function, useCapture?: boolean): void;
            open(): void;
            showCommands(commands: any[], immediate?: boolean): void;
            showOnlyCommands(commands: any[], immediate?: boolean): void;
            closedDisplayMode: string;
            commands: AppBarCommand[];
            element: HTMLElement;
            opened: boolean;
            placement: string;
        }
        class PrivateLegacyAppBar extends _LegacyAppBar {
            getCommandById(id: string): PrivateCommand;
            showCommands(commands: any[], immediate?: boolean): void;
            showCommands(commands: any, immediate?: boolean): void;
            hideCommands(commands: any[], immediate?: boolean): void;
            hideCommands(commands: any, immediate?: boolean): void;
            showOnlyCommands(commands: any[], immediate?: boolean): void;
            showOnlyCommands(commands: any, immediate?: boolean): void;
            commands: any[];
            _disposed;
            _getCommands;
            _uniqueId;
            _updateFirstAndFinalDiv;
            _layout;
            _layoutImpl;
            _visiblePosition;
            _invokeButton: HTMLButtonElement;

            static _currentAppBarId;
            static _appBarsSynchronizationPromise;
        }

        class PrivateFlyout extends Flyout {
            _disposed;
            _previousFocus;

            static _cascadeManager;
        }

        class PrivateMenuCommand extends MenuCommand {
            _disposed;
            _toggleSpan;
            _labelSpan;
            _flyoutSpan;
            _invoke;
            static _activateFlyoutCommand;
        }

        class PrivateMenu extends Menu {
            _disposed;
        }

        class PrivateSettingsFlyout extends SettingsFlyout {
            _disposed;
        }

        class PrivateNavBar extends NavBar {
            _disposed;
        }

        class PrivateNavBarCommand extends NavBarCommand {
            _buttonEl;
            _disposed;
            _splitButtonEl;
            static _EventName;
        }

        class PrivateNavBarContainer extends NavBarContainer {
            _surfaceEl;
            _measured;
            _scrollPosition
            _sizes;
            _disposed;

            static _EventName;
        }

        class PrivateHub extends Hub {
            sections: WinJS.Binding.List<PrivateHubSection>;
            _viewportElement;

            static _EventName;
            static _ClassName;
            static LoadingState;
            static AnimationType;
        }

        class PrivateHubSection extends HubSection {
            _headerContentElement;
            _setHeaderTemplate;
            _headerTabStopElement;

            static _ClassName;
            static _Constants;
        }

        class PrivateBackButton extends BackButton {
            static _getReferenceCount(): number;
        }

        class PrivateRating extends Rating {
            _ensureTooltips;
            _toolTips;
            _disposed;
        }

        class PrivatePivot extends Pivot {

            _viewportElement;
            _goNext;
            _goPrevious;
            _headersContainerElement;
            _headersState;
            forceLayout();
            _navMode;
            _currentScrollTargetLocation;
            _viewportWidth;
            _headerItemsWidth: number;

            static _ClassName;
            static _EventName;
            static _NavigationModes;
        }

        class PrivatePivotItem extends PivotItem {
            static _ClassName;
        }

        class _CommandingSurface {
            public static ClosedDisplayMode: {
                none: string;
                minimal: string;
                compact: string;
                full: string;
            };
            public static OverflowDirection: {
                bottom: string;
                top: string;
            };
            public element: HTMLElement;
            public data: WinJS.Binding.List<ICommand>;
            constructor(element?: HTMLElement, options?: any);
            public dispose(): void;
            public forceLayout(): void;
            public closedDisplayMode: string;
            public createOpenAnimation(): { execute(): Promise<any> };
            public createCloseAnimation(): { execute(): Promise<any> };
            public open(): void;
            public close(): void;
            public opened: boolean;
            public getCommandById(id: string): ICommand;
            public showOnlyCommands(commands: Array<string|ICommand>): void;
            public onbeforeopen: (ev: CustomEvent) => void;
            public onafteropen: (ev: CustomEvent) => void;
            public onbeforeclose: (ev: CustomEvent) => void;
            public onafterclose: (ev: CustomEvent) => void;
            public overflowDirection: string;
            public addEventListener(eventName: string, eventHandler: Function, useCapture?: boolean): void;
            public removeEventListener(eventName: string, eventCallback: Function, useCapture?: boolean): void;
            public dispatchEvent(type: string, eventProperties: any): boolean;
        }

        class PrivateItemContainer extends WinJS.UI.ItemContainer {
            _selectionMode: WinJS.UI.SelectionMode;
            _onFocusIn();
            _onFocusOut();
            _onKeyDown(e);
            _itemEventsHandler;
            _itemBox;
            _disposed: boolean;
            static _ClassName;
        }

        var _ItemEventsHandler;
        var _LEFT_MSPOINTER_BUTTON;
        var _RIGHT_MSPOINTER_BUTTON;
        var _selectedClass;
        var _keyboardSeenLast;
        var _lastInputType;
        var _InputTypes: {
            mouse: string;
            keyboard: string;
            touch: string;
            pen: string;
        };
        var _itemFocusOutlineClass;
        var _itemBoxClass;
        var _itemClass;
        var _headerClass;
        var _itemFocusClass;
        var _pressedClass;
        var _itemsContainerClass;
        var _laidOutClass;
        var _cellSpanningGridLayoutClass;
        var _listLayoutClass;
        var _gridLayoutClass;
        var _uniformGridLayoutClass;
        var _selectionModeClass;
        var _itemsBlockClass;
        var _structuralNodesClass;
        var _progressClass;
        var _nonDraggableClass;
        var _nonSelectableClass;
        var _INVALID_INDEX;

        var _seenUrlsMaxSize: number;
        var _seenUrlsMRUMaxSize: number;
        function _seenUrl(url: string);
        function _getSeenUrlsMRU(): string[];
        function _getSeenUrls(): string[];

        function _animationTimeAdjustment(time: number);

        function _rotationTransform3d(angle, axis);
        function _tiltTransform(clickX, clickY, elementRect);

        var ListDataSource;
        var _SelectionMode;
        var _SelectionManager;
        var _NoGroups;
        var _VersionManager;
        var _getMargins;
        var _ItemSet;
        var _Selection;
        var _LayoutCommon;
        var _LISTVIEW_PROGRESS_DELAY;
        var _Overlay;
        var _AppBarCommandsLayout;

        module XYFocus {
            function _xyFocus(direction: string, referenceRect?: IRect): void;
        }

        module Pages {
            function _remove(frag);
            var _cacheStore;
        }

        module Fragments {
            var _cacheStore;
            function clearCache();
            var _getFragmentContents;
            var _writeProfilerMark;
        }
    }

    module Binding {
        class PrivateList<T> extends List<T> {
            _getKey(index: number): string;
            _getFromKey(key: string): T;
            _spliceFromKey(key: string, howMany: number, ...items: T[]): T[];
            _notifyMutatedFromKey(key: string);
        }
        function _bindingParser(input, context);
        function getValue(obj: any, path: string[]);

        class PrivateTemplate extends Template {
            static _interpretAll: boolean;
            _shouldCompile: boolean;
            _renderImpl;
            _compileTemplate;
            _reset;
        }

        var _TemplateCompiler;
    }
}


text:
More on this later!

## Admin Features

The following are features for Admin users. Most of these deal with app maintenance and setup.

#### Redshift Inflight Queries
![inflight](images/inflight.png)

Redshift only.

This tab contains a list of currently running queries allowing admins to monitor Aleph's usage on the Redshift cluster. It includes saved queries as well as unsaved queries run in the REPL.

This tab surfaces who is running the query as well as giving a link back to the original query (except REPL queries). Clicking on the clipboard icon will copy formatted sql to your clipboard.

The list is searchable and sortable.

Only `admin` users will see an Inflight tab.

#### Schema Filters

These are site wide, saved filters to hide schema information by schema or table. Supports both black and white list style filter based on regex. This is useful if you have some "operational" tables in Redshift/Snowflake that you do not want to expose to end users.

See [example here](../config/example/table_blacklist.yml)


text:
Plugin.define "EverFocus-CCTV" do
author "Brendan Coles <bcoles@gmail.com>" # 2011-04-08
version "0.1"
description "EverFoxus CCTV router web interface"
website "http://www.everfocus.com/products.cfm"

# Default Logins:
# EverFocus - PowerPlex - admin:admin
# EverFocus - PowerPlex - supervisor:supervisor
# EverFocus - PowerPlex - operator:operator

# ShodanHQ results as at 2011-04-08 #
# 5,871 for http server/everfocus

# Matches #
matches [

# Redirect page
{ :regexp=>/^	If the page is not redirected, please click here<\/a>
$/ },

# HTML Comment
{ :text=>'' },

]

# Passive #
def passive
	m=[]

	# HTTP Server Header
	if @headers["server"] =~ /^http server\/everfocus$/

		m << { :name=>"HTTP Server Header" }

		# HTML Comment
		if @body =~ //

			# Version Detection
			m << { :version=>@body.scan(/^/).flatten }

			# Firmware Build/Year Detection
			m << { :firmware=>@body.scan(/^/).flatten }

		end

		# ERViewer.ocx Version Detection # JavaScript
		m << { :module=>"ERViewer.ocx/"+@body.scan(/var g_sVersion = "([\d\.]+)"/).flatten } if @body =~ /var g_sVersion = "[\d\.]+"/

	end

	# Return passive matches
	m
end

end


text:
package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/EverythingMe/meduza/query"

	"gopkg.in/yaml.v2"

	"github.com/dvirsky/go-pylog/logging"
)

// ListenCtl starts the conrtol server, panics if it can't be started
func ListenCtl(addr string) {

	mux := http.NewServeMux()
	mux.HandleFunc("/deploy", HandleDeploySchema)
	mux.HandleFunc("/status", HandleStatus)
	mux.HandleFunc("/confdump", HandleDumpConfig)
	mux.HandleFunc("/stats", HandleStats)
	mux.HandleFunc("/schemadump", HandleDumpSchema)
	mux.HandleFunc("/dump", HandleDumpData)
	mux.HandleFunc("/load", HandleLoadDump)
	mux.HandleFunc("/drop", HandleDrop)

	go func() {
		logging.Info("Starting ctl server on %s", addr)
		err := http.ListenAndServe(addr, mux)
		if err != nil {
			panic(err)
		}
	}()
}

func HandleDumpSchema(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	sch := r.FormValue("schema")

	for _, s := range meduzaServer.sp.Schemas() {
		if s.Name == sch {

			b, err := yaml.Marshal(s)
			if err != nil {
				http.Error(w, "Could not dump schema: "+err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "text/yaml")
			w.Write(b)
			return
		}
	}
	http.Error(w, "Could not find schema "+sch, http.StatusNotFound)
}

func HandleDumpData(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	sch := r.FormValue("schema")
	tbl := r.FormValue("table")

	err := meduzaServer.Dump(sch, tbl, w)
	if err != nil {
		fmt.Fprintf(w, "\nError dumping data: %s\n ", err)
	}
}

func HandleLoadDump(w http.ResponseWriter, r *http.Request) {

	sch := r.URL.Query().Get("schema")
	tbl := r.URL.Query().Get("table")

	err := meduzaServer.LoadDump(sch, tbl, r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	} else {
		fmt.Fprintln(w, "OK")
	}

}

func HandleDrop(w http.ResponseWriter, r *http.Request) {

	sch := r.URL.Query().Get("schema")
	tbl := r.URL.Query().Get("table")

	dq := query.NewDelQuery(fmt.Sprintf("%s.%s", sch, tbl)).Where("id", query.All)
	dr := meduzaServer.drv.Delete(*dq)
	if dr.Err() != nil {
		http.Error(w, dr.Err().Error(), http.StatusInternalServerError)
	} else {
		fmt.Fprintf(w, "Deleted %d records", dr.Num)
	}

}

func HandleDeploySchema(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	var data string
	uri := r.FormValue("uri")
	if uri == "" {
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "Error reading form data", 400)
			return
		}

		data = string(b)

	}

	if uri == "" && data == "" {
		http.Error(w, "No data URI or raw data given", 400)
		return
	}

	var err error
	if uri != "" {
		logging.Info("Deploying schema from uri %s", uri)
		err = meduzaServer.sd.DeployUri(uri)
	} else {
		if len(data) > 10 {
			logging.Info("Deploying raw schema data '%s...' (%d bytes)", data[:10], len(data))
		}

		err = meduzaServer.sd.Deploy(strings.NewReader(data))
	}

	if err == nil {
		logging.Info("Successfully written schema")
		w.Write([]byte("OK"))
	} else {
		logging.Error("Error deploying schema: %s", err)
		http.Error(w, fmt.Sprintf("Error deploying schema: %s", err), 500)
	}

}

func HandleStatus(w http.ResponseWriter, r *http.Request) {

	var err error
	if meduzaServer == nil {
		err = errors.New("No meduza node running")
	}

	if err == nil {
		err = meduzaServer.Status()
	}

	if err != nil {
		logging.Error("Status check failed: %s", err)
		http.Error(w, err.Error()+"\r\n", 500)

	} else {
		w.Write([]byte("OK\r\n"))
	}

}

func HandleDumpConfig(w http.ResponseWriter, r *http.Request) {

	b, err := yaml.Marshal(config)
	if err != nil {
		http.Error(w, "Error dumping configs: "+err.Error(), 500)
		return
	}

	w.Header().Set("Content-Type", "text/yaml")
	w.Write(b)

}

func HandleStats(w http.ResponseWriter, r *http.Request) {

	defer func() {
		err := recover()
		if err != nil {
			logging.Error("PANIC dumping stats: %s", err)
		}
	}()

	stats, err := meduzaServer.Stats()

	if err != nil {
		http.Error(w, "Error dumping stats: "+err.Error(), 500)
		return
	}

	b, err := yaml.Marshal(stats)
	if err != nil {
		http.Error(w, "Error dumping stats: "+err.Error(), 500)
		return
	}

	w.Header().Set("Content-Type", "text/yaml")
	w.Write(b)

}


text:
#include <aws/elasticloadbalancingv2/model/ModifyTargetGroupAttributesRequest.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h>

using namespace Aws::ElasticLoadBalancingv2::Model;
using namespace Aws::Utils;

ModifyTargetGroupAttributesRequest::ModifyTargetGroupAttributesRequest() :
    m_targetGroupArnHasBeenSet(false),
    m_attributesHasBeenSet(false)
{
}

Aws::String ModifyTargetGroupAttributesRequest::SerializePayload() const
{
  Aws::StringStream ss;
  ss << "Action=ModifyTargetGroupAttributes&";
  if(m_targetGroupArnHasBeenSet)
  {
    ss << "TargetGroupArn=" << StringUtils::URLEncode(m_targetGroupArn.c_str()) << "&";
  }

  if(m_attributesHasBeenSet)
  {
    unsigned attributesCount = 1;
    for(auto& item : m_attributes)
    {
      item.OutputToStream(ss, "Attributes.member.", attributesCount, "");
      attributesCount++;
    }
  }

  ss << "Version=2015-12-01";
  return ss.str();
}

void  ModifyTargetGroupAttributesRequest::DumpBodyToUrl(Aws::Http::URI& uri ) const
{
  uri.SetQueryString(SerializePayload());
}


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

using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Twilio.TwiML.Tests
{
    [TestClass]
	public class SmsTests : TestBase
	{
		[TestMethod]
		public void Can_Generate_Single_Sms()
		{
			var response = new TwilioResponse();
			response.Sms("Hello world");

			Assert.IsTrue(IsValidTwiML(response.ToXDocument()));
		}

		[TestMethod]
		public void Can_Generate_Single_Sms_And_Attributes()
		{
			var response = new TwilioResponse();
			response.Sms("Hello world", new { to = "+15551111111", from = "+15552222222", action = "sms.php", method = "GET", statusCallback = "status.php" });

			Assert.IsTrue(IsValidTwiML(response.ToXDocument()));
		}
	}
}


text:
package http

import (
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/smira/aptly/aptly"
	"github.com/smira/aptly/utils"
)

type expectedRequest struct {
	URL      string
	Err      error
	Response string
}

// FakeDownloader is like Downloader, but it used in tests
// to stub out results
type FakeDownloader struct {
	expected    []expectedRequest
	anyExpected map[string]expectedRequest
}

// Check interface
var (
	_ aptly.Downloader = (*FakeDownloader)(nil)
)

// NewFakeDownloader creates new expected downloader
func NewFakeDownloader() *FakeDownloader {
	result := &FakeDownloader{}
	result.expected = make([]expectedRequest, 0)
	result.anyExpected = make(map[string]expectedRequest)
	return result
}

// ExpectResponse installs expectation on upcoming download with response
func (f *FakeDownloader) ExpectResponse(url string, response string) *FakeDownloader {
	f.expected = append(f.expected, expectedRequest{URL: url, Response: response})
	return f
}

// AnyExpectResponse installs expectation on upcoming download with response in any order (url should be unique)
func (f *FakeDownloader) AnyExpectResponse(url string, response string) *FakeDownloader {
	f.anyExpected[url] = expectedRequest{URL: url, Response: response}
	return f
}

// ExpectError installs expectation on upcoming download with error
func (f *FakeDownloader) ExpectError(url string, err error) *FakeDownloader {
	f.expected = append(f.expected, expectedRequest{URL: url, Err: err})
	return f
}

// Empty verifies that are planned downloads have happened
func (f *FakeDownloader) Empty() bool {
	return len(f.expected) == 0
}

// DownloadWithChecksum performs fake download by matching against first expectation in the queue or any expectation, with cheksum verification
func (f *FakeDownloader) DownloadWithChecksum(url string, filename string, expected *utils.ChecksumInfo, ignoreMismatch bool, maxTries int) error {
	var expectation expectedRequest
	if len(f.expected) > 0 && f.expected[0].URL == url {
		expectation, f.expected = f.expected[0], f.expected[1:]
	} else if _, ok := f.anyExpected[url]; ok {
		expectation = f.anyExpected[url]
		delete(f.anyExpected, url)
	} else {
		return fmt.Errorf("unexpected request for %s", url)
	}

	if expectation.Err != nil {
		return expectation.Err
	}

	err := os.MkdirAll(filepath.Dir(filename), 0755)
	if err != nil {
		return err
	}

	outfile, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer outfile.Close()

	cks := utils.NewChecksumWriter()
	w := io.MultiWriter(outfile, cks)

	_, err = w.Write([]byte(expectation.Response))
	if err != nil {
		return err
	}

	if expected != nil {
		if expected.Size != cks.Sum().Size || expected.MD5 != "" && expected.MD5 != cks.Sum().MD5 ||
			expected.SHA1 != "" && expected.SHA1 != cks.Sum().SHA1 || expected.SHA256 != "" && expected.SHA256 != cks.Sum().SHA256 {
			if ignoreMismatch {
				fmt.Printf("WARNING: checksums don't match: %#v != %#v for %s\n", expected, cks.Sum(), url)
			} else {
				return fmt.Errorf("checksums don't match: %#v != %#v for %s", expected, cks.Sum(), url)
			}
		}
	}

	return nil
}

// Download performs fake download by matching against first expectation in the queue
func (f *FakeDownloader) Download(url string, filename string) error {
	return f.DownloadWithChecksum(url, filename, nil, false, 1)
}

// GetProgress returns Progress object
func (f *FakeDownloader) GetProgress() aptly.Progress {
	return nil
}