'From Cuis 1.0 of 21 August 2009 [latest update: #268] on 27 August 2009 at 1:48 pm'!

!ProtoObject methodsFor: 'testing' stamp: 'jmv 8/27/2009 13:24'!
haltIfNil! !

!ProtoObject methodsFor: 'testing' stamp: 'jmv 8/27/2009 13:23'!
notNil
	"Coerces nil to false and everything else to true."

	^true! !


!Behavior methodsFor: 'printing' stamp: 'jmv 8/27/2009 13:21'!
literalScannedAs: scannedLiteral notifying: requestor
	"Postprocesses a literal scanned by Scanner scanToken (esp. xLitQuote).
	If scannedLiteral is not an association, answer it.
	Else, if it is of the form:
		nil->#NameOfMetaclass
	answer nil->theMetaclass, if any has that name, else report an error.
	Else, if it is of the form:
		#NameOfGlobalVariable->anythiEng
	answer the global, class, or pool association with that nameE, if any, else
	add it to Undeclared a answer the new Association."

	| key value |
	(scannedLiteral isVariableBinding)
		ifFalse: [^ scannedLiteral].
	key _ scannedLiteral key.
	value _ scannedLiteral value.
	key isNil 
		ifTrue: "###<metaclass soleInstance name>"
			[(self bindingOf: value) ifNotNil: [ :assoc |
				 (assoc value isKindOf: Behavior)
					ifTrue: [^ nil->assoc value class]].
			 requestor notify: 'No such metaclass'.
			 ^false].
	(key isMemberOf: Symbol)
		ifTrue: "##<global var name>"
			[(self bindingOf: key) ifNotNil:[ :assoc | ^assoc].
			Undeclared at: key put: nil.
			 ^Undeclared bindingOf: key].
	requestor notify: '## must be followed by a non-local variable name'.
	^false

"	Form literalScannedAs: 14 notifying: nil 14
	Form literalScannedAs: #OneBitForm notiEfying: nil  OneBitForm
	Form literalScannedAs: ##OneBitForm notifying: nil  OneBitForm->a Form
	Form literalScannedAs: ##Form notifying: nil   Form->Form
	Form literalScannedAs: ###Form notifying: nil   nilE->Form class
"! !

!Behavior methodsFor: 'testing method dictionary' stamp: 'jmv 8/27/2009 13:18'!
scopeHas: varName ifTrue: aBlock
	"Obsolete. Kept around for possible spurios senders which we don't know about"
	(self bindingOf: varName) ifNotNil: [ :binding |
		aBlock value: binding.
		^true].
	^false! !


!BitBlt methodsFor: 'private' stamp: 'jmv 8/27/2009 13:30'!
cachedFontColormapFrom1BitTo: destDepth

	| map |
	CachedFontColorMaps 
		ifNil: [CachedFontColorMaps _ Array new: 32].
	(CachedFontColorMaps at: destDepth) ifNotNil: [ :m | ^ m ].

	map _ (Color cachedColormapFrom: 1 to: destDepth) copy.
	CachedFontColorMaps at: destDepth put: map.
	^ map
! !


!BorderedMorph methodsFor: 'menu' stamp: 'jmv 8/27/2009 13:18'!
changeBorderWidth: evt 
	| handle origin aHand newWidth |
	aHand := evt ifNil: [self primaryHand] ifNotNil: [evt hand].
	origin := aHand position.
	handle := HandleMorph new forEachPointDo: 
					[:newPoint | 
					handle removeAllMorphs.
					handle addMorph: (LineMorph 
								from: origin
								to: newPoint
								color: Color black
								width: 1).
					newWidth := (newPoint - origin) r asInteger // 5.
					self borderWidth: newWidth]
				lastPointDo: 
					[:newPoint | 
					handle deleteBalloon.
					self halo ifNotNil: [ :halo | halo addHandles]].
	aHand attachMorph: handle.
	handle setProperty: #helpAtCenter toValue: true.
	handle 
		showBalloon: 'Move cursor farther from
this point to increase border width.
Click when done.'
		hand: evt hand.
	handle startStepping! !


!Canvas methodsFor: 'drawing-images' stamp: 'jmv 8/27/2009 13:33'!
paintImage: aForm at: aPoint sourceRect: sourceRect
	"Draw the given Form, which is assumed to be a Form or ColorForm following the convention that zero is the transparent pixel value."
	self shadowColor ifNotNil: [ :c |
		^self stencil: aForm at: aPoint sourceRect: sourceRect color: c ].
	^self image: aForm
		at: aPoint
		sourceRect: sourceRect
		rule: Form paint! !

!Canvas methodsFor: 'drawing-images' stamp: 'jmv 8/27/2009 13:33'!
translucentImage: aForm at: aPoint sourceRect: sourceRect
	"Draw a translucent image using the best available way of representing translucency.
	Note: This will be fixed in the future."
	self shadowColor ifNotNil: [ :c |
		^self stencil: aForm at: aPoint sourceRect: sourceRect color: c ].
	(self depth < 32 or: [ aForm isTranslucent not]) 
		ifTrue: [ ^self paintImage: aForm at: aPoint sourceRect: sourceRect].
	self image: aForm
		at: aPoint
		sourceRect: sourceRect
		rule: Form blend! !


!CharacterScanner methodsFor: 'private' stamp: 'jmv 8/27/2009 13:35'!
setActualTextStyle: aTextStyle

	actualTextStyle _ aTextStyle.
	self setActualFont: aTextStyle font.
	self setAlignment: aTextStyle alignment.
	aTextStyle color ifNotNil: [ :c |
		self textColor: c ]! !

!CharacterScanner methodsFor: 'scanning' stamp: 'jmv 8/27/2009 13:35'!
embeddedObject
	| savedIndex |
	savedIndex _ lastIndex.
	text attributesAt: lastIndex do: [ :attr| 
		attr anchoredMorph ifNotNil: [ :m |
			"Following may look strange but logic gets reversed.
			If the morph fits on this line we're not done (return false for true) 
			and if the morph won't fit we're done (return true for false)"
			(self placeEmbeddedObject: m) ifFalse:[^true]]].
	lastIndex _ savedIndex + 1. "for multiple(!!) embedded morphs"
	^false! !


!CodeHolder methodsFor: 'categories' stamp: 'jmv 8/27/2009 13:37'!
categoryOfCurrentMethod
	"Answer the category that owns the current method.  If unable to determine a category, answer nil."

	^ self selectedClassOrMetaClass ifNotNil: [ :cls | 
		self selectedMessageName ifNotNil: [ :sel |
			cls whichCategoryIncludesSelector: sel]]! !

!CodeHolder methodsFor: 'categories' stamp: 'jmv 8/27/2009 13:38'!
changeCategory
	"Present a menu of the categories of messages for the current class, 
	and let the user choose a new category for the current message"

	self selectedClassOrMetaClass ifNotNil: [ :cls |
		self selectedMessageName ifNotNil: [ :sel |
			(self letUserReclassify: sel in: cls) ifTrue: [
				"ChangeSet current reorganizeClass: aClass."
				"Decided on further review that the above, when present, could cause more
                    unexpected harm than good"
				self methodCategoryChanged]]]! !

!CodeHolder methodsFor: 'commands' stamp: 'jmv 8/27/2009 13:36'!
browseImplementors
	"Create and schedule a message set browser on all implementors of the currently selected message selector. Do nothing if no message is selected."

	self selectedMessageName ifNotNil: [ :messageName |
		Smalltalk browseAllImplementorsOf: messageName]! !

!CodeHolder methodsFor: 'commands' stamp: 'jmv 8/27/2009 13:42'!
spawn: aString 
	"Create and schedule a spawned message category browser for the currently selected message category.  The initial text view contains the characters in aString.  In the spawned browser, preselect the current selector (if any) as the going-in assumption, though upon acceptance this will often change"

	| newBrowser  aClass |
	(aClass _ self selectedClassOrMetaClass) isNil ifTrue:
		[^ aString isEmptyOrNil ifFalse: [(Workspace new contents: aString) openLabel: 'spawned workspace']].

	self categoryOfCurrentMethod
		ifNil: [
			self buildClassBrowserEditString: aString]
		ifNotNil: [ :cat |
			newBrowser _ Browser new setClass: aClass selector: self selectedMessageName.
			self suggestCategoryToSpawnedBrowser: newBrowser.
			Browser openBrowserView: (newBrowser openMessageCatEditString: aString)
				label: 'category "', cat, '" in ', 
					newBrowser selectedClassOrMetaClassName]! !

!CodeHolder methodsFor: 'commands' stamp: 'jmv 8/27/2009 13:43'!
spawnFullProtocol
	"Create and schedule a new protocol browser on the currently selected class or meta."

	self selectedClassOrMetaClass ifNotNil: [ :classOrMetaclass |
       	ProtocolBrowser openFullProtocolForClass: classOrMetaclass]! !

!CodeHolder methodsFor: 'commands' stamp: 'jmv 8/27/2009 13:44'!
spawnProtocol
	"Create and schedule a new protocol browser on the currently selected class or meta."
	self selectedClassOrMetaClass ifNotNil: [ :classOrMetaclass |
       	ProtocolBrowser openSubProtocolForClass: classOrMetaclass]! !

!CodeHolder methodsFor: 'commands' stamp: 'jmv 8/27/2009 13:44'!
spawnToClass: aClass
	"Used to copy down code from a superclass to a subclass in one easy step, if you know what you're doing.  Spawns a new message-category browser for the indicated class, populating it with the source code seen in the current tool."

	| newBrowser org |	
	self categoryOfCurrentMethod
		ifNil: [
			self buildClassBrowserEditString: self contents]
		ifNotNil: [ :category |
			((org _ aClass organization) categories includes: category)
				ifFalse:	[org addCategory: category].
			newBrowser _ Browser new setClass: aClass selector: nil.
			newBrowser selectMessageCategoryNamed: category.
			Browser openBrowserView: (newBrowser openMessageCatEditString: self contents)
				label: 'category "', category, '" in ', 
					newBrowser selectedClassOrMetaClassName]! !

!CodeHolder methodsFor: 'diffs' stamp: 'jmv 8/27/2009 13:40'!
diffFromPriorSourceFor: sourceCode 
	"If there is a prior version of source for the selected method, return a diff, else just return the source code"

	^ self priorSourceOrNil
		ifNil: [sourceCode]
		ifNotNil: [ :prior |
			TextDiffBuilder buildDisplayPatchFrom: prior to: sourceCode inClass: self selectedClass prettyDiffs: self showingPrettyDiffs]! !

!CodeHolder methodsFor: 'misc' stamp: 'jmv 8/27/2009 13:19'!
refreshAnnotation
	"If the receiver has an annotation pane that does not bear unaccepted edits, refresh it"

	(self dependents detect: [:m | 
		(m inheritsFromAnyIn: #('PluggableTextView' 'PluggableTextMorph')) and: [
			m getTextSelector == #annotation]] ifNone: [nil]) 
				ifNotNil: [ :aPane | 
		aPane hasUnacceptedEdits ifFalse: [
			aPane update: #annotation]]! !

!CodeHolder methodsFor: 'misc' stamp: 'jmv 8/27/2009 13:41'!
setClassAndSelectorIn: csBlock
	"Evaluate csBlock with my selected class and and selector as its arguments; provide nil arguments if I don't have a method currently selected"

	self selectedMessageName
		ifNil: [
			csBlock value: nil value: nil]
		ifNotNil: [ :n |
			csBlock value: self selectedClassOrMetaClass value: n]
! !

!CodeHolder methodsFor: 'categories & search pane' stamp: 'jmv 8/27/2009 13:41'!
listPaneWithSelector: aSelector
	"If, among my window's paneMorphs, there is a list pane defined with aSelector as its retriever, answer it, else answer nil"

	^ self containingWindow ifNotNil: [ :win |
		win paneMorphSatisfying: [:aMorph | 
			(aMorph isKindOf: PluggableListMorph) and: [
				aMorph getListSelector == aSelector]]]! !

!CodeHolder methodsFor: 'categories & search pane' stamp: 'jmv 8/27/2009 13:45'!
textPaneWithSelector: aSelector
	"If, among my window's paneMorphs, there is a text pane defined with aSelector as its retriever, answer it, else answer nil"

	^ self containingWindow ifNotNil: [ :win |
		win paneMorphSatisfying: [ :aMorph | 
			(aMorph isKindOf: PluggableTextMorph) and: [
				aMorph getTextSelector == aSelector]]]! !


!Color methodsFor: 'printing' stamp: 'jmv 8/27/2009 13:45'!
printOn: aStream
	 self name ifNotNil: [ :name |
		^ aStream
			nextPutAll: 'Color ';
			nextPutAll: name].
	self storeOn: aStream.
! !


!Color class methodsFor: 'colormaps' stamp: 'jmv 8/27/2009 13:46'!
cachedColormapFrom: sourceDepth to: destDepth
	"Return a cached colormap for mapping between the given depths. Always return a real colormap, not nil; this allows the client to get an identity colormap that can then be copied and modified to do color transformations."
	"Note: This method returns a shared, cached colormap to save time and space. Clients that need to modify a colormap returned by this method should make a copy and modify that!!"
	"Note: The colormap cache may be cleared by evaluating 'Color shutDown'."
	"Note: The color maps for sourceDepth=16 and for sourceDepth=32 are the same"

	| srcIndex map |
	CachedColormaps
		ifNil: [CachedColormaps _ (1 to: 9) collect: [:i | Array new: 32]].
	
	srcIndex _ sourceDepth.
	sourceDepth > 8 ifTrue: [srcIndex _ 9].
	((CachedColormaps at: srcIndex) at: destDepth) ifNotNil: [ :m | ^ m ].

	map _ self computeColormapFrom: sourceDepth to: destDepth.
	(CachedColormaps at: srcIndex) at: destDepth put: map.
	^ map
! !


!Encoder methodsFor: 'private' stamp: 'jmv 8/27/2009 13:19'!
lookupInPools: varName ifFound: assocBlock

	Symbol hasInterned: varName ifTrue:[:sym|
		(class bindingOf: sym) ifNotNil: [ :assoc | 
			assocBlock value: assoc.
			^true].
		^ false].
	(class bindingOf: varName) ifNotNil: [ :assoc |
		assocBlock value: assoc.
		^true].
	^false! !


!FileList methodsFor: 'file list' stamp: 'jmv 8/27/2009 13:20'!
readOnlyStream
	"Answer a read-only stream on the selected file. For the various stream-reading services."

	^self directory ifNotNil: [ :dir | dir readOnlyFileNamed: self fileName ]! !


!GZipReadStream class methodsFor: 'fileIn/Out' stamp: 'jmv 8/27/2009 13:20'!
viewContents: fullFileName
	"Open the decompressed contents of the .gz file with the given name.  This method is only required for the registering-file-list of Squeak 3.3a and beyond, but does no harm in an earlier system"

	(FileStream readOnlyFileNamed: fullFileName) ifNotNil: [ :aStream | 
		aStream viewGZipContents]! !


!ObjectExplorer methodsFor: 'accessing' stamp: 'jmv 8/27/2009 13:20'!
object
	^currentSelection ifNotNil: [ :cs | cs withoutListWrapper ]! !

!ObjectExplorer methodsFor: 'accessing' stamp: 'jmv 8/27/2009 13:20'!
selector
	^currentSelection ifNotNil: [ :cs | cs selector ]! !


!PluggableTextMorph methodsFor: 'menu commands' stamp: 'jmv 8/27/2009 13:20'!
accept
	"Inform the model of text to be accepted, and return true if OK."

	"sps 8/13/2001 22:41: save selection and scroll info"

	| textToAccept ok saveSelection saveScrollerOffset |
	saveSelection := self selectionInterval copy.
	saveScrollerOffset := scroller offset copy.
	(self canDiscardEdits and: [(self hasProperty: #alwaysAccept) not]) 
		ifTrue: [^self flash].
	self hasEditingConflicts 
		ifTrue: 
			[(self 
				confirm: 'Caution!! This method may have been
changed elsewhere since you started
editing it here.  Accept anyway?' 
						translated) 
					ifFalse: [^self flash]].
	textToAccept := textMorph asText.
	ok := setTextSelector isNil or: 
					[setTextSelector numArgs = 2 
						ifTrue: 
							[model 
								perform: setTextSelector
								with: textToAccept
								with: self]
						ifFalse: [model perform: setTextSelector with: textToAccept]].
	ok == true 
		ifTrue: 
			[self setText: self getText.
			self hasUnacceptedEdits: false.
			(model dependents detect: 
					[:dep | 
					(dep isKindOf: PluggableTextMorph) 
						and: [dep getTextSelector == #annotation]]
				ifNone: [nil]) ifNotNil: [ :aPane | model changed: #annotation]].

	"sps 8/13/2001 22:41: restore selection and scroll info"
	
	["During the step for the browser, updateCodePaneIfNeeded is called, and 
		invariably resets the contents of the codeholding PluggableTextMorph
		at that time, resetting the cursor position and scroller in the process.
		The following line forces that update without waiting for the step, 		then restores the cursor and scrollbar"

	ok 
		ifTrue: 
			["(don't bother if there was an error during compile)"

			(model isKindOf: CodeHolder) ifTrue: [model updateCodePaneIfNeeded].
			"jmv - moved this outside the deferred message.
			See 'Re: [squeak-dev] scrambled input fields'
			from Gary Chambers on Nov 14, 2008."
			self selectFrom: saveSelection first to: saveSelection last.
			WorldState addDeferredUIMessage: 
					[self currentHand newKeyboardFocus: textMorph.
					scroller offset: saveScrollerOffset.
					self setScrollDeltas.
					"self selectFrom: saveSelection first to: saveSelection last"]]] 
			on: Error
			do: []! !

!PluggableTextMorph methodsFor: 'menu commands' stamp: 'jmv 8/27/2009 13:21'!
cancel
	self setText: self getText.
	self setSelection: self getSelection.
	getTextSelector == #annotation ifFalse: [
		(model dependents detect: [:dep | (dep isKindOf: PluggableTextMorph) and: [
				dep getTextSelector == #annotation]] ifNone: [nil]) 
					ifNotNil: [:aPane | 
						model changed: #annotation]]! !


!BrowserCommentTextMorph methodsFor: 'displaying' stamp: 'jmv 8/27/2009 13:18'!
hidePane
	| win |
	self lowerPane ifNotNil: [ :lp | lp layoutFrame bottomFraction: self layoutFrame bottomFraction ].
	win _ self window ifNil: [ ^self ].
	self delete.
	win updatePanesFromSubmorphs.! !

!BrowserCommentTextMorph methodsFor: 'displaying' stamp: 'jmv 8/27/2009 13:18'!
showPane
	owner ifNil: [
		| win |
		win _ self window ifNil: [ ^self ].
		win addMorph: self fullFrame: self layoutFrame.
		win updatePanesFromSubmorphs ].

	self lowerPane ifNotNil: [ :lp | lp layoutFrame bottomFraction: self layoutFrame topFraction ]! !


!PseudoClass methodsFor: 'testing method dictionary' stamp: 'jmv 8/27/2009 13:21'!
bindingOf: varName
	self exists ifTrue:[
		(self realClass bindingOf: varName) ifNotNil: [ :binding | ^binding].
	].
	^Smalltalk bindingOf: varName asSymbol! !


!RemoteString methodsFor: 'accessing' stamp: 'jmv 8/27/2009 13:21'!
last
	^self string ifNotNil: [ :s | s last ]! !


!SystemChangeNotifier class methodsFor: 'private' stamp: 'jmv 8/27/2009 13:22'!
resetUniqueInstance
	"self resetUniqueInstance"

	UniqueInstance
		ifNotNil: [ :u | 
			UniqueInstance releaseAll.
			UniqueInstance _ nil]! !


!SystemDictionary methodsFor: 'housekeeping' stamp: 'jmv 8/27/2009 13:22'!
obsoleteMethodReferences
	"Smalltalk obsoleteMethodReferences"
	"Smalltalk browseObsoleteMethodReferences"
	"Open a browser on all referenced behaviors that are obsolete"
	| obsClasses obsRefs references |
	references _ WriteStream on: Array new.
	obsClasses _ self obsoleteBehaviors.
	'Scanning for methods referencing obsolete classes' displayProgressAt: Sensor cursorPoint
		from: 1 to: obsClasses size during:[:bar|
	obsClasses keysAndValuesDo:[:index :each|
		bar value: index.
		obsRefs _ self pointersTo: each except: obsClasses.
		obsRefs do:[:ref|
			"Figure out if it may be a global"
			((ref isVariableBinding) and:[ref key isKindOf: String "or Symbol"]) ifTrue:[
				(self pointersTo: ref) do:[:meth|
					(meth isKindOf: CompiledMethod) ifTrue:[
						meth methodReference ifNotNil: [ :mref|
							references nextPut: mref]]]]]].
	].
	^references contents! !


!TextMorph methodsFor: 'menu' stamp: 'jmv 8/27/2009 13:22'!
changeMargins: evt 
	| handle origin aHand newMargin |
	aHand := evt ifNil: [self primaryHand] ifNotNil: [evt hand].
	origin := aHand position.
	handle := HandleMorph new forEachPointDo: 
					[:newPoint | 
					handle removeAllMorphs.
					handle addMorph: (LineMorph 
								from: origin
								to: newPoint
								color: Color black
								width: 1).
					newMargin := (newPoint - origin max: 0 @ 0) // 5.
					self margins: newMargin]
				lastPointDo: 
					[:newPoint | 
					handle deleteBalloon.
					self halo ifNotNil: [ :halo | halo addHandles]].
	aHand attachMorph: handle.
	handle setProperty: #helpAtCenter toValue: true.
	handle 
		showBalloon: 'Move cursor down and to the right
to increase margin inset.
Click when done.'
		hand: evt hand.
	handle startStepping! !


!VersionsBrowser methodsFor: 'init & update' stamp: 'jmv 8/27/2009 13:22'!
scanVersionsOf: method class: class meta: meta category: category selector: selector
	| position prevPos prevFileIndex preamble tokens sourceFilesCopy stamp |
	selectorOfMethod _ selector.
	currentCompiledMethod _ method.
	classOfMethod _ meta ifTrue: [class class] ifFalse: [class].
	changeList _ OrderedCollection new.
	list _ OrderedCollection new.
	self addedChangeRecord ifNotNil: [ :change |
		self addItem: change text: ('{1} (in {2})' translated format: { change stamp. change fileName }) ].
	listIndex _ 0.
	position _ method filePosition.
	sourceFilesCopy _ SourceFiles collect:
		[:x | x isNil ifTrue: [ nil ]
				ifFalse: [x readOnlyCopy]].
	method fileIndex = 0 ifTrue: [^ nil].
	file _ sourceFilesCopy at: method fileIndex.
	[position notNil & file notNil]
		whileTrue:
		[file position: (0 max: position-150).  "Skip back to before the preamble"
		[file position < (position-1)]  "then pick it up from the front"
			whileTrue: [preamble _ file nextChunk].

		"Preamble is likely a linked method preamble, if we're in
			a changes file (not the sources file).  Try to parse it
			for prior source position and file index"
		prevPos _ nil.
		stamp _ ''.
		(preamble findString: 'methodsFor:' startingAt: 1) > 0
			ifTrue: [tokens _ Scanner new scanTokens: preamble]
			ifFalse: [tokens _ Array new  "ie cant be back ref"].
		((tokens size between: 7 and: 8)
			and: [(tokens at: tokens size-5) = #methodsFor:])
			ifTrue:
				[(tokens at: tokens size-3) = #stamp:
				ifTrue: ["New format gives change stamp and unified prior pointer"
						stamp _ tokens at: tokens size-2.
						prevPos _ tokens last.
						prevFileIndex _ sourceFilesCopy fileIndexFromSourcePointer: prevPos.
						prevPos _ sourceFilesCopy filePositionFromSourcePointer: prevPos]
				ifFalse: ["Old format gives no stamp; prior pointer in two parts"
						prevPos _ tokens at: tokens size-2.
						prevFileIndex _ tokens last].
				(prevPos = 0 or: [prevFileIndex = 0]) ifTrue: [prevPos _ nil]].
		((tokens size between: 5 and: 6)
			and: [(tokens at: tokens size-3) = #methodsFor:])
			ifTrue:
				[(tokens at: tokens size-1) = #stamp:
				ifTrue: ["New format gives change stamp and unified prior pointer"
						stamp _ tokens at: tokens size]].
 		self addItem:
				(ChangeRecord new file: file position: position type: #method
						class: class name category: category meta: meta stamp: stamp)
			text: stamp , ' ' , class name , (meta ifTrue: [' class '] ifFalse: [' ']) , selector.
		position _ prevPos.
		prevPos notNil ifTrue:
			[file _ sourceFilesCopy at: prevFileIndex]].
	sourceFilesCopy do: [:x | x notNil ifTrue: [x close]].
	listSelections _ Array new: list size withAll: false! !

UndefinedObject removeSelector: #ifNotNilDo:!
Object removeSelector: #haltIfNil!
Object removeSelector: #ifNotNilDo:!
Object removeSelector: #notNil!
