Index: geniuswebcore/geniusweb/bidspace/BidsWithUtility.py
===================================================================
--- geniuswebcore/geniusweb/bidspace/BidsWithUtility.py	(revision 81)
+++ geniuswebcore/geniusweb/bidspace/BidsWithUtility.py	(revision 81)
@@ -0,0 +1,209 @@
+
+
+from geniusweb.issuevalue.Bid import Bid
+from geniusweb.issuevalue.Domain import Domain
+from geniusweb.issuevalue.Value import Value
+from geniusweb.profile.utilityspace.LinearAdditive import LinearAdditive
+from tudelft.utilities.immutablelist.AbstractImmutableList import AbstractImmutableList
+from tudelft.utilities.immutablelist.FixedList import FixedList
+from tudelft.utilities.immutablelist.ImmutableList import ImmutableList
+from tudelft.utilities.immutablelist.JoinedList import JoinedList
+from tudelft.utilities.immutablelist.MapList import MapList
+from tudelft.utilities.immutablelist.Tuple import Tuple
+from typing import List, Dict
+from geniusweb.bidspace.IssueInfo import IssueInfo
+from geniusweb.bidspace.Interval import Interval
+from geniusweb.utils import val
+from decimal import Decimal
+
+class BidsWithUtility :
+	'''
+	WARNING DO NOT USE, NOT YET WORKING CORRECTLY
+	
+	Tool class containing functions dealing with utilities of all bids in a given
+	{@link LinearAdditive}. This class caches previously computed values to
+	accelerate the calls and subsequent calls. Re-use the object to keep/reuse
+	the cache.
+	<h2>Rounding</h2> Internally, utilities of bids are rounded to the given
+	precision. This may cause inclusion/exclusion of some bids in the results.
+	See {@link #BidsWithUtility(LinearAdditive, int)} for more details
+	Immutable.
+	'''
+
+
+	def __init__(self, issuesInfo:List[IssueInfo] , precision:int ) :
+		'''
+		@param issuesInfo List of the relevant issues (in order of relevance) and
+		                  all info of each issue.
+		@param precision the number of digits to use for computations. In
+		                 practice, 6 seems a good default value.
+		                 <p>
+		                 All utilities * weight are rounded to this number of
+		                 digits. This value should match the max number of
+		                 (digits used in the weight of an issue + number of
+		                 digits used in the issue utility). To determine the
+		                 optimal value, one may consider the step size of the
+		                 issues, and the range of interest. For instance if the
+		                 utility function has values 1/3 and 2/3, then these have
+		                 an 'infinite' number of relevant digits. But if the goal
+		                 is to search bids between utility 0.1 and 0.2, then
+		                 computing in 2 digits might already be sufficient.
+		                 <p>
+		                 This algorithm has memory and space complexity O(
+		                 |nissues| 10^precision ). For spaces up to 7 issues, 7
+		                 digits should be feasible; for 9 issues, 6 digits may be
+		                 the maximum.
+		'''
+		if issuesInfo == None or len(issuesInfo)==0:
+			raise ValueError("sortedissues list must contain at least 1 element")
+		self._issueInfo = issuesInfo;
+		self._precision = precision;
+		# cache. Key = call arguments for {@link #get(int, Interval)}. Value=return
+	 	# value of that call.
+
+		self._cache:Dict[Tuple[int, Interval], ImmutableList[Bid]]  = {}
+
+	@staticmethod
+	def create(space:LinearAdditive, precision:int=6) -> "BidsWithUtility":
+		'''
+		Support constructor, uses default precision 6. This value seems practical
+		for the common range of issues, utilities and weights. See
+		{@link #BidsWithUtility(LinearAdditive, int)} for more details on the
+		precision.
+		
+		@param space the {@link LinearAdditive} to analyze
+		@param space     the {@link LinearAdditive} to analyze. Optional, defaults to 6
+		'''
+		return BidsWithUtility(BidsWithUtility._getInfo(space, precision), precision);
+
+
+	def getRange(self) ->Interval :
+		'''
+		@return the (rounded) utility {@link Interval} of this space: minimum and
+		        maximum achievable utility.
+		'''
+		return self._getRange(len(self._issueInfo) - 1)
+
+	def getBids(self, range: Interval) -> ImmutableList[Bid] :
+		'''
+		@param range the minimum and maximum utility required of the bids. to be
+		             included (both ends inclusive).
+		@return a list with bids that have a (rounded) utility inside range.
+		        possibly empty.
+		'''
+		return self._get(len(self._issueInfo) - 1, range.round(self._precision));
+
+	def getInfo(self) -> List[IssueInfo] :
+		return self._issueInfo.copy()
+
+	def getExtremeBid(self, isMax:bool) ->Bid :
+		'''
+		@param isMax the extreme bid required
+		@return the extreme bid, either the minimum if isMax=false or maximum if
+		        isMax=true
+		'''
+		map:Dict[str, Value]  = {}
+		for info in self._issueInfo:
+			map[info.getName()] = info.getExtreme(isMax)
+		return Bid(map)
+
+	def _get(self, n:int , goal:Interval) -> ImmutableList[Bid] :
+		'''
+		Create partial BidsWithUtil list considering only issues 0..n, with
+		utilities in given range.
+		
+		@param n    the number of issueRanges to consider, we consider 0..n here.
+		            The recursion decreases n until n=0
+		@param goal the minimum and maximum utility required of the bids. to be
+		            included (both ends inclusive)
+		@return BidsWithUtil list, possibly empty.
+		'''
+		if goal == None:
+			raise ValueError("Interval=null")
+
+		# clamp goal into what is reachable. Avoid caching empty
+		goal = goal.intersect(self._getRange(n))
+		if (goal.isEmpty()):
+			return FixedList([])
+
+		cachetuple = Tuple(n, goal)
+		if (cachetuple in self._cache):
+			return self._cache[cachetuple]
+
+		result = self._checkedGet(n, goal)
+		self._cache[cachetuple]=result
+		return result
+
+	@staticmethod
+	def _getInfo(space2:LinearAdditive , precision:int) -> List[IssueInfo] :
+		dom = space2.getDomain()
+		return [IssueInfo(issue, dom.getValues(issue), \
+				val(space2.getUtilities().get(issue)), \
+				space2.getWeight(issue), precision) \
+				for issue in dom.getIssues()]
+		
+
+	def _checkedGet(self, n:int, goal:Interval ) -> ImmutableList[Bid] :
+		info = self._issueInfo[n]
+		# issue is the first issuesWithRange.
+		issue = info.getName()
+
+		if n == 0:
+			return OneIssueSubset(info, goal)
+
+		# make new list, joining all sub-lists
+		fulllist:ImmutableList[Bid]  = FixedList([])
+		for val in info.getValues():
+			weightedutil = info.getWeightedUtil(val)
+			subgoal = goal.subtract(weightedutil)
+			# recurse: get list of bids for the subspace
+			partialbids = self._get(n - 1, subgoal)
+
+			bid = Bid({issue: val})
+			fullbids = BidsWithUtility.maplist(bid, partialbids)
+			if fullbids.size() != 0:
+				fulllist = JoinedList[Bid]([fullbids, fulllist])
+		return fulllist
+	
+	@staticmethod
+	def maplist(bid: Bid, partialbids: ImmutableList[Bid]) -> ImmutableList[Bid]:
+		'''
+		this is just to force a scope onto bid
+		'''
+		return MapList[Bid, Bid](lambda pbid: pbid.merge(bid), partialbids)
+
+	def _getRange(self,  n:int) ->Interval :
+		'''
+		@param n the maximum issuevalue utility to include. Use n=index of last
+		         issue s= (#issues in the domain - 1) for the full range of this
+		         domain.
+		@return Interval (min, max) of the total weighted utility Interval of
+		        issues 0..n. All weighted utilities have been rounded to the set
+		        {@link #precision}
+		'''
+		value = Interval(Decimal(0),Decimal(0))
+		for i in range(0,n+1): # include end point
+			value = value.add(self._issueInfo[i].getInterval())
+		return value
+
+class OneIssueSubset (AbstractImmutableList[Bid]):
+	'''
+	List of all one-issue bids that have utility inside given interval.
+	'''
+	def __init__(self, info:IssueInfo , interval:Interval ) :
+		'''
+		@param info     the {@link IssueInfo}
+		@param interval a utility interval (weighted)
+		'''
+		self._info = info;
+		self._interval = interval;
+		self._size = info._subsetSize(interval)
+
+	#Override
+	def get(self, index:int) ->Bid :
+		return Bid({self._info.getName():
+				self._info._subset(self._interval)[index]})
+
+	#Override
+	def size(self) ->int:
+		return self._size
Index: geniuswebcore/geniusweb/bidspace/Interval.py
===================================================================
--- geniuswebcore/geniusweb/bidspace/Interval.py	(revision 81)
+++ geniuswebcore/geniusweb/bidspace/Interval.py	(revision 81)
@@ -0,0 +1,110 @@
+from decimal import Decimal
+from math import floor, ceil
+from typing import Optional
+
+class Interval:
+	'''
+	An interval [min, max].
+	'''
+	#ZERO = Interval(0,0) can't be done in Python...
+
+
+	def __init__(self, min:Decimal, max:Decimal):
+		'''
+		AN interval [min,max]. If min &gt; max, then there are no values in this
+		interval.
+		
+		@param min the minimum value of the interval
+		@param max the maximum value of the interval
+		'''
+		if min == None or max == None:
+			raise ValueError("min and max must contain not None")
+		self._min = min
+		self._max = max
+
+	def getMin(self)->Decimal :
+		'''
+		@return the minimum value of the interval
+		'''
+		return self._min
+
+	def getMax(self) ->Decimal :
+		'''
+		@return the maximum value of the interval
+		'''
+		return self._max
+
+	def isEmpty(self)->bool :
+		'''
+	 	@return true iff this range does not contain any element.
+		'''
+		return self._min > self._max
+
+	def contains(self, value:Decimal ) ->bool :
+		'''
+		@param value the value to test
+		@return true iff min &le; value &le; max
+		'''
+		return self._min<=value  and self._max>= value
+
+	def add(self, other:"Interval" ) ->"Interval" :
+		'''
+		@param other {@link Interval} to be added to this
+		@return new interval [ this.min + other.min , this.max + other.max ]
+		'''
+		return Interval(self._min + other._min, self._max+other._max)
+
+	def intersect(self, other:"Interval" ) ->"Interval" :
+		'''
+		@param other another {@link Interval} intersect with
+		@return intersection of this with other. returns null if intersection is
+		        empty.
+		'''
+		return Interval(max(self._min,other._min),min(self._max,other._max))
+
+	def invert(self,  other:"Interval") -> Optional["Interval"] :
+		'''
+		@param other the other minmax to deal with
+		@return the range of values that, when added to a value from other, will
+		        possibly get in our range. effectively, [min-other.max,
+		        max-other.min]. Returns None if the resulting range is empty.
+		'''
+		newmin = self._min-other._max
+		newmax = self._max-other._min
+		if newmin>newmax:
+			return None;
+		return Interval(newmin, newmax);
+
+	def subtract(self,  value:Decimal) ->"Interval" :
+		'''
+		@param value the value to subtract
+		@return Interval with both min and max reduced by value.
+		'''
+		return Interval(self._min-value, self._max-value)
+
+	def multiply(self, weight:Decimal ) -> "Interval" :
+		return Interval(self._min*weight, self._max*weight)
+	
+	#Override
+	def __repr__(self) ->str:
+		return "Interval[" + str(self._min) + "," + str(self._max) + "]"
+
+	def round(self, precision:int)->"Interval" :
+		'''
+		@param precision number of digits required
+		@return this but with modified precision. The interval is rounded so that
+		        the new interval is inside the old one.
+		'''
+		factor=Decimal(10)**precision
+		return Interval( ceil(self._min * factor)/factor,
+						floor(self._max * factor)/factor)	
+
+	#Override
+	def __hash__(self)->int:
+		return hash((self._min, self._max))
+
+	def __eq__(self, other):
+		return isinstance(other, self.__class__) and \
+			self._min == other._min and \
+			self._max == other._max
+
Index: geniuswebcore/geniusweb/bidspace/IssueInfo.py
===================================================================
--- geniuswebcore/geniusweb/bidspace/IssueInfo.py	(revision 81)
+++ geniuswebcore/geniusweb/bidspace/IssueInfo.py	(revision 81)
@@ -0,0 +1,127 @@
+from decimal import Decimal
+from geniusweb.issuevalue.ValueSet import ValueSet
+from geniusweb.profile.utilityspace.ValueSetUtilities import ValueSetUtilities
+from geniusweb.bidspace.Interval import Interval
+from geniusweb.issuevalue.Value import Value
+from typing import List, Dict, Optional
+
+class IssueInfo:
+	'''
+	 Tool class to collect all relevant info about one issue (from LinearAdditive)
+	 in one class. Used for internally grouping data for more efficient
+	 processing. This class may change in the future, not recommended for direct
+	 use.
+	 <p>
+	 immutable
+	'''
+
+	def __init__(self, name:str, values:ValueSet ,  utils:ValueSetUtilities,
+			weight:Decimal , precision:int ) :
+		'''
+		@param name      the issue name
+		@param values    the {@link ValueSet} of the issue
+		@param utils     the {@link ValueSetUtilities} of the issue profile
+		@param weight    the weight of the {@link ValueSetUtilities}
+		@param precision the precision to compute with. Basically the number of
+		         decimal places used for the computations.
+		'''
+		self._name = name;
+		self._values = values;
+		self._weightedUtils = self._computeWeightedUtils(utils, weight, precision);
+		self._interval = self._getRange();
+
+	def getValues(self) ->ValueSet :
+		return self._values
+
+	def getName(self)->str:
+		return self._name;
+
+	def getInterval(self)->Interval:
+		'''
+		@return weighted minimum and maximum utility achievable with this issue,
+		    rounded to the requested precision.
+		'''
+		return self._interval;
+
+	def getExtreme(self, isMax:bool)->Value :
+		'''
+		@param isMax if true the max {@link Value} is returned, else the min is
+		             returned.
+		@return the extreme value, either the minimum if isMax=false or maximum
+		        if isMax=true
+		'''
+		extremeutil:Decimal = None #type:ignore
+		extremeval:Decimal = None #type:ignore
+		for val in self._values:
+			util = self._weightedUtils.get(val)
+			if extremeval == None:
+				extremeutil = self._weightedUtils.get(val) #type:ignore
+				extremeval = val
+			else:
+				if isMax:
+					if util > extremeutil: #type:ignore
+						extremeutil = util #type:ignore
+						extremeval = val
+				else:
+					if util<extremeutil: #type:ignore
+						extremeutil = util #type:ignore
+						extremeval = val
+		return extremeval #type:ignore
+
+	def getWeightedUtil(self, val:Value ) -> Decimal :
+		'''
+		@param val the issue value to be evaluated
+		@return weighted utility of given value, rounded to nearest value with
+		        the requested precision number of digits.
+		'''
+		return self._weightedUtils.get(val) #type:ignore
+
+	def _subset(self,  interval:Interval) -> List[Value]:
+		'''
+		@param interval an {@link Interval} of utility values.
+		@return all values that are inside the interval.
+		'''
+
+		selection:List[Value]  = []
+		for value in self._values:
+			if interval.contains(self.getWeightedUtil(value)):
+				selection.append(value);
+		return selection
+
+	def _subsetSize( self, interval:Interval) ->int:
+		'''
+		Faster way to determine subset size, it does not create a list
+		
+		@param interval an {@link Interval} of utility values.
+		@return size of the subset that you will get from calling subset
+		'''
+		n = 0
+		for value in self._values:
+			if interval.contains(self.getWeightedUtil(value)):
+				n=n+1
+		return n
+
+	def _getRange(self)->Interval :
+		'''
+		@return the {@link Interval} (minimum and maximum) of the utility of the
+		        weighted utility of this issue, properly rounded to the
+		        {@link #precision}/
+
+		'''
+		min = Decimal(1)
+		max = Decimal(0)
+		for value in  self._values:
+			util = self.getWeightedUtil(value)
+			if util < min:
+				min = util
+			if util > max:
+				max = util
+		return Interval(min, max)
+
+	def _computeWeightedUtils(self, utilities:ValueSetUtilities, w:Decimal, prec:int) \
+				-> Dict[Value, Decimal] :
+		map:Dict[Value, Decimal]  = {}
+
+		for val in self._values:
+			map[val] = round(utilities.getUtility(val)* w, prec)
+		return map
Index: geniuswebcore/geniusweb/issuevalue/Bid.py
===================================================================
--- geniuswebcore/geniusweb/issuevalue/Bid.py	(revision 80)
+++ geniuswebcore/geniusweb/issuevalue/Bid.py	(revision 81)
@@ -34,5 +34,5 @@
         '''
         @param issue name of the issue
-        @return the value for the given issue, or null if there is no value for
+        @return the value for the given issue, or None if there is no value for
                 the given issue.
         '''
Index: geniuswebcore/geniusweb/references/Parameters.py
===================================================================
--- geniuswebcore/geniusweb/references/Parameters.py	(revision 80)
+++ geniuswebcore/geniusweb/references/Parameters.py	(revision 81)
@@ -4,4 +4,5 @@
 from email._header_value_parser import Parameter
 from typing import Dict, Any, List, Optional
+from numbers import Number
 
 from pyson.JsonGetter import JsonGetter
@@ -103,5 +104,5 @@
 		        contain a double, or is outside [min, max].
 		'''
-		if  not name in self._params or not type(self._params[name])==float:
+		if  not name in self._params or not isinstance(self._params[name], Number):
 			return defaultval;
 		val:float = self._params[name]
Index: geniuswebcore/requirements.txt
===================================================================
--- geniuswebcore/requirements.txt	(revision 80)
+++ geniuswebcore/requirements.txt	(revision 81)
@@ -1,5 +1,5 @@
 wheel
 https://tracinsy.ewi.tudelft.nl/pubtrac/Utilities/export/312/pyson/dist/pyson-1.1.3.tar.gz
-https://tracinsy.ewi.tudelft.nl/pubtrac/Utilities/export/309/utilitiespy/dist/utilities-1.0.4.tar.gz
+https://tracinsy.ewi.tudelft.nl/pubtrac/Utilities/export/314/utilitiespy/dist/utilities-1.0.5.tar.gz
 https://tracinsy.ewi.tudelft.nl/pubtrac/Utilities/export/226/loggingpy/dist/logging-1.0.0.tar.gz
 websocket-client==1.0.1
Index: geniuswebcore/setup.py
===================================================================
--- geniuswebcore/setup.py	(revision 80)
+++ geniuswebcore/setup.py	(revision 81)
@@ -3,5 +3,5 @@
 setup(
     name='geniusweb',
-    version='1.1.2',    
+    version='1.1.3',    
     description='GeniusWeb glue code to connect python3 parties',
     url='https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWeb',
@@ -12,5 +12,5 @@
     install_requires=[ 
         "pyson@https://tracinsy.ewi.tudelft.nl/pubtrac/Utilities/export/312/pyson/dist/pyson-1.1.3.tar.gz",
-        "utilities@https://tracinsy.ewi.tudelft.nl/pubtrac/Utilities/export/309/utilitiespy/dist/utilities-1.0.4.tar.gz",
+        "utilities@https://tracinsy.ewi.tudelft.nl/pubtrac/Utilities/export/314/utilitiespy/dist/utilities-1.0.5.tar.gz",
         "logging@https://tracinsy.ewi.tudelft.nl/pubtrac/Utilities/export/226/loggingpy/dist/logging-1.0.0.tar.gz",
         "websocket-client==1.0.1"
Index: geniuswebcore/test/geniusweb/bidspace/BidsWithUtilityTest.py
===================================================================
--- geniuswebcore/test/geniusweb/bidspace/BidsWithUtilityTest.py	(revision 81)
+++ geniuswebcore/test/geniusweb/bidspace/BidsWithUtilityTest.py	(revision 81)
@@ -0,0 +1,97 @@
+import unittest
+from pyson.ObjectMapper import ObjectMapper
+from geniusweb.bidspace.Interval import Interval
+from decimal import Decimal
+from geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace import LinearAdditiveUtilitySpace
+import json
+from geniusweb.profile.Profile import Profile
+from geniusweb.bidspace.BidsWithUtility import BidsWithUtility
+from random import randrange
+from geniusweb.bidspace.AllBidsList import AllBidsList
+import time
+from pathlib import Path
+
+class BidsWithUtilityTest(unittest.TestCase):
+	jackson = ObjectMapper()
+	utilityGoal = Interval(Decimal("0.50"), Decimal("0.51"))
+	accuracy = 5
+	
+	
+	parameters=[
+		[ "test/resources/jobs/jobs1.json", 11 ],
+		[ "test/resources/7issues/7issues1.json", 260000 ],
+		[ "test/resources/9issues/9issues1.json", 25000000 ] 
+	]
+	
+	def testAll(self):
+		''' 
+		runs all the tests. Python has no standard 'parameterized' mechanism
+		so we have to do it ourselves.
+		'''
+		for [filename, expectedsize] in self.parameters:
+			self.filename=filename
+			self.expectedSize= expectedsize
+			with self.subTest("test"+self.filename):
+				self.before()
+				self.simple()
+			with self.subTest("testMaxUtil"+self.filename):
+				self.before()
+				self.MaxUtil()
+			with self.subTest("benchmark"+self.filename):
+				self.before()
+				self.benchmark()
+
+	def before(self):
+		print("Running from file " + self.filename)
+		file = Path(self.filename).read_text("utf-8")
+		self.profile = self.jackson.parse(json.loads(file), Profile)
+
+			
+
+	def simple(self):
+		'''
+		Test if the values are within acceptable range from the goal.
+		'''
+		list = BidsWithUtility.create(self.profile, self.accuracy).getBids(self.utilityGoal);
+		#check not all but only 10000 random bids as list may be way too large
+		#to test them all. Testing 1 billion bids may take 15 minutes or so on
+		#quad core i7 @2.4GHz.....
+		#also notice that we may be checking only part of the list if
+		#the size of the list would become bigger than maxint.
+		for n in range(10000):
+			bid = list.get(randrange(list.size()))
+			self.assertTrue(self.utilityGoal.contains(
+				round(self.profile.getUtility(bid),self.accuracy-1)),
+				"bid "+str(bid)+" is not in range "+str(self.utilityGoal))
+						
+		self.assertTrue(list.size()>= self.expectedSize)
+
+	def MaxUtil(self) :
+		bidswithutil = BidsWithUtility.create(self.profile)
+		#notice, this is the *rounded* max util
+		maxutil = bidswithutil.getRange().getMax()
+		goal = Interval(maxutil - Decimal("0.00001"), maxutil)
+
+		bidsnearmax = bidswithutil.getBids(goal)
+		self.assertTrue(bidsnearmax.size() != 0)
+
+		foundmax = Decimal(0)
+		for bid in bidsnearmax :
+			util = self.profile.getUtility(bid)
+			if util>foundmax:
+				foundmax = util;
+		#found maximum may be slightly lower or higher because we rounded
+		#all weighted utilities.
+		self.assertTrue(abs(foundmax - maxutil) < 0.0001)
+
+	def benchmark(self):
+		print("\nBenchmarking " + self.profile.getName());
+		domainsize = AllBidsList(self.profile.getDomain()).size()
+
+		start = round(time.time()*1000)
+		body = BidsWithUtility.create(self.profile, self.accuracy)
+		list = body.getBids(self.utilityGoal)
+		end = round(time.time()*1000)
+		print("run time: " + str((end - start) / 1000.) + "s");
+		print("Total size of bidspace:" + str(domainsize))
+		print("Result size: " + str(list.size()))
Index: geniuswebcore/test/geniusweb/bidspace/IntervalTest.py
===================================================================
--- geniuswebcore/test/geniusweb/bidspace/IntervalTest.py	(revision 81)
+++ geniuswebcore/test/geniusweb/bidspace/IntervalTest.py	(revision 81)
@@ -0,0 +1,85 @@
+import unittest
+from unitpy.GeneralTests import GeneralTests
+from decimal import Decimal
+from geniusweb.bidspace.Interval import Interval
+from typing import List
+
+class IntervalTest (unittest.TestCase, GeneralTests[Interval]):
+
+	ZERO = Decimal(0)
+	ONE = Decimal(1)
+	TWO = Decimal(2)
+	THREE = Decimal(3)
+	TEN = Decimal(10)
+	
+	int1 = Interval(ZERO, ONE)
+	int1a = Interval(ZERO, ONE)
+	int2 = Interval(ONE, TEN)
+	int3 = Interval(TWO, TEN)
+
+	#Override
+	def getGeneralTestData(self)->List[List[Interval]] :
+		return [[self.int1, self.int1a], [self.int2],[self.int3]]
+
+	#Override
+	def getGeneralTestStrings(self) -> List[str] :
+		return ["Interval\\[0,1\\]", "Interval\\[1,10\\]",
+				"Interval\\[2,10\\]"]
+
+	def testsmokeTest(self) :
+		Interval(self.ZERO, self.ONE)
+
+	def testsmokeTestBad(self):
+		i = Interval(self.TEN, self.ONE)
+		self.assertTrue(i.isEmpty())
+
+	def testsmokeNull1Test(self):
+		self.assertRaises(ValueError, lambda: Interval(None,self.ZERO))
+
+	def testsmokeNull2test(self):
+		self.assertRaises(ValueError, lambda:Interval(self.ZERO, None))
+
+	def testMin(self):
+		self.assertEqual(Decimal(0), self.int1.getMin())
+		self.assertEqual(Decimal(1), self.int2.getMin())
+
+	def testMax(self):
+		self.assertEqual(Decimal(1), self.int1.getMax())
+		self.assertEqual(Decimal(10), self.int2.getMax())
+
+	def testcontainsTest(self):
+		self.assertTrue(self.int1.contains(Decimal(0.3)))
+		self.assertFalse(self.int1.contains(Decimal(-0.3)))
+		self.assertFalse(self.int1.contains(Decimal(1.3)))
+
+		self.assertFalse(self.int3.contains(self.ZERO))
+		self.assertFalse(self.int3.contains(self.ONE))
+		self.assertTrue(self.int3.contains(self.TWO));
+		self.assertTrue(self.int3.contains(self.THREE));
+		self.assertTrue(self.int3.contains(self.TEN));
+		self.assertFalse(self.int3.contains(Decimal(10.3)))
+
+	def testIntersect(self) :
+		self.assertEqual(self.int1, self.int1.intersect(self.int1))
+		self.assertEqual(Interval(self.ONE, self.ONE), self.int1.intersect(self.int2))
+		self.assertTrue(self.int1.intersect(self.int3).isEmpty())
+		self.assertEqual(Interval(self.ONE, self.TWO),
+				Interval(self.ZERO, self.TEN).intersect(Interval(self.ONE, self.TWO)))
+		self.assertEqual( Interval(self.ONE, self.TWO),
+				Interval(self.ONE, self.TWO).intersect(Interval(self.ZERO, self.TEN)))
+		self.assertEqual(Interval(self.ONE, self.TWO),
+				Interval(self.ZERO, self.TWO).intersect(Interval(self.ONE, self.TEN)))
+		self.assertEqual( Interval(self.ONE, self.TWO),
+				Interval(self.ONE, self.TEN).intersect( Interval(self.ZERO, self.TWO)))
+
+	def testsubtractTest(self):
+		self.assertEqual(Interval(Decimal(-1), self.ZERO),
+				self.int1.subtract(self.ONE))
+	
+	def testinvertTest(self) :
+		self.assertEqual(Interval(Decimal(-10), self.ZERO),
+				self.int1.invert(self.int2))
+		self.assertEqual(Interval(self.ZERO, self.TEN), self.int2.invert(self.int1))
+		self.assertEqual(
+				Interval(Decimal(-9), Decimal(8)),
+				self.int2.invert(self.int3))
Index: geniuswebcore/test/geniusweb/bidspace/IssueInfoTest.py
===================================================================
--- geniuswebcore/test/geniusweb/bidspace/IssueInfoTest.py	(revision 81)
+++ geniuswebcore/test/geniusweb/bidspace/IssueInfoTest.py	(revision 81)
@@ -0,0 +1,46 @@
+import unittest
+from geniusweb.issuevalue.DiscreteValue import DiscreteValue
+from decimal import Decimal
+from typing import Set, Dict
+from geniusweb.issuevalue.DiscreteValueSet import DiscreteValueSet
+from geniusweb.profile.utilityspace.DiscreteValueSetUtilities import DiscreteValueSetUtilities
+from geniusweb.bidspace.IssueInfo import IssueInfo
+from geniusweb.bidspace.Interval import Interval
+
+class IssueInfoTest(unittest.TestCase):
+
+	NAME = "name"
+	VAL1 = DiscreteValue("v1")
+	VAL2 = DiscreteValue("v2")
+	VAL3 = DiscreteValue("v3")
+	N03 = Decimal("0.3")
+	N04 = Decimal("0.4")
+	N05 = Decimal("0.5")
+	N06 = Decimal("0.6")
+	
+	def setUp(self) :
+		issuevalues:Set[DiscreteValue]  = set()
+		issuevalues.add(self.VAL1)
+		issuevalues.add(self.VAL2)
+		issuevalues.add(self.VAL3)
+		values = DiscreteValueSet(issuevalues)
+		valueUtils:Dict[DiscreteValue,Decimal] = {}
+		valueUtils[self.VAL1]= self.N03
+		valueUtils[self.VAL2]= self.N04
+		valueUtils[self.VAL3]= self.N05
+		utils = DiscreteValueSetUtilities(valueUtils)
+		self.info = IssueInfo(self.NAME, values, utils, self.N06, 6)
+
+	def testsmokeTest(self):
+		pass
+
+	def testGetExtremeMin(self):
+		self.assertEqual(self.VAL1, self.info.getExtreme(False))
+		self.assertEqual(self.VAL3, self.info.getExtreme(True))
+
+	def testgetNameTest(self):
+		self.assertEqual(self.NAME, self.info.getName())
+
+	def testgetIntervalTest(self):
+		self.assertEqual(Interval(self.N03*self.N06, self.N05*self.N06),
+				self.info.getInterval())
Index: geniuswebcore/test/geniusweb/references/ParametersTest.py
===================================================================
--- geniuswebcore/test/geniusweb/references/ParametersTest.py	(revision 80)
+++ geniuswebcore/test/geniusweb/references/ParametersTest.py	(revision 81)
@@ -45,4 +45,6 @@
 		# test fallback None
 		self.assertEqual(None, self.params2.getDouble("b", None, 4., 6.))
+		# a is integer!
+		self.assertEqual(1, self.params2.getDouble("a", 0., -0., 2.))		
 
 	def testGetDoubleWithErrors(self):
Index: geniuswebcore/test/resources/7issues/7issues1.json
===================================================================
--- geniuswebcore/test/resources/7issues/7issues1.json	(revision 81)
+++ geniuswebcore/test/resources/7issues/7issues1.json	(revision 81)
@@ -0,0 +1,105 @@
+{
+	"LinearAdditiveUtilitySpace": {
+		"name": "7issues1",
+		"issueUtilities": {
+			"i1": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.11,
+					"highValue": 9,
+					"highUtility": 0.99
+
+				}
+			},
+			"i2": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.12,
+					"highValue": 9,
+					"highUtility": 0.97
+
+				}
+			},
+			"i3": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.13,
+					"highValue": 9,
+					"highUtility": 0.96
+
+				}
+			},
+			"i4": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.14,
+					"highValue": 9,
+					"highUtility": 0.94
+
+				}
+			},
+			"i5": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.15,
+					"highValue": 9,
+					"highUtility": 0.93
+
+				}
+			},
+			"i6": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.16,
+					"highValue": 9,
+					"highUtility": 0.92
+
+				}
+			},
+			"i7": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.16,
+					"highValue": 9,
+					"highUtility": 0.91
+
+				}
+			}
+		},
+		"issueWeights": {
+			"i1": 0.07531677352656704,
+			"i2": 0.18148468268008364,
+			"i3": 0.13035193969082373,
+			"i4": 0.24649985443378972,
+			"i5": 0.16931694966873587,
+			"i6": 0.131353,
+			"i7": 0.0656768
+		},
+		"domain": {
+			"name": "7issues",
+			"issuesValues": {
+				"i1": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i2": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i3": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i4": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i5": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i6": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i7": {
+					"range": {"low":0,"high":9,"step":1}
+				}
+			}
+		}
+	}
+}
Index: geniuswebcore/test/resources/7issues/7issues2.json
===================================================================
--- geniuswebcore/test/resources/7issues/7issues2.json	(revision 81)
+++ geniuswebcore/test/resources/7issues/7issues2.json	(revision 81)
@@ -0,0 +1,105 @@
+{
+	"LinearAdditiveUtilitySpace": {
+		"name": "7issues2",
+		"issueUtilities": {
+			"i1": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.51,
+					"highValue": 9,
+					"highUtility": 0.11
+
+				}
+			},
+			"i2": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.92,
+					"highValue": 9,
+					"highUtility": 0.21
+
+				}
+			},
+			"i3": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.93,
+					"highValue": 9,
+					"highUtility": 0.13
+
+				}
+			},
+			"i4": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.94,
+					"highValue": 9,
+					"highUtility": 0.14
+
+				}
+			},
+			"i5": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.95,
+					"highValue": 9,
+					"highUtility": 0.15
+
+				}
+			},
+			"i6": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.96,
+					"highValue": 9,
+					"highUtility": 0.16
+
+				}
+			},
+			"i7": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.97,
+					"highValue": 9,
+					"highUtility": 0.17
+
+				}
+			}
+		},
+		"issueWeights": {
+			"i1": 0.24745759773026107,
+			"i2": 0.11824193959921694,
+			"i3": 0.1860471425098606,
+			"i4": 0.20629555826677742,
+			"i5": 0.16112666189388397,
+			"i6": 0.0538874,
+			"i7": 0.0269437
+		},
+		"domain": {
+			"name": "7issues",
+			"issuesValues": {
+				"i1": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i2": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i3": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i4": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i5": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i6": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i7": {
+					"range": {"low":0,"high":9,"step":1}
+				}
+			}
+		}
+	}
+}
Index: geniuswebcore/test/resources/9issues/9issues1.json
===================================================================
--- geniuswebcore/test/resources/9issues/9issues1.json	(revision 81)
+++ geniuswebcore/test/resources/9issues/9issues1.json	(revision 81)
@@ -0,0 +1,134 @@
+{
+	"LinearAdditiveUtilitySpace": {
+		"name": "9issues1",
+		"issueUtilities": {
+			"i1": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.11,
+					"highValue": 9,
+					"highUtility": 0.99
+
+				}
+			},
+			"i2": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.12,
+					"highValue": 9,
+					"highUtility": 0.97
+
+				}
+			},
+			"i3": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.13,
+					"highValue": 9,
+					"highUtility": 0.96
+
+				}
+			},
+			"i4": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.14,
+					"highValue": 9,
+					"highUtility": 0.94
+
+				}
+			},
+			"i5": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.15,
+					"highValue": 9,
+					"highUtility": 0.93
+
+				}
+			},
+			"i6": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.16,
+					"highValue": 9,
+					"highUtility": 0.92
+
+				}
+			},
+			"i7": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.16,
+					"highValue": 9,
+					"highUtility": 0.91
+
+				}
+			},
+			"i8": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.7664,
+					"highValue": 9,
+					"highUtility": 0.183
+
+				}
+			},
+
+			"i9": {
+				"NumberValueSetUtilities": {
+					"lowValue": 0,
+					"lowUtility": 0.191,
+					"highValue": 9,
+					"highUtility": 0.891
+
+				}
+			}
+
+		},
+		"issueWeights": {
+			"i1": 0.07531677352656,
+			"i2": 0.18148468268008,
+			"i3": 0.12035193969082,
+			"i4": 0.21649985443378,
+			"i5": 0.15621694966876,
+			"i6": 0.111253,
+			"i7": 0.0656768,
+			"i8": 0.0201,
+			"i9": 0.0531
+		},
+		"domain": {
+			"name": "9issues",
+			"issuesValues": {
+				"i1": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i2": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i3": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i4": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i5": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i6": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i7": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i8": {
+					"range": {"low":0,"high":9,"step":1}
+				},
+				"i9": {
+					"range": {"low":0,"high":9,"step":1}
+				}
+
+			}
+		}
+	}
+}
