Etoys Inbox: Skeleton-Richo.1.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Etoys Inbox: Skeleton-Richo.1.mcz

commits-2
Spam detection software, running on the system "europa.mgmt.inetu.net", has
identified this incoming email as possible spam.  The original message
has been attached to this so you can view it (if it isn't spam) or label
similar future email.  If you have any questions, see
the administrator of that system for details.

Content preview:  Ricardo Moran uploaded a new version of Skeleton to project
   Etoys Inbox: http://source.squeak.org/etoysinbox/Skeleton-Richo.1.mcz ====================
   Summary ==================== Name: Skeleton-Richo.1 Author: Richo Time: 14
   October 2011, 7:52:01 pm UUID: 1e40d535-a560-e247-ba6b-7e2cda5b8ba3 Ancestors:
   [...]

Content analysis details:   (7.4 points, 5.0 required)

 pts rule name              description
---- ---------------------- --------------------------------------------------
 3.5 BAYES_99               BODY: Bayesian spam probability is 99 to 100%
                            [score: 1.0000]
 0.0 MISSING_MID            Missing Message-Id: header
 1.2 INVALID_DATE           Invalid Date: header (not RFC 2822)
 1.0 DATE_IN_PAST_12_24     Date: is 12 to 24 hours before Received: date
 1.7 TVD_FUZZY_SYMBOL       BODY: TVD_FUZZY_SYMBOL
 1.0 FUZZY_AMBIEN           BODY: Attempt to obfuscate words in spam
 0.8 SARE_OBFU_PART_INA     BODY: obfusciation of word containing ina
 3.8 TVD_STOCK1             BODY: TVD_STOCK1
 0.1 RDNS_NONE              Delivered to trusted network by a host with no rDNS
-5.7 AWL                    AWL: From: address is in the auto white-list



Ricardo Moran uploaded a new version of Skeleton to project Etoys Inbox:
http://source.squeak.org/etoysinbox/Skeleton-Richo.1.mcz

==================== Summary ====================

Name: Skeleton-Richo.1
Author: Richo
Time: 14 October 2011, 7:52:01 pm
UUID: 1e40d535-a560-e247-ba6b-7e2cda5b8ba3
Ancestors:

Integrating Skeleton-Base-0.4.1 with a few modifications from me:
* Added SkSheetMorph>>#width: and #height: so that changing the Spreadsheet's extent from the viewer works.
* Added "spreadsheet" viewer category, with a few slots and commands to iterate over the contents of the spreadsheet.
* Added "data i/o" viewer category, which allows you to import/export data from/to csv files. It requires the CSV package, which I'll upload in a separate commit.

==================== Snapshot ====================

SystemOrganization addCategory: #'Skeleton-Base'!
SystemOrganization addCategory: #'Skeleton-Base-Sheet'!

Parser subclass: #SkParser
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkParser class>>pointToA1Name: (in category 'support') -----
pointToA1Name: aPoint
        "(self new pointToA1Name: 1@1) = 'A1'  
        (self new pointToA1Name: 10@10) = 'J10'  
        (self new pointToA1Name: 100@100) = 'CV100'"
        | base i dest remain xPos |
        base _ 26.
        dest _ aPoint x.
        i _ 1.
        xPos _ (String
                                streamContents: [:aStream | [dest > 0]
                                                whileTrue: [remain _ dest \\ (i * base).
                                                        dest _ dest - remain.
                                                        aStream
                                                                nextPut: (Character value: 64 + (remain / i)).
                                                        i _ i * base]]) reverse.
        ^ xPos , aPoint y printString!

----- Method: SkParser>>A1Node:interval: (in category 'error correction') -----
A1Node: proposedVariable interval: spot
        | receiver argument |
        receiver _ encoder
                                encodeVariable: 'holder'
                                sourceRange: spot
                                ifUnknown: [encoder undeclared: proposedVariable].
        argument _ encoder
                                encodeLiteral: (self cellPositionOf: proposedVariable).
        ^ MessageNode new
                receiver: receiver
                selector: #at:
                arguments: (Array with: argument)
                precedence: 3
                from: encoder!

----- Method: SkParser>>cellPositionOf: (in category 'error correction') -----
cellPositionOf: aString
        "(self new cellPositionOf: 'A1') = (1@1)"
        "(self new cellPositionOf: 'B2') = (2@2)"
        "(self new cellPositionOf: 'CV100') = (100@100)"
        | col |
        col _ aString stemAndNumericSuffix first
                                inject: 0
                                into: [:subTotal :next |
                                        subTotal _ subTotal * 26.
                                        subTotal _ subTotal + next asciiValue - $A asciiValue + 1].
        ^ col @ aString stemAndNumericSuffix second asNumber!

----- Method: SkParser>>correctVariable:interval: (in category 'error correction') -----
correctVariable: proposedVariable interval: spot
        | receiver argument |
        (self isA1Name: proposedVariable)
                ifTrue: [^ self A1Node: proposedVariable interval: spot].
        receiver _ encoder
                                encodeVariable: 'holder'
                                sourceRange: spot
                                ifUnknown: [encoder undeclared: proposedVariable].
        argument _ encoder encodeLiteral: proposedVariable.
        ^ MessageNode new
                receiver: receiver
                selector: #findName:
                arguments: (Array with: argument)
                precedence: 3
                from: encoder"^ encoder global: #Moge -> 1 name: #Hoge"!

----- Method: SkParser>>isA1Name: (in category 'testing') -----
isA1Name: aString
        "
        (self new isA1Name: 'A1') = true.
        (self new isA1Name: 'XYZ123') = true.
        (self new isA1Name: '123') = false.
        (self new isA1Name: 'ABC') = false.
        (self new isA1Name: 'Abc') = false.
        (self new isA1Name: 'abc') = false.
        (self new isA1Name: 'Hello12') = false.
        "
        | begin end number |
        begin _ aString indexOfAnyOf: ($A to: $Z) asCharacterSet startingAt: 0.
        begin isZero
                ifTrue: [^ false].
        end _ aString indexOfAnyOf: ($A to: $Z) asCharacterSet complement startingAt: begin.
        end isZero
                ifTrue: [^ false].
        number _ (aString allButFirst: end - 1).
        ^ (number anySatisfy: [:c | c isDigit not]) not!

----- Method: HaloMorph>>endInteraction (in category '*skeleton-base-sheet') -----
endInteraction
        "Clean up after a user interaction with the a halo control"

        | m |
        target endHaloInteraction.
        self isMagicHalo: false. "no longer"
        self magicAlpha: 1.0.
        (target isInWorld not or: [owner isNil]) ifTrue: [^self].
        [target isFlexMorph and: [target hasNoScaleOrRotation]] whileTrue:
                        [m := target firstSubmorph.
                        target removeFlexShell.
                        target := m].
        self isInWorld
                ifTrue:
                        ["make sure handles show in front, even if flex shell added"

                        self comeToFront.
                        self addHandles].
        (self valueOfProperty: #commandInProgress) doIfNotNil:
                        [:cmd |
                        self rememberCommand: cmd.
                        self removeProperty: #commandInProgress]!

----- Method: PhraseTileMorph>>arrowTargets (in category '*skeleton-base-arrow') -----
arrowTargets
        ^ Array with: 'player' -> self actualObject!

----- Method: PasteUpMorph>>createOrResizeTrailsForm (in category '*skeleton-base-pentrail') -----
createOrResizeTrailsForm
        "If necessary, create a new turtleTrailsForm or resize the existing one to fill my bounds. On return, turtleTrailsForm exists and is the correct size."

        | newForm |
        turtleTrailsForm ifNil:
                ["create new TrailsForm if needed"
                turtleTrailsForm _ Form extent: self extent depth: 32.
                turtleTrailsForm fillColor: self color.
                turtlePen _ nil].

        turtleTrailsForm extent = self extent ifFalse:
                ["resize TrailsForm if my size has changed"
                newForm _ Form extent: self extent depth: 32.
                newForm fillColor: self color.
                newForm copy: self bounds from: turtleTrailsForm
                                        to: 0@0 rule: Form paint.
                turtleTrailsForm _ newForm.
                turtlePen _ nil].

        "Recreate Pen for this form"
        turtlePen ifNil: [turtlePen _ Pen newOnForm: turtleTrailsForm.
                                        turtlePen combinationRule: Form blend].!

----- Method: PasteUpMorph>>runStepMethods (in category '*skeleton-base-sheet') -----
runStepMethods
        "dirty hack"
        worldState runStepMethodsIn: self.
        (self valueOfProperty: #SkStepList)
                ifNotNilDo: [:m | m
                                do: [:s | s safetyResolve]]!

ContextVariablesInspector subclass: #SkCellInspector
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkCellInspector class>>holder:key: (in category 'initialize-release') -----
holder: holder key: key
        ^ self new holder: holder key: key!

----- Method: SkCellInspector>>contents (in category 'accessing') -----
contents
        ^ self holder textAt: self key!

----- Method: SkCellInspector>>contents: (in category 'accessing') -----
contents: textOrString
        ^ self holder textAt: self key put: textOrString!

----- Method: SkCellInspector>>holder (in category 'accessing') -----
holder
        ^ object
                ifNotNil: [object tempAt: 1]!

----- Method: SkCellInspector>>holder:key: (in category 'accessing') -----
holder: holder key: key
        | cell context |
        self holder
                ifNotNil: [self holder removeDependent: self].
        holder addDependent: self.
        cell _ holder cellAt: key.
        context _ MethodContext
                                sender: holder
                                receiver: cell
                                method: SkNullCell >> #resolveContextOn:at:
                                arguments: {holder. key}.
        self inspect: context!

----- Method: SkCellInspector>>key (in category 'accessing') -----
key
        ^ object tempAt: 2!

----- Method: SkCellInspector>>update: (in category 'update') -----
update: aSymbol
        self changed: #contents!

PackageInfo subclass: #SkeletonBaseInfo
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkeletonBaseInfo commentStamp: 'tak 4/10/2004 22:24' prior: 0!
This is a spreadsheet package in Skeleton.
To open a spreadsheet, try
SkSheet open.


























-- workspace --

*  package building

SkeletonBaseInfo fileOutSar.
SkeletonConnectorsInfo fileOutSar.

* make change set to current project *
self makeChangeSetForThisPackage

* benchmark
MessageTally spyOn: [1000 timesRepeat: [World runStepMethods]]

* It's useful for debug set/unset when old project is hung.
SkGridMorph>>isDebug

* sound initialize *
self createSoundLibFromWav: 'sound\cas.wav' name: 'cassete'
self createSoundLibFromWav: 'sound\cork.wav' name: 'cork'
self createSoundLibFromWav: 'sound\arrow.wav' name: 'arrow'
self createSoundLibFromWav: 'sound\mochi.wav' name: 'mochi'
self createSoundLibFromWav: 'sound\unstick.wav' name: 'unstick'
self createSoundLibFromWav: 'sound\rice.wav' name: 'rice'

* Initialize
Compiler evaluate: self new postscriptText

* stepping list
(World valueOfProperty: #SkSheet) ifNotNilDo: [:set | set asArray]

* for DEMO
TTCFont newTextStyleFromTTFile: 'C:\WINDOWS\Fonts\verdana.ttf'.
TTCFont newTextStyleFromTTFile: 'C:\WINDOWS\Fonts\pala.ttf'

* debug for Babel
Language subclass: #Romaji   instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Babel-Kernel'.
Romaji compile: 'name
^ #Romaji'!

----- Method: SkeletonBaseInfo class>>addClass:toChangeset: (in category 'fileIn/Out') -----
addClass: aClass toChangeset: aChangeSet
        aChangeSet addClass: aClass.
        aChangeSet commentClass: aClass.
        aClass selectors
                do: [:aSymbol | aChangeSet adoptSelector: aSymbol forClass: aClass].
        aClass class selectors
                do: [:aSymbol | aChangeSet adoptSelector: aSymbol forClass: aClass class].
        ^ aChangeSet!

----- Method: SkeletonBaseInfo class>>addPseudoMethodForBabel (in category 'class initialization') -----
addPseudoMethodForBabel
        "This method supports both 3.6 and 3.7"
        "self addPseudoMethodForBabel"
        | addMethodBlock |
        addMethodBlock _ [:class | class compileInobtrusively:
'translated
        ^ self'
        classified: 'forward compatibility'].
        ['Can you translate?' translated]
                on: MessageNotUnderstood
                do: [:ex | addMethodBlock
                                value: (Smalltalk
                                                at: #AbstractString
                                                ifAbsent: [^ addMethodBlock value: String])]!

----- Method: SkeletonBaseInfo class>>arrow (in category 'sound library') -----
arrow
SampledSound
        addLibrarySoundNamed: 'arrow'
        samples: (self mimeStringToBuffer:
'/WD9a/0g/N78nvx0/Kv9Rv39/qz/gACQAYsCGAIjAfIB9AJeAxgD2AREBGsElgTABOoFHAU9
BU4FPwTpBIMEOwP+A+gEGQRSBDQDrQMcAr4CWwHeAXIBKwEjAUgBRwEFAKQASwAF/6P/C/50
/g792P3D/bL9hP0i/G77efqF+dL5hvmf+fH6Wfrl+6D8P/xr/GL8q/1b/hj+oP8a/9sA3QGy
AfMBnwEdAMcAoQCxARABsgKUA6AEfgTjBL8EPgPcA+EEBgQFA90DfAK9AcMBMgGYAqwDkAPe
A9MDpQM8AqgCXQKuA2YEDQRnBIgEjARwBCUDtAMdAlQBYwBv/6X/Gf6Z/gb9sf3V/gD9pvzD
++b7oPvS++373fva++H75fwL/HD83v0P/S79nP5R/xf/xgA1AG4AjgBe/6/+8f62/v3/RP78
/hn9JfyP/Dz8H/wv/Bb70/vj/HD9Iv1m/Nr7yPq7+cf4sveN9rP2LfXZ9ib3XfkM+sv8dv4D
/5QBFgKFBEoGjwkYC1oMewyjDO0NwA70EF4RhxI4EmkR5hDhD8YOhw0UC8QK3QnxCGAGkAU8
BDEC4gDt/lb70voH+PT4SPd29kb1D/Pj8qDxSu+67fvsOepP6I7nnud559vos+mi6mTrge2s
8KbzvPb9+pj+EgE6BC0GvgkbC80O4hITFQEXTxkKGlsbKBtCGn8ZCBd8FnoWCBWVFJYS4RCC
DbUK6Ag+BZMCsP9W+5r3/PSH8NXtJuom58rl6OUe5bPm0+fQ6L/p/+vl7j3wV/H483r1WvgD
+4b/8gUmCfMNEA6HDuIOUQ08DK8NJQ2ADMkMCgzYD10SLRO2FAoUFhP2E6ATHhIVEHgOQQsK
BwECZPzG9ibvYOmn5d/jvuJV4TjgdOBf4UXjCOWv6UvthfIP9tf8BgGFBkEJkQvXDMUMHQq7
CRUHSwX/BhUIHAriDGIMaQvCCs0KEQnzCikJhAZ7AU78S/nf+yb+zwGaATz+O/rh+O74Vvf8
98b5Ov0XAgIGHAhECLUJZwxOEOwUghUTE3kR4BFZEQgPGQtYB+IGlQbaBhUCjP1s+SP2m/Ry
8P3s3eqJ60rteO5D7RjroOtp7Hns6utC6RbpIuxY8UD1Zvgo+xz/zwZjDVkTVxisHWsgXyD/
IBwe3R4fHhsd3BvxGEkT8Q95CtQFff8e+PP08POv9AD0D/L/8O3uAeql5/TnCed753vmkOaD
6OftAfDD8/T4eP57A5QGeAivDAAQBxOnFsoZRRn7F9UTKA3PCMQDVf1E92PzB/D/8IvwufD0
78rsn+k556/n7ee/5gDkn+XA6RztTfHQ9vL81wNDCZYPdhVsG3EgtiUtKLYqdSo+KNgnFCUH
IlgfBBrwFgEQdgotA0z8vfc/8zvwXO2f6sbodOb35X3i1N883Fvbjdzc34XjV+gx7Tbx4PZW
+2MBwQhtDhAStRY2GDgZQxnpGgoYtxUWD4YJLwL9/QH3MvMA8hLzsfVE9OfzJ/I586r20vkZ
+Hv1OfEM7j7uafFf9gr7UgDIBqYMqBJ8GCMc7yCfJAgnVyoVK9EsFSsKKR8mXCL0H10bfhbn
EZMLgwSM/TT2VfDR7frtru0+6mLlPN942z3ZvNoQ2mjaD9n924re2+Lt5yzr5fE49xP9pASL
CvwQzxZAG1sgHCRHJxcn3SbTJOYi4yEdHz8clhkSFUYSIBCbEA8OJwn2BMT/ifoG8/rtoOdY
4b3dYNpP2LnZQNt73Zveut+04QfiJOL25G7nx+za8an1f/oiAC4FsQivCRoJFgriDfsPfw0E
BqD+svg/9Yj2+ftcAYEIng9xFHYW2ReAGIMaohyGHL4a8Rd8EuMNnwftAeT7tfVU7nbnlOGw
3VXat9m02cLar9yM30fi7OeH7PDzF/nyAVII8BCDF4Uc/CBMIhwjPiNZIc0e6RuYGBQTyw6j
CNACQPtT9F/tGOYS4I3crNoG2E3XQddW2Qzb2t8y4wHm/er/7t/xyvPc9vD8BAHIBtYLihE4
GCEfDCUFKaosFyviKgsn1SYfJT4kpCN6IRcdaxmUFr8UhBFDDDMHQQVSBcsE0gB1+l70re/h
6+npd+kC6VXonOY84ubf7N8I4Rjk5Ojt7XbyrvcF+TD6BvtX/b4AVQJjBDcG6gvZEncXnBjo
FxMUNRG/EBQPFw4pC8cG0//s+HzxMenw4xfduNpE2KrY59nx2sLcB95y4cnlvunA7azyBva+
+7ABQwetDuIWOxyzIoUoUC1PMCowfC9FLcIr/im2Jw0j3CBIHK0YyhRaD0wJoAOd/Rj14e6/
6BbhotvH1yfUPNN91KbW2dmX3L7gOeQC6EDtIPKe+Lr/fAa5DlYWEh0oIo8lmibZJ6soWyhI
JwMkeiE4HboZvRVFEGUKrwSQ/sb5CvNU7lTqZOcu45ffAdq42GjYitpm3DTcpNyW3a7gaORR
6JvsS+7o8T31A/rcAXQHkw1+E70aMCBKJXIpVyvlLT8t5y33LN8qrCf5JMwhPR3fGsoXbhNK
DogKMwc3BMoBB/tU9Rnv9ewe6F7ji94C2WbXAtbA11HXWNZ61W/VWta+2RzcBt9H4kjlJejQ
7V/yFPZ9+rn/YgTeCsgQnRZKG/chhyYiKSUq+CxPLa4vMzACL0MtIyoKJl4iyh+PHE8YrRRh
D3MKVwUG/vL4HPFD6y7mIeGa3OPYMdSn01XUFdWg1xfYhNoE27Td2+B942jmf+nu7eryNfac
+34A4QZSC6oQ9haEHJciiydfKnUrgSszKuIrECttK1Ap5Cc+JFYhmh62G2EXkRMxDgYILAIx
/NL4nfUH8Onskuks5rLk8+Rb5HnkFOK04NLe7tzt2wDaU9tv3WnfauFe44zmVOl47CPuW/Fq
9j378gEPBTIIaQpxC4AMRw1rDxkQVQ+4DQYJtgiLCzcP3BLYEqcQwA+cELUUAxgrGs0aJRbc
E44SxRUmGQobvxs+F4cSbw4QC8gLfQuAClUHrAPG/4z8BPlN9xn03/GU7IvmVODa3hPeK+Bx
5KPpmOzb7KrpyOdy6IvtAfKq9uz35/YM9Cf1Q/o/ASEG/wqdDNwPchNJF6Ma1RwhHE0cdRze
HMkbUhiJFPEQrAw7CHMFHQF4/UX4O/IL62rlzOIE3//f4+HT5Drkd+Gq3b7bvd0P4IXknOkr
7kbzY/gB+7j+Cf8pAIcDUwb8CYkJagc8BTkE2AYvCQYM3xD3FK4XLBd7FZMSaA9dDg0PORG2
E48TshG/DdoJdgaxBj4HCwgRCSEJ3gm4CPgITAe1BqUEyQLnAosEBgXIBgEEFwC//Rn6Bvfa
9iX0fvM98oryFvHs8kzzF/Oc8tLwb+3C7ODu6PLG9dr2H/Oi8FTuZO5L7rvuwO8X8L/y+PQG
8z7xjfCd8bL1DPnD/lICJAW1CIsJdgjLCG0KOg5rExEWBxayFasToBDiDoMOdhEdFMMXhBgn
FncTGA7ECq8IXAg0CSsJXAflBeQEIAGR/VX4XvTd84zyp/DQ7pXsvOuQ6qTpIud05zzpme4W
8vr3E/p1/N79Xfuy+N72cPWc9r748Ppp+oP6LPnx+X/4Y/aw9cD2//oE/Un/4AHbA8IFcwY4
BesFFARTBAsEgQXfB8EJKglhCJAHlAbVBZ4DiAGaAUgCwgTVBsoI5ArgDCQMpgxNC1EKsgsC
C/sM9g1JDI0KcwdFBCwBjP7R/C/6efoC+mz6v/o/+Qn3m/aI9hr2P/cr+NL6FPnM+CH2XPWO
9X71i/YC95D55PuZ+5P5+Pfg9r73e/lf+xz8Rvy+/Dn7Fvpq+xP9Fv/nAuAFAwVWBDMDAgKS
AmYBoACRAI0B1AMXA0MCkwIpAqsDXwNLArQCsAPeBgcIfwqCC7YMhg1HDYkNDQxGC7QL9g1z
D10QCg6PC8oJsgk5CUsITgYFA8UC0wL/Aw4B9v/L/ZT8FPs6+oL5YfgP9zv2y/ZK9av1PvXZ
96/5g/pp+pn6bvoH+ZP5gPoS+uv71fzi/ab92P1q/BT6RvkL+ND5L/lO+LT3o/ZD9Q/1L/bA
+JX6E/ui/Xr/PgDtAp4DkAO6BLIHQgpaDK8OAw9VEasU3hfrGZYZmxlQGaQaEhoYGcYZTxjY
GFkXtxayFRgTHBD3DsMMvwqnB8sEDgAr/Sv7RPms98r1gvL/8Pfvwu737k7tk+yT65vrD+sx
7BntdO8o8Wzz+/Yx94r33fe2+AL5N/sO/Mf91/4i/dP9dv2S/ib+6f+A/7H/k/8s/nj9zP2F
/cz+X/6F/iP99P52/6EBAwHzAn8DSASBBfcHUAg1CMAJWwplC/YNeg5zDzQQKhFUEmoS2xJY
EU8QWg+lDsgNLQrxCNEHFQVtA4gBVv8M/Rn7q/qJ+Y34rvfK9033ufhV+BP3EfYB9Un1AfUK
9Tr1bvW49lT3FveI96L3kfds96X4v/qG/Av8vfzV/K/8hPyO/KH8U/vU++39Df6d/7kAOwBv
ALEBXwJIAtoC9gMNA8kFWgbtB6wHqAdyB2kHUgbdBkgFzAVbBQkEwQQyAygBzwDHAFX/6v8E
/bP8hPwv/Kb9Evzq/Fb7wPsh+iT5AvgI9xf2U/XY9V/01vRh9Bv0MfSN9Of1KfVS9XP1xvaU
9/b5Zvpc+x/8Gf0w/if+zf8b/zX/R/98/6//mv+I//EA4gIlA1QEPwUZBcAF5QWQBScFaAab
B+AIfQizCNsJAAjsCGwH3Ae9CCAIuAjqCEoHRAaQBkQGEQXvBfoF5wV6BNMD0wI1ADn+VPzZ
+/b7a/ql+Tv3OvUh813yBvE68O/wqvAk75vvT+9G74fwNvFB8mHzc/RC9Jr00fWM9yv5l/xM
/skA7QLJBJwGqAjPCtEMfQ3HDv0QTxE3ESEQNA8QDhMNHgvmCjgICAWSAx8Axv53/B/5xfeR
9ab0HPLU8YbwNe7+7cHsn+vt69fsle488IHy+/U49yP5K/uI/j4BaQSsB2wJoQuCDTMO1BBY
EagSxxOfFAYT7hNMEg8QOQ4nDHELVQpzCSMHIwTlAvEBOf9J/N76Rff99f/z6PHH8C7vmO/1
8LjxbPI183/1Wfc3+Jv5r/rF+738hv11/nb+9P8U/7kBHgK2A+EEVgRgBJUFMgXhBiEGBAYF
BfsFgQTMBB4DnANAApQBcgAc/p79WPzD/J38tv0m/av+Jf62/3QAggGwAq8DggQFBDQEWgQ0
AzEBeP++/nH9X/xY+436+PqV+qD61frZ+vD7UvvY/Dj8Gvts+lL5FfhL+EL4yPmZ+mj7GvvN
/HT9AP2Y/j/+yv8W/zr/bv+d/4H/MP8H/yv/b/+4ABMAUwBqAMwB2wN5BRsGEwZYBoUHEwgX
CTYJ7gpQCsILWwvBC4UKsAm7CQYImQf9BsQFbgTJBPoFjQXMBWsFAgUVBWgFcQTpBDYD8AQI
BAQDqQMtAuACpgI/AcIBUwDTAB7/NP5R/bL9b/22/pz/0AEKAhwCzgMsA4UD4wQSBCIEXwTe
BWQF0AYHBa4EjALtAUD/yf7F/iX9bPxN+vf53fmK+hf66Ptf+0f60fpx+nD6hvpB+aj5QPlY
+b76LPp1+pv6//vL/MP94v8sAE0BGQGpAhICZwKxAwMDfwQNBIEE2AT5BKoD6AL+AlYCGAH7
AbIBOQDTAN8BYwHzAiUB7wHAAfkCZAKeAocCSQJHAqoDTAQcBOYFaAXbBmsGzAbJBoMGcwbx
B5AHuwdgBqAFnQRpAwgBkAAO/qf9yP1u/Rb8ZPs8+fj5U/mN+mr7sPzp/Y39pf2Y/b3+Ov8K
AA0BDAHEAisCjwMNA2EDlwPpBD8EqwVUBdgF4AV3BLAD2QNBAskCJAEF/2/90Pxz+136evmO
+G/3EPVn88HydPFs8H3vmu7n7rXu++9l79/wivF88pzzsfSG9Sj2Efe3+dH76f3t/9EBkAN5
BckIRQpYC70Mww2jDksOuw8eD7QQaxDtEWMR/RJHEfURFQ+nDeUMMgq7CYMIbwdaBjoFJQRD
A08Bzv/l/gL8Q/rU+dX5Gfh599P3Mfbq9yL3tviF+UX5vPoG+mn7Evvm/Kv9cv5y/6AAvQFy
AXMA3wAv/7L/b/9D/xL+9P80/+cAqgEUASoBOQGKAisCxAMGA0cD2QRbBFYD4wNjAx4DAAKZ
AZwANv7f/hr+Av4g/g/92f2x/bn98P4d/jH+eP8mABoBCAGvAdcBXwB9/5//C/7x/07/if8C
/dL8fPti+oT5nPjL+Kv5bvp7+xn7LPsi+1r73/x2/Mr86f0B/PD8yPzb/UX9+v7D/1X/sQAL
AIUBEAFvAagCBwKMAw4DQQLnAmcCTgKYAu4C3gJUAcQBZQEXAMAAPP+p/zH+vf6M/t7/Sf+W
ABIAuQEhAQ4A1QDvAUABkAH0AjQCCwGVAOgAGv+D/1r/cv+R/9kAXADCAOoBCwFKAcYCYQKp
ApYCeQJvAosCkwIMASIAT/9p/kD9HPwg+0L6ifnp+Ur4qfgD93P3Pfdi95j3u/fs+GL5O/pZ
+2L7/Pwy/J39vv9BAE0AiABrALUBgwI/AocCiQKJArEC8wLzAocB3AEuANMA8AE1AVABSgF2
Ag0CwgMeAvMCXgHiAfECXwLxA3QDkgOIA9gEcAUBBUQFKAUOBQcE2QSYBDwDkwLVAkcB3QFG
AEj/Ef3n/P78dPvg+rT5APcp9an04fSq9KH0svUM9bj2cPb/92v3yPiM+hP7zf0k/iH+8P/h
AR0CUwM2A7MD5wQrBJ0FFQVwBaIF0QYABfYF0wWyBX4FSwTqBD0DswNFAnABOwAL/z/+5/6g
/jX9rvzo/AH7Yfsu+zn7JfrT+oj6a/qN+uj7Nftm+7D8Ffx5/LD8p/yV/KH8z/0t/ar+Lv6s
/wH/UP//ARcCLALMAuACuwLAAxADiAP0BGUE4wVJBaQGBwZpBsMG9AbuBrkGKwVdBMMETwO0
AtoBsQBT/tb9Mfun+nn5nPj6+D/3RvaW9ln2M/Ya9h32Ofa+98X41PmC+fn6v/wL/Z//MgCc
AeIDNASzBkoHyAkJCgAKmwrhCvYK2Ap5CfUJWAiXB6kGiwVUBAwClADi/y/9v/x++xf5g/gc
9yn2n/Y+9ev1pvVe9U31xPaa96n4+/pL+278iv2s/tL/6ADkAfcDDgPsBJwFLQXGBocHIwd0
B68H8AhVCLIImgg6B9UHQAaPBegFKwRaA5QC/gKbAgkBHQAA/r39rv05/P/8gfvY+1f7Gvrk
+of6N/o9+sj73/0r/i3+u/79/1QABgD3AecCuANdA88EJwSPBPcFSAWYBdAFzQWjBWME+ARe
A54C3wJLAdUBawD/AH7/5v85/o/+F/3D/XP9Mfz1/Nn9NP3i/nH+x/7+/1H//ADLAT0BIwDF
AJQAtQEZAasCLAJzAqUC2wL7AtUCcgItAhoB9QHAAYoBPwD4AK8ASf/m/6D/df9I/vD+jv5F
/eL9dP1A/UP9cP23/er9+v3x/eH91v3P/eb+If5g/qL+9f9M/6P/3P/V/7X/vAAJAHkA4QFc
AfECbQLFAvcC9wLgAswC5gMyAz8C0gIuAZEBBABA/yT+M/2y/Tj8o/wi+938B/yF/OH8+P0f
/Zf+Of7B/xP/KP8n/0n/k//d/+j/rP+K/7QAAABoAM8BDAFNAaEB7QJNAr8DFQNNA3kDtwRC
BRoF/ga7BzEHOgbRBjwFqAT3BCYDUQJoAW8AmP/4/3T+/f6f/kX9w/0T/EL7dPrh+pr6iPqj
+t77OvvC/Ev8nvzL/QL9d/42/wn/wwBcAMAA6wEHAT0BjQHRAdgBowFjATYBIQEPAO0A8gFM
AcoCKAI6AeABSgC5AB7/av7F/lD+HP4f/i3+Af2M/RX8yfyJ/Ev8G/v1+9z7uvt5+0j7cvwW
/QT98/6v/yH/hgBHAS0BuQHwAh4CdQL9A3wDyQPvA/MD1gOlA3EDNwLTAmACFwHNAWEA/gDA
ANABHQFAARYAygCNAF3/3v8I/l799/2g/YH9sv36/j3+pf9hAE0BHQGkAdcB9AI0AoAC5ANZ
A5UDgQMyAsACagJZAnwCmgJvAhYBxwFwAQ4AqAA5/97/r/+f/23+1P4k/b/9df0Y/JP74/tr
+0/7WPtw+2X7W/u+/F386v1i/ar+A/7G/8YAywGRAd8B/QIbAjwCcgJ2AjICEQI3AokC3QLr
AsQClwJmAkECFAHPAaIBdAEJAGL/jf7G/kD91/1u/QP8mvw2+7n7KfrW+u/7Yvv2/Hb86/1P
/Zn+E/7j/9QAtwGNAmoDKQNuA0QDNAOuBHkE5QTgBOsFBwT9BL8EKAN1Ay4DWQOkA7cDQgJP
AR8AFP9//0n/Qv83/vX+v/6t/kD9efzV/IT8d/x4/Ij84/04/Tb9Pf1w/a/+Hf6Z/sX+kP4W
/aL9jv3E/f7+MP54/u7/kwBqAV0CHwJ4Ao0CugMtA8gEagTmBNwEWgPhA5gDXAMiAs8CcQJG
Aj0CDwG1AWwBUwE8AP0ApgBqAGwAggCCAJIAvADGAJoASv/n/3n/CP64/on+Rf4H/fv99v3Y
/aj9cv1t/ab90f2h/QX8Wvwg/F78u/zo/ML8fvx7/Lr86PzM/ID8QPxD/Jz9Ff1q/ZD9pv3m
/nH+6v8J/xn/dwBDAWACdgNCA8EEHASOBQYFVwWkBgUGWgaEBmUGBQXBBfoGxAeoCAIHtAcK
BlgFvwUPBBwDBAIAAU4AygAQ/zD+ev4F/bv9VPyt/Av7ffrs+nP5/vmN+Wf5f/m5+lP7bvy/
/cD+A/23/Xv9rP4y/rP+8/7r/sv+8v+EACwAlQDMAPwBDQDIAEH/4AALALQBQwExAKkAPQA/
AJgA9QEIAKT/4v88/vz/C/86/zn+7/60/q7+tf63/on+M/4x/rP/cgA7ARgCHwM3BBUEpgUV
BXkFzwXxBbsFQgS1BDUD0ANyAvoCYAGxAPEAIf8+/kH9JvwF+vn6MPnj+fX6D/oa+hz6FPoO
+ib6o/u2/Ob9j/2t/ZX9pP4h/v7/+QDPAS0BFwEBATABgAGkAYQBaAGCAZEBXgEaAR8BhQHE
AVgAnwAb/8b/pP+u/3P+4f6C/qD++v8x/yL+8v7Z/ub+5f66/rz/Jv+w//j/xP81/tL+6/89
/3n/mf/GAB0AiQDgAQABAwFIAdQCPwJgAlMCNAISAdoBfgEYALkAcwAy/6P+y/38/U/83fy1
/Jj8Xvws/DH8c/y+/Nb8s/xv/D78WPy//Vf96f4x/kv+ev63/vf/ZQAaANIBGADlALwA+AFs
Ab8B4wIQAl4CowLLAwUDaQO4A7cDcwMQAqcCbwKJArQCoQJkAjkCJgIVAgAByQFiAPoAvwCy
AKwAlACNALkA+wEmARoA3gCyAMAA5gECAPgAl//3/3L/If7b/pj+av5j/o3+xP62/lv9/f28
/Yv9ZP1J/UL9Vf11/Xj9Qfz0/Mz8v/zJ/QD9Uv2j/e3+Mf6E/vX/af/B/+H/zf/WAC8AtgE2
AYgBvAIMAngC7AN1A+wEFQQBA/4EQwShBLgEfQQfA84DlANRAukCPAE+AFL/zP9t/un+J/0x
/GL8B/wA/BH8Cfvd+7f7xvwV/F38T/wu/GP8+P29/nT+/P+EAEMBKwHnAjsChAMJA4MD2QQO
A/MDnwNOAvwCuwKYAnsCcAJ7AlsB5wFoASAA3gB6AAn/eP7G/gr9K/w4+1X6l/pA+kL6OPo0
+lf6ivrK+xb7nPyM/YX+Sf8W//EA0AGlAkQC5QOVA+sD6APLA5EDVwMtAwcC8QLfAs8C6gMn
AzkC8gJ8AhABlwDuACL/X/7T/ov+gv6r/rr+ev4b/dX9y/38/j7+nP8Z/3T/ov/YAD4A2AFN
AWgBcgGfAesCKwIjAhwCeAMIA3sDpgOGA1gDIgLeAp8CJAFbAJ4AAv+L/0X+5P5Y/fD9vP2I
/Pz8FPtj+0r7mPwV/KP9Jf2p/lf/Mv/8AIsA6AEMAREBHQELANoAvwC6AMwBEgFeAXUBbwGK
AbYBoQFOAP4AqQBD//D/0P/qAAn/6f+r/4T/e/+h/9T/v/9b/tT+Uf4J/jj+3/+a//wAC//8
/9r/n/9G/uf+tv6Y/lr+Mf58/00AYAFeAhcCeQJkAfwBqgGkAdQCEQInAfIBcQDbAHoAWQBP
AFMAagCIAKMAtADDANMAwABU/27+R/1f/Qz9Tv3p/mP+YP4O/dH92P34/c39RPzZ/OD9Lv2c
/hz+g/7W/zD/ff/AACUAjgDKAOAA/AFEAa8CGwKIAuIDHQNWA2UDIQLbArkClgJkAiYB2wGA
ARYAzQDLAPABFAEhAQgAzgCGAFwAXwBYAC3/9v+2/1f+2v59/mD+Nv30/dX9nf0a/Jb8TvxR
/H78lvyw/Qf9lv40/q//Gf+gAB8AjwEPAWYBlQIEAroDXwOtA5sDZQM9AykDJgMbAxMDLgNB
AykDAQLNAocCSQH8AYgBLgEfASEA6wBz/8P/Ef6t/q7+4v8C/un+tv6R/mz+M/3t/cT93v4p
/lj+KP3G/aj94v4W/i3+Vf6U/uH/Jv8j/tP+iP53/qv/Fv9g/zH+yv6q/t3/Kf9o/5X/1gBS
AOgBWgGZAc4CJgKQAswCrwJfAioCNQJxAqoCqAJ0AksCUQJlAhkBVwCsAGIAOwAI/5n+p/1h
/G38Kfwi+9L7ivur++X8A/w3/IL8tfzP/Pr9RP2M/cP97v4r/rf/b//mACgAewD0AYkCDgJd
AoYCkgKeAsoC6QLmAucC2AKKAgEBZgD/APMBIAE6AQwAtgB9AGcASwAY/8T/Uf76/tf+s/6Q
/qj+3P79/xP/I/9A/47/3v/4//YAFgB9AOwBDQEVAWYB8AJvArgCzQLBAp8CfwJjAgEBYgEK
ARcBNgFKATUAp//g/5D/vv/g/8D/cP8L/tb+5v7w/sv+fv4U/cj91P4E/hH+CP4B/ff99f4I
/kH+jv67/tf/Cv8z/0n/VP8+/y7/dAAGAIMAnAByAEgAJAANAB0ANAAsABUACAAHAAUAEAAu
AD0AQABAABv/9f/7ABMAQgCIANwBSwGiAdwCRwKlApICFgEsAB7/cv8U/tf+6v9J/9kAZwCg
AIcARwAA//sAcgFdAowDcwN9ApcBMf/K/rT+Jv4n/nL+1v88/3H/cf9F/tj+U/3X/Uj87/0i
/ZL93f3z/c/9iv1D/QH8+f1//mT++/7k/nT+R/6D/rf+vf71/2X/0ABZAQEBawGBAVgBDADx
ASgBcQGSAYcBagFEAPIAaP+l/qj9yP1y/Zz98/4s/jT+Wv7M/zP/Nf7a/nn+k/9VAEEA3QFC
AcMChwObBN8F6wZqBmkGJgXRBXsFOQUMBNcEkgRUBA8DowMWAm8BwgE8ANcAY//w/7f/vf/E
/57/ZP9Y/5D/3QAYADkAMf/9/6z/Pv7G/m3+QP5N/o3+vv7I/rX+gv5d/lr+Uf5P/k/+Of4s
/iH9/P3a/d/+M/7N/0n/pP/+//b/ev8C/uH/Fv9B/x3+6P7I/rH+pv6L/nL+kP68/sD+rP6X
/ob+ZP5J/lj+Y/5f/oj+4f9C/3H/NP7V/rf+vf6r/p7+3P9O/57/1QAVAEgAiQDNAOMA7QEC
AP4A5QCyAGsAKP/v//YASgCtAR8BhQGRAWUBLgDZAH8AKP/I/2r/Jf8s/4P/4wAYACMALwBz
AN0BQQGDAZsBvwIDAk4CowLNAqYCcQJCAh8COQJaAkUCDAGzATwAmP/K/z3/IP9Z//cAoADQ
AJoAQwAQACMAMgAgAA8ABQAOABj//f/k/+sAFwBwAMkA9wDkAH8AF//r/9H/wf+v/4f/fP97
/0z/RP+O/8r/1v/sADIAfwCBADT/7P/R/6v/Yv8s/xf/CP8S/zT/P/8e/tP+gv6D/s//B/8R
/wj++P78/yj/Wv9k/1D/P/88/1L/gv+g/6b/xv/+ACwAXQCfAMwAywC7AK8AqwDHAOoA8wD/
ARAA9wC/AIEARgAtADsAWwB/AI8AigCFAHkAXQA4ABYAFwAzAD0AOAAi/9//jf9O/zD/Sv9u
/1n/JP8Q/zL/Z/90/3b/vgAtAF8AJf+i/zD+8/7R/s3+6/8K/zn/pgBJAO4BiwIkAooCmgJu
AjACFwI7AloCYwKEApUCZAIUAckBrwHXAf8B9AG2AUIApf/r/zf+sP41/aL9Kv0T/W/99/5T
/on+qP6I/jT9y/1d/RX8+v0J/VX9w/4j/nT+vv78/yP/OP9X/4D/rv/mABwAVACLAJ8AgQAy
/9n/0QAVAF0AlQCiAIcAeQBoAD0AEP/a/6f/hf9Y/yz/Jf82/0T/MP8X/y//V/9n/2D/JP7R
/rP+uv7T/wr/Sv+Q/8//2/+5/5T/fv+E/6T/0AADADUAVwBfAFYAUgBYAFMAOAAXABgAMwAx
ABUAJwBpAJUArQDqASsBNwEuAS8BMQEyARIA0wDDAO0BIwFOAVoBUQE8APsAxwD+AXQB1gH/
AecBqwFPANcAlACoANwBDwEhAQgA9gDiAKAASP/h/27/Mf9B/1T/Of8R/vP+vP50/lv+jf7x
/1H/hf+m/8z/yv+K/zf/CP8N/x//Ov97/7n/0v/a/9H/yv/nAAIAFAA6AEcAMQAiABIACP/2
/5n/Ef7F/qr+YP3I/Un9P/14/bv+CP4//lj+Zf5M/i7+S/6L/sL+8v8n/2z/zAA5AJQAuwC3
ALkA3wEFAPMAvACUAHoAdQCUALQAvgC5AL8A+wFQAXYBaQFMAUMBSgEiAPIA+wDfAHEAEP/l
/+P//P/9/+H/3P/yAAIAHQBfAIwAYwAvAD4AiQDzAS4BGgEZAU0BgAGlAbgByAHkAeQBygG0
AaUBqgGkAW8BLgDmAIkAPwAH/+n/8//W/2b+7v6n/qH+wf7i/v7/HP8+/1D/Lv8C/uv+u/6O
/pr+xf78/zL/Zf++ADEAgwCaAIcAdgBoAE0APgA8AEEAaQCFAHQAVAAS/8X/sv+n/33/W/9A
/yX++v6k/kj99/2g/Wz9a/11/XL9bv2R/c/94/3a/cr9nf17/Xn9df17/ZL9nf2z/eL+Df4k
/h7+Df4g/mv+4v9d/7H/3P/8AAj/6P/WABcAfQDPAQYBIQFBAXUBmQGuAcABugHBAfACCwHo
AZEBKwDeAKwAkgCoANEA5ADeAN0A/AEQAOQApABiAAH/sP+s/94AGwBUAIsAzwEmAYMBugGk
AVwBAgCgAFIAKgAVABcALAAY/7//c/9o/27/Z/9o/27/g/+w/8L/tP/B/+P//AAQACwAWQCP
ALQA3AENASIBIwFVAbkB/QIEAgQCEQIiAjYCKgIBAfsCGAIdAeEBSwCZACv/4/+O/1n/YP+I
/8T/+//9/9X/tf+R/0v/D/8A/xP/Wv/PACgAZQC6ARMBSgFnAWcBLwDBAF8AUQCSANkBAQEe
ATcBKQDrALEAkABO/9j/bf84/y//Qf9P/z//KP8V/tj+ff5H/in+Ff41/oD+4f9g/8L/5QAA
ABUADgApAHMAoQCeAJAAmgC9AN0A1ACeAH8AogDEAKUAUP/u/6r/iv9h/xj+zv7U/y3/X/82
/v/+0P6x/rn+1/8e/4j/tf+k/6f/v//uADYAawCiAPkBMgEkAQQA/AEHASgBcQHSAiICMgIF
Ad4BvgFwASAA+wDUAJUAVwBDAHgApQCKAGoAbAB9AIcAcgBqAHQAOf/j/8P/xv/sADkAjwD5
AUgBUwFPATgBBADsAOwA8gEOAPYAfP/6/8T/y//E/43/Yv9p/3v/Yf8i/vf+3/7C/qH+eP5r
/pT+tv7A/sf+m/5w/pv+wf60/rL+rP6P/mr+N/4H/er97/40/oL+uv8W/3T/jv+J/5T/qf+V
/0v/Ov+A/80AKQB0AGYATQBVAEsAVABoADv/5f+M/y7+7/7e/vj/Mf9i/37/if+Y/9EAAv/4
//oAHQAqADcARgAyAAb/z/+O/17/YP+a/+AAAQAIABwAWQCwAOgA7QDUAJUAMf/b/7z/v/+V
/xf+k/5X/kD+Ef3q/gH+OP5o/pb+uv7d/wL/E/81/47/5wAZAB8ADgASABQACwAtAE8AUQB/
AMUA1wDCAKsAwADxAOAAjwBJACAAMgCDAMoA6gD+ARgBGgDGADb/yP+R/3H/Tf8o/yD/Nv9S
/2X/ZP9q/5L/qv+e/5n/nP+e/6r/qP+L/4P/rv/sADcAoAD5AQoA+QD3AQEA/wDiAMgA5gE0
AX4BqwGoAWcA8QBtACkASwCGAIIAXgBPADwAFf/t/9X/zv/F/67/mf95/z7/Ef8I/xz/P/9I
/y7/EP7v/uj/LP+d//8ANQBOAHoAoQCJAEYABP/R/63/iv+L/8sABAAZACcAFP/f/7H/h/9d
/zH+7P61/rT+vv7F/uL+8v7U/qX+hP57/pP+v/72/z//fv+Q/5j/zwAsAG0AiQDHATMBdgFb
AR8BCwEUAQsA8QDhAOwBDgE4AX0B4wIeAfkBrQF4AWsBggGXAXoBJQDMALoA5AEEARUBRgGP
AbYBogF3AUQA+QCsAHkAZQB+ALYA6AEWATIBEQDBAI0AiwB7AEEAFgAUADcAewCzALcAkABt
AHUAoADTAQABDwEWAToBSgE+AT4BQQFDATIA2wBi////rf95/03/Ef7w/vb/E/8x/x3/B/81
/3j/s//Z/8z/xf/j/+j/vv90/yb+8/69/pv+zP8y/6AAAAAjAA7/3/+W/2j/kf/X/+T/w/+6
/8r/1//xAAwAAP/D/2L/H/8S/vr+6P8g/2T/dv+C/6L/uP+n/3T/TP8+/z7/Vf9+/5X/kP+S
/7X/3f/9ABAACP/9AAb//P/f/9H/5QA0AI4AjgBQAB3/+//3////+wAqAIsAtwCjAI8AiQBm
AB7/7//c/5X/K/76/w7/Q/9l/2L/fP/I//r/+v/a/5X/Mv7k/u//M/9Z/4H/4wAS/8//kf+h
/7b/nP+a/9QABQAcAEUAcAB6AGsAQQAOAAQAJQA8ADEAMABTAGgAVAA2ABoAA//7AAUAJwBi
AKUA4QELARkBFgEBANAAkwCUAPsBWgFjAWMBcgFTASsBMgFDARsAuwB1AHMAkAC9AP0BHQDm
AHcASwCBAKIAggBmAGAAeQCqAMEAvAChAGEAHP/j/7f/o/+J/2j/Tf8X/vz/Nv90/5b/t/+3
/6f/nf+A/4f/5wBLAE7/+/+b/03/I/9K/4n/ev8o/tr+z/8J/yr/Hv8e/xj/C/8G/t7+v/7N
/rT+fv6J/sL+3v7T/tH+8P8J/xH/If8m/wj+3P7N/vj/Lf84/0z/j//F/9H/3f/6ABUAKgBD
AFMAWQBsAHoAcQBhAFsAZgB6AHsAaQBdAF0AcgCLAH0AXAB1ANABJAFEAT4BHgDyANwA6QED
APoAygC8ANkA0QCOAEYALgBgAKYAyQDxASgBOgErARMA+ADfAMcAuwDPAPIBAADsALQAegBc
AFYAYgBrAE4AEv/h/83/xP+p/4v/h/90/yf+1f7D/tj+zf6j/o/+qf7g/xz/O/9A/0r/Sv8o
/w//Hv85/0z/Zf+D/5j/uP/i//gABwAwAE4ANv/+/9L/vP+6/+UANgBE/93/Zf87/1z/kf+e
/4r/if+t/9f/0f+c/3D/TP8Y/vn/AP8F/u/+vf6e/s7/Lf97/5b/jP+M/5H/kf+v/90AAQAl
ACoAA//l/9r/zv++/6n/pv++/+EAHAB4ANYBDQD5AN0BDAE7ATcBRgFQARcAygCOAFwAQAAy
ABX/6P/D/7P/pv+b/6P/r/+t/7n/5QAZADEAFP/W/53/ev97/6P/z//b/8//s/+O/5n/7ABB
AFsAWgBeAEoABv/A/6L/mP+g/7v/xv/SAA8AUwBqAGoAbwBvAE4AFf/0/+f/yP+i/4f/ef9/
/3v/bP95/43/ff9Z/0P/Sf9Y/1b/Yv+F/5b/nv+q/63/1QAfAEgAUQBQADkALwBEAEwANwAq
AFYAxQFFAacB2wHTAaUBggGDAaIByAHlAfQB6wHXAdkB4AGyAUEAwgB3AGoAigC/AN4A0wCk
AFcAEwAIADwAjQC2AJwAhgCSAJAAagA4ACQAOwBFADAAMQBJADz/+f/C/94AIgA5AC4AIgAL
/+T/wv+q/3z/U/+E/+H/8//C/5r/q//i/+T/qf99/2j/Y/+B/7D/yv+2/6j/6wAyABn/1v+m
/5T/h/9T/yX/DP7H/pv+yP7m/tv+4P72/yD/Pf89/1r/j/+7//QAFgAE//gAGwBsALUAtACS
AIwAoACuAJoAfQCBAJAAjwCLAJkAsgCiAHUAeQCaAJcAdAAr/9n/wf/L/9L/1//D/7b/2//9
/+T/ov92/4L/k/+V/5//sv/bABoAMwAoAA//1P+h/6X/uf++/7v/v//R/9n/yf+b/1T/HP79
/v7/Tv/DAAUAGwAL/9j/tP+z/7z/xf/YAAwAPgA7AC4AMQAwAEoAggCeAJMAXf/+/6b/gf+c
/+sAPABhADr/4v+z/7//3gAJADQASABOAEEAJwAYAAj/6P/B/6j/vP/h//cAEAAI/6z/M/7l
/tL+9/8q/0X/Uv9c/3D/qf/zABT////d/9wACABTAKUA0QC8AJMAgQB9AJAAsACaAEL/8P/K
/7j/u//oACgATABNAFAAWgBPAD8APgBTAJgA8QEfASkBCQCrAEYAGgAmAFMAZwBBABb/7f+Y
/y/++v8Q/zn/NP8c/yn/Rv9F/yj/Cv7//wP/Ef8f/yL/Pf9t/2v/U/9t/4//lf+b/6f/t//V
AAUARABxAIAAjACbAK4AxAC2AIMATgAtAD4AdAClAMoAzACfAGkAKv/f/7T/lP9w/4H/uv/h
/+T/3f/m/9j/kv9i/33/pP+6/9v/+f/0/9j/vv+5/+EAIQA0AB4AKQBPAFgAWQByAHcAUwAi
/+3/w//S//wABQAEAAX/8v/j/9L/qP+V/6b/sv+k/3z/aP9u/0//Mf9T/4f/xwAkAHAAoQCj
AFsAEf/w/+EAAgBQAIEAegBeAFsAcgCGAIsAfwBUABj/2f+k/5D/q//c//H/0/+i/27/RP89
/0X/SP9H/y7/Fv8t/1D/VP9D/0X/if/qAAX/5f/c//QABwAOABMADgAA//j/+P/v/9T/v//a
ABYANgBJAGMAVwAk//v/4//T/9H/7gApAFEATwBKAFUAZwB2AGsASAA5AEwAZQBsAF8ASgBG
AGAAewCAAIEAlADBAPAA+QDmAN4A4wD1AP4A7wDgAMwApACaALYAwAC8AMIAqgBbACUAUgCd
AKMAfQBpAFsAOgAJ/+z/8//5/+P/zf+8/6P/pP/WACIAXQBgACr/8v/X/9T/+QBAAHEAagA9
ABoAIwAuABf/9f/Q/7X/0gAPADAAPgBPAFgAUwBJAEQAPAAsACIAC//Y/63/p/+5/73/p/+D
/1z/Rv9P/2r/nv/d/9z/pf+P/6b/zAAGAEQAVgAc/83/wP//AFQAjACZAJYAdwBIAFMAhQCf
ALkA2wDmANEAlQBVAEIAQAA3ABn/6P/vACMAIwAKABgAOABeAIgAiQBI//n/5QAIAEIAfQCT
AJsAswCtAJEAgABH//n/6wAPADsAZAB4AHMAXgBTAE0ARgBvALUAuACUAIUAhgCPAGwACv/V
/+YABAApAEYARAAvABQABv/3/8//vf/dAAwAMAAp/+3/r/+Y/7P/6AASABn/6f+h/5j/3AAx
AF8ATQAoAB4AKQA+AEAAJgAhADEAI//q/6j/lv+r/6f/kv9s/yP+7/7e/tr/Ef9o/5f/tv+9
/3//GP7W/u7/P/9z/43/rv+5/6T/i/+J/6T/tv+7/87/2P+w/2n/Rf9d/2L/LP8M/yT/WP+j
/9//9//+/+D/nf9Y/yn/Mv9s/5T/qf/H/9D/uv+q/84AIwBTADH/9v/b/9b/tP9s/1L/f/+k
/6T/nf+b/6P/p/+N/1//Q/9O/2r/bf9Y/zT/Bf7l/tD+vv7e/zL/ev+e/63/v//4ADcARgAv
ABD/7f/U/8P/wP/rADIAawCnAO8BBwDVAIkAVwBVAHMAjQCZAJsAjABlACT/4//H/7j/kf9q
/1P/Uf9t/5D/qv+q/2X/EP8G/yb/R/9n/23/df+g/8f/6QASACsATQCcAPUBIAEKAMwAjwB6
AJYAnQB4AHgAlgCHAGQARQAd//D/vP+Z/70AHQBiAEH/+//3AAb/8//j/77/gP9//8cAFAAv
AAH/xv+1/7n/yf/uAA8AEf/s/6v/c/9m/3z/nP/IAAgAOQBJAE0ASgBFAEwAXABtAHwAgAB7
AGgAQwAd////8AAAAC8AagCCAFAAGAAsAFoATgAR/+D/2//R/5X/ZP9m/27/b/95/3//g/+P
/7H/8gAnADIAQgByAJkAnQCTAIUAZgBGADgAMQBDAGIAUAAtAEAAZQBoAFMAWQCXAMwAvQCL
AGMAZQB9AHgAfACfAKUAmwC3ANQA1QDKALgAqQCmAKkAnQCCAHoAlwDBAM4AsACkAMMAxACG
AEoANwAvAAn/3f/S/9v/+QAqADsALwAnABIACQAuAEkARABEAFEAagCJAJ4AuwDGAJ0AcwBs
AHEAlQDNANsA1QDhAM0AmACFAKIAuACzALUAxQCzAHoAUwBeAIIAiwBhAB7/8v/u//f/6f+z
/2b/OP9B/1b/cv+f/8T/7gAT//f/zf/d//j/6/+0/2z/SP9c/4j/nv+L/4j/rf+//7f/v//T
/9n/y/+6/7b/tf+3/7v/sf+g/57/n/+c/67/zv/L/5z/bv9f/3X/hf9q/1n/cP9z/1H/M/8+
/2//j/+T/7L/1v/V/9D/2v/v//v/3P+y/8YAHgBwAHMALP/g/7n/pv+D/2b/f/+w/73/rf+i
/4X/Nf7a/q3+m/57/k7+L/5A/nj+qP69/rn+uP7U/u//Df9Y/6H/w//sABYAJQAeABAAFAAt
ADIADf/Z/7v/tf+8/9X/0/+Z/2D/X/+I/6r/rf+w/8H/0f/m/+T/r/94/3v/zQBIAI8AkwCX
AJsAgABYADD//f/Q/8v/6P/8AAYAIgBMAGgAewCkANEAvQB5AD4AFAALADMAZwCiAOMA4QCT
AFcAUgBhAHIAeQBxAGUAXgBiAHYAmACxAKQAjgCYAJEAWwAf//0AEwBWAGwASwAsABYAIQBX
AJwA5AEDAOwA3QDbANUA1gDQANcA9wDpAKkAfwCEAJsAkwB0AG8AcABH//n/rv99/1D/OP9m
/7T/4P/M/47/lf/wABX/7f+//53/i/+H/5//7QAzAEQAQgAxAA3/3f+w/8EAAAAS//H/2//l
/+v/yv+c/3P/S/9G/2//twAfAGYAXAA3ABL/3f+2/6z/o/+f/7D/z//p//4ADgAJ/+T/pf9/
/6P/8gAiAC0AF//H/3P/YP9w/3H/WP8+/1b/iv+R/4n/q//P/8P/of+l/7v/nf94/4H/nf/J
AAMALwBfAIEAiwCpALgAmgCAAFQADP/wABgAdADYANL///66/kn/fwFGAccAof7+/h7+fP/b
AUMBjwDH/+j/h/9//2X/Tv+vADwAgwC2ALgAYAAqAEgAggCjAHMAHf/s/9b/6QAvAHgAlgBv
AEQAaQCXAIAARwAlADQANv/a/1j/B/7b/sv+3/8H/yT/Kf86/4L/5wAwACv/1v+H/3P/c/90
/4//u//i/+3/zf+o/6j/nP9y/3b/sf/Y/+wAEQAjAAL/uP9g/1H/o//a/7r/pf/KAAgAQQBg
AGYAWAA+ADsAQgA3ACsAOQB0AMIA3wDlAPUA7wDrAP0A9QDdAMgAugDVAPYA3ACQADX/9//r
//kAIABaAHkAggCHAIAAdwB2AHcAbABVAGoAqwCtAGUAQwBnAJcAugDGAKYAaQAw//7/2//b
AA4AcADDALwAawAR/9H/y//6ABsAEgAEABkAXwCRAEb/yv/CACYAkQDGAKEAZQBdAFsAMv/n
/6P/qf/O/9b/5P/6ABQAUgCEAJcAsQCzAIUALv/R/8n/+wAEAAEACgAC//j/9AALAE8AhACN
AIIAawA8//j/x//E/7z/oP+e/8gAAAAbACQAJ//x/5L/Vv8+/0H/Y/+kAAUAM//o/4X/Y/9z
/4v/jv+oAAQAVgBoAF8AVQA9AA7/6f/wAAD/+wAGAEIAiwCeAIoAgwBoACwAFgAyAFYAfQCP
AGYAAP+Y/4f/0gAfAB3/zv91/y7++v8S/3b/vv/fABMAKP/u/5v/fP+vAAYAQABYAE4AIQAN
ACoAQQAr/+n/xQAKAGAAWgAtACgAPgBAABb//QAkAEkAOQAY//L/z//UAAoAKf/a/zT+vf7A
/vz/Fv73/tT+5f8X/zX/B/53/ef92v46/n3+fP6c/v3/LP8F/v7/LP83/yr/K/8X/tn+l/6P
/sz+/f7p/rD+h/6Q/sD+8f8b/x3+8v7l/wf/H/8l/yv/Kf8P/uj+1P8B/5oAeAEYASwA1wBw
AFkAoQD1ARAA4gCmAKsA1QDMAJsAoADjAQIA8gD8APsAxgCbAJUAmACUAIEAewCVAMcBDAEz
ASAA+gDSAMIA5QEPAToBfQGbAW0BEACzAI0ApQD2AXABvAHAAZsBQgDsAPYBMAEwAO0AmgBI
/+r/n/+X/9AABP/q/6X/mP+3/7b/cf7t/mj+Iv4d/mL+x/7W/oX+I/3g/ej+M/5m/kr+Af3S
/er+P/6I/m79+P2M/Wr9o/4k/o3+v/74/0X/rAAeACr/r/8j/tf+4P9M/9sAE//b/5r/o//i
ADsAowDtAPkAwABwAHAAtQDTALkAhQBAACEAYADtAXwBwwHiAfoBxwFgATsBZAGeAboBrgGm
AZkBQgDNAIQAagCDALsA6gEXAT4BUwF1AcECMgKzAwkDCgKzAgoBQwCpAF4AgwEpAeoCKgHE
ASsAzACzAMoA5gCn/9v/Af66/tv+yP5z/kD+af60/pz+F/25/dX+Nv5v/iX9efzv/M39E/1+
/af9m/2m/bT9nP19/ar+R/8D/4f/0v/m/7T/RP6+/m/+hP7n/1//mf+I/54AIACuAMwAmwCP
AK8ApgBiABkAAAAsAHkAqACUAGgAaABnACD/y/+4ABYAyQFQAW8BcgGlAiUCpAKqAlQB8gGW
AW8BmwHlAgMBvQFeAVUBmAIXArMC/QLJAjsBpgGIAaoBhQFAAQsAxwCUAIMAjQCyAM8AsABF
/73/Yf8W/rz+n/7e/0b/nf/F/9H/vv97/zr+3v5D/d39zP3G/df96v26/Uv8q/w7/G/87/1C
/Yz90/3X/Zb9Tv04/VP9uP6P/4cAMgCGAJYAdwBGABgAEwBCAHgAkACDAHQAmQDoASMBGgD2
AQ8BOAERAPYBVwHRAe4ByQG1AeoCXALEAvIC9QMEAzIDbAOvA9EDoQNWAz4DRgMmAsMCWgJF
AoQCyQLaArQCegJLAkQCPgHXAS0AzgDAAK0AjgBvAEsAMAAiABsAGAAfAC4ADP+w/5b/7QA2
AAz/iP8J/sX+h/4h/bb9dP19/cf+AP3x/a79Wf0a/O78pvwm+5z7afu3/FD85f0x/Rn88P0Q
/XH95P4W/aD8mvvk/FX9mf6l/xL/D/6+/mD+RP5Y/kj99v3j/n7/NP9c/0n/cv+v/5z/Uf9v
ABkAuQEVAVMBdAGCAZsB1AIzApkC6AMAArICPAI9AuMDzQRoBGgEDQO9A7ED6wQtBD4EIQPX
A0sCnAI6AmQCkwI/AbYBkAH9AsEDZANlAoQBUQDXARABJwEiAXEB4QHxAWAAev/X/6n/8ABe
ACT/F/4S/aP9bPzb+/r7R/rn+tb7Kvuh+/D8KvxM/Cz7uvsE+kz52fng+oL7hPxn/Lr8TfuK
+zr7ePvM++/8Bfxt/Tv+Ff6i/rr+jP6R/tz/Ev8a/yz/Sf8m/rj+jP8K/8kAHQAJADoBBQHb
AikCEAHjAb8BvAIMArUDWwOxA/AEUAS1BOYEoQP1A5wEAAR2BDEDcgMYA2oD7QRUBLgFDAUP
BNcEtwTFBOYE9gSpA9gC/AKiApwCXAHgAYgBMgClAEcAQf/+/1//DP81/zf+nP3C/Rj8Vfto
+0f8UP05/OX7+fup+9D7afqT+lv62PsL+mL5YPjC+Jr4yfly+mv7Kftn+037N/tO+1z7L/q8
+i/6CfqI+2v8hP2Z/jf+OP3//iv+zv9zAC0BLgHXAd8CBwKzAysC2QI6AhYCXgKIAoECsQNN
BBUExQU9BU4FFwT1BM4EfgRCBBkDuwMnAuYDpgTyBX4FEwSaBKUFCQU/BTcFQgUxBOUE5wVO
BYEFSgUSBSwFSATyBDsDgAMSAusCoQH8AT0AngAk/7n/Tf7H/fX9Gvze/SD9Qf0s/PP8ePvf
+4L7Uvra+kv6fvsy+zX6aPmw+XL5bvlh+Wb5w/p9+1/8IPyl/S79sf2+/Uj8wvyb/N/9Tf3j
/rj/fgAOAJ8BCQD3AJEATABrAK8AzADyAT8BfAG1AgYCIAHwAfECZgL1Ay8DEQL4A1wERwUV
BRkEUANRAuYDVgP3A+8DMwJ1AmAC+QPHBBkDfgKFAjIClwL8AxcDPQOoA/IDrALyAf4A2//X
/z//BP8F/1L/5gBF/+v/Av4t/eT+Cv3p/U783/zu/Sb9CvxX+5P7dfvh/GP8lfw/+9X7yPwW
/Lr9Q/0H/Dr7iftZ+6/8OPz6/iX/Jv9e/yz/QP/BAE8ArADuAO8AkAAo//oAEwBvAMYA4ADH
AHn/7P88/tP/Df99/4H/X//YAQYCIAJqAiwCEAJAApwC5gLnAsECjgJAAdYBMQBc/+kAWwFg
AhUCEQHhAi8C3QMaAm0BggFPAdoCfgK4AoYCQQHvAXYBMgE/ATAA0gAg/z3+nP5n/lv+Rf4M
/bb9av1f/Z79yf2t/dP+fP8C/vj+tv53/fr9Vf0o/X/9pf1W/SH9l/5r/ob9ePws+7r8Uf1O
/hH+i/7N/rr+cP4h/cL9WP1F/d3+sf7N/iX9qv3t/qv/Vv+P/0z+u/4//lL+8/+hABIATABV
AEoAjwFSAhYCTwH2AWUBHwFOAZYBzwImAqkDSQPVA/sDtgNLAxADKQN7A/QEWAQzA8QDsAPB
A1gCewHVAf8C5QQFBKsELAMAAo0DIQO+A5oC5wKSAu8DTAM+AxgDEgL4AoEB0QFLAM4ASAAt
AHYATf9I/in96v5Z/mj91/2O/i7/E/89/rP+Mv4N/fX9kP0R/O39N/3C/hb9oPy3/DX8P/xn
/DD7iPtA+9j8gfxm+/r8MPzj/Qv8ivwa+9P7e/tt/AD81f1S/Xj9uv4I/fX9yv47/zn/6//R
/2n/X/+U/4j/NP7o/sj+4f9hAFkBaAHPAVkA4QECAT8BKgERAU8BwwINAjUCdAJ/AjgCKgKH
AvkDOAMvAzQDngRSBRoFpQWuBbIGKAaWBk8FPgQEA30DogOsA3gDcgOWA4AC+gJOAhwCcQKh
AmUCAwGRAQsAmgBaAFkAmgD2AT8BQwDpAIAAegDNAPgAsgBiAGYAdQAj/zj96f0V/U7+Av5W
/hz9tf2A/Wv9O/zo/Kr8v/0U/Uv9JvyO+6P65vrY+5D8lf0v/Tn9GP0V/TP9R/07/TH9Lf0M
/ND8gvw6/Cb8YfzH/PL82Pz9/Xf96P4r/jn+O/5//vf/Qf8U/q7+uv9G/9MAKAAs//3//AAv
AIEBFAGzAfwBwgEwALMAXAARAA8AWgCgAMUA1AD2AUoBvgI7Ao4CowLBAvIDDQMUAtwCewJe
AnMCeAJ9ApsC6AMmAuwCZQHzAbcByAICAhwCGgIfAjcCEwFQADv/jf+L/+P////U/+sAYADJ
AQABEQDuALIAswDvAO4AjQA4ADIAbgCwAJkAAv8l/qX/Dv/fABv/rP8q/u/+0P6K/k7+Qv4h
/gz+VP7D/wD++v7e/wn/df+s/5H/cP+E/8X/9v/J/yz+mv6p/zX/ov+p/13+/P7Z/xz/if+s
/3H/Nv8F/rX+gv6b/sj+xP5//iv+Gf5H/nD+iP7B/0P/6AA+AB3/4v/e/+r/v/+A/5T/6f/z
/5f/T/9b/3H/Vv9D/37/4AARAAf/8P/R/6//vAAAAB7/zf9P/xr/OP9e/2T/Uv9A/2j/4gBP
AE3/7v+R/5j/+AAxAAn/xf+m/7f/2P/4ACgASAAyAB0ANwB4ALIAev/p/8cAYQEsAYUBRQDV
AJoAsAEMAVYBVQFkAbwCBwIHAdEBkQFzAakCPgKtAoACEAHOAa8BeAEYANoA5wDvAO0BGgE0
AQUAwACYAKwAvABd/9b/u//g/9D/tv/pAEMAggCmALAAnABvAC3/7v+6/4T/dv+V/53/gv9Q
/wb+4P8A/xf+7P6u/rP/F/+3AEYAiwC9AQ0BIQC0AAb/cf85/1H/bf+F/7H/7gAzAEoAMQAQ
/6//Fv63/oj+ev7B/xT/Ff7k/sf+2P7o/tf+4/8m/4s=')
        samplingRate: 44100!

----- Method: SkeletonBaseInfo class>>cassete (in category 'sound library') -----
cassete
SampledSound
        addLibrarySoundNamed: 'cassete'
        samples: (self mimeStringToBuffer:
'AQD/AP4A/wD+AAAAAAD+AP8AAAD/AP0AAAAAAP8AAAABAAIA/AD/AP0A/wAAAAEA/QADAAAA
AAD+AP8AAQACAP8A/wD+AP8AAgD9AAQA/AD/AP8AAAACAP0AAAD6AAgACgD4APkA9gAGABIA
CQDpAPwA/gANAAoAAgDpAAEABwD2AOwAAQD/AAsA/gAFAAoAAQD5ABIABAAaAPcA1wDeAAEA
BwARABwA9AD3APIA8QD3ABkA/AATAPMA+wAAAPEAEgD+AAoABgD9AP4A9wD0AAYA+wAEAAgA
9QD8AAYAAAD3APsADQABAAoA+AD8AAEA9AD2APgA+AAGAAwADQAKAAMA9wD4APsACQAPAAUA
+gD5APQA9gDzAAAABgAGAA4ABwD7APoA9wD3AAIACgARAAcA+gD3APkA+gAAAAkA/wACAPgA
9AD5AP4A/gADAAAACQACAAEA/gAAAP0AAAD9AAAAAAAFAPwA/QD7AAEA/gACAAMAAwD7AP0A
+wD/AAIAAwAFAAYA/gD8APgA/QABAAEA/wD/AP8A/wD9AAAAAAADAAAA/wD/APsA+wAEAPkA
BAD9AAIA/AAFAPwA/wD8AAIA+gABAAUA/gACAP8ABQD7AP4AAQACAPwAAAABAP8A/gABAP4A
AAD+AP0AAAAAAAIA/gD/AAIA/gD/AAAA/wD/AP4AAAD/AAMAAgD+AAAA/AD+APwAAwAAAP4A
AAABAP8A/gACAAEAAQD/AA4A9AAGAPsA6QAIAAMA9AASABgA5AD/AAIA9gAKAPsAFwAHAMwA
5gAlABcAPQAGAMkAygDoABYALwD/ANcAyAACACkAOgAXAOEABgDHAPkA+AA0ABoAEgDMAOAA
5AAOAB0AJgAMANwAzwDwADYAFgAUAPEA/QDaAPwA/gAnAP8A9wDlAO4AIQAdACQADgDgAMYA
8gAVAC0AOAD/ANsAzQDqAPMACwALAPoA+ADrAAEAFAAqABUA8QDgAPEAFQAFABIABQDyAOkA
6wAJABYACgD0APIA9QAFAAcAFAAPAOgA5QDsAAwAFgARAOwA+QD5ABMADQAKAOkA7QAAAAMA
FAAEAAQA8QD7APkAGwAQAA8A9wDxAOQA6gD8AAoAEgAMAP0A/wAQAAUA6QDtAPoA+gD3ABAA
JAAYAAIA4gDeAOUA/QAUAAsABAD6APsA9wAKABMAEQD4APcA8AAKAAQAAgD5APgA+AD3AP4A
/AD6APYA+wADAA8ABwAKAA4ABQD6AOsA7gD7AAkA+gAEAPcA+AD+AAkACwAEAP4A/wD7AP0A
BwAOAAsABwADAP4A/QD3APQA9QD4APUAAwALAA0A/AD2APgA/AAFAAsABwADAAMAAgAAAP8A
AwACAP0A8AD0APkAAwAFAAEA/QD9APcA/gAEAAgA/QD5APwAAAAHAAQAAgAEAPMA9gD6APkA
BAAEAPUACQAIAP8A9wD/APsABAAAAAoACAD8APUA8AADAA0ADQAGAP8A9wD4APwACAAGAAMA
/QD9APkA/gD3APwAAQACAAAAAwAHAAkAAwD8APsA/wAFAAcABgAAAP0A+QD0APsA/gADAAIA
/gD7APwA/QADAAAAAgD/AP4A/wD7AP4A/AD9AP0AAQABAAEAAAD+AAAAAwAEAAMABAADAAIA
/wD/AP4A/QD+AP0A/QD+APsA+wD8AAEAAgACAAIAAgAAAP8A/gD/AAEAAQAAAP0A/gAAAP8A
/wAAAP8A/wD/AP8AAwABAP8A/gD/AP8AAgAFAAQAAAD/AP4A/QD+AP8AAgAEAAIA/wD/AP4A
/gD/AAIABAABAP8AAgD9AP4A/AAAAAEAAgD/AP4A/gD9AP8A/wD+AP0A/gABAAEA/wD/AP8A
AAAAAAAAAQAAAP4A/gD9AP0A/wD/AAIAAQAAAP8AAAAAAAEAAQADAAAAAAD+AP8A/gAAAP8A
AQAAAP4A/QAAAP8AAAABAAEAAQACAAEAAAD+AP8A/wAAAAEAAQD9AP0A/AD8AP0AAQACAAAA
AAD+AP8A/wAAAP8AAgACAAAA/gD+APwA+wD8AAMACQALAAQA+gD0APYA+AD9AAMACAAIAAIA
/QD5APwA/gABAAIABAADAP8A+wD5APoAAAAFAAYAAwAAAPwA+QD+AAAA/wABAAMAAgACAP0A
/AACAAMAAgAEAP0A/gD+AP8A/wABAP4AAQAAAP4A/AD9AP8AAAD/AAIAAgABAP4A/gD8AP0A
AAD/AP8AAAD+AP0A/wD+AP4A/QD+AP4A/gD/AAAA/wAAAAEAAgAEAAIAAQAAAP4A/QABAAMA
AQABAAAA/gD+AP8A/wAAAP8A/QAAAP8AAQACAAEAAQABAAIAAAD/AP4A/wD/AAAA/wD+APwA
/wD+APwA/AD+AP0A/gACAAUABQADAAAA/wD/AP8AAQABAAAAAAAAAP8AAAD9AP0A/gD/AAAA
/wAAAAAAAAD/AAAAAAABAAMAAwD/AP0A+QD9AAAAAAABAAEAAQD/AP4A/gD+AP8AAAAAAAAA
AQABAAEAAAD/AAAA/wD/AP8A/wAAAP8A/gAAAAAA/wABAAEAAQAAAAAA/gAAAAIAAQABAAEA
AAAAAAAAAAAAAAAAAAAAAP4A/gD/AAAAAQABAAEAAQAAAP8A/gD+AP4A/gD/AAAA/wAAAP4A
/gD/AP8A/wD/AAAAAAABAP8AAAAAAAAA/wD+AP4AAAAAAP8AAAD+AP4A/gD/AAAAAgABAP8A
/QD9AP0AAAABAAIAAQABAP4A/QD8AP0A/wABAAEAAgAAAP4A/wD/AAAAAQABAAEAAQAAAP8A
/gD+AP8AAAABAAAAAQD/AP0A/QD+AAAAAgABAAEAAgAAAP8A/wD/AP8A/wD/AAAA/wD+AP4A
/wD/AAAAAAAAAAAAAAD/AAAA/wD/AP8AAQAAAAAA/wD+AP0A/gD/AAEAAQAAAAAA/gD+AP8A
AAABAAIAAAD/AP8A/QD+AAAAAAAAAAAA/wD+AP4A/QAAAAAAAQAAAAAA/gD/AP4A/gD/AAEA
AAABAP8A/gD+AP4A/wABAAEAAQAAAP8A/wD/AAAA/wABAAEAAQD/AP8A/QD/AAAAAAABAAAA
/wD/AAAA/gD/AAAAAAABAAAA/wD+AP8A/gAAAP8A/wD/AP8A/gAAAP8A/wAAAAEAAQABAAAA
/wD/AP8A/gAAAAEAAQAAAP8A/gD/AAAAAAAAAAAA/wAAAP4A/QD8AP8AAQACAAEAAAD/AP0A
/gD+AP8AAQAAAAAAAAD9AP8A/gAAAAAAAAD/AP4A/QD9AAAAAgACAAIAAAD+AP8A/gD/AP8A
/wAAAAEAAQAAAP8A/gD+AAAAAQAAAP8A/wD+AP4A/wD/AAAAAQABAP8A/QD8APsA/gABAAMA
AQACAAAAAAD/AAAA/gAAAP8AAAAAAAEAAAAAAP4A/wD+AAAA/gABAP4AAAD+AAEAAAACAP8A
AAAAAP8A/wAAAAAAAQAAAP8A/gD/AP4AAAAAAAEAAAABAP4AAAD+AAAAAAABAAAA/wAAAAAA
/wAAAP8AAAD/AAAAAAAAAP4AAAD+AAEA/wABAAEAAQAAAAEA/gD/AP0A/gD+AP4A/gAAAAAA
AAABAAEAAAAAAP8A/wAAAP8A/gD/AP4AAQAAAAAAAAD/AP4A/wD/AP8AAAAAAP8AAAD/AAAA
AAABAAIAAQACAAIA/AD9APwA+gAAAAMABgABAPwA/QD+AAQAAgADAAIA/gD8AP0A/AABAP4A
AgD/AAIA/wD+APsAAAABAAQA/wABAP0A/gD9AAAA/QACAAAAAQAAAAEA/gABAP8AAAAAAP8A
/wD+AP8A/wD/AAAAAAABAAEAAwABAP8A/gD9AP8AAAACAP8A/gD/AP4AAAAAAAEA/wAAAP4A
AwD/AAEA/QD/AP0AAgD/AAIA/wABAP4A/wD9AP8A/wAAAAEAAwABAP0A/gD+AAIA/wABAP8A
AAD9AP4A+wAAAP8AAgAAAP8A/QD/AP8AAAABAAIAAQD/AP0A/wD+AAAAAgABAAAA/wAAAAAA
/wD/AAIA/wD+AP0A/gD/AAAA/wADAAEAAAD+AAAA/wABAP8A/wD9AP8A/wD/AAAAAQD/AP4A
/QD+AAEAAAD/AP8A/gD/AP8A/wABAAEA/QD+AP4AAAD/AAEA/wABAP0A/gD/AP0AAgAAAAMA
/QD/AP4A/wD+AAIAAwAIAP4AAAD5AP4A/AACAAAAAgD7AP8A/gD/AAAABQABAP8AAAD/AAAA
AQACAAIAAAD9AAAAAQABAAEAAAD+AP4AAAD+AAQA/wABAPwA/gACAAEAAQABAP0A/AD7AAEA
AAAAAAAAAAAAAP8A/QD+AAAAAQADAP0A/wD/AAMAAQAAAP8A/gD8AAEAAgABAP4AAgD+AP4A
/QABAAAA/wD+AP4A/gD/AAAAAAAAAP8AAwD9AAAA/gABAAAAAQABAAEA/wABAAQAAgABAPsA
/QABAP8A/gD/AP4A/wABAAAAAAD7AAQA+gAEAP8A/wACAAIA/AABAAAAAwD8AP0A+QAFAP0A
AAD5AAcA+gAKAPkA+wD5AAwAAwAGAAIA+wALAPYAAAD1AAQA+QAKAPsACAD6AAEA+wAEAPwA
AAAAAAAA/AABAP4A/wACAAIABAD6AP8A/gABAP8A/QADAP0A/QD+AAEA/AD+AAEAAwD8AAAA
/wADAP8AAQD6AAEAAwD8APgA/gD6AAcA/AACAPsA/wAAAAEA/QD9AAAAAwAEAAEAAQD7AAEA
AQD+AAAA+wACAP4A/QAAAAAAAgAEAP8AAAD/AAMAAgACAAcA/gADAP0A/AD/AP0AAwABAP0A
+gD7AP0A/wD9APwA/QABAAEA+wAKAAMADAAAAAMA9QD5APcADAAGAP0A/QDoAOoA/gALABAA
IwD6APEA8wD3AOkACwAAAAwACgD0APkA9gABAAIABwADAA8A+AAIAPoAAwD+AAgA/gDxAAYA
AAACAAgA/wD6APoABwAFAP4ABAABAAAA+wD2AP8A/gD6AAEAAAABAPkA9AD+AP8AAQAFAAYA
/wAAAAQA+QAEAPoA/QAAAAcACgAAAPwA+gADAAEAAgD7APYAAgAIAAQA/gD4APkABgAEAAMA
AQD/AAQABAD+APYA9AD6AAAACwALAAsAEQD2AOgA+gD8ABgAGQD+APAA+QDVAPsA4gAQACkA
LQAWAAkAxwDSAOEABQAiACYAFQD8APMA5ADsAP8AFwAQAPkA5AD+ABcACQDxAPkABAANAPwA
7gD7AP0ABwAHAAAA/AAEABoAGQD+AOcA1wDuABMAEwABAAUA/gAUAPUA7gDiAPQA/QAEABIA
FQAZABYAEwD2AOUA5gDpAOgA/wAFAAkAIAAXAP4A6gDjAPAAIAAMAAYA3gDZAPwAFAAmAB8A
AQDtAPoA7gDtAAYAEAALAAoABwAFABAABAD0AOQA6wDxAAUAFgANAAsA8gDzAPcAAwD9AAkA
DQAEAP0A8wD4AAoABQAQAAUA8wDhAOgAFgARAPEA/ADVABYA/QAhABIAKAD1AM0ACgAdAD8A
MgDmALgA0wAiADoA5QDlAOsA6gD3AC0AGAAbACQA9wDQAL4A3ADpAB4APQAKAMMAyQDtABkA
6wAmACsAzwDqAOMAEwADADsAKQD1AAwAygALABMA+QAkAOYAwQDxACQAJgAFABcA8QDlACEA
+AA5APsA+AD5APoA+wA0AC0AHADAAMAA2gDtABYAEwACAPAA6AD6AAUAGQAhAPMAyQDxADMA
IwAtAAMAxQDFAMQA7QAyADgALAD6AMIAzQDyACQARwA+AAgA3gDlAN4AEQAEAPgAEgANAOIA
8QD1APgA7wDwAPoAGwAqAB0AFAD6APEA9wD2AAcAJgAEAOwA6wD7AO0A8gAAAPQA9gD7AA4A
FgAWAP0ABwANABkAAwD3AAIA/wDxAOYA4AD/AAcAAgD4AO8A/gD4AAAAEgATAP4ABAABAPgA
8gD3AP0A8wDwAOEA9QD8AAgAIgAYAAIA7QDoAPUAEQAMAPsA9QD0AP8AAQD4AAgADgAIAP0A
AQAHAA4AEAAAAAwAFgANAAkA/wD3APYA/QD+AAMACwD9AO0A7wD3AA4ADwAHAPsA7QD3AAMA
DwAWAAsA+ADyAPcA9QD/AAMA/QD3APsA+QD+AAgABQAAAAIABgAEAAgABQABAAEA+wD3APgA
/AACAPYA9gDyAPUABAAQAAUAAwAAAPwA7gD3AAIABwD2AO8A/AAQAAQA8wD9APkABQABAA0A
CwD+APUA9AD/AAYABAACAAQABQAFAAcAEAAOAA8ABwAFAAcAAQD4APwAAAD8APoAAgACAAAA
+gD6APoA+AD5APgA9gADAAQA/AD+AP0A+wD0APYA+wD+AAAA+AD6APsAAQAEAAwABwD9APwA
/gD/AAMABAABAAQABAD/APkA/AD+AAIA+gD+AAcABQADAAEAAQACAAkABwADAPwA+QD4APsA
/QABAP4AAAADAAYAAQD/AP8AAQAFAAgABAACAAEABAD9APoA+gD9APwAAAD/AAAA/gACAAQA
AAACAAEA/QD6APwA+wD6APwA/gD9AAAA/wABAPsA9wD5AP0ABgD/AP8A+QDwAPUA/AAHAAYA
AQABAPsA+gD9AAUACAAGAAIA/QAAAAQAAwACAAAA/wAAAAEABgABAAQAAAAFAAMABQAIAAYA
/wD8AP4AAAD+AP4A/AD7APsA/QD/AP4A/QD7APcA+wABAAIAAAACAP0A+wD6AP0AAgAIAAYA
BQD8APkA+wD+AAAAAgD+AP4A/QD+AAAABAAJAAkACQAGAAEA/wACAAMAAwD/AP0A9wD5APsA
/wD+AP4A/QD+AAAAAQABAAEAAAABAP8A/QD9AP0A+wD7APsA/QD8APwA/AD7AP8A/wACAAMA
BAADAAMABAAFAAUABAAEAAIA/AD6APoA/gD+AP4A/AD9APsA+QD8AP8AAgACAAEABAADAAEA
AAD/AAAAAAD9APwA/QD9APwA/gD/AAIAAwACAAMAAwADAAQABQADAAEAAQAAAAAA/gD8APsA
+gD7AP4AAAAAAP8A/gD+AAEAAQD/AAEAAQD/AAEAAQAAAAAA/wD+AP4A/wD/AP8A/wABAAEA
AAD/AAAAAQACAAAA/wD/AP4AAAADAAAA/wADAAIA')
        samplingRate: 11025!

----- Method: SkeletonBaseInfo class>>cork (in category 'sound library') -----
cork
SampledSound
        addLibrarySoundNamed: 'cork'
        samples: (self mimeStringToBuffer:
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA/wD+AP0A/QD7APoA+QD3APgA9wD4APcA+AD4AP0A+gD7AP0A/AD9AP0A+wD9APsA
/AAAAAAAAwAEAAcAAgAIAAoACQANACcAHgAjACAAIQAnACgAGQAzAC4AHgAnACQAGwAbABMA
AwD1AMEArACrAK8AvgDnAA8AJQAtABsA9wDUALUAuwDBAM0A9wAmACcAKQARAN0A0gDNANAA
/AAKAA0AFADuAOAA7QDyACAAOgA0ADEACQDaANUA0wDuAB0AJwAqABAA4gDUANYA6gAQACAA
JAANAOkA2wDdAO4ADwAgACEADQDxAOMA5QD6ABIAHwAeAAwA9wDuAPEAAwAWAB4AGgAKAPsA
9QD9AAkAFAAVAA0AAAD1APMA+gADAAkABwD9APMA8QD1AAAACQAMAAYA/ADxAOsA8QD6AAMA
BgAEAP0A9gD4AP0ABAALAAcAAgD9APcA+wADAAwAEgASAAwABgADAAEAAwAEAAAA+wD1APMA
9gAAAAcADAAJAP4A8wDoAOYA7QD0AP4ABQADAAMAAgABAAUABgAGAAYAAgAAAP4A/AD9AP8A
/wAAAAAAAgAGAAgACQAGAAAA+wD3APcA/QACAAYACAADAP4A+AD0APQA9wD7AAAAAAD/AP4A
/QD9AAAAAQABAAEA/wD7APoA9wD3APsA/QABAAQAAgAAAAAA/AD9AAAAAgAHAAkABwAGAAMA
AAAAAP8A/gD9APsA+QD4APgA+wAAAAMABQAFAAIAAQAAAAAAAAD/AP0A/AD7APwA/wACAAQA
BQACAP4A+QD3APgA/QABAAUABQADAAAA/wD/AAAABAAJAAoACQAHAAMAAAD+AP0A/QD9APsA
+gD6APoA+gD8AP0AAAAAAAAAAQAAAP0A/AD6AP0AAAAFAAkACwAJAAUA/wD6APgA+AD8AAAA
AgADAAIAAAABAAIAAwAGAAUAAwAAAPsA+AD3APkA/AAAAAMABgAHAAYABQACAAAA/QD7APoA
+wD8AP4AAAAAAAEAAwAEAAYACAAGAAQAAAD9APoA+gD7AAAAAgADAAQAAgAAAAAAAAAAAAEA
AAAAAP4A+wD7AP0A/gABAAIAAQAAAP0A+wD7APsA/AD9AP0A/QD9AP4AAAADAAYACAAHAAUA
AwABAAAAAAAAAP4A/QD9AP0A/gAAAAMABQAGAAMAAgAAAP0A/QD+AP8AAAD9AP0A/QD9AAAA
AgAEAAUABAAAAP8A/AD6APsA/QD+AAAAAgADAAUABgAGAAYAAwAAAP8A/AD6APoA+gD8AP8A
AQADAAUABQAEAAIAAAD9APwA/AD9AP0A/gD+AP8A/wAAAAAAAQABAAAAAAD+AP4A/QD/AAAA
AAAAAAAAAAAAAAAAAAACAAMAAgAAAP8A/QD9AP0A/wAAAAAAAAAAAAAAAAACAAMAAwABAAAA
/gD9AP0A/QD/AP8A/wD/AP8AAAABAAMAAwADAAAA/gD8APsA/QD+AAAAAQACAAIAAgACAAMA
AwACAAAA/QD6APkA+gD9AAAAAwAEAAMAAQD/AP0A/QD9AP8AAAD/AP4A/gD+AAAAAQACAAMA
AgAAAAAA/gD+AP8AAAAAAAAAAAAAAAAAAAAAAAEAAgABAAAA/wD9AP0A/QD+AP8AAAAAAAAA
AQABAAAAAAAAAAAAAAAAAP4A/QD9AP0A/QD/AAAAAwADAAQAAwABAAAA/wD+AP4A/gD+AP4A
/gD/AP8AAAAAAAAAAQABAAAAAAD/AP4A/gD/AP8AAAAAAAAAAQACAAMAAwABAAAA/QD9APwA
/QD/AAAAAAAAAAAAAAAAAAAAAgACAAIAAAD+AP0A+wD8AP4AAAABAAIAAgABAAEAAAAAAAAA
AAAAAP8A/gD+AP8AAAABAAIAAgABAAEAAAAAAAAAAAD/AP0A/AD8AP0A/gAAAAAAAgACAAEA
AQAAAAAAAAD/AP0A/QD8APwA/gAAAAEAAgACAAAAAAD/AP8A/wAAAAAAAAD/AP4A/gAAAAAA
AgADAAMAAQAAAP0A/QD9AP0A/wAAAAAAAAAAAAAAAAAAAAEAAQABAAAAAAD/AP4A/QD+AP8A
AAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAD/AP8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
/wD/AP8A/wD/AAAAAAAAAAEAAQAAAAAAAAD+AP0A/QD9AP4A/wAAAAAAAQACAAIAAQAAAAAA
/wD+AP0A/gD/AAAAAAAAAAAAAAAAAAEAAQAAAAAAAAD+AP0A/QD+AAAAAQACAAMAAgABAAAA
AAAAAAAA/wD/AP4A/gD+AP8AAAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAA/wD/AP4A/gAAAAAA
AAABAAAAAAAAAAAAAAAAAP8A/wD+AP4A/wAAAAAAAQABAAEAAAAAAAAA/wAAAAAAAAAAAP8A
/wAAAAAAAAABAAIAAQAAAAAAAAD/AP8A/wAAAAAAAAAAAAAAAAAAAAEAAQABAAAAAAAAAP8A
/gD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8A/wD/AP8AAAAAAAEAAQABAAAAAAAAAAAA
AAAAAAAA/wD/AP8A/wAAAAAAAQABAAAAAAD/AP8A/wD/AAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA/wD/AP8A/wD/AP8AAAAAAAAAAAABAAEAAAAAAAAAAAAAAAAAAAD/AP8A/wAAAAAA
AAAAAAAAAAAAAAAAAAD/AP8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AP8A
/wD/AAAAAAAAAAAAAAAAAAAA/wD/AP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AP8A
/wD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8A/gD/AP8AAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA/wD/AP8AAAAAAAAAAQABAAEAAAAAAAAA/wD/AP8AAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP8A/wD/AP8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/AP8AAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wD/AP4A/wD/AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AP8A
/wAAAAAAAAABAAEAAAAAAAAA/wD/AP8A/wD/AAAAAAAAAAAAAAABAAEAAAAAAAAA/wD/AP8A
/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wD/AA==')
        samplingRate: 11025!

----- Method: SkeletonBaseInfo class>>createSoundLibFromWav:name: (in category 'sound') -----
createSoundLibFromWav: fileName name: aString
        "self createSoundLibFromWav: 'sound\cas.wav' name: 'cassete'"
        self
                createSoundMethod: (SampledSound fromWaveFileNamed: fileName)
                name: aString.
        self perform: aString asSymbol.
        (SampledSound soundNamed: aString) play!

----- Method: SkeletonBaseInfo class>>createSoundMethod:name: (in category 'sound') -----
createSoundMethod: aSampleSound name: aString
        "
        see self>>createSoundLibFromWav:name:
        "
        | method |
        method _ aString , '
SampledSound
        addLibrarySoundNamed: ' , aString printString , '
        samples: (self mimeStringToBuffer:
' , (Base64MimeConverter
                                        mimeEncode: (ReadStream on: aSampleSound samples asByteArray)) contents printString ,
')
        samplingRate: ', aSampleSound originalSamplingRate asString.
        self class compile: method classified: 'sound library'!

----- Method: SkeletonBaseInfo class>>initialize (in category 'class initialization') -----
initialize
        self installMenu.
        self installWorld.
        self installSound.
        self addPseudoMethodForBabel
!

----- Method: SkeletonBaseInfo class>>installMenu (in category 'class initialization') -----
installMenu
        TheWorldMenu registerOpenCommand: {'Skeleton Spreadsheet'. {SkSheet. #open}}.
!

----- Method: SkeletonBaseInfo class>>installSound (in category 'class initialization') -----
installSound
        | sounds |
        sounds _ self class organization listAtCategoryNamed: #'sound library'.
        sounds
                do: [:each | self perform: each]!

----- Method: SkeletonBaseInfo class>>installWorld (in category 'class initialization') -----
installWorld
        Preferences enable: #batchPenTrails!

----- Method: SkeletonBaseInfo class>>makeChangeSetForThisPackage (in category 'fileIn/Out') -----
makeChangeSetForThisPackage
        "This is for building .pr file"
        "self makeChangeSetForThisPackage"
        | aChangeSet package |
        aChangeSet _ ChangeSet current.
        package _ self default.
        package classes
                do: [:aClass | self addClass: aClass toChangeset: aChangeSet].
        package extensionMethods
                do: [:method | aChangeSet adoptSelector: method methodSymbol forClass: method actualClass].
        aChangeSet postscriptString: self default postscriptText.
        ^ aChangeSet!

----- Method: SkeletonBaseInfo class>>mimeStringToBuffer: (in category 'sound') -----
mimeStringToBuffer: aString
        ^ SoundBuffer fromByteArray: (Base64MimeConverter
                        mimeDecodeToBytes: (ReadStream on: aString)) contents!

----- Method: SkeletonBaseInfo class>>mochi (in category 'sound library') -----
mochi
SampledSound
        addLibrarySoundNamed: 'mochi'
        samples: (self mimeStringToBuffer:
'8gDsAOIA3gDvAC4AUQBDAA8AAAAxACsAHQAtABIA4wDEAMEA6gDbAPYAOQAqAAwAEADzALkA
xAAGAOgAzgABADAAMwAgADEAGQAEAAQAxgDgAPQA7QDUAN4A+gDtAPQABwD9ANoAxQDNANoA
4gAEAC8AOgBDAEEANgATAAIA6ADRAMcAxQDRANcA3ADpAAYAEQAtAEMAPwAtABwALQBDAD8A
NgAwACcAHAATAAIA7wDoAM8AygDBAMkAxgDGANUA3wDqAPEA9gD7AAAAAAABAAgACgADAAIA
AwACAAEA9wD1AAEABQAEAA4AEwAVABEAEQAQABcAIAAeABQAEgAgABcADgAVABIADwAIAA4A
EQATABIACgAJAAoABAAAAPYA9wD7APkA+QABAAAA9gD7AAAA9AD0APcA7gDtAPYA8QDxAPcA
+wD2AO8A8wD4APkA/AAAAAEAAAACAAAA/gD1APMA+AD4APcA+AD5APYA+wD8APoA/AD4APIA
7ADzAPYA+gD7AP4ABAAHAAoACAAEAAIAAAD4APkA9wDvAPAA+AD8APoAAAAAAAMABQAFAAQA
/wAAAAAABAAEAAkACwAGAAoADgANAAgACQAGAAIA/wD9APkA+wAAAAEAAAADAAgACAAKAAsA
CQAOAA8ADQAQABIADgAIAAcADAAQAAwACAAEAAUAAgACAAUAAgAEAAgACQAFAAcACQAGAAcA
BwAHAAQABQAGAAYABQAAAPwA/AAAAAAAAAAAAP4AAAAAAP0AAAACAPsA9QD6APwA+gD6APoA
+QD4APgA+gD8APoA+AD5APoA+wD8APoA/AD/AP8A/QD9APwA+QD2APUA9wD1APUA+gD7APoA
+wD7APsA/gAAAAAAAQABAAAAAAAAAAQABQAAAAMAAAD9AP4A+wD7AP0A/QD9AP0A/QD+AP0A
+AD4APcA9QD3APcA9wD8APwA+wD9AP8A+wD5APoA+AD5APsA+AD7AP0A/gAAAAIAAwAAAAAA
/gD8APwA/AD9AP4AAQABAAAAAgAFAAUAAgACAAEA/wD+AP4AAAABAAIAAAAAAAEA/wAAAAEA
AAAAAP4A/QABAAIAAAACAAIAAQABAAAAAAAAAAAAAAADAAMABAADAAIABQAFAAIAAQADAAEA
AgADAAIABAAEAAQABAAEAAMAAwAFAAQABgAGAAUABgAHAAcABQAEAAQAAwACAAAAAQABAAEA
AQADAAMABQADAAEAAAAAAP8A/gAAAAEAAgADAAYABwAEAAQAAwABAAEAAgAAAAEAAgABAAEA
AQAAAAAAAAACAAMAAAD/AAAAAgACAAEAAQACAAEAAAACAAEAAAD/AAAA/gD+AAAAAAAAAAEA
AAAAAAAAAAD+AP0A/QD9AP4A/gD/AAAA/wD/AP0A/QD9AP0A/QD9AP4A/gD+AP4AAAAAAAAA
AAABAAAA/AD7APsA+wD8APwA/gAAAAAAAgAEAAMABAAFAAUABAAEAAIAAAAAAAEA/gD+AAAA
AAD/AAAAAAD+AP0A/QD/AP8A/AD9AP8AAAAAAAMABAAEAAUABAAFAAUABAAEAAMAAwADAAMA
BAAHAAcABAAEAAIAAwAFAAQABQAHAAcAAwADAAQAAwADAAUAAwACAAMAAQABAAQAAgAAAAAA
AAAAAAAA/wD+AP4A/QD+AP8A/wD+AP4A/gAAAP8A/gD/AP4A/wD/AP8A/gD7APoA+AD5APoA
+gD8AP0A/AD+AP8A/gD+APwA/AD9AP0A/AD9AP4A/QD/AAAAAAAAAAAAAgAAAAAA/wD/AAAA
AAAAAP8A/wAAAAEAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQADAAIA
AAD+AP8AAAAAAAAAAgACAAEAAgABAAAAAAABAAAAAAAAAP8A/wABAAAAAQABAAAAAAACAAMA
AQADAAQAAwABAAEAAQAAAAEAAwACAAIAAgAAAAAA/wD+AP4AAAAAAAAA/wD/AP8A/wD/AAAA
AAAAAAAA/wD+AAAAAQAAAP4A/wD/AP4A/gAAAAAAAAAAAAIAAQAAAAEAAQAAAAEA/wD+AAAA
/wD/AAAAAAACAAAAAQACAAEAAQAAAAAAAAAAAAAAAAACAAIAAQADAAMAAwACAAIAAQAAAAAA
AAD/AAAAAAD/AP8AAAAAAP4A/gD9AP0A/QD9AP4A/wD/AP8A/wAAAAAA/wD+AP4A/gD9AP0A
/gD9AP8AAAAAAAAAAAD/AP4A/gD+APwA/QD9AP4A/QD+AAAAAAAAAAAA/wD+AP4A/gD9AP4A
/QD+AAAAAAAAAAAAAAACAAAAAAAAAAAA/gD+AP4A/wD/AAAAAAAAAAAAAAD/AP8AAAD+AP0A
/QD/AAAAAAD/AAAAAgAAAAAAAAD/AP4A/gD9AP0A/QD9AP4AAAABAAAA/wAAAP8A/gD+AP4A
/gD+AP8AAAD/AAAAAQAAAAAAAQAAAP4A/wD/AP4A/gD+AP4A/wAAAAAAAAD/AAAA/wD+AP8A
AAAAAAEAAQACAAIAAwACAAIAAgADAAEAAAABAAIAAwAEAAQABQAFAAMAAgABAAEAAQAAAAEA
AgADAAIAAgABAAAAAAAAAAAAAAABAAEAAgADAAMAAgACAAMAAQABAAIAAgABAAAAAAAAAAAA
AAAAAAEAAQABAAEAAQADAAMAAgADAAMAAgADAAQABAAEAAMAAgACAAIAAgACAAEAAgABAAAA
AQABAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgABAAEAAAD+AP4AAAD/AP4A/wD/AP8A
/wAAAP8AAAAAAP4A/wD/AP8AAAAAAP8A/gD/AAAA/wD/AP8A/wD/AP4A/gD+AP8AAAAAAAAA
AAAAAP8AAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAAAAAQACAAEAAAAAAAEA
AAABAAEAAAAAAAAAAAAAAAEAAAAAAAEAAAAAAAAAAQABAAEAAAAAAAAAAQABAAEAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AP8AAAAAAP8A/gD/AAAA
/wD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP8A/wD/AP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AP8A/gAAAAAA
AAAAAAAA/wD/AP8A/wAAAAAAAAAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAP8A
/wD+AP8A/wAAAAAAAAD/AP8AAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAEAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAEAAgACAAEAAQABAAEAAgACAAIAAgABAAEA
AgADAAIAAQABAAMAAgACAAIAAgAAAAAAAQABAAEAAQAAAAAAAAABAAAAAAAAAAAA/wD/AAAA
AAAAAAAAAAAAAP8AAAAAAAAAAAABAAAAAAABAAAAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAA
AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAA/wD/AP8A/wAAAAAA/wD/AP8A/wD+AP4A
/wD+AP4A/gD+AP4A/wD/AP8AAAD/AP8A/wD/AP8A/gD+AP4A/wD/AP8AAAD/AAAAAAAAAP8A
/wD/AP8A/wD/AP8A/wAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA
AQAAAAAAAAAAAAAAAAAAAAAA/wD/AP8A/wD/AAAAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AP8A
/wD/AP8A/wD/AAAA/wD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAA
/wD/AAAAAAAAAAAAAAAAAAAAAAAAAP8A/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA/wD/AP8A/wD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAEAAQABAAEAAQAAAAAAAAAAAAAAAAABAAEAAgACAAEAAQABAAEAAAAAAAAAAAAAAAAA
AQABAAEAAQAAAAEAAQABAAAAAAAAAAAAAAAAAAEAAQABAAEAAgABAAAAAAAAAAAAAAAAAAEA
AQABAAEAAQAAAAEAAQAAAA==')
        samplingRate: 11025!

----- Method: SkeletonBaseInfo class>>point (in category 'parts bin') -----
point
        "self point openInHand"
        ^ EllipseMorph new extent: 24 @ 24;
        color: (Color r: 0.0 g: 0.8 b: 0.7);
        borderColor: (TranslucentColor r: 0.0 g: 0.8 b: 0.7 alpha: 0.4)
                 yourself!

----- Method: SkeletonBaseInfo class>>renameAllProtocol:to: (in category 'utility') -----
renameAllProtocol: before to: after
        "
        Change all method category.
        self renameAllProtocol: #'*skeleton-2003' to: #'obsolete-sk2003'.
        self renameAllProtocol: #'*skeleton-2003-var' to: #'obsolete-sk2003-var'
        self renameAllProtocol: #'*skeleton-velocity' to: #'obsolete-velocity'
        self renameAllProtocol: #'*skeleton-morph-sumim' to: #'*skeleton-connectors-sumim'
        "
        ProtoObject
                withAllSubclassesDo: [:class |
                        (class organization listAtCategoryNamed: before) isEmpty not
                                ifTrue: [class organization renameCategory: before toBe: after].
                        (class class organization listAtCategoryNamed: before) isEmpty not
                                ifTrue: [class organization renameCategory: before toBe: after]]!

----- Method: SkeletonBaseInfo class>>rice (in category 'sound library') -----
rice
SampledSound
        addLibrarySoundNamed: 'rice'
        samples: (self mimeStringToBuffer:
'CgAGAPQADAAAAAgA/gAIAPoABAAEAO4AAAAAAPoA9AAGAAIA+gAIAPIACgD6AAoA+gACAA4A
AAD+AP4ABADmAPQADAD2AP4AAAD2AAgAAAD0AA4A/gACAAgACAAAAAgAAgD2APgA/gDwAPoA
BgDyAAYA6AAWAPgAAgD8AAIAAgAOAPYABgAGAPoACgD6AAIA8gACAPYAAAAAAP4A+AD8AP4A
AgD8APwABAAOAPwACgAMAAIA/AACAPQAAgAAAAYA9gD8APwABAD6APgA8gAAAPgACAAAAAYA
AAAGAAQA/gAGAPoAAAAAAP4A+AAAAPgA+gAEAP4A/AD2APoABAAEAAgA9gAOAP4A/gAGAP4A
DAD+APAACAAAAPYAAgD0AP4A+gD6AAQA/AD6AAwA9AAAAP4ACgD6AAoA/gAIAP4AAgAGAAAA
+gD+APQA7gAAAPYA/gAAAPgA+gD6APwAAgAKAAIACAD6AAQAEgD6AAgA/gD2APgA+gD+APwA
9gD6AAQA/AD4AAQA/AAOAAAA+gAKABAA+gAEAAQA9AAGAAIA5gAIAP4A7gD6AAYABADuAPwA
DgD6AAAABgAGAPgACgAIAAoA+AACAAgA9gDyAAIA9gAEAPAA+gD8AAIABAAAAAIAAgD+AAYA
/gAIAAYA9gAIAAIAAAAGAPgA+gD+APoABADuAPQABgD4AAgA9gD+AAoAAgD8AAwAAgAKAAIA
AAAEAPoABgAEAPYA8gAEAPQA+AD2AAAABAAAAP4ABAD8AAwA/gAEAAoA/AAAAAwA/AD4AAAA
/AD8AP4A9gAAAPwA/gD6APgACAD+AAYAAgAIAPwACAACAP4ABgD+AAIA/gD6APoA9AD8APoA
/gD8APwABAD8AAQAAgD+AAQA/gAGAAIAAgAAAAAA/gD2AAQAAAACAPYA9gD8APoAAAAAAPwA
/AAGAPwACAAAAAQA/gAAAAgAAAD6AAIA/AD+APoA8gD8AAIAAAD6AP4A+gACAP4ABgD8AAYA
BAAAAAQABgD+APwA/gAEAAIA/AD2AP4A/AAAAPgAAgD4APwA/gD+AP4ACAAAAAQABAAAAAYA
AAD8AAYA9AAIAPwA+gD6AP4A/AD4APwA+AAGAPwABgAAAAAAAAAEAAAACAD+APoAAgD+AAAA
+gD8APwA+AD6AAAA/gD+AAAAAAAEAAIAAAAEAPgABAD8AAAABAACAPYABAD+AAAA/gD4AP4A
/AD+AAAA/gD+AAIA/AAEAAQA+gD8AAIA/gD8AAAABgACAAIA+AAAAP4A+gD+AAAA+gD+APoA
/AAAAAAAAAAAAP4ABgD+AAYA+gACAAIAAgD+AP4AAgD8APQAAAD8AP4A/gD8AP4A/gAAAAIA
BAAAAAIABAACAP4AAgAAAP4A+gD8AP4A/gAGAPQA/gACAPwABgD6AAYAAAAAAAIA/gACAAQA
BAD6AP4A/gD6APwAAgD6APwA/AAAAAQA/gAAAPwAAAAAAAYA/AAAAA==')
        samplingRate: 11025!

----- Method: SkeletonBaseInfo class>>unstick (in category 'sound library') -----
unstick
SampledSound
        addLibrarySoundNamed: 'unstick'
        samples: (self mimeStringToBuffer:
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAADAAAAAAD+AP0A+gACAAQAAAAAAAAA
AAAAAP8AAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
/wAAAAAAAAABAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAQD/AAAAAQAAAP8AAQACAP4AAQATAAAA/wAKAPQA
9gD8APUABQD/APQACQAEAAQAAAAFAAQAAAAAAPsA/QD3AP0A/gAGAAUABAAGAAIA/gD/AAEA
AAD/AAAAAQABAAQAAwAAAAAA/gD9AP4A/wD/AP4AAAABAAAAAAABAAAA/wABAP4AAAAFAAQA
+gAHAAEAAAABAAAA/QD8AAAA/AABAAEAAAACAAAAAAABAAAAAAAAAAEAAAAAAAIAAgAAAAAA
AAD+APwAAAAAAAAAAAAAAAAA/AD9AAAAAgADAAAABAAAAAAAAQABAAAAAAAAAAAAAAD/AAAA
/QD3ABUACQDmAP8A7gD6APwAEAAAAA4ABAD/AP8AAAD8AAAA/QAAAP0AAgAEAAMAAQABAP4A
/AD+AP0AAQACAP8AAAAEAAAAAAACAAEA/wD+AAAAAAAAAAAA/wAAAP8A/AD/AAAAAAABAAEA
/wD9AAIAAQAEAAMAAAABAAUAAAAAAP0AAwD6APwA/gABAAAAAQD/AAAAAgD+AAAAAAD+AAAA
AAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQACAP4AAAD+AAIAAAAAAAIAAAABAAAAAAABAAAA
AQAAAAAAAAD/AP8AAQAAAAAAAAAAAAAAAAAAAP8AAAAAAAAA/gABAAAAAAABAAAAAAABAAEA
AAAAAAAAAAD/AAAAAAAAAP8AAAAAAP8A/wAAAAIAAAAAAAAAAQAAAAAAAAD9AAAA/gAAAAAA
AwACAAAAAAD/AP8AAQAAAAAA/wAAAAAA/gAAAAAAAQAAAAAAAAD/AAEAAAD6AAMAAAACAP8A
AgD8APIA9wALABMABAD/APoA9gD/AAMACAAGAAUAAgD+APoA9wD7AP4AAgAAAAMABgAEAAEA
/AD9AP8A/wABAAQAAQAAAP4A/gD+AP8A/wD6AAUABQAQABAAAADsANcA8QD0ABoADwAIAAYA
AwD9AAIAAwD6APsAAQABAAQACwAEAP0A/gD8AP8AAwADAAAAAgD+AAAA/wD/AP8AAgACAAAA
AAD8AP0AAAD+AAAAAAAAAPwABQADAAAABQD/AP8A/AD9AP0AAAACAAQAAwAAAP8A/QD+AAAA
/gAAAAEAAAADAAAABAD+AAAA+wD/AAAAAAAFAAQAAQD+AP4A/QABAAIAAQAAAP8A/wAAAP8A
AQABAAEAAQACAAAAAAAAAP4A/QD/AP4AAAACAAIAAAABAAAAAAD/AP8A/wD+AAAA/gAAAAIA
AAACAAQAAAD/APsA/QD8AAMAAQADAAAAAQD+AP8AAAD+AAAAAAAAAAIAAQAAAAAABQAHAAAA
DQAAAOwA8wDvAAkA/AAOAAkAAQD8AAIAAAD+AAQACgD0AAwA/ADyAAoA4QD+AAcA+wAAAAoA
AwD9AAYADAD9AAwAAwAHAPkACQD2APgABgDzAPwABQD6AAUAAgD7AAIAAAD/AP4ABAAGAAEA
/wD+APwAAwABAAAAAAABAP8AAAD8AP0A/wD/AAAAAAACAAAABAABAAAAAAAKAPgAAgAAAAAA
9wAHAP4A9wACAAQA+AAIAAwADAAJAOsA9ADeAAAAJwADAAUADADtAOAADQD1AP8AEgD1APQA
CwAaAP8ABwABAOkABAAAAP4AAgAAAAAACQAJAAAAAQAGAPkA/QD/APYA+gAAAAEABAALAAIA
AQD/APkA/gAJAPUAAAADAPwA/AACAAAAAQAGAAUA/AD9APcA9gADAAoAAgADAP8A/QAHAP0A
/QD/AP4AAAAJAAMAAQABAPwA/gAAAPoABgD1AAEAAwAHAAAAAAABAPwAAQAEAP8A/AD+AAMA
AgAAAPsA/wD7AAEAAgD/AAAA/wAAAAIABAABAAEA/QD+AAIA/gACAP8AAAD+AAAAAQABAPsA
AAACAAEAAQAAAP0A+gAAAP4AAwD/AP0A/gD4APgAJAAFAAkA/AABAOAAAgDwAAIACgAGAA0A
FAAMAPoABwDTAOoAAQDxABoADgD+AAoA/gAFAP0A+gD9APcA/AAEAAMABgAIAP0ABgABAPsA
/gD9APsAAgACAP4A/gAMAAUAAAAFAPoA8QD8APkAAAAKAAUABwD/AAAA/AD8AAIA9wACAAcA
AAAFAPoA/QACAP4A+gADAPwA+wACABQA/AALAPYA+gDsABAABgAGAAEABAD+APsABgDyAO0A
AAD5AAcAEQAHAAIABAAAAP8AAAD9APcA/QAEAAYACQAHAPoA+wD0APUAAAD+AAsACgAHAAYA
AQAEAAAAAQD8APwA/gAAAAEABAAAAAIAAgAAAP4AAAD/AP0A/AAAAAEABgABAP8A/wAAAAAA
AAD8AP8A/QD5AAAAAwAAAAMAAAD+APwA/AAAAP4AAQAAAP8A/QDwAAkA/gAHAAoA/QAAAPsA
AAD/AAQAAAAAAAAAAAABAAIABwAAAAAA/QD8AP8AAAACAAIAAAAAAP0AAgAAAAQAAAAAAP0A
/gAAAAIACAAAAAEA+AD5AAUA/gAHAAEABwAAAAAAAAD+AP0AAQABAAAAAQAAAAAAAAD9AAAA
AAD/AAMABgAHAAEA9gAAAOYABAD6AAAABAAIAAEAAAAAAP0AAAD/AAAA/gD/AAIA/wD/AAEA
AgD+AAQAAQABAAEA/wD8AAAA/QAAAAMAAQAAAP8A/AD8AAEA/gD/AAAAAAAAAAEAAQACAP8A
AwAAAAAAAAAAAAAAAQAAAP4A/gD/AAAAAAAEAAMAAAAAAAAAAQABAAIAAAD/AAAA/AD/AP8A
/AAAAAEAAAABAAMA/gAAAAAAAAABAAAAAQAAAAIAAgADAAEAAQABAAIAAQAAAAAA/AD8APoA
/QAAAAIAAgABAAIAAwACAP4A/gD3APUA+gAEAAkACgABAP8A9gAAAAAAAQD/AAEAAAACAP4A
AQD+AAEA/wAAAAEAAQAAAAEA/wAAAAAAAAAAAP4A+wAHAAQA7AAIAPkA+wAGAAoA9gAKAPsA
AgD6AAIAAQADAAQAAQACAAEAAQD/AAAA/gD/AP0AAAAAAAAAAQAAAPwAAQD/AAEABAAAAP4A
AwD3AAAAAAADAAUABQABAAAA+gD9APsA+gAAAAEAAAD9AAIAAAAFAP0ABAAAAAQAAAADAAEA
AQAAAAAAAQACAAMAAQADAAAAAgD/AAEA/QD8AP4A/gD9AP4AAwACAP4AAAD9AP4A/QAAAP8A
AwAFAAEABAACAPwAAAAAAAAAAwABAP4AAAD/AP8A/AD9AAQA/QAGAAQABgD7APwA+QD6AP0A
/QADAAMABgADAAAA/gD8AAMA/QDuABYA+wAbAPoABQDzAPgAAAD6AAcAAgAEAP0ABwAAAAAA
AAADAP4A/gD8AAIA/AACAP0ACgAAAAcAAAABAPsAAwD/AP8AAAADAAMAAAAEAP8A/gD+AAEA
AAABAAEAAAD7APwAAAD+AAEAAAD/AP8AAQAAAAEAAAAAAP4AAQD/AAAAAQAEAP8A9wABAP4A
9QAAAP8AFADzAAAABgD2ABIAAAAAAAEA+QD+AAQAAAAHAP4AAgAAAAMABQACAP4AAAD7AP4A
/gABAAAAAQD/AAAAAAABAAEA/QD+AAEAAAAEAAIAAAAAAP0A/AD8AAIABgAEAP4A/gD6APwA
BgAAAAgA/AABAPoAAAD+AAMA/gAAAP8A/wAAAP8AAgAAAAAA/wD/AAAAAAABAAAA/wACAAAA
AAAAAP8AAgADAP0A/gAJAAEABQD6AAAAAgD+AAgA/QD7APgADAD4AA8A+AAGAPYAAAAAAAIA
AQACAP8ABQAAAAAA/wAAAAAA/wABAP8AAgD+AAAA+gAAAAUABQADAAAA+gD/AAEAAwD9AAIA
/gAFAP4A/QD/AP0AAgD+AAEA+wAQAAAA9wDmAOgA+gD4ABcAGAALAAcAAgD9APUACQACAAsA
DADoAOEA9QDvAAQAHAAYABAACgD/APcA9wAEAAkAAwAKAPoA+gAFAAAAAAD5APcA+wACAAYA
AQD/AP4A+AD7AAAAAQAAAAAA/gD/AP8A/gABAAIA/gD+AAAA/QD9AAIABQAAAAAA/wAAAPwA
/AADAAEAAAAAAAAA/wAAAAQAAAADAAAAAQAAAAMABQAAAAEA/AAAAP0ADAD/AAUA+gADAOwA
AQDoAA0AAAAeAPYACgD5APUAAwABAAIAAAAEAO4ADQARAAUAEAAGABsA6wAAAPsACAD7APgA
6gAFAAEAEAAGAP8A9AD7APkA+QD5AAEABAD/AP8AAAD+APoABAD+AP8A+wD6AAAAAwD+APkA
/gADAAAAAQD/APwA/gD/AAAA/wADAAUA/wAAAAIAAAABAAMAAQAAAAAAAAAAAP8AAgAAAAIA
AwAAAAEAAQD/AAEAAQABAAQAAgACAP8AAQACAAIA/AD/AP4AAgADAAIAAQAAAP4AAAAAAAAA
AgAAAAMA/QD9AP8ABAACAP8A/wAAAP0AAQABAAAA/wAAAP4AAAAAAP4AAAAAAP8A/gD+AAAA
AAD/AAAAAAD+AAIAAAAAAAAA/gAAAAAAAQD8AAAAAQAEAP8A/gD9AAIAAQAAAAEAAwAAAAEA
AAAEAP8AAAAAAAAA/wAAAP8AAAD+AP8AAAABAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAP8A
AAABAAEAAQABAAAAAAAAAAAAAAAAAAAA/wD/AAEAAAAAAAAAAAAAAP8AAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA/wAAAAAAAQAAAAEAAAABAAAAAAAAAAAAAAAAAP8AAAAAAAEAAAAAAAAAAAAAAAAA
AAAAAP8A/wAAAP0AAQAAAAEA/wAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAA/wAAAAAA
AAAAAAAAAAAAAAAAAQD/AAAA/wAAAAAA/wD/AP8AAAAAAAAAAQAAAP8AAAAAAAAAAAABAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wD/AP8AAAABAAEAAgAAAP8AAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAIAPkABQD8AAMA/gABAAAA/wD/AAMAAAAAAAEA
AAAAAAAAAAD/AAAAAAD/AP8AAAD6AAAADgD8ABEA8wAJAPQA/QD/AAIAAQACAAIAAAABAAAA
/wAAAAEAAAACAAAAAAAAAAAAAQD/AAIAAAAAAP8A/gD9AAIA/AAGAAAAAQAAAAAA/gD/AP4A
/wAAAAYA/AAMAPkAAwD6AP8ABgACAAAAAAD4AAEA/QACAAAA/wAGAPsAAgD8AAEAAAAAAAAA
AAD7AAEACAD6ABAA8wAHAPgA/wACAAIABAABAAAAAAAAAAEA/gAAAPwAAAACAAAAAgD/AAAA
/wD/AAAA/wABAAEAAAD/AP0A/QD/AAAAAgABAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAAAP8A
AAD+AAAAAAAAAAEAAgAAAP4AAgABAP8AAwD9AAQA/QADAAAA/wD/AAAAAAAAAAEAAAAAAAEA
/wAAAAAAAAAAAAAAAAAAAAAAAQAAAAAA/wD/AAEA/wAAAAAAAAD/AP8AAAAAAPwA/QAWAPcA
9gABAAMA+gD9AAsAAAD4AAkABgD3AAEABAD4AP4AAAAAAP8AAQAEAAAAAAACAAMABQD+AAAA
AAD/AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAA/wAAAAAAAAD/AAEAAAAAAP8A
AAD/AP8AAAACAP4A/gABAAAA/gD/AAEAAAD/AAAAAgD9AP0AAQAAAAEA/gD/AP8AAQAAAAAA
AAD/AAAAAAAAAP4AAAACAAEAAQAAAAAAAAAAAAAAAAAAAP8AAwACAAAAAQD8AAMA/gADAAAA
AQD/AP8A/wAAAAQA/wABAAMA/QAJAPgABAD+AP8AAAABAAAAAAD9AAEA/QAAAAAAAwAAAP8A
/QAAAP8AAAABAAEAAgD6AP0ABAD3AAUA/gD/AAAAAAACAAAABAABAAIAAQAAAAEAAAACAAAA
AAADAAEAAAD7AP4A/gD/AAEAAQD/APwAAAADAAEAAwD+AP0AAAD/AAEABQADAP8A/AABAAIA
AAAAAAAABAACAAAA+wD7AAsACQAGAPoABwD/APcA/AD3AP8A/wAFAAEAAAD9AAAA/QAAAP4A
AAAAAAAA/wAAAAIABAADAAoAAAAHAP8ABAD/AAIAAQADAPwA/gD9APoAAgD+AP4A/gABAAAA
AAAAAP4AAQAHABAAGQDoAOEA1AAGAAQAIwATAPkA7wDtAP4ABwAZAP4A+wAFAPoACAD/AAQA
AAD3AP0A+QABAAYA/AAEAPsABQAAAAIA+wACAAAAAAAAAAAAAgAAAAAABAAHAPkA+wD6AP8A
BgALAAEAAQD5APwAAAACAAsAAwAAAPUA+wACAAMABAADAP4AAgD8AAIA/gD7AAIADADxAA8A
8QADAAIA/AD5ANoA9gATAA0ANAAeAPYAwwDOAAEALQA8ACQA2gDDAOcAHQAzACoACwDuAOsA
/wAKAA4ABAD7AO8AAgABAAIA+gAAAAgA+gAFAPAAAADtAAYAAgAJAPEA/gD7AAEA6wD8AAEA
BAAEAPAA7QD+AAcAAgANAOoABgD1AAAAEAAbAPEA9AD6ANAA+AADAAQAFwAdAAQADwAPAPkA
CgD4APoA6wD6APsAAQAAAAQA7AADAPEA/QAXAN4AAwAHAP0AHwAHAA0A7wAAABcACQANAAsA
BAD0AP0A9QD+AAUACQAAAAgAAwADAPkA/QD5AAUA/QAHAAQA+AD1AAAA+wAVABcA1ADsAAQA
/gAgAOkADAAJAAsAzwDsAOMAIQBGACYA6QDmAM4A8QArAAYAHgDkACkAEgA5ABQA6QDGAN8A
5QAcAA4A8wDdAOcA8AAQAB4AHgAKAO0ACQD4AAYA+wDyAPkAHwASAPYA9wD6AO4ACQAFAAMA
+AD1AA0AIgAYAOUADADWAOMA6gD7APwA6QDvAPcABgACABoADQAOAPMA+QD6APUA+gACAAMA
8wAHAA8ACQAIAAoA8ADyAPcACgATABsAEQAQAAwABAD4AAsABAANAAIABwD4AP0ABQD/AAsA
BAAEAPoABAAFAAEAEgD7AAQABwALAAgAAAAKAPUA7gD0APUA+gAUAPsA/wAEAAoAAAD5APQA
9QD/APoABQACAPkACAAAAAMA8wDwAPcA7wD/AAsACwD4ABEA8QDxABcAIAAQAPgA5wDlAO4A
+AAHAA4ACQDyAPwA8ADwAPcA+wD3AAAA/gD/AAAACgABAP8ABgAKAAIA+QD/APoA6QAmAA4A
9QDxAAYA2QDkAO0AAAA3ACIAHAD+AP0A3QDrAAIAHAAUAPMA6QDxAAMACgD3APUA+AAGAAIA
CgDuAAoA+QAFAOIAIgAHABoAAQACAO8AAQDwAP4AEQALAAsA6gAAAP0ACQAFAAAABQD9AAEA
9wAKABUA/wD6APgA/gAAAAsA8QD7AAAAEQD9AAAA/wD3AAQAAwD9AA8A8QAMAAAA+QAIAP4A
CADyAAgA+gAUAAMA+wDsAPUA/gAAAAIACADzAAQA/AD1ABMAAQALAAYADQD/AAoA+wD9AAkA
9QD9APsABQD5AAEA/wD/APoADADoAPEA/QAQAAQABwD2ABUAAAAHAAsACgACAPUAAwABAP4A
BAACAPwAFQDrAPAADgD6AAYACwDvAOUACQADAP8A9QD7AAIA8AD8AAQABgAHAAEA/wD4AAAA
/AD8AAIA+wAIAAAADQD8AAAABwAGAO4ABQAGAP8A9QAgAPMACwAFAAkAFQDvAP4A/wADAAYA
CgDlAOUA/gAAAAwAEAAbABIAAgACAAkA7wABAO8A9gD3AAAA4wD3ABUA8wAdAAQADgAAAAEA
FgD3APMA/wD9AP4A/gAIABkA9QDqAPsA5AD2ABQA6AADAPgABgAMAAUADwALAOsA9QD3APUA
CQAKAAwABAAAAPsA/gAHAP8A/QANAP8A/QABAAoAAAAIAP0ACgADAPgAAwAAAAAA9wADAAcA
AQAEAPcAAgD8AAAA+gD7AAgA/QDzAAAA8wAFAAcAJgD4AOEA8QDgAOsADwAPAOsACwD7AB8A
AgARAA8A1wDvAOoA5AANACEAFQAGAPoACQAAAA0AFgARAPcA/gD8AAoAAAD9AAEAAQDzAAYA
/QAAAPsA/QDwAPUA7gD2AAkABAABAAAA/QD8AAAAAAAYAAsAAAAAAP0A/gAHAPsA/wD8ABEA
/wAAAOoA7gD1ABgA+QAFAAsA7QD9APUA2ADmAPMABwATABoADAAHABQADgAOAAYACwAFAAcA
+AAAAAcAIAAcAPYA+ADjAN0ABgATABIADAD3AOIA+gAEAPgA/gASAAsAFAARAPQA6QAAAAIA
CAAEAAsAAAD8APUA/wD1APYA8wD3AAcA/QAIAAkA9QD7AP0ABAD8AAYAAwD4APUAAwAGAAUA
CQAGAPwA/gD+APkA/QAAAP8A/AAIAAMA9AD6AAQA9AAEAAgAGQANAAoA2gAMAOgA9gAZABEA
4AASAP8AAgAaAAgAAAAEAPkA9wDtAO4A8AD/APsAAAACAAgAEQAJAP0AAAAHAPIA/AAEAPcA
AAD5AAIA/wD2APQABgADAP0AAgAHAPkAAQAHAAUAAwAFAP4A/AAEAPwA/wABAAYACgAYAPYA
CQADAPQA+wD7AAgA/gAAAPMA+wABAPgADgAKAAkABADuAPkA+QD1AAMAAgAIAAUABQADABYA
CAD5AAYA+wD9AAAA/wAFAPoA/gAAAP0AAAD5APwABAAVAAIA8AD7AO4A+QD+APMA9wAEAAgA
EgAIAAIADAAAAAoA9AD8AP4A+gD5AAoA9gD/AAQAAQABAPsAAgADABgA/AAAAP4ADQD5AAAA
+gDxAPoA/wADAAAA+gAAAPUABwD7AAAAFAD2AAkA/wANAOcA/wAAAAAABADxAAwA9QADAP0A
BgAFAPIABQD0AAAA/wD4ABgA8QABAAEA/wAMAAEAAQD3ABIAAgAFAA4ACAD6AAMAAQAMAAYA
+gAEAAAABgAEAP0ADQD4ABEA8gD/APwA+AAEAP0ABAABAAAAAAD6AP4A+QD3APkAAAADAPgA
7wD5AAEAAgD8AP0A9wD6AAQACgD9AP4AAAAEAP0A/wAGAPoAAgACAPwAAgD9AP0A+wAFAAQA
AwADAAIAAQAEAAMA/wD+AAIAAQAGAP4A+gD9AAQAFwD9AAMAEQD4AAEADwAJAAgA/wD+AA4A
CwD3APIA8AD9AAQAAAD6APgA+QDxAPMAEwAhAPoABQDqAPcA7QANAAwADAD3AAIA8wADAPcA
BQD7AAIA/gADAAEA/QD5APsA+wD/AAgAAAAHAPoAAQD+AAgAAgABAP0A+wD7APwAAAAHAAAA
BQD9AAEA+QD3AO4A9gD6AAAA/wACAPoA+QA=')
        samplingRate: 22050!

----- Method: SkeletonBaseInfo class>>version (in category 'constant') -----
version
        ^ '0.4.1'!

----- Method: SkeletonBaseInfo>>packageName (in category 'naming') -----
packageName
        ^ 'Skeleton-Base'!

----- Method: SkeletonBaseInfo>>readmeText (in category 'introspection') -----
readmeText
        ^ 'Skeleton ', self class version, '

Skeleton is a easy scripting system with spreadsheet-like user interface.  It handles an etoy''s slot as a spread sheet''s cell. So user can describe declarative rules among morphs as spread sheet''s "=A1 +A2" style. It is similar with Visio''s "shape sheet", but Skeleton-sheet has more dynamic and real-time behavior.

Takashi Yamamiya <[hidden email]>
http://languagegame.org:8080/ggame/11

SkSheet example

2004-04-10
        Fix some dirty code (Remove references of Transcript, Fix a word in world menu).
        Support Babel.
'!

PackageInfo subclass: #SkeletonInfo
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkeletonInfo commentStamp: 'tak 3/30/2004 21:40' prior: 0!
I am a full Skeleton package information.!

----- Method: SkeletonInfo>>packageName (in category 'naming') -----
packageName
        ^ 'Skeleton'!

----- Method: Color>>asCellText (in category '*skeleton-base') -----
asCellText
        ^ '=', self asString!

----- Method: Object>>asCellText (in category '*skeleton-base') -----
asCellText
        ^ self asString!

----- Method: Object>>isSkObject (in category '*skeleton-base') -----
isSkObject
        ^ false!

----- Method: Object>>rule:do: (in category '*skeleton-base') -----
rule: sub do: aBlock
        ^ SkRule new
                observer: self
                subjects: sub
                rule: aBlock!

Object subclass: #SkCellScreenConverter
        instanceVariableNames: 'border grid xCache yCache offset cellTopLeft'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkCellScreenConverter commentStamp: 'tak 12/27/2003 16:55' prior: 0!
Main comment stating the purpose of this class and relevant relationship to other classes.

Possible useful expressions for doIt or printIt.

Structure:
border Number
model
grid SkGridMorph
xCache Array
yCache Array
offset Number topLeft of the cache
screenOfset Point
!

----- Method: SkCellScreenConverter class>>grid:border: (in category 'instance creation') -----
grid: anSkGridMorph border: aNumber
        ^ self new grid: anSkGridMorph border: aNumber
!

----- Method: SkCellScreenConverter>>cellAreaToScreen:topLeft: (in category 'accessing') -----
cellAreaToScreen: aRectangle topLeft: topLeft
        ^ (self cellToScreenRect: aRectangle topLeft topLeft: topLeft) topLeft - border corner: (self cellToScreenRect: aRectangle bottomRight - 1 topLeft: topLeft) bottomRight + border!

----- Method: SkCellScreenConverter>>cellToScreenRect:topLeft: (in category 'accessing') -----
cellToScreenRect: aPoint topLeft: topLeft
        | xRange yRange |
        (self extent containsPoint: aPoint)
                ifFalse: [self
                                createCacheFor: (self extent
                                                merge: (aPoint extent: 1 @ 1))].
        xRange _ xCache at: aPoint x - (cellTopLeft x + offset x) + 1.
        yRange _ yCache at: aPoint y - (cellTopLeft y + offset y) + 1.
        ^ (xRange first @ yRange first corner: xRange last @ yRange last)
                translateBy: topLeft!

----- Method: SkCellScreenConverter>>createCacheFor: (in category 'private') -----
createCacheFor: aRectangle
        "xCache = #{{left. right}. {left. right}. ...}"
        | first last screenOffset |
        offset _ aRectangle topLeft - cellTopLeft.
        screenOffset _ self createOffset: offset.
        xCache _ Array new: aRectangle width.
        first _ screenOffset x + border.
        aRectangle left
                to: aRectangle right - 1
                do: [:i |
                        last _ first + (grid
                                                        cellExtentAt: (grid globalToLocal: i @ 0)) x.
                        xCache at: i - aRectangle left + 1 put: {first. last}.
                        first _ last + border].
        yCache _ Array new: aRectangle height.
        first _ screenOffset y + border.
        aRectangle top
                to: aRectangle bottom - 1
                do: [:i |
                        last _ first + (grid
                                                        cellExtentAt: (grid globalToLocal: 0 @ i)) y.
                        yCache at: i - aRectangle top + 1 put: {first. last}.
                        first _ last + border]!

----- Method: SkCellScreenConverter>>createOffset: (in category 'private') -----
createOffset: aPoint
        | x y |
        x _ ((aPoint x min: 0)
                                to: (aPoint x max: 0) - 1)
                                inject: 0
                                into: [:sub :next | sub + (grid cellExtentAt: next @ 0) x + border].
        x _ aPoint x negative
                                ifTrue: [0 - x]
                                ifFalse: [x].
        y _ ((aPoint y min: 0)
                                to: (aPoint y max: 0) - 1)
                                inject: 0
                                into: [:sub :next | sub + (grid cellExtentAt: 0 @ next) y + border].
        y _ aPoint y negative
                                ifTrue: [0 - y]
                                ifFalse: [y].
        ^ x @ y!

----- Method: SkCellScreenConverter>>extent (in category 'accessing') -----
extent
        ^ cellTopLeft + offset extent: xCache size @ yCache size!

----- Method: SkCellScreenConverter>>grid:border: (in category 'initialization') -----
grid: aSkGridMorph border: aNumber
        border _ aNumber.
        grid _ aSkGridMorph.
        cellTopLeft _ aSkGridMorph visibleArea topLeft.
        self
                createCacheFor: (cellTopLeft extent: 1 @ 1)!

----- Method: SkCellScreenConverter>>screenToCell:topLeft: (in category 'accessing') -----
screenToCell: aPoint topLeft: topLeft
        "Convert screen position to cell position"
        | x y right left bottom top |
        aPoint x < topLeft x
                ifTrue: [x _ self extent left - 1.
                        left _ topLeft x.
                        [(left _ left - (grid cellExtentAt: x @ 0) x + border) > aPoint x]
                                whileTrue: [x _ x - 1]]
                ifFalse: [x _ self extent left.
                        right _ topLeft x.
                        [(right _ right + (grid cellExtentAt: x @ 0) x + border) < aPoint x]
                                whileTrue: [x _ x + 1]].
        aPoint y < topLeft y
                ifTrue: [y _ self extent top - 1.
                        top _ topLeft y.
                        [(top _ top - (grid cellExtentAt: 0 @ y) y + border) > aPoint y]
                                whileTrue: [y _ y - 1]]
                ifFalse: [y _ self extent top.
                        bottom _ topLeft y.
                        [(bottom _ bottom + (grid cellExtentAt: 0 @ y) y + border) < aPoint y]
                                whileTrue: [y _ y + 1]].
        ^ x @ y!

Object subclass: #SkColorSet
        instanceVariableNames: 'basic base label selected borderStyle selectedBorderStyle plug'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!
SkColorSet class
        instanceVariableNames: 'map default'!

!SkColorSet commentStamp: 'tak 12/20/2003 21:43' prior: 0!
This is a cache of color property.
!
SkColorSet class
        instanceVariableNames: 'map default'!

----- Method: SkColorSet class>>at: (in category 'accessing') -----
at: anObject
        ^ map
                at: anObject
                ifAbsent: [self
                                projectAt: anObject
                                ifAbsent: [default]]!

----- Method: SkColorSet class>>baseFor: (in category 'query') -----
baseFor: anObject
        ^ (self at: anObject) base!

----- Method: SkColorSet class>>basicFor: (in category 'query') -----
basicFor: anObject
        ^ (self at: anObject) basic!

----- Method: SkColorSet class>>borderStyleFor: (in category 'query') -----
borderStyleFor: anObject
        ^ (self at: anObject) borderStyle!

----- Method: SkColorSet class>>for:color: (in category 'accessing') -----
for: anObject color: color
        "Resist color for the morph"
        | property |
        property _ self new.
        property basic: color.
        map
                ifNil: [map _ WeakKeyDictionary new].
        map at: anObject put: property!

----- Method: SkColorSet class>>initialize (in category 'accessing') -----
initialize
        "It's read by system"
        "self initialize"
        map
                ifNil: [self reset]!

----- Method: SkColorSet class>>labelFor: (in category 'query') -----
labelFor: anObject
        ^ (self at: anObject) label!

----- Method: SkColorSet class>>map (in category 'accessing') -----
map
        "This is temporary implementation, see SkProxy comment"
        ^ map!

----- Method: SkColorSet class>>plugFor: (in category 'query') -----
plugFor: anObject
        ^ (self at: anObject) plug!

----- Method: SkColorSet class>>projectAt:ifAbsent: (in category 'accessing') -----
projectAt: anObject ifAbsent: aBlock
        | set colors |
        set _ SkProject current colorSet.
        set
                ifNil: [^ aBlock value].
        colors _ set
                                at: anObject
                                ifAbsent: [^ aBlock value].
        SkColorSet for: anObject color: colors basic.
        ^ colors!

----- Method: SkColorSet class>>reset (in category 'accessing') -----
reset
        "self reset"
        map := WeakKeyDictionary new.
        default := self new basic: Color blue!

----- Method: SkColorSet class>>selectedBorderStyleFor: (in category 'query') -----
selectedBorderStyleFor: anObject
        ^ (self at: anObject) selectedBorderStyle!

----- Method: SkColorSet class>>selectedFor: (in category 'query') -----
selectedFor: anObject
        ^ (self at: anObject) selected!

----- Method: SkColorSet>>base (in category 'accessing') -----
base
        "Answer the value of base"

        ^ base!

----- Method: SkColorSet>>basic (in category 'accessing') -----
basic
        ^basic!

----- Method: SkColorSet>>basic: (in category 'accessing') -----
basic: aColor
        | border |
        basic _ aColor.
        label _ aColor luminance > 0.9
                                ifTrue: [aColor alpha: aColor alpha]
                                ifFalse: [Color
                                                h: aColor hue
                                                s: aColor saturation * 0.5
                                                v: aColor brightness
                                                alpha: aColor alpha * 0.7].
        base _ aColor luminance > 0.9
                                ifTrue: [Color
                                                h: aColor hue
                                                s: 0.1
                                                v: aColor brightness - 0.05
                                                alpha: aColor alpha]
                                ifFalse: [Color
                                                h: aColor hue
                                                s: 0.08
                                                v: (aColor brightness * 2 max: 0.8)
                                                alpha: aColor alpha].
        border _ aColor luminance > 0.9
                                ifTrue: [Color
                                                h: aColor hue
                                                s: aColor saturation * 0.5
                                                v: aColor brightness - 0.2]
                                ifFalse: [Color
                                                h: aColor hue
                                                s: aColor saturation * 0.5
                                                v: aColor brightness].
        borderStyle _ BorderStyle color: border width: 1.
        selected _ aColor luminance > 0.95
                                ifTrue: [aColor]
                                ifFalse: [Color
                                                h: base hue
                                                s: base saturation
                                                v: base brightness - 0.1].
        selectedBorderStyle _ BorderStyle color: border lighter width: 1.
        plug _ base darker!

----- Method: SkColorSet>>borderStyle (in category 'accessing') -----
borderStyle
        "Answer the value of borderStyle"

        ^ borderStyle!

----- Method: SkColorSet>>label (in category 'accessing') -----
label
        "Answer the value of label"

        ^ label!

----- Method: SkColorSet>>plug (in category 'accessing') -----
plug
        ^ plug!

----- Method: SkColorSet>>selected (in category 'accessing') -----
selected
        "Answer the value of selected"

        ^ selected!

----- Method: SkColorSet>>selectedBorderStyle (in category 'accessing') -----
selectedBorderStyle
        "Answer the value of border"

        ^ selectedBorderStyle!

Object subclass: #SkNullCell
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkNullCell commentStamp: 'tak 12/7/2003 19:53' prior: 0!
The cell object is used when a cell is not modified yet.
!

SkNullCell subclass: #SkDictionaryCell
        instanceVariableNames: 'dictionary key isKey'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkDictionaryCell commentStamp: 'tak 12/30/2003 00:23' prior: 0!
I am a proxy of dictionary.!

----- Method: SkDictionaryCell class>>new (in category 'instance creation') -----
new
        self shouldNotImplement !

----- Method: SkDictionaryCell class>>newFor:key: (in category 'instance creation') -----
newFor: aSkDictionary key: aString
        ^ super new dictionary: aSkDictionary key: aString!

----- Method: SkDictionaryCell>>contents (in category 'accessing') -----
contents
        (dictionary includesPosition: key)
                ifTrue: [key x = 1
                                ifTrue: [^ (dictionary rowAt: key y) key].
                        key x = 2
                                ifTrue: [^ (dictionary rowAt: key y) value].
                        ^ ''].
        ^ dictionary
                nameAt: key
                ifAbsent: ['']!

----- Method: SkDictionaryCell>>contents: (in category 'accessing') -----
contents: anObject
        dictionary isLocked
                ifTrue: [^ self].
        key
                ifNil: [dictionary at: anObject asString put: '']
                ifNotNil: [self isKey
                                ifTrue: [dictionary removeAt: key.
                                        dictionary at: anObject asString put: '']
                                ifFalse: [dictionary at: key put: anObject]]!

----- Method: SkDictionaryCell>>dictionary:key: (in category 'initialization') -----
dictionary: aSkDictionary key: aString
        dictionary _ aSkDictionary.
        key _ aString!

----- Method: SkDictionaryCell>>editContents: (in category 'accessing') -----
editContents: anObject
        ^ self contents: anObject!

----- Method: SkDictionaryCell>>isKey (in category 'accessing') -----
isKey
        ^ isKey ifNil: [false]!

----- Method: SkDictionaryCell>>isKey: (in category 'accessing') -----
isKey: aBoolean
        isKey _ aBoolean!

----- Method: SkNullCell class>>evaluatorClass (in category 'accessing') -----
evaluatorClass
        ^ SkCompiler!

----- Method: SkNullCell>>contents (in category 'accessing') -----
contents
        ^ ''!

----- Method: SkNullCell>>contents: (in category 'accessing') -----
contents: anObject
        ^ ''!

----- Method: SkNullCell>>editContents: (in category 'accessing') -----
editContents: aText!

----- Method: SkNullCell>>formula (in category 'accessing') -----
formula
        ^ nil!

----- Method: SkNullCell>>hasCard (in category 'accessing') -----
hasCard
        ^ self contents isSkObject!

----- Method: SkNullCell>>hasFormula (in category 'accessing') -----
hasFormula
        ^ self formula notNil!

----- Method: SkNullCell>>hasUpdated (in category 'testing') -----
hasUpdated
        ^ false!

----- Method: SkNullCell>>label (in category 'accessing') -----
label
        ^ nil!

----- Method: SkNullCell>>morph (in category 'accessing') -----
morph
        ^ nil!

----- Method: SkNullCell>>player (in category 'accessing') -----
player
        ^ nil!

----- Method: SkNullCell>>printOn: (in category 'printing') -----
printOn: aStream
        super printOn: aStream.
        aStream nextPutAll: '('.
        aStream print: self identityHash;
                 nextPutAll: ')'!

----- Method: SkNullCell>>privateContents (in category 'accessing') -----
privateContents
        ^ self contents!

----- Method: SkNullCell>>referenceAt: (in category 'updating') -----
referenceAt: aPoint
        ^ #()!

----- Method: SkNullCell>>remember (in category 'accessing') -----
remember
!

----- Method: SkNullCell>>resolveContextOn:at: (in category 'updating') -----
resolveContextOn: holder at: pos!

----- Method: SkNullCell>>resolveFormulaOn:at: (in category 'updating') -----
resolveFormulaOn: sheet at: aPoint
!

----- Method: SkNullCell>>resolveOn:at: (in category 'updating') -----
resolveOn: sheet at: aPoint
!

----- Method: SkNullCell>>value (in category 'accessing') -----
value
        ^ ''!

SkNullCell subclass: #SkProxyCell
        instanceVariableNames: 'holderCell argCell'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkProxyCell commentStamp: 'tak 12/30/2003 14:07' prior: 0!
I represent the top of cells at card model.!

----- Method: SkProxyCell>>contents (in category 'accessing') -----
contents
        ^ holderCell contents!

----- Method: SkProxyCell>>contents: (in category 'accessing') -----
contents: anObject
        ^ holderCell contents: anObject
!

----- Method: SkProxyCell>>editContents: (in category 'accessing') -----
editContents: anObject
        ((anObject isString
                                or: [anObject isText])
                        and: [anObject first = $=])
                ifTrue: [^ argCell editContents: anObject]
                ifFalse: [^ holderCell editContents: anObject]!

----- Method: SkProxyCell>>formula (in category 'accessing') -----
formula
        ^ argCell formula!

----- Method: SkProxyCell>>hasUpdated (in category 'testing') -----
hasUpdated
        ^ holderCell hasUpdated!

----- Method: SkProxyCell>>holderCell (in category 'accessing') -----
holderCell
        ^ holderCell!

----- Method: SkProxyCell>>holderCell:argCell: (in category 'initialization') -----
holderCell: hCell argCell: aCell
        holderCell _ hCell.
        argCell _ aCell.!

----- Method: SkProxyCell>>privateContents (in category 'accessing') -----
privateContents
        ^ holderCell contents!

----- Method: SkProxyCell>>resolveFormulaOn:at: (in category 'updating') -----
resolveFormulaOn: sheet at: aPoint
        "I execute rule's formula.
        And chlid's card is build in this message as soon.
        So recursive call is not supported (Need more lasy solution).
"
        argCell resolveFormulaOn: sheet rule at: aPoint
!

SkNullCell subclass: #SkValueCell
        instanceVariableNames: 'formula block model getter setter oldValue'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkValueCell class>>new (in category 'instance creation') -----
new
        ^ super new initialize!

----- Method: SkValueCell>>block (in category 'accessing') -----
block
        ^ block!

----- Method: SkValueCell>>contents (in category 'accessing') -----
contents
        ^ (model perform: getter) ifNil: ['']!

----- Method: SkValueCell>>contents: (in category 'accessing') -----
contents: anObject
        model perform: setter with: anObject!

----- Method: SkValueCell>>editContents: (in category 'accessing') -----
editContents: anObject
        | string |
        (self formula: anObject)
                ifTrue: [^ self].
        anObject isNumber
                ifTrue: [^ self contents: anObject].
        string _ anObject isString
                                ifTrue: [anObject]
                                ifFalse: [(anObject isText
                                                        and: [anObject unembellished])
                                                ifTrue: [anObject asString]].
        string
                ifNotNil: [^ self
                                contents: ((self isLikeNumber: string)
                                                ifTrue: [string asNumber]
                                                ifFalse: [string])].
        self contents: anObject!

----- Method: SkValueCell>>formula (in category 'accessing') -----
formula
        ^ formula!

----- Method: SkValueCell>>formula: (in category 'accessing') -----
formula: anObject
        "Set formula if appropriate object.  
        Answer true if fomula"
        formula _ block _ nil.
        (anObject isString
                        or: [anObject isText])
                ifFalse: [^ false].
        anObject first = $=
                ifFalse: [^ false].
        formula _ anObject asString.
        block _ (Compiler new parserClass: SkParser)
                                evaluate: '[:holder :pos | ' , formula allButFirst , ']'
                                in: nil
                                to: nil
                                notifying: nil
                                ifFail: [Error signal].
        ^ true!

----- Method: SkValueCell>>hasUpdated (in category 'testing') -----
hasUpdated
        ^ self hasCard
                or: [(self contents = oldValue) not]!

----- Method: SkValueCell>>initialize (in category 'initialization') -----
initialize
        model _ ValueHolder new.
        setter _ #contents:.
        getter _ #contents!

----- Method: SkValueCell>>isLikeNumber: (in category 'support') -----
isLikeNumber: aString
        "
        self new isLikeNumber: '0'  
        self new isLikeNumber: '-3.141592'  
        self new isLikeNumber: 'word'  
        self new isLikeNumber: '10a'  
        "
        ^ aString = ([aString asNumber] on: Error do: [0]) asString!

----- Method: SkValueCell>>isNull (in category 'testing') -----
isNull
        ^ block isNil
                and: [self contents = '']!

----- Method: SkValueCell>>label (in category 'accessing') -----
label
        ^ (self contents isKindOf: Player)
                ifTrue: [self contents externalName]
                ifFalse: [(model isKindOf: Player)
                                ifTrue: [self slotName]]!

----- Method: SkValueCell>>modelAddDependent: (in category 'updating') -----
modelAddDependent: anObject
        model addDependent: anObject!

----- Method: SkValueCell>>modelRemoveDependent: (in category 'updating') -----
modelRemoveDependent: anObject
        model removeDependent: anObject!

----- Method: SkValueCell>>on:getter:setter: (in category 'accessing') -----
on: anObject getter: getSelector setter: setSelector
        model _ anObject.
        getter _ getSelector.
        setter _ setSelector!

----- Method: SkValueCell>>player (in category 'accessing') -----
player
        (self contents isKindOf: Player)
                ifTrue: [^ self contents].
        (model isKindOf: Player)
                ifTrue: [^ model].
        ^ super morph!

----- Method: SkValueCell>>printOn: (in category 'printing') -----
printOn: aStream
        aStream nextPutAll: '[' , self contents printString , ' | ' , formula printString , ']'.
        aStream nextPutAll: '('.
        aStream print: self identityHash;
                 nextPutAll: ')'!

----- Method: SkValueCell>>referenceAt: (in category 'updating') -----
referenceAt: aPoint
        | finder |
        ^ self hasCard
                ifTrue: [(self hasCard
                                        and: [self contents isInstance])
                                ifTrue: [(self contents referenceAt: aPoint) asSet]
                                ifFalse: [#()]]
                ifFalse: [finder _ SkRefFinder new.
                        self resolveOn: finder at: aPoint.
                        finder keys]!

----- Method: SkValueCell>>remember (in category 'accessing') -----
remember
        oldValue _ self contents!

----- Method: SkValueCell>>resolveCardOn:at: (in category 'updating') -----
resolveCardOn: sheet at: aPoint
        | ruleCase privateCase |
        ruleCase _ self contents.
        privateCase _ (sheet assuredCellAt: aPoint) privateContents.
        ruleCase = sheet
                ifTrue: [^ self].
        (privateCase isSkObject
                        and: [ruleCase rule = privateCase rule])
                ifFalse: [privateCase _ block value: sheet value: aPoint.
                        sheet at: aPoint put: privateCase.
                        privateCase holder: sheet at: aPoint.
                        self changed: #cardList].
        privateCase resolveOn: sheet!

----- Method: SkValueCell>>resolveFormulaOn:at: (in category 'updating') -----
resolveFormulaOn: sheet at: aPoint
        block
                ifNil: [^ self].
        sheet
                at: aPoint
                put: ([block value: sheet value: aPoint]
                                ifError: [:err :rcvr |
                                        false
                                                ifTrue: [Transcript show: err printString;
                                                                 cr;
                                                                 show: rcvr printString;
                                                                 cr].
                                        0])!

----- Method: SkValueCell>>resolveOn:at: (in category 'updating') -----
resolveOn: sheet at: aPoint
        "Execute card if I have already had card
        Execute formula if I doesn't have card"
        self hasFormula
                ifTrue: [self hasCard
                                ifTrue: [self resolveCardOn: sheet at: aPoint]
                                ifFalse: [self resolveFormulaOn: sheet at: aPoint]]!

----- Method: SkValueCell>>slotName (in category 'accessing') -----
slotName
        "See Player>>tearOffFancyWatcherFor:"
        | info watcherWording anInterface |
        info _ model slotInfoForGetter: getter.
        info
                ifNil: [anInterface _ Vocabulary eToyVocabulary
                                                methodInterfaceAt: getter
                                                ifAbsent: [].
                        watcherWording _ anInterface elementWording]
                ifNotNil: [watcherWording _ Utilities inherentSelectorForGetter: getter].
        ^ model tileReferringToSelf bePossessive labelMorph contents , ' ' , watcherWording!

----- Method: SkValueCell>>sourceCode (in category 'accessing') -----
sourceCode
        | code |
        code := block sourceCode.
        ^ code copyFrom: (code indexOf: $[)
                        + 1 to: (code lastIndexOf: $])
                        - 1!

----- Method: SkValueCell>>veryDeepInner: (in category 'coping') -----
veryDeepInner: deepCopier
        "block is not copied"
        model _ model veryDeepCopyWith: deepCopier.
        getter _ getter veryDeepCopyWith: deepCopier.
        setter _ setter veryDeepCopyWith: deepCopier.
        oldValue _ oldValue veryDeepCopyWith: deepCopier.
!

Object subclass: #SkObject
        instanceVariableNames: ''
        classVariableNames: 'NullCell Root'
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkObject commentStamp: 'tak 1/11/2004 13:57' prior: 0!
I am a base class of Skeleton object.!

SkObject subclass: #SkLibrary
        instanceVariableNames: 'args direction'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

SkLibrary subclass: #SkAverage
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base-Sheet'!

----- Method: SkAverage class>>defaultColor (in category 'instance creation') -----
defaultColor
        ^ (TranslucentColor r: 0.484 g: 0.806 b: 0.0 alpha: 0.667)!

----- Method: SkAverage>>resolve (in category 'updating') -----
resolve
        | elements |
        args size < 2 ifTrue: [^self].
        elements _ args allButFirst
                        collect: [:each | each contents].
        args first contents: (elements sum) / elements size!

SkLibrary subclass: #SkCopy
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base-Sheet'!

----- Method: SkCopy>>resolve (in category 'updating') -----
resolve
        | first |
        args isEmpty
                ifTrue: [^ self].
        first _ args first contents.
        args allButFirst
                do: [:each | each contents: first copy]!

SkLibrary subclass: #SkCount
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base-Sheet'!

----- Method: SkCount class>>defaultColor (in category 'instance creation') -----
defaultColor
        ^(TranslucentColor r: 0.226 g: 0.258 b: 1.0 alpha: 0.812)!

----- Method: SkCount>>resolve (in category 'updating') -----
resolve
        args withIndexDo: [ :each :index | each contents: index].
!

SkLibrary subclass: #SkDistance
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base-Sheet'!

----- Method: SkDistance class>>defaultColor (in category 'instance creation') -----
defaultColor
        ^ (TranslucentColor r: 0.806 g: 0.0 b: 0.065 alpha: 0.745)!

----- Method: SkDistance>>initialize (in category 'initialization') -----
initialize
        super initialize.
        args _ {SkValueCell new. SkValueCell new. SkValueCell new}!

----- Method: SkDistance>>resolve (in category 'updating') -----
resolve
        | m1 m2 distance |
        args size < 3
                ifTrue: [^ self].
        m1 _ (args first contents isKindOf: Player)
                                ifTrue: [args first contents costume]
                                ifFalse: [^ self].
        m2 _ (args second contents isKindOf: Player)
                                ifTrue: [args second contents costume]
                                ifFalse: [^ self].
        distance _ args third contents isNumber
                                ifTrue: [args third contents]
                                ifFalse: [^ self].
        self
                setDistanceFrom: m1
                to: m2
                distance: distance!

----- Method: SkDistance>>setDistanceFrom:to:distance: (in category 'updating') -----
setDistanceFrom: m1 to: m2 distance: distance
        | goal |
        goal _ m1 position direction2: m2 position distance: distance.
        m2 position: goal.
!

----- Method: SkDistance>>size: (in category 'accessing') -----
size: aNumber
!

----- Method: SkDistance>>wantsUpdate (in category 'updating') -----
wantsUpdate
        ^ true!

----- Method: SkLibrary class>>collectDependents (in category 'planning') -----
collectDependents
        ^ #()!

----- Method: SkLibrary class>>defaultColor (in category 'instance creation') -----
defaultColor
        ^ TranslucentColor
                r: 0.0
                g: 0.71
                b: 0.806
                alpha: 0.745!

----- Method: SkLibrary class>>direction: (in category 'instance creation') -----
direction: aSymbol
        ^self new direction: aSymbol!

----- Method: SkLibrary class>>direction:size: (in category 'instance creation') -----
direction: direction size: aNumber
        | instance |
        instance _ self new.
        instance direction: direction.
        instance size: aNumber.
        ^ instance!

----- Method: SkLibrary class>>wantsUpdate (in category 'testing') -----
wantsUpdate
        ^ false!

----- Method: SkLibrary>>argPositions (in category 'arg accessing') -----
argPositions
        ^ (1 to: args size)
                collect: [:index | index @ 1]!

----- Method: SkLibrary>>args (in category 'accessing') -----
args
        ^ args!

----- Method: SkLibrary>>attachProject (in category 'structure') -----
attachProject
!

----- Method: SkLibrary>>cardList: (in category 'cell accessing') -----
cardList: aRectangle
        ^ #()!

----- Method: SkLibrary>>cellAt:ifAbsent: (in category 'cell accessing') -----
cellAt: key ifAbsent: aBlock
        key class = Point
                ifTrue: [key y = 1
                                ifTrue: [key x <= args size
                                                ifTrue: [^ args at: key x ifAbsent: aBlock]]].
        ^ aBlock value!

----- Method: SkLibrary>>direction (in category 'accessing') -----
direction
        ^ direction!

----- Method: SkLibrary>>direction: (in category 'accessing') -----
direction: aSymbol
        direction _ aSymbol!

----- Method: SkLibrary>>holder:at: (in category 'holder and card') -----
holder: aSkSheet at: aPoint
        | holderCell |
        self initializeArgs.
        (self referenceAt: aPoint)
                withIndexDo: [:pos :index |
                        holderCell _ aSkSheet assuredCellAt: pos.
                        holderCell modelAddDependent: self.
                        args at: index put: holderCell].
        self update: #contents.!

----- Method: SkLibrary>>initialize (in category 'initialization') -----
initialize
        super initialize.
        self initializeArgs.
        direction _ #right.
!

----- Method: SkLibrary>>initializeArgs (in category 'initialization') -----
initializeArgs
        args
                ifNil: [args _ #()]
                ifNotNil: [args
                                do: [:each | each class = SkValueCell
                                                ifTrue: [each modelRemoveDependent: self]]]!

----- Method: SkLibrary>>initializeArgs: (in category 'initialization') -----
initializeArgs: aNumber
        self initializeArgs.
        args _ Array new: aNumber.
        args
                withIndexDo: [:each :index |
                        | cell |
                        cell _ SkValueCell new.
                        cell modelAddDependent: self.
                        args at: index put: cell]!

----- Method: SkLibrary>>parent (in category 'structure') -----
parent
        ^ self rule parent!

----- Method: SkLibrary>>referenceAt: (in category 'arg accessing') -----
referenceAt: aPoint
        "Answer the dependents object's point"
        ^ self argPositions
                collect: [:each | self pointForHolder: aPoint at: each]!

----- Method: SkLibrary>>releaseHolder (in category 'holder and card') -----
releaseHolder
        self initializeArgs: 3.
        super releaseHolder!

----- Method: SkLibrary>>resolve (in category 'updating') -----
resolve!

----- Method: SkLibrary>>resolveOn: (in category 'updating') -----
resolveOn: sheet
        [self resolve]
                ifError: [:err :rcvr |
                        false
                                ifTrue: [Transcript show: err printString;
                                                 cr;
                                                 show: rcvr printString;
                                                 cr].
                        0]!

----- Method: SkLibrary>>rule (in category 'structure') -----
rule
        ^ self class!

----- Method: SkLibrary>>size (in category 'accessing') -----
size
        ^ args size!

----- Method: SkLibrary>>size: (in category 'accessing') -----
size: aNumber
        args _ Array new: aNumber.
        args _ args
                                collect: [:each | SkValueCell new]!

----- Method: SkLibrary>>wantsSteps (in category 'updating') -----
wantsSteps
        ^ true!

SkLibrary subclass: #SkName
        instanceVariableNames: 'holder'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base-Sheet'!

----- Method: SkName class>>defaultColor (in category 'instance creation') -----
defaultColor
        ^ (TranslucentColor r: 0.581 g: 0.581 b: 0.581 alpha: 0.682)!

----- Method: SkName>>cell (in category 'accessing') -----
cell
        ^ args second!

----- Method: SkName>>holder:at: (in category 'arg accessing') -----
holder: aSkSheet at: aPoint
        super holder: aSkSheet at: aPoint.
        holder _ aSkSheet.
        holder updateKeys!

----- Method: SkName>>initialize (in category 'initialization') -----
initialize
        super initialize.
        args _ {SkValueCell new. SkValueCell new}!

----- Method: SkName>>key (in category 'accessing') -----
key
        ^ args first contents!

----- Method: SkName>>releaseHolder (in category 'holder and card') -----
releaseHolder
        holder removeAt: self key.
        holder updateKeys.
        super releaseHolder!

----- Method: SkName>>resolve (in category 'updating') -----
resolve
        args first hasUpdated ifTrue: [holder updateKeys]!

----- Method: SkName>>size: (in category 'accessing') -----
size: aNumber
!

SkLibrary subclass: #SkSum
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base-Sheet'!

----- Method: SkSum class>>defaultColor (in category 'instance creation') -----
defaultColor
        ^ (TranslucentColor r: 0.484 g: 0.806 b: 0.0 alpha: 0.667)!

----- Method: SkSum>>resolve (in category 'updating') -----
resolve
        args first contents: (args allButFirst
                        collect: [:each | each contents]) sum!

SkObject subclass: #SkNamed
        instanceVariableNames: 'parent'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkNamed commentStamp: 'tak 1/11/2004 13:58' prior: 0!
I am a abstract class of Skeleton object that has a name.

parent SkObject!

SkNamed subclass: #SkMap
        instanceVariableNames: 'map'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

SkMap subclass: #SkCollection
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkCollection commentStamp: 'tak 1/22/2004 08:41' prior: 0!
SkCollection open!

----- Method: SkCollection>>add: (in category 'accessing') -----
add: anObject
        map add: anObject.
        self changed: #cardList.!

----- Method: SkCollection>>cardPositions (in category 'accessing') -----
cardPositions
        ^ (1 to: map size)
                collect: [:each | 1 @ (each + 1)]!

----- Method: SkCollection>>cellAt:ifAbsent: (in category 'cell accessing') -----
cellAt: key ifAbsent: aBlock
        | contents |
        (self isApplicableKey: key)
                ifTrue: [contents _ map at: (key - 1) y ifAbsent: aBlock.
                        ^ SkValueCell new contents: contents]
                ifFalse: [^ aBlock value]!

----- Method: SkCollection>>do: (in category 'enumrating') -----
do: aBlock
        map do: aBlock!

----- Method: SkCollection>>includes: (in category 'testing') -----
includes: anObject
        ^ map includes: anObject!

----- Method: SkCollection>>initialize (in category 'initialization') -----
initialize
        super initialize.
        map _ OrderedCollection new.
!

----- Method: SkCollection>>isApplicableKey: (in category 'testing') -----
isApplicableKey: anObject
        anObject class == Point
                ifFalse: [^ false].
        anObject x = 1
                ifFalse: [^ false].
        (anObject y < 2
                        or: [anObject y > (map size + 1)])
                ifTrue: [^ false].
        ^ true!

----- Method: SkCollection>>isInstance (in category 'testing') -----
isInstance
"maybe bad"
        ^ false!

----- Method: SkCollection>>isStepList (in category 'testing') -----
isStepList
        ^ self ruleName = 'StepList'!

----- Method: SkCollection>>isStepping (in category 'updating') -----
isStepping
        (self isStepList
                        and: [map isEmpty not])
                ifTrue: [^ true].
        ^ super isStepping!

----- Method: SkCollection>>remove: (in category 'accessing') -----
remove: value
        map
                removeAllSuchThat: [:each | each = value].
        self changed: #cardList.
        ^ value!

----- Method: SkCollection>>removeAt: (in category 'cell accessing') -----
removeAt: key
        (self isApplicableKey: key)
                ifFalse: [^ NullCell].
        map removeAt: key y - 1.
        self changed: #cardList.
        ^ NullCell!

----- Method: SkCollection>>stopStepping (in category 'updating') -----
stopStepping
        map _ OrderedCollection new.
        self changed: #cardList.
!

SkMap subclass: #SkDictionary
        instanceVariableNames: 'comment orderedCache args'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkDictionary commentStamp: 'tak 12/22/2003 16:11' prior: 0!
This is a dictionary like rule.!

----- Method: SkDictionary>>argPositions (in category 'arg accessing') -----
argPositions
        ^ (1 to: self args size)
                collect: [:index | index @ 1]!

----- Method: SkDictionary>>args (in category 'accessing') -----
args
        ^ args
                ifNil: [self initializeArgs]!

----- Method: SkDictionary>>assuredCellAt: (in category 'cell accessing') -----
assuredCellAt: key
        (self includesArgs: key)
                ifTrue: [^ args at: key x].
        (self includesPosition: key)
                ifTrue: [key x = 1
                                ifTrue: [^ (SkDictionaryCell newFor: self key: (self rowAt: key y) key)
                                                isKey: true]
                                ifFalse: [^ SkDictionaryCell newFor: self key: (self rowAt: key y) key]].
        ^ key class == Point
                ifTrue: [SkDictionaryCell newFor: self key: nil]
                ifFalse: [SkDictionaryCell newFor: self key: key]!

----- Method: SkDictionary>>at:put: (in category 'accessing') -----
at: key put: anObject
        self flag: #TODO.
        map at: key put: anObject.
        self updateCache.
        ^ anObject!

----- Method: SkDictionary>>cardPositions (in category 'accessing') -----
cardPositions
        ^ (1 to: orderedCache size + 1)
                collect: [:each | 2 @ each]
                thenSelect: [:key | (self at: key) isSkObject]!

----- Method: SkDictionary>>cellAt:ifAbsent: (in category 'cell accessing') -----
cellAt: key ifAbsent: aBlock
        "Evaluate aBlock when not found and key is not point"
        (self includesArgs: key)
                ifTrue: [^ self args at: key x].
        (self includesPosition: key)
                ifTrue: [^ SkDictionaryCell newFor: self key: key].
        (map includesKey: key)
                ifTrue: [^ SkDictionaryCell newFor: self key: key]
                ifFalse: [^ aBlock value]!

----- Method: SkDictionary>>defaultArea (in category 'accessing') -----
defaultArea
        ^ 0 @ 0 extent: 3 @ (self namesSize + 1)!

----- Method: SkDictionary>>holder:at: (in category 'arg accessing') -----
holder: aSkSheet at: aPoint
        | holderCell |
        (self referenceAt: aPoint)
                withIndexDo: [:pos :index |
                        holderCell _ aSkSheet assuredCellAt: pos.
                        args at: index put: holderCell]!

----- Method: SkDictionary>>includesArgs: (in category 'testing') -----
includesArgs: aPoint
        ^ {1 @ 1. 2 @ 1} includes: aPoint!

----- Method: SkDictionary>>includesPosition: (in category 'testing') -----
includesPosition: aPoint
        aPoint class == Point
                ifFalse: [^ false].
        aPoint y < 2
                ifTrue: [^ false].
        aPoint y > (map size + 1)
                ifTrue: [^ false].
        (#(1 2 ) includes: aPoint x)
                ifFalse: [^ false].
        ^ true!

----- Method: SkDictionary>>initialize (in category 'initialization') -----
initialize
        super initialize.
        map _ Dictionary new.
        comment _ '' asText.
        self updateCache.
        self initializeArgs!

----- Method: SkDictionary>>initializeArgs (in category 'initialization') -----
initializeArgs
        ^ args _ {SkValueCell new. SkValueCell new}!

----- Method: SkDictionary>>isLocked (in category 'testing') -----
isLocked
        ^ map includesKey: 'locked'!

----- Method: SkDictionary>>keyAtValue:ifAbsent: (in category 'structure') -----
keyAtValue: anObject ifAbsent: aBlock
        ^ map keyAtValue: anObject ifAbsent: aBlock!

----- Method: SkDictionary>>locked: (in category 'accessing') -----
locked: boolean.
        map at: 'locked' put: boolean!

----- Method: SkDictionary>>nameAt:ifAbsent: (in category 'accessing') -----
nameAt: key ifAbsent: aBlock
        ^ map at: key ifAbsent: aBlock!

----- Method: SkDictionary>>namesSize (in category 'accessing') -----
namesSize
        ^ map size!

----- Method: SkDictionary>>referenceAt: (in category 'arg accessing') -----
referenceAt: aPoint
        "Answer the dependents object's point"
        ^ self argPositions
                collect: [:each | self pointForHolder: aPoint at: each]!

----- Method: SkDictionary>>removeAt: (in category 'structure') -----
removeAt: key
        | cell name |
        name _ key class == Point
                                ifTrue: [(self rowAt: key y) key]
                                ifFalse: [key].
        self isLocked
                ifTrue: [^ self cellAt: name].
        cell _ super removeAt: name.
        self updateCache.
        self update: #cardList.
        ^ cell!

----- Method: SkDictionary>>removeForce: (in category 'structure') -----
removeForce: key
        map removeKey: key ifAbsent: []!

----- Method: SkDictionary>>resolveOn: (in category 'updating') -----
resolveOn: holder
        | value |
        (value _ map
                                        at: args first contents
                                        ifAbsent: [args second contents: ''.
                                                ^ self]) = args second contents
                ifFalse: [args second contents: value.
                        holder changed: #cardList.
                        self changed: #cardList]!

----- Method: SkDictionary>>rowAt: (in category 'accessing') -----
rowAt: aNumber
        ^ (1 < aNumber
                        and: [aNumber <= (orderedCache size + 1)])
                ifTrue: [orderedCache at: aNumber - 1]!

----- Method: SkDictionary>>size (in category 'accessing') -----
size
        ^ 2!

----- Method: SkDictionary>>updateCache (in category 'accessing') -----
updateCache
        orderedCache _ SortedCollection
                                sortBlock: [:x :y | x key name <= y key name].
        map
                associationsDo: [:assoc | orderedCache add: assoc]!

----- Method: SkDictionary>>wantsSteps (in category 'updating') -----
wantsSteps
        ^ true!

SkDictionary subclass: #SkProject
        instanceVariableNames: 'colorSet'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkProject commentStamp: 'tak 1/25/2004 00:00' prior: 0!
I hold all spreadsheets in a project.
I find my parent from class variable but instance variable.
This is because to aviod copy all trees when I am saved into project file.

colorSet -- SkColorSet ... This is temporary implementation. It is bounded to save as project.!

----- Method: SkProject class>>current (in category 'accessing') -----
current
        ^ self for: Project current!

----- Method: SkProject class>>for: (in category 'accessing') -----
for: aProject
        "SkProject for: (Project named: 'Unnamed1')"
        | parent dict |
        parent _ self root at: 'Projects'.
        dict _ parent
                                at: aProject
                                ifAbsent: [(SkProject newFor: aProject) parent: parent;
                                                 name: aProject].
        ^ dict!

----- Method: SkProject class>>forceRemoveAt: (in category 'accessing') -----
forceRemoveAt: aProject
        "remove for debug"
        "self forceRemoveAt: Project current"
        (SkDictionary allInstances
                select: [:each | each includesKey: aProject])
                do: [:each | each removeForce: aProject]!

----- Method: SkProject class>>newFor: (in category 'accessing') -----
newFor: aProject
        "find this instance for the project. little tricky"
        "self findProject: Project current"
        | map |
        map _ SkDictionary allInstances
                                detect: [:each | each includesKey: aProject]
                                ifNone: [^ self new].
        ^ map at: aProject!

----- Method: SkProject>>colorSet (in category 'accessing') -----
colorSet
        ^colorSet!

----- Method: SkProject>>initialize (in category 'initialization') -----
initialize
        super initialize.
        colorSet _ SkColorSet map!

----- Method: SkProject>>parent (in category 'structure') -----
parent
        ^ self class root findName: 'Projects'!

----- Method: SkProject>>parent: (in category 'structure') -----
parent: aSkObject
        "do nothing"
        ^ self!

----- Method: SkProject>>stepList (in category 'accessing') -----
stepList
        ^ self
                at: 'StepList'
                ifAbsent: [| list |
                        list _ SkCollection new.
                        self at: 'StepList' put: list.
                        list parent: self.
                        World setProperty: #SkStepList toValue: list.
                        list]!

----- Method: SkMap>>removeAt: (in category 'structure') -----
removeAt: key
        | cell |
        cell _ self cellAt: key.
        map
                removeKey: key
                ifAbsent: [].
        ^ cell!

SkMap subclass: #SkSheet
        instanceVariableNames: 'plan dependMap'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkSheet commentStamp: 'tak 4/2/2004 21:27' prior: 0!
I am a simple spreadsheets model.

Preferences enable: #batchPenTrails
SkSheet example

Structure:
 dictionary Dictionary -- reference of cells
!

----- Method: SkSheet class>>example (in category 'examples') -----
example
        "self example"
        | sheet p1 p2 |
        ActiveWorld setProperty: #originAtCenter toValue: true.
        sheet _ SkSheet new.
        p1 _ (SkeletonBaseInfo point color: Color blue) openInWorld assuredPlayer.
        p2 _ (SkeletonBaseInfo point color: Color red) openInWorld assuredPlayer.
        sheet
                modelAt: 1 @ 1
                for: p1
                getter: #getX
                setter: #setX:.
        sheet
                modelAt: 2 @ 1
                for: p1
                getter: #getY
                setter: #setY:.
        sheet
                modelAt: 1 @ 2
                for: p2
                getter: #getX
                setter: #setX:.
        sheet
                modelAt: 2 @ 2
                for: p2
                getter: #getY
                setter: #setY:.
        sheet textAt: 1 @ 1 put: '=( 4 * A2 ) degreeSin * 200'.
        sheet textAt: 2 @ 1 put: '=( 7 * A2 ) degreeSin * 200'.
        p1 setPenDown: true.
        p1
                setPenColor: (TranslucentColor
                                r: 1.0
                                g: 0.0
                                b: 0.0
                                alpha: 0.1).
        p1 setPenSize: 3.
        p2 setX: 0;
                 setY: 0.
        sheet grid openInWorld!

----- Method: SkSheet>>assuredCellAt: (in category 'cell accessing') -----
assuredCellAt: key
        ^ self
                cellAt: key
                ifAbsent: [map at: key put: SkValueCell new]!

----- Method: SkSheet>>cardList: (in category 'accessing') -----
cardList: aRectangle
        ^ self cardPositions
                collect: [:key | key
                                -> (self at: key)]!

----- Method: SkSheet>>cardPositions (in category 'planning') -----
cardPositions
        ^ map keys
                select: [:each | each class = Point
                                and: [(map at: each) hasCard]]!

----- Method: SkSheet>>cellAt:ifAbsent: (in category 'cell accessing') -----
cellAt: key ifAbsent: aBlock
        ^ map at: key ifAbsent: aBlock!

----- Method: SkSheet>>cleaning (in category 'updating') -----
cleaning
        (map keys
                select: [:key | (map at: key) isNull
                                and: [(dependMap keys includes: key) not]])
                do: [:key | map removeKey: key]!

----- Method: SkSheet>>collectCardDependents: (in category 'planning') -----
collectCardDependents: depArray
        "Answer  
        #((observer subject subject ..) .."
        "This is ugly code because using Array. We should use Dictionary by  
        building plan"
        | dict |
        dict _ Dictionary new.
        depArray
                do: [:each | dict at: each first put: each allButFirst asSet].
        (self cardPositions
                select: [:each | (map at: each) contents isInstance])
                do: [:each | ((map at: each) contents collectDependentsForCard: each)
                                ifNotNilDo: [:depends | depends
                                                keysAndValuesDo: [:key :value | (dict at: key ifAbsentPut: Set new)
                                                                addAll: value]]].
        ^ self dictToArray: dict!

----- Method: SkSheet>>collectDependents (in category 'planning') -----
collectDependents
        "Answer
        #((observer subject subject ..)
        (observer subject subject ..)
        (observer subject subject ..))"
        | node myDepends |
        myDepends _ self collectTargets
                                collect: [:point |
                                        node _ ((self cellAt: point)
                                                                referenceAt: point)
                                                                asSortedCollection: self sortBlock.
                                        node _ node asOrderedCollection addFirst: point;
                                                                 yourself.
                                        node asArray].
        ^ self collectCardDependents: myDepends!

----- Method: SkSheet>>collectOrder (in category 'planning') -----
collectOrder
        | trees |
        trees _ self collectTrees.
        ^ trees
                inject: OrderedCollection new
                into: [:order :next | order
                                addAll: (self collectOrder: next);
                                 yourself]!

----- Method: SkSheet>>collectOrder: (in category 'planning') -----
collectOrder: tree
        tree isCollection
                ifFalse: [^ Array with: tree].
        ^ Array
                streamContents: [:aStream |
                        tree allButFirst
                                do: [:node | aStream
                                                nextPutAll: (self collectOrder: node)].
                        aStream nextPut: tree first]!

----- Method: SkSheet>>collectTargets (in category 'planning') -----
collectTargets
        "Answer points that has formula or card"
        ^ ((map keys
                select: [:key | key class = Point
                                and: [(map at: key) hasFormula]])
                asSortedCollection: self sortBlock) asArray!

----- Method: SkSheet>>collectTrees (in category 'planning') -----
collectTrees
        "Adopt parted node (collectDependents) into a big tree"
        "The order is important"
        | pool newNodes isFound |
        "pool is a map of observer -> subjects"
        pool _ self collectDependents.
        newNodes _ OrderedCollection new.
        pool
                do: [:node |
                        isFound _ false.
                        (pool copyWithout: node)
                                do: [:mother | (self hasRecursion: mother first in: node)
                                                ifFalse: [2
                                                                to: mother size
                                                                do: [:index | (isFound not
                                                                                        and: [(mother at: index)
                                                                                                        = node first])
                                                                                ifTrue: [mother at: index put: node.
                                                                                        isFound _ true]]]].
                        isFound
                                ifFalse: [newNodes add: node]].
        ^ newNodes asArray!

----- Method: SkSheet>>dependMap (in category 'planning') -----
dependMap
        "directory of (subject -> a set of observers)"
        | dep values |
        dep _ Dictionary new.
        "Make simple dictionary reverse of dependents #(observers  subject ..)"
        self collectDependents
                do: [:each | each allButFirst
                                do: [:point |
                                        values _ dep at: point ifAbsentPut: Set new.
                                        values add: each first]].
        dep keys
                do: [:key | self
                                dependMap: key
                                addKey: (dep at: key)
                                dict: dep].
        ^ dep!

----- Method: SkSheet>>dependMap:addKey:dict: (in category 'planning') -----
dependMap: target addKey: addKey dict: dict
        | founds more |
        founds _ Set with: target.
        founds
                addAll: (dict at: target).
        more _ Set new.
        addKey
                do: [:key | more
                                addAll: ((dict
                                                at: key
                                                ifAbsent: [#()])
                                                select: [:value | (founds includes: value) not])].
        more isEmpty
                ifTrue: [^ self].
        (dict at: target)
                addAll: more.
        self
                dependMap: target
                addKey: more
                dict: dict!

----- Method: SkSheet>>dictToArray: (in category 'planning') -----
dictToArray: aDictionary
        "
        (self new dictToArray: (Dictionary new  
        at: 1@2 put: (Set new addAll: {2@2. 3@2});
        at: 1@1 put: (Set new addAll: {3@1. 2@1});  
        yourself)) = {{1@1. 2@1. 3@1}.{1@2. 2@2. 3@2}}
        "
        | set line |
        ^ ((aDictionary keys asSortedCollection: self sortBlock)
                collect: [:key |
                        line _ OrderedCollection new.
                        line add: key.
                        set _ aDictionary at: key.
                        line
                                addAll: (set asSortedCollection: self sortBlock).
                        line asArray]) asArray!

----- Method: SkSheet>>grid (in category 'initialization') -----
grid
        self startStepping.
        ^ super grid!

----- Method: SkSheet>>hasRecursion:in: (in category 'planning') -----
hasRecursion: aPoint in: node
        "(self new hasRecursion: 1@1 in: {2@2. {1@1. 2@2}}) = true"
        "(self new hasRecursion: 1@1 in: {3@3. {2@2. 1@1}}) = false"
        ^ node first = aPoint
                or: [node allButFirst
                                anySatisfy: [:each | each isCollection
                                                and: [self hasRecursion: aPoint in: each]]]!

----- Method: SkSheet>>initialize (in category 'initialization') -----
initialize
        super initialize.
        map _ Dictionary new.
        plan _ #()!

----- Method: SkSheet>>installFormulaAt: (in category 'holder and card') -----
installFormulaAt: aPoint
        | cell card |
        (cell _ self cellAt: aPoint) hasCard
                ifTrue: [card _ cell contents.
                        card isInstance
                                ifTrue: [card holder: self at: aPoint].
                        self changed: #cardList.].
        self updatePlan.
        self changed!

----- Method: SkSheet>>isInstance (in category 'testing') -----
isInstance
        ^ false!

----- Method: SkSheet>>keyAtValue:ifAbsent: (in category 'structure') -----
keyAtValue: value ifAbsent: aBlock
        "Answer only named key"
        map
                associationsDo: [:association | (value == association value contents
                                        and: [association key class ~= Point])
                                ifTrue: [^ association key]].
        ^ aBlock value!

----- Method: SkSheet>>modelAt:for:getter:setter: (in category 'accessing') -----
modelAt: aPoint for: anObject getter: getter setter: setter
        self
                textAt: aPoint
                put: (anObject perform: getter).
        (self cellAt: aPoint)
                on: anObject
                getter: getter
                setter: setter.
!

----- Method: SkSheet>>nameAt:putCell: (in category 'cell accessing') -----
nameAt: aString putCell: cell
        map at: aString put: cell.!

----- Method: SkSheet>>plan (in category 'accessing') -----
plan
        ^ plan!

----- Method: SkSheet>>rememberUpdatesOn: (in category 'updating') -----
rememberUpdatesOn: holder
        dependMap keys do: [:key | (holder cellAt: key) remember]!

----- Method: SkSheet>>resolveOn: (in category 'updating') -----
resolveOn: holder
        "Aplly all constrains to cells in holder"
        | updates |
        dependMap
                ifNil: [^ self].
        updates _ Set new
                                addAll: (self updatedCellsOn: holder);
                               
                                addAll: (self updatedCellsInCardOn: holder);
                                 yourself.
        plan
                do: [:pair | (updates includes: pair key)
                                ifTrue: [pair value resolveOn: holder at: pair key]].
        self rememberUpdatesOn: holder.
"
        updates isEmpty not
                ifTrue: [Transcript show: updates asString;
                                 cr]
"!

----- Method: SkSheet>>sortBlock (in category 'planning') -----
sortBlock
        ^ [:a :b | a y < b y
                or: [a y == b y
                                and: [a x <= b x]]]!

----- Method: SkSheet>>updateKeys (in category 'accessing') -----
updateKeys
        | propertyKeys newMap |
        propertyKeys _ self findName: 'PropertyKeys'.
        newMap _ Dictionary new.
        map
                associationsDo: [:assoc | (assoc key class == Point
                                        or: [propertyKeys includes: assoc key])
                                ifTrue: [newMap at: assoc key put: assoc value]].
        (map values
                select: [:cell | cell contents class == SkName]
                thenCollect: [:cell | cell contents])
                do: [:each | newMap at: each key put: each cell].
        map _ newMap.!

----- Method: SkSheet>>updatePlan (in category 'planning') -----
updatePlan
        "Order of plan is reserved, but not redundant"

        | keys remain |
        keys := self collectOrder.
        remain := keys asSet.
        plan := (keys select:
                                        [:key |
                                        (remain includes: key) and:
                                                        [(self cellAt: key) hasFormula and:
                                                                        [remain remove: key.
                                                                        true]]]
                                thenCollect: [:key | key -> (map at: key)]) asArray.
        dependMap := self dependMap!

----- Method: SkSheet>>updatedCellsInCardOn: (in category 'updating') -----
updatedCellsInCardOn: holder
        "Ask card to want to update?"
        ^ self cardPositions
                select: [:each | (map at: each) contents wantsUpdate]!

----- Method: SkSheet>>updatedCellsOn: (in category 'updating') -----
updatedCellsOn: holder
        "detect where I have to do"

        | updates |
        updates := Set new.
        dependMap keys do:
                        [:key |
                        (holder cellAt: key) hasUpdated
                                ifTrue: [updates addAll: (dependMap at: key)]].
        ^updates!

----- Method: SkSheet>>wantsSteps (in category 'updating') -----
wantsSteps
        ^ true!

SkMap subclass: #SkSimple
        instanceVariableNames: 'rules'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkSimple commentStamp: 'tak 3/11/2004 19:12' prior: 0!
I am a simple spreadsheet object.!

----- Method: SkSimple>>addRule: (in category 'accessing') -----
addRule: aSkRule
        rules add: aSkRule.
        ^ aSkRule.!

----- Method: SkSimple>>at:ifAbsent: (in category 'accessing') -----
at: key ifAbsent: aBlock
        ^ (map at: key ifAbsent: aBlock) value!

----- Method: SkSimple>>at:put: (in category 'accessing') -----
at: key put: anObject
        map at: key put: anObject.
        ^ anObject!

----- Method: SkSimple>>initialize (in category 'initialization') -----
initialize
        super initialize.
        map _ Dictionary new.
        rules _ OrderedCollection new.
!

----- Method: SkSimple>>resolveOn: (in category 'updating') -----
resolveOn: holder
        rules
                do: [:each | each resolveOn: holder]!

----- Method: SkSimple>>textAt: (in category 'accessing') -----
textAt: aPoint
        ^ (self at: aPoint) asString!

----- Method: SkSimple>>textAt:put: (in category 'accessing') -----
textAt: aPoint put: aText
        aText = ''
                ifTrue: [self removeAt: aPoint.
                        ^ ''].
        map at: aPoint put: aText asString.
        self changed.
        ^ aText!

----- Method: SkNamed>>parent (in category 'structure') -----
parent
        ^ parent!

----- Method: SkNamed>>parent: (in category 'structure') -----
parent: aSkObject
        parent _ aSkObject!

----- Method: SkNamed>>siblingWith: (in category 'copying') -----
siblingWith: deepCopier
        ^ self new!

----- Method: SkNamed>>veryDeepCopyWith: (in category 'copying') -----
veryDeepCopyWith: deepCopier
        | new |
        new _ super veryDeepCopyWith: deepCopier.
        new parent: SkProject current uniqueName: self ruleName.
        ^ new!

----- Method: SkNamed>>veryDeepInner: (in category 'copying') -----
veryDeepInner: deepCopier
        "parent is not copied"
        super veryDeepInner: deepCopier.
!

----- Method: SkObject class>>codeString (in category 'accessing') -----
codeString
        ^ self ruleName!

----- Method: SkObject class>>color: (in category 'accessing') -----
color: aColor
        SkColorSet for: self color: aColor!

----- Method: SkObject class>>contents: (in category 'instance creation') -----
contents: aBlock
        | holder |
        holder _ self new.
        aBlock value: holder.
        ^ holder!

----- Method: SkObject class>>defaultColor (in category 'instance creation') -----
defaultColor
        ^ Color blue!

----- Method: SkObject class>>defaultName (in category 'instance creation') -----
defaultName
        ^ self name allButFirst: 2!

----- Method: SkObject class>>direction (in category 'accessing') -----
direction
        ^ #right!

----- Method: SkObject class>>direction: (in category 'instance creation') -----
direction: aSymbol
        ^self new direction: aSymbol!

----- Method: SkObject class>>grid (in category 'instance creation') -----
grid
        | case grid |
        grid _ SkSheetMorph new model: (case _ self new).
        grid area: case defaultArea.
        ^ grid!

----- Method: SkObject class>>initialize (in category 'class initialization') -----
initialize
        "self initialize"
        super initialize.
        SkColorSet initialize.
        NullCell _ SkNullCell new.
        Root _ self initializeRoot.
        self initializeLibrary.
!

----- Method: SkObject class>>initializeLibrary (in category 'class initialization') -----
initializeLibrary
        "self initializeLibrary"
        | library |
        library _ (self root at: 'Library' put: SkDictionary new)
                                parent: self root.
        library locked: true.
        library
                color: (Color
                                r: 0.258
                                g: 0.645
                                b: 0.0).
        SkLibrary allSubclasses asArray , {SkSheet. SkDictionary}
                do: [:each |
                        each parent: library;
                                 name: each defaultName.
                        each color: each defaultColor].
        self initializePropertyKeys!

----- Method: SkObject class>>initializePropertyKeys (in category 'class initialization') -----
initializePropertyKeys
        | library |
        library _ self root at: 'Library'.
        library at: 'PropertyKeys' put: {'CellExtent'} asSet!

----- Method: SkObject class>>initializeRoot (in category 'class initialization') -----
initializeRoot
        | root library projects |
        root _ SkDictionary new.
        library _ SkDictionary new.
        library color:  (Color r: 0.258 g: 0.645 b: 0.0).
        projects _ SkDictionary new.
        root at: 'Root' put: root.
        root parent: root.
        root at: 'Library' put: library.
        library parent: root.
        root at: 'Projects' put: projects.
        projects parent: root.
        projects locked: true.
        root locked: true.
        ^ root!

----- Method: SkObject class>>invokeCardMenu: (in category 'menu') -----
invokeCardMenu: evt!

----- Method: SkObject class>>isInstance (in category 'testing') -----
isInstance
        ^ false!

----- Method: SkObject class>>isSkObject (in category 'testing') -----
isSkObject
        ^true!

----- Method: SkObject class>>name: (in category 'structure') -----
name: aString
        self parent uniqueNameAt: aString put: self rule!

----- Method: SkObject class>>name:contents: (in category 'instance creation') -----
name: aString contents: aBlock
        | holder |
        holder _ self new name: aString.
        aBlock value: holder.
        ^ holder!

----- Method: SkObject class>>new (in category 'instance creation') -----
new
        ^ super new initialize!

----- Method: SkObject class>>open (in category 'instance creation') -----
open
        "self open"
        ^ self new grid openInHand!

----- Method: SkObject class>>parent (in category 'structure') -----
parent
        ^ self root at: 'Library'!

----- Method: SkObject class>>parent: (in category 'structure') -----
parent: anObject
        "parent can't set"!

----- Method: SkObject class>>releaseHolder (in category 'holder and card') -----
releaseHolder!

----- Method: SkObject class>>root (in category 'accessing') -----
root
        ^ Root!

----- Method: SkObject class>>rule (in category 'accessing') -----
rule
        ^ self!

----- Method: SkObject class>>ruleName (in category 'accessing') -----
ruleName
        "Answer name or nil"
        ^ self parent
                ifNotNil: [self parent keyAtValue: self rule]!

----- Method: SkObject class>>siblingWith: (in category 'copying') -----
siblingWith: deepCopier
!

----- Method: SkObject class>>size (in category 'accessing') -----
size
        ^ 0!

----- Method: SkObject class>>size: (in category 'accessing') -----
size: aNumber
        ^ aNumber!

----- Method: SkObject class>>stopStepping (in category 'updating') -----
stopStepping
        World
                ifNotNil: [(World valueOfProperty: #SkSheet)
                                ifNotNilDo: [:set | set remove: self ifAbsent: []]]!

----- Method: SkObject>>++ (in category 'arithmetic') -----
++ anObject
        ^ SkParametric new func: #+ arg1: self arg2: anObject
        !

----- Method: SkObject>>adopt: (in category 'structure') -----
adopt: aSkObject
        (self findName: aSkObject ruleName)
                        = aSkObject rule
                ifTrue: [^ self].
        self uniqueNameAt: aSkObject ruleName put: aSkObject!

----- Method: SkObject>>args (in category 'accessing') -----
args
        ^ #()!

----- Method: SkObject>>assuredCellAt: (in category 'cell accessing') -----
assuredCellAt: key
        ^ self cellAt: key!

----- Method: SkObject>>at: (in category 'accessing') -----
at: key
        "Anwer '' NOT nil when unfound"
        ^ self
                at: key
                ifAbsent: [^ '']!

----- Method: SkObject>>at:ifAbsent: (in category 'accessing') -----
at: key ifAbsent: aBlock
        "answer a value of the point"
        ^ (self
                cellAt: key
                ifAbsent: [^ aBlock value]) contents!

----- Method: SkObject>>at:put: (in category 'accessing') -----
at: aPosition put: anObject
        | cell |
        cell _ self assuredCellAt: aPosition.
        cell contents: anObject.
        ^ anObject!

----- Method: SkObject>>attachProject (in category 'structure') -----
attachProject
        self parent: SkProject current uniqueName: self ruleName
!

----- Method: SkObject>>beAlone (in category 'structure') -----
beAlone
        self parent
                ifNotNil: [self parent removeAt: self ruleName]!

----- Method: SkObject>>cardList: (in category 'accessing') -----
cardList: aRectangle
        ^ self cardPositions
                collect: [:key | key
                                -> (self at: key)]!

----- Method: SkObject>>cardPositions (in category 'accessing') -----
cardPositions
        ^ #()!

----- Method: SkObject>>caseAt:put: (in category 'holder and card') -----
caseAt: key put: case
        "Drop the case into me"
        self at: key put: case.!

----- Method: SkObject>>cellAt: (in category 'cell accessing') -----
cellAt: key
  ^ self
                cellAt: key
                ifAbsent: [NullCell]!

----- Method: SkObject>>cellAt:ifAbsent: (in category 'cell accessing') -----
cellAt: key ifAbsent: aBlock
        ^ aBlock value!

----- Method: SkObject>>codeString (in category 'accessing') -----
codeString
        ^ self ruleName , ' direction: ' , self direction printString , ' size: ' , (self size
                        ifNil: [0]) printString!

----- Method: SkObject>>collectDependents (in category 'planning') -----
collectDependents
        ^ #()!

----- Method: SkObject>>collectDependentsForCard: (in category 'updating') -----
collectDependentsForCard: aPoint
        ^nil!

----- Method: SkObject>>collectUpdates: (in category 'updating') -----
collectUpdates: aPoint
        "Answer updated position"
        ^ #()!

----- Method: SkObject>>collectUpdatesForCard: (in category 'updating') -----
collectUpdatesForCard: aPoint
        ^#()!

----- Method: SkObject>>color (in category 'accessing') -----
color
        ^ SkColorSet basicFor: self rule!

----- Method: SkObject>>color: (in category 'accessing') -----
color: aColor
        SkColorSet for: self color: aColor!

----- Method: SkObject>>defaultArea (in category 'initialization') -----
defaultArea
        ^ 0 @ 0 extent: 3 @ 3!

----- Method: SkObject>>defaultColor (in category 'accessing') -----
defaultColor
        ^ Color blue.!

----- Method: SkObject>>defaultName (in category 'constants') -----
defaultName
        ^ 'Sheet'!

----- Method: SkObject>>dependMap (in category 'accessing') -----
dependMap
        ^ #()!

----- Method: SkObject>>direction (in category 'accessing') -----
direction
        ^ #right!

----- Method: SkObject>>direction: (in category 'accessing') -----
direction: aSymbol
!

----- Method: SkObject>>direction:size: (in category 'instance creation') -----
direction: direction size: aNumber
        | card |
        card := self rule new.
        card direction: direction.
        card size: aNumber.
        ^card!

----- Method: SkObject>>findLibrary:ifAbsent: (in category 'name accessing') -----
findLibrary: aString ifAbsent: aBlock
        ^ (self class root findName: 'Library')
                at: aString
                ifAbsent: aBlock!

----- Method: SkObject>>findName: (in category 'name accessing') -----
findName: aString
        ^ self
                findName: aString
                ifAbsent: [nil]!

----- Method: SkObject>>findName:ifAbsent: (in category 'name accessing') -----
findName: aString ifAbsent: aBlock
        "Search parent if not found"
        aString = 'parent'
                ifTrue: [^ self parent].
        ^ self
                at: aString
                ifAbsent: [(self = self parent
                                        or: [self parent isNil])
                                ifTrue: [self findLibrary: aString ifAbsent: aBlock]
                                ifFalse: [self parent findName: aString ifAbsent: aBlock]]!

----- Method: SkObject>>grid (in category 'initialization') -----
grid
        | grid |
        grid _ SkSheetMorph new model: self.
        grid area: self defaultArea.
        ^ grid!

----- Method: SkObject>>includesKey: (in category 'structure') -----
includesKey: key
        self
                at: key
                ifAbsent: [^ false].
        ^ true!

----- Method: SkObject>>initialize (in category 'initialization') -----
initialize
        "initialize code is here"!

----- Method: SkObject>>inspectAt: (in category 'accessing') -----
inspectAt: key
        | inspector |
        inspector _ SkCellInspector holder: self key: key.
        inspector
                openLabel: (SkParser pointToA1Name: key)!

----- Method: SkObject>>install:to: (in category 'initialization') -----
install: aSkCard to: aSkObject
        "It can remove when SkDefine doesn't use SkProxy"!

----- Method: SkObject>>installFormulaAt: (in category 'holder and card') -----
installFormulaAt: aPoint
!

----- Method: SkObject>>invokeCardMenu: (in category 'menu') -----
invokeCardMenu: evt!

----- Method: SkObject>>isInstance (in category 'testing') -----
isInstance
        ^ true!

----- Method: SkObject>>isSkObject (in category 'testing') -----
isSkObject
        ^ true!

----- Method: SkObject>>isStepping (in category 'updating') -----
isStepping
        ^ SkProject current stepList includes: self!

----- Method: SkObject>>keyAtValue: (in category 'structure') -----
keyAtValue: anObject
        ^ self
                keyAtValue: anObject
                ifAbsent: []!

----- Method: SkObject>>keyAtValue:ifAbsent: (in category 'structure') -----
keyAtValue: anObject ifAbsent: aBlock
        ^ self subclassResponsibility!

----- Method: SkObject>>name: (in category 'structure') -----
name: aString
        self parent
                ifNil: [self parent: SkProject current].
        self parent uniqueNameAt: aString put: self rule!

----- Method: SkObject>>new (in category 'instance creation') -----
new
        "Build instance object"
        ^ self isInstance
                ifTrue: [self]
                ifFalse: [SkProxy newFrom: self]!

----- Method: SkObject>>parent (in category 'structure') -----
parent
        ^ nil!

----- Method: SkObject>>parent: (in category 'structure') -----
parent: aSkRule
        self subclassResponsibility!

----- Method: SkObject>>parent:uniqueName: (in category 'structure') -----
parent: aSkObject uniqueName: aString
        self parent: aSkObject;
                 name: aString!

----- Method: SkObject>>pointForHolder:at: (in category 'support') -----
pointForHolder: holderPoint at: aPoint
        "Translating cordinate local to holder
        holderPoint is a point that I am put"
        | rotateDirection standardized |
        rotateDirection _ self direction == #right
                                ifFalse: [self direction == #down
                                                ifTrue: [#right]
                                                ifFalse: [self direction == #left
                                                                ifTrue: [#pi]
                                                                ifFalse: [self direction == #up
                                                                                ifTrue: [#left]]]].
        standardized _ aPoint + (0 @ -1).
        rotateDirection
                ifNotNil: [standardized _ standardized rotateBy: rotateDirection centerAt: 0 @ 0].
        ^ standardized + holderPoint!

----- Method: SkObject>>printOn: (in category 'accessing') -----
printOn: aStream
        | aName |
        super printOn: aStream.
        (aName _ self ruleName printString) notNil
                ifTrue: [aStream nextPutAll: '<' , aName , '>'].
        aStream nextPutAll: '('.
        aStream
                print: self identityHash;
                nextPutAll: ')'!

----- Method: SkObject>>referenceAt: (in category 'updating') -----
referenceAt: aPoint
        "Answer the dependents object's point(with cordinate of holder)."
        ^ #()!

----- Method: SkObject>>releaseHolder (in category 'holder and card') -----
releaseHolder!

----- Method: SkObject>>removeAt: (in category 'cell accessing') -----
removeAt: aPosition
        "Remove value and formula, Then answer the cell"
        ^NullCell!

----- Method: SkObject>>resolve (in category 'updating') -----
resolve
        "Rule should not be specified if instantiation is done"
        self rule resolveOn: self!

----- Method: SkObject>>resolveOn: (in category 'updating') -----
resolveOn: holder
!

----- Method: SkObject>>rule (in category 'accessing') -----
rule
        ^ self!

----- Method: SkObject>>ruleName (in category 'structure') -----
ruleName
        "Answer name or nil"
        ^ self parent
                ifNil: [self rule class ruleName]
                ifNotNil: [self parent keyAtValue: self rule]!

----- Method: SkObject>>safetyResolve (in category 'updating') -----
safetyResolve
        [self resolve]
                ifError: [:err :rcvr |
                        self stopStepping.
                        self error: err]!

----- Method: SkObject>>saftyResolve (in category 'updating') -----
saftyResolve
        self safetyResolve!

----- Method: SkObject>>siblingWith: (in category 'copying') -----
siblingWith: deepCopier
        ^ self veryDeepCopyWith: deepCopier!

----- Method: SkObject>>size (in category 'accessing') -----
size
        ^ 0!

----- Method: SkObject>>size: (in category 'accessing') -----
size: aNumber
!

----- Method: SkObject>>startStepping (in category 'updating') -----
startStepping
        | stepList |
        self wantsSteps
                ifFalse: [^ self].
        self attachProject.
        stepList _ SkProject current stepList.
        (stepList includes: self)
                ifFalse: [stepList add: self]!

----- Method: SkObject>>stopStepping (in category 'updating') -----
stopStepping
        SkProject current stepList remove: self!

----- Method: SkObject>>textAt: (in category 'accessing') -----
textAt: aPoint
        "I am send when a user want to edit the value by text editor"
        | cell contents |
        aPoint = (0 @ 0)
                ifTrue: [^ self ruleName asString].
        cell _ self cellAt: aPoint.
        ^ cell formula
                ifNil: [contents _ (self cellAt: aPoint) contents.
                        contents isText
                                ifTrue: [contents]
                                ifFalse: [contents asCellText asText]]
                ifNotNil: [cell formula]!

----- Method: SkObject>>textAt:put: (in category 'accessing') -----
textAt: aPoint put: aText
        | cell |
        aText = ''
                ifTrue: [cell _ self removeAt: aPoint.
                        cell hasCard
                                ifTrue: [cell contents releaseHolder.
                                        self updatePlan.
                                        self changed: #cardList].
                        ^ ''].
        aPoint = (0 @ 0)
                ifTrue: [^ self name: aText asString].
        cell _ self assuredCellAt: aPoint.
        cell editContents: aText.
        cell resolveFormulaOn: self at: aPoint.
        self installFormulaAt: aPoint.
        self changed.
        ^ aText!

----- Method: SkObject>>uniqueNameAt:put: (in category 'structure') -----
uniqueNameAt: aString put: aSkObject
        "put object with unique name"
        | rule oldKey newName |
        rule _ self rule.
        oldKey _ rule
                                keyAtValue: aSkObject
                                ifAbsent: [].
        "object has the name already"
        (aString notNil
                        and: [aString = oldKey])
                ifTrue: [^ aSkObject].
        "rename"
        oldKey
                ifNotNil: [rule removeAt: oldKey].
        newName _ self
                                uniqueNameLike: (aString
                                                ifNil: [self defaultName])
                                satisfy: [:s | (rule includesKey: s) not].
        rule at: newName put: aSkObject.
        "aSkObject parent: rule."
        ^ aSkObject!

----- Method: SkObject>>uniqueNameLike:satisfy: (in category 'support') -----
uniqueNameLike: aString satisfy: aBlock
"
self new uniqueNameLike: 'test' satisfy: [:s | (#('test' 'test1' 'test2') includes: s) not]
self new uniqueNameLike: 'test1' satisfy: [:s | (#('test' 'test1' 'test2') includes: s) not]
"
        | try |
        (aBlock value: aString)
                ifTrue: [^ aString]
                ifFalse: [1
                                to: 999999
                                do: [:i |
                                        try _ aString splitInteger first , i printString.
                                        (aBlock value: try)
                                                ifTrue: [^ try]]]!

----- Method: SkObject>>up (in category 'accessing') -----
up
        ^ self parent
                ifNil: [SkProject current]!

----- Method: SkObject>>updateKeys (in category 'accessing') -----
updateKeys
!

----- Method: SkObject>>updatePlan (in category 'updating') -----
updatePlan!

----- Method: SkObject>>wantsUpdate (in category 'updating') -----
wantsUpdate
        ^ false!

SkObject subclass: #SkParametric
        instanceVariableNames: 'func arg1 arg2'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base-Sheet'!

----- Method: SkParametric>>cellAt:ifAbsent: (in category 'accessing') -----
cellAt: aPoint ifAbsent: aBlock
        | holder |
        holder _ ValueHolder new.
        holder
                contents: ((arg1 isSkObject
                                ifTrue: [arg1 at: aPoint]
                                ifFalse: [arg1])
                                perform: func
                                with: (arg2 isSkObject
                                                ifTrue: [arg2 at: aPoint]
                                                ifFalse: [arg2])).
        ^ holder!

----- Method: SkParametric>>func:arg1:arg2: (in category 'initialization') -----
func: aSymbol arg1: obj1 arg2: obj2
        func _ aSymbol.
        arg1 _ obj1.
        arg2 _ obj2.
!

SkObject subclass: #SkProxy
        instanceVariableNames: 'rule map size direction'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkProxy class>>newForTest (in category 'instance creation') -----
newForTest
        "It is just used for test"
        ^ self newFrom: SkSheet new!

----- Method: SkProxy class>>newFrom: (in category 'instance creation') -----
newFrom: aSkObject
        ^ super new rule: aSkObject rule!

----- Method: SkProxy>>argPositions (in category 'accessing') -----
argPositions
        ^ (1 to: size)
                collect: [:index | index @ 1]!

----- Method: SkProxy>>assuredCellAt: (in category 'cell accessing') -----
assuredCellAt: key
        key class == Point
                ifFalse: [^ rule assuredCellAt: key].
        ^ map
                at: key
                ifAbsent: [map
                                at: key
                                put: (SkProxyCell new
                                                holderCell: SkValueCell new
                                                argCell: (rule assuredCellAt: key))]!

----- Method: SkProxy>>cardChanged (in category 'updating') -----
cardChanged
        self changed: #cardList.!

----- Method: SkProxy>>cardList: (in category 'accessing') -----
cardList: aRectangle
        ^ self cardPositions
                select: [:key | (self at: key) isSkObject]
                thenCollect: [:key | key
                                -> (self at: key)]!

----- Method: SkProxy>>cardPositions (in category 'accessing') -----
cardPositions
        ^ (map keys
                select: [:each | each class = Point
                                and: [(map at: each) hasCard]]) addAll: rule cardPositions;
                 yourself!

----- Method: SkProxy>>cellAt:ifAbsent: (in category 'cell accessing') -----
cellAt: key ifAbsent: aBlock
        ^ map
                at: key
                ifAbsent: [rule cellAt: key ifAbsent: aBlock]!

----- Method: SkProxy>>collectDependentsForCard: (in category 'updating') -----
collectDependentsForCard: aPoint
        | points dict |
        self flag: #TODO.
        "It has a BAD assumption"
        points _ self referenceAt: aPoint.
        dict _ Dictionary new.
        ^ points size > 1
                ifTrue: [dict at: points first put: {aPoint} asSet; yourself]!

----- Method: SkProxy>>direction (in category 'accessing') -----
direction
        ^ direction!

----- Method: SkProxy>>direction: (in category 'accessing') -----
direction: aSymbol
        direction _ aSymbol!

----- Method: SkProxy>>holder:at: (in category 'updating') -----
holder: aSkSheet at: aPoint
        | holderCell |
        (aSkSheet cellAt: aPoint) hasCard
                ifFalse: [^ aSkSheet].
        (self referenceAt: aPoint)
                withIndexDo: [:pos :index |
                        holderCell _ aSkSheet assuredCellAt: pos.
                        map
                                at: index @ 1
                                put: (SkProxyCell new
                                                holderCell: holderCell
                                                argCell: (rule assuredCellAt: index @ 1))]!

----- Method: SkProxy>>initialize (in category 'initialization') -----
initialize
        super initialize.
        direction _ #right.
        map _ Dictionary new.
        size _ 0!

----- Method: SkProxy>>installFormulaAt: (in category 'holder and card') -----
installFormulaAt: aPoint
        rule installFormulaAt: aPoint.
        "Cell is not needed where card is"
        (rule cellAt: aPoint) hasCard ifTrue: [
        self removeAt: aPoint].!

----- Method: SkProxy>>parent (in category 'structure') -----
parent
        ^ rule ifNotNil: [rule parent]!

----- Method: SkProxy>>parent: (in category 'structure') -----
parent: aSkRule
        rule parent: aSkRule!

----- Method: SkProxy>>referenceAt: (in category 'updating') -----
referenceAt: aPoint
        "Answer the dependents object's point"
        ^ self argPositions
                collect: [:each | self pointForHolder: aPoint at: each]!

----- Method: SkProxy>>removeAt: (in category 'cell accessing') -----
removeAt: key
        | cell |
        cell _ self cellAt: key.
        map
                removeKey: key
                ifAbsent: [].
        ^ cell!

----- Method: SkProxy>>resolveOn: (in category 'updating') -----
resolveOn: holder
        rule resolveOn: self!

----- Method: SkProxy>>rule (in category 'accessing') -----
rule
        ^ rule!

----- Method: SkProxy>>rule: (in category 'accessing') -----
rule: SkObject
        rule
                ifNotNil: [rule removeDependent: self].
        SkObject
                ifNotNil: [SkObject addDependent: self].
        rule _ SkObject
!

----- Method: SkProxy>>siblingWith: (in category 'copying') -----
siblingWith: deepCopier
        | new |
        new _ self clone.
        new siblingWithInner: deepCopier.
        ^ new!

----- Method: SkProxy>>siblingWithInner: (in category 'copying') -----
siblingWithInner: deepCopier
        map _ map veryDeepCopyWith: deepCopier.
        size _ size veryDeepCopyWith: deepCopier.
        direction _ direction veryDeepCopyWith: deepCopier.
        ^ self!

----- Method: SkProxy>>size (in category 'accessing') -----
size
        ^ size!

----- Method: SkProxy>>size: (in category 'accessing') -----
size: aNumber
        size _ aNumber!

----- Method: SkProxy>>up (in category 'accessing') -----
up
        ^ rule!

----- Method: SkProxy>>update: (in category 'updating') -----
update: anObject
        anObject == #cardList
                ifTrue: [self updateCardList].
        self changed: anObject!

----- Method: SkProxy>>updateCardList (in category 'updating') -----
updateCardList
        "Delete dispensable cards"
        | ruleCards |
        ruleCards _ rule cardPositions.
        (self cardPositions
                select: [:key | (ruleCards includes: key) not])
                do: [:key | self removeAt: key]!

----- Method: SkProxy>>updateKeys (in category 'accessing') -----
updateKeys
        rule updateKeys!

----- Method: SkProxy>>wantsSteps (in category 'updating') -----
wantsSteps
        ^ true!

SkObject subclass: #SkRefFinder
        instanceVariableNames: 'keys'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkRefFinder>>at: (in category 'accessing') -----
at: key
        keys add: key.
        ^ ''!

----- Method: SkRefFinder>>at:put: (in category 'accessing') -----
at: aPosition put: anObject
        ^ anObject!

----- Method: SkRefFinder>>initialize (in category 'initialization') -----
initialize
        super initialize.
        keys _ Set new.!

----- Method: SkRefFinder>>keys (in category 'accessing') -----
keys
        ^ keys!

Object subclass: #SkRule
        instanceVariableNames: 'observer subjects rule'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkRule class>>observer:subjects:rule: (in category 'instance creation') -----
observer: obs subjects: sub rule: aBlock
        ^ self new
                observer: obs
                subjects: sub
                rule: aBlock!

----- Method: SkRule>>observer:subjects:rule: (in category 'initialization') -----
observer: obs subjects: sub rule: aBlock
        observer _ obs.
        subjects _ sub.
        rule _ aBlock!

----- Method: SkRule>>printOn: (in category 'printing') -----
printOn: aStream
        observer printOn: aStream.
        aStream nextPutAll: ' rule: {'.
        subjects
                do: [:each |
                        each printOn: aStream.
                        aStream nextPut: $.].
        aStream nextPutAll: '} do: '.
        rule printOn: aStream.!

----- Method: SkRule>>resolveOn: (in category 'evaluating') -----
resolveOn: holder
        holder
                at: observer
                put: (rule
                                valueWithArguments: (subjects
                                                collect: [:each | holder at: each]))!

----- Method: Player>>asCellText (in category '*skeleton-base') -----
asCellText
        ^ '=References at: #', self uniqueNameForReference!

----- Method: Player>>clearColumn (in category '*skeleton-spreadsheet') -----
clearColumn
        0 to: self getTotalRows - 1 do: [:i |
                self sheet removeAt: self getColumnIndex @ i
        ]!

----- Method: Player>>clearRow (in category '*skeleton-spreadsheet') -----
clearRow
        0 to: self getTotalColumns - 1 do: [:i |
                self sheet removeAt: i @ self getRowIndex
        ]!

----- Method: Player>>clearTable (in category '*skeleton-spreadsheet') -----
clearTable
        0 to: self getTotalColumns - 1 do: [:i |
                0 to: self getTotalRows - 1 do: [:j |
                        self sheet removeAt: i @ j
                ]
        ]!

----- Method: Player>>csvFileName (in category '*skeleton-base') -----
csvFileName
        ^self sheetMorph valueOfProperty: #csvFileName ifAbsent: ['fileName.csv'].!

----- Method: Player>>csvFileName: (in category '*skeleton-base') -----
csvFileName: aString
        self sheetMorph setProperty: #csvFileName toValue: aString!

----- Method: Player>>csvSeparator (in category '*skeleton-base') -----
csvSeparator
        ^ self sheetMorph valueOfProperty: #csvSeparator ifAbsent: [$,].!

----- Method: Player>>csvSeparator: (in category '*skeleton-base') -----
csvSeparator: aCharacter
        self sheetMorph setProperty: #csvSeparator toValue: aCharacter!

----- Method: Player>>exportDataToFile (in category '*skeleton-data i/o') -----
exportDataToFile
        [self saveCSVFile: self csvFileName separator: self csvSeparator]
                on: Error do: [:err| ^ self inform: err description]!

----- Method: Player>>getColumnIndex (in category '*skeleton-spreadsheet') -----
getColumnIndex
        ^ self sheetMorph selection ifNil: [0] ifNotNil: [:rect | rect origin x]!

----- Method: Player>>getCsvFileName (in category '*skeleton-data i/o') -----
getCsvFileName
        ^ self csvFileName!

----- Method: Player>>getCsvSeparator (in category '*skeleton-data i/o') -----
getCsvSeparator
        ^ self csvSeparator asString!

----- Method: Player>>getCurrentCharacters (in category '*skeleton-spreadsheet') -----
getCurrentCharacters
        ^ (self sheet cellAt: self getColumnIndex @ self getRowIndex) contents!

----- Method: Player>>getCurrentNumericValue (in category '*skeleton-spreadsheet') -----
getCurrentNumericValue
        | str |
        ^ [(str := self getCurrentCharacters) asNumber]
                        ifError: [:err :rcvr | str asInteger ifNil: [0]]!

----- Method: Player>>getRowIndex (in category '*skeleton-spreadsheet') -----
getRowIndex
        ^ self sheetMorph selection ifNil: [0] ifNotNil: [:rect | rect origin y]!

----- Method: Player>>getTotalColumns (in category '*skeleton-spreadsheet') -----
getTotalColumns
        ^ self sheetMorph visibleArea corner x!

----- Method: Player>>getTotalRows (in category '*skeleton-spreadsheet') -----
getTotalRows
        ^ self sheetMorph visibleArea corner y!

----- Method: Player>>getWriteMode (in category '*skeleton-data i/o') -----
getWriteMode
        ^ self writeMode!

----- Method: Player>>importDataFromFile (in category '*skeleton-data i/o') -----
importDataFromFile
[[self openCSVFile: self csvFileName separator: self csvSeparator]
        on: FileDoesNotExistException do: [:err | self inform: 'The file doesn''t exist.' translated]]
        on: Error do: [:err | self inform: 'An error occurred. Please check if the file''s format is CSV.' translated].!

----- Method: Player>>openCSVFile:separator: (in category '*skeleton-data i/o') -----
openCSVFile: filePath separator: separator
        FileStream
                readOnlyFileNamed: filePath
                do: [:file || values rows columns |
                        values := (CSVParser on: file)
                                                        useDelimiter: separator;
                                                        rows.
                        rows := values size.
                        columns := values first size.
                        self setTotalRows: rows + 1;
                                setTotalColumns: columns + 1.
                        1 to: rows do: [:r|
                                1 to: columns do: [:c |
                                        ((values at: r) at: c ifAbsent: nil)
                                                ifNotNil: [:aString |
                                                        (self sheet assuredCellAt: c @ r) contents: aString]]]].!

----- Method: Player>>rows (in category '*skeleton-base') -----
rows
        ^ (1 to: self getTotalRows - 1) collect: [:r |
                (1 to: self getTotalColumns - 1) collect: [:c |
                 (self sheet cellAt: c @ r) contents]]!

----- Method: Player>>saveCSVFile:separator: (in category '*skeleton-data i/o') -----
saveCSVFile: filePath separator: separator
        FileStream
                perform: (self writeMode = #overwrite ifTrue: [#forceNewFileNamed:do:] ifFalse: [#fileNamed:do:])
                with: filePath
                with: [:file |
                        file setToEnd.
                        self rows do: [:row |
                                row do: [:cell | file
                                                nextPut: $";
                                                nextPutAll: (cell copyReplaceAll: '"' with: '""');
                                                nextPut: $"]
                                        separatedBy: [file nextPut: separator].
                                file cr]]!

----- Method: Player>>setColumnIndex: (in category '*skeleton-spreadsheet') -----
setColumnIndex: aNumber
        self sheetMorph selectSelection: (aNumber \\ self getTotalColumns) @ self getRowIndex!

----- Method: Player>>setCsvFileName: (in category '*skeleton-data i/o') -----
setCsvFileName: aString
        self csvFileName: aString!

----- Method: Player>>setCsvSeparator: (in category '*skeleton-data i/o') -----
setCsvSeparator: aString
        ^ self csvSeparator: (aString at: 1 ifAbsent: $,)!

----- Method: Player>>setCurrentCharacters: (in category '*skeleton-spreadsheet') -----
setCurrentCharacters: aString
        (self sheet assuredCellAt: self getColumnIndex @ self getRowIndex) contents: aString!

----- Method: Player>>setCurrentNumericValue: (in category '*skeleton-spreadsheet') -----
setCurrentNumericValue: aNumber
        self setCurrentCharacters: aNumber asString!

----- Method: Player>>setRowIndex: (in category '*skeleton-spreadsheet') -----
setRowIndex: aNumber
        self sheetMorph selectSelection: self getColumnIndex @ (aNumber \\ self getTotalRows)!

----- Method: Player>>setTotalColumns: (in category '*skeleton-spreadsheet') -----
setTotalColumns: aNumber
        ^ self sheetMorph area: (0@0 corner: aNumber @ self getTotalRows)!

----- Method: Player>>setTotalRows: (in category '*skeleton-spreadsheet') -----
setTotalRows: aNumber
        ^ self sheetMorph area: (0@0 corner: self getTotalColumns @ aNumber)!

----- Method: Player>>setWriteMode: (in category '*skeleton-data i/o') -----
setWriteMode: aSymbol
        (#(overwrite append) includes: aSymbol)
                ifTrue: [self writeMode: aSymbol]!

----- Method: Player>>sheet (in category '*skeleton-base') -----
sheet
        ^ self sheetMorph model!

----- Method: Player>>sheetMorph (in category '*skeleton-base') -----
sheetMorph
        ^ self costume renderedMorph!

----- Method: Player>>writeMode (in category '*skeleton-base') -----
writeMode
        ^self sheetMorph valueOfProperty: #writeMode ifAbsent: [#overwrite].!

----- Method: Player>>writeMode: (in category '*skeleton-base') -----
writeMode: aSymbol
        self sheetMorph setProperty: #writeMode toValue: aSymbol!

----- Method: SequenceableCollection>>split:do: (in category '*skeleton-base-sheet') -----
split: delimitor do: aBlock
        | start end |
        start _ 1.
        [start <= self size] whileTrue:
                [end _ self indexOf: delimitor startingAt: start ifAbsent: [self size + 1].
                end _ end - 1.
                aBlock value: (self copyFrom: start  to: end).
                start _ end + 2]

"
See SkSheetTest>>testSplitDo
'first second forth' delimited: Character tab do: [:aField | Transcript cr; show: aField]
'first
second

forth
' delimited: Character tab do: [:aField | Transcript cr; show: aField]
"!

----- Method: Morph>>addHalo: (in category '*skeleton-base-arrow') -----
addHalo: evt
        | halo prospectiveHaloClass |
        prospectiveHaloClass _ Smalltalk at: self haloClass ifAbsent: [HaloMorph].
        halo _ prospectiveHaloClass new bounds: self worldBoundsForHalo.
        halo popUpFor: self event: evt.
        self showPointArrow.
        ^halo!

----- Method: Morph>>arrowTargets (in category '*skeleton-base-arrow') -----
arrowTargets
        | player friends |
        player _ self player
                                ifNil: [^ #()].
        friends _ OrderedCollection new.
        player class allInstVarNames
                withIndexDo: [:name :index | ((#(#dependents #costume #costume ) includes: name) not
                                        and: [(player instVarAt: index)
                                                        isKindOf: Player])
                                ifTrue: [friends add: name
                                                        -> (player instVarAt: index)]].
        ^ friends!

----- Method: Morph>>endHaloInteraction (in category '*skeleton-base-sheet') -----
endHaloInteraction!

----- Method: Morph>>showPointArrow (in category '*skeleton-base-arrow') -----
showPointArrow
        "ActiveWorld submorphsDo: [:m | m showPointArrow]"
        self arrowTargets
                do: [:each | self
                                showPointArrowFrom: each value costume
                                to: self
                                label: each key]!

----- Method: Morph>>showPointArrowFrom:to:label: (in category '*skeleton-base-arrow') -----
showPointArrowFrom: morph1 to: morph2 label: aString
        "Morph new showPointArrowFrom: (Morph new position: 0@0) to: (Morph  
        new position: 200@200) label: 'test'"
        | p1 p2 arrow label connector |
        p1 := morph1 center.
        p2 := morph2 center.
        arrow := PolygonMorph arrowPrototype.
        arrow
                borderColor: (TranslucentColor
                                r: 1.0
                                g: 0.3
                                b: 0.0
                                alpha: 0.6).
        arrow
                setVertices: (Array with: p1 with: p2).
        arrow dashedBorder: {30. 30. Color transparent. 0. -10};
                 startStepping.
        (Smalltalk
                at: #NCConnectorMorph
                ifAbsent: [])
                ifNotNil: [connector := NCConnectorMorph fromMorph: morph1 toMorph: morph2.
                        connector line: arrow.
                        connector lock.
                        label := NCLabelMorph new string: aString.
                        label input: morph1.
                        label color: Color red.
                        label openInWorld.
                        arrow := connector].
        [arrow openInWorld.
        (Delay forMilliseconds: 500) wait.
        arrow delete.
        label
                ifNotNilDo: [:obj | obj delete]] fork!

Morph subclass: #SkGridMorph
        instanceVariableNames: 'area converter'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkGridMorph class>>standardCellExtent (in category 'constant') -----
standardCellExtent
        ^ 80 @ 20!

----- Method: SkGridMorph class>>titleStyle (in category 'constant') -----
titleStyle
        #(#NewYork #Accujen )
                do: [:fontName | (TextStyle named: fontName)
                                ifNotNilDo: [:style | ^ style fontOfPointSize: 24]].
        Error signal: 'Font not found'!

----- Method: SkGridMorph>>area (in category 'accessing') -----
area
        ^ area
!

----- Method: SkGridMorph>>area: (in category 'accessing') -----
area: aRectangle
        area = aRectangle
                ifTrue: [^ self].
        area _ aRectangle.
        self areaChanged.
        self changed!

----- Method: SkGridMorph>>areaChanged (in category 'layout') -----
areaChanged
        | newBounds |
        self visibleArea
                ifNil: [^ self hide]
                ifNotNil: [converter _ SkCellScreenConverter grid: self border: 1.
                        self show.
                        newBounds _ self cellAreaToScreen: self visibleArea.
                        self position: newBounds topLeft.
                        self extent: newBounds extent]!

----- Method: SkGridMorph>>borderStyle (in category 'visual properties') -----
borderStyle
        ^ self model
                ifNil: [super borderStyle]
                ifNotNil: [SkColorSet borderStyleFor: self model rule]!

----- Method: SkGridMorph>>cellAreaToScreen: (in category 'layout') -----
cellAreaToScreen: aRectangle
  ^ converter cellAreaToScreen: aRectangle topLeft: self topLeft + self expandSize!

----- Method: SkGridMorph>>cellExtentAt: (in category 'layout') -----
cellExtentAt: aPoint
        ^self class standardCellExtent!

----- Method: SkGridMorph>>cellOrigin (in category 'accessing') -----
cellOrigin
        ^ area origin
!

----- Method: SkGridMorph>>cellToScreenRect: (in category 'layout') -----
cellToScreenRect: aPoint
        ^ converter cellToScreenRect: aPoint topLeft: self topLeft + self expandSize!

----- Method: SkGridMorph>>drawBorder: (in category 'drawing') -----
drawBorder: aCanvas
        | y offset x borderColor borderWidth |
        offset _ self borderWidth // 2.
        borderColor _ self borderColor.
        borderWidth _ self borderWidth.
        self visibleArea top
                to: self visibleArea bottom - 2
                do: [:row |
                        y _ (self cellToScreenRect: self visibleArea right @ row) bottom + offset.
                        aCanvas
                                fillRectangle: (self left + borderWidth @ y corner: self right - borderWidth @ y + 1)
                                color: borderColor].
        self visibleArea left
                to: self visibleArea right - 2
                do: [:col |
                        x _ (self cellToScreenRect: col @ self visibleArea top) right + offset.
                        aCanvas
                                fillRectangle: (x @ (self top + borderWidth) corner: x + 1 @ (self bottom - borderWidth))
                                color: borderColor]!

----- Method: SkGridMorph>>drawCell:at: (in category 'drawing') -----
drawCell: aCanvas at: aPoint
!

----- Method: SkGridMorph>>drawContents: (in category 'drawing') -----
drawContents: aCanvas
        | block |
        block _ [self model
                                ifNil: [^ self].
                        self visibleArea top
                                to: self visibleArea bottom - 1
                                do: [:row | self visibleArea left
                                                to: self visibleArea right - 1
                                                do: [:col | self drawCell: aCanvas at: col @ row]]].
        self isDebug
                ifTrue: [[block value]
                                ifError: [:err :rcvr | rcvr]]
                ifFalse: [block value]!

----- Method: SkGridMorph>>drawContents:on:at: (in category 'drawing') -----
drawContents: anObject on: aCanvas at: aPoint
        "To debug, try
        self drawCell: World canvas at: 2@6  
        "
        | aRectangle string morph |
        (anObject isSkObject)
                ifTrue: [^ self].
        (anObject isKindOf: Player)
                ifTrue: [^ self
                                drawPlayer: anObject
                                on: aCanvas
                                at: aPoint].
        anObject = ''
                ifTrue: [^ self].
        aRectangle _ self localCellToScreenRect: aPoint.
        string _ anObject isString
                                ifTrue: [anObject]
                                ifFalse: [anObject isNumber
                                                ifTrue: [anObject asString]].
        string
                ifNil: [morph _ anObject isText
                                                ifTrue: [TextMorph new contents: anObject]
                                                ifFalse: [(anObject isKindOf: Player)
                                                                ifTrue: [anObject costume]
                                                                ifFalse: [anObject asMorph]].
                        aCanvas
                                translateTo: aRectangle topLeft - morph bounds origin
                                clippingTo: (aRectangle topLeft corner: self bottomRight)
                                during: [:c | morph drawOn: c]]
                ifNotNil: [aCanvas
                                drawString: string
                                in: (aRectangle expandBy: -2)
                                font: TextStyle defaultFont
                                color: Color black]!

----- Method: SkGridMorph>>drawDependMap: (in category 'drawing') -----
drawDependMap: aCanvas
        | subjectColor dependArray observer subjects observerColor |
        subjectColor _ SkColorSet selectedFor: self model rule.
        observerColor _ subjectColor adjustBrightness: -0.06.
        dependArray _ self model rule collectDependents.
        "draw subjects"
        aCanvas
                clipBy: self bounds
                during: [:canvas |
                        (dependArray
                                inject: Set new
                                into: [:set :next | set addAll: next allButFirst;
                                                 yourself])
                                do: [:each | canvas
                                                fillOval: ((self localCellToScreenRect: each) center - (7 @ 7) extent: 14 @ 14)
                                                fillStyle: subjectColor].
                        "draw objerver and line"
                        dependArray
                                do: [:each |
                                        observer _ each first.
                                        subjects _ each allButFirst.
                                        canvas
                                                fillOval: ((self localCellToScreenRect: observer) center - (4 @ 4) extent: 8 @ 8)
                                                fillStyle: observerColor.
                                        subjects
                                                do: [:end | canvas
                                                                line: (self localCellToScreenRect: observer) center
                                                                to: (self localCellToScreenRect: end) center
                                                                width: 1
                                                                color: observerColor]]]!

----- Method: SkGridMorph>>drawGrabAreaOn: (in category 'drawing') -----
drawGrabAreaOn: aCanvas
        | rect borderColor |
        borderColor _ self borderColor.
        rect _ self grabArea.
        rect left
                to: rect right
                by: 2
                do: [:x | aCanvas
                                frameRectangle: (x @ rect top corner: x + 1 @ rect bottom)
                                color: borderColor]!

----- Method: SkGridMorph>>drawLabel:string:at: (in category 'drawing') -----
drawLabel: aCanvas string: aString at: aPoint
        | aRectangle |
        aRectangle _ self localCellToScreenRect: aPoint.
        aCanvas
                clipBy: self bounds
                during: [:canvas |
                        canvas
                                fillRectangle: aRectangle
                                color: (SkColorSet
                                                labelFor: (self model
                                                                ifNotNil: [self model rule])).
                        canvas
                                drawString: aString asString
                                in: ((aRectangle expandBy: -2)
                                                withLeft: aRectangle left + 6)
                                font: ScriptingSystem fontForTiles
                                color: Color black]!

----- Method: SkGridMorph>>drawPlayer:on:at: (in category 'drawing') -----
drawPlayer: aPlayer on: aCanvas at: aPoint
        "To debug, try  
        self drawCell: World canvas at: 2@6  
        "
        | aRectangle morph form scaleX scaleY scale |
        morph _ aPlayer costume.
        aRectangle _ self localCellToScreenRect: aPoint.
        form _ morph imageForm.
        scaleY _ aRectangle height / form height.
        scaleX _ aRectangle width / form width.
        scale _ (scaleX min: scaleY)
                                min: 1.
        form _ form
                                magnify: form boundingBox
                                by: scale @ scale
                                smoothing: 2.
        aCanvas translucentImage: form at: (aRectangle topLeft + (aRectangle extent - form extent / 2)) asIntegerPoint!

----- Method: SkGridMorph>>expandSize (in category 'accessing') -----
expandSize
        ^ 0!

----- Method: SkGridMorph>>externalName (in category 'accessing') -----
externalName
        ^ self model
                ifNotNilDo: [:m | "name can be nil"
                        m ruleName asString]!

----- Method: SkGridMorph>>fillStyle: (in category 'visual properties') -----
fillStyle: aFillStyle
        super fillStyle: aFillStyle.
        self model
                ifNotNil: [SkColorSet for: self model rule color: aFillStyle asColor].
        self changed!

----- Method: SkGridMorph>>globalToLocal: (in category 'layout') -----
globalToLocal: aPoint
        ^ aPoint!

----- Method: SkGridMorph>>grabArea (in category 'accessing') -----
grabArea
        ^ (self topLeft corner: self right @ (self top + 16))
                insetBy: 3!

----- Method: SkGridMorph>>isDebug (in category 'debug') -----
isDebug
        ^ true!

----- Method: SkGridMorph>>labelAt: (in category 'drawing') -----
labelAt: aPoint
        aPoint x = aPoint y
                ifTrue: [^ ''].
        aPoint x = 0
                ifTrue: [^ aPoint y asString].
        ^ ($A asInteger + aPoint x - 1) asCharacter asString!

----- Method: SkGridMorph>>localCellToScreenRect: (in category 'layout') -----
localCellToScreenRect: aPoint
        ^ self cellToScreenRect: aPoint!

----- Method: SkGridMorph>>model (in category 'accessing') -----
model
        ^ self subclassResponsibility!

----- Method: SkGridMorph>>screenToCell: (in category 'layout') -----
screenToCell: aPoint
        ^ converter screenToCell: aPoint topLeft: self topLeft + self expandSize!

----- Method: SkGridMorph>>setExtentFromHalo: (in category 'layout') -----
setExtentFromHalo: newExtent
        "Answer new cell size"
        | newSize |
        newSize _ (self screenToCell: self topLeft + newExtent)
                                - self area origin.
        newSize _ newSize max: 1 @ 1.
        self area extent ~~ newSize
                ifTrue: [self
                                area: (self area origin extent: newSize)].
        ^ newSize!

----- Method: SkGridMorph>>visibleArea (in category 'accessing') -----
visibleArea
        ^ self area!

SkGridMorph subclass: #SkGridPartsMorph
        instanceVariableNames: 'holder'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

SkGridPartsMorph subclass: #SkCardMorph
        instanceVariableNames: 'model origin size'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkCardMorph commentStamp: 'tak 12/26/2003 19:45' prior: 0!
I am a Card bar of a rule.

area always NIL
model SkRule (maybe SkCard)
origin Point a position of label
size SmallInteger -- It is used when model has no size (it is ugly implementation...)

The morphs area is determined based on area's origin, size, and model's direction.!

----- Method: SkCardMorph class>>model: (in category 'instance creation') -----
model: aSkObject
        ^ super new model: aSkObject!

----- Method: SkCardMorph class>>new (in category 'instance creation') -----
new
        self error: 'SkCardMorph must only be created with model: aSkObject'!

----- Method: SkCardMorph class>>newFrom: (in category 'instance creation') -----
newFrom: aSkSheetMorph
        | cardMorph |
        cardMorph _ self model: aSkSheetMorph model.
        cardMorph
                area: (0 @ 1 extent: aSkSheetMorph area width @ 1).
        cardMorph position: aSkSheetMorph position.
        ^ cardMorph!

----- Method: SkCardMorph>>addFlexShellIfNecessary (in category 'rotate scale and flex') -----
addFlexShellIfNecessary
        "When scaling or rotating from a halo, I can do this without a flex shell"

        ^ self
!

----- Method: SkCardMorph>>area (in category 'accessing') -----
area
        ^ model direction = #right
                ifTrue: [origin extent: self size + 1 @ 1]
                ifFalse: [model direction = #down
                                ifTrue: [origin extent: 1 @ (self size + 1)]
                                ifFalse: [model direction = #left
                                                ifTrue: [origin - (self size @ 0) corner: origin + 1]
                                                ifFalse: [origin - (0 @ self size) corner: origin + 1]]]!

----- Method: SkCardMorph>>area: (in category 'accessing') -----
area: aRectangle
        "area corner is determined by size and direction"
        self
                cellOrigin: ((#(#right #down ) includes: model direction)
                                ifTrue: [aRectangle origin]
                                ifFalse: [model direction = #left
                                                ifTrue: [aRectangle origin + (self size @ 0)]
                                                ifFalse: [aRectangle origin + (0 @ self size)]]).
        self isHorizonal
                ifTrue: [self size: aRectangle width - 1]
                ifFalse: [self size: aRectangle height - 1].
        self changed!

----- Method: SkCardMorph>>cellOrigin (in category 'accessing') -----
cellOrigin
        "The cell point which has label"
        ^ origin!

----- Method: SkCardMorph>>cellOrigin: (in category 'accessing') -----
cellOrigin: aPoint
        "The cell point which has label"
        origin _ aPoint.
        self areaChanged.!

----- Method: SkCardMorph>>direction (in category 'accessing') -----
direction
        ^ model direction!

----- Method: SkCardMorph>>direction: (in category 'accessing') -----
direction: aSymbol
        self
                keepCellOriginDo: [model direction: aSymbol]!

----- Method: SkCardMorph>>doubleClick: (in category 'event handling') -----
doubleClick: evt
        | sheet |
        (holder notNil
                        and: [owner = holder])
                ifTrue: [^ holder goto: model].
        self owner = World
                ifTrue: [self delete].
        sheet _ SkSheetMorph allInstances
                                detect: [:each | each world = World
                                                and: [each model = model]]
                                ifNone: [model grid].
        sheet position: self position;
                 openInWorld!

----- Method: SkCardMorph>>drawCell:at: (in category 'drawing') -----
drawCell: aCanvas at: aPoint
        | modelPoint |
        modelPoint _ self globalToLocal: aPoint.
        modelPoint = (0 @ 1)
                ifTrue: [^ self
                                drawLabel: aCanvas
                                string: model ruleName
                                at: modelPoint].
        self drawContents: (model at: modelPoint) on: aCanvas at: modelPoint.
!

----- Method: SkCardMorph>>drawOn: (in category 'drawing') -----
drawOn: aCanvas
        super drawOn: aCanvas.
        self drawGrabAreaOn: aCanvas.
        self drawContents: aCanvas.
        self drawBorder: aCanvas!

----- Method: SkCardMorph>>endHaloInteraction (in category 'event handling') -----
endHaloInteraction
        self isOnHolder
                ifFalse: [^ self].
        holder model textAt: self cellOrigin put: '=' , model codeString.
        self halo
                ifNotNilDo: [:halo |
                        halo
                                setTarget: (holder
                                                cardMorphAt: self cellOrigin
                                                ifAbsent: []).
                        self delete]!

----- Method: SkCardMorph>>expandSize (in category 'accessing') -----
expandSize
        ^ -2!

----- Method: SkCardMorph>>fillStyle (in category 'visual properties') -----
fillStyle
        ^ SkColorSet baseFor: model rule!

----- Method: SkCardMorph>>globalToLocal: (in category 'layout') -----
globalToLocal: aPoint
        "Transformation a position of cell"
        | normalized |
        normalized _ aPoint - self cellOrigin.
        model direction = #left
                ifTrue: [^ normalized * -1 + (0 @ 1)].
        model direction = #down
                ifTrue: [^ normalized transposed + (0 @ 1)].
        model direction = #up
                ifTrue: [^ normalized transposed * -1 + (0 @ 1)].
        ^ normalized + (0 @ 1)!

----- Method: SkCardMorph>>grabArea (in category 'accessing') -----
grabArea
        | width inset base |
        width _ 16.
        inset _ 3.
        base _ self cellToScreenRect: self cellOrigin.
        ^ model direction = #right
                ifTrue: [(base topLeft corner: base left + width @ base bottom)
                                insetBy: inset]
                ifFalse: [model direction = #down
                                ifTrue: [(base topLeft corner: base right @ (base top + width))
                                                insetBy: inset]
                                ifFalse: [model direction = #left
                                                ifTrue: [(base right - width @ base top corner: base bottomRight)
                                                                insetBy: inset]
                                                ifFalse: [(base left @ (base bottom - width) corner: base bottomRight)
                                                                insetBy: inset]]]!

----- Method: SkCardMorph>>handlesMouseDown: (in category 'event handling') -----
handlesMouseDown: evt
        ^ (self screenToCell: evt position)
                = self cellOrigin!

----- Method: SkCardMorph>>holderArea (in category 'accessing') -----
holderArea
        ^ 1@1 corner: holder area bottomRight!

----- Method: SkCardMorph>>initialize (in category 'initialization') -----
initialize
        super initialize.
        origin _ 0 @ 0.
        self
                borderStyle: (RaisedBorder color: Color black width: 1).
        self
                fillStyle: (SolidFillStyle
                                color: (Color
                                                r: 1.0
                                                g: 0.935
                                                b: 0.839)).
        self cornerStyle: #rounded!

----- Method: SkCardMorph>>isHorizonal (in category 'testing') -----
isHorizonal
        ^ #(#right #left ) includes: model direction!

----- Method: SkCardMorph>>isMorphicModel (in category 'classification') -----
isMorphicModel
        ^true!

----- Method: SkCardMorph>>keepCellOriginDo: (in category 'accessing') -----
keepCellOriginDo: aBlock
        | oldOriginByScreen delta |
        oldOriginByScreen _ (self cellToScreenRect: self cellOrigin) topLeft.
        aBlock value.
        self areaChanged.
        delta _ oldOriginByScreen - (self cellToScreenRect: self cellOrigin) topLeft.
        self topLeft: self topLeft + delta.
        self areaChanged!

----- Method: SkCardMorph>>localCellToScreenRect: (in category 'layout') -----
localCellToScreenRect: aPoint
        ^ self
                cellToScreenRect: (self localToGlobal: aPoint)!

----- Method: SkCardMorph>>localToGlobal: (in category 'layout') -----
localToGlobal: aPoint
        | normalized |
        normalized _ aPoint + (0 @ -1).
        model direction = #left
                ifTrue: [^ normalized * -1 + self cellOrigin].
        model direction = #down
                ifTrue: [^ normalized transposed + self cellOrigin].
        model direction = #up
                ifTrue: [^ normalized transposed * -1 + self cellOrigin].
        ^ normalized + self cellOrigin!

----- Method: SkCardMorph>>model (in category 'accessing') -----
model
        ^ model!

----- Method: SkCardMorph>>model: (in category 'accessing') -----
model: aSkRule
        model _ aSkRule.
        self areaChanged!

----- Method: SkCardMorph>>mouseDown: (in category 'event handling') -----
mouseDown: evt
        "For easy doublecilck to selection"
        evt hand waitForClicksOrDrag: self event: evt.
        evt yellowButtonPressed
                ifTrue: [^ model invokeCardMenu: evt]
                ifFalse: [(self grabArea containsPoint: evt position)
                                ifTrue: [evt hand grabMorph: self]]!

----- Method: SkCardMorph>>referencePosition (in category 'rotate scale and flex') -----
referencePosition
        ^ (self cellToScreenRect: self cellOrigin) center!

----- Method: SkCardMorph>>replaceToSheet: (in category 'layout') -----
replaceToSheet: newCellExtent
        "Create new spreadsheet for the model. And I will be deleted"
        | sheetMorph |
        (newCellExtent y > 1
                        and: [newCellExtent x > 1])
                ifTrue: [sheetMorph _ SkSheetMorph new model: model.
                        sheetMorph
                                area: (0 @ 0 extent: newCellExtent).
                        sheetMorph position: self position.
                        self owner addMorph: sheetMorph.
                        self halo
                                ifNotNilDo: [:helo | helo setTarget: sheetMorph].
                        ^ self delete]!

----- Method: SkCardMorph>>rotationDegrees: (in category 'rotate scale and flex') -----
rotationDegrees: degrees
        | d newDirection |
        d _ degrees \\ 360.
        newDirection _ #right.
        (d < 45
                        or: [315 <= d])
                ifTrue: [newDirection _ #right]
                ifFalse: [d < 135
                                ifTrue: [newDirection _ #down]
                                ifFalse: [d < 225
                                                ifTrue: [newDirection _ #left]
                                                ifFalse: [d < 315
                                                                ifTrue: [newDirection _ #up]]]].
        self forwardDirection: degrees.
        self direction ~~ newDirection
                ifTrue: ["Transcript show: ActiveHand target printString."
                        self direction: newDirection.
                        self halo
                                ifNil: [self isOnHolder
                                                ifTrue: [holder model textAt: self cellOrigin put: '=' , model codeString]]].
        self changed!

----- Method: SkCardMorph>>setExtentFromHalo: (in category 'layout') -----
setExtentFromHalo: newExtent
        | newCellExtent nSize |
        newCellExtent _ (self screenToCell: ActiveHand position - 10)
                                - origin.
        (newCellExtent y > 1
                        and: [newCellExtent x > 1])
                ifTrue: [^ self replaceToSheet: newCellExtent].
        nSize _ (newCellExtent x abs max: newCellExtent y abs)
                                max: 0.
        newCellExtent y > (0 - newCellExtent x)
                ifTrue: [newCellExtent y < newCellExtent x
                                ifTrue: [self direction: #right]
                                ifFalse: [self direction: #down]]
                ifFalse: [newCellExtent y < newCellExtent x
                                ifTrue: [self direction: #up]
                                ifFalse: [self direction: #left]].
        self size: nSize!

----- Method: SkCardMorph>>size (in category 'accessing') -----
size
        ^ model size
                ifNil: [size
                                ifNil: [size _ 0]]!

----- Method: SkCardMorph>>size: (in category 'accessing') -----
size: aNumber
        (aNumber > 0
                        and: [model isInstance not])
                ifTrue: [self
                                model: model new].
        self
                keepCellOriginDo: [model size
                                ifNil: ["Maybe it doesn't need"
                                        nil.
                                        size _ aNumber]
                                ifNotNil: [model size: aNumber]]!

----- Method: SkCardMorph>>veryDeepInner: (in category 'accessing') -----
veryDeepInner: deepCopier
        "rule is not copied"
        model _ model siblingWith: deepCopier.
        origin _ origin veryDeepCopyWith: deepCopier.
        size _ size veryDeepCopyWith: deepCopier.
        super veryDeepInner: deepCopier!

----- Method: SkGridPartsMorph>>cellAreaToScreen: (in category 'layout') -----
cellAreaToScreen: aRectangle
        ^ (self isOnHolder
                ifTrue: [holder cellAreaToScreen: aRectangle]
                ifFalse: [super cellAreaToScreen: aRectangle])
                expandBy: self expandSize!

----- Method: SkGridPartsMorph>>cellToScreenRect: (in category 'layout') -----
cellToScreenRect: aRectangle
        ^ self isOnHolder
                ifTrue: [holder cellToScreenRect: aRectangle]
                ifFalse: [super cellToScreenRect: aRectangle]!

----- Method: SkGridPartsMorph>>holder (in category 'accessing') -----
holder
        "it's only for test"
        ^ holder.!

----- Method: SkGridPartsMorph>>holder: (in category 'accessing') -----
holder: anObject
        holder _ anObject!

----- Method: SkGridPartsMorph>>holderArea (in category 'accessing') -----
holderArea
        ^ holder area!

----- Method: SkGridPartsMorph>>isOnHolder (in category 'testing') -----
isOnHolder
        ^ holder notNil
                and: [owner = holder]!

----- Method: SkGridPartsMorph>>veryDeepInner: (in category 'copying') -----
veryDeepInner: deepCopier
        "holder is not copied"
!

----- Method: SkGridPartsMorph>>visibleArea (in category 'accessing') -----
visibleArea
        "Answer nil if no intersect"
        | visibleArea |
        self area
                ifNil: [^ nil].
        ^ self isOnHolder
                ifTrue: [visibleArea _ self area intersect: self holderArea.
                        visibleArea hasPositiveExtent
                                ifTrue: [visibleArea]]
                ifFalse: [self area]!

SkGridPartsMorph subclass: #SkGridSelectionMorph
        instanceVariableNames: 'editor'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkGridSelectionMorph>>area: (in category 'accessing') -----
area: aRectangle
        editor
                ifNil: [super area: aRectangle]
                ifNotNil: [(editor text isEmpty not
                                        and: [editor text first = $=
                                                        and: [editor hasUnacceptedEdits]])
                                ifTrue: [editor
                                                correctSelectionWithString: (SkParser pointToA1Name: aRectangle origin)]
                                ifFalse: [editor accept.
                                        editor _ nil.
                                        super area: aRectangle]]!

----- Method: SkGridSelectionMorph>>borderStyle (in category 'visual properties') -----
borderStyle
        ^ SkColorSet
                selectedBorderStyleFor: (holder
                                ifNotNil: [holder model rule])!

----- Method: SkGridSelectionMorph>>deleteEditor (in category 'accessing') -----
deleteEditor
        editor delete.
        editor _ nil!

----- Method: SkGridSelectionMorph>>doubleClick: (in category 'event handling') -----
doubleClick: evt
        (self bounds containsPoint: ActiveHand position)
                ifTrue: [self installEditor]!

----- Method: SkGridSelectionMorph>>drawOn: (in category 'drawing') -----
drawOn: aCanvas
        | clip |
        clip _ aCanvas copyClipRect: self bounds.
        super drawOn: aCanvas.
        editor
                ifNil: [holder drawBorder: clip.
                        holder drawContents: clip]!

----- Method: SkGridSelectionMorph>>editor (in category 'accessing') -----
editor
        ^ editor!

----- Method: SkGridSelectionMorph>>expandSize (in category 'accessing') -----
expandSize
        ^ 2!

----- Method: SkGridSelectionMorph>>externalName (in category 'accessing') -----
externalName
        ^ SkParser pointToA1Name: area topLeft!

----- Method: SkGridSelectionMorph>>fillStyle (in category 'visual properties') -----
fillStyle
        ^ SkColorSet
                selectedFor: (holder
                                ifNotNil: [holder model rule])!

----- Method: SkGridSelectionMorph>>handlesKeyboard: (in category 'event handling') -----
handlesKeyboard: evt
        ^ true!

----- Method: SkGridSelectionMorph>>handlesMouseDown: (in category 'event handling') -----
handlesMouseDown: evt
        ^ true!

----- Method: SkGridSelectionMorph>>initialize (in category 'initialization') -----
initialize
        super initialize.
        area _ 1 @ 1 extent: 4 @ 4.
        self
                borderStyle: (RaisedBorder color: Color black width: 1).
        self
                fillStyle: (SolidFillStyle
                                color: (Color
                                                r: 1.0
                                                g: 0.935
                                                b: 0.839)).
" self cornerStyle: #rounded"!

----- Method: SkGridSelectionMorph>>installEditor (in category 'event handling') -----
installEditor
        self area ifNil: [^self].
        editor
                ifNil: [editor _ PluggableTextMorph
                                                on: holder
                                                text: #editContents
                                                accept: #editContents:].
        editor setProperty: #alwaysAccept toValue: true.
        editor acceptOnCR: true.
        editor hideScrollBarIndefinitely.
        editor borderWidth: 0.
        editor
                bounds: (holder cellToScreenRect: self area origin).
        editor selectAll.
        self addMorphFront: editor.
        ActiveHand newKeyboardFocus: editor.
        editor
                on: #mouseLeave
                send: holder
                to: #acceptCell!

----- Method: SkGridSelectionMorph>>invokeMenu: (in category 'menu') -----
invokeMenu: evt
        | menu |
        menu _ MenuMorph new defaultTarget: holder.
        (holder model cellAt: self area topLeft) label
                ifNotNilDo: [:label | menu addTitle: label].
        menu
                add: (holder showFormula
                                ifTrue: ['<on>']
                                ifFalse: ['<off>'])
                                , 'formula' translated
                target: holder
                selector: #toggleFormula.
        (holder model cellAt: self area topLeft) player
                ifNotNilDo: [:player |
                        menu
                                add: 'reveal this object'
                                target: player
                                selector: #revealPlayerIn:
                                argument: ActiveWorld.
                        player costume
                                showPointArrowFrom: player costume
                                to: self
                                label: ' '].
        menu addList: {{'library' translated. #openLibrary}.
                                 #-.
                                {'copy (c)' translated. #copySelection}.
                                {'cut (x)' translated. #cut}.
                                {'paste (v)' translated. #paste}.
                                {'spawn (o)' translated. #spawn}}.
        menu popUpEvent: evt in: self world!

----- Method: SkGridSelectionMorph>>keyStroke: (in category 'event handling') -----
keyStroke: evt
        evt keyValue = $c asciiValue
                ifTrue: [^ holder copySelection].
        evt keyValue = $o asciiValue
                ifTrue: [^ holder spawn].
        evt keyValue = $v asciiValue
                ifTrue: [^ holder paste].
        evt keyValue = $x asciiValue
                ifTrue: [^ holder cut].
        self installEditor.
        editor ifNotNil: [editor keyStroke: evt].!

----- Method: SkGridSelectionMorph>>model (in category 'accessing') -----
model
        ^ holder
                ifNotNil: [holder model]!

----- Method: SkGridSelectionMorph>>mouseDown: (in category 'event handling') -----
mouseDown: evt
        evt yellowButtonPressed
                ifTrue: [^ self invokeMenu: evt].
        owner
                ifNotNil: [owner mouseDown: evt]!

----- Method: SkGridSelectionMorph>>mouseMove: (in category 'event handling') -----
mouseMove: evt
        | newArea |
        newArea _ self area encompass: (holder screenToCell: evt position)
                                        + 1.
        area _ newArea.
        self areaChanged!

----- Method: SkGridSelectionMorph>>screenToCell: (in category 'layout') -----
screenToCell: aPoint
        ^ holder
                ifNil: [super screenToCell: aPoint]
                ifNotNil: [holder screenToCell: aPoint]!

----- Method: SkGridSelectionMorph>>setExtentFromHalo: (in category 'layout') -----
setExtentFromHalo: newExtent
        self isOnHolder
                ifTrue: [holder setCellExtentFromHalo: newExtent]!

SkGridMorph subclass: #SkSheetMorph
        instanceVariableNames: 'history model selectionMorph dropZone showFormula'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

!SkSheetMorph commentStamp: 'tak 12/11/2003 19:10' prior: 0!
I am a presentation compornent for showing as 2-D grid.
The contents what I show is depended on a model.
I never access to a cell directly except through model because
a cell doesn't know where he locates. Basically, Position information is
only in model.

cellArea Rectangle -- the area of cells for drawing. Actual size of table is cellArea extent.
model SkSheet --
!

----- Method: SkSheetMorph class>>additionsToViewerCategories (in category 'viewer categories') -----
additionsToViewerCategories
^ #(
(#spreadsheet (
#(command clearTable 'Deletes the contents of all cells')
#(command clearRow 'Deletes the contents of the current row cells' )
#(command clearColumn 'Deletes the contents of the current columns cells' )
#(slot totalRows 'Lets you change the amount of rows in the spreadsheet' Number readWrite Player getTotalRows Player setTotalRows:  )
#(slot totalColumns 'Lets you change the amount of columns in the spreadsheet' Number readWrite Player getTotalColumns Player setTotalColumns:  )
#(slot rowIndex 'Sets the current row' Number readWrite Player getRowIndex Player setRowIndex:  )
#(slot columnIndex 'Sets the current column' Number readWrite Player getColumnIndex Player setColumnIndex:  )
#(slot currentCharacters 'Lets you read and modify the characters of the current cell' String readWrite Player getCurrentCharacters Player setCurrentCharacters:  )
#(slot currentNumericValue 'Lets you read and modify the numeric value of the current cell' Number readWrite Player getCurrentNumericValue Player setCurrentNumericValue:  )
))

(#'data i/o' (
#(slot writeMode 'Lets you choose a write mode (overwrite or append)' WriteMode readWrite Player getWriteMode Player setWriteMode:  )
#(slot csvSeparator 'Lets you choose a character to act as a separator between cells' String readWrite Player getCsvSeparator Player setCsvSeparator:  )
#(slot csvFileName 'Sets the name of the file to import/export data' String readWrite Player getCsvFileName Player setCsvFileName:  )
#(command importDataFromFile 'Reads the data from the file and loads it in the spreadsheet')
#(command exportDataToFile 'Writes the data from the spreadsheet into the file')
))

)!

----- Method: SkSheetMorph class>>descriptionForPartsBin (in category 'parts bin') -----
descriptionForPartsBin
        ^ self partName: 'Spread Sheet'
                categories: #('Skeleton')
                documentation: 'A spread sheet'!

----- Method: SkSheetMorph class>>formPreviousPage (in category 'constants') -----
formPreviousPage
 ^((ColorForm
        extent: 5@9
        depth: 1
        fromArray: #( 4026531840 3758096384 3489660928 2952790016 1879048192 2952790016 3489660928 3758096384 4026531840)
        offset: 0@0)
        colorsFromArray: #(#(0.0 0.0 0.0) #( )  ))
" form storeString "!

----- Method: SkSheetMorph class>>formUpPage (in category 'constants') -----
formUpPage
 ^((ColorForm
        extent: 9@5
        depth: 2
        fromArray: #( 2859106304 2845474816 2795929600 2326298624 1431650304)
        offset: 0@0)
        colorsFromArray: #(#(0.004 0.004 0.008) #(0.0 0.0 0.004) #( ) #(0.0 0.0 0.0)  ))
" form storeString "!

----- Method: SkSheetMorph class>>initialize (in category 'class initialization') -----
initialize
        "
        self initialize.
        "
        Vocabulary addStandardVocabulary: (SymbolListType new vocabularyName: #WriteMode;
                         symbols: #(#overwrite #append)).!

----- Method: SkSheetMorph class>>model: (in category 'instance creation') -----
model: aSkObject
        ^ super new model: aSkObject!

----- Method: SkSheetMorph>>acceptDroppingMorph:event: (in category 'drag and drop') -----
acceptDroppingMorph: aMorph event: evt
        | cellPos successed |
        cellPos _ self screenToCell: aMorph topLeft.
        (cellPos x < 1
                        or: [cellPos y < 1])
                ifTrue: [self beep: 'arrow'.
                        ^ aMorph rejectDropMorphEvent: evt].
        successed _ false.
        successed _ (aMorph isKindOf: SkGridPartsMorph)
                                ifTrue: [self acceptRuleMorph: aMorph event: evt]
                                ifFalse: [aMorph class = PhraseTileMorph
                                                ifTrue: [self acceptPhraseTileMorph: aMorph event: evt]
                                                ifFalse: [aMorph class = TileMorph
                                                                ifTrue: [self acceptTileMorph: aMorph event: evt]]].
        successed
                ifTrue: [self beep: 'cassete']
                ifFalse: [self beep: 'arrow'.
                        aMorph rejectDropMorphEvent: evt]!

----- Method: SkSheetMorph>>acceptPhraseTileMorph:event: (in category 'drag and drop') -----
acceptPhraseTileMorph: aMorph event: evt
        | setter getter |
        getter _ aMorph operatorTile operatorOrExpression.
        setter _ ('set'
                                , (getter allButFirst: 3) , ':') asSymbol.
        self model
                modelAt: (self screenToCell: aMorph topLeft)
                for: aMorph actualObject
                getter: getter
                setter: setter.
        ^ true!

----- Method: SkSheetMorph>>acceptRuleMorph:event: (in category 'drag and drop') -----
acceptRuleMorph: aMorph event: evt
        | cellPos card |
        model parent adopt: aMorph model rule.
        cellPos _ (self screenToCell: aMorph topLeft)
                                + (aMorph cellOrigin - aMorph area topLeft).
        self model textAt: cellPos put: '=' , aMorph model codeString.
        card _ self
                                cardMorphAt: cellPos
                                ifAbsent: [^ false].
        card model rule = aMorph model rule
                ifFalse: ["maybe successed"
                        ^ false].
        aMorph halo
                ifNotNilDo: [:halo | halo setTarget: card].
        ^ true!

----- Method: SkSheetMorph>>acceptTileMorph:event: (in category 'drag and drop') -----
acceptTileMorph: aMorph event: evt
        | object |
        object _ aMorph actualObject.
        self model
                at: (self screenToCell: aMorph topLeft)
                put: object.
        ^ true!

----- Method: SkSheetMorph>>areaChanged (in category 'layout') -----
areaChanged
        super areaChanged.
        self
                submorphsDo: [:m | (m isKindOf: SkGridMorph)
                                ifTrue: [m areaChanged]]!

----- Method: SkSheetMorph>>cardMorphAt:ifAbsent: (in category 'accessing') -----
cardMorphAt: aPoint ifAbsent: aBlock
        ^ self submorphs
                detect: [:m | m class = SkCardMorph
                                and: [m cellOrigin = aPoint]]
                ifNone: aBlock!

----- Method: SkSheetMorph>>cellExtentAt: (in category 'layout') -----
cellExtentAt: aPoint
        | cellExtent x y |
        ^ (model notNil
                        and: [(cellExtent _ model findName: self cellExtentName) class == SkSheet ])
                ifTrue: [x _ (cellExtent
                                                at: aPoint x @ 1
                                                ifAbsent: [SkGridMorph standardCellExtent]) x.
                        y _ (cellExtent
                                                at: 1 @ aPoint y
                                                ifAbsent: [SkGridMorph standardCellExtent]) y.
                        x @ y]
                ifFalse: [SkGridMorph standardCellExtent]!

----- Method: SkSheetMorph>>cellExtentName (in category 'layout') -----
cellExtentName
        ^ 'CellExtent'!

----- Method: SkSheetMorph>>copySelection (in category 'action') -----
copySelection
        | text |
        text _ Text
                                streamContents: [:aStream | self selection top
                                                to: self selection bottom - 1
                                                do: [:y |
                                                        (self selection left to: self selection right - 1)
                                                                do: [:x | aStream
                                                                                nextPutAll: (model textAt: x @ y)]
                                                                separatedBy: [aStream nextPut: Character tab].
                                                        aStream nextPut: Character cr]].
        Clipboard clipboardText: text!

----- Method: SkSheetMorph>>cut (in category 'action') -----
cut
        self copySelection.
        self selection top
                to: self selection bottom - 1
                do: [:y | self selection left
                                to: self selection right - 1
                                do: [:x | model textAt: x @ y put: '']]!

----- Method: SkSheetMorph>>drawCell:at: (in category 'drawing') -----
drawCell: aCanvas at: aPoint
        (aPoint x isZero
                        or: [aPoint y isZero])
                ifTrue: [^ self
                                drawLabel: aCanvas
                                string: (self labelAt: aPoint)
                                at: aPoint].
        self flag: #TODO.
        self
                drawContents: ((showFormula notNil
                                        and: [showFormula])
                                ifTrue: [model textAt: aPoint]
                                ifFalse: [ showFormula _ false.model at: aPoint.])
                on: aCanvas
                at: aPoint!

----- Method: SkSheetMorph>>drawName: (in category 'drawing') -----
drawName: aCanvas
        | name |
        name := model ruleName asString.
        model isInstance
                ifTrue: [name := name , '*'].
        aCanvas
                clipBy: self bounds
                during: [:canvas | canvas
                                drawString: name
                                at: self topLeft + (28 @ 6)
                                font: self class titleStyle
                                color: Color gray]!

----- Method: SkSheetMorph>>drawOn: (in category 'drawing') -----
drawOn: aCanvas
        super drawOn: aCanvas.
        self drawGrabAreaOn: aCanvas.
        dropZone
                ifNotNil: [aCanvas
                                fillRectangle: (self
                                                cellAreaToScreen: (dropZone intersect: area))
                                fillStyle: (SkColorSet labelFor: model)
                                borderStyle: self borderStyle].
        self drawDependMap: aCanvas.
        self drawName: aCanvas.
        self drawBorder: aCanvas.
        self drawContents: aCanvas!

----- Method: SkSheetMorph>>editContents (in category 'accessing') -----
editContents
self selection ifNil: [^''].
        ^ model
                ifNil: ['']
                ifNotNil: [model textAt: self selection origin]!

----- Method: SkSheetMorph>>editContents: (in category 'accessing') -----
editContents: aText
        "Accept text"
        self selection ifNil: [^self].
        model
                ifNotNil: [model textAt: self selection origin put: aText].
        selectionMorph deleteEditor!

----- Method: SkSheetMorph>>fillStyle (in category 'visual properties') -----
fillStyle
        ^ SkColorSet baseFor: model rule!

----- Method: SkSheetMorph>>goto: (in category 'navigation') -----
goto: aSkObject
        | grid |
        self beep: 'rice'.
        grid _ aSkObject grid.
        self replace: grid.
        grid history: self.
        ^ grid!

----- Method: SkSheetMorph>>handlesKeyboard: (in category 'event handling') -----
handlesKeyboard: evt
        ^ true!

----- Method: SkSheetMorph>>handlesMouseDown: (in category 'event handling') -----
handlesMouseDown: evt
        ^ (self grabArea containsPoint: evt position) not!

----- Method: SkSheetMorph>>handlesMouseOver: (in category 'event handling') -----
handlesMouseOver: evt
        ^ true
!

----- Method: SkSheetMorph>>handlesMouseOverDragging: (in category 'event handling') -----
handlesMouseOverDragging: evt

        ^ true
!

----- Method: SkSheetMorph>>height: (in category 'accessing') -----
height: aNumber
        ^ self setExtentFromHalo: self width @ aNumber!

----- Method: SkSheetMorph>>history: (in category 'navigation') -----
history: aSkSheetMorph
        history
                ifNil: [history _ aSkSheetMorph]!

----- Method: SkSheetMorph>>initialize (in category 'initialization') -----
initialize
        super initialize.
        self showPageControls.
        selectionMorph _ SkGridSelectionMorph new holder: self.
        self
                area: (1 @ 1 extent: 4 @ 4).
        self
                borderStyle: (RaisedBorder color: Color black width: 1).
        self
                fillStyle: (SolidFillStyle
                                color: (Color
                                                r: 1.0
                                                g: 0.935
                                                b: 0.839)).
        self cornerStyle: #rounded.
        self selection: nil.
        showFormula _ false!

----- Method: SkSheetMorph>>initializeToStandAlone (in category 'parts bin') -----
initializeToStandAlone
        super initializeToStandAlone.
        self model: SkSheet new attachProject.
        self
                area: (0 @ 0 extent: 3 @ 3)!

----- Method: SkSheetMorph>>isModelStepping (in category 'stepping and presenter') -----
isModelStepping
        ^ model isStepping!

----- Method: SkSheetMorph>>isMorphicModel (in category 'classification') -----
isMorphicModel
        ^true!

----- Method: SkSheetMorph>>keyStroke: (in category 'event handling') -----
keyStroke: evt
        selectionMorph keyStroke: evt!

----- Method: SkSheetMorph>>model (in category 'accessing') -----
model
        ^ model!

----- Method: SkSheetMorph>>model: (in category 'accessing') -----
model: anObject
        model
                ifNotNil: [model removeDependent: self].
        anObject
                ifNotNil: [anObject addDependent: self].
        model _ anObject.
        self update: #all.
!

----- Method: SkSheetMorph>>mouseDown: (in category 'event handling') -----
mouseDown: event
        self
                selectSelection: (self screenToCell: event position).
        event yellowButtonPressed
                ifTrue: [^ selectionMorph invokeMenu: event].
        "For easy doublecilck to selection"
        event hand waitForClicksOrDrag: selectionMorph event: event.
        event hand mouseFocus: selectionMorph!

----- Method: SkSheetMorph>>mouseEnter: (in category 'event handling') -----
mouseEnter: evt
        | hand tile |
        hand _ evt hand.
        hand submorphs size = 1
                ifFalse: [^ self].
        tile _ hand firstSubmorph renderedMorph.
        (self wantsDroppedMorph: tile event: evt)
                ifFalse: [^ self].
        self
                startStepping: #trackDropZones
                at: Time millisecondClockValue
                arguments: nil
                stepTime: 20!

----- Method: SkSheetMorph>>mouseEnterDragging: (in category 'event handling') -----
mouseEnterDragging: evt
        "Test button state elsewhere if at all"
        ^ self mouseEnter: evt!

----- Method: SkSheetMorph>>mouseLeave: (in category 'event handling') -----
mouseLeave: evt
        dropZone _ nil.
        self stopSteppingSelector: #trackDropZones!

----- Method: SkSheetMorph>>mouseLeaveDragging: (in category 'event handling') -----
mouseLeaveDragging: evt
        ^ self mouseLeave: evt!

----- Method: SkSheetMorph>>mouseUpTick:onItem: (in category 'event handling') -----
mouseUpTick: evt onItem: aMorph
        aMorph isTicking
                ifTrue: [model stopStepping.
                        aMorph isTicking: false]
                ifFalse: [model startStepping.
                        aMorph isTicking: true]!

----- Method: SkSheetMorph>>openLibrary (in category 'action') -----
openLibrary
        (SkObject root at: 'Library') grid openInHand!

----- Method: SkSheetMorph>>paste (in category 'action') -----
paste
        | pos selection isJustACell |
        selection _ self selection.
        isJustACell _ selection extent = (1 @ 1).
        pos _ selection origin.
        Clipboard clipboardText
                split: Character cr
                do: [:line |
                        line
                                split: Character tab
                                do: [:field |
                                        (isJustACell
                                                        or: [selection containsPoint: pos])
                                                ifTrue: [model textAt: pos put: field].
                                        pos _ pos + (1 @ 0)].
                        pos _ selection left @ (pos y + 1)]!

----- Method: SkSheetMorph>>previousPage (in category 'navigation') -----
previousPage
        self beep: 'rice'.
        ^ history
                ifNotNil: [self replace: history]!

----- Method: SkSheetMorph>>privateRemoveMorph: (in category 'private') -----
privateRemoveMorph: aMorph
        aMorph class = SkCardMorph
                ifTrue: [self beep: 'cork'.
                        self model textAt: aMorph cellOrigin put: ''].
        super privateRemoveMorph: aMorph!

----- Method: SkSheetMorph>>replace: (in category 'navigation') -----
replace: aSkSheetMorph
        aSkSheetMorph area: self area.
        aSkSheetMorph position: self position.
        self delete.
        aSkSheetMorph openInWorld.
        ^ aSkSheetMorph!

----- Method: SkSheetMorph>>selectSelection: (in category 'action') -----
selectSelection: aPoint
        "Select at event position"
        aPoint
                ifNil: [^ self].
        self
                selection: (aPoint extent: 1 @ 1).
        self changed!

----- Method: SkSheetMorph>>selection (in category 'accessing') -----
selection
        ^ selectionMorph area!

----- Method: SkSheetMorph>>selection: (in category 'accessing') -----
selection: aRectangle
        submorphs first == selectionMorph
                ifFalse: [self addMorphFront: selectionMorph].
        selectionMorph area: aRectangle!

----- Method: SkSheetMorph>>selectionMorph (in category 'accessing') -----
selectionMorph
        ^ selectionMorph!

----- Method: SkSheetMorph>>setCellExtentFromHalo: (in category 'layout') -----
setCellExtentFromHalo: newExtent
        | eachExtent cellExtent |
        model
                ifNil: [^ self].
        cellExtent _ model
                                at: self cellExtentName
                                ifAbsent: [model
                                                at: self cellExtentName
                                                put: (SkSheet new parent: model)].
        eachExtent _ newExtent // self selection extent max: 10 @ 10.
        self selection left
                to: self selection right - 1
                do: [:x | cellExtent at: x @ 1 put: eachExtent].
        self selection top
                to: self selection bottom - 1
                do: [:y | cellExtent at: 1 @ y put: eachExtent].
        self areaChanged.
        self changed!

----- Method: SkSheetMorph>>setExtentFromHalo: (in category 'layout') -----
setExtentFromHalo: newExtent
        | card cardMorph direction size |
        super setExtentFromHalo: newExtent.
        direction := nil.
        area height = 1
                ifTrue:
                        [direction := #right.
                        size := area width - 1]
                ifFalse:
                        [area width = 1
                                ifTrue:
                                        [direction := #down.
                                        size := area height - 1]].
        direction ifNotNil:
                        [card := model new.
                        card direction: direction.
                        card size: size.
                        cardMorph := SkCardMorph model: card.
                        cardMorph position: self position.
                        self owner addMorph: cardMorph.
                        self halo ifNotNilDo: [:helo | helo setTarget: cardMorph].
                        self delete]!

----- Method: SkSheetMorph>>showFormula (in category 'accessing') -----
showFormula
        ^ showFormula!

----- Method: SkSheetMorph>>showPageControls (in category 'initialization') -----
showPageControls
        | panel prev up |
        panel _ Morph new extent: 80@20; color: Color transparent.
        panel
                on: #mouseDown
                send: #yourself
                to: self.
        panel addMorph: self tickMorph.
        prev _ (PolygonMorph new setVertices: {0 @ 7. 7 @ 0. 7 @ 14}) borderWidth: 1;
borderColor: Color darkGray;
                                 color: Color transparent.
        prev
                on: #mouseDown
                send: #previousPage
                to: self.
        prev position: 24 @ 3.
        prev setBalloonText: 'View the previous sheet.' translated.
        panel addMorph: prev.
        up _ prev copy heading: 90.
        up
                on: #mouseDown
                send: #upPage
                to: self.
        up position: 36 @ 4.
        up setBalloonText: 'View the definision or the parent rule.' translated.

        panel addMorph: up.
        self addMorph: panel!

----- Method: SkSheetMorph>>spawn (in category 'action') -----
spawn
        model inspectAt: self selection topLeft!

----- Method: SkSheetMorph>>spawn: (in category 'action') -----
spawn: anObject
        self spawn!

----- Method: SkSheetMorph>>startStepping (in category 'stepping and presenter') -----
startStepping
        model
                ifNotNil: [model startStepping].
        super startStepping.
!

----- Method: SkSheetMorph>>step (in category 'stepping and presenter') -----
step
        self changed!

----- Method: SkSheetMorph>>tickMorph (in category 'initialization') -----
tickMorph
        | tick |
        tick _ SkPluggableTickMorph new.
        tick position: self position + 1.
        tick on: self isTickingSel: #isModelStepping.
        tick
                on: #mouseUp
                send: #mouseUpTick:onItem:
                to: self.
        tick stepTime: 500.
        tick startStepping.
        tick setBalloonText: 'Press to toggle ticking state.' translated.
        ^ tick!

----- Method: SkSheetMorph>>toggleFormula (in category 'accessing') -----
toggleFormula
        showFormula _ showFormula not!

----- Method: SkSheetMorph>>trackDropZones (in category 'event handling') -----
trackDropZones
        | hand target |
        hand _ self primaryHand.
        ((self hasOwner: hand) not
                        and: [hand submorphCount > 0])
                ifTrue: [target _ hand submorphs first.
                        dropZone _ (self screenToCell: target topLeft)
                                                extent: ((target respondsTo: #area)
                                                                ifTrue: [target area extent]
                                                                ifFalse: [1 @ 1]).
                        (dropZone topLeft x < 1
                                        or: [dropZone topLeft y < 1])
                                ifTrue: [dropZone _ nil].
                        self changed]
                ifFalse: [dropZone _ nil.
                        self stopSteppingSelector: #trackDropZones]!

----- Method: SkSheetMorph>>tryToRenameTo: (in category 'accessing') -----
tryToRenameTo: aName
        ^ model
                ifNotNilDo: [:m | m name: aName]!

----- Method: SkSheetMorph>>upPage (in category 'navigation') -----
upPage
        self beep: 'rice'.
        ^ self goto: model up!

----- Method: SkSheetMorph>>update: (in category 'updating') -----
update: anObject
        anObject = #cardList
                ifTrue: [self updateCardList].
        anObject = #all
                ifTrue: [self updateCardList].
        self changed!

----- Method: SkSheetMorph>>updateCardList (in category 'updating') -----
updateCardList
        | cardList morph |
        cardList _ model cardList: self visibleArea.
        self
                removeAllMorphsIn: (self submorphs
                                select: [:m | m class == SkCardMorph]).
        cardList
                do: [:cardInfo |
                        morph _ SkCardMorph model: cardInfo value.
                        morph holder: self.
                        self addMorph: morph.
                        morph cellOrigin: cardInfo key].
        selectionMorph hide!

----- Method: SkSheetMorph>>veryDeepInner: (in category 'copying') -----
veryDeepInner: deepCopier
        "history is not copied"
        model _ model veryDeepCopyWith: deepCopier.
        selectionMorph _ (selectionMorph veryDeepCopyWith: deepCopier) holder: self.
        dropZone _ dropZone veryDeepCopyWith: deepCopier.
        showFormula _ showFormula veryDeepCopyWith: deepCopier.
        super veryDeepInner: deepCopier!

----- Method: SkSheetMorph>>wantsDroppedMorph:event: (in category 'drag and drop') -----
wantsDroppedMorph: aMorph event: anEvent
        ^ aMorph class = PhraseTileMorph
                or: [aMorph class = TileMorph
                                or: [aMorph isKindOf: SkGridPartsMorph]]!

----- Method: SkSheetMorph>>width: (in category 'accessing') -----
width: aNumber
        ^ self setExtentFromHalo: aNumber @ self height!

----- Method: ScriptEditorMorph>>arrowTargets (in category '*skeleton-base-arrow') -----
arrowTargets
        ^ Array with: 'player' -> playerScripted!

Compiler subclass: #SkCompiler
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkCompiler class>>parserClass (in category 'accessing') -----
parserClass
        ^ SkParser!

TickIndicatorMorph subclass: #SkPluggableTickMorph
        instanceVariableNames: 'model isTickingSel'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkPluggableTickMorph>>isTicking (in category 'accessing') -----
isTicking
        ^model perform: isTickingSel.
!

----- Method: SkPluggableTickMorph>>on:isTickingSel: (in category 'accessing') -----
on: anObject isTickingSel: tickSel
        model _ anObject.
        isTickingSel _ tickSel.
!

----- Method: SkPluggableTickMorph>>runningColor (in category 'accessing') -----
runningColor
        ^ Color
                r: 0.767
                g: 0.767
                b: 1.0!

----- Method: SkPluggableTickMorph>>stepAt: (in category 'stepping and presenter') -----
stepAt: nowTick
        | delta |
        self isTicking
                ifTrue: [(lastTick isNil
                                        or: [nowTick < lastTick])
                                ifTrue: [lastTick _ nowTick].
                        delta _ nowTick - lastTick // stepTime.
                        delta > 0
                                ifTrue: [self color: self runningColor.
                                        index _ index + delta.
                                        lastTick _ nowTick.
                                        self changed]]
                ifFalse: [self color: self stoppedColor]!

----- Method: SkPluggableTickMorph>>stoppedColor (in category 'accessing') -----
stoppedColor
        ^ Color
                r: 1.0
                g: 0.774
                b: 0.774!

TestCase subclass: #SkBaseTest
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base'!

----- Method: SkBaseTest>>testAsSkeletonText (in category 'text test') -----
testAsSkeletonText
        | morph |
        self assert: 1 asCellText = '1'.
        self assert: Color white asCellText = '=Color white'.
        morph _ Morph new name: 'AsSkeletonText'.
        self assert: morph assuredPlayer asCellText = '=References at: #AsSkeletonText'.
        References removeKey: #AsSkeletonText.
!

TestCase subclass: #SkSheetTest
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Skeleton-Base-Sheet'!

----- Method: SkSheetTest>>testA1Name (in category 'sheet test') -----
testA1Name
        | s |
        s _ SkSheet new.
        s textAt: 100@100 put: 'test'.
        s textAt: 1@1 put: '=CV100'.
        s resolve.
        self assert: (s at: 1@1) = 'test'.
!

----- Method: SkSheetTest>>testAddCardIntoProxy (in category 'rule and case') -----
testAddCardIntoProxy
        | proxy base |
        base _ SkSheet new.
        proxy _ SkProxy newForTest.
        proxy parent: base uniqueName: 'Case'.
        proxy textAt: 2@2 put: '=Case direction: #right size: 1'.
        self assert: (proxy at: 2@2) rule = proxy rule.
!

----- Method: SkSheetTest>>testAdopt (in category 'card tests') -----
testAdopt
        | s1 c1 s2 c2 |
        (SkProject current)
                removeAt: 'Sheet';
                removeAt: 'Card'.
        s1 := SkSheet new attachProject name: 'Sheet'.
        c1 := SkProxy newForTest attachProject name: 'Card'.
        s1 adopt: c1.
        self assert: (s1 findName: 'Card') = c1 rule.
        s2 := SkSheet new.
        c2 := SkProxy newForTest parent: s2 uniqueName: 'Card'.
        s2 adopt: c1.
        self assert: c2 parent = s2.
        self assert: (s2 findName: 'Card1') = c1.
        self assert: c2 ruleName = 'Card'!

----- Method: SkSheetTest>>testAtPut (in category 'sheet test') -----
testAtPut
        | s |
        s _ SkSheet new.
        s textAt: 1@1 put: 1.
        self assert: (s cellAt: 1@1) contents == 1.

        s textAt: 1@1 put: '1'.
        self assert: (s cellAt: 1@1) contents == 1.

        s textAt: 2@1 put: 'test'.
        self assert: (s cellAt: 2@1) contents = 'test'.

        s textAt: 3@1 put: 'test' asText.
        self assert: (s cellAt: 3@1) contents = 'test'.
        self assert: (s cellAt: 3@1) contents class = String.

        s textAt: 1@2 put: '=A1*2'.
        s resolve.
        self assert: (s cellAt: 1@2) contents == 2.
!

----- Method: SkSheetTest>>testBehavior (in category 'text test') -----
testBehavior
        | s |
        s _ SkSimple contents: [ :h |
                h addRule: (1@1 rule: {2@1. 3@1} do: [ :a :b | a + b]).
                h at: 2@1 put: 2.
                h at: 3@1 put: 3.
                h resolve.
        ].
" s grid openInWorld."
!

----- Method: SkSheetTest>>testBidirectional (in category 'planning test') -----
testBidirectional
        | s |
        s _ SkSheet new.
        s textAt: 1 @ 1 put: '=B1'.
        s textAt: 2 @ 1 put: '=A1'.
        s at: 1 @ 1 put: 'first'.
        s resolve.
        self assert: (s at: 2 @ 1)
                        = 'first'.
        s at: 2 @ 1 put: 'second'.
        s resolve.
        self assert: (s at: 1 @ 1)
                        = 'second'.
!

----- Method: SkSheetTest>>testCardBidirectional (in category 'planning test') -----
testCardBidirectional
        | s c |
        s := SkSheet new.
        c := SkProxy newForTest parent: s uniqueName: 'Inc'.
        c textAt: 1 @ 1 put: '=B1+1'.
        s textAt: 1 @ 1 put: '=Inc direction: #right size: 2'.
        s textAt: 1 @ 2 put: '=Inc direction: #right size: 2'.
        s textAt: 3 @ 2 put: '=B1'.
        s at: 3 @ 1 put: 10.
        s resolve.
        self assert: (s at: 2 @ 2) = 12.
        s at: 3 @ 1 put: 100.
        s resolve.
        self assert: (s at: 2 @ 2) = 102.
        s textAt: 3 @ 1 put: '=B2'.
        s textAt: 3 @ 2 put: '10'.
        self assert: (s dependMap at: 3 @ 2)
                                = {
                                                1 @ 1.
                                                2 @ 1.
                                                3 @ 1.
                                                1 @ 2.
                                                2 @ 2} asSet.
        s resolve.
        self assert: (s at: 2 @ 1) = 12.
        s at: 3 @ 2 put: 100.
        s resolve.
        self assert: (s at: 2 @ 1) = 102!

----- Method: SkSheetTest>>testCardCode (in category 'card tests') -----
testCardCode
        | c |
        SkProject current removeAt: 'Test'.
        c := SkProxy newForTest attachProject.
        c size: 3.
        c direction: #left.
        c name: 'Test'.
        self assert: c codeString = 'Test direction: #left size: 3'!

----- Method: SkSheetTest>>testCardHasContents (in category 'card tests') -----
testCardHasContents
        self flag: #abeyance.
[
        | proxy sheet |
        proxy _ SkProxy newForTest size: 1.
        sheet _ SkSheet new.
        proxy at: 1@1 put: 'test'.
        sheet caseAt: 1@1 put: proxy.
        self assert: (sheet at: 2@1) = 'test'.
]!

----- Method: SkSheetTest>>testCardInCardMorphCopy (in category 'copy test') -----
testCardInCardMorphCopy
        | old new card sample |
        SkProject current removeAt: 'Test'.
        card := SkProxy newForTest attachProject name: 'Test'.
        card size: 3.
        old := SkCardMorph model: card.
        sample := 'test'.
        card at: 1 @ 1 put: sample.
        new := old veryDeepCopy.
        self assert: old model ~~ new model.
        self assert: old model parent == new model parent.
[
        self flag: #TODO. "I don't know sure if the proxy should copy old contents".
        self assert: (new model at: 1 @ 1) = 'test'.
].
        self assert: ((new model at: 1 @ 1) == sample) not.
        self assert: new model ruleName notNil!

----- Method: SkSheetTest>>testCardInSheetMorphCopy (in category 'copy test') -----
testCardInSheetMorphCopy
        | old new card sample |
        SkProject current removeAt: 'Test'.
        card := SkProxy newForTest attachProject name: 'Test'.
        card size: 3.
        old := SkSheetMorph model: card.
        sample := 'test'.
        card at: 1 @ 1 put: sample.
        new := old veryDeepCopy.
        self assert: old model ~~ new model.
        self assert: old model parent == new model parent.
        self assert: (new model at: 1 @ 1) = 'test'.
        self assert: ((new model at: 1 @ 1) == sample) not.
        self assert: new model ruleName notNil!

----- Method: SkSheetTest>>testCardInThenEdit (in category 'rule and case') -----
testCardInThenEdit
        | sheet card |
        SkProject current removeAt: 'Sheet'; removeAt: 'Card'.
        sheet _ SkSheet new name: 'Sheet'.
        card _ SkSheet new name: 'Card'.
        sheet textAt: 1@1 put: '=Card direction: #right size: 2'.
" sheet explore. (sheet at: 1@1) explore."

        card textAt: 2@1 put: '=A1'.
        sheet textAt: 2@1 put: 'test'.
        sheet resolve.
        self assert: (sheet at: 3@1) = 'test'.
!

----- Method: SkSheetTest>>testCardMorph (in category 'card tests') -----
testCardMorph
        "It has not assert, just drawing test for avoid error."
        | s m f |
        SkProject current removeAt: 'Test'.
        s _ SkSheet new attachProject name: 'Test'.
        m _ SkCardMorph model: s.
        s at: 1 @ 1 put: 1.
        s at: 2 @ 1 put: 2.
        s at: 3 @ 1 put: 3.
        m
                area: (2 @ 2 extent: 3 @ 1).
        m areaChanged.
        f _ FormCanvas extent: m extent.
        m drawOn: f!

----- Method: SkSheetTest>>testCardPut (in category 'card tests') -----
testCardPut
        | sheet card1 card2 |
        SkProject current removeAt: 'Sheet'.
        sheet := SkSheet new attachProject name: 'Sheet'.
        card1 := SkProxy newFrom: sheet.
        card1 size: 1.
        card1 textAt: 1 @ 1 put: 'test1'.
        card1 textAt: 2 @ 1 put: 'test2'.
        self assert: (card1 at: 1 @ 1) = 'test1'.
        card2 := SkProxy newFrom: sheet.
        self assert: (card2 at: 1 @ 1) = ''.
        self assert: (card2 at: 2 @ 1) = ''.
        card1 textAt: 1 @ 1 put: '=100'.
        self assert: (card2 textAt: 1 @ 1) = '=100'!

----- Method: SkSheetTest>>testCardResolve (in category 'card tests') -----
testCardResolve
        | sheet card |
        (SkProject current)
                removeAt: 'Sheet';
                removeAt: 'Card'.
        sheet := SkSheet new attachProject name: 'Sheet'.
        card := SkProxy newForTest attachProject name: 'Card'.
        card textAt: 1 @ 1 put: '=B1+C1'.
        sheet textAt: 1 @ 1 put: '=Card direction: #right size: 3'.
        sheet textAt: 3 @ 1 put: '1'.
        sheet textAt: 4 @ 1 put: '2'.
        sheet resolve.
        self assert: (sheet at: 2 @ 1) = 3.
        self assert: ((sheet at: 1 @ 1) at: 2 @ 1) = 1.
        sheet textAt: 1 @ 5 put: '=Card direction: #up size: 3'.
        sheet textAt: 1 @ 2 put: '1'.
        sheet textAt: 1 @ 3 put: '2'.
        sheet resolve.
        self assert: (sheet at: 1 @ 4) = 3 !

----- Method: SkSheetTest>>testCaseInCase (in category 'rule and case') -----
testCaseInCase
        | s1 s2 s3 |
        SkProject current removeAt: 'Sheet1'; removeAt: 'Sheet2'.
        s1 _ SkSheet new attachProject name: 'Sheet1'.
        s2 _ SkSheet new attachProject name: 'Sheet2'.
        s1 textAt: 1@1 put: '=B1'.
        s2 textAt: 1@2 put: '=Sheet1 direction: #right size: 2'.
        s3 _ s2 new.
        s3 textAt: 3@2 put: '2'.
       
        s3 resolve.
        s2 textAt: 1@2 put: ''.
        self assert: (s2 at: 1@2) = ''.
        self assert: (s3 at: 1@2) = ''.

       
 !

----- Method: SkSheetTest>>testCaseInCaseDelete (in category 'rule and case') -----
testCaseInCaseDelete
        | s1 s2 s3 |
        SkProject current removeAt: 'Sheet1'; removeAt: 'Sheet2'.
        s1 _ SkSheet new attachProject name: 'Sheet1'.
        s2 _ SkSheet new attachProject name: 'Sheet2'.
        s1 textAt: 1@1 put: '=B1'.
        s2 textAt: 1@2 put: '=Sheet1 direction: #right size: 2'.
        s2 textAt: 3@2 put: '1'.
        s3 _ s2 new.
        s3 textAt: 3@2 put: '2'.
       
        s2 resolve. s3 resolve.
        self assert: (s2 at: 2@2) = 1.
        self assert: (s3 at: 2@2) = 2.
 !

----- Method: SkSheetTest>>testCellOrigin (in category 'card tests') -----
testCellOrigin
        | c |
        c := SkCardMorph model: SkProxy newForTest.
        c
                size: 2;
                direction: #right.
        c cellOrigin: 5 @ 5.
        self assert: c area origin = (5 @ 5).
        c
                size: 2;
                direction: #left.
        c cellOrigin: 5 @ 5.
        self assert: c area origin = (3 @ 5).
        c
                size: 2;
                direction: #up.
        c cellOrigin: 5 @ 5.
        self assert: c area origin = (5 @ 3).
        c
                size: 2;
                direction: #down.
        c cellOrigin: 5 @ 5.
        self assert: c area origin = (5 @ 5)!

----- Method: SkSheetTest>>testCellToScreenRect (in category 'gui tests') -----
testCellToScreenRect
        | grid |
        grid _ SkSheetMorph model: SkSheet new.
        self assert: (grid cellExtentAt: 1 @ 1)
                        = (80 @ 20).
        grid
                area: (0 @ 0 extent: 2 @ 2).
        grid position: 20 @ 10.
        self assert: (grid cellToScreenRect: 0 @ 0)
                        = (21 @ 11 corner: 101 @ 31).
        self assert: (grid cellToScreenRect: 1 @ 1)
                        = (102 @ 32 corner: 182 @ 52)!

----- Method: SkSheetTest>>testCellToScreenRect2 (in category 'gui tests') -----
testCellToScreenRect2
        | conv grid |
        grid _ SkSheetMorph new.
        grid area: (0 @ 0 extent: 2 @ 2).
        conv _ SkCellScreenConverter grid: grid border: 1.

        self assert: (conv cellToScreenRect: 0 @ 0 topLeft: 20@10)
                        = (21 @ 11 corner: 101 @ 31).
        self assert: (conv cellToScreenRect: 1 @ 1 topLeft: 20@10)
                        = (102 @ 32 corner: 182 @ 52).
        self assert: (conv cellToScreenRect: 100 @ 100 topLeft: 20@10)
                        = (((20@10) + 1 + (((80@20) + 1) * 100)) extent: 80@20).
        self assert: (conv cellToScreenRect: -1 @ -1 topLeft: 20@10)
                        = (((20@10) + 1 + (((80@20) + 1) * -1)) extent: 80@20).
        self assert: (conv cellToScreenRect: 10 @ -1 topLeft: 20@10)
                        = ((20@10) + 1 + (((800@-20) + (10@-1))) extent: 80@20)
!

----- Method: SkSheetTest>>testCopyFromFlap (in category 'copy test') -----
testCopyFromFlap
        | base sheet new |
        SkProject current removeAt: 'Original'.
        base _ SkSheet new.
        sheet _ SkSheetMorph model: (SkSheet new parent: base uniqueName: 'Original').
        new _ sheet veryDeepCopy.
        self assert: new model parent = SkProject current.
        self assert: new model ruleName = 'Original'.
!

----- Method: SkSheetTest>>testCopyInCardMorph (in category 'copy test') -----
testCopyInCardMorph
        | old new |
        old _ SkCardMorph model: SkSheet new.
        new _ old veryDeepCopy.
        self assert: old model ~= new model.
        self assert: old model rule == new model rule.

        old _ SkCardMorph model: SkProxy newForTest.
        new _ old veryDeepCopy.
        self assert: old model ~= new model.
        self assert: old model rule == new model rule.
         !

----- Method: SkSheetTest>>testCopyInSheetMorph (in category 'copy test') -----
testCopyInSheetMorph
        | old new |
        old _ SkSheetMorph model: SkSheet new.
        new _ old veryDeepCopy.
        self assert: old model ~= new model.

        old _ SkSheetMorph new model: SkProxy newForTest.
        new _ old veryDeepCopy.
        self assert: old model rule ~= new model rule.
         !

----- Method: SkSheetTest>>testCopyPaste (in category 'sheet test') -----
testCopyPaste
        | s grid |
        s _ SkSheet new.
        s textAt:1@1 put: 1.
        s textAt:2@1 put: 'string'.
        s textAt:1@2 put: 'text' asText.
        s textAt:2@2 put: '=A1'.
        s textAt:1@3 put: 'remain'.
        grid _ SkSheetMorph new model: s.
        grid selection: (1@1 extent: 2@2).
        grid copySelection.
        self assert: Clipboard clipboardText =
'1 string
text =A1
' asText.

        grid selection: (2@2 extent: 1@1).
        grid paste.
        grid selection: (1@1 extent: 3@3).
        grid copySelection.
        self assert: Clipboard clipboardText = '1 string
text 1 string
remain text =A1
' asText.

        Clipboard clipboardText: 'x x x x
x x x x
x x x x
x x x x
' asText.
        grid selection: (1@1 extent: 2@2).
        grid paste.
        grid selection: (1@1 extent: 4@4).
        grid copySelection.
        self assert: Clipboard clipboardText = 'x x
x x string
remain text =A1
                       
' asText.
!

----- Method: SkSheetTest>>testCopySkSheet (in category 'copy test') -----
testCopySkSheet
        | sheet new |
        SkProject current removeAt: 'Test'.
        sheet _ SkSheetMorph
                                model: (SkProxy newForTest attachProject name: 'Test').
        sheet
                history: (SkSheetMorph new model: SkProject current).
        new _ sheet duplicate.
        new!

----- Method: SkSheetTest>>testCopyWithCard (in category 'copy test') -----
testCopyWithCard
        | old new |
        old _ SkSheetMorph model: SkSheet new.
        old model textAt: 1@1 put: '=Sum direction: #right size: 3'.
        old model at: 3@1 put: 1.
        old model at: 4@1 put: 2.
        new _ old veryDeepCopy.
        self assert: ((old model at: 1@1) at: 2@1) = ((new model at: 1@1) at: 2@1).
        self assert: new submorphs first model = (new model at: 1@1).
        !

----- Method: SkSheetTest>>testCreateOffset (in category 'gui tests') -----
testCreateOffset
        | conv |
        conv _ SkCellScreenConverter grid: SkSheetMorph new border: 1.
        self assert: (conv createOffset: 0@0) = (0@0).
        self assert: (conv createOffset: 1@1) = (81@21).
        self assert: (conv createOffset: -1@-1) = (-81@-21)!

----- Method: SkSheetTest>>testCutAndPasteWithGUI (in category 'copy test') -----
testCutAndPasteWithGUI
        | sheet morph |
        SkProject current removeAt: 'Sheet'.
        sheet := SkSheet new attachProject name: 'Sheet'.
        morph := SkSheetMorph model: sheet.
        sheet textAt: 1 @ 1 put: '=Sum'.
        self
                assert: (morph submorphs select: [:m | m class = SkCardMorph]) size = 1.
        morph selection: (1 @ 1 extent: 1 @ 1).
        morph cut.
        self
                assert: (morph submorphs select: [:m | m class = SkCardMorph]) isEmpty!

----- Method: SkSheetTest>>testDeepCopy (in category 'copy test') -----
testDeepCopy
        |old new sheet sample |
        SkProject current removeAt: 'Test'.
        sheet _ SkSheet new attachProject name: 'Test'.
        old _ SkSheetMorph model: sheet.
        sample _ 'test'.
        sheet at: 1@1 put: sample.
        new _ old veryDeepCopy.
        self assert: old model ~~ new model.
        self assert: old model parent == new model parent.
        self assert: ((new model at: 1@1) = 'test').
        self assert: (((new model at: 1@1) == sample) not).
        self assert: new model ruleName notNil!

----- Method: SkSheetTest>>testDependents (in category 'planning test') -----
testDependents
        | sheet1 dep |
        sheet1 _ SkSheet new.
        sheet1 textAt: 1 @ 1 put: '0'.
        sheet1 textAt: 2 @ 1 put: '=A1 + 1'.
        sheet1 textAt: 3 @ 1 put: '=B1 + 1'.
        sheet1 textAt: 1 @ 2 put: '=B2 + C2'.
        sheet1 textAt: 2 @ 2 put: '=C2 + 1'.
        sheet1 textAt: 3 @ 2 put: '=A1 + 1'.
        dep _ sheet1 dependMap.
        self assert: ((dep at: 1@1) includes: 2@1).
        self assert: ((dep at: 1@1) includes: 3@1).
        self assert: ((dep at: 1@1) includes: 1@2).
        self assert: ((dep at: 1@1) includes: 2@2).
        self assert: ((dep at: 1@1) includes: 3@2).
        self assert: ((dep at: 2@1) includes: 3@1).
        self assert: ((dep at: 3@1 ifAbsent: [nil]) isNil).
        self assert: ((dep at: 1@2 ifAbsent: [nil]) isNil).
        self assert: ((dep at: 2@2) includes: 1@2).
        self assert: ((dep at: 3@2) includes: 1@2).
        self assert: ((dep at: 3@2) includes: 2@2).
!

----- Method: SkSheetTest>>testDictionary (in category 'structure test') -----
testDictionary
        | d |
        d _ SkDictionary new.
        d at: 'orenge' put: 'mikan'.
        d at: 'apple' put: 'ringo'.
        d at: 'banana' put: 'banana'.
        self assert: (d at: 1 @ 2)
                        = 'apple'.
        self assert: (d at: 2 @ 4)
                        = 'mikan'!

----- Method: SkSheetTest>>testDictionaryCard (in category 'structure test') -----
testDictionaryCard
        | d |
        d := SkProxy newFrom: SkDictionary new.
        d at: 'orenge' put: 'mikan'.
        d at: 'apple' put: 'ringo'.
        d at: 'banana' put: 'banana'.
        self assert: (d at: 1 @ 2) = 'apple'.
        self assert: (d at: 2 @ 4) = 'mikan' !

----- Method: SkSheetTest>>testDictionaryCell (in category 'dictionary test') -----
testDictionaryCell
        |cell dict |
        dict _ SkDictionary new.
        cell _ SkDictionaryCell newFor: dict key: 'hello'.
        cell contents: 'world'.
        self assert: (dict at: 'hello') = 'world'!

----- Method: SkSheetTest>>testDictionaryNewName (in category 'dictionary test') -----
testDictionaryNewName
        | dict |
        dict _ SkDictionary new name: 'test'.
        self assert: (dict at: 'test') = ''.
!

----- Method: SkSheetTest>>testDirection (in category 'card tests') -----
testDirection
        | c |
        c := SkCardMorph model: SkProxy newForTest.
        c direction: #right.
        c area: (4 @ 5 extent: 4 @ 1).
        self assert: c size = 3.
        c direction: #down.
        self assert: c area = (4 @ 5 corner: 5 @ 9).
        c direction: #left.
        self assert: c area = (1 @ 5 corner: 5 @ 6).
        c direction: #up.
        self assert: c area = (4 @ 2 corner: 5 @ 6).
        c size: 2.
        self assert: c area = (4 @ 3 corner: 5 @ 6).
        c direction: #right.
        self assert: c area = (4 @ 5 corner: 7 @ 6) !

----- Method: SkSheetTest>>testFindName (in category 'structure test') -----
testFindName
        | s c |
        s := SkSheet new attachProject.
        self assert: (s findName: 'Projects') = s parent parent.
        self assert: (s findName: 'Root') = s parent parent parent.
        c := SkProxy newFrom: s.
        self assert: (c findName: 'Projects') = s parent parent !

----- Method: SkSheetTest>>testFormula (in category 'cell test') -----
testFormula
        | cell |
        cell _ SkValueCell new.
        cell formula: '=A1+B2'.
        self assert: cell block sourceCode = 'DoIt
        ^ [:t1 :t2 | (t1 at: 1@1)
                + (t1 at: 2@2)]'
!

----- Method: SkSheetTest>>testFunction (in category 'cell test') -----
testFunction
        | s |
        s _ SkSheet new.

        s textAt: 1@1 put: 1.
        s textAt: 2@1 put: '=A1 sin'.
        s resolve.
        self assert: ((s cellAt: 2@1) contents closeTo: 0.8414).

        s textAt: 1@1 put: '1' asText.
        s resolve.
        self assert: ((s cellAt: 2@1) contents closeTo: 0.8414).

!

----- Method: SkSheetTest>>testGlobalToLocal (in category 'card tests') -----
testGlobalToLocal
        | m |
        m := SkCardMorph model: SkProxy newForTest.
        m area: (2 @ 3 corner: 6 @ 4).
        m direction: #right.
        self assert: (m globalToLocal: 3 @ 3) = (1 @ 1).
        self assert: (m globalToLocal: 5 @ 3) = (3 @ 1).
        m direction: #left.
        self assert: (m globalToLocal: 1 @ 3) = (1 @ 1).
        self assert: (m globalToLocal: -1 @ 3) = (3 @ 1).
        m direction: #down.
        m area: (2 @ 3 corner: 3 @ 7).
        self assert: (m globalToLocal: 2 @ 4) = (1 @ 1).
        self assert: (m globalToLocal: 2 @ 6) = (3 @ 1).
        m direction: #up.
        self assert: (m globalToLocal: 2 @ 2) = (1 @ 1).
        self assert: (m globalToLocal: 2 @ 0) = (3 @ 1) !

----- Method: SkSheetTest>>testGoto (in category 'navigation test') -----
testGoto
        | sheet goal result |
        SkProject current removeAt: 'Test'.
        sheet _ SkSheetMorph
                                model: (SkSheet new attachProject name: 'Test').
        result _ sheet goto: (goal _ SkSheet new).
        self assert: goal = result model.
        result delete.

        result _ sheet goto: (goal _ SkSheet).
        self assert: goal = result model class.
        result delete.
!

----- Method: SkSheetTest>>testIncludesPosition (in category 'dictionary test') -----
testIncludesPosition
        | dict |
        dict _ SkDictionary new.
        dict at: 'hello' put: 'world'.
        self assert: (dict includesPosition: 'hello') not.
        self assert: (dict includesPosition: 1@1) not.
        self assert: (dict includesPosition: 1@2) .
        self assert: (dict includesPosition: 2@2) .
        self assert: (dict includesPosition: 1@3) not.
        self assert: (dict includesPosition: 3@2) not.
!

----- Method: SkSheetTest>>testLibraryName (in category 'card tests') -----
testLibraryName
        | sheet |
        SkProject current removeAt: 'Sheet'.
        SkProject current removeAt: 'sum'.
        sheet _ SkSheet new attachProject name: 'Sheet'.
        sheet textAt: 1 @ 1 put: '=Sum direction: #right size: 3'.
        sheet textAt: 3 @ 1 put: '1'.
        sheet textAt: 4 @ 1 put: '2'.
        sheet resolve.
        self assert: (sheet at: 2 @ 1) = 3.
        self assert: (SkProject current at: 'Sum') = ''.
        self assert: (sheet findName: 'Sum') parent = (sheet findName: 'Library')
!

----- Method: SkSheetTest>>testName (in category 'structure test') -----
testName
        | sheet card |
        SkProject current removeAt: 'Test'.
        sheet := SkSheet new attachProject name: 'Test'.
        card := SkProxy newFrom: sheet.
        self assert: card ruleName = 'Test'.
        sheet beAlone.
        card := SkProxy newFrom: SkSheet new.
        card attachProject name: 'Test'.
        self assert: card ruleName = 'Test'.
        card beAlone !

----- Method: SkSheetTest>>testNameOnCard (in category 'structure test') -----
testNameOnCard
        | card sheet |
        card := SkProxy newForTest.
        self assert: (card findName: 'cellExtent') isNil.
        self assert: (card at: 'cellExtent') = ''.
        sheet := card at: 'cellExtent' put: (SkSheet new parent: sheet).
        self assert: (card at: 'cellExtent') == sheet !

----- Method: SkSheetTest>>testNil (in category 'other tests') -----
testNil
        | sheet |
        sheet _ SkSheet new.
        self assert: (sheet at: 1@1) = ''.
        self assert: (sheet at: 1@1 ifAbsent: ['ABSENT']) = 'ABSENT'.!

----- Method: SkSheetTest>>testNullCell (in category 'sheet test') -----
testNullCell
        | s |
        s _ SkSheet new.
        self assert: (s cellAt: 1 @ 1) value = ''.
        s textAt: 2 @ 1 put: 'test'.
        s textAt: 2 @ 1 put: ''.
        self assert: (s cellAt: 2 @ 1) class = SkNullCell.
        self assert: (s cellAt: 2 @ 1) value = ''!

----- Method: SkSheetTest>>testPlan (in category 'planning test') -----
testPlan
        | sheet1 |
        sheet1 _ SkSheet new.
        sheet1 textAt: 1@1 put: '0'.
        sheet1 textAt: 2@1 put: '=A1 + 1'.
        sheet1 textAt: 3@1 put: '=B1 + 1'.
        sheet1 textAt: 1@2 put: '=B2 + C2'.
        sheet1 textAt: 2@2 put: '=C2 + 1'.
        sheet1 textAt: 3@2 put: '=A1 + 1'.

        self assert: (sheet1 collectTargets = {2@1. 3@1. 1@2. 2@2. 3@2}).
        self assert: sheet1 collectDependents =
                {{2@1. 1@1}.
                {3@1. 2@1}.
                {1@2. 2@2. 3@2}.
                {2@2. 3@2}.
                {3@2. 1@1}}.
        self assert: (sheet1 collectTrees =
                {
                {3@1. {2@1. 1@1}}.
                {1@2. {2@2. 3@2}. {3@2. 1@1}}}).

        self assert: sheet1 collectOrder asArray =
                {1@1. 2@1. 3@1.
                3@2. 2@2.
                1@1. 3@2. 1@2.}.
        sheet1 resolve.
        self assert: (sheet1 at: 1@2) = 3.
        self assert: (sheet1 plan collect: [:each | each key]) =
                {2@1. 3@1. 3@2. 2@2. 1@2}.
!

----- Method: SkSheetTest>>testPlanWithCard (in category 'planning test') -----
testPlanWithCard
        | sheet card |
        sheet := SkSheet new.
        card := SkProxy newForTest parent: sheet uniqueName: 'Card'.
        card textAt: 1 @ 1 put: '=B1'.
        sheet textAt: 1 @ 1 put: '=Card direction: #right size: 2'.
        self assert: sheet cardPositions asArray = {
                                                1 @ 1}.
       
        [self assert: sheet collectTargets = {
                                                1 @ 1}.
        self
                assert: sheet collectDependents = {
                                                {
                                                        1 @ 1.
                                                        2 @ 1.
                                                        3 @ 1}.
                                                {
                                                        2 @ 1.
                                                        3 @ 1}}] !

----- Method: SkSheetTest>>testPointForHolder (in category 'card tests') -----
testPointForHolder
        | proxy |
        proxy _ SkProxy newForTest.
        proxy direction: #right.
        self assert: (proxy pointForHolder: 10 @ 10 at: 1 @ 1)
                        = (11 @ 10).
        proxy direction: #down.
        self assert: (proxy pointForHolder: 10 @ 10 at: 1 @ 1)
                        = (10 @ 11).
        proxy direction: #left.
        self assert: (proxy pointForHolder: 10 @ 10 at: 1 @ 1)
                        = (9 @ 10).
        proxy direction: #up.
        self assert: (proxy pointForHolder: 10 @ 10 at: 1 @ 1)
                        = (10 @ 9) !

----- Method: SkSheetTest>>testPrePrecess (in category 'cell test') -----
testPrePrecess
        "ABSOLUTE"
[
        | cell |
        cell _ SkValueCell new.
        self assert: (cell preProcess: '=A1+1')
                        = '(holder at: 1@1)+1'.
        self assert: (cell preProcess: '=A1+B2')
                        = '(holder at: 1@1)+(holder at: 2@2)'
]!

----- Method: SkSheetTest>>testProxyRererenceAt (in category 'card tests') -----
testProxyRererenceAt
        | proxy |
        proxy _ SkProxy newForTest.
        proxy size: 3.
        proxy direction: #down.
        self assert: (proxy referenceAt: 10@10) = {10@11. 10@12. 10@13}. !

----- Method: SkSheetTest>>testReference (in category 'planning test') -----
testReference
        | sheet1 sheet2  cell |
        sheet1 _ SkSheet new.
        sheet1 textAt: 1@1 put: '=B1 + C1'.
        sheet1 textAt: 2@1 put: '=C1'.
        cell _ sheet1 cellAt: 1@1.
        self assert: (cell referenceAt: 1@1) = {2@1. 3@1} asSet.

        sheet2 _ SkSheet new.
        sheet1 parent: sheet2 uniqueName: 'Sheet1'.
        sheet2 textAt: 1@1 put: '=Sheet1 direction: #right size: 3'.
        cell _ sheet2 cellAt: 1@1.
        self assert: (cell referenceAt: 1@1) = {2@1. 3@1. 4@1} asSet.
!

----- Method: SkSheetTest>>testRotationCard (in category 'gui tests') -----
testRotationCard
        | sheet card oldCard |
        SkProject current removeAt: 'Card'.
        sheet := SkSheetMorph model: SkSheet new attachProject.
        sheet area: (0 @ 0 extent: 5 @ 5).
        sheet model textAt: 1 @ 2 put: 'test'.
        SkProxy newForTest attachProject name: 'Card'.
        sheet model textAt: 2 @ 2 put: '=Card direction: #right size: 1'.
        oldCard := card := sheet submorphs detect: [:m | m class = SkCardMorph].
        card rotationDegrees: 90.
        self
                assert: (sheet model textAt: 2 @ 2) = '=Card direction: #down size: 1'.
        card endHaloInteraction.
        self assert: oldCard owner isNil.
        card := sheet submorphs detect: [:m | m class = SkCardMorph].
        card rotationDegrees: 180.
        self
                assert: (sheet model textAt: 2 @ 2) = '=Card direction: #left size: 1'.
        card := sheet submorphs detect: [:m | m class = SkCardMorph].
        card rotationDegrees: 270.
        self assert: (sheet model textAt: 2 @ 2) = '=Card direction: #up size: 1'!

----- Method: SkSheetTest>>testRuleAsCell (in category 'sheet test') -----
testRuleAsCell
        | s1 s2 |
        SkProject current removeAt: 'Test1'.
        s1 _ SkSheet new attachProject name: 'Test1'.
        s1 textAt: 1 @ 1 put: '=B1'.
        s1 textAt: 2 @ 1 put: '=A1'.
        s1 at: 1 @ 1 put: 'test'.
        s1 resolve.
        self assert: (s1 at: 2 @ 1)
                        = 'test'.
        s2 _ SkSheet new attachProject.
        s2 textAt: 1 @ 1 put: '=Test1 direction: #right size: 2'.
        s2 textAt: 1 @ 2 put: '=Test1 direction: #right size: 2'.
        s2 textAt: 2 @ 1 put: 'source1'.
        s2 textAt: 2 @ 2 put: 'source2'.
        s2 resolve.
        self assert: (s2 at: 3 @ 1)
                        = 'source1'.
        self assert: (s2 at: 3 @ 2)
                        = 'source2'!

----- Method: SkSheetTest>>testScreenToCell (in category 'gui tests') -----
testScreenToCell
        | grid |
        grid _ SkSheetMorph model: SkSheet new.
        grid
                area: (0 @ 0 extent: 2 @ 2).
        grid position: 20 @ 10.
        self assert: (grid screenToCell: 101 @ 31)
                        = (0 @ 0).
        self assert: (grid screenToCell: 102 @ 32)
                        = (1 @ 1)!

----- Method: SkSheetTest>>testScreenToCell2 (in category 'gui tests') -----
testScreenToCell2
        | conv grid |
        grid _ SkSheetMorph new.
        grid area: (0 @ 0 extent: 2 @ 2).
        conv _ SkCellScreenConverter grid: grid border: 1.
        self assert: (conv screenToCell: 101 @ 31 topLeft: 20@10)
                        = (0 @ 0).
        self assert: (conv screenToCell: 102 @ 32 topLeft: 20@10)
                        = (1 @ 1).
        self assert: (conv screenToCell: 19 @9 topLeft: 20@10)
                        = (-1 @ -1)!

----- Method: SkSheetTest>>testSheetInCardMorphCopy (in category 'copy test') -----
testSheetInCardMorphCopy
        |old new card sample |
        "SkSheet should be copied in SkCardMorph"
        SkProject current removeAt: 'Test'.
        card _ SkSheet new attachProject name: 'Test'.
        card size: 3.
        old _ SkCardMorph model: card.
        sample _ 'test'.
        card at: 1@1 put: sample.
        new _ old veryDeepCopy.
        self assert: old model ~= new model.
        self assert: old model parent == new model parent.
        self assert: ((new model at: 1@1) = 'test').
        self assert: new model ruleName notNil!

----- Method: SkSheetTest>>testSheetPlus (in category 'parameter test') -----
testSheetPlus
        "NOT YET"
        | base s1 s2 |
        SkProject current removeAt: 'Base'; removeAt: 'St1'; removeAt: 'St2'.
        base _ SkSheet new attachProject name: 'Base'.
        s1 _ SkSheet new attachProject name: 'St1'.
        s2 _ SkSheet new attachProject name: 'St1'.

        base textAt: 1@1 put: '=B1+C1'.
        base textAt: 2@1 put: '=number'.
        base textAt: 3@1 put: '=number'.
        s1. s2.!

----- Method: SkSheetTest>>testSimple (in category 'text test') -----
testSimple
        | s |
        s _ SkSimple contents: [ :h |
                h at: 1@1 put: [ (h at: 2@1) + (h at: 3@1)].
                h at: 2@1 put: 2.
                h at: 3@1 put: 3].
" s grid openInWorld."
!

----- Method: SkSheetTest>>testSkGridPartHolder (in category 'copy test') -----
testSkGridPartHolder
        |card new|
        card _ SkCardMorph model: (SkProxy newForTest).
        new _ card veryDeepCopy.
        self assert: new holder = card holder!

----- Method: SkSheetTest>>testSkProxy (in category 'copy test') -----
testSkProxy
        |card new|
        SkProject current removeAt: 'Sheet'; removeAt: 'Sheet1'.
        card _ SkCardMorph model: (SkProxy newForTest name: 'Sheet').
        card model textAt: 1@1 put: '=B1'.
        new _ card veryDeepCopy.

        self assert: new model rule = card model rule.

        self assert: (SkProject current at: 'Sheet1' ifAbsent: [nil]) = nil.!

----- Method: SkSheetTest>>testSlotName (in category 'cell test') -----
testSlotName
        | cell morph |
        cell _ SkValueCell new.
        morph _ EllipseMorph new.
        cell
                on: morph assuredPlayer
                getter: #getX
                setter: #setX:.
        Project current naturalLanguage
                in: [:currentLanguage | [Project current setNaturalLanguageTo: #English.
                        self assert: cell slotName = 'Ellipse''s x']
                                ensure: [Project current setNaturalLanguageTo: currentLanguage]]!

----- Method: SkSheetTest>>testSplitDo (in category 'cell test') -----
testSplitDo
        self assert: (Array
                        streamContents: [:s | 'hi,hello,thanks'
                                        split: $,
                                        do: [:each | s nextPut: each]]) contents = #('hi' 'hello' 'thanks' ).

        self assert: (Array
                        streamContents: [:s | 'hi,hello,thanks,'
                                        split: $,
                                        do: [:each | s nextPut: each]]) contents = #('hi' 'hello' 'thanks' ).

        self assert: (Array
                        streamContents: [:s | 'hi,hello,thanks,,'
                                        split: $,
                                        do: [:each | s nextPut: each]]) contents = #('hi' 'hello' 'thanks' '')!

----- Method: SkSheetTest>>testStructureOnDictionary (in category 'structure test') -----
testStructureOnDictionary
        | s1 s2 s3 s4 |
        SkProject current removeAt: 'Sheet'.
        s1 := SkDictionary new.
        s2 := SkNamed new.
        s3 := SkDictionary new.
        s4 := SkNamed new.
        s2 parent: s1; name: 'TestName'.
        self assert: s2 ruleName = 'TestName'.
        s3 parent: s1; name: 'TestName'.
        self assert: s3 ruleName = 'TestName1'.
        s3 beAlone.
        self assert: s4 ruleName isNil.
        s4 attachProject.
        self assert: s4 ruleName = 'Sheet'.
!

----- Method: SkSheetTest>>testStructureOnSheet (in category 'structure test') -----
testStructureOnSheet
        | s1 s2 s3 s4 |
        s1 := SkSheet new.
        s2 := SkNamed new.
        s3 := SkSheet new.
        s4 := SkNamed new.
        s2 parent: s1; name: 'TestName'.
        self assert: s2 ruleName = 'TestName'.
        s4 parent: s3 uniqueName: nil.
        self assert: s4 ruleName = 'Sheet'.
        s4 parent: s1; name: 'TestName'.
        self assert: s4 ruleName = 'TestName1'.
        s4 beAlone.
        self assert: s4 ruleName isNil!

----- Method: SkSheetTest>>testText (in category 'text test') -----
testText
        | sheet |
        sheet _ SkSheet
                                contents: [:holder |
                                        holder
                                                at: 1 @ 1
                                                put: [(holder at: 2 @ 1)
                                                                + (holder at: 3 @ 1)].
                                        holder at: 2 @ 1 put: 1.
                                        holder at: 3 @ 1 put: 1].
" sheet grid openInWorld."!

----- Method: SkSheetTest>>testlocalToGlobal (in category 'card tests') -----
testlocalToGlobal
        | m |
        m := SkCardMorph model: SkProxy newForTest.
        m area: (2 @ 3 corner: 6 @ 4).
        m direction: #right.
        self assert: (m localToGlobal: 1 @ 1) = (3 @ 3).
        self assert: (m localToGlobal: 3 @ 1) = (5 @ 3).
        m direction: #left.
        self assert: (m localToGlobal: 1 @ 1) = (1 @ 3).
        self assert: (m localToGlobal: 3 @ 1) = (-1 @ 3).
        m direction: #down.
        " m area: (2@3 corner: 3@7)."
        self assert: (m localToGlobal: 1 @ 1) = (2 @ 4).
        self assert: (m localToGlobal: 3 @ 1) = (2 @ 6).
        m direction: #up.
        self assert: (m localToGlobal: 1 @ 1) = (2 @ 2).
        self assert: (m localToGlobal: 3 @ 1) = (2 @ 0)!

----- Method: Pen>>squareNib: (in category '*skeleton-base-pentrail') -----
squareNib: widthInteger
        "Makes this pen draw with a square nib of the given width."
        self sourceForm: (Form extent: widthInteger @ widthInteger) fillBlack.
        combinationRule
                ifNil: [self combinationRule: Form over
                        "a bit faster than paint mode"]!

----- Method: Point>>direction2:distance: (in category '*skeleton-base-sheet') -----
direction2: freePoint distance: distance
        "Ask Point by extention of self - freePoint with distance.  
        (100@100 direction: 400@100 distance: 100) =  
        (200@100)"
        "IT SHOULD BE REMOVED!!!!!! use #direction:distance:"
        self flag: #TODO.
        ^ self = freePoint
                ifTrue: [self]
                ifFalse: [self + (freePoint - self * distance / (freePoint - self) r)]!


_______________________________________________
etoys-dev mailing list
[hidden email]
http://lists.squeakland.org/mailman/listinfo/etoys-dev
Reply | Threaded
Open this post in threaded view
|

Re: Etoys Inbox: Skeleton-Richo.1.mcz

Bert Freudenberg
On 14.10.2011, at 22:52, [hidden email] wrote:

Spam detection software, running on the system "europa.mgmt.inetu.net", has
identified this incoming email as possible spam.  

Err, sometimes spam detectors are stupid ;)

Something is suspicious though. E.g., I think we can remove this:


----- Method: SkeletonBaseInfo class>>addPseudoMethodForBabel (in category 'class initialization') -----
addPseudoMethodForBabel
"This method supports both 3.6 and 3.7"
"self addPseudoMethodForBabel"
| addMethodBlock |
addMethodBlock _ [:class | class compileInobtrusively:
'translated
^ self'
classified: 'forward compatibility'].
['Can you translate?' translated]
on: MessageNotUnderstood
do: [:ex | addMethodBlock
value: (Smalltalk
at: #AbstractString
ifAbsent: [^ addMethodBlock value: String])]!


And do we really want to add all those sounds? They will make the sound drop-down longer.


----- Method: SkeletonBaseInfo class>>arrow (in category 'sound library') -----
arrow
SampledSound
addLibrarySoundNamed: 'arrow'
samples: (self mimeStringToBuffer:
'/WD9a/0g/N78nvx0/Kv9Rv39/qz/gACQAYsCGAIjAfIB9AJeAxgD2AREBGsElgTABOoFHAU9
BU4FPwTpBIMEOwP+A+gEGQRSBDQDrQMcAr4CWwHeAXIBKwEjAUgBRwEFAKQASwAF/6P/C/50

...

----- Method: SkeletonBaseInfo class>>cassete (in category 'sound library') -----
cassete
SampledSound
addLibrarySoundNamed: 'cassete'
samples: (self mimeStringToBuffer:
'AQD/AP4A/wD+AAAAAAD+AP8AAAD/AP0AAAAAAP8AAAABAAIA/AD/AP0A/wAAAAEA/QADAAAA
AAD+AP8AAQACAP8A/wD+AP8AAgD9AAQA/AD/AP8AAAACAP0AAAD6AAgACgD4APkA9gAGABIA
...
----- Method: SkeletonBaseInfo class>>cork (in category 'sound library') -----
cork
SampledSound
addLibrarySoundNamed: 'cork'
samples: (self mimeStringToBuffer:
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
...

----- Method: SkeletonBaseInfo class>>mochi (in category 'sound library') -----
mochi
SampledSound
addLibrarySoundNamed: 'mochi'
samples: (self mimeStringToBuffer:
'8gDsAOIA3gDvAC4AUQBDAA8AAAAxACsAHQAtABIA4wDEAMEA6gDbAPYAOQAqAAwAEADzALkA
xAAGAOgAzgABADAAMwAgADEAGQAEAAQAxgDgAPQA7QDUAN4A+gDtAPQABwD9ANoAxQDNANoA
...
----- Method: SkeletonBaseInfo class>>rice (in category 'sound library') -----
rice
SampledSound
addLibrarySoundNamed: 'rice'
samples: (self mimeStringToBuffer:
'CgAGAPQADAAAAAgA/gAIAPoABAAEAO4AAAAAAPoA9AAGAAIA+gAIAPIACgD6AAoA+gACAA4A
...
----- Method: SkeletonBaseInfo class>>unstick (in category 'sound library') -----
unstick
SampledSound
addLibrarySoundNamed: 'unstick'
samples: (self mimeStringToBuffer:
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
...


How about this?

PackageInfo subclass: #SkeletonInfo
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Skeleton-Base'!

!SkeletonInfo commentStamp: 'tak 3/30/2004 21:40' prior: 0!
I am a full Skeleton package information.!

----- Method: SkeletonInfo>>packageName (in category 'naming') -----
packageName
^ 'Skeleton'!

And there are some method flagged TODO.

----- Method: Point>>direction2:distance: (in category '*skeleton-base-sheet') -----
direction2: freePoint distance: distance 
"Ask Point by extention of self - freePoint with distance.  
(100@100 direction: 400@100 distance: 100) =  
(200@100)"
"IT SHOULD BE REMOVED!!!!!! use #direction:distance:"
self flag: #TODO.
^ self = freePoint
ifTrue: [self]
ifFalse: [self + (freePoint - self * distance / (freePoint - self) r)]!

This here uses fork without synchronizing with the Morphic UI process:

----- Method: Morph>>showPointArrowFrom:to:label: (in category '*skeleton-base-arrow') -----
showPointArrowFrom: morph1 to: morph2 label: aString 
"Morph new showPointArrowFrom: (Morph new position: 0@0) to: (Morph  
new position: 200@200) label: 'test'"
| p1 p2 arrow label connector |
p1 := morph1 center.
p2 := morph2 center.
arrow := PolygonMorph arrowPrototype.
arrow
borderColor: (TranslucentColor
r: 1.0
g: 0.3
b: 0.0
alpha: 0.6).
arrow
setVertices: (Array with: p1 with: p2).
arrow dashedBorder: {30. 30. Color transparent. 0. -10};
 startStepping.
(Smalltalk
at: #NCConnectorMorph
ifAbsent: [])
ifNotNil: [connector := NCConnectorMorph fromMorph: morph1 toMorph: morph2.
connector line: arrow.
connector lock.
label := NCLabelMorph new string: aString.
label input: morph1.
label color: Color red.
label openInWorld.
arrow := connector].
[arrow openInWorld.
(Delay forMilliseconds: 500) wait.
arrow delete.
label
ifNotNilDo: [:obj | obj delete]] fork!

It should be at least something like

arrow openInWorld.
[
(Delay forMilliseconds: 500) wait.
WorldState addDeferredUIMessage: [
arrow delete.
label ifNotNilDo: [:obj | obj delete]].
] fork

Or even better schedule an alarm instead of forking, e.g.

arrow openInWorld.
arrow addAlarm: #delete after: 500.
label ifNotNil: [label addAlarm: #delete after: 500.

- Bert -


_______________________________________________
etoys-dev mailing list
[hidden email]
http://lists.squeakland.org/mailman/listinfo/etoys-dev