Felix Geller avatar Felix Geller committed d7a88ec Merge

Merged from main

Comments (0)

Files changed (7)

AtomicInstaller.ns3

-Newspeak3
+Newspeak3
+'Mirrors'
+class AtomicInstaller usingPlatform: platform = NewspeakObject (
+"Initial version of atomic install. This handles adding, removing and modifying stuff. 
 
-'Mirrors'
+What remains unaddressed is changing classes of individual objects, and changing superclasses of individual classes. These can of course be handled elsewhere, but not as part of a broader atomic transaction as is done here. The API of this class should be extended to deal with these requirements.
 
-
+The process of an atomic install is as follows:
 
-class AtomicInstaller usingPlatform: platform = NewspeakObject (
-"Initial version of atomic install. This handles adding, removing and modifying stuff. 
-
-What remains unaddressed is changing classes of individual objects, and changing superclasses of individual classes. These can of course be handled elsewhere, but not as part of a broader atomic transaction as is done here. The API of this class should be extended to deal with these requirements.
-
-The process of an atomic install is as follows:
-
-We construct a list of old objects, and another of revised objects.  These two lists parallel each other: the i'th element of the revised object list is the revised version of the i'th element in the old objects list. Eventually, we will do a one way become: of the old objects into the new ones.
-The list is populated with mixins, classes and instances that need to be modified.
-
-The input consists of a tuple of MixinReps, and a map containing any existing outermost mixins being processed . Each element in the tuple describes an ''outermost'' mixin and its nested mixins. By ''outermost mixin'' we mean a mixin that is not nested within any other mixin being processed at this time. It could be a top level mixin, but it could also be a nested mixin provided its enclosing mixins are not subject to change.
-
-We distinguish between new and existing mixins. We use the map in order to do this.  This is essential, since we cannot assume a global namespace in which to look up mixins to see if they exist or not. 
-
-New mixins are simply created per their description, recursively including their nested mixins. These new mixins are gathered in the newMixins array.
-
-If the mixin described by the MixinRep exists, we store the existing mixin in the old object array, and create a new one per the description. The new mixin is then placed in the revised objects array.  
-
-The recursive processing of each MixinRep yields a MixinList: a list of classes, the head of which corresponds to the outermost mixin described by the MixinRep, and the tail being a list of MixinLists corresponding the MixinReps of outermost mixin's nested mixins. This list is returned at the end.
-
-For each existing mixin, we also go through all its invocations. We note that the invocation is associated with a modified mixin by adding an entry to a map, definingMirrors, that maps classes to mirrors that describe their mixin. We also collect the invocation and all its subclasses  These are stored in a map called existingClasses, which maps  depth in the inheritance hierarchy to sets of existing classes classes at that depth. This gives us the set of existing classes that will require modification - either because their mixin has changed, or their superclass has changed. The data structure allows us to easily traverse the set of existing classes in order, base classes first.
-
-We then recursively process the nested mixins of each mixin being processed. Each nested mixin is processed with a namespace consisting of the nested mixins of its enclosing mixin (which allows us again to determine whether a mixin being described is new or pre-existing).
-
-Next, we go through the existing classes. For each class we produce a new class, which we store in a map, newClasses, keyed by the old class.  It is important not to use the class name as a key, as we cannot assume a global namespace in Newspeak.
-The new class may differ in its own structure (because its mixin differs) or only in having a revised superclass. 
-
-We also store the old class in the old objects array, and the new class in the revised objects array. Because we traverse the classes in increasing depth order we are assured that a class' superclass has either already been processed, and can be looked up in newClasses, or it has not changed. This is essential, because the new class points at its up-to-date superclass and uses data derived from it.
-
-If the layout of a class has changed, we also process all its instances. For each existing instance of an old class whose shape has changed, we create an instance of the new class, taking care to copy the data of fields shared between the old and new classes from the old instance to the new one. Each such processed object is placed in the old objects array, with the new version in the revised objects array.
-
-At this point, we can do the one way become:  and the installation is complete.
-
-One more detail: we track what mixins have been removed from existing mixins. We then make sure these mixins are removed from the subclasses array of ProtoObject (though this is not done atomically). Our goal is to ensure that the Class object level data structure is consistent at the end of the operation
-
-One concern is the involvement of this class with metadata issues such as the class organization. For new code,  AtomicInstaller produces an organization based on the information available in the mirrors provided.  For existing ones it copies the information that was already in place.  
-
-Now it seems that, ideally, a higher level layer should be dealing with this kind of metadata and AtomicInstaller should be completely oblivious to it.  Alas, it isn't quite so simple.
-
-The installer processes classes whose mixin has not been modified, it is important that it clones them in their entirety so that their organization does not get lost.  Higher level layers aren't in a good position to deal with these classes without replicating much of the installer's work.  
-
-Likewise, high level layers aren't really well situated to track down mixin applications of mixins that have been modified.  They only deal with the mixins themselves. However, the organization of a mixin invocation is a special object that actually bases its definitions on the organization of the defining class. So copying these is ok as well.
-
-In principle, metadata should be kept at the mixin level, and individual classes should just refer to their mixin for it. In that case, higher level mirrors could deal with the metadata, and the installer would not have to do anything at all about it  - neither for new or old code.
-In that scenario, even if a class has unique metadata, then it would only change of the class itself were changed individually (which amounts to changing its superclass) and then the higher layers would know about it and deal with it.
-
-Until that happy day, it looks like the installer has no choice but to take care of this. That is why low level squeak mirrors carry metadata such as category information with them, making it available to the installer. 
-
-What could be improved is the handling of new mixins. Higher level mirrors could take care of setting up the organization of these.  This is part of the pending overall mirror reform.  Then we could take #setOrganizationOfClass;BasedOn: out of AtomicInstaller, along with the import of ClassOrganizer.
-
-Copyright (c) 2009-2010 Gilad Bracha
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the ''Software''), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED ''AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE."
-|	"imports"
-	Map = platform Collections Dictionary.
-	List = platform Collections OrderedCollection.
-	Set = platform Collections Set.
-	ProtoObject = platform Kernel ProtoObject.
-	MethodDictionary = platform Kernel MethodDictionary.
-	Metaclass = platform Kernel Metaclass.
-	ClassOrganizer = platform Kernel ClassOrganizer.
-	SystemMetadata = platform NewsqueakMixins SystemMetadata.
-	DefiningClassMetadata = platform NewsqueakMixins DefiningClassMetadata.
-	Mixin = platform NewsqueakMixins Mixin.
-	MixinManager = platform NewsqueakMixins MixinManager.
-	NewspeakObject = platform NewspeakCore NewspeakObject.
-	vmmirror = platform NewspeakCore VMMirror new.
-	
-	"module variables"
-	newMixins <List[Mixin]>
-	revisedObjects <List[Object]>
-	oldObjects <List[Object]>
-	existingClasses <Map[Integer, Set[Class]]>
-	newClasses <Map[Class, Class]>
-	deletedClasses <List[Class]>
-	definingMirrors <Map[Class, LowLevelMixinMirror]> 
-|
-)
+We construct a list of old objects, and another of revised objects.  These two lists parallel each other: the i'th element of the revised object list is the revised version of the i'th element in the old objects list. Eventually, we will do a one way become: of the old objects into the new ones.
+The list is populated with mixins, classes and instances that need to be modified.
 
-(
+The input consists of a tuple of MixinReps, and a map containing any existing outermost mixins being processed . Each element in the tuple describes an ''outermost'' mixin and its nested mixins. By ''outermost mixin'' we mean a mixin that is not nested within any other mixin being processed at this time. It could be a top level mixin, but it could also be a nested mixin provided its enclosing mixins are not subject to change.
 
-
+We distinguish between new and existing mixins. We use the map in order to do this.  This is essential, since we cannot assume a global namespace in which to look up mixins to see if they exist or not. 
 
-class MixinList  head: hd <Class>  tail: tl <MixinList> = (
-"MxinList =  (Class, MixinList) | Nil."
-|
-	head <Class> = hd.
-	tail <MixinList> = tl.
-|
-)
+New mixins are simply created per their description, recursively including their nested mixins. These new mixins are gathered in the newMixins array.
 
-()'private'
+If the mixin described by the MixinRep exists, we store the existing mixin in the old object array, and create a new one per the description. The new mixin is then placed in the revised objects array.  
 
-adjust: newObj to: oldObj = (
+The recursive processing of each MixinRep yields a MixinList: a list of classes, the head of which corresponds to the outermost mixin described by the MixinRep, and the tail being a list of MixinLists corresponding the MixinReps of outermost mixin's nested mixins. This list is returned at the end.
 
-
+For each existing mixin, we also go through all its invocations. We note that the invocation is associated with a modified mixin by adding an entry to a map, definingMirrors, that maps classes to mirrors that describe their mixin. We also collect the invocation and all its subclasses  These are stored in a map called existingClasses, which maps  depth in the inheritance hierarchy to sets of existing classes classes at that depth. This gives us the set of existing classes that will require modification - either because their mixin has changed, or their superclass has changed. The data structure allows us to easily traverse the set of existing classes in order, base classes first.
 
-cleanup = (
+We then recursively process the nested mixins of each mixin being processed. Each nested mixin is processed with a namespace consisting of the nested mixins of its enclosing mixin (which allows us again to determine whether a mixin being described is new or pre-existing).
 
-
+Next, we go through the existing classes. For each class we produce a new class, which we store in a map, newClasses, keyed by the old class.  It is important not to use the class name as a key, as we cannot assume a global namespace in Newspeak.
+The new class may differ in its own structure (because its mixin differs) or only in having a revised superclass. 
 
-cloneClass: oldClass <Class> ^ <Class> = (
   	newMeta:: Metaclass new.
                 methodDictionary: oldClass class methodDictionary
                 format: oldClass class format.	
+We also store the old class in the old objects array, and the new class in the revised objects array. Because we traverse the classes in increasing depth order we are assured that a class' superclass has either already been processed, and can be looked up in newClasses, or it has not changed. This is essential, because the new class points at its up-to-date superclass and uses data derived from it.
 
-
+If the layout of a class has changed, we also process all its instances. For each existing instance of an old class whose shape has changed, we create an instance of the new class, taking care to copy the data of fields shared between the old and new classes from the old instance to the new one. Each such processed object is placed in the old objects array, with the new version in the revised objects array.
 
-depthFor: klass <Class> = (
+At this point, we can do the one way become:  and the installation is complete.
 
-
+One more detail: we track what mixins have been removed from existing mixins. We then make sure these mixins are removed from the subclasses array of ProtoObject (though this is not done atomically). Our goal is to ensure that the Class object level data structure is consistent at the end of the operation
 
-existingMixinFor: m <LowLevelMixinMirror> in: ns <Map[Symbol, Class]> ^ <Class | Nil> = (
+One concern is the involvement of this class with metadata issues such as the class organization. For new code,  AtomicInstaller produces an organization based on the information available in the mirrors provided.  For existing ones it copies the information that was already in place.  
 
-
+Now it seems that, ideally, a higher level layer should be dealing with this kind of metadata and AtomicInstaller should be completely oblivious to it.  Alas, it isn't quite so simple.
 
-install: newObjects <Array> insteadOf: old <Array>  = (
+The installer processes classes whose mixin has not been modified, it is important that it clones them in their entirety so that their organization does not get lost.  Higher level layers aren't in a good position to deal with these classes without replicating much of the installer's work.  
 
-
+Likewise, high level layers aren't really well situated to track down mixin applications of mixins that have been modified.  They only deal with the mixins themselves. However, the organization of a mixin invocation is a special object that actually bases its definitions on the organization of the defining class. So copying these is ok as well.
 
-installAll = (
+In principle, metadata should be kept at the mixin level, and individual classes should just refer to their mixin for it. In that case, higher level mirrors could deal with the metadata, and the installer would not have to do anything at all about it  - neither for new or old code.
+In that scenario, even if a class has unique metadata, then it would only change of the class itself were changed individually (which amounts to changing its superclass) and then the higher layers would know about it and deal with it.
 
-
+Until that happy day, it looks like the installer has no choice but to take care of this. That is why low level squeak mirrors carry metadata such as category information with them, making it available to the installer. 
 
-installNewMixins = (
+What could be improved is the handling of new mixins. Higher level mirrors could take care of setting up the organization of these.  This is part of the pending overall mirror reform.  Then we could take #setOrganizationOfClass;BasedOn: out of AtomicInstaller, along with the import of ClassOrganizer.
 
-
+Copyright (c) 2009-2010 Gilad Bracha
 
-layoutHasChangedBetween: oldClass <Class> and: newClass <Class> ^ <Boolean> = (
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the ''Software''), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
 
-
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
 
-methodDictionaryFor: c <Class> from: m <LowLevelMixinMirror> ^ <MethodDictionary> = (
+THE SOFTWARE IS PROVIDED ''AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE."|	"imports"
+	Map = platform Collections Dictionary.
+	List = platform Collections OrderedCollection.
+	Set = platform Collections Set.
+	ProtoObject = platform Kernel ProtoObject.
+	MethodDictionary = platform Kernel MethodDictionary.
+	Metaclass = platform Kernel Metaclass.
+	ClassOrganizer = platform Kernel ClassOrganizer.
+	SystemMetadata = platform NewsqueakMixins SystemMetadata.
+	DefiningClassMetadata = platform NewsqueakMixins DefiningClassMetadata.
+	Mixin = platform NewsqueakMixins Mixin.
+	MixinManager = platform NewsqueakMixins MixinManager.
+	NewspeakObject = platform NewspeakCore NewspeakObject.
+	vmmirror = platform NewspeakCore VMMirror new.
+	
+	"module variables"
+	newMixins <List[Mixin]>
+	revisedObjects <List[Object]>
+	oldObjects <List[Object]>
+	existingClasses <Map[Integer, Set[Class]]>
+	newClasses <Map[Class, Class]>
+	deletedClasses <List[Class]>
+	definingMirrors <Map[Class, LowLevelMixinMirror]> 
+|)
+(
+class MixinList head: hd <Class>  tail: tl <MixinList> = (
+"MxinList =  (Class, MixinList) | Nil."|
+	head <Class> = hd.
+	tail <MixinList> = tl.
+|)
+()'accessing'
+atomicallyInstallMixinReps: mixins <List[LowLevelMixinRep]> namespace: ns <Map[Symbol, Class]> ^ <List[MixinList]> = (
+"Install all elements of mixins, correctly modifying their applications and the subclasses thereof, and any metadata. Return a list of outermost  classes corresponding to said mixins and their nested classes recursively. In other words, we take a list of MixinReps and return a corresponding list of MixinLists, such that
 
-
+MixinList = {Class. List[MixinList]}
 
-mixinLayoutHasChangedBetween: oldMixin <Mixin> and: newMixin <Mixin> ^ <Boolean> = (
+Ergo, the outermost class whose mirror heads the rep is returned at the head of the corresponding list, and a list of mixin lists that matches the nested classes of said outermost class follows, echoing the structure of the incoming rep.
 
-
+ "
+	| results <List[MixinList]> |
+	setup.
+	results:: mixins collect:[:rep <LowLevelMixinRep> |  processOutermostRep: rep in: ns].
+	processExistingClasses.
+	installAll.
+	Object flushCache. "Clear all lookup caches"
+	removeDeletedClasses.
+	cleanup.
+	^results
+)'private'
+adjust: newObj to: oldObj = (
+	| newInstVarNames <Array[String]> oldInstVarNames <Array[String]> sharedInstVarNames <Array[String]> |
+	newInstVarNames:: newObj class allInstVarNames.
+	oldInstVarNames:: oldObj class allInstVarNames.
+	sharedInstVarNames:: oldInstVarNames select:[:n <String> | newInstVarNames includes: n ].
+	"find intersection of slots names between oldObj and newObj"
+	sharedInstVarNames do:[: n <String> | 
+		"for each slot in the intersection set newObj's value to that in oldObj"
+		| oldIndex newIndex val |
+		oldIndex:: oldInstVarNames indexOf: n.
+		newIndex:: newInstVarNames indexOf: n.
+		val:: vmmirror namedSlotOf: oldObj at: oldIndex ifFail: [halt].
+		vmmirror namedSlotOf: newObj at: newIndex put: val ifFail: [halt].
+	]. 
+)
+cleanup = (
+	newMixins:: nil.
+	revisedObjects:: nil.
+	oldObjects:: nil.
+	existingClasses:: nil.
+	newClasses:: nil.
+	deletedClasses: nil.
+	definingMirrors:: nil.	
+)
+cloneClass: oldClass <Class> ^ <Class> = (
+	| newMeta <Metaclass>  newClass <Class> superKlass <Class> |
+	
+	superKlass::  newClasses at: oldClass superclass ifAbsent:[oldClass superclass].
+   	newMeta:: Metaclass new.
+	newMeta superclass: NewspeakObject class
+                 methodDictionary: oldClass class methodDictionary
+                 format: oldClass class format.	
+	newClass:: newMeta new.
+	newClass superclass: superKlass
+			methodDictionary: oldClass methodDictionary
+			format: (Mixin new pointerFormatNumberOfInstVars: superKlass instSize + oldClass instVarNames size).
+	newClass setInstVarNames: oldClass instVarNames.
+	superKlass instSize ~= oldClass superclass instSize ifTrue:[
+			#MARK yourself.
+			Mixin new generateAccessorsFor: newClass offset: superKlass instSize.
+		].
+	setupDataFor: newClass basedOn: oldClass.
+	^newClass
+)
+depthFor: klass <Class> = (
+	klass isNil ifTrue:[^0].
+	^1 + (depthFor: klass superclass) "Mirrors!"
+)
+existingMixinFor: m <LowLevelMixinMirror> in: ns <Map[Symbol, Class]> ^ <Class | Nil> = (
+	"Find an existing mixin corresponding to me, or nil if there is none"
+	^ns at: m name ifAbsent:[]
+)
+install: newObjects <Array> insteadOf: old <Array>  = (
+	assert:[newObjects size = old size] message: 'New objects array size ', newObjects size printString, ' differs from old objects array size ', oldObjects size printString.
+		oldObjects asArray elementsForwardIdentityToEvenIfImmutable: revisedObjects asArray
+	"one way become of oldObjects to revisedObjects"
+)
+installAll = (
+	installNewMixins.
+	install: revisedObjects asArray insteadOf: oldObjects asArray
+)
+installNewMixins = (
+	newMixins do:[:m <Mixin>  | MixinManager soleInstance addMixinFor: m definingClass].
+	"this makes little sense. We should just manufacture a defining class, not a mixin. Yet this might work anyway"
+	"Moreover, it is not atomic! Do we care?"
+)
+layoutHasChangedBetween: oldClass <Class> and: newClass <Class> ^ <Boolean> = (
+	oldClass ifNil:[
+			newClass ifNil:[^false].
+			^newClass size ~= 0
+			].
+	newClass ifNil:[^oldClass size ~= 0].
+	^(layoutHasChangedBetween: oldClass superclass and: newClass superclass)
+		or:[mixinLayoutHasChangedBetween: (mixinOf: oldClass) and: (mixinOf: newClass)]
+)
+methodDictionaryFor: c <Class> from: m <LowLevelMixinMirror> ^ <MethodDictionary> = (
+	| md <MethodDictionary> methods <List[LowLevelMethodMirror]> |
+	methods:: m methods collect:[:mtd <LowLevelMethodMirror> | mtd].
+	md:: MethodDictionary new: methods size.
+	methods do:[:cm <LowLevelMethodMirror> | 
+		cm klass: c.
+		md at: cm selector put: cm compiledMethod
+		].
+	^md
+)
+mixinLayoutHasChangedBetween: oldMixin <Mixin> and: newMixin <Mixin> ^ <Boolean> = (
+	oldMixin isNil ifTrue:[^false].
+	^oldMixin instVarNames ~= newMixin instVarNames
+)
+mixinOf: invocation <Class> ^ <Class> = (
+	^SystemMetadata mixinOf: invocation
+)
+newClassFor: oldClass <Class> ^ <Class> = (
+	| m <LowLevelMixinMirror> |
+	m:: definingMirrors at: oldClass ifAbsent:[nil].
+	^m isNil ifTrue:[cloneClass: oldClass] ifFalse: [newClassFor: oldClass basedOn: m].
+)
+newClassFor: oldClass <Class> basedOn: m <LowLevelMixinMirror> ^ <Class> = (
+	| 
+	newMeta <Metaclass> 
+	newClass <Class> 
+	instVarNames <List[String]>
+	superKlass <Class>
+	|
+	superKlass::  newClasses at: oldClass superclass ifAbsent:[oldClass superclass].
+	instVarNames:: m instVars collect:[:ivm <InstanceVariableMirror> | ivm name].
+   	newMeta:: Metaclass new.
+	newMeta superclass: NewspeakObject class
+                 methodDictionary: (methodDictionaryFor: newMeta from: m classMixin)
+                 format: oldClass class format.	
+	newClass:: newMeta new.
+	newClass superclass: superKlass
+			methodDictionary: (methodDictionaryFor: newClass from: m)
+			format:  (Mixin new pointerFormatNumberOfInstVars: superKlass instSize + instVarNames size).
+	newClass setInstVarNames:  instVarNames.
+	superKlass instSize ~= 0 ifTrue:[
+			#MARK yourself.
+			Mixin new generateAccessorsFor: newClass offset: superKlass instSize.
+		].
+	setupDataFor: newClass basedOn: oldClass.
+	^newClass
+)
+newFor: old = (
+	^[revisedObjects at: (oldObjects indexOf: old) ifAbsent:[old]] ifError: [old]
+)
+newMixinFrom: m <LowLevelMixinMirror> ^ <Mixin> = (
+	| 
+	mixin <Mixin> 
+	fmt <Integer> 
+	newMeta <Metaclass> 
+	newClass <Class> 
+	instVarNames <List[String]>
+	unSyntheticMethods
+	|
+	
+   	newMeta:: Metaclass new.
+	newMeta superclass: NewspeakObject class
+                 methodDictionary: (methodDictionaryFor: newMeta from: m classMixin)
+                 format: NewspeakObject class format.	"Newspeak classes never add class instance variables"
+	newClass:: newMeta new.
+	setOrganizationOfClass: newMeta basedOn: m classMixin.
 
-mixinOf: invocation <Class> ^ <Class> = (
+	instVarNames:: m instVars collect:[:ivm <InstanceVariableMirror> | ivm name].
+	mixin:: Mixin new.
+	fmt:: mixin pointerFormatNumberOfInstVars: instVarNames size.
+	newClass superclass: ProtoObject
+			methodDictionary: (methodDictionaryFor: newClass from: m)
+			format: fmt.
+	newClass setInstVarNames: instVarNames.
+	newClass setName: m name.
 
-
+	"This is slow and will be handled in post install, so don't do it here
+	setOrganizationOfClass: newClass basedOn: m."
 
-newClassFor: oldClass <Class> ^ <Class> = (
+	"override existing metadata"
+	SystemMetadata systemMetadataOf: newClass put: (
+		DefiningClassMetadata new definingClass: newClass
+		).
+	mixin definingClass: newClass.
+	^mixin
+)
+noteDeletedClass: c <Class>  = (
+"Recursively note all mixins that must be deleted"
+	deletedClasses add: c.
+	(SystemMetadata systemMetadataOf: c) nestedClasses do:[:nc | noteDeletedClass: nc].
+)
+noteNestedMixinsOf: existingMixin <Class> deletedIn: nested <List[MixinList]> = (
+	| survivors <List[LowLevelMixinMirror]> |
+	
+	survivors::nested collect:[:r <MixinList> | r head name].
+	(SystemMetadata systemMetadataOf: existingMixin) nestedMixins do:[:nm <Class> |
+		 (survivors includes: nm name) ifFalse:[noteDeletedClass: nm]
+		]
+)
+processClass: c <Class> = (
+	| newClass <Class> |
+	newClass:: newClassFor: c.
+	newClasses at: c  put: newClass.
+	oldObjects add: c.
+	revisedObjects add: newClass.
+	oldObjects add: c class.
+	revisedObjects add: newClass class.
+	(layoutHasChangedBetween: c and: newClass) 
+		ifTrue:[processInstancesOf: c withNewClass: newClass]
+)
+processExistingClasses = (
+	existingClasses keys asSortedCollection do:[: k <Integer> |
+		(existingClasses at: k) do:[:c <Class> | processClass: c]
+		]
+)
+processExistingMixin: m <LowLeveMixinMirror> withExistingMixin: existingMixin <Class> ^ <Class> = (
+	| newMixin <Mixin> |
+	newMixin:: newMixinFrom: m.
+	SystemMetadata 
+		enclosingMixinOf: newMixin definingClass put: (SystemMetadata mixinOf: existingMixin).
+	SystemMetadata 
+		enclosingMixinOf: newMixin definingClass class put: (SystemMetadata mixinOf: existingMixin class).
+		"set enclosing mixin, in case this was not a top level mixin"
+	revisedObjects addLast: newMixin definingClass.
+	oldObjects addLast: existingMixin.
+	revisedObjects addLast: newMixin definingClass class.
+	oldObjects addLast: existingMixin class.
+	 existingMixin mixin applications do:[: app <Class> | 
+		definingMirrors at: app put: m.
+		sortClass: app
+		].
+	^newMixin definingClass
+)
+processExistingOutermostClass: rep <LowLevelMixinRep> in: ns <Map[Symbol, Class]>  ^ <MixinList> = (
+	| existingOutermostClass <Class> results <MixinList> |
 
-
+	existingOutermostClass:: existingMixinFor: rep first in: ns.
+	assert: [existingOutermostClass superclass = ProtoObject]
+	message: 'Class ', rep first name, ' is not a mixin; it has a non-trivial superclass'.
+	results:: processMixinRep: rep in: ns.
+	(SystemMetadata systemMetadataOf: results head) enclosingClass: (SystemMetadata mixinOf: existingOutermostClass).
+	"existingOutermostClass may not be a top level class. In that case, we need to adjust  the new versions metadata to point at its enclosing class"
+	^results
+)
+processInstancesOf: c <Class> withNewClass: newClass <Class> = (
+	c allInstances do:[: o  | | newObj |
+		"create new instance of newClass"
+		newObj:: newClass basicNew.
+		adjust: newObj to: o. "copy state from o to newObj as needed"
+		oldObjects add: o.
+		revisedObjects add: newObj
+	]
+)
+processMixinRep: rep <LowLevelMixinRep> in: ns <Map[Symbol, Class]> ^ <MixinList> = (
+	| existingMixin <Class> |
+	rep isNil ifTrue:[^nil].
+	rep isEmpty ifTrue:[^nil].
+	existingMixin:: existingMixinFor: rep first in: ns.
+	^existingMixin isNil
+		ifTrue:[processNewMixinRep: rep]
+		ifFalse: [processMixinRep: rep withExistingMixin: existingMixin]
+)
+processMixinRep: rep <LowLevelMixinRep> withExistingMixin: existingMixin <Class> ^ <MixinList> = (
+"existingMixin is the mixin being redefined by rep. The resulting MixinList will include the new version of existingMixin and all its nested mixins as described by rep "
+	| enclosing <Class> nested <List[MixinList]> ns <Map[Symbol, Class]> |
+	enclosing:: processExistingMixin: rep first withExistingMixin: existingMixin.
+	ns:: Map new.
+	((SystemMetadata systemMetadataOf: existingMixin) nestedClasses) do:[:c <Class> |
+		ns at: c name put: c.
+		].
+	nested:: rep last collect:[:r <LowLevelMixinRep> | processMixinRep: r in: ns].
+	nested do:[:nm <MixinList> |  SystemMetadata nestedClass: nm head within: enclosing].
+	noteNestedMixinsOf: existingMixin deletedIn: nested.
+	^MixinList head: enclosing
+			 tail: nested.
+)
+processNewMixin: m <LowLevelMixinMirror> ^ <Class> = (
+	"create mixin and add to new mixins"
+	| newMixin <Mixin> definingClass <Class> |
+	newMixin:: newMixinFrom: m.
+	newMixins addLast: newMixin.
+	definingClass:: newMixin definingClass.
+	ProtoObject addSubclass: definingClass.
+	^definingClass.
+)
+processNewMixinRep: rep <LowLevelMixinRep> ^ <MixinList> = (
+	| enclosing <Class> nested <List[MixinList]> |
+	rep isNil ifTrue:[^nil].
+	rep isEmpty ifTrue:[^nil].
+	enclosing:: processNewMixin: rep first.
+	nested:: rep last collect:[:r <LowLevelMixinRep> | processNewMixinRep: r].
+	nested do:[:nm <MixinList> |  SystemMetadata nestedClass: nm head within: enclosing].
+	^MixinList head: enclosing
+			 tail: nested.
+)
+processOutermostRep: rep <LowLevelMixinRep> in: ns <Map[Symbol, Class]> ^ <MixinList> = (
+	ns at: rep first name asSymbol ifAbsent:[^processNewMixinRep: rep].
+	^processExistingOutermostClass: rep in: ns.
+)
+removeDeletedClasses = (
+	deletedClasses do:[:dc <Class> | ProtoObject removeSubclass: dc]
+)
+setOrganizationOfClass: cls <Class>
+basedOn: lm <LowLevelMixinMirror> = (
+	| nonSyntheticMethods <LowLevelMethodMirror> |
+	nonSyntheticMethods:: (lm methods select: [ :mt | mt isSynthetic not]).
+	
+	"manually set organization, excluding synthetic methods"
+	cls organization:  (ClassOrganizer defaultList: (nonSyntheticMethods collect: [:ea | ea selector])).
 
-newClassFor: oldClass <Class> basedOn: m <LowLevelMixinMirror> ^ <Class> = (
   	newMeta:: Metaclass new.
                 methodDictionary: (methodDictionaryFor: newMeta from: m classMixin)
                 format: oldClass class format.	
+	"classify (non-synthetic) elements if mirror includes category information"
+	(nonSyntheticMethods 
+		select: [ :um | um metadata includesKey: #category ])
+		do: [ :cm | cls organization
+						classify: cm selector
+						under: (cm metadata at: #category) ].
+)
+setup = (
+	newMixins:: List new.
+	revisedObjects:: List new.
+	oldObjects:: List new.
+	existingClasses:: Map new.
+	newClasses:: Map new.
+	deletedClasses:: List new.
+	definingMirrors:: Map new.	
+)
+setupDataFor: newClass <Class> basedOn: oldClass <Class> = (
+	| newMeta <Metaclass> |
+	newMeta:: newClass class.
 
-
-
-newFor: old = (
-
-
-
-newMixinFrom: m <LowLevelMixinMirror> ^ <Mixin> = (
   	newMeta:: Metaclass new.
                 methodDictionary: (methodDictionaryFor: newMeta from: m classMixin)
                 format: NewspeakObject class format.	"Newspeak classes never add class instance variables"
-
-
-
-noteDeletedClass: c <Class>  = (
-
-
-
-noteNestedMixinsOf: existingMixin <Class> deletedIn: nested <List[MixinList]> = (
-
-
-
-processClass: c <Class> = (
-
-
-
-processExistingClasses = (
-
-
-
-processExistingMixin: m <LowLeveMixinMirror> withExistingMixin: existingMixin <Class> ^ <Class> = (
-
-
-
-processExistingOutermostClass: rep <LowLevelMixinRep> in: ns <Map[Symbol, Class]>  ^ <MixinList> = (
-
-
-
-processInstancesOf: c <Class> withNewClass: newClass <Class> = (
-
-
-
-processMixinRep: rep <LowLevelMixinRep> in: ns <Map[Symbol, Class]> ^ <MixinList> = (
-
-
-
-processMixinRep: rep <LowLevelMixinRep> withExistingMixin: existingMixin <Class> ^ <MixinList> = (
-
-
-
-processNewMixin: m <LowLevelMixinMirror> ^ <Class> = (
-
-
-
-processNewMixinRep: rep <LowLevelMixinRep> ^ <MixinList> = (
-
-
-
-processOutermostRep: rep <LowLevelMixinRep> in: ns <Map[Symbol, Class]> ^ <MixinList> = (
-
-
-
-removeDeletedClasses = (
-
-
-
-setOrganizationOfClass: cls <Class>
-
-
-
-setup = (
-
-
-
-setupDataFor: newClass <Class> basedOn: oldClass <Class> = (
-
-
-
-sortClass: app <Class>  = (
-
-
-
-'accessing'
-
-atomicallyInstallMixinReps: mixins <List[LowLevelMixinRep]> namespace: ns <Map[Symbol, Class]> ^ <List[MixinList]> = (
 "
-
-
-
-)
+	#MARK yourself.
+	SystemMetadata mixinOf: newClass put: (newFor: (SystemMetadata mixinOf: oldClass)).
+	SystemMetadata mixinOf: newMeta put: (newFor: (SystemMetadata mixinOf: oldClass class)).
+	SystemMetadata enclose: newClass inObject: (SystemMetadata enclosingObjectOf: oldClass).
+	SystemMetadata enclose: newMeta inObject: (SystemMetadata enclosingObjectOf: oldClass class).
+	SystemMetadata systemMetadataOf: newClass put:(SystemMetadata systemMetadataOf: oldClass).
+	newClass organization: oldClass organization.
+	newMeta organization: oldClass class organization.
+	newClass setName: oldClass name.		
+)
+sortClass: app <Class>  = (
+| classes <Set[Class]> depth <Integer> |
+	depth:: depthFor: app.
+	classes:: existingClasses 
+		at: depth 
+		ifAbsent:[existingClasses at: depth put: Set new].
+	classes add: app. "optimize? If app is already there, no need to recurse on subclasses"
+	app subclasses do:[: sc <Class> | sortClass: sc]. "use mirrors"
+))
 ^names
 )
 classAndSelectorString = (
-	| cn = (className subStrings: '`') reverse reduce: [ :m :o | m, ' in ', o]. |
-	^ selector asString, ' in ', cn
+|	cs = className subStrings: '`'.
+	legibleClassName = cs reverse reduce: [ :m :o | m, ' in ', o]. | 
+	^ selector asString, ' in ', legibleClassName.
 )
 implementingClass = (
 
 	^link: aClass name action: [browseClass: aClass]
 )
 linkToBrowseClassMirror: aMirror = (
-
-	^link: aMirror name action: [browseClassMirror: aMirror]
+|	cs = aMirror name subStrings: '`'.
+	legibleClassName = cs reverse reduce: [ :m :o | m, ' in ', o]. | 
+	^ link: legibleClassName action: [browseClassMirror: aMirror]
 )
 linkToBrowseSelector: selector = (
 

NSUnit.ns3

-Newspeak3
 |
 	result:: TestResult new.
 	false] on: anExceptionalEvent
 	false] on: anExceptionalEvent
 	false] on: anExceptionalEvent
 	| exception |
    "Evaluate aBlock in a forked process and if it takes more than anInteger milliseconds
    to run we terminate the process and report a test failure.  It'' important to
    use the active process for the test failure so that the failure reporting works correctly
    in the context of the exception handlers."
    | evaluated evaluationProcess result delay testProcess |
    evaluated:: false.
    delay:: Delay forDuration: aDuration.
    testProcess:: Processor activeProcess.
    "Create a new process to evaluate aBlock"
    evaluationProcess:: [
        result:: aBlock value.
        evaluated:: true.
        delay unschedule.
        testProcess resume ] forkNamed: 'Process to evaluate should: notTakeMoreThanMilliseconds:'.
    "Wait the milliseconds they asked me to"
    delay wait.
    "After this point either aBlock was evaluated or not..."
    evaluated ifFalse: [
        evaluationProcess terminate.
       assert: false description: ('Block evaluation took more than the expected <1p>' expandMacrosWith: aDuration)].
   
    ^result
    "For compatibility with other Smalltalks"
   should: aBlock notTakeMoreThan: (Duration milliSeconds: anInteger).
 	false] 
- testModuleName ^ <Symbol> - returning the name of the class under test
- configuration: ideNamespace <Namespace> ^ <Class> - returning a test case class that can be instantiated into a test case. "
-Newspeak3
+Newspeak3
+'StructuredVCS'
+class VCS usingPlatform: p vcs: vcs ide: ide = (
+"A source control application that supports different VCS backends (git, hg, ...).
 
-'StructuredVCS'
+Support for new VCSs can be added by providing a custom implementation of AbstractBackend.
 
-
 
-class VCS usingPlatform: p vcs: vcs ide: ide = (
-"A source control application that supports different VCS backends (git, hg, ...).
-
-Support for new VCSs can be added by providing a custom implementation of AbstractBackend.
-
-
-Copyright (c) 2010-2011 Matthias Kleine
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ''Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED ''AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"|
-
-"some awkward name, as outer sends can currently not be compiled"
-protected importedSourceMirrors = vcs sourceMirrors.
-
-"should an explicit reference to a newspeak specific mirror be here?"
-protected ClassSourceMirror = importedSourceMirrors ClassSourceMirror.
-
-private diffing = vcs diffing.
-
-"Collections"
-protected Set = p Collections Set.
-protected OrderedCollection = p Collections OrderedCollection.
-protected Dictionary = p Collections Dictionary.
-
-
-protected Stream = p Collections Stream.
-protected TextStream = p Collections TextStream.
-
-protected ExternalLauncher = p ExternalProcess ExternalLauncher.
-
-protected UUID = p Network UUID.
-
-protected Time = p Kernel Time.
-protected Monitor = p Kernel Monitor.
-
-protected Color = p Graphics Color.
-
-protected MultiByteBinaryOrTextStream = p Multilingual MultiByteBinaryOrTextStream.
-
-private CrLfFileStream = p Files CrLfFileStream.
-
-protected HopscotchImages = p Hopscotch HopscotchImages.
-
-protected hopscotch = p hopscotch.
-protected Subject = hopscotch core Subject.
-protected Presenter = hopscotch core Presenter.
-protected RowComposer = hopscotch composers RowComposer.
-protected ColumnComposer = hopscotch composers ColumnComposer.
-protected BlankFragment = hopscotch fragments BlankFragment.
-protected TextEditorFragment = hopscotch fragments TextEditorFragment.
-protected SeparatorItem = hopscotch SeparatorItem.
-protected Menu = hopscotch Menu.
-protected MenuItem = hopscotch MenuItem.
-protected EditableLinePresenter = hopscotch fragments EditableLinePresenter.
-
-protected Transcript = p Transcript.
-
-brazil = p brazil.
-private Gradient = brazil plumbing Gradient.
-
-private FileDirectory = p Files FileDirectory.
-
-"Nested classes"
-
-protected Differencer = diffing Differencer.
-protected WordMerger = diffing WordMerger.
-
-protected SourceControlSubject = vcs ui SourceControlSubject.
-
-Processor = p Processor.
-
-"Other fields"
-protected logger = Logger new.
-private processes = Set new.
-|)
+Copyright (c) 2010-2011 Matthias Kleine
 
-(
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ''Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
-
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 
-class Logger = (|
-	logMonitor = Monitor new.
-	logCounter ::= 0.
-|)
+THE SOFTWARE IS PROVIDED ''AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"|
 
-('as yet unclassified'
+"some awkward name, as outer sends can currently not be compiled"
+protected importedSourceMirrors = vcs sourceMirrors.
 
-halt: message = (
+"should an explicit reference to a newspeak specific mirror be here?"
+protected ClassSourceMirror = importedSourceMirrors ClassSourceMirror.
 
-
+private diffing = vcs diffing.
 
-info: message = (
+"Collections"
+protected Set = p Collections Set.
+protected OrderedCollection = p Collections OrderedCollection.
+protected Dictionary = p Collections Dictionary.
 
-
 
-log: message = (
+protected Stream = p Collections Stream.
+protected TextStream = p Collections TextStream.
 
-
+protected ExternalLauncher = p ExternalProcess ExternalLauncher.
 
-log: message around: block = (
+protected UUID = p Network UUID.
 
-
+protected Time = p Kernel Time.
+protected Monitor = p Kernel Monitor.
 
-warn: message = (
+protected Color = p Graphics Color.
 
-
+protected MultiByteBinaryOrTextStream = p Multilingual MultiByteBinaryOrTextStream.
 
-)
+private CrLfFileStream = p Files CrLfFileStream.
 
-
+protected HopscotchImages = p Hopscotch HopscotchImages.
 
-class AbstractBackend = ("Abstract superclass for concrete back-ends. Provides shared functionality.
-
-Concrete implementations must provide a subclass of AbstractBackend that implements classes/methods marked as such"|
-|)
+protected hopscotch = p hopscotch.
+protected Subject = hopscotch core Subject.
+protected Presenter = hopscotch core Presenter.
+protected RowComposer = hopscotch composers RowComposer.
+protected ColumnComposer = hopscotch composers ColumnComposer.
+protected BlankFragment = hopscotch fragments BlankFragment.
+protected TextEditorFragment = hopscotch fragments TextEditorFragment.
+protected SeparatorItem = hopscotch SeparatorItem.
+protected Menu = hopscotch Menu.
+protected MenuItem = hopscotch MenuItem.
+protected EditableLinePresenter = hopscotch fragments EditableLinePresenter.
 
-(
+protected Transcript = p Transcript.
 
-
+brazil = p brazil.
+private Gradient = brazil plumbing Gradient.
 
-class AbstractRemoteRepository onLocalRepository: lr onRepositoryId: repositoryId onName: n = Repository onRepositoryId: repositoryId (|
-	protected localRepository = lr.
-	protected name = n.|)
+private FileDirectory = p Files FileDirectory.
 
-(
+"Nested classes"
 
-
+protected Differencer = diffing Differencer.
+protected WordMerger = diffing WordMerger.
 
-class AbstractRemoteHistorian named: historianName versionId: vId = GeneralHistorian named: historianName ("A historian stored in a remote repository. It knows only it's version's identifier"|
-	versionId = vId.
-|)
+protected SourceControlSubject = vcs ui SourceControlSubject.
 
-('actions'
+Processor = p Processor.
 
-createIfFail: failBlock = (
+"Other fields"
+protected logger = Logger new.
+private processes = Set new.
+|)
+(
+class AbstractBackend = ("Abstract superclass for concrete back-ends. Provides shared functionality.
 
-
+Concrete implementations must provide a subclass of AbstractBackend that implements classes/methods marked as such"|
+|)
+(
+class AbstractLocalRepository onRepositoryId: repositoryId = Repository onRepositoryId: repositoryId (|
+protected repositoryDirectory = FileDirectory on: repositoryId.
+protected repositoryVersionAccessing = RepositoryVersionAccessing new.
+|)
+(
+class AbstractLocalHistorian named: n version: v = SuperHistorian named: n (|
+	version = v.
+|)
+('accessing'
+canMergeWith: otherVersion = (
 
-trackAs: localHistorianName = (
+	^ (version isAncestorOf: otherVersion version) not and: [
+			(otherVersion version isAncestorOf: version) not]
+)'actions'
+cloneAs: clonedHistorianName ifFail: failBlock = (
 
-
+	^ repository
+		newHistorianNamed: clonedHistorianName
+		setTo: version
+		ifFail: failBlock.
+)
+forkAs: forkedHistorianName ifFail: failBlock = (
 
-'accessing'
+	| forkedHistorian |
+	forkedHistorian:: repository newHistorianNamed: forkedHistorianName setTo: version ifFail: failBlock.
+	^ forkedHistorian
+)
+forwardTrackedHistorianIfFail: failBlock = (
 
-isTracked = (
+	trackedHistorianifPresent: [:trackedHistorian | trackedHistorian setTo: version ifFail: failBlock]
+	ifAbsent: [failBlock value: 'No tracked historian available']
+	ifError: [
+		logger warn: 'Couln''t access historian'.
+		failBlock value: 'Failed to access historian']
+)
+setTo: newVersion ifFail: failBlock = (
 
-
+	super setTo: newVersion ifFail: failBlock.
+	version:: newVersion
+)
+shareTo: remoteRepository = (
 
-version = (
+	| newName newHistorian |
+	newHistorian:: remoteRepository newHistorianNamed: name setTo: version ifFail: [logger error: 'Could not create a new remote historian'].
+	trackedHistorian: newHistorian.
+)'subclassResponsibility'
+trackedHistorian: otherHistorian = (
 
-
+	subclassResponsibility
+)
+trackedHistorianifPresent: presentBlock ifAbsent: absentBlock ifError: errorBlock = (
 
-)'accessing'
+	subclassResponsibility
+))
+class AbstractRepositoryVersionAccessing = ()
+(
+class AbstractRepositoryVersion = Version ("An immutable Version that can be retrieved from the repository using an identifier."|
+	internalId
+	message
+	author
+	cachedWithAncestors
+|)
+('accessing'
+hash = (
 
-GeneralHistorian = (
+	^ internalId hash
+)
+isParentOfImage = (
 
-
+	^ imageHistorian version = self
+)
+isRepositoryVersion = (
 
-historianNamed: name versionId: versionId = (
+	^ true
+)
+parents = (
 
-
+	^ parentInternalIds collect: [:each | versionAtInternalId: each].
+)
+withAncestors = (
 
-repository = (
+	nil = cachedWithAncestors ifTrue: [
+		cachedWithAncestors:: super withAncestors].
+	^ cachedWithAncestors
+)'actions'
+loadIntoImage = (
 
-
+	sourceMirrors installMirrorsAsToplevelClasses: mirrors
+)'subclassResponsibility'
+parentInternalIds = (
 
-'actions'
+	subclassResponsibility
+)'testing'
+= other = (
 
-exportVersionId: versionId = (
+	^ other internalId = internalId
+))
+class AbstractRepositoryVersionStream onStream: s = Stream (|
+	stream = s.
+|)
+('accessing'
+atEnd = (
 
-
+	^ stream atEnd
+)
+contents = (
 
-importVersionId: versionId = (
+	| copied |
+	copied:: self class onStream: stream contents readStream.
+	^ Array streamContents: [:resultStream |
+		[copied atEnd] whileFalse: [
+			resultStream nextPut: copied next]].
+)'actions'
+nextLine = (
 
-
+	^ String streamContents: [:resultStream | | c |
+		c:: stream next.
+		[c = nil or: [c = Character cr]] whileFalse: [
+			resultStream nextPut: c.
+			c:: stream next]]
+))'accessing'
+Version = (
 
-)
+	"We shouldn't require this. But something appears to be broken with the compiler."
+	^ outer AbstractBackend Version
+)'subclassResponsibility'
+exportVersionId: internalId to: remoteRepository = (
 
-
+	subclassResponsibility
+)
+importVersionId: internalId from: remoteRepository = (
 
-class Version = ("Common functionality shared by all versions
-
-Subclasses must provide:
-- parents
-- mirrors
-- hash
-- =
-- commonAncestorWith:
-
-Generic implementations could be provided for hash, =, commonAncestorWith: if needed at some point."|
-|)
+	subclassResponsibility
+)
+versionAtInternalId: internalId = (
 
-('accessing'
+	subclassResponsibility
+))'accessing'
+Stream = (
 
-commonAncestorWith: otherVersion = (
+	"Something is broken with the NS2 compiler. It cannot find Stream otherwise."
+	^ outer VCS Stream
+)
+SuperHistorian = (
 
-
+	^ super Historian
+)
+historianNamed: name versionId: versionId = (
 
-diffsFrom: version = (
+	^ Historian named: name version: (versionAtInternalId: versionId)
+)
+logStream = (
 
-
+	^ repositoryVersionAccessing logStream
+)
+remoteRepositoryAt: repositoryId = (
 
-diffsFromFirstParent = (
+	^ remoteRepositories detect: [:each |
+		each repositoryId = repositoryId or: [each name = repositoryId]]
+)
+versionAtInternalId: internalId = (
 
-
+	^ repositoryVersionAccessing versionAtInternalId: internalId
+)'actions'
+exportVersionId: internalId to: remoteRepository = (
 
-diffsTo: version = (
+	repositoryVersionAccessing exportVersionId: internalId to: remoteRepository
+)
+importVersionId: internalId from: remoteRepository = (
 
-
+	^ repositoryVersionAccessing importVersionId: internalId from: remoteRepository
+)
+refresh = (
 
-hash = (
+	"May be overridden"
+)'subclassResponsibility'
+RepositoryVersionAccessing = (
 
-
+	subclassResponsibility
+)
+create = (
 
-mirrors = (
+	subclassResponsibility
+)
+imageHistorian = (
 
-
+	subclassResponsibility
+)
+remoteRepositories = (
 
-parents = (
+	subclassResponsibility
+))
+class AbstractRemoteRepository onLocalRepository: lr onRepositoryId: repositoryId onName: n = Repository onRepositoryId: repositoryId (|
+	protected localRepository = lr.
+	protected name = n.|)
+(
+class AbstractRemoteHistorian named: historianName versionId: vId = GeneralHistorian named: historianName ("A historian stored in a remote repository. It knows only it's version's identifier"|
+	versionId = vId.
+|)
+('accessing'
+isTracked = (
 
-
+	^ localRepository historians anySatisfy: [:each |
+		each
+			trackedHistorianifPresent: [:trackedHistorian | self = trackedHistorian]
+			ifAbsent: [false]
+			ifError: [
+				logger warn: 'Couln''t access historian'.
+				false]]
+)
+version = (
 
-versionsIncomingFrom: otherVersion = (
+	repository exportVersionId: versionId.
+	^ localRepository versionAtInternalId: versionId
+)'actions'
+createIfFail: failBlock = (
 
-
+	repository importVersionId: version internalId.
+	super createIfFail: failBlock
+)
+trackAs: localHistorianName = (
 
-withAncestors = (
+	^ localRepository
+		newHistorianNamed: localHistorianName
+		trackingHistorian: self
+		setTo: version
+		ifFail: [insertErrorHandlingForTrackingAHistorianWhenALocalHistorianWithTheGivenNameAlreadyExists]
+))'accessing'
+GeneralHistorian = (
 
-
+	^ super Historian
+)
+historianNamed: name versionId: versionId = (
 
-zipMirrors: mirrorCollections = (
+	^ Historian named: name versionId: versionId
+)
+repository = (
 
-
+	^ self
+)'actions'
+exportVersionId: versionId = (
 
-zippedMirrorsWith: other = (
+	localRepository importVersionId: versionId from: self
+)
+importVersionId: versionId = (
 
-
+	localRepository exportVersionId: versionId to: self
+))
+class AbstractRepository onRepositoryId: rid = (|
+    private repositoryId = rid.
+	protected cachedCommand
+|)
+(
+class AbstractCommand = (|
+	cachedLauncher
+|)
+(
+class Launcher = (|
+cachedExternalLauncher
+command
 
-'testing'
+|)
+('accessing'
+externalLauncher = (
 
-= other = (
+	nil = cachedExternalLauncher ifTrue: [
+		cachedExternalLauncher:: ExternalLauncher for: command.
+		cachedExternalLauncher
+			otherUnixLocations: {'/opt/local/bin'. '/usr/local/bin'};
+			otherWindowsLocations: {'c:\cygwin\bin'}].
+	^cachedExternalLauncher
+)'actions'
+noDefaultArgumentsRun: arguments = (
 
-
+	^ externalLauncher
+		runWith: arguments
+		ifSuccess: [ :stdout <ReadStream> :stderr <ReadStream> |
+			stdout contents]
+		ifFailure: [ :stdout <ReadStream> :stderr <ReadStream> |
+			halt]
+)
+run: arguments = (
 
-isAncestorOf: version = (
+	^ run: arguments ifFail: [halt]
+)
+run: arguments ifFail: failBlock= (
 
-
+	^ run: arguments ifSuccess: [:stdout :stderr | stdout contents] ifFailure: [:stdout :stderr | failBlock value]
+)
+run: arguments ifSuccess: successBlock ifFailure: failureBlock = (
 
-'private'
+	^ externalLauncher
+		runWith: defaultArguments, arguments
+		ifSuccess: [ :stdout <ReadStream> :stderr <ReadStream> |
+			successBlock value: stdout value: stderr]
+		ifFailure: [ :stdout <ReadStream> :stderr <ReadStream> |
+			failureBlock value: stdout value: stderr]
+)
+runLines: arguments = (
 
-genericZip: partitions sortBlock: sortBlock = (
+	^ runLines: arguments ifFail: [halt]
+)
+runLines: arguments ifFail: failBlock = (
 
-
+	| result|
+	result:: OrderedCollection new.
+	(run: arguments ifFail: failBlock) linesDo: [:each |
+		result add: each].
+	^ result
+)
+runStream: arguments = (
 
-)
+	| resultStream |
+	resultStream:: run: arguments ifSuccess: [:stdout :stderr | stdout] ifFailure: [:stdout :stderr | halt].
+	^ (MultiByteBinaryOrTextStream with: resultStream contents encoding: 'utf8') reset
+))'accessing'
+ignoredFilename = (
 
-
+	^ '.ignore'
+)
+launcher = (
 
-class AbstractLocalRepository onRepositoryId: repositoryId = Repository onRepositoryId: repositoryId (|
-protected repositoryDirectory = FileDirectory on: repositoryId.
-protected repositoryVersionAccessing = RepositoryVersionAccessing new.
-|)
+	cachedLauncher = nil ifTrue: [
+		cachedLauncher::  Launcher new
+			command: commandLine;
+			yourself].
+	^ cachedLauncher
+)'actions'
+writeStream: stream toFileNamed: filename = (
 
-(
+	(CrLfFileStream forceNewFileNamed: (repository repositoryDirectory / filename) pathName)
+		ascii;
+		nextPutAll: stream contents;
+		close.
+)'subclassResponsibility'
+commandLine = (
 
-
+	subclassResponsibility
+)
+defaultArguments = (
 
-class AbstractRepositoryVersionAccessing = ()
+	subclassResponsibility
+)'testing'
+isFilenameIgnored: filename = (
 
-(
+	^ filename = ignoredFilename
+))
+class AbstractHistorian named: historianName = (|
 
-
+	public name = historianName.
+|)
+(
+class AbstractHistorianChange onVersion: v = ("Encapsulates the action of committing a new version"|
 
-class AbstractRepositoryVersionStream onStream: s = Stream (|
-	stream = s.
-|)
+newVersion = v.
+|)
+('accessing'
+changedMirrors = (
 
-('actions'
+	| filteredZippedMirrors |
+	"TODO: Move zippedMirrors + allEqual into intermediate Project/StoreSnapshot abstraction. Check for senders of allEqual:"
+	filteredZippedMirrors:: zippedMirrors reject: [:each |
+		nil = each first
+			or: [Differencer allEqual: each]].
+	^ filteredZippedMirrors collect: [:each | each first]
+)
+deletedOriginalMirrors = (
 
-nextLine = (
+	| filteredZippedMirrors |
+	filteredZippedMirrors:: zippedMirrors select: [:each | nil = each first].
+	^ filteredZippedMirrors collect: [:each | each second]
+)
+historian = (
 
-
+	^ outer AbstractHistorian historian
+)'actions'
+commit = (
 
-'accessing'
+	subclassResponsibility
+)'private'
+zippedMirrors = (
 
-atEnd = (
+	"try zippedMirrorsWith:"
+	^ newVersion zipMirrors: {newVersion mirrors. historian version mirrors}.
+))'accessing'
+hash = (
 
-
+	^ name hash
+)
+historian = (
 
-contents = (
+	^ self
+)
+repository = (
 
-
+	^ outer AbstractRepository repository
+)
+versionsIncomingFrom: otherHistorian = (
 
-)
+	^ version versionsIncomingFrom: otherHistorian version
+)'actions'
+commit: v = (
 
-
+	"Commits a new version and sets the historian to it. We might want to do this using
+	setTo:ifFail: only. We could dispatch on the version to determine whether the version is new and has to be committed."
+	| change |
+	(v parents includes: self version) ifFalse: [logger error: 'Trying to commit non-child version'].
+	change:: HistorianChange onVersion: v.
+	change commit
+)
+loadIntoImage = (
 
-class AbstractRepositoryVersion = Version ("An immutable Version that can be retrieved from the repository using an identifier."|
-	internalId
-	message
-	author
-	cachedWithAncestors
-|)
+	version loadIntoImage.
+	makeCurrentHistorian
+)'subclassResponsibility'
+HistorianChange = (
 
-('accessing'
+	subclassResponsibility
+)
+createIfFail: failBlock = (
 
-hash = (
+	subclassResponsibility
+)
+makeCurrentHistorian = (
 
-
+	subclassResponsibility
+)
+version = (
 
-isParentOfImage = (
+	subclassResponsibility
+)'testing'
+= other = (
 
-
+	^ repository = other repository and: [name = other name]
+)
+canForwardTo: otherVersion = (
 
-isRepositoryVersion = (
+	^ (version = otherVersion version) not and: [
+		version isAncestorOf: otherVersion version]
+))'accessing'
+command = (
 
-
+	nil = cachedCommand ifTrue: [
+		cachedCommand:: Command new.].
+	^ cachedCommand
+)
+hash = (
 
-parents = (
+	^ self repositoryId hash
+)
+historianNamed: historianName ifFail: failBlock = (
 
-
+	^ historians detect: [:each | each name = historianName] ifNone: failBlock
+)
+repository = (
 
-withAncestors = (
+	^ self
+)'actions'
+createNewVersion = (
 
-
+	^ NewVersion new
+)
+newHistorianNamed: historianName setTo: initialVersion ifFail: failBlock = (
 
-'subclassResponsibility'
+	(historians anySatisfy: [:each | each name = historianName]) ifTrue: [
+		^ failBlock value].
+	^ (Historian named: historianName version: initialVersion)
+		createIfFail: failBlock;
+		yourself
+)
+newHistorianNamed: historianName trackingHistorian: trackedHistorian setTo: initialVersion ifFail: failBlock = (
 
-parentInternalIds = (
+	| result |
+	result:: newHistorianNamed: historianName setTo: initialVersion ifFail: failBlock.
+	nil = trackedHistorian ifFalse: [
+		result trackedHistorian: trackedHistorian].
+	^ result
+)'subclassResponsibility'
+Historian = (
 
-
+	subclassResponsibility
+)
+clone: repositoryLocation = (
 
-'testing'
+	subclassResponsibility
+)
+historianNamed: name versionId: versionId = (
 
-= other = (
+	"Implemented in abstract subclasses"
+	subclassResponsibility
+)
+historians = (
 
-
+	subclassResponsibility
+)
+logStream = (
 
-'actions'
+	subclassResponsibility
+)
+repositoryType = (
 
-loadIntoImage = (
+	subclassResponsibility
+)'testing'
+= other = (
 
-
+	^ self repositoryId = other repositoryId and: [
+		self repositoryType = other repositoryType]
+))
+class NewVersion = Version (
+"A version that has not yet been committed."|
+	parents
+	mirrors
+	message
+|)
+('accessing'
+hash = (
 
-)'subclassResponsibility'
+	^ message hash
+)'testing'
+= other = (
 
-exportVersionId: internalId to: remoteRepository = (
+	"TODO: Move zippedMirrors + allEqual into intermediate Project/StoreSnapshot abstraction. Check for senders of allEqual:"
+	^ other message = message and: [ | zippedMirrors |
+		zippedMirrors:: self zipMirrors: {self mirrors. other mirrors}.
+		(zippedMirrors allSatisfy: [:each | Differencer allEqual: each]) and: [
+			other parents asSet = parents asSet]]
+)
+commonAncestorWith: version = (
 
-
+	parents size = 0 ifTrue: [logger halt: 'no parents set'].
+	^ parents inject: version into: [:acc :each | acc commonAncestorWith: each]
+))
+class Version = ("Common functionality shared by all versions
 
-importVersionId: internalId from: remoteRepository = (
+Subclasses must provide:
+- parents
+- mirrors
+- hash
+- =
+- commonAncestorWith:
 
-
+Generic implementations could be provided for hash, =, commonAncestorWith: if needed at some point."|
+|)
+('accessing'
+commonAncestorWith: otherVersion = (
 
-versionAtInternalId: internalId = (
+	subclassResponsibility
+)
+diffsFrom: version = (
 
-
+	| zippedMirrors |
+	zippedMirrors:: zippedMirrorsWith: version.
+	^ zippedMirrors collect: [:each |
+		Differencer compare: each last to:each first withAncestor: each second]
+)
+diffsFromFirstParent = (
 
-'accessing'
+	^ diffsFrom: parents first
+)
+diffsTo: version = (
 
-Version = (
+	^ version diffsFrom: self
+)
+hash = (
 
-
+	subclassResponsibility
+)
+mirrors = (
 
-)
+	subclassResponsibility
+)
+parents = (
 
-
+	subclassResponsibility
+)
+versionsIncomingFrom: otherVersion = (
 
-class AbstractLocalHistorian named: n version: v = SuperHistorian named: n (|
-	version = v.
-|)
+	"The name isn't too descriptive. But withAncestorsNotContainedIn: (works the other way) isn't that good, either"
+	"The implementation is slow and can be optimized to traverse ancestors in parallel, should efficiency become a problem."
+	^ otherVersion withAncestors copyWithoutAll: self withAncestors asSet
+)
+withAncestors = (
 
-('actions'
+	"While traversing our ancestors we must keep track of ancestors that we already added to the result. We're using an iterative approach for traversing through the ancestors, as a recursive algorithm was too slow."
+	| result position ancestorsAlreadyAdded |
 
-cloneAs: clonedHistorianName ifFail: failBlock = (
+	result:: OrderedCollection new.
+	position:: 1.
+	ancestorsAlreadyAdded:: Set new.	
+	result add: self.
 
-
+	[position > result size] whileFalse: [ | current |
+		current:: result at: position.
+		position:: position + 1.
+		current parents do: [:each |
+			(ancestorsAlreadyAdded includes: each) ifFalse: [
+				ancestorsAlreadyAdded add: each.
+				result add: each]]].
+	^ result		
+)
+zipMirrors: mirrorCollections = (
 
-forkAs: forkedHistorianName ifFail: failBlock = (
+	| sortBlock |
+	sortBlock:: [:a :b | a name asString <= b name asString].
+	^ genericZip: mirrorCollections sortBlock: sortBlock
+)
+zippedMirrorsWith: other = (
 
-
+	| commonAncestor |
+	commonAncestor:: commonAncestorWith: other.
+	^ zipMirrors: {mirrors. commonAncestor mirrors. other mirrors}.
+)'private'
+genericZip: partitions sortBlock: sortBlock = (
 
-forwardTrackedHistorianIfFail: failBlock = (
+	"Taken from my parsing code"
+	| streams result partitionsHavingSmallest |
+	result:: OrderedCollection new.
+	partitionsHavingSmallest:: OrderedCollection new.
+	streams:: partitions collect: [:each |
+		(each asSortedCollection: sortBlock) readStream].
+	[streams allSatisfy: [:each | each atEnd]] whileFalse: [ | smallest zipped  |
+		partitionsHavingSmallest reset.
+		smallest:: nil.
+		streams doWithIndex: [:stream :i | | c |
+			stream atEnd ifFalse: [
+				c:: stream peek.
+				(smallest isNil or: [sortBlock value: c value: smallest]) ifTrue: [
+					(smallest isNil or: [(sortBlock value: smallest value: c) not]) ifTrue: [
+						smallest:: c.
+						partitionsHavingSmallest reset].
+					partitionsHavingSmallest add: i]]].
+		zipped:: Array ofSize: partitions size. "Object allocation"
+		partitionsHavingSmallest do: [:i | | stream |
+			stream:: streams at: i.
+			zipped at: i put: stream next].
+		result add: zipped].
+	^ result
+)'testing'
+= other = (
 
-
+	subclassResponsibility
+)
+isAncestorOf: version = (
 
-setTo: newVersion ifFail: failBlock = (
+	^ self = (self commonAncestorWith: version)
+))'accessing'
+sourceMirrors = (
 
-
+	^ importedSourceMirrors
+)'subclassResponsibility'
+LocalRepository = (
 
-shareTo: remoteRepository = (
+	subclassResponsibility
+)
+RemoteRepository = (
 
-
+	subclassResponsibility
+))
+class Logger = (|
+	logMonitor = Monitor new.
+	logCounter ::= 0.
+|)
+('as yet unclassified'
+error: msg = (
+	Error signal: msg
+)
+halt: message = (
 
-'subclassResponsibility'
+	log: 'HALT: ', message.
+	halt
+)
+info: message = (
 
-trackedHistorian: otherHistorian = (
+	log: 'INFO: ', message.
+)
+log: message = (
 
-
+	"logMonitor critical: [
+		logCounter:: logCounter + 1.
+		Transcript cr; show: '[', logCounter asString, ' | ', Time now asString, ']', message.]."
+)
+log: message around: block = (
 
-trackedHistorianifPresent: presentBlock ifAbsent: absentBlock ifError: errorBlock = (
+	| result |
+	log: '[BEGIN]', message.
+	result:: block value.
+	log: '[END]', message.
+	^ result
+)
+warn: message = (
 
-
+	log: 'WARNING: ', message
+))'accessing'
+sourceMirrors = (
 
-'accessing'
+	^ importedSourceMirrors
+)'actions'
+forkAndRemember: block = (
 
-canMergeWith: otherVersion = (
+	[
+		| process |
+		process:: Processor activeProcess.
+		processes add: process.
+		block ensure: [processes remove: process]] fork
+)
+shutdown = (
 
-
-
-)'accessing'
-
-Stream = (
-
-
-
-SuperHistorian = (
-
-
-
-historianNamed: name versionId: versionId = (
-
-
-
-logStream = (
-
-
-
-remoteRepositoryAt: repositoryId = (
-
-
-
-versionAtInternalId: internalId = (
-
-
-
-'actions'
-
-exportVersionId: internalId to: remoteRepository = (
-
-
-
-importVersionId: internalId from: remoteRepository = (
-
-
-
-refresh = (
-
-
-
-'subclassResponsibility'
-
-RepositoryVersionAccessing = (
-
-
-
-create = (
-
-
-
-imageHistorian = (
-
-
-
-remoteRepositories = (
-
-
-
-)
-
-
-
-class AbstractRepository onRepositoryId: rid = (|
-    private repositoryId = rid.
-	protected cachedCommand
-|)
-
-(
-
-
-
-class AbstractCommand = (|
-	cachedLauncher
-|)
-
-(
-
-
-
-class Launcher = (|
-cachedExternalLauncher
-command
-
-|)
-
-('actions'
-
-noDefaultArgumentsRun: arguments = (
-
-
-
-run: arguments = (
-
-
-
-run: arguments ifFail: failBlock= (
-
-
-
-run: arguments ifSuccess: successBlock ifFailure: failureBlock = (
-
-
-
-runLines: arguments = (
-
-
-
-runLines: arguments ifFail: failBlock = (
-
-
-
-runStream: arguments = (
-
-
-
-'accessing'
-
-externalLauncher = (
-
-
-
-)'testing'
-
-isFilenameIgnored: filename = (
-
-
-
-'subclassResponsibility'
-
-commandLine = (
-
-
-
-defaultArguments = (
-
-
-
-'accessing'
-
-ignoredFilename = (
-
-
-
-launcher = (
-
-
-
-'actions'
-
-writeStream: stream toFileNamed: filename = (
-
-
-
-)
-
-
-
-class AbstractHistorian named: historianName = (|
-
-	public name = historianName.
-|)
-
-(
-
-
-
-class AbstractHistorianChange onVersion: v = ("Encapsulates the action of committing a new version"|
-
-newVersion = v.
-|)
-
-('accessing'
-
-changedMirrors = (
-
-
-
-deletedOriginalMirrors = (
-
-
-
-historian = (
-
-
-
-'private'
-
-zippedMirrors = (
-
-
-
-'actions'
-
-commit = (
-
-
-
-)'accessing'
-
-hash = (
-
-
-
-historian = (
-
-
-
-repository = (
-
-
-
-versionsIncomingFrom: otherHistorian = (
-
-
-
-'subclassResponsibility'
-
-HistorianChange = (
-
-
-
-createIfFail: failBlock = (
-
-
-
-makeCurrentHistorian = (
-
-
-
-version = (
-
-
-
-'actions'
-
-commit: v = (
-
-
-
-loadIntoImage = (
-
-
-
-'testing'
-
-= other = (
-
-
-
-canForwardTo: otherVersion = (
-
-
-
-)'accessing'
-
-command = (
-
-
-
-hash = (
-
-
-
-historianNamed: historianName ifFail: failBlock = (
-
-
-
-repository = (
-
-
-
-'subclassResponsibility'
-
-Historian = (
-
-
-
-clone: repositoryLocation = (
-
-
-
-historianNamed: name versionId: versionId = (
-
-
-
-historians = (
-
-
-
-logStream = (
-
-
-
-repositoryType = (
-
-
-
-'actions'
-
-createNewVersion = (
-
-
-
-newHistorianNamed: historianName setTo: initialVersion ifFail: failBlock = (
-
-
-
-newHistorianNamed: historianName trackingHistorian: trackedHistorian setTo: initialVersion ifFail: failBlock = (
-
-
-
-'testing'
-
-= other = (
-
-
-
-)
-
-
-
-class NewVersion = Version (
-"A version that has not yet been committed."|
-	parents
-	mirrors
-	message
-|)
-
-('accessing'
-
-hash = (
-
-
-
-'testing'
-
-= other = (
-
-
-
-commonAncestorWith: version = (
-
-
-
-)'accessing'
-
-sourceMirrors = (
-
-
-
-'subclassResponsibility'
-
-LocalRepository = (
-
-
-
-RemoteRepository = (
-
-
-
-)'accessing'
-
-sourceMirrors = (
-
-
-
-'actions'
-
-forkAndRemember: block = (
-
-
-
-shutdown = (
-
-
-
-)
+	"Might currently be called multiple times"
+	"Don't shut down the mirror loader for now, as we're reinstantiating VCS without doing so for the SourceMirrors"
+))

VCSMercurialBackendProvider.ns3

 mergeIfNeeded = (
 
 	1 = newVersion parents size ifFalse: [ | mergeSource |
-		mergeSource:: newVersion parents detect: [:each | each ~= historian version].
+		mergeSource:: newVersion parents detect: [:each | (each = historian version) not].
 		command merge: mergeSource internalId].
 )
 withoutActivationCommit = (
 bb1.prefex=',url,'
 bb1.password=',password,'
 bb1.username=',username,'
+[hostfingerprints]
+bitbucket.org=81:2b:08:90:dc:d3:71:ee:e0:7c:b4:75:ce:9b:6c:48:94:56:a1:fe
 [newspeak]
 current_historian=main
 [newspeak_tracking_historian]
 	refreshSCAfter: [subject loadIntoImage]
 )))
 class SourceControlSubject onModel: model = Subject onModel: model (|
-title = 'New Source Control'.
+title = 'MemoryHole'.
 	mergingUI = MergingUI new.
 	
 	
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.