<?xml version="1.0"?><st-source><!-- Name: StatisticsHideSource: falseParcel: #('Statistics')SaveSource: trueDate: 8:29:38 pm May 29, 2005 --><time-stamp>From VisualWorks® NonCommercial, 7.2 of November 3, 2003 on May 29, 2005 at 8:29:38 pm</time-stamp><do-it>(Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned.  Choose terminate or close.']</do-it><class><name>FrequencyTableTest</name><environment>Smalltalk</environment><super>XProgramming.SUnit.TestCase</super><private>false</private><indexed-type>none</indexed-type><inst-vars>testTable testTable2 testTableEmpty values </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Fnordistan</category><attributes><package>(none)</package></attributes></class><comment><class-id>FrequencyTableTest</class-id><body>SUnit tests for FrequencyTable.Instance Variables:	testTable	&lt;FrequencyTable&gt;	description of testTable	values	&lt;Array&gt;	description of values</body></comment><class><name>BellCurve</name><environment>Core</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>permutationsArray exactProbabilityArray ascendingProbabilityArray descendingProbabilityArray trials rangeMin rangeMax </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Fnordistan</category><attributes><package>(none)</package></attributes></class><comment><class-id>Core.BellCurve</class-id><body>A BellCurve shows ranges of probabilities given a set number of trials, each one consisting of a random number within a certain range. It can be thought of as a dice simulation, with each trial representing one "die" and the rangeMin and rangeMax indicating the lowest and highest values on the dice. (An actual BellCurve can have ranges that are negative numbers or otherwise cannot really be reflected on a polyhedral die.)Instance Variables:	ascendingProbabilityArray	&lt;Array&gt; 	description of ascendingProbabilityArray	descendingProbabilityArray	&lt;Array&gt;	description of descendingProbabilityArray	exactProbabilityArray	&lt;Array&gt;	description of exactProbabilityArray	permutationsArray	&lt;Array&gt;		description of permutationsArray	rangeMax	&lt;Integer&gt;	description of rangeMax	rangeMin	&lt;Integer&gt;	description of rangeMin	trials		&lt;Integer&gt;	number of trials for this BellCurve</body></comment><class><name>FrequencyTable</name><environment>Smalltalk</environment><super>Core.OrderedCollection</super><private>false</private><indexed-type>objects</indexed-type><inst-vars>distributionVectors </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Fnordistan</category><attributes><package>(none)</package></attributes></class><comment><class-id>FrequencyTable</class-id><body>A FrequencyTable is an OrderedCollection that can arrange itself in histograph format.By default, an empty initialized FrequencyTable will return nil for range and frequency boundaries, and 1 distributionVector. A FrequencyTable initialized with a number will be assigned that many distribution vectors. Otherwise, you should set the distribution vectors yourself, according to how many "columns" you want in your frequency table.Instance Variables:	distributionVectors	&lt;Number&gt;	The number of 'classes' that the data is distributed into.</body></comment><class><name>StatisticTest</name><environment>Smalltalk</environment><super>XProgramming.SUnit.TestCase</super><private>false</private><indexed-type>none</indexed-type><inst-vars>testStat stat1 stat2 valueArray valueHash </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Fnordistan</category><attributes><package>(none)</package></attributes></class><class><name>Statistic</name><environment>Smalltalk</environment><super>Core.Collection</super><private>false</private><indexed-type>none</indexed-type><inst-vars>Values </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Fnordistan</category><attributes><package>(none)</package></attributes></class><comment><class-id>Statistic</class-id><body>A Statistic is a Collection of numbers that can answer a variety of statistical calculations about itself. Treat a Statistic object as an array of values that can tell you its median, mean, etc. Internally, Statistic stores an OrderedCollection, and most Collection methods are invoked on this internal Collection.Alternatively, use any of Statistic's Class methods to answer with values about an external Collection.Instance Variables:	Values	&lt;SortedCollection&gt;	an internal list of values stored in this Statistic object.</body></comment><methods><class-id>FrequencyTableTest</class-id> <category>initialize-release</category><body package="(none)">initialize	"Initialize a newly created instance. This method must answer the receiver."	^self</body></methods><methods><class-id>FrequencyTableTest</class-id> <category>testing</category><body package="(none)">setUp	values := #(4 5 12 3 15 7 -2 8).	testTableEmpty := FrequencyTable new.	testTable := FrequencyTable new: (values size).	testTable2 := FrequencyTable new: (values size) with: (values size).	testTable addAll: values.	testTable2 addAll: values.</body><body package="(none)">testClasses	"Make sure tables return expected ranges"	"	values := #(4 5 12 3 15 7 -2 8)."		self assert: (testTableEmpty rangeStart = nil).	self assert: (testTableEmpty rangeEnd = nil).	self assert: (testTable rangeStart = -2).	self assert: (testTable rangeEnd = 15).	self assert: (testTable2 rangeStart = -2).	self assert: (testTable2 rangeEnd = 15).</body><body package="(none)">testClassWidth	"Make sure ClassWidths have expected sizes"	self assert: (testTableEmpty classWidth = 0).	self assert: (testTable classWidth = 17).	self assert: (testTable2 classWidth = (17/8)).</body><body package="(none)">testDistributionVectors	"Make sure tables return expected ranges"	"	values := #(4 5 12 3 15 7 -2 8)."	self assert: (testTableEmpty distributionVectors = 1).	self assert: (testTable distributionVectors = 1).	self assert: (testTable2 distributionVectors = (testTable2 size)).</body><body package="(none)">testInstantiation	"Make sure constructors work"	self assert: (testTableEmpty class = FrequencyTable).	self assert: (testTable class = FrequencyTable).	self assert: (testTable2 class = FrequencyTable).</body><body package="(none)">testRange	"Make sure tables return expected ranges"	"	values := #(4 5 12 3 15 7 -2 8)."		self assert: (testTableEmpty rangeStart = nil).	self assert: (testTableEmpty rangeEnd = nil).	self assert: (testTable rangeStart = -2).	self assert: (testTable rangeEnd = 15).	self assert: (testTable2 rangeStart = -2).	self assert: (testTable2 rangeEnd = 15).	"and we can add and change those values"	testTable add: 400.	testTable add: -10.	testTable2 add: 400.	testTable2 add: -10.	self assert: (testTable rangeStart = -10).	self assert: (testTable rangeEnd = 400).	self assert: (testTable2 rangeStart = -10).	self assert: (testTable2 rangeEnd = 400).</body><body package="(none)">testSize	"Make sure tables have expected sizes"	self assert: (testTableEmpty size = 0).	self assert: (testTable size = (values size)).	self assert: (testTable2 size = (values size)).	"and we can add and change those values"	testTable add: 400.	testTable add: -10.	testTable2 add: 400.	testTable2 add: -10.	testTableEmpty add: 400.	testTableEmpty add: -10.	self assert: (testTableEmpty size = 2).	self assert: (testTable size = ((values size) + 2)).	self assert: (testTable2 size = ((values size) + 2)).</body><body package="(none)">testSortedData	"Make sure tables have expected sortedData sets."	| emptyData data data2 |	emptyData := testTableEmpty sortedData.	data := testTable sortedData.	data2 := testTable2 sortedData.	self assert: (emptyData = nil).</body></methods><methods><class-id>FrequencyTableTest class</class-id> <category>instance creation</category><body package="(none)">new	"Answer a newly created and initialized instance."	^super new initialize</body></methods><methods><class-id>Core.BellCurve</class-id> <category>initialize-release</category><body package="(none)">initialize: numberOfTrials range: min to: max 	"Initialize probability arrays"	self trials: numberOfTrials.	self range: min to: max.	permutationsArray := BellCurve createPermutationsArray: numberOfTrials range: min to: max.	exactProbabilityArray := BellCurve createExactProbabilityArray: permutationsArray with: (self range raisedTo: trials).	ascendingProbabilityArray := BellCurve createAscendingProbabilityArray: exactProbabilityArray.	descendingProbabilityArray := BellCurve createDescendingProbabilityArray: exactProbabilityArray.	^self</body></methods><methods><class-id>Core.BellCurve</class-id> <category>printing</category><body package="(none)">printPermutations	"Answers the permutationsArray as a comma-delimited values string."	| displayString |	displayString := 'Permutations: '.	permutationsArray do: [:p | displayString := displayString , p printString , ','].	^displayString</body><body package="(none)">printString	"Standard object message answering a descriptive string."	^'a BellCurve for ' , trials printString , ' trials of ' , rangeMin printString , ' to ' , rangeMax printString</body></methods><methods><class-id>Core.BellCurve</class-id> <category>accessing</category><body package="(none)">ascendingProbabilityArray	"Answers an array of probabilities ascending cumulatively with the sum of all preceding values."	^ascendingProbabilityArray</body><body package="(none)">descendingProbabilityArray	"Answers an array of probabilities descending cumulatively from the sum of all following values."	^descendingProbabilityArray</body><body package="(none)">exactProbabilityArray	"Answers the array of exact probabilities for each position on the BellCurve."	^exactProbabilityArray</body><body package="(none)">permutationsArray	"Answers the array of total possible permutations possible for each value on the BellCurve"	^permutationsArray</body><body package="(none)">range	"Answers the range min-max, giving the length of the probability arrays"	^rangeMax - rangeMin + 1</body><body package="(none)">range: min to: max	"Set the min to max range for each trial. min and max must both be integers and max must be greater than or equal to min"	(min isInteger and: [max isInteger])		ifTrue: [			max &lt; min 				ifTrue: [self error: 'range maximum cannot be less than the minimum: ' , max printString]				ifFalse: [					rangeMin := min.					rangeMax := max]]		ifFalse: [self error: 'range parameters must be integers: ' , min printString , ', ' , max printString].</body><body package="(none)">rangeMax	^rangeMax</body><body package="(none)">rangeMin	^rangeMin</body><body package="(none)">trials	"Answers numberof trials in this BellCurve"	^trials</body><body package="(none)">trials: numberOfTrials	"Sets the number of trials for this BellCurve. numberOfTrials must be an Integer &gt; 0"	(numberOfTrials isInteger and: [numberOfTrials &gt; 0])		ifTrue: [trials := numberOfTrials]		ifFalse: [self error: 'trials must be an integer &gt; 0: ' , numberOfTrials printString].</body></methods><methods><class-id>Core.BellCurve class</class-id> <category>instance creation</category><body package="(none)">new	"Default one-element BellCurve."	^super new initialize: 1 range: 1 to: 1</body><body package="(none)">new: numberOfDice	"Creates a BellCurve for a specified number of standard 6-sided dice."	^super new	initialize: numberOfDice range: 1 to: 6</body><body package="(none)">new: numberOfDice max: numberOfSides 	"Create a BellCurve for a given number of dice that range from 1 to an upper bound"	^super new initialize: numberOfDice range: 1 to: numberOfSides</body><body package="(none)">new: numberOfDice min: lowerBound max: numberOfSides	"Create a BellCurve based on a given number of dice ranging from a lower bound to an upper bound."	^super new initialize: numberOfDice range: lowerBound to: numberOfSides</body></methods><methods><class-id>Core.BellCurve class</class-id> <category>creating probability arrays</category><body package="(none)">createAscendingProbabilityArray: exactProbs 	"Answers an array of probabilities that are cumulative totals from the index backward (&lt;=)"	| probArray |	probArray := exactProbs copyFrom: 1 to: exactProbs size.	(Interval from: 2 to: probArray size)		do: [:i | probArray at: i put: (probArray at: i) + (probArray at: i - 1)].	^probArray</body><body package="(none)">createDescendingProbabilityArray: exactProbs 	"Answers an array of probabilities that are cumulative totals from the index forward (&gt;=)"	| probArray |	probArray := exactProbs copyFrom: 1 to: exactProbs size.	(Interval from: probArray size - 1 to: 1 by: -1)		do: [:i | probArray at: i put: (probArray at: i) + (probArray at: i + 1)].	^probArray</body><body package="(none)">createExactProbabilityArray: permutations with: range 	"Answers the array of the exact probability of generating a result at a particular point on the BellCurve"	"permutations must be an Array with the number of possible permutations for each position in the array, wirh range being the total number of permutations possible."	| probArray index end |	probArray := Array new: permutations size.	index := 1.	end := permutations size.	[index &lt;= end]		whileTrue: [			| val |			val := permutations at: index.			probArray at: index put: val / range.			index := index + 1].	^probArray</body><body package="(none)">createPermutationsArray: trials range: min to: max	"This answers an Array filled with raw probabilities given a number of #trials with equal probability of any integer from #min to #max. 	This should only be invoked from the initialize method, or from itself, which is assumed to have already validated our input values.	trials, min, and max can also be seen as dice, i.e. trials=3, min=1, max=6 is equivalent to 3D6, or rolling 3 six-sided dice.	The elements of the returned array contain the total number of permutations which can result in the sum corresponding to the given index.	E.g., a 1-6 array will return #(1, 1, 1, 1, 1, 1,) because there is exactly one possible result for each value from 1-6.	A 2 x 1-6 array will return  #(1 2 3 4 5 6 5 4 3 2 1); there is one result that can return a 2, two that can return a 3, three that can return a 4, etc.	Note that the array begins at 1; you must make sure you handle the adjustment so the index values actually correspond to die rolls (i.e. mapping a 2-12 roll to a 1-11 array."	| baseArray arraySize arrayAdjust baseRange|	arraySize := ((trials * max) - (trials * min)) +1.	baseArray := Array new: arraySize.	baseRange := (max - min) + 1.	arrayAdjust := (trials * baseRange) - arraySize.  "This is used so we can store correct values in an array without zero-filling the unused numbers from 1 to min. (e.g. a '2-12' array is actually 1-11)"	"Zero-initialize the array"	(Interval from: 1 to: arraySize)		do: [:index | baseArray at: index put: 0].	"Now we iterate through our initial range and recursively add the range from the previous array to it."	trials = 1		"If dice is 1, this is the base case; all values have an equal probability."		ifTrue: [			(Interval from: 1 to: arraySize)				do: [:index | baseArray at: index put: 1]]		ifFalse: [			"Recursively fetch the array from 1 fewer dice"			|previousArray|			previousArray := self createPermutationsArray: (trials-1) range: min to: max.			(Interval from: 1 to: previousArray size)				do: [:previndex |						"Iterate through the baseArray recursively adding 1 to the total in each position with each iteration"						(Interval from: 1 to: baseRange)							do: [:dieval |								|prevArrayValue index oldVal|								prevArrayValue := previousArray at: previndex.								index := (previndex + trials-2) + dieval - arrayAdjust.								oldVal := baseArray at: index.								baseArray at: index put: (oldVal + prevArrayValue)]]].	^baseArray</body></methods><methods><class-id>FrequencyTable</class-id> <category>accessing</category><body package="(none)">classWidth	"Returns the width of each data class, determined by distributing the range of data equally between the number of data classes."	|min max|	self isEmpty		ifTrue: [^0].	min := self rangeStart.	max := self rangeEnd.	^(max - min)/(self distributionVectors)</body><body package="(none)">distributionVectors	"Return the number of classes into which our data is distributed"	^distributionVectors</body><body package="(none)">distributionVectors: anInteger	"Set the number of classes to distribute our data into, and automatically orders our data accordingly."	(anInteger isInteger and: [anInteger &gt; 0])		ifFalse: [self error: 'numberOfClasses must be an Integer &gt; 0'].	distributionVectors := anInteger.</body><body package="(none)">rangeEnd	"Find the largest value in our data"	| max |	self isEmpty		ifTrue: [^nil].	max := self at: 1.	(self size) &gt; 1		ifTrue: [2 to: (self size) do: [ :index | (self at: index) &gt; max	ifTrue: [max := self at: index]]].	^max</body><body package="(none)">rangeStart	"Find the smallest value in our data"	| min |	self isEmpty		ifTrue: [^nil].	min := self at: 1.	(self size) &gt; 1		ifTrue: [2 to: (self size) do: [ :index | (self at: index) &lt; min	ifTrue: [min := self at: index]]].	^min</body><body package="(none)">sortedData	"Returns an Array of Bags consisting of all the data sorted into classes according to our numberOfClasses. nil if empty"	| width dataSort |	self isEmpty		ifTrue: [^nil].	dataSort := Array new: distributionVectors.	1 to: distributionVectors do: [:i | dataSort at: i put: Bag new].	width := self classWidth.	1 to: (self size) do: [:n |		| index |		index := (n // width) asInteger.	Transcript show: 'INDEX : ', index printString, ' for ', n printString,' // ', width printString;cr.		(dataSort at: index) add: n.	].	^dataSort</body></methods><methods><class-id>FrequencyTable</class-id> <category>initialize-release</category><body package="(none)">initialize	"Initialize a newly created instance. This method must answer the receiver."	^(self initialize: 1)</body><body package="(none)">initialize: anInteger	"Initialize a newly created instance. This method must answer the receiver."	(anInteger isInteger and: [anInteger &gt; 0])		ifFalse: [self error: 'Initial distribution vectors must be an Integer &gt; 0'].	self distributionVectors: anInteger.	^self</body></methods><methods><class-id>FrequencyTable class</class-id> <category>instance creation</category><body package="(none)">new	"Answer a newly created and initialized instance."	^super new initialize</body><body package="(none)">new: anInteger	"Answer a newly created and initialized instance with a set size."	^(super new: anInteger) initialize</body><body package="(none)">new: anInteger with: startingVectors	"Answer a newly created and initialized instance with a set size and number of starting distributionVectors."	^(super new: anInteger) initialize: startingVectors</body></methods><methods><class-id>StatisticTest</class-id> <category>testing</category><body package="(none)">setUp	"Create the text fixture"	valueArray := #(4 12 7 18 14 3 29 25 1 11 7 16 8 31 2).	valueHash := Dictionary new.	valueHash at: 'size' put: 15.	valueHash at: 'mean' put: (188/15).	valueHash at: 'median' put: 11.	valueHash at: 'stdev' put: 9.650067851.	valueHash at: 'popstdev' put: 9.322851257.	stat1 := Statistic new.	stat2 := Statistic new.	stat2 addAll: valueArray.</body><body package="(none)">testInstantiation	"Test that we can create a Statistic object"	self assert: (stat1 class = Statistic).	self assert: (stat2 class = Statistic).</body><body package="(none)">testMean	"test the mean method"	| values upperLimit expectedMean |	upperLimit := 1.	expectedMean := 1.	values := Bag new.	self should: [Statistic mean: values] raise: Exception.	values add: upperLimit.	self assert: ((Statistic mean: values) = expectedMean).	upperLimit := upperLimit + 1.	values add: upperLimit.	expectedMean := 1.5.	self assert: ((Statistic mean: values) = expectedMean).		100 timesRepeat: [		upperLimit := upperLimit + 1.		values add: upperLimit.		expectedMean := expectedMean + 0.5.		self assert: ((Statistic mean: values) = expectedMean).	].	" Test our Statistic collections."	self should: [stat1 mean] raise: Exception.	self assert: (stat2 mean asFloat = (valueHash at: 'mean')).</body><body package="(none)">testMedian	"test the median method"	| values upperLimit expectedMedian |	upperLimit := 1.	expectedMedian := 1.	values := Bag new.	self should: [Statistic median: values ] raise: Exception.	[upperLimit &lt; 100] whileTrue: [		values add: upperLimit.		(values size) &gt; 1			ifTrue: [self assert: ((Statistic median: values) = expectedMedian)]			ifFalse: [self should: [Statistic median: values ] raise: Exception].		expectedMedian := expectedMedian + 0.5.		upperLimit := upperLimit + 1].	" Test our Statistic collections."	self should: [stat1 median] raise: Exception.	self assert: (stat2 median == (valueHash at: 'median')).</body></methods><methods><class-id>Statistic</class-id> <category>initialize-release</category><body package="(none)">initialize	"Initialize a newly created instance. This method must answer the receiver."	Values := SortedCollection new.	^self</body></methods><methods><class-id>Statistic</class-id> <category>adding</category><body package="(none)">add: newObject	"add a new value to our Values."	Values add: newObject.</body></methods><methods><class-id>Statistic</class-id> <category>enumerating</category><body package="(none)">do: aBlock	"Perform the Block operation on our values."	Values do: aBlock.</body></methods><methods><class-id>Statistic</class-id> <category>removing</category><body package="(none)">remove: oldObject ifAbsent: anExceptionBlock	"Removes a value from our internal values array."	Values remove: oldObject.</body></methods><methods><class-id>Statistic</class-id> <category>statistical calculations</category><body package="(none)">mean	"Answers the mean of this Statistic"	^(Statistic mean: Values)</body><body package="(none)">median	"Answers the median of this Statistic"	^(Statistic median: Values)</body></methods><methods><class-id>Statistic class</class-id> <category>probability distributions</category><body package="(none)">binomialDistribution: p trials: n successes: r 	"Get the probability of scoring EXACTLY r successes out of n trials given a base probability of p"	(r isInteger and: [r &gt;= 0])		ifFalse: [self error: 'successes must be an Integer &gt;= 0'].	(n isInteger and: [n &gt;= r])		ifFalse: [self error: 'trials must be an Integer &gt;= number of successes'].	(p &gt;= 0 and: [p &lt;= 1])		ifFalse: [self error: 'probability must be integer 0 &lt;=&gt; 1'].	^(Statistic combination: n select: r) * (p raisedTo: r) * ((1 - p) raisedTo: (n - r))</body><body package="(none)">binomialDistributionCumulative: p trials: n successes: r	"Recursively get cumulative probability for scoring at least r successes"	| P r0 |	"Cumulative probability"	P := 0.	"Probability of exactly r-1 successes"	r0 := r - 1.	"Recursive loop"	[r0 &gt;= 0]		whileTrue: [			P := P + (Statistic binomialDistribution: p trials: n successes: r0).			r0 := r0 - 1].	"Now we have the cumulative odds of scoring r-1 or fewer successes. Subtract from 1 for odds of more than r successes"	P := 1 - P.	^P</body></methods><methods><class-id>Statistic class</class-id> <category>permutations</category><body package="(none)">combination: size select: choices 	"	***This is decompiled code.*** 	The source was unavailable because the source pointer appears to point to an incorrect position in 	the file. The file may have been modified after this method was updated."	| t3 t4 comb t6 t7 |	(size isInteger and: [choices isInteger])		ifFalse: [self error: 'size and choices must both be integers'].	(choices &lt; 0 or: [size &lt; 0])		ifTrue: [self error: 'both values must be at least 0'].	size &gt;= choices ifFalse: [self error: 'size must be greater than or equal to choices'].	choices = 0		ifTrue: [comb := 1]		ifFalse: 			[t3 := size.			t6 := size - 1.			t7 := size - choices + 1.			[t6 &gt;= t7]				whileTrue: 					[t3 := t3 * t6.					t6 := t6 - 1].			t4 := choices factorial.			comb := t3 / t4].	^comb</body></methods><methods><class-id>Statistic class</class-id> <category>range values</category><body package="(none)">mean: aCollection	"Answers the mean of a Collection (assuming all values are numbers)"	| sum |	aCollection isEmpty		ifTrue: [self error: 'cannot calculate median for an empty set'].	sum := 0.	aCollection do: [:n | sum := sum + n].	^(sum/(aCollection size))</body></methods><do-it>"Imported Classes:"</do-it><do-it>self error: 'Attempting to file-in parcel imports.  Choose terminate or close'</do-it><class><name>Object</name><environment>Core</environment><super></super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Kernel-Objects</category><attributes><package>Kernel-Objects</package></attributes></class><class><name>Collection</name><environment>Core</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars></inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Collections-Abstract</category><attributes><package>Collections-Abstract</package></attributes></class><class><name>OrderedCollection</name><environment>Core</environment><super>Core.SequenceableCollection</super><private>false</private><indexed-type>objects</indexed-type><inst-vars>firstIndex lastIndex </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>Collections-Sequenceable</category><attributes><package>Collections-Sequenceable</package></attributes></class><class><name>TestCase</name><environment>XProgramming.SUnit</environment><super>Core.Object</super><private>false</private><indexed-type>none</indexed-type><inst-vars>testSelector </inst-vars><class-inst-vars></class-inst-vars><imports></imports><category>SUnit</category><attributes><package>SUnit</package></attributes></class></st-source>