Giter Site home page Giter Site logo

gt4gemstone-old's Introduction

gt4gemstone Build Status

gt4gemstone is the Glamorous Toolkit for remote work with Gemstone/S. It is a project developed by feenk.com.

Installation

The gt4gemstone tools require code to be installed both on the client and on the server images. To create a new client containing the latest version, after installing GsDevKit, do the following from the $GS_HOME folder:

cd $GS_HOME/shared/repos
git clone https://github.com/feenkcom/gt4gemstone.git
createClient -t pharo Gt4Gemstone -l -v Pharo5.0 -s gs_333 -z $GS_HOME/shared/repos/gt4gemstone/.smalltalk.ston
startClient Gt4Gemstone -s Gt4Gemstone

For creating a new stone containing the latest version use:

createStone -u http://ws.stfx.eu/4TIV0I28KZ6O?format=text -i Gt4Gemstone -l Gt4Gemstone Gt4Gemstone 3.3.3

For installing gt4gemstone in a stone that has GsDevKit installed see gt4gemstone server instalation using GsDevKit.

For installing gt4gemstone in a stone doesn't have GsDevKit see gt4gemstone server instalation without GsDevKit.

For installing and configuring GsDevKit on Windows see GsDevKit Windows Installation.

Once you installed gt4gemstone you can take at a look at some examples of how to use a gemstone client.

Connecting to a stone

gt4gemstone comes with a session manager that can be opened from the World menu. This manager allows you to create connections to stones based on session descriptions. By default it uses the session descriptions present in the GsDevKit installation.

Remote Playground

A remote Pharo Playgrond that works on a remote stone is created using the context menu of a selected session. This playground has a distinct blue border and provides actions for executing and inspecting code remotely.

Alternatively opening a Pharo Playground can be achived using the following API:

gtClient := GtGsMinimalClient forDefaultSessionDescription.
gsPlayground := (GtGsPlayground forGemstoneClient: gtClient).
gsPlayground openEmpty.

Inspecting objects

gt4gemstone further comes with a moldable inspector that allows you to inspect objects using multiple presentations.

Debugger & Editor

Custom object view

gt4gemstone uses GTInspector and allows every object to have multiple views. A similar API can be used to create views for Pharo and GemStone objects. For example, an AddressBook object can have a view to show the list of contacts from the address book. The following code creates this view both for an AddressBook object stored either in Pharo or GemStone:

gtGsInspectorAContactsOn: aComposite
   <gtInspectorPresentationOrder: 5>

   aComposite table
      title: 'Contacts';
      display: [ self contacts ];
      column: 'Name' evaluated: [ :aContact | 
         aContact fullName ] width: 150;
      column: 'Telephone' evaluated: [ :aContact | 
         aContact address telephone fullNumber ]

The first screenshot shows this view on an instance of an AddressBook object stored in GemStone and the second on an instance from Pharo:

Utility scripts

Updating the code of gt4gemstone in a Gemstone stone:

gtClient := GtGsMinimalClient forSessionDescriptionNamed: SCIGemStoneServerConfigSpec defaultSessionName.
gtClient evaluateCommandStream: 'project load Gt4Gemstone' readStream .
gtClient evaluateCommandStream: 'commit' readStream.

Evaluating and inspecting a remote command:

gtClient performStringRemotelyAndInspect: '40+2'.

gt4gemstone-old's People

Contributors

chisandrei avatar dalehenrich avatar girba avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gt4gemstone-old's Issues

There should be only one annotation for inspector extensions

Right now, we have two extensions, one for Pharo one for GS. We should only have the default one that works in Pharo. For presentations that are specific only to GS we can use a gtForGS: method.

 gtContactsOn: aComposite
   <gtInspectorPresentationOrder: 5>
   <gtGsInspectorPresentationOrder: 5>
   aComposite table
    title: 'Contacts';
    display: [ self contacts ];
    column: 'Name' evaluated: [ :aContact | aContact fullName ];
    column: 'Telephone' evaluated: [ :aContact | 
        aContact address telephone fullNumber ]

Only populate the details of the active presentation

Currently, the details of all presentations are serialized.

We should only send the details of the active presentation. When selecting another presentation, the cache logic would know how to retrieve the extra data.

Better mechanism for detecting which windows to close on logout

Currently #closeAllRemoteWindows hardcodes a list with all types of tools that will be closed when the gemstone client is closed. This includes tools like the debugger or inspector. As the number of tools used to interact with a remote session is increasing a better mechanism based on annotations is needed: add an annotation to all glamour browsers that support remote interactions.

Create GS code presentation

We need a dedicated GLMGemstoneCodePresentation that knows how to deal with remote execution. This should be added at the level of Glamour.

Remote actions

We need a concept for defining and executing remote actions from a presentation.

Likely, the actions will be defined through a message like gsAct: ... and this will inform the Gemstone "presentation" to serialize the result of the block. We need to experiment here with how to allow Gemstone to access the ports of the inspector panes.

How do I get a full printString in eval pane of debugger?

I evaluate the following in the eval pane:

self indexSpec

and I get the following printed:

GsIndexSpec new
	equalityIndex: 'each.theSmallInteger'
		lastElementClass: SmallInteger;
	identityIndex: 'each.theSmallInteger';
	equalityIndex: 'each.c2.theCharacter'
		lastElementClass: Character
		...

but I am interested in the full string ... inspecting the result of self indexSpec gives me the same truncated string ...

I guess if I inspect the result of self indexSpec printString, I get the full string:

GsIndexSpec new
	equalityIndex: 'each.theSmallInteger'
		lastElementClass: SmallInteger;
	identityIndex: 'each.theSmallInteger';
	equalityIndex: 'each.c2.theCharacter'
		lastElementClass: Character
		options: GsIndexOptions optimizedComparison;
	identityIndex: 'each.c2.theCharacter';
	equalityIndex: 'each.c2.theSizeArray'
		lastElementClass: SizeArray;
	identityIndex: 'each.c2.theSizeArray';
	equalityIndex: 'each.c2.c3.theNumber'
		lastElementClass: Number;
	identityIndex: 'each.c2.c3.theNumber';
	equalityIndex: 'each.c2.c3.theSmallDouble'
		lastElementClass: SmallDouble;
	identityIndex: 'each.c2.c3.theSmallDouble';
	equalityIndex: 'each.c2.c3.c4.theBoolean'
		lastElementClass: Boolean;
	identityIndex: 'each.c2.c3.c4.theBoolean';
	equalityIndex: 'each.c2.c3.c4.theScaledDecimal'
		lastElementClass: ScaledDecimal
		options: GsIndexOptions optimizedComparison;
	identityIndex: 'each.c2.c3.c4.theScaledDecimal';
	equalityIndex: 'each.c2.c3.c4.theDecimalFloat'
		lastElementClass: DecimalFloat;
	identityIndex: 'each.c2.c3.c4.theDecimalFloat';
	equalityIndex: 'each.c2.c3.c4.c5.theUndefinedObject'
		lastElementClass: UndefinedObject;
	identityIndex: 'each.c2.c3.c4.c5.theUndefinedObject';
	equalityIndex: 'each.c2.c3.c4.c5.theAbstractCharacter'
		lastElementClass: AbstractCharacter
		options: GsIndexOptions optimizedComparison;
	identityIndex: 'each.c2.c3.c4.c5.theAbstractCharacter';
	equalityIndex: 'each.c2.c3.c4.c5.c6.theJISCharacter'
		lastElementClass: JISCharacter
		options: GsIndexOptions optimizedComparison;
	identityIndex: 'each.c2.c3.c4.c5.c6.theJISCharacter';
	equalityIndex: 'each.c2.c3.c4.c5.c6.theFraction'
		lastElementClass: Fraction
		options: GsIndexOptions optimizedComparison;
	identityIndex: 'each.c2.c3.c4.c5.c6.theFraction';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.theDateTime'
		lastElementClass: DateTime
		options: GsIndexOptions optimizedComparison;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.theDateTime';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.theTime'
		lastElementClass: Time
		options: GsIndexOptions optimizedComparison;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.theTime';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.theString'
		lastElementClass: String;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.theString';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.theDate'
		lastElementClass: Date
		options: GsIndexOptions optimizedComparison;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.theDate';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.theInteger'
		lastElementClass: Integer;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.theInteger';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.theCharacterCollection'
		lastElementClass: CharacterCollection;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.theCharacterCollection';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.theBinaryFloat'
		lastElementClass: BinaryFloat;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.theBinaryFloat';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.theInvariantString'
		lastElementClass: InvariantString;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.theInvariantString';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.theSmallFloat'
		lastElementClass: SmallFloat;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.theSmallFloat';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.theDoubleByteSymbol'
		lastElementClass: DoubleByteSymbol;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.theDoubleByteSymbol';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.theDoubleByteString'
		lastElementClass: DoubleByteString;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.theDoubleByteString';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.theIndexableByteArray'
		lastElementClass: IndexableByteArray;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.theIndexableByteArray';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.theFloat'
		lastElementClass: Float;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.theFloat';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.theSymbol'
		lastElementClass: Symbol;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.theSymbol';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.theQuadByteString'
		lastElementClass: QuadByteString;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.theQuadByteString';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.theLargeInteger'
		lastElementClass: LargeInteger;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.theLargeInteger';
	equalityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.theQuadByteSymbol'
		lastElementClass: QuadByteSymbol;
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.theQuadByteSymbol';
	unicodeIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.c15.theUnicode7'
		collator: (IcuCollator forLocaleNamed: 'en_US');
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.c15.theUnicode7';
	unicodeIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.c15.theUnicode16'
		collator: (IcuCollator forLocaleNamed: 'en_US');
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.c15.theUnicode16';
	unicodeIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.c15.theUnicode32'
		collator: (IcuCollator forLocaleNamed: 'en_US');
	identityIndex: 'each.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11.c12.c13.c14.c15.theUnicode32';
	yourself.

but there should be an easier ... more obvious way ... I looked on the menu and didn't see anything useful ...

Add a playground to each inspector pane

Right now, we only serialize basic presentations. For the playground in each inspector pane, we can either rely on this and add a separate tab, or make it like in the Pharo inspector. In the latter case, we need to serialize a Tabulator.

Walkback on `proceed` in debugger ... debugger came up because of a `self halt`...

UndefinedObject(Object)>>doesNotUnderstand: #selectedCodeRangeForContext:
[ :code | 
code
	selectionInterval:
		(aDebugger session
			selectedCodeRangeForContext: aDebugger currentContext) ] in GtGsDebuggerStackFrame>>methodCodeIn:forDebugger: in Block: [ :code | ...
GLMPharoMethodPresentation(GLMPresentation)>>initializePresentation
[ :each | each initializePresentation ] in GLMCompositePresentation>>initializePresentation in Block: [ :each | each initializePresentation ]
OrderedCollection>>do:
GLMCompositePresentation>>do:
GLMCompositePresentation>>initializePresentation
[ presentations pane: nil.
presentations resetAnnouncer.
aCompositePresentation pane: self.
presentations := aCompositePresentation.
presentations initializePresentation ] in GLMPane>>presentations: in Block: [ presentations pane: nil....
GLMPane>>notingPresentationChangeDo:
GLMPane>>presentations:
[ self transmission destination pane clearIn: aContext.
self transmission destination pane
	presentations: self presentations copy ] in GLMReplacePresentationsStrategy>>transmitIn: in Block: [ self transmission destination pane clearIn: aCon...etc...
GLMPane>>notingPresentationChangeDo:
GLMReplacePresentationsStrategy>>transmitIn:
[ self transmissionStrategy transmitIn: aContext.
self destination receive: self in: aContext ] in GLMTransmission>>transmitIn: in Block: [ self transmissionStrategy transmitIn: aContext....
GLMPane>>notingPresentationChangeDo:
GLMPanePort(GLMBoundPort)>>notingPresentationChangeDo:
GLMTransmission>>transmitIn:
[ :each | each transmitIn: aPortEvent transmissionContext copy ] in GLMTabulator(GLMExplicitBrowser)>>innerPortEvent: in Block: [ :each | each transmitIn: aPortEvent transmission...etc...
OrderedCollection>>do:
GLMTabulator(GLMExplicitBrowser)>>innerPortEvent:
GLMPane>>portEvent:
[ self silentValue: anObject.
self pane
	portEvent:
		(GLMPortEvent
			on: self
			previouslyValued: oldValue
			in: aTransmissionContext) ] in GLMPanePort>>changeValueTo:in: in Block: [ self silentValue: anObject....
GLMPane>>notingPresentationChangeDo:
GLMPanePort>>changeValueTo:in:
GLMPanePort>>value:in:
GLMPanePort>>receive:in:
[ self transmissionStrategy transmitIn: aContext.
self destination receive: self in: aContext ] in GLMTransmission>>transmitIn: in Block: [ self transmissionStrategy transmitIn: aContext....
GLMPane>>notingPresentationChangeDo:
GLMPanePort(GLMBoundPort)>>notingPresentationChangeDo:
GLMTransmission>>transmitIn:

Code installer scripts should improved to accept gs sessions parameters as arguments

Code installer scripts in gt4gemstone/bin/utils/ should improved to accept gs sessions parameters as arguments:
-s (default gt4gemstone)
-u (default system)
-p (default swordfish)
-c

The -c argument is the amount of memory in MB that is used by topaz gemstone session and can be passed to topaz with something similar to
topaz -il -C GEM_TEMPOBJ_CACHE_SIZE=${tempObjCacheSize}MB

hangs (hot) when selecting large character string temps in debugger ...

I actually cannot tell how big the string is .. yet, but I assume that it is large, because I ran out of memory in the gem when I first tried selecting auditResult ... I've tried trimming the size to 2000 characters and it still hangs ...

image

I also bumped the temp obj cache to a large size (2G) ... hmmmm now I see that pharo is running hot ...

Remote Playground

We need a Playground that is distinct from the default Pharo one and from which we execute exclusively code remotely on Gemstone.

Debugger should return value when resuming from halt

When the gemstone debugger is opened due to a resumable exception (for example a halt) and proceed is selected, the debugger should return the correct value to the Pharo process. For example, after resuming the debugger, the following code returns nil and not 42:

gtClient performStringRemotely: '
	1 to: 2 do: [ : i | i printString ].
	self halt.
   40 + 2'

Adding instance variable in Gemstone Brower - Produces walkback

When one attempts to add an instance variable to an existing class in a Remote Gemstone Class Browser (ex: Categories Browser), a walkback occurs in the client and the instance variable is not added to the class.

Also, If I try to create a new class by changing the class definition in the browser, a walkback occurs. This probably should be supported as well.

Remote Debugging Fails - GsGciLostSessionError

I attempted to remote debug (from a remote playground) the code below. The remote debugging failed with a GsGciLostSessionError.

OrderedCollection new
add: 1;
add: 2;
yourself

All of the other remote menu options worked.

Server: a Gt4Gemstone 3.3.3 stone - no GsDevKit tools loaded in the server or client.
Client: Pharo 5.0 using the GtGsBareClient.

MessageNotUnderstood: GtGsDebuggerStackFrame>>shortDebugStackOn:

I tried to use copy to clipboard menu item in GemStone debugger (note I had to select a pharo frame to get the menu item --- would be nice to have menu item for gemstone frames as well -- without error :) ) and this error occurred:

GtGsDebuggerStackFrame(Object)>>doesNotUnderstand: #shortDebugStackOn:
[ :s | self debugger interruptedContext shortDebugStackOn: s ] in CopyToClipboardDebugAction>>executeAction in Block: [ :s | self debugger interruptedContext shortDebug...etc...
String class(SequenceableCollection class)>>new:streamContents:
String class(SequenceableCollection class)>>streamContents:
CopyToClipboardDebugAction>>executeAction
CopyToClipboardDebugAction(DebugAction)>>execute
[ self execute ] in CopyToClipboardDebugAction(DebugAction)>>asGlamourAction in Block: [ self execute ]
BlockClosure>>glamourValueWithArgs:
GLMGenericAction(GLMAction)>>actOn:
GLMGenericAction(GLMAction)>>morphicActOn:
[ | selArgCount |
"show cursor in case item opens a new MVC window"
(selArgCount := selector numArgs) = 0
	ifTrue: [ target perform: selector ]
	ifFalse: [ selArgCount = arguments size
			ifTrue: [ target perform: selector withArguments: arguments ]
			ifFalse: [ target perform: selector withArguments: (arguments copyWith: evt) ].
		self showShortcut ].
self changed ] in ToggleMenuItemMorph(MenuItemMorph)>>invokeWithEvent: in Block: [ | selArgCount |...
BlockClosure>>ensure:
CursorWithMask(Cursor)>>showWhile:
ToggleMenuItemMorph(MenuItemMorph)>>invokeWithEvent:
ToggleMenuItemMorph(MenuItemMorph)>>mouseUp:
ToggleMenuItemMorph(MenuItemMorph)>>handleMouseUp:
MouseButtonEvent>>sentTo:
ToggleMenuItemMorph(Morph)>>handleEvent:
MorphicEventDispatcher>>dispatchDefault:with:
MorphicEventDispatcher>>handleMouseUp:
MouseButtonEvent>>sentTo:
[ ^ anEvent sentTo: self ] in MorphicEventDispatcher>>dispatchEvent:with: in Block: [ ^ anEvent sentTo: self ]
BlockClosure>>ensure:
MorphicEventDispatcher>>dispatchEvent:with:
ToggleMenuItemMorph(Morph)>>processEvent:using:
MorphicEventDispatcher>>dispatchDefault:with:
MorphicEventDispatcher>>handleMouseUp:
MouseButtonEvent>>sentTo:
[ ^ anEvent sentTo: self ] in MorphicEventDispatcher>>dispatchEvent:with: in Block: [ ^ anEvent sentTo: self ]
BlockClosure>>ensure:

Columns should be sortable

Currently the columns in a table presentation in the inspector are not sortable. This should be implemented as in the Pharo inspector by adding a sort block when defining a column. This block will be executed on the gemstone side when sorting.

Create session manager

We need a tool that allows us to:

  • view existing sessions
  • create a new session
  • select the active session
  • inspector/playground on the active session

broken instance/class view

pharo5.0 commit a2b75e4:

image

No methods visible for selected class on either Instance or Class side. On class-side only conversions protocol is shown (empty) and on instance-side an empty accessing protocol is show regardless of selected class ...

Prior to opening the category browser, I had opened a SymbolList browser, but didn't click around...

Now that I've opened a SymbolList browser the protocols were working until I hit a walk back:

image

and now I see that GtGsBareClient is on the stack, but I have logged into a stone with tODE included so it probably shouldn't be using the bare client?

Probably need a way to specify whther or not you need a bare client when using the Sessions Handler? Nice to (potentially) be able to open different browsers from Sessions Handler...

State presentation should be fast

Currently the state presentation uses a tree view to display the state of an object. This tree view computes the children for all roots. This can be slow for large objects. The tree view should fetch the children of each element only on expansion.

security error doing senders as non-SystemUser user ...

Logging in as DataCurator or another non-SystemUser user is a common use case. In these cases though, shared globals owned by SystemUser can be problematic unless one either adjusts the permissions on the shared global or puts user-specific globals into UserGlobals (which exists on a per-user basis) or puts user-specific globals into Session Temps ...

In this case it looks like you are already using SessionTemps for the cached class organizer, so it probably makes sense to cache your default GtGsSystemNavigation instance in session temps as well ...

screen shot 2017-05-09 at 6 19 22 am

Introduce a dedicated presentation provider for special classes

The inspector extensions rely on method extensions. However, in Gemstone, core classes require special privileges. To not require the developer to have those privileges, we should introduce a separate mechanism through which to define these extensions for special classes (such as GsNMethod).

session manager doesn't recognize lost session error

kill a gem out from under gt4gemstone and the you get a nice lost session error immediately, but the session manager stubbornly continues to show a logged in session ... attempting to use logout gives you an error, but session manager still shows logged in status:

image

the menu let's you login at this point, so the menu items get updated, it's just the display that is misleading

One object for implementing forwarders

Currently adding a client forwarder to an object requires adding two attributes to an object: one for referencing the forwarder and one for storing the oop of the forwarder. This could be improved through a dedicated class for modeling a forwarder.

missing tool tip over session description menu icon

... didn't realize that I had to click on the icon and was a bit shy about clicking on a button that I didn't know what it would do ... I had to go back to read me to realize that it would produce a session description list ...

Use the three column display for stack frames

The Pharo debugger shows the content of the stack using a table having three columns. The Gemstone debugger uses just a simple list. This should be changed to provide the same three columns as the Pharo debugger.

Could use object `oop` field in inspectors

When doing work with GemStone having the oop of every object immediately available is very useful. The oop gives the developer instance #== confirmation without having to go through any hijinks to arrange to do the object comparison or send the #asOop message ...

Personally I use it constantly.

Unregister remote object on proxy finalization

The unregistration mechanism should have a counter that allows the client to register multiple times on the same instance and only release the remote object when all proxies are gone.

Accessing large collections results in a delay

Accessing large ordered collections is normally fast. However, there's some delay the first time you access it (2-3 seconds) but then moving over the single elements/elements groups and jumping to a an element is lovably fast. The "strange" thing is that if you logout and then login with a new GS session, the initial delay doesn't happen anymore. I don't think it happens so because the collection wasn't loaded in GS's SPC.

customizing Object>>gtGsVariableValuePairsWithSelfIf: for GemStone

I find that I want to add some synthetic fields for GemStone: oop and dependencyList are the two most pressing (see #38), but I am curious as to the best way to extend the method Object>>gtGsVariableValuePairsWithSelfIf: ... it is shared between Pharo and GemStone, so it looks like I need to wrap the GemStone-specific code with a #gtGsIsGemstone call ... but then I wonder how to handle competing additions to this method ... ???

Anyway, I think I can add what I need, but it seems that additional customizations can get a bit difficult to do without having different developers stomping on each other ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.