Re: Strartup list (Squeak-dev Digest, Vol 196, Issue 31 msg 4)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
jas
Reply | Threaded
Open this post in threaded view
|

Re: Strartup list (Squeak-dev Digest, Vol 196, Issue 31 msg 4)

jas

> ------------------------------
>
> Message: 4
> Date: Fri, 26 Apr 2019 13:03:42 -0700
> From: tim Rowledge <[hidden email]>
> To: The general-purpose Squeak developers list
> <[hidden email]>
> Subject: Re: [squeak-dev] Lessons learned from (Re:  Faster fibonacci)
> Message-ID: <[hidden email]>
>
>
>
>
>> On 2019-04-25, at 7:40 PM, tim Rowledge <[hidden email]> wrote:
>>
>>
>> Looking at FileStream class initialise I see
>> Smalltalk
>> addToStartUpList: self after: SecurityManager; "the intent being before: AutoStart"
>> and yet inspecting the startuplist shows that FileStream comes well *after* AutoStart (which in a somewhat convoluted way actually makes ProjectLauncher actually do the startup document reading) and so we got things messed up sometime.
> It seems all we need is to run
> FileStream initialise
> to fix this, at least in a current image.
>
> I'd guess that making sure the order of things in the startup list is correct is something the ReleaseManager ought to be able to do. I would have guessed that it might use SmalltalkImage class>>#initializeStartUpList but can't see a connection in the code right now.
>
> Mind you, that method has a fairly big bug in that it ignores the ordering desires of all the classes involved, which may explain the original problem. We can't simplistically run through the list of classes currently in the startup list and send #initialize to them since any number of them might do much more stuff in those methods, including stuff that could be destructive. We would need to separate out the startup list related code and only run that.
>
> So conceptually,
> a) in all senders of #addToStartUpList* and related methods, split out the startup list part to an agreed method such as #addToStartUpSequence that handles the ordering requirements, if any. A default nul version inObject would be nice.
> b) to rebuild the startup list, take copy of the current list and send each item #addToStartUpSequence
> c) some classes may need to be checked out for where they need to be in the ordering - I see thsat ProcessorScheduler is mentioned particularly in SmalltalkImage class>>#initializeStartUpList and yet its #initialize makes no reference to #addToStartUpList*
> d) use the rebuilt method from ReleaseBuilder
>
> Ideas?

Object class>>systemStartupDependsOnMe

                 "

                             If it does, then override this method

                             to notify yourself of at least one other class

                             whose startup initialization you are
certain you depend on.

                             Something like

                                    self #startupDependsOn:
aClassOrSomeClasses

                                             ; startupDependsOn:
aClassOrSomeClasses2

                 "

             ^self startupDependsOn: #()



Some class>>systemStartupDependsOnMe

             self startupDependsOn: aClassOrSomeClasses

                     ; startupDependsOn: aClassOrSomeClasses2

                     ; ...


At startup, we send #systemStartupDependsOnMe

to all the classes which define it.


We then do a topological sort of the identified dependencies,

and send #initialize or whatever to each class in the resulting list.


If the ordering proves insufficient, we add dependency

corrections as and where they are discovered, and keep adding new ones

until we get a partial ordering that works.


Thereafter, maintenance should be pretty straightforward.


-Jim

Jim Sawyer: [hidden email]


> tim
> --
> tim Rowledge; [hidden email]; http://www.rowledge.org/tim
> Useful random insult:- Lights are on but nobody's home.
>
>
>
>
> ------------------------------
>
> Message: 5
> Date: Fri, 26 Apr 2019 22:03:32 +0200
> From: Nicolas Cellier <[hidden email]>
> To: The general-purpose Squeak developers list
> <[hidden email]>
> Subject: Re: [squeak-dev] Using high res clock in benchmarks
> Message-ID:
> <CAKnRiT6L8RC=6Rb9riUqVX-4cw0Yim+jvztK_my6+12ot0jX=[hidden email]>
> Content-Type: text/plain; charset="utf-8"
>
> Thanks
>
> Le ven. 26 avr. 2019 à 01:15, Levente Uzonyi <[hidden email]> a
> écrit :
>
>> 70ns difference can easily come from cache misses. I think you'd get
>> more consistent results if you compiled a method and ran that instead of
>> compiling a new block for each execution.
>>
>> The first two numbers are larger because the jit kicks in. IIRC no jit for
>> the first run, jitting during the second run. All futher executions use
>> the jitted code.
>>
> Yes, it makes sense
>
>> Also, the "hickups" probably happen because your OS is running other
>> processes as well.
>>
>> IIRC the highResClock primitive uses TSC on Intel CPUs, so it may not be
>> as reliable as you'd expect it to be[1], especially on older CPUs (clock
>> rate depends on CPU frequency, cores' clocks are not synced).
>>
>> Yes, constant rate was the first question that came to my mind.
> But it's not really a problem: having the number of ticks is a good
> information per se, whatever the power saving, it tells how many cycles we
> use
> More problematic is un-synced drifting TSC on multi-core, because diffing
> makes no sense then if ever affinity changes...
> I suggest making it a Preference (inbox).
>
> Normally, the best feature of TSC is that they have very cheap access.
> Unfortunately, t's not that cheap thru the primitive.
> I re-ran today:
>
> [Time utcMicrosecondClock] bench.
>   '20,500,000 per second. 48.7 nanoseconds per run.'
> [Time highResClock] bench.
>   '22,800,000 per second. 43.8 nanoseconds per run.'
>
> and
> (1 to: 200) collect: [:i | Time highResClock - Time highResClock * 1000000
> // Time highResClockTicksPerMillisecond]
>   #(-5479 -203 -45 -41 -36 -39 -38 -38 -41 -41 -39 -42 -41 -41 -41 -41 -39
> -41 -39 -41 -39 -39 -38 -39 -41 -38 -41 -41 -41 -41 -41 -41 -39 -41 -41 -39
> -39 -41 -41 -39 -43 -43 -39 -36 -36 -39 -38 -38 -38 -36 -35 -36 -35 -35 -35
> -35 -35 -36 -36 -35 -35 -35 -36 -35 -36 -35 -35 -36 -35 -35 -35 -35 -36 -35
> -36 -35 -36 -35 -36 -35 -35 -36 -36 -35 -36 -35 -36 -35 -36 -36 -35 -35 -36
> -35 -36 -36 -35 -35 -35 -36 -35 -35 -35 -35 -38 -36 -35 -36 -35 -35 -35 -35
> -35 -36 -36 -35 -35 -35 -36 -35 -36 -36 -35 -36 -35 -35 -35 -35 -36 -35 -36
> -35 -36 -35 -36 -35 -35 -36 -36 -35 -36 -35 -36 -35 -36 -36 -35 -35 -36 -36
> -36 -36 -35 -35 -35 -35 -36 -35 -36 -35 -36 -36 -36 -35 -35 -36 -35 -35 -35
> -36 -36 -35 -35 -35 -36 -35 -36 -36 -35 -36 -35 -35 -35 -35 -36 -35 -36 -35
> -36 -35 -36 -35 -35 -36 -36 -35 -36 -35 -36 -35)
>
> which is somehow consistent
>
> The utcMicrosecondsClock is very poor on windows VM (1 ms resolution).
> So maybe the high res clock can still be an interesting add-on...
>
> Levente
>
> [1] https://en.wikipedia.org/wiki/Time_Stamp_Counter
>
> On Fri, 26 Apr 2019, Nicolas Cellier wrote:
>
>> Huh, in fact it's a bit different...
>>
>> Le jeu. 25 avr. 2019 à 23:28, Nicolas Cellier <
> [hidden email]> a écrit :
>>
>> Le jeu. 25 avr. 2019 à 23:22, Nicolas Cellier <
> [hidden email]> a écrit :
>>        Hi,
>> I recently published a Chronology-Core version for using high resolution
> clock.
>> On my 2.7GHz core i5 MBP (2015) I get this:
>>
>> Time highResClockTicksPerMillisecond
>>
>>   2699824
>> => OK, consistent with 2.7GHz
>>
>> Time highResClock - Time highResClock * 1000000 // Time
> highResClockTicksPerMillisecond.
>>   -578 -563
>> => Huh, invoking a primitive takes that long (500 to 600 nanoseconds)
>>
>>
>>
>> (1 to: 200) collect: [:i | Time highResClock - Time highResClock *
> 1000000 // Time highResClockTicksPerMillisecond].
>>   #(-528 -96 -71 -61 -63 -61 -61 -61 -63 -61 -58 -61 -61 -61 -61 -61 -58
> -58 -61 -57 -61 -58 -63 -61 -61 -61 -61 -61 -61 -63 -61 -61 -61 -61 -61 -61
> -61 -58 -61 -61 -61 -61 -61 -63 -61 -61 -61 -61 -61 -61 -61 -61 -61 -64 -58
>> -63 -61 -58 -61 -58 -61 -61 -61 -57 -61 -61 -58 -61 -61 -61 -58 -61 -61
> -61 -61 -61 -61 -58 -61 -61 -61 -61 -61 -65 -61 -61 -61 -61 -61 -61 -61 -61
> -61 -61 -61 -61 -61 -63 -61 -58 -61 -58 -61 -58 -63 -61 -61 -61 -61 -61 -61
>> -63 -61 -58 -61 -57 -61 -58 -61 -58 -61 -61 -61 -61 -61 -61 -61 -61 -61
> -61 -61 -61 -61 -57 -61 -61 -61 -61 -61 -61 -61 -61 -61 -61 -61 -61 -61 -58
> -61 -61 -61 -61 -61 -61 -61 -61 -61 -61 -63 -61 -63 -61 -58 -61 -57 -61 -61
>> -61 -61 -58 -61 -58 -63 -57 -61 -58 -61 -61 -58 -63 -58 -63 -58 -58 -61
> -61 -61 -61 -63 -61 -58 -61 -58 -61 -61 -61 -61 -57 -61 -58)
>> In fact it's 500ns at first eval (JIT or something), then it's only 60ns.
>>
>>
>>              But I can correct it. Let's try it:
>>
>> [10 factorial] bench.
>>
>>   '14,000,000 per second. 71.2 microseconds per run.'
>> => this is the reference result
>>
>> Huh, I messed up with printing the timing (because I modified benchFor:
> using µsec clock)
>> [10 factorial] bench.
>>   '14,500,000 per second. 69 nanoseconds per run.'
>>
>> [] bench.
>>   '191,000,000 per second. 5.25 nanoseconds per run.'
>>
>> So this is including 5ns for evaluating block + incrementing counter +
> looping...
>> tmp := [].
>> (1 to: 50) collect: [:i || ticks |
>> ticks := Time highResClock.
>> tmp value.
>> Time highResClock - ticks + (Time highResClock - Time highResClock) *
> 1000000 // Time highResClockTicksPerMillisecond].
>>   #(1020 54 14 11 4 4 4 4 2 5 1 2 4 4 2 4 5 2 4 2 2 5 2 2 2 4 4 4 5 4 4 4
> 4 2 5 4 4 4 2 0 5 2 5 4 5 5 4 4 4 4)
>> => it's about 5ns but here we are in the noise of correction (it varies
> between 57 and 63ns as we saw above)
>> That's the limit os single evaluation with µ-bench
>>
>> | tmp |
>> tmp := [10 factorial].
>> (1 to: 200) collect: [:i || ticks |
>> ticks := Time highResClock.
>> tmp value.
>> Time highResClock - ticks + (Time highResClock - Time highResClock) *
> 1000000 // Time highResClockTicksPerMillisecond].
>> | tmp |
>> tmp := [10 factorial].
>> (1 to: 100) collect: [:i || ticks |
>> ticks := Time highResClock.
>> tmp value.
>> Time highResClock - ticks + (Time highResClock - Time highResClock) *
> 1000000 // Time highResClockTicksPerMillisecond].
>>   #(3227 267 212 161 130 125 130 127 127 126 127 126 125 133 124 130 125
> 128 125 130 127 125 126 127 128 127 130 127 130 127 130 124 125 124 125 126
> 124 126 124 131 127 132 125 130 124 130 124 130 126 124 128 126 130 126 130
>> 127 131 126 130 125 124 125 124 127 125 127 125 130 127 133 124 130 125
> 128 127 125 122 130 124 127 126 124 128 124 130 123 130 124 130 126 130 124
> 127 128 127 128 124 130 125 130)
>>   #(1663 208 97 94 96 118 97 94 94 94 96 94 93 93 94 93 94 93 93 94 94 93
> 93 96 93 94 93 94 91 94 93 93 94 93 94 94 93 93 96 94 93 93 94 91 93 93 94
> 93 93 94 94 93 93 94 93 94 91 93 91 77 94 93 94 94 93 93 96 94 93 93 94 91
> 93
>> 93 94 93 93 94 94 93 93 94 93 94 91 93 91 77 77 93 93 77 80 94 80 94 93
> 93 94 91)
>> two regimes again... and not the 70ns of bench this time...
>>
>>
>> (1 to: 10) collect: [:i |
>>      | ticks |
>>      ticks := Time highResClock.
>>      10 factorial.
>>      Time highResClock - ticks +
>>
>> sorry for the extra +, editing code in mail and not doing it is a recipe
> for not validating!
>>            + (Time highResClock - Time highResClock) "correction"
>>      * 1000000 // Time highResClockTicksPerMillisecond "get nanoseconds"].
>>
>>   #(1309 247 88 84 74 69 71 71 71 69)
>> => OK, first runs are a bit long, but we get 70ns per run as the reference
>>
>>   #(1977 191 143 148 142 120 122 122 117 120)
>> => Oups??? Second run gives different results???
>>
>>   #(2239 180 143 143 142 116 117 117 117 114)
>> => and third about the same than second...
>> Any idea how to explain that?
>>
>>
>> If I run 200 times, I sometimes get the two regimes separated by hickups
>>
>>   #(1899 107 142 150 123 124 115 122 117 122 118 120 120 120 120 120 121
> 120 118 120 120 120 120 120 121 120 118 120 120 120 120 120 121 120 118 120
> 120 120 120 120 121 120 118 120 120 123 117 122 117 122 116 122 117 123
>> 117 122 117 122 7950 128 117 122 120 118 9963 87 69 71 69 71 69 69 71 71
> 68 69 72 71 68 69 72 71 68 69 72 71 68 69 69 71 69 71 69 71 69 71 69 71 69
> 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69
>> 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69
> 71 69 71 69 71 72 71 68 69 72 71 68 69 69 71 69 71 69 71 68 69 69 71 69 71
> 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71 69 71
>> 69 71 69 71)
>>
>>
>>
> -------------- next part --------------
> An HTML attachment was scrubbed...
> URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20190426/b7b4a058/attachment-0001.html>
>
> ------------------------------
>
> Message: 6
> Date: Fri, 26 Apr 2019 20:28:04 0000
> From: [hidden email]
> To: [hidden email],
> [hidden email]
> Subject: [squeak-dev] The Trunk: ShoutCore-nice.63.mcz
> Message-ID: <E1hK7S1-0001sh-NS@andreas>
>
> Nicolas Cellier uploaded a new version of ShoutCore to project The Trunk:
> http://source.squeak.org/trunk/ShoutCore-nice.63.mcz
>
> ==================== Summary ====================
>
> Name: ShoutCore-nice.63
> Author: nice
> Time: 7 April 2019, 3:24:31.721529 pm
> UUID: 7440b898-b497-493b-adfa-67aef04e0980
> Ancestors: ShoutCore-eem.62
>
> Attempt to fix highlighting of 1to:-1
>
> I don't see the point of testing the presence of a binary selector character after a colon $:, except maybe the case of assignment :=, so only test that case.
>
> =============== Diff against ShoutCore-eem.62 ===============
>
> Item was changed:
>    ----- Method: SHParserST80>>scanIdentifier (in category 'scan') -----
>    scanIdentifier
>    
>     | c start |
>     start := sourcePosition.
>     [
>     (c := self nextChar) isAlphaNumeric
>     or: [ allowUnderscoreSelectors and: [ c == $_ ] ] ] whileTrue.
> + (c == $: and: [ self peekChar ~= $= ])
> - (c == $: and: [ (self isSelectorCharacter: self peekChar) not ])
>     ifTrue: [ self nextChar ].
>     currentToken := source copyFrom: start to: sourcePosition - 1.
>     currentTokenSourcePosition := start!
>
>
>
> ------------------------------
>
> Message: 7
> Date: Fri, 26 Apr 2019 17:48:33 -0700
> From: tim Rowledge <[hidden email]>
> To: Chris Muller <[hidden email]>, The general-purpose Squeak
> developers list <[hidden email]>
> Subject: Re: [squeak-dev] SqueakMap updating fails to update files
> Message-ID: <[hidden email]>
> Content-Type: text/plain; charset=us-ascii
>
>
> Argh.
>
> I just tried to update SM for the NuScratch package again. I had saved the new version to SqueakSource and released the version. I opened SM and selected the prior version, chose 'Create New Release'. Updated the install code. Added a commit comment. Set my password. Set the version name. Click on Save'. Wait... timeout!
>
> It failed during the SMReleaseBrowser>savePackageRelease: method, trying to do `smClient save: release`. The actual timeout came as a result of the attempt to read the response, which was reported as
> 'HTTP/1.1 302 Moved Temporarily
>
> Server: nginx/1.14.2
>
> Date: Sat, 27 Apr 2019 00:31:21 GMT
>
> Content-Type: text/html
>
> Content-Length: 53
>
> Connection: keep-alive
>
> URI: /account
>
> Location: /account
>
> Set-Cookie: SessionID=B2C7C610EB4946C2; path=/
>
> X-Clacks-Overhead: GNU Terry Pratchett
>
>
>
> Temporarily moved to: <A HREF="/account">/account</A>
> {followed by junk}
>
> Seems different to the last problem I had.
>
> tim
> --
> tim Rowledge; [hidden email]; http://www.rowledge.org/tim
> Success always occurs in private, and failure in full view.
>
>
>
>
> ------------------------------
>
> Message: 8
> Date: Sat, 27 Apr 2019 01:10:51 0000
> From: [hidden email]
> To: [hidden email],
> [hidden email]
> Subject: [squeak-dev] The Trunk: Monticello-cmm.699.mcz
> Message-ID: <E1hKBrh-0005ne-N7@andreas>
>
> Chris Muller uploaded a new version of Monticello to project The Trunk:
> http://source.squeak.org/trunk/Monticello-cmm.699.mcz
>
> ==================== Summary ====================
>
> Name: Monticello-cmm.699
> Author: cmm
> Time: 22 April 2019, 2:33:18.479505 pm
> UUID: de205c9e-af00-4954-9f2a-243d83ac9f1e
> Ancestors: Monticello-nice.695
>
> - Fix revisions of class definitions when there's another PackageInfo defined whose full name is only a prefix of the working copy the selected class belongs to.
> - Check the local package-cache before hitting the server for operations where the ancestral UUID is known, such as diffing from the History list.  Keep its allFileNamesCache up to date.
>
> =============== Diff against Monticello-nice.695 ===============
>
> Item was removed:
> - (PackageInfo named: 'Monticello') preamble: '"Woops, somehow missed the #browseMcMethodRevisions Service."
> - | methodMenuServiceCategory classMenuServiceCategory |
> - methodMenuServiceCategory := ServiceRegistry current serviceWithId: #browserMethodMenu.
> - methodMenuServiceCategory services copy do:
> - [ : each | (#(#browseMcMethodHistory #browseMcMethodOrigin ) includes: each id) ifTrue: [ methodMenuServiceCategory services remove: each ] ].
> - classMenuServiceCategory := ServiceRegistry current serviceWithId: #browserClassMenu.
> - classMenuServiceCategory services copy do:
> - [ : each | (#(#browseMcClassHistory #browseMcClassOrigin ) includes: each id) ifTrue: [ classMenuServiceCategory services remove: each ] ]'!
>
> Item was changed:
>    ----- Method: Class>>packageInfo (in category '*monticello') -----
>    packageInfo
> + ^ (PackageInfo allPackages select: [ : each | each includesClass: self ])
> + ifEmpty: [ nil ]
> + ifNotEmpty:
> + [ : myPackages | "Select the most-qualified match."
> + myPackages detectMax: [ : each | each packageName size ] ]!
> - ^ PackageInfo allPackages
> - detect: [ : each | each includesClass: self ]
> - ifNone: [ nil ]!
>
> Item was removed:
> - ----- Method: MCRepository>>isTrunkBackup (in category 'testing') -----
> - isTrunkBackup
> - ^ false!
>
> Item was changed:
>    ----- Method: MCRepository>>prepareVersionForStorage: (in category 'accessing') -----
>    prepareVersionForStorage: aVersion
>     ^ self alwaysStoreDiffs
>     ifTrue: [aVersion asDiffAgainst:
> + (self withCache closestAncestorVersionFor: aVersion info ifNone: [^ aVersion])]
> - (self closestAncestorVersionFor: aVersion info ifNone: [^ aVersion])]
>     ifFalse: [aVersion]!
>
> Item was added:
> + ----- Method: MCRepository>>withCache (in category 'accessing') -----
> + withCache
> + "Answer the receiver with package-cache in front of it."
> + ^ MCRepositoryGroup with: self!
>
> Item was added:
> + ----- Method: MCRepositoryGroup class>>with: (in category 'instance creation') -----
> + with: aMCRepository
> + ^ self new
> + addRepository: aMCRepository ;
> + yourself!
>
> Item was added:
> + ----- Method: MCRepositoryGroup>>closestAncestorVersionFor:ifNone: (in category 'accessing') -----
> + closestAncestorVersionFor: anAncestry ifNone: errorBlock
> + anAncestry breadthFirstAncestorsDo:
> + [:ancestorInfo |
> + (self versionWithInfo: ancestorInfo) ifNotNil: [:v | ^ v]].
> + ^ errorBlock value!
>
> Item was changed:
>    ----- Method: MCRepositoryGroup>>flushAllFilenames (in category 'private') -----
>    flushAllFilenames
> + self repositories do: [ : each | each flushAllFilenames ]!
> - repositories do: [ : each | each flushAllFilenames ]!
>
> Item was changed:
>    ----- Method: MCRepositoryGroup>>versionWithInfo:ifAbsent: (in category 'repository-api') -----
>    versionWithInfo: aVersionInfo ifAbsent: aBlock
> + self repositories do:
> - repositories do:
>     [ : each | ([each
>     versionWithInfo: aVersionInfo
>     ifAbsent: [ nil ]] on: NetworkError do: [ : err | nil ]) ifNotNil:
>     [ : ver | ^ ver ] ].
>     ^ aBlock value!
>
> Item was added:
> + ----- Method: MCRepositoryGroup>>withCache (in category 'accessing') -----
> + withCache
> + ^ self!
>
> Item was changed:
>    ----- Method: MCVersionNotification>>initializeWithVersion:repository: (in category 'private') -----
>    initializeWithVersion: aVersion repository: aRepository
>     version := aVersion.
>     repository := aRepository.
> + ancestor := repository withCache closestAncestorVersionFor: version info ifNone: [].
> - ancestor := repository closestAncestorVersionFor: version info ifNone: [].
>     changes := ancestor
>     ifNil: [#()]
>     ifNotNil: [(version snapshot patchRelativeToBase: ancestor snapshot) operations sorted]!
>
> Item was changed:
>    ----- Method: MCWorkingCopy>>changesRelativeToRepository: (in category 'operations') -----
> + changesRelativeToRepository: aRepository
> - changesRelativeToRepository: aRepository
>     | ancestorVersion ancestorSnapshot |
> + ancestorVersion := aRepository withCache
> + closestAncestorVersionFor: ancestry
> + ifNone: [ nil ].
> + ancestorSnapshot := ancestorVersion
> + ifNil: [ MCSnapshot empty ]
> + ifNotNil: [ ancestorVersion snapshot ].
> - ancestorVersion := aRepository closestAncestorVersionFor: ancestry ifNone: [].
> - ancestorSnapshot := ancestorVersion ifNil: [MCSnapshot empty] ifNotNil: [ancestorVersion snapshot].
>     ^ package snapshot patchRelativeToBase: ancestorSnapshot!
>
> Item was changed:
>    ----- Method: MCWorkingCopyBrowser>>viewChanges (in category 'actions') -----
>    viewChanges
>     | patch |
>     self canSave ifTrue:
> + [patch := workingCopy changesRelativeToRepository: self repository withCache.
> + patch isNil ifTrue: [ ^self ].
> - [patch := workingCopy changesRelativeToRepository: self repository.
> - patch isNil ifTrue: [^ self].
>     patch isEmpty
>     ifTrue: [ workingCopy modified: false.
>     self inform: 'No changes' ]
>     ifFalse:
>     [ workingCopy modified: true.
>     (MCPatchBrowser forPatch: patch)
>     label: 'Patch Browser: ', workingCopy description;
>     environmentInDisplayingImage: workingCopy environment;
> + show ] ]!
> - show]]!
>
> Item was removed:
> - (PackageInfo named: 'Monticello') postscript: 'MCDefinitionIndex migrateAllInstances'!
>
>
>
> ------------------------------
>
> Message: 9
> Date: Sat, 27 Apr 2019 01:15:27 0000
> From: [hidden email]
> To: [hidden email],
> [hidden email]
> Subject: [squeak-dev] The Trunk: Installer-Core-cmm.431.mcz
> Message-ID: <E1hKBw9-0005rq-5p@andreas>
>
> Chris Muller uploaded a new version of Installer-Core to project The Trunk:
> http://source.squeak.org/trunk/Installer-Core-cmm.431.mcz
>
> ==================== Summary ====================
>
> Name: Installer-Core-cmm.431
> Author: cmm
> Time: 21 April 2019, 7:54:57.789733 pm
> UUID: c241b3df-f0a8-4ed3-b11b-f8975ab292cf
> Ancestors: Installer-Core-tcj.426
>
> Auto-install Metacello if necessary when a Metacello load script is executed.
>
> =============== Diff against Installer-Core-tcj.426 ===============
>
> Item was changed:
>    ----- Method: Installer class>>ensureRecentMetacello (in category 'scripts') -----
>    ensureRecentMetacello
>     "Copied and adapted from https://github.com/Metacello/metacello/blob/master/README.md"
>    
>     | metacello |
>     ((Smalltalk classNamed: #WebClient)
>     ifNil: [ false ]
>     ifNotNil: [ :webClient |
>     [ (webClient httpHead: 'https://github.com') isSuccess ]
>     on: Error
>     do: [ false ] ])
>     ifFalse: [ ^self inform: 'Could not connect to "https://github.com".\\You need an internet connection and SSL support\to install (or update) Metacello.\\Please fix those issues and try again.' translated withCRs ].
>    
> + self isMetacelloInstalled ifFalse: [
> + "Prepare a clean environment for it."
> + Smalltalk globals removeKey: #Metacello.
> - metacello := (Smalltalk classNamed: #Metacello) ifNil: [
>     "Get the Metacello configuration (for Squeak users)"
>     Installer gemsource
>     project: 'metacello';
>     addPackage: 'ConfigurationOfMetacello';
>     install.
>    
>     "Bootstrap Metacello Preview, using mcz files (#'previewBootstrap' symbolic version"
>     ((Smalltalk classNamed: #ConfigurationOfMetacello) project
>     version: #'previewBootstrap') load.
>    
> + metacello := Smalltalk classNamed: #Metacello ].
> - Smalltalk classNamed: #Metacello ].
>    
>     "Now load latest version of Metacello"
>     metacello new
>     baseline: 'Metacello';
>     repository: 'github://Metacello/metacello:master/repository';
>     get.
>     metacello new
>     baseline: 'Metacello';
>     repository: 'github://Metacello/metacello:master/repository';
>     load: #('default' 'Metacello-Help').
>    !
>
> Item was added:
> + ----- Method: Installer class>>installAndOpenGitBrowser (in category 'scripts') -----
> + installAndOpenGitBrowser
> + self installGitInfrastructure.
> + (Smalltalk at: #SquitBrowser) open.!
>
> Item was changed:
>    ----- Method: Installer class>>installGitInfrastructure (in category 'scripts') -----
>    installGitInfrastructure
> + | priorSetting |
> + "for INIFileTest>>#testComplexRead"
> + priorSetting := Scanner allowUnderscoreAsAssignment.
> + Scanner allowUnderscoreAsAssignment: true.
>    
> - self ensureRecentMetacello.
> -
>     (Smalltalk at: #Metacello) new
>      baseline: 'Squot';
>      repository: 'github://hpi-swa/Squot:master/src';
> +  load.
> +
> + Scanner allowUnderscoreAsAssignment: priorSetting
> + !
> -  load.!
>
> Item was added:
> + ----- Method: Installer class>>isMetacelloInstalled (in category 'scripts') -----
> + isMetacelloInstalled
> + "Squeak is shipped with the global #Metacello referring to lightweight MetacelloStub.  After the first message is sent, the latest Metacello is installed, replacing the stub."
> + ^ (Smalltalk at: #Metacello) ~= MetacelloStub!
>
> Item was added:
> + Object subclass: #MetacelloStub
> + instanceVariableNames: ''
> + classVariableNames: ''
> + poolDictionaries: ''
> + category: 'Installer-Core'!
> +
> + !MetacelloStub commentStamp: 'cmm 4/8/2019 14:00' prior: 0!
> + MetacelloStub is a loose reference to the class Metacello in its host repository.  It's kept at both its real name, #MetacelloStub, as well as the name #Metacello.  This is done to allow Squeak to respond to messages sent to Metacello (e.g., as referenced in external installation scripts), without the need to ship with Metacello pre-installed.!
>
> Item was added:
> + ----- Method: MetacelloStub class>>confirmMetacello (in category 'overriding') -----
> + confirmMetacello
> + Installer isMetacelloInstalled ifFalse:
> + [ (UIManager confirm: 'This action requires Metacello, but it''s not installed.  Download and install it now?') ifTrue: [ Installer ensureRecentMetacello ] ]!
>
> Item was added:
> + ----- Method: MetacelloStub class>>doesNotUnderstand: (in category 'overriding') -----
> + doesNotUnderstand: aMessage
> + "Handle any messages sent to Metacello class, too."
> + self confirmMetacello.
> + ^ aMessage sendTo: (Smalltalk classNamed: #Metacello)!
>
> Item was added:
> + ----- Method: MetacelloStub class>>initialize (in category 'initialize-release') -----
> + initialize
> + Smalltalk
> + at: #Metacello
> + ifAbsentPut: [ self ]!
>
> Item was added:
> + ----- Method: MetacelloStub class>>isMetacelloConfig (in category 'overriding') -----
> + isMetacelloConfig
> + "Sent during Metacello's bootstrap initialization to all classes in the system.  Respond false."
> + ^ false!
>
> Item was added:
> + ----- Method: MetacelloStub class>>new (in category 'overriding') -----
> + new
> + self confirmMetacello.
> + ^ (Smalltalk at: #Metacello) new!
>
>
>
> ------------------------------
>
> Message: 10
> Date: Sat, 27 Apr 2019 01:36:12 0000
> From: [hidden email]
> To: [hidden email],
> [hidden email]
> Subject: [squeak-dev] The Trunk: Morphic-cmm.1486.mcz
> Message-ID: <E1hKCGH-00068v-0u@andreas>
>
> Chris Muller uploaded a new version of Morphic to project The Trunk:
> http://source.squeak.org/trunk/Morphic-cmm.1486.mcz
>
> ==================== Summary ====================
>
> Name: Morphic-cmm.1486
> Author: cmm
> Time: 26 April 2019, 8:35:52.194323 pm
> UUID: 94a2f848-a9cf-43a7-a2bb-597457bf319f
> Ancestors: Morphic-mt.1485
>
> - Fix a glitch in #tryInvokeHalo: which could lead to mis-identification of the correct halo target.
> - Update the new Tools menu entry to read "Git Browser".
>
> =============== Diff against Morphic-mt.1485 ===============
>
> Item was changed:
>    ----- Method: PasteUpMorph>>tryInvokeHalo: (in category 'events-processing') -----
>    tryInvokeHalo: aUserInputEvent
>     "Invoke halos around the top-most world container at aUserInputEvent's #position.  If it was already halo'd, zero-in on its next inward component morph at that position.  Holding Shift during the click reverses this traversal order."
>     | stack innermost haloTarget |
>     Preferences noviceMode ifTrue: [ ^ self ].
>     Morph haloForAll ifFalse: [ ^ self ].
>     "the stack is the top-most morph to bottom-most."
>     stack := (self morphsAt: aUserInputEvent position unlocked: true) select:
>     [ : each | each wantsHaloFromClick or: [ each handlesMouseDown: aUserInputEvent ] ].
>     innermost := aUserInputEvent hand halo
>     ifNil: [ stack first ]
>     ifNotNil:
> + [ : existingHalo | (stack copyWithout: existingHalo) "No halos on halos"
> - [ : existingHalo | stack allButFirst "existingHalo is first on the stack, not a target"
>     detect: [ : each | each owner == self ]
>     ifFound:
>     [ : worldContainer | "Is existingHalo's target part of the same worldContainer as the morph clicked?"
>     (existingHalo target withAllOwners includes: worldContainer)
>     ifTrue: [ "same hierarchy, let #transferHalo: continue to handle it for now."  ^self ]
>     ifFalse:
>     [ "different hierarchy, remove + add."
>     aUserInputEvent hand removeHalo.
>     aUserInputEvent shiftPressed
>     ifTrue: [ stack second "first is still the just removed halo" ]
>     ifFalse: [ worldContainer ] ] ]
>     ifNone: [ "existingHalo is on the World, defer to #transferHalo: for now."  ^self ] ].
>     "If modifier key is pressed, start at innermost (the target), otherwise the outermost (direct child of the world (self))."
> + haloTarget := (innermost == self or: [aUserInputEvent shiftPressed])
> - haloTarget  := (innermost == self or: [aUserInputEvent shiftPressed])
>     ifTrue: [ innermost ]
>     ifFalse:
>     [ "Find the outermost owner that wants it."
>     innermost withAllOwners reversed allButFirst
>     detect: [ : each | each wantsHaloFromClick ]
>     ifNone: [ "haloTarget has its own mouseDown handler, don't halo."  ^ self ] ].
>     "Now that we have the haloTarget, show the halo."
>     aUserInputEvent hand
>     newMouseFocus: haloTarget
>     event: aUserInputEvent.
>     haloTarget invokeHaloOrMove: aUserInputEvent.
>     "aUserInputEvent has been consumed, don't let it cause any further side-effects."
>     aUserInputEvent ignore!
>
> Item was changed:
>    ----- Method: TheWorldMainDockingBar>>gitInfrastructureMenuItemOn: (in category 'submenu - tools') -----
>    gitInfrastructureMenuItemOn: menu
>     menu addItem:
>     [ : item | item
> + contents: 'Git Browser' translated ;
> + help: 'Browse repositories on github.com' translated ;
> - contents: 'Git Infrastructure' translated ;
> - help: 'Load tools for accessing github repositories.' translated ;
>     icon: (self colorIcon: Color lightGray) ;
>     target: Installer ;
>     selector: #installGitInfrastructure ]!
>
> Item was changed:
> + (PackageInfo named: 'Morphic') postscript: '"Added Git Browser to Tools menu"
> - (PackageInfo named: 'Morphic') postscript: '"updated Tools menu"
>    TheWorldMainDockingBar updateInstances'!
>
>
>
> ------------------------------
>
> Message: 11
> Date: Sat, 27 Apr 2019 01:42:18 0000
> From: [hidden email]
> To: [hidden email],
> [hidden email]
> Subject: [squeak-dev] The Trunk: Morphic-cmm.1487.mcz
> Message-ID: <E1hKCMB-0006FA-KM@andreas>
>
> Chris Muller uploaded a new version of Morphic to project The Trunk:
> http://source.squeak.org/trunk/Morphic-cmm.1487.mcz
>
> ==================== Summary ====================
>
> Name: Morphic-cmm.1487
> Author: cmm
> Time: 26 April 2019, 8:41:58.231963 pm
> UUID: 8cb25e4c-50bf-40a5-b912-905db496b69f
> Ancestors: Morphic-mt.1485
>
> - Fix revisions of class definitions when there's another PackageInfo defined whose full name is only a prefix of the working copy the selected class belongs to.
> - Check the local package-cache before hitting the server for operations where the ancestral UUID is known, such as diffing from the History list.  Keep its allFileNamesCache up to date.
>
> =============== Diff against Morphic-mt.1485 ===============
>
> Item was changed:
>    ----- Method: PasteUpMorph>>tryInvokeHalo: (in category 'events-processing') -----
>    tryInvokeHalo: aUserInputEvent
>     "Invoke halos around the top-most world container at aUserInputEvent's #position.  If it was already halo'd, zero-in on its next inward component morph at that position.  Holding Shift during the click reverses this traversal order."
>     | stack innermost haloTarget |
>     Preferences noviceMode ifTrue: [ ^ self ].
>     Morph haloForAll ifFalse: [ ^ self ].
>     "the stack is the top-most morph to bottom-most."
>     stack := (self morphsAt: aUserInputEvent position unlocked: true) select:
>     [ : each | each wantsHaloFromClick or: [ each handlesMouseDown: aUserInputEvent ] ].
>     innermost := aUserInputEvent hand halo
>     ifNil: [ stack first ]
>     ifNotNil:
> + [ : existingHalo | (stack copyWithout: existingHalo) "No halos on halos"
> - [ : existingHalo | stack allButFirst "existingHalo is first on the stack, not a target"
>     detect: [ : each | each owner == self ]
>     ifFound:
>     [ : worldContainer | "Is existingHalo's target part of the same worldContainer as the morph clicked?"
>     (existingHalo target withAllOwners includes: worldContainer)
>     ifTrue: [ "same hierarchy, let #transferHalo: continue to handle it for now."  ^self ]
>     ifFalse:
>     [ "different hierarchy, remove + add."
>     aUserInputEvent hand removeHalo.
>     aUserInputEvent shiftPressed
>     ifTrue: [ stack second "first is still the just removed halo" ]
>     ifFalse: [ worldContainer ] ] ]
>     ifNone: [ "existingHalo is on the World, defer to #transferHalo: for now."  ^self ] ].
>     "If modifier key is pressed, start at innermost (the target), otherwise the outermost (direct child of the world (self))."
> + haloTarget := (innermost == self or: [aUserInputEvent shiftPressed])
> - haloTarget  := (innermost == self or: [aUserInputEvent shiftPressed])
>     ifTrue: [ innermost ]
>     ifFalse:
>     [ "Find the outermost owner that wants it."
>     innermost withAllOwners reversed allButFirst
>     detect: [ : each | each wantsHaloFromClick ]
>     ifNone: [ "haloTarget has its own mouseDown handler, don't halo."  ^ self ] ].
>     "Now that we have the haloTarget, show the halo."
>     aUserInputEvent hand
>     newMouseFocus: haloTarget
>     event: aUserInputEvent.
>     haloTarget invokeHaloOrMove: aUserInputEvent.
>     "aUserInputEvent has been consumed, don't let it cause any further side-effects."
>     aUserInputEvent ignore!
>
> Item was changed:
>    ----- Method: TheWorldMainDockingBar>>gitInfrastructureMenuItemOn: (in category 'submenu - tools') -----
>    gitInfrastructureMenuItemOn: menu
>     menu addItem:
>     [ : item | item
> + contents: 'Git Browser' translated ;
> + help: 'Browse repositories on github.com' translated ;
> - contents: 'Git Infrastructure' translated ;
> - help: 'Load tools for accessing github repositories.' translated ;
>     icon: (self colorIcon: Color lightGray) ;
>     target: Installer ;
> + selector: #installAndOpenGitBrowser ]!
> - selector: #installGitInfrastructure ]!
>
> Item was changed:
> + (PackageInfo named: 'Morphic') postscript: '"Added Git Browser to Tools menu"
> - (PackageInfo named: 'Morphic') postscript: '"updated Tools menu"
>    TheWorldMainDockingBar updateInstances'!
>
>
>
> ------------------------------
>
> Message: 12
> Date: Fri, 26 Apr 2019 20:46:17 -0500
> From: Chris Muller <[hidden email]>
> To: squeak dev <[hidden email]>
> Cc: [hidden email]
> Subject: Re: [squeak-dev] The Trunk: Morphic-cmm.1486.mcz
> Message-ID:
> <CANzdToFSde7p+ZHnxQvFn3vyNcbE=[hidden email]>
> Content-Type: text/plain; charset="UTF-8"
>
> Just replaced this by 1487, which actually _opens_ the Git Browser,
> instead of only installsGitInfrastructure.
>
> On Fri, Apr 26, 2019 at 8:36 PM <[hidden email]> wrote:
>> Chris Muller uploaded a new version of Morphic to project The Trunk:
>> http://source.squeak.org/trunk/Morphic-cmm.1486.mcz
>>
>> ==================== Summary ====================
>>
>> Name: Morphic-cmm.1486
>> Author: cmm
>> Time: 26 April 2019, 8:35:52.194323 pm
>> UUID: 94a2f848-a9cf-43a7-a2bb-597457bf319f
>> Ancestors: Morphic-mt.1485
>>
>> - Fix a glitch in #tryInvokeHalo: which could lead to mis-identification of the correct halo target.
>> - Update the new Tools menu entry to read "Git Browser".
>>
>> =============== Diff against Morphic-mt.1485 ===============
>>
>> Item was changed:
>>    ----- Method: PasteUpMorph>>tryInvokeHalo: (in category 'events-processing') -----
>>    tryInvokeHalo: aUserInputEvent
>>          "Invoke halos around the top-most world container at aUserInputEvent's #position.  If it was already halo'd, zero-in on its next inward component morph at that position.  Holding Shift during the click reverses this traversal order."
>>          | stack innermost haloTarget |
>>          Preferences noviceMode ifTrue: [ ^ self ].
>>          Morph haloForAll ifFalse: [ ^ self ].
>>          "the stack is the top-most morph to bottom-most."
>>          stack := (self morphsAt: aUserInputEvent position unlocked: true) select:
>>                  [ : each | each wantsHaloFromClick or: [ each handlesMouseDown: aUserInputEvent ] ].
>>          innermost := aUserInputEvent hand halo
>>                  ifNil: [ stack first ]
>>                  ifNotNil:
>> +                       [ : existingHalo | (stack copyWithout: existingHalo) "No halos on halos"
>> -                       [ : existingHalo | stack allButFirst "existingHalo is first on the stack, not a target"
>>                                  detect: [ : each | each owner == self ]
>>                                  ifFound:
>>                                          [ : worldContainer | "Is existingHalo's target part of the same worldContainer as the morph clicked?"
>>                                          (existingHalo target withAllOwners includes: worldContainer)
>>                                                  ifTrue: [ "same hierarchy, let #transferHalo: continue to handle it for now."  ^self ]
>>                                                  ifFalse:
>>                                                          [ "different hierarchy, remove + add."
>>                                                          aUserInputEvent hand removeHalo.
>>                                                          aUserInputEvent shiftPressed
>>                                                                  ifTrue: [ stack second "first is still the just removed halo" ]
>>                                                                  ifFalse: [ worldContainer ] ] ]
>>                                  ifNone: [ "existingHalo is on the World, defer to #transferHalo: for now."  ^self ] ].
>>          "If modifier key is pressed, start at innermost (the target), otherwise the outermost (direct child of the world (self))."
>> +       haloTarget := (innermost == self or: [aUserInputEvent shiftPressed])
>> -       haloTarget  := (innermost == self or: [aUserInputEvent shiftPressed])
>>                  ifTrue: [ innermost ]
>>                  ifFalse:
>>                           [ "Find the outermost owner that wants it."
>>                          innermost withAllOwners reversed allButFirst
>>                                  detect: [ : each | each wantsHaloFromClick ]
>>                                  ifNone: [ "haloTarget has its own mouseDown handler, don't halo."  ^ self ] ].
>>          "Now that we have the haloTarget, show the halo."
>>          aUserInputEvent hand
>>                  newMouseFocus: haloTarget
>>                  event: aUserInputEvent.
>>          haloTarget invokeHaloOrMove: aUserInputEvent.
>>          "aUserInputEvent has been consumed, don't let it cause any further side-effects."
>>          aUserInputEvent ignore!
>>
>> Item was changed:
>>    ----- Method: TheWorldMainDockingBar>>gitInfrastructureMenuItemOn: (in category 'submenu - tools') -----
>>    gitInfrastructureMenuItemOn: menu
>>          menu addItem:
>>                  [ : item | item
>> +                        contents: 'Git Browser' translated ;
>> +                        help: 'Browse repositories on github.com' translated ;
>> -                        contents: 'Git Infrastructure' translated ;
>> -                        help: 'Load tools for accessing github repositories.' translated ;
>>                           icon: (self colorIcon: Color lightGray) ;
>>                           target: Installer ;
>>                           selector: #installGitInfrastructure ]!
>>
>> Item was changed:
>> + (PackageInfo named: 'Morphic') postscript: '"Added Git Browser to Tools menu"
>> - (PackageInfo named: 'Morphic') postscript: '"updated Tools menu"
>>    TheWorldMainDockingBar updateInstances'!
>>
>>
>
> ------------------------------
>
> Subject: Digest Footer
>
> _______________________________________________
> Squeak-dev mailing list
> [hidden email]
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/squeak-dev
>
> ------------------------------
>
> End of Squeak-dev Digest, Vol 196, Issue 31
> *******************************************

---
This email has been checked for viruses by AVG.
https://www.avg.com