3
1D3623240D0F684500981E51 /* SqueakNoOGLIPhoneAppDelegate.h */ = {
5
sepNavIntBoundsRect = "{{0, 0}, {1167, 858}}";
6
sepNavSelRange = "{3089, 12}";
7
sepNavVisRange = "{656, 2653}";
8
sepNavWindowFrame = "{{15, 15}, {694, 1008}}";
11
1D3623250D0F684500981E51 /* SqueakNoOGLIPhoneAppDelegate.m */ = {
13
sepNavIntBoundsRect = "{{0, 0}, {943, 3341}}";
14
sepNavSelRange = "{5386, 0}";
15
sepNavVisRange = "{5229, 1794}";
16
sepNavWindowFrame = "{{15, 4}, {1426, 1019}}";
19
1D6058900D05DD3D006BFB54 /* SqueakNoOGLIPhone */ = {
22
9424FF3E0DDC8654009912BF /* Squeak */,
25
29B97313FDCFA39411CA2CEA /* Project object */ = {
26
activeArchitecturePreference = armv6;
27
activeBuildConfigurationName = Distribution;
28
activeExecutable = 947E62FD10AA098300D3B69E /* SqueakPureObjc */;
29
activeSDKPreference = macosx10.5;
30
activeTarget = 947E626F10AA098300D3B69E /* SqueakPureObjc */;
32
1D6058900D05DD3D006BFB54 /* SqueakNoOGLIPhone */,
35
9458511410F03996001401E7 /* sqMacExtendedClipboard.m:101 */,
36
9458523210F040A0001401E7 /* sqMacExtendedClipboard.m:37 */,
37
9458523410F040A1001401E7 /* sqMacExtendedClipboard.m:45 */,
38
9458523610F040A2001401E7 /* sqMacExtendedClipboard.m:50 */,
39
9458523A10F040AF001401E7 /* sqMacExtendedClipboard.m:72 */,
40
9458524810F04272001401E7 /* sqMacExtendedClipboard.m:88 */,
41
9458527F10F045FB001401E7 /* sqSqueakIPhoneClipboardAPI.m:31 */,
42
9458528110F045FC001401E7 /* sqSqueakIPhoneClipboardAPI.m:24 */,
43
9458528310F045FD001401E7 /* sqSqueakIPhoneClipboardAPI.m:17 */,
44
944F6D171224D7B300DFC0CD /* sqSqueakOSXApplication+imageReadWrite.m:64 */,
45
94E8FA6512258FDF00EECD29 /* sqMacV2Memory.c:191 */,
46
9415C06312306B660067CD8E /* SqueakUIView.m:118 */,
47
9415C06512306B6F0067CD8E /* SqueakUIView.m:126 */,
48
9415C11412306FCC0067CD8E /* sqiPhoneScreenAndWindow.m:63 */,
49
94C748E012333EE900B1F982 /* sqMacUIEventsUniversal.c:1113 */,
50
943B9AF71235B9FD0056205E /* sqSqueakOSXNSWindowController.m:18 */,
51
943B9B9E1235BE580056205E /* sqMacHostWindow.m:58 */,
52
94AC16D512395FE40067037A /* sqSqueakOSXNSView.m:551 */,
53
94C8D195123EDACE0019544B /* SqueakUIViewOpenGL.m:135 */,
54
947E99CB125D78FB0048E783 /* NSLOG */,
55
947E99CC125D78FE0048E783 /* NSlog */,
56
947E99D0125D79050048E783 /* NSLog */,
57
947E99F8125D7B1C0048E783 /* cl */,
58
9427E42E12627E6A002DCA6D /* sqSqueakIPhoneApplication+imageReadWrite.m:95 */,
60
codeSenseManager = 9424FF430DDC8673009912BF /* Code sense */;
62
9424FF3E0DDC8654009912BF /* Squeak */,
63
947E62FD10AA098300D3B69E /* SqueakPureObjc */,
68
ignoreBreakpointsInProjectsDict = {
69
SqueakVMUNIXPATHS = Ignored;
72
"PBXConfiguration.PBXBreakpointsDataSource.v1:1CA1AED706398EBD00589147" = {
73
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
74
PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_LocationID;
75
PBXFileTableDataSourceColumnWidthsKey = (
85
PBXFileTableDataSourceColumnsKey = (
86
PBXBreakpointsDataSource_ActionID,
87
PBXBreakpointsDataSource_TypeID,
88
PBXBreakpointsDataSource_BreakpointID,
89
PBXBreakpointsDataSource_UseID,
90
PBXBreakpointsDataSource_LocationID,
91
PBXBreakpointsDataSource_ConditionID,
92
PBXBreakpointsDataSource_IgnoreCountID,
93
PBXBreakpointsDataSource_ContinueID,
96
PBXConfiguration.PBXFileTableDataSource3.PBXBookmarksDataSource = {
97
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
98
PBXFileTableDataSourceColumnSortingKey = PBXBookmarksDataSource_NameID;
99
PBXFileTableDataSourceColumnWidthsKey = (
104
PBXFileTableDataSourceColumnsKey = (
105
PBXBookmarksDataSource_LocationID,
106
PBXBookmarksDataSource_NameID,
107
PBXBookmarksDataSource_CommentsID,
110
PBXConfiguration.PBXFileTableDataSource3.PBXErrorsWarningsDataSource = {
111
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
112
PBXFileTableDataSourceColumnSortingKey = PBXErrorsWarningsDataSource_LocationID;
113
PBXFileTableDataSourceColumnWidthsKey = (
118
PBXFileTableDataSourceColumnsKey = (
119
PBXErrorsWarningsDataSource_TypeID,
120
PBXErrorsWarningsDataSource_MessageID,
121
PBXErrorsWarningsDataSource_LocationID,
124
PBXConfiguration.PBXFileTableDataSource3.PBXExecutablesDataSource = {
125
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
126
PBXFileTableDataSourceColumnSortingKey = PBXExecutablesDataSource_NameID;
127
PBXFileTableDataSourceColumnWidthsKey = (
132
PBXFileTableDataSourceColumnsKey = (
133
PBXExecutablesDataSource_ActiveFlagID,
134
PBXExecutablesDataSource_NameID,
135
PBXExecutablesDataSource_CommentsID,
138
PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
139
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
140
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
141
PBXFileTableDataSourceColumnWidthsKey = (
150
PBXFileTableDataSourceColumnsKey = (
151
PBXFileDataSource_FiletypeID,
152
PBXFileDataSource_Filename_ColumnID,
153
PBXFileDataSource_Built_ColumnID,
154
PBXFileDataSource_ObjectSize_ColumnID,
155
PBXFileDataSource_Errors_ColumnID,
156
PBXFileDataSource_Warnings_ColumnID,
157
PBXFileDataSource_Target_ColumnID,
160
PBXConfiguration.PBXFileTableDataSource3.PBXFindDataSource = {
161
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
162
PBXFileTableDataSourceColumnSortingKey = PBXFindDataSource_LocationID;
163
PBXFileTableDataSourceColumnWidthsKey = (
167
PBXFileTableDataSourceColumnsKey = (
168
PBXFindDataSource_MessageID,
169
PBXFindDataSource_LocationID,
172
PBXConfiguration.PBXFileTableDataSource3.PBXSymbolsDataSource = {
173
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
174
PBXFileTableDataSourceColumnSortingKey = PBXSymbolsDataSource_SymbolTypeIconID;
175
PBXFileTableDataSourceColumnWidthsKey = (
181
PBXFileTableDataSourceColumnsKey = (
182
PBXSymbolsDataSource_SymbolTypeIconID,
183
PBXSymbolsDataSource_SymbolNameID,
184
PBXSymbolsDataSource_SymbolTypeID,
185
PBXSymbolsDataSource_ReferenceNameID,
188
PBXConfiguration.PBXFileTableDataSource3.XCSCMDataSource = {
189
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
190
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
191
PBXFileTableDataSourceColumnWidthsKey = (
201
PBXFileTableDataSourceColumnsKey = (
202
PBXFileDataSource_SCM_ColumnID,
203
PBXFileDataSource_FiletypeID,
204
PBXFileDataSource_Filename_ColumnID,
205
PBXFileDataSource_Built_ColumnID,
206
PBXFileDataSource_ObjectSize_ColumnID,
207
PBXFileDataSource_Errors_ColumnID,
208
PBXFileDataSource_Warnings_ColumnID,
209
PBXFileDataSource_Target_ColumnID,
212
PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = {
213
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
214
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
215
PBXFileTableDataSourceColumnWidthsKey = (
224
PBXFileTableDataSourceColumnsKey = (
225
PBXFileDataSource_FiletypeID,
226
PBXFileDataSource_Filename_ColumnID,
227
PBXTargetDataSource_PrimaryAttribute,
228
PBXFileDataSource_Built_ColumnID,
229
PBXFileDataSource_ObjectSize_ColumnID,
230
PBXFileDataSource_Errors_ColumnID,
231
PBXFileDataSource_Warnings_ColumnID,
234
PBXPerProjectTemplateStateSaveDate = 308462977;
235
PBXWorkspaceStateSaveDate = 308462977;
237
perUserProjectItems = {
238
940125A81228E3FC002883F0 /* PBXTextBookmark */ = 940125A81228E3FC002883F0 /* PBXTextBookmark */;
239
9402DDB610CE12A5005C2102 /* PBXTextBookmark */ = 9402DDB610CE12A5005C2102 /* PBXTextBookmark */;
240
94059113122AFF8C009939CE /* PBXTextBookmark */ = 94059113122AFF8C009939CE /* PBXTextBookmark */;
241
9406B4DF11EC314E002670B7 /* PBXTextBookmark */ = 9406B4DF11EC314E002670B7 /* PBXTextBookmark */;
242
9406E7E210B663F4002F81F2 /* PBXTextBookmark */ = 9406E7E210B663F4002F81F2 /* PBXTextBookmark */;
243
9406E87110B66A74002F81F2 /* PBXTextBookmark */ = 9406E87110B66A74002F81F2 /* PBXTextBookmark */;
244
9406E8CC10B67499002F81F2 /* PBXTextBookmark */ = 9406E8CC10B67499002F81F2 /* PBXTextBookmark */;
245
940E86A31220A8D200AAB6F5 /* PBXTextBookmark */ = 940E86A31220A8D200AAB6F5 /* PBXTextBookmark */;
246
940E86EE1220AF3D00AAB6F5 /* PBXTextBookmark */ = 940E86EE1220AF3D00AAB6F5 /* PBXTextBookmark */;
247
941441FD10BC817D0088F8AC /* PBXTextBookmark */ = 941441FD10BC817D0088F8AC /* PBXTextBookmark */;
248
9414420110BC817D0088F8AC /* PBXTextBookmark */ = 9414420110BC817D0088F8AC /* PBXTextBookmark */;
249
9415C07412306BDD0067CD8E /* PBXTextBookmark */ = 9415C07412306BDD0067CD8E /* PBXTextBookmark */;
250
941A331D11E63E1A004796BA /* PBXTextBookmark */ = 941A331D11E63E1A004796BA /* PBXTextBookmark */;
251
941A331F11E63E1A004796BA /* PBXTextBookmark */ = 941A331F11E63E1A004796BA /* PBXTextBookmark */;
252
9421AB550FF1807D008F54E9 /* PBXTextBookmark */ = 9421AB550FF1807D008F54E9 /* PBXTextBookmark */;
253
94238E5E11E7B0EB004401BE /* PBXTextBookmark */ = 94238E5E11E7B0EB004401BE /* PBXTextBookmark */;
254
9427E35512626DFB002DCA6D /* PBXTextBookmark */ = 9427E35512626DFB002DCA6D /* PBXTextBookmark */;
255
9427E37B12626EE6002DCA6D /* PBXTextBookmark */ = 9427E37B12626EE6002DCA6D /* PBXTextBookmark */;
256
9427E3F612627C61002DCA6D /* PBXTextBookmark */ = 9427E3F612627C61002DCA6D /* PBXTextBookmark */;
257
9427E3F812627C61002DCA6D /* PlistBookmark */ = 9427E3F812627C61002DCA6D /* PlistBookmark */;
258
9427E3F912627C61002DCA6D /* PlistBookmark */ = 9427E3F912627C61002DCA6D /* PlistBookmark */;
259
9427E44B12628333002DCA6D /* PBXTextBookmark */ = 9427E44B12628333002DCA6D /* PBXTextBookmark */;
260
9427E44C12628333002DCA6D /* PBXTextBookmark */ = 9427E44C12628333002DCA6D /* PBXTextBookmark */;
261
9427E44D12628333002DCA6D /* PlistBookmark */ = 9427E44D12628333002DCA6D /* PlistBookmark */;
262
9427E46212629AE3002DCA6D /* PBXBookmark */ = 9427E46212629AE3002DCA6D /* PBXBookmark */;
263
9427E46312629AE3002DCA6D /* PlistBookmark */ = 9427E46312629AE3002DCA6D /* PlistBookmark */;
264
9427E4D11262B997002DCA6D /* PBXTextBookmark */ = 9427E4D11262B997002DCA6D /* PBXTextBookmark */;
265
9427E4D21262B997002DCA6D /* PBXTextBookmark */ = 9427E4D21262B997002DCA6D /* PBXTextBookmark */;
266
942807EE1224862A0000DCFE /* PBXTextBookmark */ = 942807EE1224862A0000DCFE /* PBXTextBookmark */;
267
942807EF1224862A0000DCFE /* PBXTextBookmark */ = 942807EF1224862A0000DCFE /* PBXTextBookmark */;
268
942807F01224862A0000DCFE /* PBXTextBookmark */ = 942807F01224862A0000DCFE /* PBXTextBookmark */;
269
9428BBAD10BB50E200DAD287 /* PBXTextBookmark */ = 9428BBAD10BB50E200DAD287 /* PBXTextBookmark */;
270
9428BC5510BB74BF00DAD287 /* PBXTextBookmark */ = 9428BC5510BB74BF00DAD287 /* PBXTextBookmark */;
271
9428BC5710BB74BF00DAD287 /* PBXTextBookmark */ = 9428BC5710BB74BF00DAD287 /* PBXTextBookmark */;
272
9428BF3810BBC2ED00DAD287 /* PBXTextBookmark */ = 9428BF3810BBC2ED00DAD287 /* PBXTextBookmark */;
273
9428BF4F10BBCAAC00DAD287 /* PBXTextBookmark */ = 9428BF4F10BBCAAC00DAD287 /* PBXTextBookmark */;
274
942ABEC510AA34820086D908 /* PBXTextBookmark */ = 942ABEC510AA34820086D908 /* PBXTextBookmark */;
275
942B77330EA7E642004B266D /* PBXTextBookmark */ = 942B77330EA7E642004B266D /* PBXTextBookmark */;
276
942B77380EA7E642004B266D /* PBXTextBookmark */ = 942B77380EA7E642004B266D /* PBXTextBookmark */;
277
942B779B0EA7F2E0004B266D /* PBXTextBookmark */ = 942B779B0EA7F2E0004B266D /* PBXTextBookmark */;
278
942B779C0EA7F2E0004B266D /* PBXTextBookmark */ = 942B779C0EA7F2E0004B266D /* PBXTextBookmark */;
279
942B77B90EA800E1004B266D /* PBXTextBookmark */ = 942B77B90EA800E1004B266D /* PBXTextBookmark */;
280
942B77BB0EA800E1004B266D /* PBXTextBookmark */ = 942B77BB0EA800E1004B266D /* PBXTextBookmark */;
281
942B77C00EA800E1004B266D /* PBXTextBookmark */ = 942B77C00EA800E1004B266D /* PBXTextBookmark */;
282
9430325510BD0B6D0045D33B /* PBXTextBookmark */ = 9430325510BD0B6D0045D33B /* PBXTextBookmark */;
283
9430329A10BD103B0045D33B /* PBXTextBookmark */ = 9430329A10BD103B0045D33B /* PBXTextBookmark */;
284
9430329B10BD103B0045D33B /* PBXTextBookmark */ = 9430329B10BD103B0045D33B /* PBXTextBookmark */;
285
943B9B151235BB080056205E /* PBXTextBookmark */ = 943B9B151235BB080056205E /* PBXTextBookmark */;
286
943B9B1E1235BD150056205E /* PBXTextBookmark */ = 943B9B1E1235BD150056205E /* PBXTextBookmark */;
287
943B9BD31235C1120056205E /* PBXTextBookmark */ = 943B9BD31235C1120056205E /* PBXTextBookmark */;
288
943B9BD41235C1120056205E /* PBXTextBookmark */ = 943B9BD41235C1120056205E /* PBXTextBookmark */;
289
943B9C041235C1EE0056205E /* PBXTextBookmark */ = 943B9C041235C1EE0056205E /* PBXTextBookmark */;
290
943B9C311235C3D70056205E /* PBXTextBookmark */ = 943B9C311235C3D70056205E /* PBXTextBookmark */;
291
943B9C331235C3D70056205E /* PBXTextBookmark */ = 943B9C331235C3D70056205E /* PBXTextBookmark */;
292
943B9D621235C79C0056205E /* PBXTextBookmark */ = 943B9D621235C79C0056205E /* PBXTextBookmark */;
293
943C0AC7122DF3710086B6AD /* PBXTextBookmark */ = 943C0AC7122DF3710086B6AD /* PBXTextBookmark */;
294
943C0AC8122DF3710086B6AD /* PBXTextBookmark */ = 943C0AC8122DF3710086B6AD /* PBXTextBookmark */;
295
943C0ACA122DF3710086B6AD /* PBXTextBookmark */ = 943C0ACA122DF3710086B6AD /* PBXTextBookmark */;
296
943C0AE0122DF5E70086B6AD /* PBXTextBookmark */ = 943C0AE0122DF5E70086B6AD /* PBXTextBookmark */;
297
943C0AE2122DF5E70086B6AD /* PBXTextBookmark */ = 943C0AE2122DF5E70086B6AD /* PBXTextBookmark */;
298
943C0AE5122DF5E70086B6AD /* PBXTextBookmark */ = 943C0AE5122DF5E70086B6AD /* PBXTextBookmark */;
299
943C0AE7122DF5E70086B6AD /* PBXTextBookmark */ = 943C0AE7122DF5E70086B6AD /* PBXTextBookmark */;
300
9441DB7111E6805300345F6C /* PBXTextBookmark */ = 9441DB7111E6805300345F6C /* PBXTextBookmark */;
301
9441DB7211E6805300345F6C /* PBXTextBookmark */ = 9441DB7211E6805300345F6C /* PBXTextBookmark */;
302
9448940B10F3E8FF00FB3EC8 /* PBXTextBookmark */ = 9448940B10F3E8FF00FB3EC8 /* PBXTextBookmark */;
303
9451E64F123F0E9200B4119F /* PlistBookmark */ = 9451E64F123F0E9200B4119F /* PlistBookmark */;
304
9453F58A1234AF8A00C91CF7 /* PBXTextBookmark */ = 9453F58A1234AF8A00C91CF7 /* PBXTextBookmark */;
305
9453F58C1234AF8A00C91CF7 /* PBXTextBookmark */ = 9453F58C1234AF8A00C91CF7 /* PBXTextBookmark */;
306
9453F58D1234AF8A00C91CF7 /* PBXTextBookmark */ = 9453F58D1234AF8A00C91CF7 /* PBXTextBookmark */;
307
9453F5911234AF8A00C91CF7 /* PBXTextBookmark */ = 9453F5911234AF8A00C91CF7 /* PBXTextBookmark */;
308
9453F5931234AF8A00C91CF7 /* PBXTextBookmark */ = 9453F5931234AF8A00C91CF7 /* PBXTextBookmark */;
309
9453F5951234AF8A00C91CF7 /* PBXTextBookmark */ = 9453F5951234AF8A00C91CF7 /* PBXTextBookmark */;
310
94547F160DE0AC7D00DD588F /* PBXTextBookmark */ = 94547F160DE0AC7D00DD588F /* PBXTextBookmark */;
311
945481A60DE2A79200DD588F /* PBXTextBookmark */ = 945481A60DE2A79200DD588F /* PBXTextBookmark */;
312
94554E670DF1171500FB176B /* PBXTextBookmark */ = 94554E670DF1171500FB176B /* PBXTextBookmark */;
313
94554E690DF1171500FB176B /* PBXTextBookmark */ = 94554E690DF1171500FB176B /* PBXTextBookmark */;
314
94554EB80DF1A86A00FB176B /* PBXTextBookmark */ = 94554EB80DF1A86A00FB176B /* PBXTextBookmark */;
315
9456C24F10B2F268000BF3DE /* PBXTextBookmark */ = 9456C24F10B2F268000BF3DE /* PBXTextBookmark */;
316
9456C25A10B2F2C9000BF3DE /* PBXTextBookmark */ = 9456C25A10B2F2C9000BF3DE /* PBXTextBookmark */;
317
9456C32210B32F43000BF3DE /* PBXTextBookmark */ = 9456C32210B32F43000BF3DE /* PBXTextBookmark */;
318
9456C34E10B33618000BF3DE /* PBXTextBookmark */ = 9456C34E10B33618000BF3DE /* PBXTextBookmark */;
319
9456C3CB10B341F9000BF3DE /* PBXTextBookmark */ = 9456C3CB10B341F9000BF3DE /* PBXTextBookmark */;
320
945C4D7C10BB0A8500548CC1 /* PBXTextBookmark */ = 945C4D7C10BB0A8500548CC1 /* PBXTextBookmark */;
321
945C4EAC10BB348300548CC1 /* PBXTextBookmark */ = 945C4EAC10BB348300548CC1 /* PBXTextBookmark */;
322
945E9D7C0DE525E100CDF01E /* PBXTextBookmark */ = 945E9D7C0DE525E100CDF01E /* PBXTextBookmark */;
323
945F30FC0E0C763800CFF3DC /* PBXTextBookmark */ = 945F30FC0E0C763800CFF3DC /* PBXTextBookmark */;
324
94638CEA0EB16F1100A3F155 /* PBXTextBookmark */ = 94638CEA0EB16F1100A3F155 /* PBXTextBookmark */;
325
946C240C1230A80A004938A1 /* PBXTextBookmark */ = 946C240C1230A80A004938A1 /* PBXTextBookmark */;
326
946D973B0FE165B70038846B /* PBXTextBookmark */ = 946D973B0FE165B70038846B /* PBXTextBookmark */;
327
946DA7E010C0A7A400F26F56 /* PBXTextBookmark */ = 946DA7E010C0A7A400F26F56 /* PBXTextBookmark */;
328
946DA8D910C0C32800F26F56 /* PBXTextBookmark */ = 946DA8D910C0C32800F26F56 /* PBXTextBookmark */;
329
946DA8DA10C0C32800F26F56 /* PBXTextBookmark */ = 946DA8DA10C0C32800F26F56 /* PBXTextBookmark */;
330
946DA8DB10C0C32800F26F56 /* PBXTextBookmark */ = 946DA8DB10C0C32800F26F56 /* PBXTextBookmark */;
331
946DAA3810C0D8B700F26F56 /* PBXTextBookmark */ = 946DAA3810C0D8B700F26F56 /* PBXTextBookmark */;
332
946DAA3A10C0D8B700F26F56 /* PBXTextBookmark */ = 946DAA3A10C0D8B700F26F56 /* PBXTextBookmark */;
333
946DAA3C10C0D8B700F26F56 /* PBXTextBookmark */ = 946DAA3C10C0D8B700F26F56 /* PBXTextBookmark */;
334
94700A50123DF62D00874318 /* PBXTextBookmark */ = 94700A50123DF62D00874318 /* PBXTextBookmark */;
335
94700A51123DF62D00874318 /* PBXTextBookmark */ = 94700A51123DF62D00874318 /* PBXTextBookmark */;
336
94700AAD123DFCEA00874318 /* PBXTextBookmark */ = 94700AAD123DFCEA00874318 /* PBXTextBookmark */;
337
947332EE0EA70E8C003F9084 /* PBXTextBookmark */ = 947332EE0EA70E8C003F9084 /* PBXTextBookmark */;
338
9473A34810BBD84100ED7D00 /* PBXTextBookmark */ = 9473A34810BBD84100ED7D00 /* PBXTextBookmark */;
339
9473A95A1102F70B00D135CB /* PBXTextBookmark */ = 9473A95A1102F70B00D135CB /* PBXTextBookmark */;
340
9473A9701103BE0A00D135CB /* PBXTextBookmark */ = 9473A9701103BE0A00D135CB /* PBXTextBookmark */;
341
9475A83511E6B5D50010FB38 /* PBXTextBookmark */ = 9475A83511E6B5D50010FB38 /* PBXTextBookmark */;
342
9475F4DB10BEF4100047A24B /* PBXTextBookmark */ = 9475F4DB10BEF4100047A24B /* PBXTextBookmark */;
343
9475F56B10BF20A00047A24B /* PBXTextBookmark */ = 9475F56B10BF20A00047A24B /* PBXTextBookmark */;
344
9475F5A710BF25A10047A24B /* PBXTextBookmark */ = 9475F5A710BF25A10047A24B /* PBXTextBookmark */;
345
947713D410C45E5F00890A9B /* PBXTextBookmark */ = 947713D410C45E5F00890A9B /* PBXTextBookmark */;
346
9478E13D0EC8EB46007096A7 /* PBXTextBookmark */ = 9478E13D0EC8EB46007096A7 /* PBXTextBookmark */;
347
947923FE1102BE53007C87F8 /* PBXTextBookmark */ = 947923FE1102BE53007C87F8 /* PBXTextBookmark */;
348
947E210C0EB28486007957D0 /* PBXTextBookmark */ = 947E210C0EB28486007957D0 /* PBXTextBookmark */;
349
947E61D610AA049300D3B69E /* PBXTextBookmark */ = 947E61D610AA049300D3B69E /* PBXTextBookmark */;
350
947E61DA10AA049300D3B69E /* PBXTextBookmark */ = 947E61DA10AA049300D3B69E /* PBXTextBookmark */;
351
947E61DC10AA049300D3B69E /* PBXTextBookmark */ = 947E61DC10AA049300D3B69E /* PBXTextBookmark */;
352
947E9920125D73FD0048E783 /* PBXTextBookmark */ = 947E9920125D73FD0048E783 /* PBXTextBookmark */;
353
947E9964125D756D0048E783 /* PBXTextBookmark */ = 947E9964125D756D0048E783 /* PBXTextBookmark */;
354
947E9967125D756D0048E783 /* PBXTextBookmark */ = 947E9967125D756D0048E783 /* PBXTextBookmark */;
355
947E9969125D756D0048E783 /* PBXTextBookmark */ = 947E9969125D756D0048E783 /* PBXTextBookmark */;
356
947E996B125D756D0048E783 /* PBXTextBookmark */ = 947E996B125D756D0048E783 /* PBXTextBookmark */;
357
947E996D125D756D0048E783 /* PBXTextBookmark */ = 947E996D125D756D0048E783 /* PBXTextBookmark */;
358
947E996F125D756D0048E783 /* PBXTextBookmark */ = 947E996F125D756D0048E783 /* PBXTextBookmark */;
359
947E9971125D756D0048E783 /* PBXTextBookmark */ = 947E9971125D756D0048E783 /* PBXTextBookmark */;
360
947E9994125D76820048E783 /* PBXTextBookmark */ = 947E9994125D76820048E783 /* PBXTextBookmark */;
361
947E99A0125D76BB0048E783 /* PBXTextBookmark */ = 947E99A0125D76BB0048E783 /* PBXTextBookmark */;
362
947E99FA125D7B850048E783 /* PBXTextBookmark */ = 947E99FA125D7B850048E783 /* PBXTextBookmark */;
363
948034A9122A264A00C42504 /* PBXTextBookmark */ = 948034A9122A264A00C42504 /* PBXTextBookmark */;
364
948127E812444F7800BD1543 /* PBXTextBookmark */ = 948127E812444F7800BD1543 /* PBXTextBookmark */;
365
948127E912444F7800BD1543 /* PBXTextBookmark */ = 948127E912444F7800BD1543 /* PBXTextBookmark */;
366
948127EA12444F7800BD1543 /* PBXTextBookmark */ = 948127EA12444F7800BD1543 /* PBXTextBookmark */;
367
948127EB12444F7800BD1543 /* PBXTextBookmark */ = 948127EB12444F7800BD1543 /* PBXTextBookmark */;
368
9484F86210B0DCC60038BDC0 /* PBXTextBookmark */ = 9484F86210B0DCC60038BDC0 /* PBXTextBookmark */;
369
9484F86510B0DCC60038BDC0 /* PBXTextBookmark */ = 9484F86510B0DCC60038BDC0 /* PBXTextBookmark */;
370
9484F8FC10B0E1770038BDC0 /* PBXBookmark */ = 9484F8FC10B0E1770038BDC0 /* PBXBookmark */;
371
94862F8310BA182500CAA2EB /* PBXTextBookmark */ = 94862F8310BA182500CAA2EB /* PBXTextBookmark */;
372
94862F9E10BA1A0100CAA2EB /* PBXTextBookmark */ = 94862F9E10BA1A0100CAA2EB /* PBXTextBookmark */;
373
9486302A10BA247200CAA2EB /* PBXTextBookmark */ = 9486302A10BA247200CAA2EB /* PBXTextBookmark */;
374
948704AE0E12CABF00D565C3 /* PBXTextBookmark */ = 948704AE0E12CABF00D565C3 /* PBXTextBookmark */;
375
9487071F0E132B1000D565C3 /* PBXTextBookmark */ = 9487071F0E132B1000D565C3 /* PBXTextBookmark */;
376
948C0820112DE98D0017EE7F /* PBXTextBookmark */ = 948C0820112DE98D0017EE7F /* PBXTextBookmark */;
377
948FAA0310BF855500BE88CF /* PBXTextBookmark */ = 948FAA0310BF855500BE88CF /* PBXTextBookmark */;
378
948FAB5B10BFAD3C00BE88CF /* PBXTextBookmark */ = 948FAB5B10BFAD3C00BE88CF /* PBXTextBookmark */;
379
949198B010BC8DFC00C629D1 /* PBXTextBookmark */ = 949198B010BC8DFC00C629D1 /* PBXTextBookmark */;
380
949198C910BC8FBB00C629D1 /* PBXTextBookmark */ = 949198C910BC8FBB00C629D1 /* PBXTextBookmark */;
381
9492450510BA42EF00E726F5 /* PBXTextBookmark */ = 9492450510BA42EF00E726F5 /* PBXTextBookmark */;
382
9492450710BA42EF00E726F5 /* PBXTextBookmark */ = 9492450710BA42EF00E726F5 /* PBXTextBookmark */;
383
9492450910BA42EF00E726F5 /* PBXTextBookmark */ = 9492450910BA42EF00E726F5 /* PBXTextBookmark */;
384
949245B210BA4A6200E726F5 /* PBXTextBookmark */ = 949245B210BA4A6200E726F5 /* PBXTextBookmark */;
385
9493E98F10EE90BC000C4FB3 /* PBXTextBookmark */ = 9493E98F10EE90BC000C4FB3 /* PBXTextBookmark */;
386
94977E7C11EE46BC002BC5E9 /* PBXTextBookmark */ = 94977E7C11EE46BC002BC5E9 /* PBXTextBookmark */;
387
949AD35211E54A81006D6BF4 /* PBXTextBookmark */ = 949AD35211E54A81006D6BF4 /* PBXTextBookmark */;
388
949AD36211E54AAA006D6BF4 /* PBXTextBookmark */ = 949AD36211E54AAA006D6BF4 /* PBXTextBookmark */;
389
949C3A281262C1F700F4EF15 /* PBXTextBookmark */ = 949C3A281262C1F700F4EF15 /* PBXTextBookmark */;
390
949C3A441262C2D200F4EF15 /* PBXTextBookmark */ = 949C3A441262C2D200F4EF15 /* PBXTextBookmark */;
391
949C3AFE1262C91300F4EF15 /* PBXTextBookmark */ = 949C3AFE1262C91300F4EF15 /* PBXTextBookmark */;
392
949C3AFF1262C91300F4EF15 /* PBXTextBookmark */ = 949C3AFF1262C91300F4EF15 /* PBXTextBookmark */;
393
949C3B171262C9C900F4EF15 /* PBXTextBookmark */ = 949C3B171262C9C900F4EF15 /* PBXTextBookmark */;
394
949DDD6D11D141080017F79B /* PBXTextBookmark */ = 949DDD6D11D141080017F79B /* PBXTextBookmark */;
395
949F254511EC33FA00A34245 /* PBXTextBookmark */ = 949F254511EC33FA00A34245 /* PBXTextBookmark */;
396
949F254611EC33FA00A34245 /* PBXTextBookmark */ = 949F254611EC33FA00A34245 /* PBXTextBookmark */;
397
949F254811EC33FA00A34245 /* PBXTextBookmark */ = 949F254811EC33FA00A34245 /* PBXTextBookmark */;
398
94A1B2AA10B9E92A00C64473 /* PBXTextBookmark */ = 94A1B2AA10B9E92A00C64473 /* PBXTextBookmark */;
399
94A1B41E10BA05E600C64473 /* PBXTextBookmark */ = 94A1B41E10BA05E600C64473 /* PBXTextBookmark */;
400
94AB2E6A0E003879006A79E4 /* PBXTextBookmark */ = 94AB2E6A0E003879006A79E4 /* PBXTextBookmark */;
401
94AB2E6C0E003879006A79E4 /* PBXTextBookmark */ = 94AB2E6C0E003879006A79E4 /* PBXTextBookmark */;
402
94AC16D912395FF10067037A /* PBXTextBookmark */ = 94AC16D912395FF10067037A /* PBXTextBookmark */;
403
94AC16DA12395FF10067037A /* PBXTextBookmark */ = 94AC16DA12395FF10067037A /* PBXTextBookmark */;
404
94AC16DC12395FF10067037A /* PBXTextBookmark */ = 94AC16DC12395FF10067037A /* PBXTextBookmark */;
405
94AC16DE12395FF10067037A /* PBXTextBookmark */ = 94AC16DE12395FF10067037A /* PBXTextBookmark */;
406
94AF3A1F12231A7200691409 /* PBXTextBookmark */ = 94AF3A1F12231A7200691409 /* PBXTextBookmark */;
407
94B1514E0DE2CE530059F208 /* PBXTextBookmark */ = 94B1514E0DE2CE530059F208 /* PBXTextBookmark */;
408
94B7898910C4F95E005EA70D /* PBXTextBookmark */ = 94B7898910C4F95E005EA70D /* PBXTextBookmark */;
409
94B88C560E81500200C98131 /* PBXTextBookmark */ = 94B88C560E81500200C98131 /* PBXTextBookmark */;
410
94BCAD4A10AB981B00F87527 /* PBXTextBookmark */ = 94BCAD4A10AB981B00F87527 /* PBXTextBookmark */;
411
94BCAE9010ACA3A300F87527 /* PBXTextBookmark */ = 94BCAE9010ACA3A300F87527 /* PBXTextBookmark */;
412
94BCAFC710ACC89100F87527 /* PBXTextBookmark */ = 94BCAFC710ACC89100F87527 /* PBXTextBookmark */;
413
94BE8B9C123DA0C900C89FDD /* PBXTextBookmark */ = 94BE8B9C123DA0C900C89FDD /* PBXTextBookmark */;
414
94BE8BAD123DA0EB00C89FDD /* PBXTextBookmark */ = 94BE8BAD123DA0EB00C89FDD /* PBXTextBookmark */;
415
94BE8BD5123DA32300C89FDD /* PBXTextBookmark */ = 94BE8BD5123DA32300C89FDD /* PBXTextBookmark */;
416
94BE8BF5123DA42700C89FDD /* PBXTextBookmark */ = 94BE8BF5123DA42700C89FDD /* PBXTextBookmark */;
417
94C16B42123D72AE00A8622A /* PBXTextBookmark */ = 94C16B42123D72AE00A8622A /* PBXTextBookmark */;
418
94C16B43123D72AE00A8622A /* PBXTextBookmark */ = 94C16B43123D72AE00A8622A /* PBXTextBookmark */;
419
94C16B5A123D735F00A8622A /* PBXTextBookmark */ = 94C16B5A123D735F00A8622A /* PBXTextBookmark */;
420
94C2074310AF5FB7002F4160 /* PBXTextBookmark */ = 94C2074310AF5FB7002F4160 /* PBXTextBookmark */;
421
94C2091210AF7413002F4160 /* PBXTextBookmark */ = 94C2091210AF7413002F4160 /* PBXTextBookmark */;
422
94C2092A10AF769A002F4160 /* PBXTextBookmark */ = 94C2092A10AF769A002F4160 /* PBXTextBookmark */;
423
94C2092D10AF769A002F4160 /* PBXTextBookmark */ = 94C2092D10AF769A002F4160 /* PBXTextBookmark */;
424
94C367C010AF9C0A0041953A /* PBXTextBookmark */ = 94C367C010AF9C0A0041953A /* PBXTextBookmark */;
425
94C367C210AF9C0A0041953A /* PBXTextBookmark */ = 94C367C210AF9C0A0041953A /* PBXTextBookmark */;
426
94C367D110AF9C830041953A /* PBXTextBookmark */ = 94C367D110AF9C830041953A /* PBXTextBookmark */;
427
94C3696410AFB7550041953A /* PBXTextBookmark */ = 94C3696410AFB7550041953A /* PBXTextBookmark */;
428
94C3698D10B082DF0041953A /* PBXTextBookmark */ = 94C3698D10B082DF0041953A /* PBXTextBookmark */;
429
94C3699110B082DF0041953A /* PBXTextBookmark */ = 94C3699110B082DF0041953A /* PBXTextBookmark */;
430
94C3CD4E1235C80200A4E319 /* PBXTextBookmark */ = 94C3CD4E1235C80200A4E319 /* PBXTextBookmark */;
431
94C7480712333A2900B1F982 /* PBXTextBookmark */ = 94C7480712333A2900B1F982 /* PBXTextBookmark */;
432
94C887D410ADCC0D007CB39E /* PBXTextBookmark */ = 94C887D410ADCC0D007CB39E /* PBXTextBookmark */;
433
94C888B710ADE75B007CB39E /* PBXTextBookmark */ = 94C888B710ADE75B007CB39E /* PBXTextBookmark */;
434
94C88B6810AF26F8007CB39E /* PBXTextBookmark */ = 94C88B6810AF26F8007CB39E /* PBXTextBookmark */;
435
94C8D197123EDAD30019544B /* PBXTextBookmark */ = 94C8D197123EDAD30019544B /* PBXTextBookmark */;
436
94C8D19A123EDAD30019544B /* PBXTextBookmark */ = 94C8D19A123EDAD30019544B /* PBXTextBookmark */;
437
94C8D19B123EDAD30019544B /* PBXTextBookmark */ = 94C8D19B123EDAD30019544B /* PBXTextBookmark */;
438
94C8D19C123EDAD30019544B /* PBXTextBookmark */ = 94C8D19C123EDAD30019544B /* PBXTextBookmark */;
439
94CAE0ED1230DE6C00AFE487 /* PBXTextBookmark */ = 94CAE0ED1230DE6C00AFE487 /* PBXTextBookmark */;
440
94CFE6A910BE63A900847DF5 /* PBXTextBookmark */ = 94CFE6A910BE63A900847DF5 /* PBXTextBookmark */;
441
94CFE6B810BE63A900847DF5 /* PBXTextBookmark */ = 94CFE6B810BE63A900847DF5 /* PBXTextBookmark */;
442
94CFE6B910BE63A900847DF5 /* PBXTextBookmark */ = 94CFE6B910BE63A900847DF5 /* PBXTextBookmark */;
443
94CFE6C010BE63A900847DF5 /* PBXTextBookmark */ = 94CFE6C010BE63A900847DF5 /* PBXTextBookmark */;
444
94CFE70110BE683800847DF5 /* PBXTextBookmark */ = 94CFE70110BE683800847DF5 /* PBXTextBookmark */;
445
94D16BFC10BCEFEE00A69A89 /* PBXTextBookmark */ = 94D16BFC10BCEFEE00A69A89 /* PBXTextBookmark */;
446
94D16BFE10BCEFEE00A69A89 /* PBXTextBookmark */ = 94D16BFE10BCEFEE00A69A89 /* PBXTextBookmark */;
447
94D16C2A10BCF28A00A69A89 /* PBXTextBookmark */ = 94D16C2A10BCF28A00A69A89 /* PBXTextBookmark */;
448
94D16C4010BCF3E100A69A89 /* PBXTextBookmark */ = 94D16C4010BCF3E100A69A89 /* PBXTextBookmark */;
449
94D16CA310BCF93000A69A89 /* PBXTextBookmark */ = 94D16CA310BCF93000A69A89 /* PBXTextBookmark */;
450
94D3660B10CEE03900805023 /* PBXTextBookmark */ = 94D3660B10CEE03900805023 /* PBXTextBookmark */;
451
94D715CB10B723B200F69A71 /* PBXTextBookmark */ = 94D715CB10B723B200F69A71 /* PBXTextBookmark */;
452
94D7174110B72FDF00F69A71 /* PBXTextBookmark */ = 94D7174110B72FDF00F69A71 /* PBXTextBookmark */;
453
94D7177D10B73A3800F69A71 /* PBXTextBookmark */ = 94D7177D10B73A3800F69A71 /* PBXTextBookmark */;
454
94D7178410B73A3800F69A71 /* PBXTextBookmark */ = 94D7178410B73A3800F69A71 /* PBXTextBookmark */;
455
94D7178610B73A3800F69A71 /* PBXTextBookmark */ = 94D7178610B73A3800F69A71 /* PBXTextBookmark */;
456
94D7178810B73A3800F69A71 /* PBXTextBookmark */ = 94D7178810B73A3800F69A71 /* PBXTextBookmark */;
457
94D7178A10B73A3800F69A71 /* PBXTextBookmark */ = 94D7178A10B73A3800F69A71 /* PBXTextBookmark */;
458
94D7178C10B73A3800F69A71 /* PBXTextBookmark */ = 94D7178C10B73A3800F69A71 /* PBXTextBookmark */;
459
94D7179110B73A3800F69A71 /* PBXTextBookmark */ = 94D7179110B73A3800F69A71 /* PBXTextBookmark */;
460
94D717BE10B73DD900F69A71 /* PBXTextBookmark */ = 94D717BE10B73DD900F69A71 /* PBXTextBookmark */;
461
94D717F810B743B800F69A71 /* PBXTextBookmark */ = 94D717F810B743B800F69A71 /* PBXTextBookmark */;
462
94D7183810B74BF300F69A71 /* PBXTextBookmark */ = 94D7183810B74BF300F69A71 /* PBXTextBookmark */;
463
94D7183A10B74BF300F69A71 /* PBXTextBookmark */ = 94D7183A10B74BF300F69A71 /* PBXTextBookmark */;
464
94D73E5210B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E5210B5B9CE00F8C034 /* PBXTextBookmark */;
465
94D73E5410B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E5410B5B9CE00F8C034 /* PBXTextBookmark */;
466
94D73E5610B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E5610B5B9CE00F8C034 /* PBXTextBookmark */;
467
94D73E5810B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E5810B5B9CE00F8C034 /* PBXTextBookmark */;
468
94D73E5A10B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E5A10B5B9CE00F8C034 /* PBXTextBookmark */;
469
94D73E5C10B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E5C10B5B9CE00F8C034 /* PBXTextBookmark */;
470
94D73E5E10B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E5E10B5B9CE00F8C034 /* PBXTextBookmark */;
471
94D73E6010B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E6010B5B9CE00F8C034 /* PBXTextBookmark */;
472
94D73E6210B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E6210B5B9CE00F8C034 /* PBXTextBookmark */;
473
94D73E6410B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E6410B5B9CE00F8C034 /* PBXTextBookmark */;
474
94D73E6810B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E6810B5B9CE00F8C034 /* PBXTextBookmark */;
475
94D73E6A10B5B9CE00F8C034 /* PBXTextBookmark */ = 94D73E6A10B5B9CE00F8C034 /* PBXTextBookmark */;
476
94D73EE610B5CF8400F8C034 /* PBXTextBookmark */ = 94D73EE610B5CF8400F8C034 /* PBXTextBookmark */;
477
94D73F4910B5DA4E00F8C034 /* PBXTextBookmark */ = 94D73F4910B5DA4E00F8C034 /* PBXTextBookmark */;
478
94D73FA010B5E5A200F8C034 /* PBXTextBookmark */ = 94D73FA010B5E5A200F8C034 /* PBXTextBookmark */;
479
94D73FAD10B5E69900F8C034 /* PBXTextBookmark */ = 94D73FAD10B5E69900F8C034 /* PBXTextBookmark */;
480
94D73FB510B5E6DA00F8C034 /* PBXTextBookmark */ = 94D73FB510B5E6DA00F8C034 /* PBXTextBookmark */;
481
94D7401510B5F8AF00F8C034 /* PBXTextBookmark */ = 94D7401510B5F8AF00F8C034 /* PBXTextBookmark */;
482
94D7403810B5FDDB00F8C034 /* PBXTextBookmark */ = 94D7403810B5FDDB00F8C034 /* PBXTextBookmark */;
483
94D7403A10B5FDDB00F8C034 /* PBXTextBookmark */ = 94D7403A10B5FDDB00F8C034 /* PBXTextBookmark */;
484
94D740B210B6242000F8C034 /* PBXTextBookmark */ = 94D740B210B6242000F8C034 /* PBXTextBookmark */;
485
94E1BDAB11E5A9F400D5B92B /* PBXTextBookmark */ = 94E1BDAB11E5A9F400D5B92B /* PBXTextBookmark */;
486
94E297D10DECA72F009CF73A /* PBXTextBookmark */ = 94E297D10DECA72F009CF73A /* PBXTextBookmark */;
487
94E297D30DECA72F009CF73A /* PBXTextBookmark */ = 94E297D30DECA72F009CF73A /* PBXTextBookmark */;
488
94E297D50DECA72F009CF73A /* PBXTextBookmark */ = 94E297D50DECA72F009CF73A /* PBXTextBookmark */;
489
94E297D70DECA72F009CF73A /* PBXTextBookmark */ = 94E297D70DECA72F009CF73A /* PBXTextBookmark */;
490
94E2DAD40ED2351B00012E92 /* PBXTextBookmark */ = 94E2DAD40ED2351B00012E92 /* PBXTextBookmark */;
491
94E2DB270ED2355F00012E92 /* PBXTextBookmark */ = 94E2DB270ED2355F00012E92 /* PBXTextBookmark */;
492
94E4930310BD32D00011AC75 /* PBXTextBookmark */ = 94E4930310BD32D00011AC75 /* PBXTextBookmark */;
493
94E583DB10BF43970073FD63 /* PBXTextBookmark */ = 94E583DB10BF43970073FD63 /* PBXTextBookmark */;
494
94E584AE10BF6EE30073FD63 /* PBXTextBookmark */ = 94E584AE10BF6EE30073FD63 /* PBXTextBookmark */;
495
94E584FF10BF79AB0073FD63 /* PBXTextBookmark */ = 94E584FF10BF79AB0073FD63 /* PBXTextBookmark */;
496
94E5850010BF79AB0073FD63 /* PBXTextBookmark */ = 94E5850010BF79AB0073FD63 /* PBXTextBookmark */;
497
94E7F6B812373EB800A03A11 /* PBXTextBookmark */ = 94E7F6B812373EB800A03A11 /* PBXTextBookmark */;
498
94E8EEEA11C94D5D0049D853 /* PBXTextBookmark */ = 94E8EEEA11C94D5D0049D853 /* PBXTextBookmark */;
499
94E8FA3C12258ED500EECD29 /* PBXTextBookmark */ = 94E8FA3C12258ED500EECD29 /* PBXTextBookmark */;
500
94ED7EFA0E6C2ABE00F4DD03 /* PBXTextBookmark */ = 94ED7EFA0E6C2ABE00F4DD03 /* PBXTextBookmark */;
501
94EE1DAA11E57FAB00DC6E8C /* PBXTextBookmark */ = 94EE1DAA11E57FAB00DC6E8C /* PBXTextBookmark */;
502
94EF43151262BFC100817F37 /* PBXTextBookmark */ = 94EF43151262BFC100817F37 /* PBXTextBookmark */;
503
94F155570E83EA1F001657CE /* PBXTextBookmark */ = 94F155570E83EA1F001657CE /* PBXTextBookmark */;
504
94F155580E83EA1F001657CE /* PBXTextBookmark */ = 94F155580E83EA1F001657CE /* PBXTextBookmark */;
505
94F1F15C11EB8AB5004B3AE3 /* PBXTextBookmark */ = 94F1F15C11EB8AB5004B3AE3 /* PBXTextBookmark */;
506
94F1F5C910C30C22008DB9CF /* PBXTextBookmark */ = 94F1F5C910C30C22008DB9CF /* PBXTextBookmark */;
507
94F5C1870DF26EF200099B11 /* PBXTextBookmark */ = 94F5C1870DF26EF200099B11 /* PBXTextBookmark */;
508
94F5C25F0DF42C7600099B11 /* PBXTextBookmark */ = 94F5C25F0DF42C7600099B11 /* PBXTextBookmark */;
509
94F5C2600DF42C7600099B11 /* PBXTextBookmark */ = 94F5C2600DF42C7600099B11 /* PBXTextBookmark */;
510
94F5F29110BC518B00847EEE /* PBXTextBookmark */ = 94F5F29110BC518B00847EEE /* PBXTextBookmark */;
511
94F5F29210BC518B00847EEE /* PBXTextBookmark */ = 94F5F29210BC518B00847EEE /* PBXTextBookmark */;
512
94F5F29410BC518B00847EEE /* PBXTextBookmark */ = 94F5F29410BC518B00847EEE /* PBXTextBookmark */;
513
94F5F29510BC518B00847EEE /* PBXTextBookmark */ = 94F5F29510BC518B00847EEE /* PBXTextBookmark */;
514
94F5F2A810BC539700847EEE /* PBXTextBookmark */ = 94F5F2A810BC539700847EEE /* PBXTextBookmark */;
515
94F89AFE10B4997900556475 /* PBXTextBookmark */ = 94F89AFE10B4997900556475 /* PBXTextBookmark */;
516
94F89BDE10B4B77400556475 /* PBXTextBookmark */ = 94F89BDE10B4B77400556475 /* PBXTextBookmark */;
517
94F89BE010B4B77400556475 /* PBXTextBookmark */ = 94F89BE010B4B77400556475 /* PBXTextBookmark */;
518
94F89C9110B4C0B800556475 /* PBXTextBookmark */ = 94F89C9110B4C0B800556475 /* PBXTextBookmark */;
519
94F8E42E0DE6129D003F4F53 /* PBXTextBookmark */ = 94F8E42E0DE6129D003F4F53 /* PBXTextBookmark */;
520
94FE53951230323500BA17E1 /* PBXTextBookmark */ = 94FE53951230323500BA17E1 /* PBXTextBookmark */;
522
sourceControlManager = 9424FF420DDC8673009912BF /* Source Control */;
523
userBookmarkGroup = 94B8F4B910CF5BFF00F0DD6B /* PBXBookmarkGroup */;
524
userBuildSettings = {
527
29B97316FDCFA39411CA2CEA /* main.m */ = {
529
sepNavIntBoundsRect = "{{0, 0}, {1327, 728}}";
530
sepNavSelRange = "{1872, 0}";
531
sepNavVisRange = "{278, 1871}";
532
sepNavWindowFrame = "{{15, 15}, {694, 1008}}";
535
9400325B0DEF3936002FA1C4 /* sqDummyaio.h */ = {
537
sepNavIntBoundsRect = "{{0, 0}, {1208, 824}}";
538
sepNavSelRange = "{1850, 8}";
539
sepNavVisRange = "{0, 1878}";
540
sepNavWindowFrame = "{{483, 4}, {694, 1008}}";
543
9400325C0DEF3936002FA1C4 /* sqDummyaio.c */ = {
545
sepNavIntBoundsRect = "{{0, 0}, {1357, 1040}}";
546
sepNavSelRange = "{2139, 0}";
547
sepNavVisRange = "{2081, 171}";
548
sepNavWindowFrame = "{{483, -9}, {694, 1008}}";
551
940125A81228E3FC002883F0 /* PBXTextBookmark */ = {
552
isa = PBXTextBookmark;
553
fRef = 94845C211228E29F00BEB880 /* macvideo.cpp */;
554
name = "macvideo.cpp: 883";
561
9402DD5E10CE0C16005C2102 /* SqViewBitmapConversion.h */ = {
563
sepNavIntBoundsRect = "{{0, 0}, {2070, 1053}}";
564
sepNavSelRange = "{1161, 6}";
565
sepNavVisRange = "{0, 2416}";
566
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
569
9402DD5F10CE0C16005C2102 /* SqViewBitmapConversion.m */ = {
571
sepNavIntBoundsRect = "{{0, 0}, {2077, 3523}}";
572
sepNavSelRange = "{6138, 14}";
573
sepNavVisRange = "{6017, 1887}";
574
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
577
9402DD6F10CE0E91005C2102 /* SqViewClut.m */ = {
579
sepNavIntBoundsRect = "{{0, 0}, {1167, 1066}}";
580
sepNavSelRange = "{343, 0}";
581
sepNavVisRange = "{0, 2832}";
582
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
585
9402DDB610CE12A5005C2102 /* PBXTextBookmark */ = {
586
isa = PBXTextBookmark;
587
fRef = 9402DDB710CE12A5005C2102 /* SqView.h */;
588
name = "SqView.h: 50";
595
9402DDB710CE12A5005C2102 /* SqView.h */ = {
596
isa = PBXFileReference;
597
lastKnownFileType = sourcecode.c.h;
599
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/SqueakAppKit/SqView.h";
600
sourceTree = "<absolute>";
602
9402F2AE0F3F9BB900F3D637 /* PDColoredProgressView.h */ = {
604
sepNavIntBoundsRect = "{{0, 0}, {1215, 546}}";
605
sepNavSelRange = "{1081, 6}";
606
sepNavVisRange = "{31, 1299}";
609
9402F2AF0F3F9BB900F3D637 /* PDColoredProgressView.m */ = {
611
sepNavIntBoundsRect = "{{0, 0}, {964, 1547}}";
612
sepNavSelRange = "{3465, 0}";
613
sepNavVisRange = "{2282, 1236}";
614
sepNavWindowFrame = "{{204, 6}, {1346, 974}}";
617
9402F2C50F3F9C5600F3D637 /* drawing.m */ = {
619
sepNavIntBoundsRect = "{{0, 0}, {1492, 897}}";
620
sepNavSelRange = "{0, 0}";
621
sepNavVisRange = "{0, 1669}";
624
94059106122AFB60009939CE /* ucontext.h */ = {
625
isa = PBXFileReference;
626
lastKnownFileType = sourcecode.c.h;
628
path = /Developer/SDKs/MacOSX10.6.sdk/usr/include/ucontext.h;
629
sourceTree = "<absolute>";
631
94059113122AFF8C009939CE /* PBXTextBookmark */ = {
632
isa = PBXTextBookmark;
633
fRef = 94059106122AFB60009939CE /* ucontext.h */;
634
name = "ucontext.h: 42";
641
9406B4DF11EC314E002670B7 /* PBXTextBookmark */ = {
642
isa = PBXTextBookmark;
643
fRef = 9406B4E011EC314E002670B7 /* mach_time.h */;
644
name = "mach_time.h: 46";
651
9406B4E011EC314E002670B7 /* mach_time.h */ = {
652
isa = PBXFileReference;
653
lastKnownFileType = sourcecode.c.h;
655
path = /System/Library/Frameworks/Kernel.framework/Versions/A/Headers/mach/mach_time.h;
656
sourceTree = "<absolute>";
658
9406E7E210B663F4002F81F2 /* PBXTextBookmark */ = {
659
isa = PBXTextBookmark;
660
fRef = 94C36A6D10B091BB0041953A /* NSCursor.h */;
661
name = "NSCursor.h: 75";
668
9406E87110B66A74002F81F2 /* PBXTextBookmark */ = {
669
isa = PBXTextBookmark;
670
fRef = 9406E87210B66A74002F81F2 /* SqueakInterpreterEventSensor.h */;
671
name = "SqueakInterpreterEventSensor.h: 11";
678
9406E87210B66A74002F81F2 /* SqueakInterpreterEventSensor.h */ = {
679
isa = PBXFileReference;
680
lastKnownFileType = sourcecode.c.h;
681
name = SqueakInterpreterEventSensor.h;
682
path = "/Users/johnmci/Work In Progress/smalltalk/CocoaSqueakSource/Squeak/SqueakInterpreterEventSensor.h";
683
sourceTree = "<absolute>";
685
9406E87510B66A74002F81F2 /* SqueakInterpreterEventSensor.m */ = {
686
isa = PBXFileReference;
687
lastKnownFileType = sourcecode.c.objc;
688
name = SqueakInterpreterEventSensor.m;
689
path = "/Users/johnmci/Work In Progress/smalltalk/CocoaSqueakSource/Squeak/SqueakInterpreterEventSensor.m";
690
sourceTree = "<absolute>";
692
9406E87710B66A74002F81F2 /* SqViewEventSensor.m */ = {
693
isa = PBXFileReference;
694
lastKnownFileType = sourcecode.c.objc;
695
name = SqViewEventSensor.m;
696
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/SqueakAppKit/SqViewEventSensor.m";
697
sourceTree = "<absolute>";
699
9406E8CC10B67499002F81F2 /* PBXTextBookmark */ = {
700
isa = PBXTextBookmark;
701
fRef = 9406E8CD10B67499002F81F2 /* NSTextStorageScripting.h */;
702
name = "NSTextStorageScripting.h: 21";
709
9406E8CD10B67499002F81F2 /* NSTextStorageScripting.h */ = {
710
isa = PBXFileReference;
711
lastKnownFileType = sourcecode.c.h;
712
name = NSTextStorageScripting.h;
713
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSTextStorageScripting.h;
714
sourceTree = "<absolute>";
716
9406E8D110B67499002F81F2 /* NSRange.h */ = {
717
isa = PBXFileReference;
718
lastKnownFileType = sourcecode.c.h;
720
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSRange.h;
721
sourceTree = "<absolute>";
723
940CE8540DFCE2D200EBA91B /* SqueakUIController.h */ = {
725
sepNavIntBoundsRect = "{{0, 0}, {831, 754}}";
726
sepNavSelRange = "{95, 1688}";
727
sepNavVisRange = "{0, 1839}";
730
940CE8550DFCE2D200EBA91B /* SqueakUIController.m */ = {
732
sepNavIntBoundsRect = "{{0, 0}, {922, 1365}}";
733
sepNavSelRange = "{3914, 0}";
734
sepNavVisRange = "{2585, 1552}";
735
sepNavWindowFrame = "{{15, 49}, {1346, 974}}";
738
940E86A31220A8D200AAB6F5 /* PBXTextBookmark */ = {
739
isa = PBXTextBookmark;
740
fRef = 947E647910AA100900D3B69E /* SqueakOSXAppDelegate.h */;
741
name = "SqueakOSXAppDelegate.h: 49";
748
940E86EE1220AF3D00AAB6F5 /* PBXTextBookmark */ = {
749
isa = PBXTextBookmark;
750
fRef = 9424FF5B0DDCB1C7009912BF /* sqGnu.h */;
751
name = "sqGnu.h: 165";
758
9412CAE40E6C05EC00DB8625 /* sqSqueakInfoPlistInterface.h */ = {
760
sepNavIntBoundsRect = "{{0, 0}, {831, 749}}";
761
sepNavSelRange = "{2019, 23}";
762
sepNavVisRange = "{0, 2070}";
763
sepNavWindowFrame = "{{15, 8}, {1012, 1015}}";
766
9412CAE50E6C05EC00DB8625 /* sqSqueakInfoPlistInterface.m */ = {
768
sepNavIntBoundsRect = "{{0, 0}, {965, 887}}";
769
sepNavSelRange = "{1814, 43}";
770
sepNavVisRange = "{0, 2410}";
771
sepNavWindowFrame = "{{15, 8}, {1012, 1015}}";
774
941441FD10BC817D0088F8AC /* PBXTextBookmark */ = {
775
isa = PBXTextBookmark;
776
fRef = 941441FE10BC817D0088F8AC /* NSSavePanel.h */;
777
name = "NSSavePanel.h: 207";
784
941441FE10BC817D0088F8AC /* NSSavePanel.h */ = {
785
isa = PBXFileReference;
786
lastKnownFileType = sourcecode.c.h;
787
name = NSSavePanel.h;
788
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSSavePanel.h;
789
sourceTree = "<absolute>";
791
9414420010BC817D0088F8AC /* NSPanel.h */ = {
792
isa = PBXFileReference;
793
lastKnownFileType = sourcecode.c.h;
795
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSPanel.h;
796
sourceTree = "<absolute>";
798
9414420110BC817D0088F8AC /* PBXTextBookmark */ = {
799
isa = PBXTextBookmark;
800
fRef = 9414420210BC817D0088F8AC /* NSOpenPanel.h */;
801
name = "NSOpenPanel.h: 43";
808
9414420210BC817D0088F8AC /* NSOpenPanel.h */ = {
809
isa = PBXFileReference;
810
lastKnownFileType = sourcecode.c.h;
811
name = NSOpenPanel.h;
812
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSOpenPanel.h;
813
sourceTree = "<absolute>";
815
9415BF3F123065640067CD8E /* dtraceOperationsPerSecond.d */ = {
816
isa = PBXFileReference;
817
lastKnownFileType = sourcecode.dtrace;
818
name = dtraceOperationsPerSecond.d;
819
path = /Users/johnmci/Documents/Squeak3.8.0/platforms/iOS/vm/OSX/dtraceOperationsPerSecond.d;
820
sourceTree = "<absolute>";
822
9415C06312306B660067CD8E /* SqueakUIView.m:118 */ = {
823
isa = PBXFileBreakpoint;
827
continueAfterActions = 0;
829
delayBeforeContinue = 0;
830
fileReference = 949E5DB60DE3AB6A007388E0 /* SqueakUIView.m */;
831
functionName = "-drawImageUsingClip:";
836
modificationTime = 308445394.271715;
837
originalNumberOfMultipleMatches = 1;
840
9415C06512306B6F0067CD8E /* SqueakUIView.m:126 */ = {
841
isa = PBXFileBreakpoint;
845
continueAfterActions = 0;
847
delayBeforeContinue = 0;
848
fileReference = 949E5DB60DE3AB6A007388E0 /* SqueakUIView.m */;
849
functionName = "-drawThelayers";
854
modificationTime = 308445394.299481;
855
originalNumberOfMultipleMatches = 1;
858
9415C07412306BDD0067CD8E /* PBXTextBookmark */ = {
859
isa = PBXTextBookmark;
860
fRef = 9415BF3F123065640067CD8E /* dtraceOperationsPerSecond.d */;
861
name = "dtraceOperationsPerSecond.d: 1";
868
9415C11412306FCC0067CD8E /* sqiPhoneScreenAndWindow.m:63 */ = {
869
isa = PBXFileBreakpoint;
873
continueAfterActions = 0;
875
delayBeforeContinue = 0;
876
fileReference = 9452D7640E0452D3000AD792 /* sqiPhoneScreenAndWindow.m */;
877
functionName = "-ioForceDisplayUpdateActual";
882
modificationTime = 308445394.388573;
883
originalNumberOfMultipleMatches = 1;
886
941724420F36624C0031AF33 /* squeakProxy.m */ = {
888
sepNavIntBoundsRect = "{{0, 0}, {1167, 2431}}";
889
sepNavSelRange = "{1931, 11}";
890
sepNavVisRange = "{493, 2138}";
891
sepNavWindowFrame = "{{15, 49}, {1346, 974}}";
894
941724430F36624C0031AF33 /* squeakProxy.h */ = {
896
sepNavIntBoundsRect = "{{0, 0}, {1215, 1274}}";
897
sepNavSelRange = "{3018, 6}";
898
sepNavVisRange = "{2526, 1527}";
901
941A331D11E63E1A004796BA /* PBXTextBookmark */ = {
902
isa = PBXTextBookmark;
903
fRef = 941A331E11E63E1A004796BA /* ia64.c */;
904
name = "ia64.c: 7278";
911
941A331E11E63E1A004796BA /* ia64.c */ = {
912
isa = PBXFileReference;
913
lastKnownFileType = sourcecode.c.c;
915
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/config/ia64/ia64.c";
916
sourceTree = "<absolute>";
918
941A331F11E63E1A004796BA /* PBXTextBookmark */ = {
919
isa = PBXTextBookmark;
920
fRef = 941A332011E63E1A004796BA /* gatomic.c */;
921
name = "gatomic.c: 522";
928
941A332011E63E1A004796BA /* gatomic.c */ = {
929
isa = PBXFileReference;
930
lastKnownFileType = sourcecode.c.c;
932
path = "/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_devel_glib2-devel/work/glib-2.15.6/glib/gatomic.c";
933
sourceTree = "<absolute>";
935
941D1C9A0E696FC7005B77B3 /* Entitlements.plist */ = {
937
sepNavWindowFrame = "{{15, 166}, {1288, 857}}";
940
94210B280E956AC200C1A314 /* ObjectiveCPlugin.c */ = {
942
sepNavIntBoundsRect = "{{0, 0}, {838, 27248}}";
943
sepNavSelRange = "{53186, 9}";
944
sepNavVisRange = "{52405, 1628}";
945
sepNavWindowFrame = "{{710, 97}, {901, 833}}";
948
9421AB550FF1807D008F54E9 /* PBXTextBookmark */ = {
949
isa = PBXTextBookmark;
950
fRef = 949EFD7D0FF17FED00F540EB /* ObjectiveCPlugin.c */;
951
name = "ObjectiveCPlugin.c: 1";
958
94238E5E11E7B0EB004401BE /* PBXTextBookmark */ = {
959
isa = PBXTextBookmark;
960
fRef = 9452D5DA0E044A9D000AD792 /* sqMacV2Time.h */;
961
name = "sqMacV2Time.h: 6";
968
9424FF3E0DDC8654009912BF /* Squeak */ = {
974
autoAttachOnCrash = 1;
975
breakpointsEnabled = 0;
977
"PBXLSLaunchAction-0" = {
978
PBXLSLaunchAction = 0;
979
PBXLSLaunchStartAction = 1;
980
PBXLSLaunchStdioStyle = 2;
981
PBXLSLaunchStyle = 0;
982
class = PBXLSRunLaunchConfig;
985
displayName = "Executable Runner";
988
identifier = com.apple.Xcode.launch.runConfig;
990
startActionInfo = "";
993
customDataFormattersEnabled = 1;
994
dataTipCustomDataFormattersEnabled = 1;
995
dataTipShowTypeColumn = 1;
997
debuggerPlugin = GDBDebugging;
998
disassemblyDisplayState = 0;
999
dylibVariantSuffix = "";
1001
environmentEntries = (
1004
name = NSAutoreleaseHaltOnFreedObject;
1009
name = NSZombieEnabled;
1014
name = NSAutoreleaseFreedObjectCheckEnabled;
1018
executableSystemSymbolLevel = 0;
1019
executableUserSymbolLevel = 0;
1020
libgmallocEnabled = 0;
1025
sourceDirectories = (
1027
startupPath = "<<ProductDirectory>>";
1028
variableFormatDictionary = {
1113
"*buffer-short int-primitiveNSInvocationGetShortType" = 1;
1114
"_return_value-sqInt-primitiveNSInvocationGetShortType" = 1;
1115
"actually-void *-sqAllocateMemoryMac" = 2;
1116
"data-id-primitiveNSInvocationGetObjectType" = 1;
1117
"data-short int-primitiveNSInvocationGetShortType" = 1;
1118
"dateDifference-sqInt-convertToSqueakTime" = 1;
1119
"fileSize-off_t-sqAllocateMemoryMac" = 2;
1120
"integerValue-sqInt-positive32BitIntegerFor" = 1;
1121
"mFormatID-UInt32--[sqSqueakSoundCoreAudio snd_StartRecording:stereo:semaIndex:]" = 5;
1122
"possibleLocation-void *-sqAllocateMemoryMac" = 2;
1123
"returnValue-struct objc_object * volatile-primitivePerformSelector" = 2;
1124
"startOfAnonymousMemory-void *-sqAllocateMemoryMac" = 1;
1125
"startOfAnonymousMemoryPageSize-size_t-sqAllocateMemoryMac" = 1;
1126
"unsignedData-long long unsigned int-primitiveNSInvocationGetLongLongType" = 1;
1127
"what-long int--[SqueakProxy forwardInvocation:]" = 1;
1128
"why-int-aioPoll" = 1;
1131
9424FF420DDC8673009912BF /* Source Control */ = {
1132
isa = PBXSourceControlManager;
1133
fallbackIsa = XCSourceControlManager;
1135
scmConfiguration = {
1136
repositoryName = "http://svn.isqueak.org/";
1137
repositoryNamesForRoots = {
1142
9424FF430DDC8673009912BF /* Code sense */ = {
1143
isa = PBXCodeSenseManager;
1144
indexTemplatePath = "";
1146
9424FF5B0DDCB1C7009912BF /* sqGnu.h */ = {
1148
sepNavIntBoundsRect = "{{0, 0}, {1132, 2730}}";
1149
sepNavSelRange = "{10975, 0}";
1150
sepNavVisRange = "{9372, 2508}";
1151
sepNavWindowFrame = "{{15, 4}, {1194, 1019}}";
1154
9424FF5C0DDCB1C7009912BF /* sqMemoryAccess.h */ = {
1156
sepNavIntBoundsRect = "{{0, 0}, {1327, 2171}}";
1157
sepNavSelRange = "{2839, 0}";
1158
sepNavVisRange = "{0, 0}";
1159
sepNavWindowFrame = "{{15, 4}, {878, 1019}}";
1162
9424FF5D0DDCB1C7009912BF /* sq.h */ = {
1164
sepNavIntBoundsRect = "{{0, 0}, {1027, 6916}}";
1165
sepNavSelRange = "{18266, 35}";
1166
sepNavVisRange = "{17190, 2307}";
1167
sepNavWindowFrame = "{{73, 4}, {1326, 1010}}";
1170
9424FF5E0DDCB1C7009912BF /* sqNamedPrims.c */ = {
1172
sepNavIntBoundsRect = "{{0, 0}, {800, 6890}}";
1173
sepNavSelRange = "{660, 33}";
1174
sepNavVisRange = "{0, 1563}";
1175
sepNavWindowFrame = "{{15, 38}, {847, 985}}";
1178
9424FF600DDCB1C7009912BF /* sqVirtualMachine.c */ = {
1180
sepNavIntBoundsRect = "{{0, 0}, {1338, 6500}}";
1181
sepNavSelRange = "{14571, 22}";
1182
sepNavVisRange = "{13799, 1509}";
1185
9424FF610DDCB1C7009912BF /* sqVirtualMachine.h */ = {
1187
sepNavIntBoundsRect = "{{0, 0}, {1391, 3835}}";
1188
sepNavSelRange = "{6672, 30}";
1189
sepNavVisRange = "{5691, 1846}";
1190
sepNavWindowFrame = "{{15, 55}, {1438, 968}}";
1193
9424FF640DDCB1EF009912BF /* sqPlatformSpecific.h */ = {
1195
sepNavIntBoundsRect = "{{0, 0}, {1338, 2158}}";
1196
sepNavSelRange = "{3458, 89}";
1197
sepNavVisRange = "{2732, 1658}";
1198
sepNavWindowFrame = "{{38, 19}, {905, 983}}";
1201
9424FF650DDCB1EF009912BF /* config.h */ = {
1203
sepNavIntBoundsRect = "{{0, 0}, {1132, 2912}}";
1204
sepNavSelRange = "{3660, 0}";
1205
sepNavVisRange = "{3240, 1112}";
1206
sepNavWindowFrame = "{{38, 17}, {847, 985}}";
1209
9424FF660DDCB1EF009912BF /* sqConfig.h */ = {
1211
sepNavIntBoundsRect = "{{0, 0}, {1132, 807}}";
1212
sepNavSelRange = "{88, 25}";
1213
sepNavVisRange = "{0, 302}";
1214
sepNavWindowFrame = "{{15, 4}, {1385, 1024}}";
1217
9424FF670DDCB202009912BF /* sqMacV2Memory.c */ = {
1219
sepNavIntBoundsRect = "{{0, 0}, {1069, 2522}}";
1220
sepNavSelRange = "{2861, 16}";
1221
sepNavVisRange = "{2252, 1746}";
1222
sepNavWindowFrame = "{{497, 1}, {905, 983}}";
1225
9424FF680DDCB202009912BF /* sqMacV2Memory.h */ = {
1227
sepNavIntBoundsRect = "{{0, 0}, {1132, 820}}";
1228
sepNavSelRange = "{2075, 15}";
1229
sepNavVisRange = "{0, 2098}";
1230
sepNavWindowFrame = "{{15, 40}, {905, 983}}";
1233
9424FF710DDCB234009912BF /* macintoshextra.c */ = {
1235
sepNavIntBoundsRect = "{{0, 0}, {1338, 689}}";
1236
sepNavSelRange = "{235, 11}";
1237
sepNavVisRange = "{172, 1750}";
1238
sepNavWindowFrame = "{{539, 15}, {905, 983}}";
1241
9424FF720DDCB234009912BF /* macintoshextra.h */ = {
1243
sepNavIntBoundsRect = "{{0, 0}, {1036, 629}}";
1244
sepNavSelRange = "{183, 15}";
1245
sepNavVisRange = "{0, 198}";
1248
9424FF750DDCB271009912BF /* osExports.c */ = {
1250
sepNavIntBoundsRect = "{{0, 0}, {802, 587}}";
1251
sepNavSelRange = "{389, 0}";
1252
sepNavVisRange = "{0, 571}";
1255
9427E35512626DFB002DCA6D /* PBXTextBookmark */ = {
1256
isa = PBXTextBookmark;
1257
fRef = 94C2068910AF4F53002F4160 /* sqSqueakOSXNSView.m */;
1258
name = "sqSqueakOSXNSView.m: 293";
1265
9427E37B12626EE6002DCA6D /* PBXTextBookmark */ = {
1266
isa = PBXTextBookmark;
1267
fRef = 94638B260EAFB77B00A3F155 /* iPhone.changes */;
1268
name = "iPhone.changes: 134722";
1275
9427E3F612627C61002DCA6D /* PBXTextBookmark */ = {
1276
isa = PBXTextBookmark;
1277
fRef = 94C887FA10ADCEFC007CB39E /* sqSqueakOSXApplication+imageReadWrite.m */;
1278
name = "sqSqueakOSXApplication+imageReadWrite.m: 64";
1285
9427E3F812627C61002DCA6D /* PlistBookmark */ = {
1286
isa = PlistBookmark;
1287
fRef = 949AD14911E542E8006D6BF4 /* SqueakPureObjc-InfoCOG.plist */;
1288
fallbackIsa = PBXBookmark;
1291
CFBundleGetInfoString,
1293
name = "/Users/johnmci/Documents/Squeak3.8.0/platforms/iOS/vm/SqueakPureObjc-InfoCOG.plist";
1295
rLoc = 9223372036854775808;
1297
9427E3F912627C61002DCA6D /* PlistBookmark */ = {
1298
isa = PlistBookmark;
1299
fRef = 947E5F9F10A9FFA000D3B69E /* SqueakPureObjc-Info.plist */;
1300
fallbackIsa = PBXBookmark;
1303
SqueakUIFadeForFullScreenInSeconds,
1305
name = "/Users/johnmci/Documents/Squeak3.8.0/platforms/iOS/vm/SqueakPureObjc-Info.plist";
1307
rLoc = 9223372036854775808;
1309
9427E3FC12627C61002DCA6D /* Root.plist */ = {
1310
isa = PBXFileReference;
1311
lastKnownFileType = text.plist.xml;
1313
path = /Users/johnmci/Documents/Squeak3.8.0/platforms/iOS/vm/Settings.bundle/Root.plist;
1314
sourceTree = "<absolute>";
1316
9427E42E12627E6A002DCA6D /* sqSqueakIPhoneApplication+imageReadWrite.m:95 */ = {
1317
isa = PBXFileBreakpoint;
1320
breakpointStyle = 0;
1321
continueAfterActions = 0;
1323
delayBeforeContinue = 0;
1324
fileReference = 943001270E0D5D670040BB27 /* sqSqueakIPhoneApplication+imageReadWrite.m */;
1325
functionName = "-findImageViaBundleOrPreferences";
1330
modificationTime = 308445400.27705;
1331
originalNumberOfMultipleMatches = 1;
1334
9427E44B12628333002DCA6D /* PBXTextBookmark */ = {
1335
isa = PBXTextBookmark;
1336
fRef = 94F879900E6C0C7E00662DEA /* sqSqueakIPhoneInfoPlistInterface.m */;
1337
name = "sqSqueakIPhoneInfoPlistInterface.m: 56";
1344
9427E44C12628333002DCA6D /* PBXTextBookmark */ = {
1345
isa = PBXTextBookmark;
1346
fRef = 943001270E0D5D670040BB27 /* sqSqueakIPhoneApplication+imageReadWrite.m */;
1347
name = "sqSqueakIPhoneApplication+imageReadWrite.m: 54";
1354
9427E44D12628333002DCA6D /* PlistBookmark */ = {
1355
isa = PlistBookmark;
1356
fRef = 9427E3FC12627C61002DCA6D /* Root.plist */;
1357
fallbackIsa = PBXBookmark;
1360
PreferenceSpecifiers,
1364
name = /Users/johnmci/Documents/Squeak3.8.0/platforms/iOS/vm/Settings.bundle/Root.plist;
1366
rLoc = 9223372036854775808;
1368
9427E46212629AE3002DCA6D /* PBXBookmark */ = {
1370
fRef = 94F3A9690E6BFA7C00E0B12A /* Squeak.png */;
1372
9427E46312629AE3002DCA6D /* PlistBookmark */ = {
1373
isa = PlistBookmark;
1374
fRef = 94C36C9710B0CF290041953A /* Info-iPhone.plist */;
1375
fallbackIsa = PBXBookmark;
1378
UIFileSharingEnabled,
1380
name = "/Users/johnmci/Documents/Squeak3.8.0/platforms/iOS/vm/Info-iPhone.plist";
1382
rLoc = 9223372036854775808;
1384
9427E4D11262B997002DCA6D /* PBXTextBookmark */ = {
1385
isa = PBXTextBookmark;
1386
fRef = 9452D5DE0E044A9D000AD792 /* sqSqueakFileDirectoryInterface.m */;
1387
name = "sqSqueakFileDirectoryInterface.m: 140";
1394
9427E4D21262B997002DCA6D /* PBXTextBookmark */ = {
1395
isa = PBXTextBookmark;
1396
fRef = 94BCE7A60DDDF8F800F38F31 /* sqaio.h */;
1397
name = "sqaio.h: 95";
1404
942807EE1224862A0000DCFE /* PBXTextBookmark */ = {
1405
isa = PBXTextBookmark;
1406
fRef = 94584FD910F02378001401E7 /* sqMacExtendedClipboard.m */;
1407
name = "sqMacExtendedClipboard.m: 101";
1414
942807EF1224862A0000DCFE /* PBXTextBookmark */ = {
1415
isa = PBXTextBookmark;
1416
fRef = 945851EF10F03E60001401E7 /* sqMacExtendedClipboard.m */;
1417
name = "sqMacExtendedClipboard.m: 88";
1424
942807F01224862A0000DCFE /* PBXTextBookmark */ = {
1425
isa = PBXTextBookmark;
1426
fRef = 9458525510F04339001401E7 /* sqSqueakIPhoneClipboardAPI.m */;
1427
name = "sqSqueakIPhoneClipboardAPI.m: 17";
1434
9428BA9510BB440800DAD287 /* sqSqueakOSXClipboardAPI.h */ = {
1436
sepNavIntBoundsRect = "{{0, 0}, {1215, 623}}";
1437
sepNavSelRange = "{0, 1814}";
1438
sepNavVisRange = "{0, 1814}";
1439
sepNavWindowFrame = "{{15, 4}, {878, 1019}}";
1442
9428BA9610BB440800DAD287 /* sqSqueakOSXClipboardAPI.m */ = {
1444
sepNavIntBoundsRect = "{{0, 0}, {1215, 871}}";
1445
sepNavSelRange = "{2148, 13}";
1446
sepNavVisRange = "{787, 2052}";
1447
sepNavWindowFrame = "{{16, 4}, {878, 1019}}";
1450
9428BB0410BB478600DAD287 /* sqSqueakOSXApplication+clipboard.h */ = {
1452
sepNavIntBoundsRect = "{{0, 0}, {1215, 623}}";
1453
sepNavSelRange = "{184, 2018}";
1454
sepNavVisRange = "{0, 2202}";
1457
9428BB0510BB478600DAD287 /* sqSqueakOSXApplication+clipboard.m */ = {
1459
sepNavIntBoundsRect = "{{0, 0}, {1167, 1092}}";
1460
sepNavSelRange = "{2664, 37}";
1461
sepNavVisRange = "{1451, 2157}";
1462
sepNavWindowFrame = "{{15, 4}, {878, 1019}}";
1465
9428BBAD10BB50E200DAD287 /* PBXTextBookmark */ = {
1466
isa = PBXTextBookmark;
1467
fRef = 9428BBAE10BB50E200DAD287 /* sqUnixQuartz.m */;
1468
name = "sqUnixQuartz.m: 1028";
1475
9428BBAE10BB50E200DAD287 /* sqUnixQuartz.m */ = {
1476
isa = PBXFileReference;
1477
lastKnownFileType = sourcecode.c.objc;
1478
name = sqUnixQuartz.m;
1479
path = "/Users/johnmci/Documents/SqueakIA32ABIPlugin/platforms/unix/vm-display-Quartz/sqUnixQuartz.m";
1480
sourceTree = "<absolute>";
1482
9428BBE210BB565100DAD287 /* sqUnixQuartz.m */ = {
1483
isa = PBXFileReference;
1484
lastKnownFileType = sourcecode.c.objc;
1485
name = sqUnixQuartz.m;
1486
path = "/Users/johnmci/Documents/SqueakHydra/SqueakVMMAker/platforms/unix/vm-display-Quartz/zzz/sqUnixQuartz.m";
1487
sourceTree = "<absolute>";
1489
9428BBE510BB565100DAD287 /* NSPasteboard.h */ = {
1490
isa = PBXFileReference;
1491
lastKnownFileType = sourcecode.c.h;
1492
name = NSPasteboard.h;
1493
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSPasteboard.h;
1494
sourceTree = "<absolute>";
1496
9428BC5510BB74BF00DAD287 /* PBXTextBookmark */ = {
1497
isa = PBXTextBookmark;
1498
fRef = 94BCAFC410ACC89100F87527 /* string.h */;
1499
name = "string.h: 83";
1506
9428BC5710BB74BF00DAD287 /* PBXTextBookmark */ = {
1507
isa = PBXTextBookmark;
1508
fRef = 9428BBE510BB565100DAD287 /* NSPasteboard.h */;
1509
name = "NSPasteboard.h: 138";
1516
9428BF3810BBC2ED00DAD287 /* PBXTextBookmark */ = {
1517
isa = PBXTextBookmark;
1518
fRef = 94BCAC3710AB79DA00F87527 /* NSArray.h */;
1519
name = "NSArray.h: 91";
1526
9428BF4F10BBCAAC00DAD287 /* PBXTextBookmark */ = {
1527
isa = PBXTextBookmark;
1528
fRef = 94BCAC3C10AB79DA00F87527 /* NSDictionary.h */;
1529
name = "NSDictionary.h: 75";
1536
942ABD9410AA1F8E0086D908 /* CGGeometry.h */ = {
1537
isa = PBXFileReference;
1538
lastKnownFileType = sourcecode.c.h;
1539
name = CGGeometry.h;
1540
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGGeometry.h;
1541
sourceTree = "<absolute>";
1543
942ABE0910AA21270086D908 /* NSView.h */ = {
1544
isa = PBXFileReference;
1545
lastKnownFileType = sourcecode.c.h;
1547
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSView.h;
1548
sourceTree = "<absolute>";
1550
942ABEC510AA34820086D908 /* PBXTextBookmark */ = {
1551
isa = PBXTextBookmark;
1552
fRef = 942ABEC610AA34820086D908 /* sqMacHostWindow.h */;
1553
name = "sqMacHostWindow.h: 1";
1560
942ABEC610AA34820086D908 /* sqMacHostWindow.h */ = {
1561
isa = PBXFileReference;
1562
lastKnownFileType = sourcecode.c.h;
1563
name = sqMacHostWindow.h;
1564
path = "/Volumes/pm/Mail/IMAP-johnmci@smalltalkconsulting.com@imap.gmail.com/[Gmail]/Sent Mail.imapmbox/Attachments/2958644/8/sqMacHostWindow.h";
1565
sourceTree = "<absolute>";
1567
942B77300EA7E642004B266D /* interp.c */ = {
1568
isa = PBXFileReference;
1569
lastKnownFileType = sourcecode.c.c;
1571
path = "/Users/johnmci/Documents/Squeak/Squeak3.8.1-6747-basic#2/src32iPhone/vm/interp.c";
1572
sourceTree = "<absolute>";
1574
942B77330EA7E642004B266D /* PBXTextBookmark */ = {
1575
isa = PBXTextBookmark;
1576
fRef = 942B77340EA7E642004B266D /* sqWin32Prefs.c */;
1577
name = "sqWin32Prefs.c: 184";
1584
942B77340EA7E642004B266D /* sqWin32Prefs.c */ = {
1585
isa = PBXFileReference;
1586
lastKnownFileType = sourcecode.c.c;
1587
name = sqWin32Prefs.c;
1588
path = /Users/johnmci/Documents/SqueakHydra/platforms/win32/vm/sqWin32Prefs.c;
1589
sourceTree = "<absolute>";
1591
942B77380EA7E642004B266D /* PBXTextBookmark */ = {
1592
isa = PBXTextBookmark;
1593
fRef = 94554E6D0DF1171500FB176B /* sqWin32Window.c */;
1594
name = "sqWin32Window.c: 65";
1601
942B778B0EA7EF0B004B266D /* sqUnixX11.c */ = {
1602
isa = PBXFileReference;
1603
lastKnownFileType = sourcecode.c.c;
1605
path = "/Users/johnmci/Documents/SqueakQuicktimePlugin/platforms/unix/vm-display-X11/sqUnixX11.c";
1606
sourceTree = "<absolute>";
1608
942B779B0EA7F2E0004B266D /* PBXTextBookmark */ = {
1609
isa = PBXTextBookmark;
1610
fRef = 94554E640DF1171500FB176B /* sqUnixX11.c */;
1611
name = "sqUnixX11.c: 1316";
1618
942B779C0EA7F2E0004B266D /* PBXTextBookmark */ = {
1619
isa = PBXTextBookmark;
1620
fRef = 942B778B0EA7EF0B004B266D /* sqUnixX11.c */;
1621
name = "sqUnixX11.c: 1332";
1628
942B77B90EA800E1004B266D /* PBXTextBookmark */ = {
1629
isa = PBXTextBookmark;
1630
fRef = 942B77BA0EA800E1004B266D /* sqWin32Alloc.c */;
1631
name = "sqWin32Alloc.c: 55";
1638
942B77BA0EA800E1004B266D /* sqWin32Alloc.c */ = {
1639
isa = PBXFileReference;
1640
lastKnownFileType = sourcecode.c.c;
1641
name = sqWin32Alloc.c;
1642
path = /Users/johnmci/Documents/SqueakHydra/platforms/win32/vm/sqWin32Alloc.c;
1643
sourceTree = "<absolute>";
1645
942B77BB0EA800E1004B266D /* PBXTextBookmark */ = {
1646
isa = PBXTextBookmark;
1647
fRef = 942B77BC0EA800E1004B266D /* sqWin32Alloc.h */;
1648
name = "sqWin32Alloc.h: 15";
1655
942B77BC0EA800E1004B266D /* sqWin32Alloc.h */ = {
1656
isa = PBXFileReference;
1657
lastKnownFileType = sourcecode.c.h;
1658
name = sqWin32Alloc.h;
1659
path = /Users/johnmci/Documents/SqueakHydra/platforms/win32/vm/sqWin32Alloc.h;
1660
sourceTree = "<absolute>";
1662
942B77C00EA800E1004B266D /* PBXTextBookmark */ = {
1663
isa = PBXTextBookmark;
1664
fRef = 942B77300EA7E642004B266D /* interp.c */;
1665
name = "interp.c: 21810";
1672
942CF43710BFCD52008F9BB7 /* sqGnu.h */ = {
1673
isa = PBXFileReference;
1674
lastKnownFileType = sourcecode.c.h;
1676
path = /Volumes/px2/business/SqueakiPhone/SqueakObjCBasedForOSXAndIPhone/SqueakNoOGLIPhoneOSX/platforms/unix/vm/sqGnu.h;
1677
sourceTree = "<absolute>";
1679
942CF46B10BCE44B009BD905 /* NSWindowController.h */ = {
1680
isa = PBXFileReference;
1681
lastKnownFileType = sourcecode.c.h;
1682
name = NSWindowController.h;
1683
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSWindowController.h;
1684
sourceTree = "<absolute>";
1686
942F48FA123C1C0C002B05DF /* SqueakUIViewCALayer.h */ = {
1688
sepNavIntBoundsRect = "{{0, 0}, {838, 754}}";
1689
sepNavSelRange = "{0, 0}";
1690
sepNavVisRange = "{0, 2008}";
1693
942F48FB123C1C0C002B05DF /* SqueakUIViewCALayer.m */ = {
1695
sepNavIntBoundsRect = "{{0, 0}, {1440, 1651}}";
1696
sepNavSelRange = "{3940, 0}";
1697
sepNavVisRange = "{2106, 2714}";
1698
sepNavWindowFrame = "{{501, 9}, {1140, 1019}}";
1701
942F48FC123C1C0C002B05DF /* SqueakUIViewOpenGL.h */ = {
1703
sepNavIntBoundsRect = "{{0, 0}, {1123, 1092}}";
1704
sepNavSelRange = "{2817, 0}";
1705
sepNavVisRange = "{445, 2344}";
1706
sepNavWindowFrame = "{{15, 18}, {1170, 1005}}";
1709
942F48FD123C1C0C002B05DF /* SqueakUIViewOpenGL.m */ = {
1711
sepNavIntBoundsRect = "{{0, 0}, {943, 2691}}";
1712
sepNavSelRange = "{7522, 0}";
1713
sepNavVisRange = "{4086, 1804}";
1716
942F6FFC1102F5A300A0A349 /* NSNull.h */ = {
1717
isa = PBXFileReference;
1718
lastKnownFileType = sourcecode.c.h;
1720
path = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSNull.h;
1721
sourceTree = "<absolute>";
1723
942F75D10E0B67AD00848BF2 /* sqSqueakVmAndImagePathAPI.h */ = {
1725
sepNavIntBoundsRect = "{{0, 0}, {1169, 764}}";
1726
sepNavSelRange = "{1777, 0}";
1727
sepNavVisRange = "{0, 1781}";
1728
sepNavWindowFrame = "{{913, 18}, {694, 1008}}";
1731
942F75D20E0B67AD00848BF2 /* sqSqueakVmAndImagePathAPI.m */ = {
1733
sepNavIntBoundsRect = "{{0, 0}, {1338, 1053}}";
1734
sepNavSelRange = "{3050, 9}";
1735
sepNavVisRange = "{1935, 1304}";
1736
sepNavWindowFrame = "{{15, 8}, {1012, 1015}}";
1739
942F761B0E0B6B6100848BF2 /* sqSqueakIPhoneApplication.h */ = {
1741
sepNavIntBoundsRect = "{{0, 0}, {1167, 654}}";
1742
sepNavSelRange = "{1955, 0}";
1743
sepNavVisRange = "{0, 1955}";
1744
sepNavWindowFrame = "{{15, 4}, {1573, 1024}}";
1747
942F761C0E0B6B6100848BF2 /* sqSqueakIPhoneApplication.m */ = {
1749
sepNavIntBoundsRect = "{{0, 0}, {1338, 1014}}";
1750
sepNavSelRange = "{2308, 12}";
1751
sepNavVisRange = "{1439, 1670}";
1754
942F76310E0B6C7600848BF2 /* sqSqueakMainApplication+attributes.m */ = {
1756
sepNavIntBoundsRect = "{{0, 0}, {1338, 1287}}";
1757
sepNavSelRange = "{2326, 7}";
1758
sepNavVisRange = "{1642, 1332}";
1759
sepNavWindowFrame = "{{577, 27}, {997, 998}}";
1762
942F76350E0B6CEF00848BF2 /* sqSqueakIPhoneApplication+attributes.h */ = {
1764
sepNavIntBoundsRect = "{{0, 0}, {1167, 654}}";
1765
sepNavSelRange = "{1913, 14}";
1766
sepNavVisRange = "{0, 1953}";
1769
943001260E0D5D670040BB27 /* sqSqueakIPhoneApplication+imageReadWrite.h */ = {
1771
sepNavIntBoundsRect = "{{0, 0}, {1036, 652}}";
1772
sepNavSelRange = "{1819, 94}";
1773
sepNavVisRange = "{0, 1919}";
1774
sepNavWindowFrame = "{{337, 21}, {1288, 857}}";
1777
943001270E0D5D670040BB27 /* sqSqueakIPhoneApplication+imageReadWrite.m */ = {
1779
sepNavIntBoundsRect = "{{0, 0}, {1338, 1716}}";
1780
sepNavSelRange = "{2350, 0}";
1781
sepNavVisRange = "{3722, 1639}";
1782
sepNavWindowFrame = "{{38, 24}, {1017, 978}}";
1785
943001A30E0D600C0040BB27 /* sqSqueakIPhoneFileDirectoryInterface.h */ = {
1787
sepNavIntBoundsRect = "{{0, 0}, {1036, 652}}";
1788
sepNavSelRange = "{1810, 0}";
1789
sepNavVisRange = "{0, 1951}";
1792
943001A40E0D600C0040BB27 /* sqSqueakIPhoneFileDirectoryInterface.m */ = {
1794
sepNavIntBoundsRect = "{{0, 0}, {1338, 884}}";
1795
sepNavSelRange = "{2025, 19}";
1796
sepNavVisRange = "{1339, 1475}";
1797
sepNavWindowFrame = "{{38, 4}, {1274, 998}}";
1800
9430325510BD0B6D0045D33B /* PBXTextBookmark */ = {
1801
isa = PBXTextBookmark;
1802
fRef = 94BCAB0410AB6DC000F87527 /* NSApplication.h */;
1803
name = "NSApplication.h: 314";
1810
9430329A10BD103B0045D33B /* PBXTextBookmark */ = {
1811
isa = PBXTextBookmark;
1812
fRef = 94BCAF7D10ACC0D900F87527 /* NSPathUtilities.h */;
1813
name = "NSPathUtilities.h: 26";
1820
9430329B10BD103B0045D33B /* PBXTextBookmark */ = {
1821
isa = PBXTextBookmark;
1822
fRef = 94BCAC0310AB759300F87527 /* NSURL.h */;
1823
name = "NSURL.h: 36";
1830
943198450DDF4D9800EB8E60 /* sqUnixQuartz.m */ = {
1831
isa = PBXFileReference;
1832
lastKnownFileType = sourcecode.c.objc;
1833
name = sqUnixQuartz.m;
1834
path = "/Users/johnmci/Documents/SqueakHydra/platforms/unix/vm-display-Quartz/sqUnixQuartz.m";
1835
sourceTree = "<absolute>";
1837
94360A8C10E84CC90060221A /* NSException.h */ = {
1838
isa = PBXFileReference;
1839
lastKnownFileType = sourcecode.c.h;
1840
name = NSException.h;
1841
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSException.h;
1842
sourceTree = "<absolute>";
1844
943B9AF21235B94D0056205E /* sqSqueakOSXNSWindowController.m */ = {
1845
isa = PBXFileReference;
1847
lastKnownFileType = sourcecode.c.objc;
1848
name = sqSqueakOSXNSWindowController.m;
1849
path = /Users/johnmci/Documents/Squeak3.8.0/platforms/iOS/vm/OSX/sqSqueakOSXNSWindowController.m;
1850
sourceTree = "<absolute>";
1852
943B9AF71235B9FD0056205E /* sqSqueakOSXNSWindowController.m:18 */ = {
1853
isa = PBXFileBreakpoint;
1856
breakpointStyle = 0;
1857
continueAfterActions = 0;
1859
delayBeforeContinue = 0;
1860
fileReference = 943B9AF21235B94D0056205E /* sqSqueakOSXNSWindowController.m */;
1861
functionName = "-windowShouldClose:";
1865
modificationTime = 308445393.436679;
1866
originalNumberOfMultipleMatches = 1;
1869
943B9B151235BB080056205E /* PBXTextBookmark */ = {
1870
isa = PBXTextBookmark;
1871
fRef = 94C88BDD10AF3C52007CB39E /* sqSqueakOSXScreenAndWindow.h */;
1872
name = "sqSqueakOSXScreenAndWindow.h: 42";
1879
943B9B1E1235BD150056205E /* PBXTextBookmark */ = {
1880
isa = PBXTextBookmark;
1881
fRef = 94E658FA0DDD03FE00358328 /* HostWindowPlugin.c */;
1882
name = "HostWindowPlugin.c: 45";
1889
943B9B281235BDD20056205E /* sqMacHostWindow.m */ = {
1891
sepNavIntBoundsRect = "{{0, 0}, {1533, 2587}}";
1892
sepNavSelRange = "{2304, 11}";
1893
sepNavVisRange = "{1951, 552}";
1894
sepNavWindowFrame = "{{61, 7}, {1206, 974}}";
1897
943B9B291235BDD20056205E /* sqMacHostWindow.h */ = {
1899
sepNavIntBoundsRect = "{{0, 0}, {1338, 962}}";
1900
sepNavSelRange = "{7, 17}";
1901
sepNavVisRange = "{3, 717}";
1902
sepNavWindowFrame = "{{15, 49}, {1206, 974}}";
1905
943B9B9E1235BE580056205E /* sqMacHostWindow.m:58 */ = {
1906
isa = PBXFileBreakpoint;
1909
breakpointStyle = 0;
1910
continueAfterActions = 0;
1912
delayBeforeContinue = 0;
1913
fileReference = 943B9B281235BDD20056205E /* sqMacHostWindow.m */;
1917
modificationTime = 308445393.436735;
1918
originalNumberOfMultipleMatches = 1;
1921
943B9BD31235C1120056205E /* PBXTextBookmark */ = {
1922
isa = PBXTextBookmark;
1923
fRef = 94BCEA2B0DDE0C1600F38F31 /* sqMacHostWindow.c */;
1924
name = "sqMacHostWindow.c: 57";
1931
943B9BD41235C1120056205E /* PBXTextBookmark */ = {
1932
isa = PBXTextBookmark;
1933
fRef = 94BCE6660DDDEB5000F38F31 /* sqMacHostWindow.h */;
1934
name = "sqMacHostWindow.h: 26";
1941
943B9C041235C1EE0056205E /* PBXTextBookmark */ = {
1942
isa = PBXTextBookmark;
1943
fRef = 943B9B291235BDD20056205E /* sqMacHostWindow.h */;
1944
name = "sqMacHostWindow.h: 67";
1951
943B9C311235C3D70056205E /* PBXTextBookmark */ = {
1952
isa = PBXTextBookmark;
1953
fRef = 943B9B281235BDD20056205E /* sqMacHostWindow.m */;
1954
name = "sqMacHostWindow.m: 59";
1961
943B9C331235C3D70056205E /* PBXTextBookmark */ = {
1962
isa = PBXTextBookmark;
1963
fRef = 9471D2E00E04743F00703D45 /* sqSqueakAppDelegate.m */;
1964
name = "sqSqueakAppDelegate.m: 45";
1971
943B9D621235C79C0056205E /* PBXTextBookmark */ = {
1972
isa = PBXTextBookmark;
1973
fRef = 947E642710AA0E9E00D3B69E /* sqMacV2Browser.h */;
1974
name = "sqMacV2Browser.h: 1";
1981
943C0AC7122DF3710086B6AD /* PBXTextBookmark */ = {
1982
isa = PBXTextBookmark;
1983
fRef = 9402DD5E10CE0C16005C2102 /* SqViewBitmapConversion.h */;
1984
name = "SqViewBitmapConversion.h: 23";
1991
943C0AC8122DF3710086B6AD /* PBXTextBookmark */ = {
1992
isa = PBXTextBookmark;
1993
fRef = 94D3654E10CEC86C00805023 /* BitMapConversionLogicFromX11.c */;
1994
name = "BitMapConversionLogicFromX11.c: 42";
2001
943C0ACA122DF3710086B6AD /* PBXTextBookmark */ = {
2002
isa = PBXTextBookmark;
2003
fRef = 94D3654D10CEC86C00805023 /* BitMapConversionLogicFromX11.h */;
2004
name = "BitMapConversionLogicFromX11.h: 18";
2011
943C0AE0122DF5E70086B6AD /* PBXTextBookmark */ = {
2012
isa = PBXTextBookmark;
2013
fRef = 943C0AE1122DF5E70086B6AD /* nextdemo4.m */;
2014
name = "nextdemo4.m: 86";
2021
943C0AE1122DF5E70086B6AD /* nextdemo4.m */ = {
2022
isa = PBXFileReference;
2023
lastKnownFileType = sourcecode.c.objc;
2025
path = "/Users/johnmci/Work In Progress/stx/support/MESA/Mesa-3.0/OpenStep/Old_NeXT/nextdemo4.m";
2026
sourceTree = "<absolute>";
2028
943C0AE2122DF5E70086B6AD /* PBXTextBookmark */ = {
2029
isa = PBXTextBookmark;
2030
fRef = 943C0AE3122DF5E70086B6AD /* CGLMacro.h */;
2031
name = "CGLMacro.h: 35";
2038
943C0AE3122DF5E70086B6AD /* CGLMacro.h */ = {
2039
isa = PBXFileReference;
2040
lastKnownFileType = sourcecode.c.h;
2042
path = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/OpenGL.framework/Versions/A/Headers/CGLMacro.h;
2043
sourceTree = "<absolute>";
2045
943C0AE5122DF5E70086B6AD /* PBXTextBookmark */ = {
2046
isa = PBXTextBookmark;
2047
fRef = 943C0AE6122DF5E70086B6AD /* Texturing.m */;
2048
name = "Texturing.m: 14";
2055
943C0AE6122DF5E70086B6AD /* Texturing.m */ = {
2056
isa = PBXFileReference;
2057
lastKnownFileType = sourcecode.c.objc;
2059
path = "/Volumes/330GB Photos/WWDC10-SampleCode/Mac/LayerBackedOpenGLView/Texturing.m";
2060
sourceTree = "<absolute>";
2062
943C0AE7122DF5E70086B6AD /* PBXTextBookmark */ = {
2063
isa = PBXTextBookmark;
2064
fRef = 943C0AE8122DF5E70086B6AD /* NeonTexture.m */;
2065
name = "NeonTexture.m: 21";
2072
943C0AE8122DF5E70086B6AD /* NeonTexture.m */ = {
2073
isa = PBXFileReference;
2074
lastKnownFileType = sourcecode.c.objc;
2075
name = NeonTexture.m;
2076
path = "/Volumes/pm/Mail Downloads/iProPutt/NeonEngine/NeonTexture.m";
2077
sourceTree = "<absolute>";
2079
944069CD10E6B63200353B27 /* MacMenubarPlugin.c */ = {
2081
sepNavIntBoundsRect = "{{0, 0}, {1283, 22763}}";
2082
sepNavSelRange = "{0, 0}";
2083
sepNavVisRange = "{0, 902}";
2086
9441DB7111E6805300345F6C /* PBXTextBookmark */ = {
2087
isa = PBXTextBookmark;
2088
fRef = 9452D5D80E044A9D000AD792 /* Queue.m */;
2089
name = "Queue.m: 117";
2096
9441DB7211E6805300345F6C /* PBXTextBookmark */ = {
2097
isa = PBXTextBookmark;
2098
fRef = 946DA91410C0C71100F26F56 /* sqSqueakOSXDropAPI.m */;
2099
name = "sqSqueakOSXDropAPI.m: 53";
2106
9448940B10F3E8FF00FB3EC8 /* PBXTextBookmark */ = {
2107
isa = PBXTextBookmark;
2108
fRef = 943198450DDF4D9800EB8E60 /* sqUnixQuartz.m */;
2109
name = "sqUnixQuartz.m: 406";
2116
944895AD10F4081300FB3EC8 /* PharoV10.sources */ = {
2118
sepNavIntBoundsRect = "{{0, 0}, {1209, 3.55314e+06}}";
2119
sepNavSelRange = "{1830818, 7}";
2120
sepNavVisRange = "{1829163, 2429}";
2123
944F6D171224D7B300DFC0CD /* sqSqueakOSXApplication+imageReadWrite.m:64 */ = {
2124
isa = PBXFileBreakpoint;
2127
breakpointStyle = 0;
2128
continueAfterActions = 0;
2130
delayBeforeContinue = 0;
2131
fileReference = 94C887FA10ADCEFC007CB39E /* sqSqueakOSXApplication+imageReadWrite.m */;
2132
functionName = "-attempToOpenImageFromOpenPanel";
2136
modificationTime = 308445393.4364201;
2137
originalNumberOfMultipleMatches = 1;
2140
9451E64F123F0E9200B4119F /* PlistBookmark */ = {
2141
isa = PlistBookmark;
2142
fRef = 941D1C9A0E696FC7005B77B3 /* Entitlements.plist */;
2143
fallbackIsa = PBXBookmark;
2147
name = /Users/johnmci/Documents/Squeak3.8.0/platforms/iOS/vm/Entitlements.plist;
2149
rLoc = 9223372036854775808;
2151
9452BDC10F4095DE006410DE /* sqSqueakIPhoneApplication+Network.h */ = {
2153
sepNavIntBoundsRect = "{{0, 0}, {1036, 652}}";
2154
sepNavSelRange = "{409, 0}";
2155
sepNavVisRange = "{0, 562}";
2158
9452BDC20F4095DE006410DE /* sqSqueakIPhoneApplication+Network.m */ = {
2160
sepNavIntBoundsRect = "{{0, 0}, {1215, 845}}";
2161
sepNavSelRange = "{0, 0}";
2162
sepNavVisRange = "{0, 1067}";
2165
9452D5D70E044A9D000AD792 /* Queue.h */ = {
2167
sepNavIntBoundsRect = "{{0, 0}, {1283, 845}}";
2168
sepNavSelRange = "{2692, 0}";
2169
sepNavVisRange = "{1337, 1516}";
2170
sepNavWindowFrame = "{{15, 4}, {1593, 1019}}";
2173
9452D5D80E044A9D000AD792 /* Queue.m */ = {
2175
sepNavIntBoundsRect = "{{0, 0}, {970, 1612}}";
2176
sepNavSelRange = "{2961, 27}";
2177
sepNavVisRange = "{2763, 914}";
2178
sepNavWindowFrame = "{{38, 12}, {1017, 978}}";
2181
9452D5D90E044A9D000AD792 /* sqMacV2Time.c */ = {
2183
sepNavIntBoundsRect = "{{0, 0}, {1394, 2392}}";
2184
sepNavSelRange = "{3709, 1378}";
2185
sepNavVisRange = "{3710, 1377}";
2186
sepNavWindowFrame = "{{510, 30}, {1441, 887}}";
2189
9452D5DA0E044A9D000AD792 /* sqMacV2Time.h */ = {
2191
sepNavIntBoundsRect = "{{0, 0}, {1132, 762}}";
2192
sepNavSelRange = "{72, 0}";
2193
sepNavVisRange = "{0, 1791}";
2196
9452D5DB0E044A9D000AD792 /* sqSqueakFileDirectoryAPI.h */ = {
2198
sepNavIntBoundsRect = "{{0, 0}, {1368, 572}}";
2199
sepNavSelRange = "{1792, 10}";
2200
sepNavVisRange = "{3, 1942}";
2203
9452D5DC0E044A9D000AD792 /* sqSqueakFileDirectoryAPI.m */ = {
2205
sepNavIntBoundsRect = "{{0, 0}, {1167, 2691}}";
2206
sepNavSelRange = "{7520, 20}";
2207
sepNavVisRange = "{5747, 1848}";
2208
sepNavWindowFrame = "{{15, 43}, {1379, 980}}";
2211
9452D5DD0E044A9D000AD792 /* sqSqueakFileDirectoryInterface.h */ = {
2213
sepNavIntBoundsRect = "{{0, 0}, {1338, 1170}}";
2214
sepNavSelRange = "{2012, 19}";
2215
sepNavVisRange = "{1284, 1422}";
2216
sepNavWindowFrame = "{{909, 13}, {1012, 1015}}";
2219
9452D5DE0E044A9D000AD792 /* sqSqueakFileDirectoryInterface.m */ = {
2221
sepNavIntBoundsRect = "{{0, 0}, {1076, 4108}}";
2222
sepNavSelRange = "{4849, 37}";
2223
sepNavVisRange = "{3923, 2369}";
2224
sepNavWindowFrame = "{{101, 4}, {1064, 1024}}";
2227
9452D5DF0E044A9D000AD792 /* sqSqueakMainApp.m */ = {
2229
sepNavIntBoundsRect = "{{0, 0}, {1327, 2210}}";
2230
sepNavSelRange = "{3692, 0}";
2231
sepNavVisRange = "{3261, 489}";
2234
9452D5E00E044A9D000AD792 /* sqSqueakMainApp.h */ = {
2236
sepNavIntBoundsRect = "{{0, 0}, {936, 741}}";
2237
sepNavSelRange = "{1322, 449}";
2238
sepNavVisRange = "{0, 1868}";
2241
9452D5E10E044A9D000AD792 /* sqSqueakMainApplication+vmAndImagePath.h */ = {
2243
sepNavIntBoundsRect = "{{0, 0}, {850, 778}}";
2244
sepNavSelRange = "{2087, 0}";
2245
sepNavVisRange = "{0, 2202}";
2246
sepNavWindowFrame = "{{15, 15}, {694, 1008}}";
2249
9452D5E20E044A9D000AD792 /* sqSqueakMainApplication+vmAndImagePath.m */ = {
2251
sepNavIntBoundsRect = "{{0, 0}, {1338, 1378}}";
2252
sepNavSelRange = "{2343, 37}";
2253
sepNavVisRange = "{1830, 1334}";
2254
sepNavWindowFrame = "{{15, 15}, {694, 1008}}";
2257
9452D5E30E044A9D000AD792 /* sqSqueakMainApplication.h */ = {
2259
sepNavIntBoundsRect = "{{0, 0}, {1338, 1157}}";
2260
sepNavSelRange = "{3075, 23}";
2261
sepNavVisRange = "{2009, 1532}";
2262
sepNavWindowFrame = "{{888, 14}, {694, 1008}}";
2265
9452D5E40E044A9D000AD792 /* sqSqueakMainApplication.m */ = {
2267
sepNavIntBoundsRect = "{{0, 0}, {1338, 3094}}";
2268
sepNavSelRange = "{4926, 259}";
2269
sepNavVisRange = "{4926, 701}";
2270
sepNavWindowFrame = "{{685, 38}, {905, 983}}";
2273
9452D6010E044CB3000AD792 /* sqSqueakAttributesAPI.h */ = {
2275
sepNavIntBoundsRect = "{{0, 0}, {936, 766}}";
2276
sepNavSelRange = "{88, 1700}";
2277
sepNavVisRange = "{0, 1790}";
2280
9452D6020E044CB3000AD792 /* sqSqueakAttributesAPI.m */ = {
2282
sepNavIntBoundsRect = "{{0, 0}, {1338, 754}}";
2283
sepNavSelRange = "{2248, 12}";
2284
sepNavVisRange = "{776, 1571}";
2287
9452D6060E044D2F000AD792 /* sqSqueakEventsAPI.h */ = {
2289
sepNavIntBoundsRect = "{{0, 0}, {1036, 652}}";
2290
sepNavSelRange = "{78, 0}";
2291
sepNavVisRange = "{0, 1785}";
2294
9452D6070E044D2F000AD792 /* sqSqueakEventsAPI.m */ = {
2296
sepNavIntBoundsRect = "{{0, 0}, {1538, 1118}}";
2297
sepNavSelRange = "{2380, 11}";
2298
sepNavVisRange = "{1887, 1135}";
2299
sepNavWindowFrame = "{{668, 4}, {1012, 1015}}";
2302
9452D7630E0452D3000AD792 /* sqiPhoneScreenAndWindow.h */ = {
2304
sepNavIntBoundsRect = "{{0, 0}, {838, 606}}";
2305
sepNavSelRange = "{1909, 23}";
2306
sepNavVisRange = "{0, 1943}";
2307
sepNavWindowFrame = "{{15, 50}, {1346, 974}}";
2310
9452D7640E0452D3000AD792 /* sqiPhoneScreenAndWindow.m */ = {
2312
sepNavIntBoundsRect = "{{0, 0}, {838, 871}}";
2313
sepNavSelRange = "{0, 0}";
2314
sepNavVisRange = "{0, 2225}";
2315
sepNavWindowFrame = "{{802, 9}, {878, 1019}}";
2318
9453F58A1234AF8A00C91CF7 /* PBXTextBookmark */ = {
2319
isa = PBXTextBookmark;
2320
fRef = 9453F58B1234AF8A00C91CF7 /* SqueakView.m */;
2321
name = "SqueakView.m: 57";
2328
9453F58B1234AF8A00C91CF7 /* SqueakView.m */ = {
2329
isa = PBXFileReference;
2330
lastKnownFileType = sourcecode.c.objc;
2331
name = SqueakView.m;
2332
path = "/Users/johnmci/Documents/SqueakHydraZBaseCheck/HydraVM-src/platforms/unix/vm-display-Quartz/SqueakView.m";
2333
sourceTree = "<absolute>";
2335
9453F58C1234AF8A00C91CF7 /* PBXTextBookmark */ = {
2336
isa = PBXTextBookmark;
2337
fRef = 94B88C540E81500200C98131 /* SqView.m */;
2338
name = "SqView.m: 409";
2345
9453F58D1234AF8A00C91CF7 /* PBXTextBookmark */ = {
2346
isa = PBXTextBookmark;
2347
fRef = 9453F58E1234AF8A00C91CF7 /* sqUnixQuartz.m */;
2348
name = "sqUnixQuartz.m: 1989";
2355
9453F58E1234AF8A00C91CF7 /* sqUnixQuartz.m */ = {
2356
isa = PBXFileReference;
2357
lastKnownFileType = sourcecode.c.objc;
2358
name = sqUnixQuartz.m;
2359
path = "/Users/johnmci/Documents/SqueakSpellingPlugin/platforms/unix/vm-display-Quartz/zzz/sqUnixQuartz.m";
2360
sourceTree = "<absolute>";
2362
9453F5911234AF8A00C91CF7 /* PBXTextBookmark */ = {
2363
isa = PBXTextBookmark;
2364
fRef = 9453F5921234AF8A00C91CF7 /* sqUnixQuartz.m */;
2365
name = "sqUnixQuartz.m: 155";
2372
9453F5921234AF8A00C91CF7 /* sqUnixQuartz.m */ = {
2373
isa = PBXFileReference;
2374
lastKnownFileType = sourcecode.c.objc;
2375
name = sqUnixQuartz.m;
2376
path = "/Volumes/330GB Photos/Cog Before Aug 2010 changes/platforms/unix/vm-display-Quartz/zzz/sqUnixQuartz.m";
2377
sourceTree = "<absolute>";
2379
9453F5931234AF8A00C91CF7 /* PBXTextBookmark */ = {
2380
isa = PBXTextBookmark;
2381
fRef = 9453F5941234AF8A00C91CF7 /* image.c */;
2382
name = "image.c: 1511";
2389
9453F5941234AF8A00C91CF7 /* image.c */ = {
2390
isa = PBXFileReference;
2391
lastKnownFileType = sourcecode.c.c;
2393
path = "/Users/johnmci/Work In Progress/stx/support/MESA/Mesa-3.0/src/image.c";
2394
sourceTree = "<absolute>";
2396
9453F5951234AF8A00C91CF7 /* PBXTextBookmark */ = {
2397
isa = PBXTextBookmark;
2398
fRef = 9453F5961234AF8A00C91CF7 /* OpenGLScreenReader.m */;
2399
name = "OpenGLScreenReader.m: 22";
2406
9453F5961234AF8A00C91CF7 /* OpenGLScreenReader.m */ = {
2407
isa = PBXFileReference;
2408
lastKnownFileType = sourcecode.c.objc;
2409
name = OpenGLScreenReader.m;
2410
path = "/Volumes/330GB Photos/WWDC10-SampleCode/Mac/OpenGLScreenSnapshot/OpenGLScreenReader.m";
2411
sourceTree = "<absolute>";
2413
94547F160DE0AC7D00DD588F /* PBXTextBookmark */ = {
2414
isa = PBXTextBookmark;
2415
fRef = 94547F170DE0AC7D00DD588F /* sqMacMain.c */;
2416
name = "sqMacMain.c: 486";
2423
94547F170DE0AC7D00DD588F /* sqMacMain.c */ = {
2424
isa = PBXFileReference;
2425
lastKnownFileType = sourcecode.c.c;
2427
path = "/Users/johnmci/Documents/SqueakHydra/platforms/Mac OS/vm/sqMacMain.c";
2428
sourceTree = "<absolute>";
2430
9454809B0DE2945300DD588F /* sqMacUnixFileInterface.c */ = {
2431
isa = PBXFileReference;
2432
lastKnownFileType = sourcecode.c.c;
2433
name = sqMacUnixFileInterface.c;
2434
path = "/Users/johnmci/Documents/SqueakHydra/platforms/Mac OS/plugins/FilePlugin/sqMacUnixFileInterface.c";
2435
sourceTree = "<absolute>";
2437
945481A60DE2A79200DD588F /* PBXTextBookmark */ = {
2438
isa = PBXTextBookmark;
2439
fRef = 9454809B0DE2945300DD588F /* sqMacUnixFileInterface.c */;
2440
name = "sqMacUnixFileInterface.c: 512";
2447
94554E640DF1171500FB176B /* sqUnixX11.c */ = {
2448
isa = PBXFileReference;
2449
lastKnownFileType = sourcecode.c.c;
2451
path = "/Users/johnmci/Documents/SqueakSpellingPlugin/platforms/unix/vm-display-X11/sqUnixX11.c";
2452
sourceTree = "<absolute>";
2454
94554E670DF1171500FB176B /* PBXTextBookmark */ = {
2455
isa = PBXTextBookmark;
2456
fRef = 94554E680DF1171500FB176B /* sqUnixX11.c */;
2457
name = "sqUnixX11.c: 2319";
2464
94554E680DF1171500FB176B /* sqUnixX11.c */ = {
2465
isa = PBXFileReference;
2466
lastKnownFileType = sourcecode.c.c;
2468
path = "/Users/johnmci/Documents/SqueakServicesPlugin/platforms/unix/vm-display-X11/sqUnixX11.c";
2469
sourceTree = "<absolute>";
2471
94554E690DF1171500FB176B /* PBXTextBookmark */ = {
2472
isa = PBXTextBookmark;
2473
fRef = 94554E6A0DF1171500FB176B /* sqMacWindow.c */;
2474
name = "sqMacWindow.c: 797";
2481
94554E6A0DF1171500FB176B /* sqMacWindow.c */ = {
2482
isa = PBXFileReference;
2483
lastKnownFileType = sourcecode.c.c;
2484
name = sqMacWindow.c;
2485
path = "/Users/johnmci/Documents/SqueakServicesPlugin/platforms/Mac OS/vm/sqMacWindow.c";
2486
sourceTree = "<absolute>";
2488
94554E6D0DF1171500FB176B /* sqWin32Window.c */ = {
2489
isa = PBXFileReference;
2490
lastKnownFileType = sourcecode.c.c;
2491
name = sqWin32Window.c;
2492
path = /Users/johnmci/Documents/SqueakServicesPlugin/platforms/win32/vm/sqWin32Window.c;
2493
sourceTree = "<absolute>";
2495
94554E7F0DF1171500FB176B /* sqUnixMain.c */ = {
2496
isa = PBXFileReference;
2497
lastKnownFileType = sourcecode.c.c;
2498
name = sqUnixMain.c;
2499
path = /Users/johnmci/Documents/SqueakHydra/SqueakVMMAker/platforms/unix/vm/sqUnixMain.c;
2500
sourceTree = "<absolute>";
2502
94554EB80DF1A86A00FB176B /* PBXTextBookmark */ = {
2503
isa = PBXTextBookmark;
2504
fRef = 94554E7F0DF1171500FB176B /* sqUnixMain.c */;
2505
name = "sqUnixMain.c: 526";
2512
94554F1D0DF1B65700FB176B /* sqSqueakIPhoneApplication+sound.h */ = {
2514
sepNavIntBoundsRect = "{{0, 0}, {1338, 572}}";
2515
sepNavSelRange = "{1902, 6}";
2516
sepNavVisRange = "{3, 1912}";
2517
sepNavWindowFrame = "{{15, 22}, {1064, 1001}}";
2520
94554F1E0DF1B65700FB176B /* sqSqueakiPhoneApplication+sound.m */ = {
2522
sepNavIntBoundsRect = "{{0, 0}, {1338, 1001}}";
2523
sepNavSelRange = "{2882, 22}";
2524
sepNavVisRange = "{1657, 1632}";
2527
9456C24F10B2F268000BF3DE /* PBXTextBookmark */ = {
2528
isa = PBXTextBookmark;
2529
fRef = 942ABD9410AA1F8E0086D908 /* CGGeometry.h */;
2530
name = "CGGeometry.h: 29";
2537
9456C25A10B2F2C9000BF3DE /* PBXTextBookmark */ = {
2538
isa = PBXTextBookmark;
2539
fRef = 9456C25B10B2F2C9000BF3DE /* types.h */;
2540
name = "types.h: 83";
2547
9456C25B10B2F2C9000BF3DE /* types.h */ = {
2548
isa = PBXFileReference;
2549
lastKnownFileType = sourcecode.c.h;
2551
path = /Developer/SDKs/MacOSX10.6.sdk/usr/include/i386/types.h;
2552
sourceTree = "<absolute>";
2554
9456C2F910B32D2A000BF3DE /* NSString.h */ = {
2555
isa = PBXFileReference;
2556
lastKnownFileType = sourcecode.c.h;
2558
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSString.h;
2559
sourceTree = "<absolute>";
2561
9456C32210B32F43000BF3DE /* PBXTextBookmark */ = {
2562
isa = PBXTextBookmark;
2563
fRef = 9456C32310B32F43000BF3DE /* NSClipView.h */;
2564
name = "NSClipView.h: 22";
2571
9456C32310B32F43000BF3DE /* NSClipView.h */ = {
2572
isa = PBXFileReference;
2573
lastKnownFileType = sourcecode.c.h;
2574
name = NSClipView.h;
2575
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSClipView.h;
2576
sourceTree = "<absolute>";
2578
9456C34E10B33618000BF3DE /* PBXTextBookmark */ = {
2579
isa = PBXTextBookmark;
2580
fRef = 9456C34F10B33618000BF3DE /* CALayer.h */;
2581
name = "CALayer.h: 169";
2588
9456C34F10B33618000BF3DE /* CALayer.h */ = {
2589
isa = PBXFileReference;
2590
lastKnownFileType = sourcecode.c.h;
2592
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/QuartzCore.framework/Versions/A/Headers/CALayer.h;
2593
sourceTree = "<absolute>";
2595
9456C3CB10B341F9000BF3DE /* PBXTextBookmark */ = {
2596
isa = PBXTextBookmark;
2597
fRef = 9456C3CC10B341F9000BF3DE /* NSAffineTransform.h */;
2598
name = "NSAffineTransform.h: 39";
2605
9456C3CC10B341F9000BF3DE /* NSAffineTransform.h */ = {
2606
isa = PBXFileReference;
2607
lastKnownFileType = sourcecode.c.h;
2608
name = NSAffineTransform.h;
2609
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSAffineTransform.h;
2610
sourceTree = "<absolute>";
2612
94584F6110F020BD001401E7 /* ClipboardExtendedPlugin.c */ = {
2614
sepNavIntBoundsRect = "{{0, 0}, {1283, 3107}}";
2615
sepNavSelRange = "{4263, 0}";
2616
sepNavVisRange = "{3941, 851}";
2619
94584FD910F02378001401E7 /* sqMacExtendedClipboard.m */ = {
2621
sepNavIntBoundsRect = "{{0, 0}, {1132, 1469}}";
2622
sepNavSelRange = "{3679, 40}";
2623
sepNavVisRange = "{1736, 2397}";
2624
sepNavWindowFrame = "{{242, 4}, {1438, 968}}";
2627
94584FDA10F02378001401E7 /* sqMacExtendedClipboard.h */ = {
2629
sepNavIntBoundsRect = "{{0, 0}, {1357, 507}}";
2630
sepNavSelRange = "{1388, 0}";
2631
sepNavVisRange = "{336, 1542}";
2632
sepNavWindowFrame = "{{15, 55}, {1438, 968}}";
2635
9458511410F03996001401E7 /* sqMacExtendedClipboard.m:101 */ = {
2636
isa = PBXFileBreakpoint;
2639
breakpointStyle = 0;
2640
continueAfterActions = 0;
2642
delayBeforeContinue = 0;
2643
fileReference = 94584FD910F02378001401E7 /* sqMacExtendedClipboard.m */;
2644
functionName = "sqPasteboardCopyItemFlavorDataformatformatLength()";
2649
modificationTime = 308445393.435976;
2650
originalNumberOfMultipleMatches = 1;
2653
945851EE10F03E60001401E7 /* sqMacExtendedClipboard.h */ = {
2655
sepNavIntBoundsRect = "{{0, 0}, {1331, 873}}";
2656
sepNavSelRange = "{7, 24}";
2657
sepNavVisRange = "{0, 1878}";
2658
sepNavWindowFrame = "{{15, 4}, {1378, 1024}}";
2661
945851EF10F03E60001401E7 /* sqMacExtendedClipboard.m */ = {
2663
sepNavIntBoundsRect = "{{0, 0}, {1132, 1352}}";
2664
sepNavSelRange = "{3036, 111}";
2665
sepNavVisRange = "{1524, 2240}";
2666
sepNavWindowFrame = "{{61, 13}, {1438, 968}}";
2669
9458523210F040A0001401E7 /* sqMacExtendedClipboard.m:37 */ = {
2670
isa = PBXFileBreakpoint;
2673
breakpointStyle = 0;
2674
continueAfterActions = 0;
2676
delayBeforeContinue = 0;
2677
fileReference = 945851EF10F03E60001401E7 /* sqMacExtendedClipboard.m */;
2682
modificationTime = 308445393.842733;
2683
originalNumberOfMultipleMatches = 1;
2686
9458523410F040A1001401E7 /* sqMacExtendedClipboard.m:45 */ = {
2687
isa = PBXFileBreakpoint;
2690
breakpointStyle = 0;
2691
continueAfterActions = 0;
2693
delayBeforeContinue = 0;
2694
fileReference = 945851EF10F03E60001401E7 /* sqMacExtendedClipboard.m */;
2699
modificationTime = 308445393.890903;
2700
originalNumberOfMultipleMatches = 1;
2703
9458523610F040A2001401E7 /* sqMacExtendedClipboard.m:50 */ = {
2704
isa = PBXFileBreakpoint;
2707
breakpointStyle = 0;
2708
continueAfterActions = 0;
2710
delayBeforeContinue = 0;
2711
fileReference = 945851EF10F03E60001401E7 /* sqMacExtendedClipboard.m */;
2716
modificationTime = 308445393.953986;
2717
originalNumberOfMultipleMatches = 1;
2720
9458523A10F040AF001401E7 /* sqMacExtendedClipboard.m:72 */ = {
2721
isa = PBXFileBreakpoint;
2724
breakpointStyle = 0;
2725
continueAfterActions = 0;
2727
delayBeforeContinue = 0;
2728
fileReference = 945851EF10F03E60001401E7 /* sqMacExtendedClipboard.m */;
2733
modificationTime = 308445393.982063;
2734
originalNumberOfMultipleMatches = 1;
2737
9458524810F04272001401E7 /* sqMacExtendedClipboard.m:88 */ = {
2738
isa = PBXFileBreakpoint;
2741
breakpointStyle = 0;
2742
continueAfterActions = 0;
2744
delayBeforeContinue = 0;
2745
fileReference = 945851EF10F03E60001401E7 /* sqMacExtendedClipboard.m */;
2750
modificationTime = 308445394.050499;
2751
originalNumberOfMultipleMatches = 1;
2754
9458525410F04339001401E7 /* sqSqueakIPhoneClipboardAPI.h */ = {
2756
sepNavIntBoundsRect = "{{0, 0}, {1109, 769}}";
2757
sepNavSelRange = "{58, 44}";
2758
sepNavVisRange = "{0, 1817}";
2761
9458525510F04339001401E7 /* sqSqueakIPhoneClipboardAPI.m */ = {
2763
sepNavIntBoundsRect = "{{0, 0}, {1377, 808}}";
2764
sepNavSelRange = "{398, 28}";
2765
sepNavVisRange = "{0, 1345}";
2768
9458525A10F043EB001401E7 /* sqSqueakIPhoneApplication+clipboard.h */ = {
2770
sepNavIntBoundsRect = "{{0, 0}, {1357, 624}}";
2771
sepNavSelRange = "{1956, 0}";
2772
sepNavVisRange = "{799, 1415}";
2775
9458525B10F043EB001401E7 /* sqSqueakIPhoneApplication+clipboard.m */ = {
2777
sepNavIntBoundsRect = "{{0, 0}, {1167, 654}}";
2778
sepNavSelRange = "{695, 37}";
2779
sepNavVisRange = "{0, 1522}";
2782
9458527F10F045FB001401E7 /* sqSqueakIPhoneClipboardAPI.m:31 */ = {
2783
isa = PBXFileBreakpoint;
2786
breakpointStyle = 0;
2787
continueAfterActions = 0;
2789
delayBeforeContinue = 0;
2790
fileReference = 9458525510F04339001401E7 /* sqSqueakIPhoneClipboardAPI.m */;
2795
modificationTime = 308445394.104406;
2796
originalNumberOfMultipleMatches = 1;
2799
9458528110F045FC001401E7 /* sqSqueakIPhoneClipboardAPI.m:24 */ = {
2800
isa = PBXFileBreakpoint;
2803
breakpointStyle = 0;
2804
continueAfterActions = 0;
2806
delayBeforeContinue = 0;
2807
fileReference = 9458525510F04339001401E7 /* sqSqueakIPhoneClipboardAPI.m */;
2812
modificationTime = 308445394.164388;
2813
originalNumberOfMultipleMatches = 1;
2816
9458528310F045FD001401E7 /* sqSqueakIPhoneClipboardAPI.m:17 */ = {
2817
isa = PBXFileBreakpoint;
2820
breakpointStyle = 0;
2821
continueAfterActions = 0;
2823
delayBeforeContinue = 0;
2824
fileReference = 9458525510F04339001401E7 /* sqSqueakIPhoneClipboardAPI.m */;
2829
modificationTime = 308445394.211606;
2830
originalNumberOfMultipleMatches = 1;
2833
945BA53B10B218F700C2020C /* math.h */ = {
2834
isa = PBXFileReference;
2835
lastKnownFileType = sourcecode.c.h;
2837
path = /Developer/SDKs/MacOSX10.6.sdk/usr/include/architecture/i386/math.h;
2838
sourceTree = "<absolute>";
2840
945C4D7C10BB0A8500548CC1 /* PBXTextBookmark */ = {
2841
isa = PBXTextBookmark;
2842
fRef = 945C4D7D10BB0A8500548CC1 /* OSTypes.h */;
2843
name = "OSTypes.h: 73";
2850
945C4D7D10BB0A8500548CC1 /* OSTypes.h */ = {
2851
isa = PBXFileReference;
2852
lastKnownFileType = sourcecode.c.h;
2854
path = /Developer/SDKs/MacOSX10.6.sdk/usr/include/libkern/OSTypes.h;
2855
sourceTree = "<absolute>";
2857
945C4EAC10BB348300548CC1 /* PBXTextBookmark */ = {
2858
isa = PBXTextBookmark;
2859
fRef = 94BCAAE810AB6C3500F87527 /* NSFileManager.h */;
2860
name = "NSFileManager.h: 162";
2867
945E9D7C0DE525E100CDF01E /* PBXTextBookmark */ = {
2868
isa = PBXTextBookmark;
2869
fRef = 945E9D7D0DE525E100CDF01E /* npsqueak.c */;
2870
name = "npsqueak.c: 1113";
2877
945E9D7D0DE525E100CDF01E /* npsqueak.c */ = {
2878
isa = PBXFileReference;
2879
lastKnownFileType = sourcecode.c.c;
2881
path = "/Users/johnmci/Documents/SqueakBrowserPlugin/platforms/Mac OS/vm/npsqueak/npsqueak.c";
2882
sourceTree = "<absolute>";
2884
945F30620E0C6A5000CFF3DC /* SqueakApplication.m */ = {
2885
isa = PBXFileReference;
2886
lastKnownFileType = sourcecode.c.objc;
2887
name = SqueakApplication.m;
2888
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/CocoaSqueak/SqueakApplication.m";
2889
sourceTree = "<absolute>";
2891
945F30670E0C6A5000CFF3DC /* SqueakInterpreter.m */ = {
2892
isa = PBXFileReference;
2893
lastKnownFileType = sourcecode.c.objc;
2894
name = SqueakInterpreter.m;
2895
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/Squeak/SqueakInterpreter.m";
2896
sourceTree = "<absolute>";
2898
945F30FC0E0C763800CFF3DC /* PBXTextBookmark */ = {
2899
isa = PBXTextBookmark;
2900
fRef = 945F30670E0C6A5000CFF3DC /* SqueakInterpreter.m */;
2901
name = "SqueakInterpreter.m: 200";
2908
94638B260EAFB77B00A3F155 /* iPhone.changes */ = {
2910
sepNavIntBoundsRect = "{{0, 0}, {1533, 1.75974e+06}}";
2911
sepNavSelRange = "{5549550, 0}";
2912
sepNavVisRange = "{6141, 671}";
2915
94638CEA0EB16F1100A3F155 /* PBXTextBookmark */ = {
2916
isa = PBXTextBookmark;
2917
fRef = 94638CEB0EB16F1100A3F155 /* unxMapMemory.h */;
2918
name = "unxMapMemory.h: 270";
2925
94638CEB0EB16F1100A3F155 /* unxMapMemory.h */ = {
2926
isa = PBXFileReference;
2927
lastKnownFileType = sourcecode.c.h;
2928
name = unxMapMemory.h;
2929
path = "/Users/johnmci/Work In Progress/cincom/VWSourceCode/bkup621/src-51.4/plat/unxMapMemory.h";
2930
sourceTree = "<absolute>";
2932
94638CF50EB16F1100A3F155 /* sqUnixMemory.c */ = {
2933
isa = PBXFileReference;
2934
lastKnownFileType = sourcecode.c.c;
2935
name = sqUnixMemory.c;
2936
path = /Users/johnmci/Documents/SqueakHydra/platforms/unix/vm/sqUnixMemory.c;
2937
sourceTree = "<absolute>";
2939
9463943D0E95845000015851 /* squeakSUnitTester.h */ = {
2941
sepNavIntBoundsRect = "{{0, 0}, {1219, 2646}}";
2942
sepNavSelRange = "{0, 0}";
2943
sepNavVisRange = "{0, 1036}";
2946
9463943E0E95845000015851 /* squeakSUnitTester.m */ = {
2948
sepNavIntBoundsRect = "{{0, 0}, {1215, 6762}}";
2949
sepNavSelRange = "{4085, 11}";
2950
sepNavVisRange = "{3547, 944}";
2953
9468DA7511EC31F6000ECA16 /* main time.c */ = {
2954
isa = PBXFileReference;
2955
lastKnownFileType = sourcecode.c.c;
2956
name = "main time.c";
2957
path = "/Users/johnmci/Documents/temp/time_foobar/main time.c";
2958
sourceTree = "<absolute>";
2960
946C240C1230A80A004938A1 /* PBXTextBookmark */ = {
2961
isa = PBXTextBookmark;
2962
fRef = 9471D2DF0E04743F00703D45 /* sqSqueakAppDelegate.h */;
2963
name = "sqSqueakAppDelegate.h: 55";
2970
946D973B0FE165B70038846B /* PBXTextBookmark */ = {
2971
isa = PBXTextBookmark;
2972
fRef = 946D973C0FE165B70038846B /* sqSqueakEventsAPI.m */;
2973
name = "sqSqueakEventsAPI.m: 1";
2980
946D973C0FE165B70038846B /* sqSqueakEventsAPI.m */ = {
2981
isa = PBXFileReference;
2982
lastKnownFileType = sourcecode.c.objc;
2983
name = sqSqueakEventsAPI.m;
2984
path = "/Volumes/px2/business/SqueakiPhone/SqueakObjCBasedForOSXAndIPhone/WikiWikiServer/platforms/Mac OSObjC/vm/Common/Classes/sqSqueakEventsAPI.m";
2985
sourceTree = "<absolute>";
2987
946DA77210C09A8C00F26F56 /* sqUnixQuartz.m */ = {
2988
isa = PBXFileReference;
2989
lastKnownFileType = sourcecode.c.objc;
2990
name = sqUnixQuartz.m;
2991
path = "/Users/johnmci/Documents/SqueakPrintJobPlugin/platforms/unix/vm-display-Quartz/sqUnixQuartz.m";
2992
sourceTree = "<absolute>";
2994
946DA7D710C0A6C700F26F56 /* NSWindow.h */ = {
2995
isa = PBXFileReference;
2996
lastKnownFileType = sourcecode.c.h;
2998
path = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSWindow.h;
2999
sourceTree = "<absolute>";
3001
946DA7E010C0A7A400F26F56 /* PBXTextBookmark */ = {
3002
isa = PBXTextBookmark;
3003
fRef = 946DA7E110C0A7A400F26F56 /* NSView.h */;
3004
name = "NSView.h: 327";
3011
946DA7E110C0A7A400F26F56 /* NSView.h */ = {
3012
isa = PBXFileReference;
3013
lastKnownFileType = sourcecode.c.h;
3015
path = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSView.h;
3016
sourceTree = "<absolute>";
3018
946DA8D210C0C30D00F26F56 /* DropPlugin.c */ = {
3020
sepNavIntBoundsRect = "{{0, 0}, {1283, 2496}}";
3021
sepNavSelRange = "{2324, 0}";
3022
sepNavVisRange = "{1835, 1278}";
3023
sepNavWindowFrame = "{{254, 4}, {1426, 1019}}";
3026
946DA8D910C0C32800F26F56 /* PBXTextBookmark */ = {
3027
isa = PBXTextBookmark;
3028
fRef = 946DA7D710C0A6C700F26F56 /* NSWindow.h */;
3029
name = "NSWindow.h: 580";
3036
946DA8DA10C0C32800F26F56 /* PBXTextBookmark */ = {
3037
isa = PBXTextBookmark;
3038
fRef = 946DA77210C09A8C00F26F56 /* sqUnixQuartz.m */;
3039
name = "sqUnixQuartz.m: 2093";
3046
946DA8DB10C0C32800F26F56 /* PBXTextBookmark */ = {
3047
isa = PBXTextBookmark;
3048
fRef = 946DA8DC10C0C32800F26F56 /* NSDragging.h */;
3049
name = "NSDragging.h: 56";
3056
946DA8DC10C0C32800F26F56 /* NSDragging.h */ = {
3057
isa = PBXFileReference;
3058
lastKnownFileType = sourcecode.c.h;
3059
name = NSDragging.h;
3060
path = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSDragging.h;
3061
sourceTree = "<absolute>";
3063
946DA8EF10C0C38600F26F56 /* DropPlugin.h */ = {
3065
sepNavIntBoundsRect = "{{0, 0}, {1357, 169}}";
3066
sepNavSelRange = "{300, 21}";
3067
sepNavVisRange = "{0, 490}";
3070
946DA91310C0C71100F26F56 /* sqSqueakOSXDropAPI.h */ = {
3072
sepNavIntBoundsRect = "{{0, 0}, {1357, 507}}";
3073
sepNavSelRange = "{7, 20}";
3074
sepNavVisRange = "{0, 400}";
3077
946DA91410C0C71100F26F56 /* sqSqueakOSXDropAPI.m */ = {
3079
sepNavIntBoundsRect = "{{0, 0}, {1338, 1027}}";
3080
sepNavSelRange = "{2218, 8}";
3081
sepNavVisRange = "{1320, 1285}";
3082
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
3085
946DA9FF10C0D35500F26F56 /* sqMacUnixExternalPrims.m */ = {
3087
sepNavIntBoundsRect = "{{0, 0}, {1338, 4056}}";
3088
sepNavSelRange = "{2314, 23}";
3089
sepNavVisRange = "{1497, 1319}";
3090
sepNavWindowFrame = "{{15, 4}, {1426, 1019}}";
3093
946DAA3810C0D8B700F26F56 /* PBXTextBookmark */ = {
3094
isa = PBXTextBookmark;
3095
fRef = 946DAA3910C0D8B700F26F56 /* sqUnixMain.c */;
3096
name = "sqUnixMain.c: 709";
3103
946DAA3910C0D8B700F26F56 /* sqUnixMain.c */ = {
3104
isa = PBXFileReference;
3105
lastKnownFileType = sourcecode.c.c;
3106
name = sqUnixMain.c;
3107
path = /Users/johnmci/Documents/SqueakExuperyPlugin/platforms/unix/vm/sqUnixMain.c;
3108
sourceTree = "<absolute>";
3110
946DAA3A10C0D8B700F26F56 /* PBXTextBookmark */ = {
3111
isa = PBXTextBookmark;
3112
fRef = 946DAA3B10C0D8B700F26F56 /* sqMacMain.c */;
3113
name = "sqMacMain.c: 473";
3120
946DAA3B10C0D8B700F26F56 /* sqMacMain.c */ = {
3121
isa = PBXFileReference;
3122
lastKnownFileType = sourcecode.c.c;
3124
path = "/Users/johnmci/Documents/SqueakExuperyPlugin/platforms/Mac OS/vm/sqMacMain.c";
3125
sourceTree = "<absolute>";
3127
946DAA3C10C0D8B700F26F56 /* PBXTextBookmark */ = {
3128
isa = PBXTextBookmark;
3129
fRef = 946DAA3D10C0D8B700F26F56 /* sqUnixExternalPrims.c */;
3130
name = "sqUnixExternalPrims.c: 1";
3137
946DAA3D10C0D8B700F26F56 /* sqUnixExternalPrims.c */ = {
3138
isa = PBXFileReference;
3139
lastKnownFileType = sourcecode.c.c;
3140
name = sqUnixExternalPrims.c;
3141
path = "/Users/johnmci/Documents/SqueakHydraZBaseCheck/HydraVM-src/platforms/unix/vm/sqUnixExternalPrims.c";
3142
sourceTree = "<absolute>";
3144
94700A50123DF62D00874318 /* PBXTextBookmark */ = {
3145
isa = PBXTextBookmark;
3146
fRef = 942F761C0E0B6B6100848BF2 /* sqSqueakIPhoneApplication.m */;
3147
name = "sqSqueakIPhoneApplication.m: 43";
3154
94700A51123DF62D00874318 /* PBXTextBookmark */ = {
3155
isa = PBXTextBookmark;
3156
fRef = 94A0E8450DE5EB6E0071C8B9 /* sqSqueakIPhoneApplication+attributes.m */;
3157
name = "sqSqueakIPhoneApplication+attributes.m: 102";
3164
94700AAD123DFCEA00874318 /* PBXTextBookmark */ = {
3165
isa = PBXTextBookmark;
3166
fRef = 1D3623240D0F684500981E51 /* SqueakNoOGLIPhoneAppDelegate.h */;
3167
name = "SqueakNoOGLIPhoneAppDelegate.h: 60";
3174
9471D2710E04703B00703D45 /* sqSqueakScreenAndWindow.h */ = {
3176
sepNavIntBoundsRect = "{{0, 0}, {1299, 988}}";
3177
sepNavSelRange = "{1903, 56}";
3178
sepNavVisRange = "{446, 2520}";
3179
sepNavWindowFrame = "{{15, 49}, {1346, 974}}";
3182
9471D2720E04703B00703D45 /* sqSqueakScreenAndWindow.m */ = {
3184
sepNavIntBoundsRect = "{{0, 0}, {1496, 2678}}";
3185
sepNavSelRange = "{3533, 13}";
3186
sepNavVisRange = "{2713, 1763}";
3187
sepNavWindowFrame = "{{496, 9}, {1131, 1019}}";
3190
9471D2DF0E04743F00703D45 /* sqSqueakAppDelegate.h */ = {
3192
sepNavIntBoundsRect = "{{0, 0}, {1331, 896}}";
3193
sepNavSelRange = "{2271, 12}";
3194
sepNavVisRange = "{0, 2324}";
3195
sepNavWindowFrame = "{{15, 4}, {1378, 1024}}";
3198
9471D2E00E04743F00703D45 /* sqSqueakAppDelegate.m */ = {
3200
sepNavIntBoundsRect = "{{0, 0}, {1338, 1482}}";
3201
sepNavSelRange = "{2932, 32}";
3202
sepNavVisRange = "{2325, 1128}";
3203
sepNavWindowFrame = "{{264, 7}, {1416, 1021}}";
3206
947332EE0EA70E8C003F9084 /* PBXTextBookmark */ = {
3207
isa = PBXTextBookmark;
3208
fRef = 947332EF0EA70E8C003F9084 /* sqWin32Stubs.c */;
3209
name = "sqWin32Stubs.c: 18";
3216
947332EF0EA70E8C003F9084 /* sqWin32Stubs.c */ = {
3217
isa = PBXFileReference;
3218
lastKnownFileType = sourcecode.c.c;
3219
name = sqWin32Stubs.c;
3220
path = /Users/johnmci/Documents/SqueakHydra/platforms/win32/vm/sqWin32Stubs.c;
3221
sourceTree = "<absolute>";
3223
9473A34810BBD84100ED7D00 /* PBXTextBookmark */ = {
3224
isa = PBXTextBookmark;
3225
fRef = 94BCACE310AB8AE300F87527 /* NSObject.h */;
3226
name = "NSObject.h: 74";
3233
9473A95A1102F70B00D135CB /* PBXTextBookmark */ = {
3234
isa = PBXTextBookmark;
3235
fRef = 942F6FFC1102F5A300A0A349 /* NSNull.h */;
3236
name = "NSNull.h: 9";
3243
9473A9701103BE0A00D135CB /* PBXTextBookmark */ = {
3244
isa = PBXTextBookmark;
3245
fRef = 942CF43710BFCD52008F9BB7 /* sqGnu.h */;
3246
name = "sqGnu.h: 187";
3253
9475A83511E6B5D50010FB38 /* PBXTextBookmark */ = {
3254
isa = PBXTextBookmark;
3255
fRef = 9478E02B0EC8D957007096A7 /* squeakSUnitTester.m */;
3256
name = "squeakSUnitTester.m: 126";
3263
9475F4DB10BEF4100047A24B /* PBXTextBookmark */ = {
3264
isa = PBXTextBookmark;
3265
fRef = 94E4936F10BD39E20011AC75 /* sqUnixQuartz.m */;
3266
name = "sqUnixQuartz.m: 2177";
3273
9475F56B10BF20A00047A24B /* PBXTextBookmark */ = {
3274
isa = PBXTextBookmark;
3275
fRef = 9475F56C10BF20A00047A24B /* AudioQueue.h */;
3276
name = "AudioQueue.h: 1116";
3283
9475F56C10BF20A00047A24B /* AudioQueue.h */ = {
3284
isa = PBXFileReference;
3285
lastKnownFileType = sourcecode.c.h;
3286
name = AudioQueue.h;
3287
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AudioToolbox.framework/Versions/A/Headers/AudioQueue.h;
3288
sourceTree = "<absolute>";
3290
9475F58210BF227D0047A24B /* NSApplication.h */ = {
3291
isa = PBXFileReference;
3292
lastKnownFileType = sourcecode.c.h;
3293
name = NSApplication.h;
3294
path = /System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSApplication.h;
3295
sourceTree = "<absolute>";
3297
9475F5A710BF25A10047A24B /* PBXTextBookmark */ = {
3298
isa = PBXTextBookmark;
3299
fRef = 9475F58210BF227D0047A24B /* NSApplication.h */;
3300
name = "NSApplication.h: 18";
3307
947713C410C45DD700890A9B /* NSDebug.h */ = {
3308
isa = PBXFileReference;
3309
lastKnownFileType = sourcecode.c.h;
3311
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDebug.h;
3312
sourceTree = "<absolute>";
3314
947713D410C45E5F00890A9B /* PBXTextBookmark */ = {
3315
isa = PBXTextBookmark;
3316
fRef = 947713C410C45DD700890A9B /* NSDebug.h */;
3317
name = "NSDebug.h: 53";
3324
9478E0250EC8D957007096A7 /* dummyFFI.c */ = {
3326
sepNavIntBoundsRect = "{{0, 0}, {1283, 2652}}";
3327
sepNavSelRange = "{3356, 8}";
3328
sepNavVisRange = "{2987, 642}";
3331
9478E0260EC8D957007096A7 /* dummyFFI.h */ = {
3333
sepNavIntBoundsRect = "{{0, 0}, {899, 548}}";
3334
sepNavSelRange = "{0, 0}";
3335
sepNavVisRange = "{0, 1760}";
3336
sepNavWindowFrame = "{{15, 166}, {1288, 857}}";
3339
9478E02A0EC8D957007096A7 /* squeakSUnitTester.h */ = {
3341
sepNavIntBoundsRect = "{{0, 0}, {964, 2535}}";
3342
sepNavSelRange = "{1808, 17}";
3343
sepNavVisRange = "{0, 2274}";
3346
9478E02B0EC8D957007096A7 /* squeakSUnitTester.m */ = {
3348
sepNavIntBoundsRect = "{{0, 0}, {1327, 6136}}";
3349
sepNavSelRange = "{3608, 0}";
3350
sepNavVisRange = "{2696, 1348}";
3353
9478E0320EC8D98F007096A7 /* sqSqueakSoundCoreAudioAPI.h */ = {
3355
sepNavIntBoundsRect = "{{0, 0}, {1109, 720}}";
3356
sepNavSelRange = "{103, 1666}";
3357
sepNavVisRange = "{0, 1809}";
3360
9478E0330EC8D98F007096A7 /* sqSqueakSoundCoreAudioAPI.m */ = {
3362
sepNavIntBoundsRect = "{{0, 0}, {1377, 1157}}";
3363
sepNavSelRange = "{2223, 98}";
3364
sepNavVisRange = "{1767, 2249}";
3365
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
3368
9478E05E0EC8DCFB007096A7 /* sqSqueakSoundCoreAudio.h */ = {
3370
sepNavIntBoundsRect = "{{0, 0}, {1062, 1404}}";
3371
sepNavSelRange = "{2883, 135}";
3372
sepNavVisRange = "{1833, 2636}";
3373
sepNavWindowFrame = "{{52, 4}, {997, 998}}";
3376
9478E05F0EC8DCFB007096A7 /* sqSqueakSoundCoreAudio.m */ = {
3378
sepNavIntBoundsRect = "{{0, 0}, {1540, 5941}}";
3379
sepNavSelRange = "{11445, 29}";
3380
sepNavVisRange = "{10202, 2807}";
3381
sepNavWindowFrame = "{{38, 4}, {1587, 998}}";
3384
9478E13D0EC8EB46007096A7 /* PBXTextBookmark */ = {
3385
isa = PBXTextBookmark;
3386
fRef = 9478E13E0EC8EB46007096A7 /* AudioQueue.h */;
3387
name = "AudioQueue.h: 2";
3394
9478E13E0EC8EB46007096A7 /* AudioQueue.h */ = {
3395
isa = PBXFileReference;
3396
lastKnownFileType = sourcecode.c.h;
3397
name = AudioQueue.h;
3398
path = /System/Library/Frameworks/AudioToolbox.framework/Headers/AudioQueue.h;
3399
sourceTree = "<absolute>";
3401
947923FE1102BE53007C87F8 /* PBXTextBookmark */ = {
3402
isa = PBXTextBookmark;
3403
fRef = 947923FF1102BE53007C87F8 /* sqUnixMain.c */;
3404
name = "sqUnixMain.c: 176";
3411
947923FF1102BE53007C87F8 /* sqUnixMain.c */ = {
3412
isa = PBXFileReference;
3413
lastKnownFileType = sourcecode.c.c;
3414
name = sqUnixMain.c;
3415
path = /Volumes/px2/business/SqueakiPhone/archivesOLDSTUFF/platformsOLDDrawing/unix/vm/sqUnixMain.c;
3416
sourceTree = "<absolute>";
3418
947E20F50EB281C5007957D0 /* SqueakFFIPrims.c */ = {
3420
sepNavIntBoundsRect = "{{0, 0}, {1132, 37440}}";
3421
sepNavSelRange = "{75408, 0}";
3422
sepNavVisRange = "{75315, 897}";
3423
sepNavWindowFrame = "{{15, 4}, {1385, 1024}}";
3426
947E20F90EB2826C007957D0 /* sqFFI.h */ = {
3428
sepNavIntBoundsRect = "{{0, 0}, {1132, 2210}}";
3429
sepNavSelRange = "{2071, 8}";
3430
sepNavVisRange = "{1307, 1682}";
3433
947E210C0EB28486007957D0 /* PBXTextBookmark */ = {
3434
isa = PBXTextBookmark;
3435
fRef = 94638CF50EB16F1100A3F155 /* sqUnixMemory.c */;
3436
name = "sqUnixMemory.c: 214";
3443
947E21310EB2868A007957D0 /* dummyFFI.h */ = {
3445
sepNavIntBoundsRect = "{{0, 0}, {831, 494}}";
3446
sepNavSelRange = "{87, 0}";
3447
sepNavVisRange = "{0, 1201}";
3450
947E21320EB2868A007957D0 /* dummyFFI.c */ = {
3452
sepNavIntBoundsRect = "{{0, 0}, {1283, 2587}}";
3453
sepNavSelRange = "{0, 0}";
3454
sepNavVisRange = "{0, 891}";
3457
947E5F9310A9FF4A00D3B69E /* SqueakPureObjc_Prefix.pch */ = {
3459
sepNavIntBoundsRect = "{{0, 0}, {1283, 277}}";
3460
sepNavSelRange = "{0, 0}";
3461
sepNavVisRange = "{0, 149}";
3462
sepNavWindowFrame = "{{15, 45}, {1017, 978}}";
3465
947E5F9F10A9FFA000D3B69E /* SqueakPureObjc-Info.plist */ = {
3467
sepNavIntBoundsRect = "{{0, 0}, {972, 7812}}";
3468
sepNavSelRange = "{13195, 0}";
3469
sepNavVisRect = "{{0, 7107}, {972, 697}}";
3470
sepNavWindowFrame = "{{15, 18}, {1170, 1005}}";
3473
947E61D610AA049300D3B69E /* PBXTextBookmark */ = {
3474
isa = PBXTextBookmark;
3475
fRef = 947E61D710AA049300D3B69E /* Availability.h */;
3476
name = "Availability.h: 124";
3483
947E61D710AA049300D3B69E /* Availability.h */ = {
3484
isa = PBXFileReference;
3485
lastKnownFileType = sourcecode.c.h;
3486
name = Availability.h;
3487
path = /Developer/SDKs/MacOSX10.6.sdk/usr/include/Availability.h;
3488
sourceTree = "<absolute>";
3490
947E61DA10AA049300D3B69E /* PBXTextBookmark */ = {
3491
isa = PBXTextBookmark;
3492
fRef = 947E61DB10AA049300D3B69E /* AudioFileStream.h */;
3493
name = "AudioFileStream.h: 1";
3500
947E61DB10AA049300D3B69E /* AudioFileStream.h */ = {
3501
isa = PBXFileReference;
3502
lastKnownFileType = sourcecode.c.h;
3503
name = AudioFileStream.h;
3504
path = /System/Library/Frameworks/AudioToolbox.framework/Headers/AudioFileStream.h;
3505
sourceTree = "<absolute>";
3507
947E61DC10AA049300D3B69E /* PBXTextBookmark */ = {
3508
isa = PBXTextBookmark;
3509
fRef = 947E61DD10AA049300D3B69E /* AudioFormat.h */;
3510
name = "AudioFormat.h: 1";
3517
947E61DD10AA049300D3B69E /* AudioFormat.h */ = {
3518
isa = PBXFileReference;
3519
lastKnownFileType = sourcecode.c.h;
3520
name = AudioFormat.h;
3521
path = /System/Library/Frameworks/AudioToolbox.framework/Headers/AudioFormat.h;
3522
sourceTree = "<absolute>";
3524
947E626F10AA098300D3B69E /* SqueakPureObjc */ = {
3527
947E62FD10AA098300D3B69E /* SqueakPureObjc */,
3530
947E62FD10AA098300D3B69E /* SqueakPureObjc */ = {
3531
isa = PBXExecutable;
3532
activeArgIndices = (
3546
autoAttachOnCrash = 1;
3547
breakpointsEnabled = 1;
3550
customDataFormattersEnabled = 1;
3551
dataTipCustomDataFormattersEnabled = 1;
3552
dataTipShowTypeColumn = 1;
3553
dataTipSortType = 0;
3554
debuggerPlugin = GDBDebugging;
3555
disassemblyDisplayState = 0;
3556
dylibVariantSuffix = "";
3558
environmentEntries = (
3561
name = NSAutoreleaseHaltOnFreedObject;
3566
name = NSDebugEnabled;
3571
name = NSAutoreleaseFreedObjectCheckEnabled;
3576
name = NSZombieEnabled;
3581
name = DYLD_INSERT_LIBRARIES;
3582
value = /usr/lib/libMallocDebug.A.dylib;
3586
name = MallocPreScribble;
3591
name = MallocScribble;
3596
name = MallocGuardEdges;
3600
executableSystemSymbolLevel = 0;
3601
executableUserSymbolLevel = 0;
3602
libgmallocEnabled = 0;
3603
name = SqueakPureObjc;
3607
sourceDirectories = (
3609
variableFormatDictionary = {
3634
"*from-short unsigned int-copyImage16To32" = 3;
3635
"_return_value-sqInt-primitiveGetMenuHandle" = 1;
3636
"actually-void *-sqAllocateMemoryMac" = 2;
3637
"b-unsigned char--[sqSqueakOSXNSView(BitmapConversion) extractPixels_16_to_32:srcPixelWidth:left:right:top:bottom:position:]" = 3;
3638
"bits-NSInteger-\U0001\U0000-[sqSqueakOSXApplication(cursor) setCursor:withMask:offsetX:offsetY:]" = 3;
3639
"currentVMEncoding-NSInteger-\U0001\U0000-[sqSqueakMainApplication(attributes) getAttribute:]" = 1;
3640
"endAddr-long unsigned int-sqMakeMemoryNotExecutableFromTo" = 1;
3641
"firstPage-long unsigned int-sqMakeMemoryNotExecutableFromTo" = 1;
3642
"g-unsigned char--[sqSqueakOSXNSView(BitmapConversion) extractPixels_16_to_32:srcPixelWidth:left:right:top:bottom:position:]" = 3;
3643
"inCommandID-MenuCommand-GetIndMenuItemWithCommandID" = 5;
3644
"inputCommandID-OSType-GetIndMenuItemWithCommandID" = 5;
3645
"keyBoardModifiers-NSUInteger--[sqSqueakOSXApplication(events) translateCocoaModifiersToCarbonModifiers:]" = 3;
3646
"mask-NSInteger-\U0001\U0000-[sqSqueakOSXApplication(cursor) setCursor:withMask:offsetX:offsetY:]" = 3;
3648
"modifierFlags-NSUInteger--[sqSqueakOSXNSView doCommandBySelector:]" = 3;
3649
"modifierFlags-NSUInteger--[sqSqueakOSXNSView fakeKeyDownUp:]" = 1;
3650
"oop-usqInt-pointerForOop" = 1;
3651
"oop-usqInt-sweepPhase" = 2;
3652
"ptr-char *-longAtPointerput" = 2;
3653
"r-unsigned char--[sqSqueakOSXNSView(BitmapConversion) extractPixels_16_to_32:srcPixelWidth:left:right:top:bottom:position:]" = 3;
3654
"rgb-short int--[sqSqueakOSXNSView(BitmapConversion) extractPixels_16_to_32:srcPixelWidth:left:right:top:bottom:position:]" = 3;
3655
"rgb-short unsigned int--[sqSqueakOSXNSView(BitmapConversion) extractPixels_16_to_32:srcPixelWidth:left:right:top:bottom:position:]" = 3;
3656
"shift-NSUInteger-\U0001\U0000-[sqSqueakOSXApplication(cursor) setCursor:withMask:offsetX:offsetY:]" = 3;
3657
"squeakModifiers-int--[sqSqueakOSXApplication(events) translateCocoaModifiersToSqueakModifiers:]" = 3;
3658
"startAddr-long unsigned int-sqMakeMemoryNotExecutableFromTo" = 1;
3659
"to1-int-copyImage16To32" = 3;
3660
"to2-int-copyImage16To32" = 1;
3663
947E642710AA0E9E00D3B69E /* sqMacV2Browser.h */ = {
3665
sepNavIntBoundsRect = "{{0, 0}, {1167, 756}}";
3666
sepNavSelRange = "{0, 0}";
3667
sepNavVisRange = "{0, 1518}";
3670
947E642810AA0E9E00D3B69E /* sqMacV2Browser.m */ = {
3672
sepNavIntBoundsRect = "{{0, 0}, {802, 780}}";
3673
sepNavSelRange = "{1504, 0}";
3674
sepNavVisRange = "{492, 1556}";
3677
947E647910AA100900D3B69E /* SqueakOSXAppDelegate.h */ = {
3679
sepNavIntBoundsRect = "{{0, 0}, {970, 850}}";
3680
sepNavSelRange = "{2101, 17}";
3681
sepNavVisRange = "{0, 2472}";
3682
sepNavWindowFrame = "{{522, 48}, {1017, 978}}";
3685
947E647A10AA100900D3B69E /* SqueakOSXAppDelegate.m */ = {
3687
sepNavIntBoundsRect = "{{0, 0}, {1338, 2431}}";
3688
sepNavSelRange = "{6384, 120}";
3689
sepNavVisRange = "{5242, 1273}";
3690
sepNavWindowFrame = "{{15, 4}, {1426, 1019}}";
3693
947E64CA10AA16FE00D3B69E /* sqSqueakOSXApplication.h */ = {
3695
sepNavIntBoundsRect = "{{0, 0}, {1379, 891}}";
3696
sepNavSelRange = "{2392, 0}";
3697
sepNavVisRange = "{0, 2397}";
3698
sepNavWindowFrame = "{{15, 4}, {1426, 1019}}";
3701
947E64CB10AA16FE00D3B69E /* sqSqueakOSXApplication.m */ = {
3703
sepNavIntBoundsRect = "{{0, 0}, {1338, 3315}}";
3704
sepNavSelRange = "{3879, 23}";
3705
sepNavVisRange = "{3183, 1249}";
3706
sepNavWindowFrame = "{{522, 48}, {1017, 978}}";
3709
947E9920125D73FD0048E783 /* PBXTextBookmark */ = {
3710
isa = PBXTextBookmark;
3711
fRef = 94210B280E956AC200C1A314 /* ObjectiveCPlugin.c */;
3712
name = "ObjectiveCPlugin.c: 1915";
3719
947E9964125D756D0048E783 /* PBXTextBookmark */ = {
3720
isa = PBXTextBookmark;
3721
fRef = 94B8F54E10CF677800F0DD6B /* SqViewClut.h */;
3722
name = "SqViewClut.h: 1";
3729
947E9967125D756D0048E783 /* PBXTextBookmark */ = {
3730
isa = PBXTextBookmark;
3731
fRef = 947E9968125D756D0048E783 /* renderer.cpp */;
3732
name = "renderer.cpp: 58";
3739
947E9968125D756D0048E783 /* renderer.cpp */ = {
3740
isa = PBXFileReference;
3741
lastKnownFileType = sourcecode.cpp.cpp;
3742
name = renderer.cpp;
3743
path = "/Volumes/330GB Photos/WWDC10-SampleCode/Mac/ConditionalRendering/renderer.cpp";
3744
sourceTree = "<absolute>";
3746
947E9969125D756D0048E783 /* PBXTextBookmark */ = {
3747
isa = PBXTextBookmark;
3748
fRef = 947E996A125D756D0048E783 /* EAGLView.m */;
3749
name = "EAGLView.m: 277";
3756
947E996A125D756D0048E783 /* EAGLView.m */ = {
3757
isa = PBXFileReference;
3758
lastKnownFileType = sourcecode.c.objc;
3760
path = /Users/johnmci/Shared/RayPicking/Classes/EAGLView.m;
3761
sourceTree = "<absolute>";
3763
947E996B125D756D0048E783 /* PBXTextBookmark */ = {
3764
isa = PBXTextBookmark;
3765
fRef = 947E996C125D756D0048E783 /* ES1Renderer.m */;
3766
name = "ES1Renderer.m: 155";
3773
947E996C125D756D0048E783 /* ES1Renderer.m */ = {
3774
isa = PBXFileReference;
3775
lastKnownFileType = sourcecode.c.objc;
3776
name = ES1Renderer.m;
3777
path = /Users/johnmci/Shared/CubeExample/Classes/ES1Renderer.m;
3778
sourceTree = "<absolute>";
3780
947E996D125D756D0048E783 /* PBXTextBookmark */ = {
3781
isa = PBXTextBookmark;
3782
fRef = 947E996E125D756D0048E783 /* OpenGLRenderer.m */;
3783
name = "OpenGLRenderer.m: 55";
3790
947E996E125D756D0048E783 /* OpenGLRenderer.m */ = {
3791
isa = PBXFileReference;
3792
lastKnownFileType = sourcecode.c.objc;
3793
name = OpenGLRenderer.m;
3794
path = "/Volumes/330GB Photos/WWDC10-SampleCode/Mac/GLEssentials/Classes/OpenGLRenderer.m";
3795
sourceTree = "<absolute>";
3797
947E996F125D756D0048E783 /* PBXTextBookmark */ = {
3798
isa = PBXTextBookmark;
3799
fRef = 947E9970125D756D0048E783 /* OpenGLRenderer.m */;
3800
name = "OpenGLRenderer.m: 55";
3807
947E9970125D756D0048E783 /* OpenGLRenderer.m */ = {
3808
isa = PBXFileReference;
3809
lastKnownFileType = sourcecode.c.objc;
3810
name = OpenGLRenderer.m;
3811
path = "/Volumes/330GB Photos/WWDC10-SampleCode/iOS/GLEssentials/Classes/OpenGLRenderer.m";
3812
sourceTree = "<absolute>";
3814
947E9971125D756D0048E783 /* PBXTextBookmark */ = {
3815
isa = PBXTextBookmark;
3816
fRef = 947E9972125D756D0048E783 /* PVRTexture.m */;
3817
name = "PVRTexture.m: 206";
3824
947E9972125D756D0048E783 /* PVRTexture.m */ = {
3825
isa = PBXFileReference;
3826
lastKnownFileType = sourcecode.c.objc;
3827
name = PVRTexture.m;
3828
path = /Users/johnmci/Shared/CubeExample/Classes/PVRTexture.m;
3829
sourceTree = "<absolute>";
3831
947E9976125D756D0048E783 /* Shader.mm */ = {
3832
isa = PBXFileReference;
3833
lastKnownFileType = sourcecode.cpp.objcpp;
3835
path = "/Volumes/330GB Photos/temp/oolongengine-read-only/Oolong Engine2/Renderer/Core/GraphicsDevice/Shader.mm";
3836
sourceTree = "<absolute>";
3838
947E9994125D76820048E783 /* PBXTextBookmark */ = {
3839
isa = PBXTextBookmark;
3840
fRef = 947E9976125D756D0048E783 /* Shader.mm */;
3841
name = "Shader.mm: 207";
3848
947E99A0125D76BB0048E783 /* PBXTextBookmark */ = {
3849
isa = PBXTextBookmark;
3850
fRef = 947E99A1125D76BB0048E783 /* CGLMacro.h */;
3851
name = "CGLMacro.h: 34";
3858
947E99A1125D76BB0048E783 /* CGLMacro.h */ = {
3859
isa = PBXFileReference;
3860
lastKnownFileType = sourcecode.c.h;
3862
path = "/Volumes/330GB Photos/Developer42/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/OpenGL.framework/Versions/A/Headers/CGLMacro.h";
3863
sourceTree = "<absolute>";
3865
947E99CB125D78FB0048E783 /* NSLOG */ = {
3866
isa = PBXSymbolicBreakpoint;
3869
breakpointStyle = 1;
3870
continueAfterActions = 0;
3872
delayBeforeContinue = 0;
3876
modificationTime = 308445393.439781;
3877
originalNumberOfMultipleMatches = 1;
3881
947E99CC125D78FE0048E783 /* NSlog */ = {
3882
isa = PBXSymbolicBreakpoint;
3885
breakpointStyle = 1;
3886
continueAfterActions = 0;
3888
delayBeforeContinue = 0;
3892
modificationTime = 308445393.4398431;
3893
originalNumberOfMultipleMatches = 1;
3897
947E99D0125D79050048E783 /* NSLog */ = {
3898
isa = PBXSymbolicBreakpoint;
3901
breakpointStyle = 1;
3902
continueAfterActions = 0;
3904
delayBeforeContinue = 0;
3907
location = Foundation;
3908
modificationTime = 308445393.439915;
3909
originalNumberOfMultipleMatches = 1;
3913
947E99F8125D7B1C0048E783 /* cl */ = {
3914
isa = PBXSymbolicBreakpoint;
3917
breakpointStyle = 1;
3918
continueAfterActions = 0;
3920
delayBeforeContinue = 0;
3924
modificationTime = 308445393.43997;
3925
originalNumberOfMultipleMatches = 1;
3929
947E99FA125D7B850048E783 /* PBXTextBookmark */ = {
3930
isa = PBXTextBookmark;
3931
fRef = 94C2068810AF4F53002F4160 /* sqSqueakOSXNSView.h */;
3932
name = "sqSqueakOSXNSView.h: 79";
3939
948034A9122A264A00C42504 /* PBXTextBookmark */ = {
3940
isa = PBXTextBookmark;
3941
fRef = 948034AA122A264A00C42504 /* sqWin32Window.c */;
3942
name = "sqWin32Window.c: 1856";
3949
948034AA122A264A00C42504 /* sqWin32Window.c */ = {
3950
isa = PBXFileReference;
3951
lastKnownFileType = sourcecode.c.c;
3952
name = sqWin32Window.c;
3953
path = /Users/johnmci/Documents/Squeak3.8.0/platforms/win32/vm/sqWin32Window.c;
3954
sourceTree = "<absolute>";
3956
948127E812444F7800BD1543 /* PBXTextBookmark */ = {
3957
isa = PBXTextBookmark;
3958
fRef = 949E5DB60DE3AB6A007388E0 /* SqueakUIView.m */;
3959
name = "SqueakUIView.m: 65";
3966
948127E912444F7800BD1543 /* PBXTextBookmark */ = {
3967
isa = PBXTextBookmark;
3968
fRef = 9452D7640E0452D3000AD792 /* sqiPhoneScreenAndWindow.m */;
3969
name = "sqiPhoneScreenAndWindow.m: 1";
3976
948127EA12444F7800BD1543 /* PBXTextBookmark */ = {
3977
isa = PBXTextBookmark;
3978
fRef = 949E5DB50DE3AB6A007388E0 /* SqueakUIView.h */;
3979
name = "SqueakUIView.h: 40";
3986
948127EB12444F7800BD1543 /* PBXTextBookmark */ = {
3987
isa = PBXTextBookmark;
3988
fRef = 940CE8540DFCE2D200EBA91B /* SqueakUIController.h */;
3989
name = "SqueakUIController.h: 6";
3996
94845C211228E29F00BEB880 /* macvideo.cpp */ = {
3997
isa = PBXFileReference;
3998
lastKnownFileType = sourcecode.cpp.cpp;
3999
name = macvideo.cpp;
4000
path = /opt/intel/Compiler/11.1/076/Frameworks/tbb/examples/common/gui/macvideo.cpp;
4001
sourceTree = "<absolute>";
4003
9484F7B910B0D3600038BDC0 /* SystemConfiguration.h */ = {
4004
isa = PBXFileReference;
4005
lastKnownFileType = sourcecode.c.h;
4006
name = SystemConfiguration.h;
4007
path = /System/Library/Frameworks/SystemConfiguration.framework/Versions/A/Headers/SystemConfiguration.h;
4008
sourceTree = "<absolute>";
4010
9484F86210B0DCC60038BDC0 /* PBXTextBookmark */ = {
4011
isa = PBXTextBookmark;
4012
fRef = 9484F7B910B0D3600038BDC0 /* SystemConfiguration.h */;
4013
name = "SystemConfiguration.h: 109";
4020
9484F86510B0DCC60038BDC0 /* PBXTextBookmark */ = {
4021
isa = PBXTextBookmark;
4022
fRef = 9484F86610B0DCC60038BDC0 /* ABGlobals.h */;
4023
name = "ABGlobals.h: 162";
4030
9484F86610B0DCC60038BDC0 /* ABGlobals.h */ = {
4031
isa = PBXFileReference;
4032
lastKnownFileType = sourcecode.c.h;
4034
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AddressBook.framework/Versions/A/Headers/ABGlobals.h;
4035
sourceTree = "<absolute>";
4037
9484F8FC10B0E1770038BDC0 /* PBXBookmark */ = {
4039
fRef = 945550910DF2041100FB176B /* Default.png */;
4041
94862F8310BA182500CAA2EB /* PBXTextBookmark */ = {
4042
isa = PBXTextBookmark;
4043
fRef = 94C3696610AFB7550041953A /* NSBitmapImageRep.h */;
4044
name = "NSBitmapImageRep.h: 100";
4051
94862F9E10BA1A0100CAA2EB /* PBXTextBookmark */ = {
4052
isa = PBXTextBookmark;
4053
fRef = 94BCAD0410AB922600F87527 /* NSObjCRuntime.h */;
4054
name = "NSObjCRuntime.h: 193";
4061
9486302A10BA247200CAA2EB /* PBXTextBookmark */ = {
4062
isa = PBXTextBookmark;
4063
fRef = 94C3696310AFB7550041953A /* NSGraphics.h */;
4064
name = "NSGraphics.h: 92";
4071
948704AE0E12CABF00D565C3 /* PBXTextBookmark */ = {
4072
isa = PBXTextBookmark;
4073
fRef = 948704AF0E12CABF00D565C3 /* BitBlt.java */;
4074
name = "BitBlt.java: 1";
4081
948704AF0E12CABF00D565C3 /* BitBlt.java */ = {
4082
isa = PBXFileReference;
4083
lastKnownFileType = sourcecode.java;
4085
path = /Users/johnmci/Shared/JSqueak/BitBlt.java;
4086
sourceTree = "<absolute>";
4088
9487071F0E132B1000D565C3 /* PBXTextBookmark */ = {
4089
isa = PBXTextBookmark;
4090
fRef = 948707200E132B1000D565C3 /* sqGnu.h */;
4091
name = "sqGnu.h: 3";
4098
948707200E132B1000D565C3 /* sqGnu.h */ = {
4099
isa = PBXFileReference;
4100
lastKnownFileType = sourcecode.c.h;
4102
path = /Users/johnmci/Documents/SqueakHydra/platforms/unix/vm/sqGnu.h;
4103
sourceTree = "<absolute>";
4105
94883B400E0C2B9C005A4738 /* sqUnixSocket.c */ = {
4107
sepNavIntBoundsRect = "{{0, 0}, {957, 28496}}";
4108
sepNavSelRange = "{56411, 0}";
4109
sepNavVisRange = "{6842, 1375}";
4110
sepNavWindowFrame = "{{38, 14}, {799, 988}}";
4113
948C0820112DE98D0017EE7F /* PBXTextBookmark */ = {
4114
isa = PBXTextBookmark;
4115
fRef = 948C0821112DE98D0017EE7F /* interp.c */;
4116
name = "interp.c: 4824";
4123
948C0821112DE98D0017EE7F /* interp.c */ = {
4124
isa = PBXFileReference;
4125
lastKnownFileType = sourcecode.c.c;
4127
path = /Volumes/px2/business/SqueakiPhone/SqueakObjCBasedForOSXAndIPhone/WikiWikiServer/src/vm/interp.c;
4128
sourceTree = "<absolute>";
4130
948FAA0310BF855500BE88CF /* PBXTextBookmark */ = {
4131
isa = PBXTextBookmark;
4132
fRef = 948FAA0410BF855500BE88CF /* string.h */;
4133
name = "string.h: 85";
4140
948FAA0410BF855500BE88CF /* string.h */ = {
4141
isa = PBXFileReference;
4142
lastKnownFileType = sourcecode.c.h;
4144
path = /Developer/SDKs/MacOSX10.5.sdk/usr/include/string.h;
4145
sourceTree = "<absolute>";
4147
948FAB5B10BFAD3C00BE88CF /* PBXTextBookmark */ = {
4148
isa = PBXTextBookmark;
4149
fRef = 94E5838E10BF3E080073FD63 /* AudioQueue.h */;
4150
name = "AudioQueue.h: 695";
4157
949198B010BC8DFC00C629D1 /* PBXTextBookmark */ = {
4158
isa = PBXTextBookmark;
4159
fRef = 94C88C0E10AF4196007CB39E /* NSGeometry.h */;
4160
name = "NSGeometry.h: 100";
4167
949198C910BC8FBB00C629D1 /* PBXTextBookmark */ = {
4168
isa = PBXTextBookmark;
4169
fRef = 9456C2F910B32D2A000BF3DE /* NSString.h */;
4170
name = "NSString.h: 103";
4177
9492450510BA42EF00E726F5 /* PBXTextBookmark */ = {
4178
isa = PBXTextBookmark;
4179
fRef = 9492450610BA42EF00E726F5 /* SqueakApplication.h */;
4180
name = "SqueakApplication.h: 12";
4187
9492450610BA42EF00E726F5 /* SqueakApplication.h */ = {
4188
isa = PBXFileReference;
4189
lastKnownFileType = sourcecode.c.h;
4190
name = SqueakApplication.h;
4191
path = "/Users/johnmci/Work In Progress/smalltalk/CocoaSqueakSource/CocoaSqueak/SqueakApplication.h";
4192
sourceTree = "<absolute>";
4194
9492450710BA42EF00E726F5 /* PBXTextBookmark */ = {
4195
isa = PBXTextBookmark;
4196
fRef = 9492450810BA42EF00E726F5 /* SqueakApplication.m */;
4197
name = "SqueakApplication.m: 2";
4204
9492450810BA42EF00E726F5 /* SqueakApplication.m */ = {
4205
isa = PBXFileReference;
4206
lastKnownFileType = sourcecode.c.objc;
4207
name = SqueakApplication.m;
4208
path = "/Users/johnmci/Work In Progress/smalltalk/CocoaSqueakSource/CocoaSqueak/SqueakApplication.m";
4209
sourceTree = "<absolute>";
4211
9492450910BA42EF00E726F5 /* PBXTextBookmark */ = {
4212
isa = PBXTextBookmark;
4213
fRef = 945F30620E0C6A5000CFF3DC /* SqueakApplication.m */;
4214
name = "SqueakApplication.m: 12";
4221
9492452F10BA43AA00E726F5 /* SqueakOSXApplication.h */ = {
4223
sepNavIntBoundsRect = "{{0, 0}, {1104, 674}}";
4224
sepNavSelRange = "{1872, 0}";
4225
sepNavVisRange = "{0, 1877}";
4228
9492453010BA43AA00E726F5 /* SqueakOSXApplication.m */ = {
4230
sepNavIntBoundsRect = "{{0, 0}, {1167, 806}}";
4231
sepNavSelRange = "{2023, 13}";
4232
sepNavVisRange = "{99, 2329}";
4233
sepNavWindowFrame = "{{15, 4}, {878, 1019}}";
4236
9492455D10BA462B00E726F5 /* sqUnixQuartz.m */ = {
4237
isa = PBXFileReference;
4238
lastKnownFileType = sourcecode.c.objc;
4239
name = sqUnixQuartz.m;
4240
path = "/Users/johnmci/Documents/SqueakHydra/SqueakVMMAker/platforms/unix/vm-display-Quartz/sqUnixQuartz.m";
4241
sourceTree = "<absolute>";
4243
949245B210BA4A6200E726F5 /* PBXTextBookmark */ = {
4244
isa = PBXTextBookmark;
4245
fRef = 9492455D10BA462B00E726F5 /* sqUnixQuartz.m */;
4246
name = "sqUnixQuartz.m: 1937";
4253
9493E98F10EE90BC000C4FB3 /* PBXTextBookmark */ = {
4254
isa = PBXTextBookmark;
4255
fRef = 94360A8C10E84CC90060221A /* NSException.h */;
4256
name = "NSException.h: 67";
4263
9494927D11E5178D0019BC29 /* cogit.c */ = {
4265
sepNavIntBoundsRect = "{{0, 0}, {1356, 164385}}";
4266
sepNavSelRange = "{325, 38}";
4267
sepNavVisRange = "{0, 1577}";
4268
sepNavWindowFrame = "{{15, 18}, {1170, 1005}}";
4271
9494927E11E5178D0019BC29 /* cogit.h */ = {
4273
sepNavIntBoundsRect = "{{0, 0}, {1559, 1430}}";
4274
sepNavSelRange = "{0, 0}";
4275
sepNavVisRange = "{0, 3035}";
4278
9494928011E5178D0019BC29 /* gcc3x-cointerp.c */ = {
4280
sepNavIntBoundsRect = "{{0, 0}, {1338, 540995}}";
4281
sepNavSelRange = "{1165452, 40}";
4282
sepNavVisRange = "{1164453, 1395}";
4283
sepNavWindowFrame = "{{295, 4}, {1385, 1024}}";
4286
9494928111E5178D0019BC29 /* cointerp.h */ = {
4288
sepNavIntBoundsRect = "{{0, 0}, {1368, 2275}}";
4289
sepNavSelRange = "{3374, 7}";
4290
sepNavVisRange = "{2366, 2130}";
4293
949492C011E51C6B0019BC29 /* dispdbg.h */ = {
4295
sepNavIntBoundsRect = "{{0, 0}, {1368, 1781}}";
4296
sepNavSelRange = "{306, 11}";
4297
sepNavVisRange = "{269, 1550}";
4300
949492C111E51C6B0019BC29 /* sqAssert.h */ = {
4302
sepNavIntBoundsRect = "{{0, 0}, {1368, 644}}";
4303
sepNavSelRange = "{505, 6}";
4304
sepNavVisRange = "{0, 1133}";
4305
sepNavWindowFrame = "{{15, 24}, {1661, 999}}";
4308
949492C311E51C6B0019BC29 /* sqExternalSemaphores.c */ = {
4310
sepNavIntBoundsRect = "{{0, 0}, {1132, 2925}}";
4311
sepNavSelRange = "{2737, 7}";
4312
sepNavVisRange = "{0, 2031}";
4315
949492C411E51C6B0019BC29 /* sqAtomicOps.h */ = {
4317
sepNavIntBoundsRect = "{{0, 0}, {1338, 2574}}";
4318
sepNavSelRange = "{2283, 19}";
4319
sepNavVisRange = "{1497, 1558}";
4320
sepNavWindowFrame = "{{107, 4}, {1573, 1024}}";
4323
949492C511E51C6B0019BC29 /* sqHeapMap.c */ = {
4325
sepNavIntBoundsRect = "{{0, 0}, {1283, 1352}}";
4326
sepNavSelRange = "{2420, 27}";
4327
sepNavVisRange = "{1461, 1192}";
4330
949492C611E51C6B0019BC29 /* sqTicker.c */ = {
4332
sepNavIntBoundsRect = "{{0, 0}, {1132, 3250}}";
4333
sepNavSelRange = "{7347, 0}";
4334
sepNavVisRange = "{6448, 1506}";
4335
sepNavWindowFrame = "{{15, 4}, {1385, 1024}}";
4338
9494932C11E527180019BC29 /* sqUnixHeartbeat.c */ = {
4340
sepNavIntBoundsRect = "{{0, 0}, {1327, 9100}}";
4341
sepNavSelRange = "{18414, 0}";
4342
sepNavVisRange = "{17993, 851}";
4343
sepNavWindowFrame = "{{966, 4}, {714, 1024}}";
4346
9494932D11E527180019BC29 /* sqUnixThreads.c */ = {
4348
sepNavIntBoundsRect = "{{0, 0}, {1132, 676}}";
4349
sepNavSelRange = "{428, 13}";
4350
sepNavVisRange = "{0, 1103}";
4353
9494932E11E527180019BC29 /* sqUnixVMProfile.c */ = {
4355
sepNavIntBoundsRect = "{{0, 0}, {1132, 5252}}";
4356
sepNavSelRange = "{7363, 3}";
4357
sepNavVisRange = "{6688, 1339}";
4358
sepNavWindowFrame = "{{15, 4}, {1573, 1024}}";
4361
9494935011E527AB0019BC29 /* sqMemoryFence.h */ = {
4363
sepNavIntBoundsRect = "{{0, 0}, {1368, 780}}";
4364
sepNavSelRange = "{2337, 16}";
4365
sepNavVisRange = "{386, 1997}";
4366
sepNavWindowFrame = "{{15, 4}, {1573, 1024}}";
4369
949493BF11E52ADE0019BC29 /* aio.c */ = {
4371
sepNavIntBoundsRect = "{{0, 0}, {1132, 5330}}";
4372
sepNavSelRange = "{5142, 7}";
4373
sepNavVisRange = "{4481, 1294}";
4374
sepNavWindowFrame = "{{61, 148}, {901, 833}}";
4377
94977E7C11EE46BC002BC5E9 /* PBXTextBookmark */ = {
4378
isa = PBXTextBookmark;
4379
fRef = 949F254D11EC33FA00A34245 /* mach_absolute_time.s */;
4380
name = "mach_absolute_time.s: 32";
4387
949AD14911E542E8006D6BF4 /* SqueakPureObjc-InfoCOG.plist */ = {
4389
sepNavWindowFrame = "{{15, 20}, {1185, 1003}}";
4392
949AD35211E54A81006D6BF4 /* PBXTextBookmark */ = {
4393
isa = PBXTextBookmark;
4394
fRef = 9424FF660DDCB1EF009912BF /* sqConfig.h */;
4395
name = "sqConfig.h: 4";
4402
949AD36211E54AAA006D6BF4 /* PBXTextBookmark */ = {
4403
isa = PBXTextBookmark;
4404
fRef = 9424FF650DDCB1EF009912BF /* config.h */;
4405
name = "config.h: 162";
4412
949C3A281262C1F700F4EF15 /* PBXTextBookmark */ = {
4413
isa = PBXTextBookmark;
4414
fRef = 9424FF5D0DDCB1C7009912BF /* sq.h */;
4422
949C3A441262C2D200F4EF15 /* PBXTextBookmark */ = {
4423
isa = PBXTextBookmark;
4424
fRef = 9494928011E5178D0019BC29 /* gcc3x-cointerp.c */;
4425
name = "gcc3x-cointerp.c: 40714";
4432
949C3AFE1262C91300F4EF15 /* PBXTextBookmark */ = {
4433
isa = PBXTextBookmark;
4434
fRef = 94EF6CBE11E55947003BA64D /* gcc3x-interp.c */;
4435
name = "gcc3x-interp.c: 1";
4442
949C3AFF1262C91300F4EF15 /* PBXTextBookmark */ = {
4443
isa = PBXTextBookmark;
4444
fRef = 9424FF670DDCB202009912BF /* sqMacV2Memory.c */;
4449
949C3B171262C9C900F4EF15 /* PBXTextBookmark */ = {
4450
isa = PBXTextBookmark;
4451
fRef = 9424FF670DDCB202009912BF /* sqMacV2Memory.c */;
4452
name = "sqMacV2Memory.c: 83";
4459
949DDD4811D13F630017F79B /* NSDateFormatter.h */ = {
4460
isa = PBXFileReference;
4461
lastKnownFileType = sourcecode.c.h;
4462
name = NSDateFormatter.h;
4463
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDateFormatter.h;
4464
sourceTree = "<absolute>";
4466
949DDD6D11D141080017F79B /* PBXTextBookmark */ = {
4467
isa = PBXTextBookmark;
4468
fRef = 949DDD4811D13F630017F79B /* NSDateFormatter.h */;
4469
name = "NSDateFormatter.h: 1";
4476
949E5B970DE3623B007388E0 /* sqUnixMain.c */ = {
4477
isa = PBXFileReference;
4478
lastKnownFileType = sourcecode.c.c;
4479
name = sqUnixMain.c;
4480
path = /Users/johnmci/Documents/SqueakHydra/platforms/unix/vm/sqUnixMain.c;
4481
sourceTree = "<absolute>";
4483
949E5DB50DE3AB6A007388E0 /* SqueakUIView.h */ = {
4485
sepNavIntBoundsRect = "{{0, 0}, {838, 754}}";
4486
sepNavSelRange = "{1791, 218}";
4487
sepNavVisRange = "{0, 2259}";
4488
sepNavWindowFrame = "{{21, 20}, {694, 1008}}";
4491
949E5DB60DE3AB6A007388E0 /* SqueakUIView.m */ = {
4493
sepNavIntBoundsRect = "{{0, 0}, {1202, 2587}}";
4494
sepNavSelRange = "{2580, 13}";
4495
sepNavVisRange = "{2490, 1684}";
4496
sepNavWindowFrame = "{{152, 50}, {1040, 978}}";
4499
949EFD7D0FF17FED00F540EB /* ObjectiveCPlugin.c */ = {
4500
isa = PBXFileReference;
4501
lastKnownFileType = sourcecode.c.c;
4502
name = ObjectiveCPlugin.c;
4503
path = /Volumes/px2/business/SqueakiPhone/SqueakObjCBasedForOSXAndIPhone/WikiWikiServer/src/vm/intplugins/ObjectiveCPlugin/ObjectiveCPlugin.c;
4504
sourceTree = "<absolute>";
4506
949F254511EC33FA00A34245 /* PBXTextBookmark */ = {
4507
isa = PBXTextBookmark;
4508
fRef = 9468DA7511EC31F6000ECA16 /* main time.c */;
4509
name = "main time.c: 10";
4516
949F254611EC33FA00A34245 /* PBXTextBookmark */ = {
4517
isa = PBXTextBookmark;
4518
fRef = 949F254711EC33FA00A34245 /* mach_absolute_time.s */;
4519
name = "mach_absolute_time.s: 26";
4526
949F254711EC33FA00A34245 /* mach_absolute_time.s */ = {
4527
isa = PBXFileReference;
4528
lastKnownFileType = sourcecode.asm;
4529
name = mach_absolute_time.s;
4530
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/Libc/ppc/mach/mach_absolute_time.s";
4531
sourceTree = "<absolute>";
4533
949F254811EC33FA00A34245 /* PBXTextBookmark */ = {
4534
isa = PBXTextBookmark;
4535
fRef = 949F254911EC33FA00A34245 /* mach_absolute_time.c */;
4536
name = "mach_absolute_time.c: 40";
4543
949F254911EC33FA00A34245 /* mach_absolute_time.c */ = {
4544
isa = PBXFileReference;
4545
lastKnownFileType = sourcecode.c.c;
4546
name = mach_absolute_time.c;
4547
path = "/Users/johnmci/Shared/docs/Computer/Libc-391.2.5/i386/mach/mach_absolute_time.c";
4548
sourceTree = "<absolute>";
4550
949F254D11EC33FA00A34245 /* mach_absolute_time.s */ = {
4551
isa = PBXFileReference;
4552
lastKnownFileType = sourcecode.asm;
4553
name = mach_absolute_time.s;
4554
path = "/Users/johnmci/Shared/docs/Computer/Libc-391.2.5/ppc/mach/mach_absolute_time.s";
4555
sourceTree = "<absolute>";
4557
94A0E8440DE5EB6E0071C8B9 /* sqSqueakMainApplication+attributes.h */ = {
4559
sepNavIntBoundsRect = "{{0, 0}, {1167, 654}}";
4560
sepNavSelRange = "{1987, 14}";
4561
sepNavVisRange = "{0, 2027}";
4562
sepNavWindowFrame = "{{38, 19}, {905, 983}}";
4565
94A0E8450DE5EB6E0071C8B9 /* sqSqueakIPhoneApplication+attributes.m */ = {
4567
sepNavIntBoundsRect = "{{0, 0}, {1167, 1417}}";
4568
sepNavSelRange = "{4729, 0}";
4569
sepNavVisRange = "{2120, 2560}";
4570
sepNavWindowFrame = "{{812, 34}, {818, 994}}";
4573
94A0E8830DE5EF430071C8B9 /* sqSqueakMainApplication+imageReadWrite.h */ = {
4575
sepNavIntBoundsRect = "{{0, 0}, {850, 778}}";
4576
sepNavSelRange = "{1898, 31}";
4577
sepNavVisRange = "{0, 1966}";
4580
94A0E8840DE5EF430071C8B9 /* sqSqueakMainApplication+imageReadWrite.m */ = {
4582
sepNavIntBoundsRect = "{{0, 0}, {1338, 793}}";
4583
sepNavSelRange = "{2342, 35}";
4584
sepNavVisRange = "{589, 1890}";
4585
sepNavWindowFrame = "{{15, 15}, {694, 1008}}";
4588
94A0E9820DE5F1FE0071C8B9 /* sqSqueakMainApplication+screen.h */ = {
4590
sepNavIntBoundsRect = "{{0, 0}, {1169, 764}}";
4591
sepNavSelRange = "{1779, 0}";
4592
sepNavVisRange = "{0, 1983}";
4593
sepNavWindowFrame = "{{15, 15}, {694, 1008}}";
4596
94A0E9830DE5F1FE0071C8B9 /* sqSqueakMainApplication+screen.m */ = {
4598
sepNavIntBoundsRect = "{{0, 0}, {905, 767}}";
4599
sepNavSelRange = "{1924, 15}";
4600
sepNavVisRange = "{0, 2171}";
4601
sepNavWindowFrame = "{{15, 15}, {694, 1008}}";
4604
94A0EBB20DE608350071C8B9 /* squeakAudioVideoPipeLineSignalInterface.c */ = {
4605
isa = PBXFileReference;
4606
lastKnownFileType = sourcecode.c.c;
4607
name = squeakAudioVideoPipeLineSignalInterface.c;
4608
path = "/Volumes/pm/Mail Downloads/squeakAudioVideoPipeLineSignalInterface.c";
4609
sourceTree = "<absolute>";
4611
94A1B0050E0DBE2400EB5EFC /* sqSqueakMainApplication+events.h */ = {
4613
sepNavIntBoundsRect = "{{0, 0}, {1338, 598}}";
4614
sepNavSelRange = "{2009, 11}";
4615
sepNavVisRange = "{3, 2024}";
4616
sepNavWindowFrame = "{{312, -14}, {1416, 1021}}";
4619
94A1B0060E0DBE2400EB5EFC /* sqSqueakMainApplication+events.m */ = {
4621
sepNavIntBoundsRect = "{{0, 0}, {1338, 1053}}";
4622
sepNavSelRange = "{1907, 2}";
4623
sepNavVisRange = "{841, 1729}";
4624
sepNavWindowFrame = "{{437, 4}, {847, 985}}";
4627
94A1B02B0E0DC10D00EB5EFC /* sqSqueakSoundAPI.h */ = {
4629
sepNavIntBoundsRect = "{{0, 0}, {854, 738}}";
4630
sepNavSelRange = "{7, 16}";
4631
sepNavVisRange = "{0, 1798}";
4632
sepNavWindowFrame = "{{15, 15}, {694, 1008}}";
4635
94A1B02C0E0DC10D00EB5EFC /* sqSqueakSoundAPI.m */ = {
4637
sepNavIntBoundsRect = "{{0, 0}, {1338, 676}}";
4638
sepNavSelRange = "{1926, 6}";
4639
sepNavVisRange = "{252, 1760}";
4640
sepNavWindowFrame = "{{15, 45}, {1017, 978}}";
4643
94A1B0300E0DC19300EB5EFC /* sqSqueakMainApplication+sound.h */ = {
4645
sepNavIntBoundsRect = "{{0, 0}, {1036, 652}}";
4646
sepNavSelRange = "{1878, 6}";
4647
sepNavVisRange = "{0, 1891}";
4648
sepNavWindowFrame = "{{38, 145}, {1288, 857}}";
4651
94A1B0310E0DC19300EB5EFC /* sqSqueakMainApplication+sound.m */ = {
4653
sepNavIntBoundsRect = "{{0, 0}, {1338, 559}}";
4654
sepNavSelRange = "{868, 1033}";
4655
sepNavVisRange = "{3, 1898}";
4658
94A1B21A10B9DE0300C64473 /* keyBoardStrokeDetails.h */ = {
4660
sepNavIntBoundsRect = "{{0, 0}, {1279, 859}}";
4661
sepNavSelRange = "{1866, 25}";
4662
sepNavVisRange = "{0, 2034}";
4663
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
4666
94A1B21B10B9DE0300C64473 /* keyBoardStrokeDetails.m */ = {
4668
sepNavIntBoundsRect = "{{0, 0}, {1167, 723}}";
4669
sepNavSelRange = "{1867, 0}";
4670
sepNavVisRange = "{0, 1908}";
4673
94A1B2AA10B9E92A00C64473 /* PBXTextBookmark */ = {
4674
isa = PBXTextBookmark;
4675
fRef = 94A1B2AB10B9E92A00C64473 /* NSCache.h */;
4676
name = "NSCache.h: 25";
4683
94A1B2AB10B9E92A00C64473 /* NSCache.h */ = {
4684
isa = PBXFileReference;
4685
lastKnownFileType = sourcecode.c.h;
4687
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSCache.h;
4688
sourceTree = "<absolute>";
4690
94A1B41E10BA05E600C64473 /* PBXTextBookmark */ = {
4691
isa = PBXTextBookmark;
4692
fRef = 94A1B41F10BA05E600C64473 /* objc.h */;
4693
name = "objc.h: 64";
4700
94A1B41F10BA05E600C64473 /* objc.h */ = {
4701
isa = PBXFileReference;
4702
lastKnownFileType = sourcecode.c.h;
4704
path = /Developer/SDKs/MacOSX10.6.sdk/usr/include/objc/objc.h;
4705
sourceTree = "<absolute>";
4707
94A3488C0DDCCCC700D1D4A9 /* sqSqueakScreenAPI.h */ = {
4709
sepNavIntBoundsRect = "{{0, 0}, {1169, 764}}";
4710
sepNavSelRange = "{78, 0}";
4711
sepNavVisRange = "{0, 1806}";
4712
sepNavWindowFrame = "{{15, 8}, {1012, 1015}}";
4715
94A3488D0DDCCCC700D1D4A9 /* sqSqueakScreenAPI.m */ = {
4717
sepNavIntBoundsRect = "{{0, 0}, {1048, 1872}}";
4718
sepNavSelRange = "{3724, 21}";
4719
sepNavVisRange = "{2363, 1770}";
4720
sepNavWindowFrame = "{{21, 20}, {694, 1008}}";
4723
94A349B50DDCDBE200D1D4A9 /* iPhone.image */ = {
4725
sepNavIntBoundsRect = "{{0, 0}, {807273, 3.9741e+06}}";
4726
sepNavSelRange = "{18277000, 0}";
4727
sepNavVisRange = "{1158, 1564}";
4730
94AB2E6A0E003879006A79E4 /* PBXTextBookmark */ = {
4731
isa = PBXTextBookmark;
4732
fRef = 94AB2E6B0E003879006A79E4 /* npsqueak.c */;
4733
name = "npsqueak.c: 984";
4740
94AB2E6B0E003879006A79E4 /* npsqueak.c */ = {
4741
isa = PBXFileReference;
4742
lastKnownFileType = sourcecode.c.c;
4744
path = "/Users/johnmci/Documents/SqueakBrowserPlugin/platforms/Mac OS/vm/npsqueak copy 1/npsqueak.c";
4745
sourceTree = "<absolute>";
4747
94AB2E6C0E003879006A79E4 /* PBXTextBookmark */ = {
4748
isa = PBXTextBookmark;
4749
fRef = 94AB2E6D0E003879006A79E4 /* npsqueak.c */;
4750
name = "npsqueak.c: 1";
4757
94AB2E6D0E003879006A79E4 /* npsqueak.c */ = {
4758
isa = PBXFileReference;
4759
lastKnownFileType = sourcecode.c.c;
4761
path = "/Users/johnmci/Documents/SqueakBrowserPlugin/platforms/Mac OS/vm/npsqueak copy/npsqueak.c";
4762
sourceTree = "<absolute>";
4764
94AC16D512395FE40067037A /* sqSqueakOSXNSView.m:551 */ = {
4765
isa = PBXFileBreakpoint;
4768
breakpointStyle = 0;
4769
continueAfterActions = 0;
4771
delayBeforeContinue = 0;
4772
fileReference = 94C2068910AF4F53002F4160 /* sqSqueakOSXNSView.m */;
4773
functionName = "-doCommandBySelector:";
4777
modificationTime = 308445393.4367589;
4778
originalNumberOfMultipleMatches = 1;
4781
94AC16D912395FF10067037A /* PBXTextBookmark */ = {
4782
isa = PBXTextBookmark;
4783
fRef = 94C3687710AFA77F0041953A /* sqSqueakOSXApplication+cursor.m */;
4784
name = "sqSqueakOSXApplication+cursor.m: 90";
4791
94AC16DA12395FF10067037A /* PBXTextBookmark */ = {
4792
isa = PBXTextBookmark;
4793
fRef = 947E64CB10AA16FE00D3B69E /* sqSqueakOSXApplication.m */;
4794
name = "sqSqueakOSXApplication.m: 249";
4801
94AC16DC12395FF10067037A /* PBXTextBookmark */ = {
4802
isa = PBXTextBookmark;
4803
fRef = 94C88BDE10AF3C52007CB39E /* sqSqueakOSXScreenAndWindow.m */;
4804
name = "sqSqueakOSXScreenAndWindow.m: 70";
4811
94AC16DE12395FF10067037A /* PBXTextBookmark */ = {
4812
isa = PBXTextBookmark;
4813
fRef = 9492453010BA43AA00E726F5 /* SqueakOSXApplication.m */;
4814
name = "SqueakOSXApplication.m: 48";
4821
94AF3A1F12231A7200691409 /* PBXTextBookmark */ = {
4822
isa = PBXTextBookmark;
4823
fRef = 94A1B0050E0DBE2400EB5EFC /* sqSqueakMainApplication+events.h */;
4824
name = "sqSqueakMainApplication+events.h: 42";
4831
94B1514E0DE2CE530059F208 /* PBXTextBookmark */ = {
4832
isa = PBXTextBookmark;
4833
fRef = 94B1514F0DE2CE530059F208 /* sqMacWindowUniversal.c */;
4834
name = "sqMacWindowUniversal.c: 580";
4841
94B1514F0DE2CE530059F208 /* sqMacWindowUniversal.c */ = {
4842
isa = PBXFileReference;
4843
lastKnownFileType = sourcecode.c.c;
4844
name = sqMacWindowUniversal.c;
4845
path = "/Users/johnmci/Documents/SqueakHydra/platforms/Mac OS/vm/sqMacWindowUniversal.c";
4846
sourceTree = "<absolute>";
4848
94B6E9D910BC775E00333E9E /* English */ = {
4850
sepNavIntBoundsRect = "{{0, 0}, {1132, 807}}";
4851
sepNavSelRange = "{238, 0}";
4852
sepNavVisRange = "{0, 238}";
4853
sepNavWindowFrame = "{{15, 4}, {878, 1019}}";
4856
94B7898910C4F95E005EA70D /* PBXTextBookmark */ = {
4857
isa = PBXTextBookmark;
4858
fRef = 94CFE6BD10BE63A900847DF5 /* SqViewEventSensor.m */;
4859
name = "SqViewEventSensor.m: 80";
4866
94B88C540E81500200C98131 /* SqView.m */ = {
4867
isa = PBXFileReference;
4868
lastKnownFileType = sourcecode.c.objc;
4870
path = "/Users/johnmci/Work In Progress/smalltalk/CocoaSqueakSource/SqueakAppKit/SqView.m";
4871
sourceTree = "<absolute>";
4873
94B88C560E81500200C98131 /* PBXTextBookmark */ = {
4874
isa = PBXTextBookmark;
4875
fRef = 94B88C570E81500200C98131 /* MsgContext.m */;
4876
name = "MsgContext.m: 97";
4883
94B88C570E81500200C98131 /* MsgContext.m */ = {
4884
isa = PBXFileReference;
4885
lastKnownFileType = sourcecode.c.objc;
4886
name = MsgContext.m;
4887
path = "/Users/johnmci/Work In Progress/smalltalk/FScriptSources-20031020/FScript/FScriptFramework/MsgContext.m";
4888
sourceTree = "<absolute>";
4890
94B88C640E81500200C98131 /* SqueakObjcBridge.m */ = {
4891
isa = PBXFileReference;
4892
lastKnownFileType = sourcecode.c.objc;
4893
name = SqueakObjcBridge.m;
4894
path = "/Users/johnmci/Work In Progress/smalltalk/CocoaSqueakSource/Squeak/SqueakObjcBridge.m";
4895
sourceTree = "<absolute>";
4897
94B8F4B910CF5BFF00F0DD6B /* PBXBookmarkGroup */ = {
4898
isa = PBXBookmarkGroup;
4900
94B8F54210CF675200F0DD6B /* PBXBookmark */,
4904
94B8F54210CF675200F0DD6B /* PBXBookmark */ = {
4906
fRef = 9402DD6F10CE0E91005C2102 /* SqViewClut.m */;
4908
94B8F54E10CF677800F0DD6B /* SqViewClut.h */ = {
4910
sepNavIntBoundsRect = "{{0, 0}, {764, 742}}";
4911
sepNavSelRange = "{3, 12}";
4912
sepNavVisRange = "{0, 254}";
4915
94B9528510E6B79E00DC476A /* MacMenubarPlugin.h */ = {
4917
sepNavIntBoundsRect = "{{0, 0}, {1283, 3354}}";
4918
sepNavSelRange = "{1194, 0}";
4919
sepNavVisRange = "{1043, 535}";
4920
sepNavWindowFrame = "{{602, 4}, {1078, 1014}}";
4923
94B9533310E6BD7100DC476A /* MacMenuOS9ToOSX.h */ = {
4925
sepNavIntBoundsRect = "{{0, 0}, {1215, 537}}";
4926
sepNavSelRange = "{201, 0}";
4927
sepNavVisRange = "{0, 201}";
4928
sepNavWindowFrame = "{{554, 14}, {1078, 1014}}";
4931
94B9533410E6BD7100DC476A /* MacMenuOS9ToOSX.m */ = {
4933
sepNavIntBoundsRect = "{{0, 0}, {1368, 3614}}";
4934
sepNavSelRange = "{5489, 0}";
4935
sepNavVisRange = "{4856, 1272}";
4936
sepNavWindowFrame = "{{15, 9}, {1078, 1014}}";
4939
94BCAAE810AB6C3500F87527 /* NSFileManager.h */ = {
4940
isa = PBXFileReference;
4941
lastKnownFileType = sourcecode.c.h;
4942
name = NSFileManager.h;
4943
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSFileManager.h;
4944
sourceTree = "<absolute>";
4946
94BCAB0410AB6DC000F87527 /* NSApplication.h */ = {
4947
isa = PBXFileReference;
4948
lastKnownFileType = sourcecode.c.h;
4949
name = NSApplication.h;
4950
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSApplication.h;
4951
sourceTree = "<absolute>";
4953
94BCABBF10AB72A600F87527 /* sqSqueakOSXFileDirectoryInterface.h */ = {
4955
sepNavIntBoundsRect = "{{0, 0}, {996, 793}}";
4956
sepNavSelRange = "{2017, 0}";
4957
sepNavVisRange = "{0, 2022}";
4960
94BCABC010AB72A600F87527 /* sqSqueakOSXFileDirectoryInterface.m */ = {
4962
sepNavIntBoundsRect = "{{0, 0}, {1227, 1482}}";
4963
sepNavSelRange = "{2641, 19}";
4964
sepNavVisRange = "{2047, 2077}";
4965
sepNavWindowFrame = "{{562, 20}, {1274, 998}}";
4968
94BCAC0310AB759300F87527 /* NSURL.h */ = {
4969
isa = PBXFileReference;
4970
lastKnownFileType = sourcecode.c.h;
4972
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSURL.h;
4973
sourceTree = "<absolute>";
4975
94BCAC3710AB79DA00F87527 /* NSArray.h */ = {
4976
isa = PBXFileReference;
4977
lastKnownFileType = sourcecode.c.h;
4979
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSArray.h;
4980
sourceTree = "<absolute>";
4982
94BCAC3C10AB79DA00F87527 /* NSDictionary.h */ = {
4983
isa = PBXFileReference;
4984
lastKnownFileType = sourcecode.c.h;
4985
name = NSDictionary.h;
4986
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDictionary.h;
4987
sourceTree = "<absolute>";
4989
94BCAC4E10AB7A2B00F87527 /* NSProcessInfo.h */ = {
4990
isa = PBXFileReference;
4991
lastKnownFileType = sourcecode.c.h;
4992
name = NSProcessInfo.h;
4993
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSProcessInfo.h;
4994
sourceTree = "<absolute>";
4996
94BCACE310AB8AE300F87527 /* NSObject.h */ = {
4997
isa = PBXFileReference;
4998
lastKnownFileType = sourcecode.c.h;
5000
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSObject.h;
5001
sourceTree = "<absolute>";
5003
94BCAD0410AB922600F87527 /* NSObjCRuntime.h */ = {
5004
isa = PBXFileReference;
5005
lastKnownFileType = sourcecode.c.h;
5006
name = NSObjCRuntime.h;
5007
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSObjCRuntime.h;
5008
sourceTree = "<absolute>";
5010
94BCAD1B10AB942300F87527 /* sqSqueakOSXApplication+attributes.h */ = {
5012
sepNavIntBoundsRect = "{{0, 0}, {838, 749}}";
5013
sepNavSelRange = "{109, 1692}";
5014
sepNavVisRange = "{0, 1897}";
5017
94BCAD1C10AB942300F87527 /* sqSqueakOSXApplication+attributes.m */ = {
5019
sepNavIntBoundsRect = "{{0, 0}, {1533, 2145}}";
5020
sepNavSelRange = "{3001, 3}";
5021
sepNavVisRange = "{2826, 1075}";
5022
sepNavWindowFrame = "{{622, 43}, {1017, 978}}";
5025
94BCAD4A10AB981B00F87527 /* PBXTextBookmark */ = {
5026
isa = PBXTextBookmark;
5027
fRef = 94BCAC4E10AB7A2B00F87527 /* NSProcessInfo.h */;
5028
name = "NSProcessInfo.h: 20";
5035
94BCAE6710ACA10100F87527 /* sqSqueakOSXInfoPlistInterface.h */ = {
5037
sepNavIntBoundsRect = "{{0, 0}, {1283, 1066}}";
5038
sepNavSelRange = "{2066, 0}";
5039
sepNavVisRange = "{1327, 2847}";
5040
sepNavWindowFrame = "{{29, 4}, {1326, 1010}}";
5043
94BCAE6810ACA10100F87527 /* sqSqueakOSXInfoPlistInterface.m */ = {
5045
sepNavIntBoundsRect = "{{0, 0}, {1338, 3523}}";
5046
sepNavSelRange = "{2248, 0}";
5047
sepNavVisRange = "{1325, 1573}";
5048
sepNavWindowFrame = "{{15, 45}, {1017, 978}}";
5051
94BCAE9010ACA3A300F87527 /* PBXTextBookmark */ = {
5052
isa = PBXTextBookmark;
5053
fRef = 94BCAE9110ACA3A300F87527 /* NSUserDefaults.h */;
5054
name = "NSUserDefaults.h: 13";
5061
94BCAE9110ACA3A300F87527 /* NSUserDefaults.h */ = {
5062
isa = PBXFileReference;
5063
lastKnownFileType = sourcecode.c.h;
5064
name = NSUserDefaults.h;
5065
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSUserDefaults.h;
5066
sourceTree = "<absolute>";
5068
94BCAE9D10ACA3A300F87527 /* NSBundle.h */ = {
5069
isa = PBXFileReference;
5070
lastKnownFileType = sourcecode.c.h;
5072
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSBundle.h;
5073
sourceTree = "<absolute>";
5075
94BCAEDF10ACAE2500F87527 /* NSValue.h */ = {
5076
isa = PBXFileReference;
5077
lastKnownFileType = sourcecode.c.h;
5079
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSValue.h;
5080
sourceTree = "<absolute>";
5082
94BCAF7D10ACC0D900F87527 /* NSPathUtilities.h */ = {
5083
isa = PBXFileReference;
5084
lastKnownFileType = sourcecode.c.h;
5085
name = NSPathUtilities.h;
5086
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSPathUtilities.h;
5087
sourceTree = "<absolute>";
5089
94BCAFC410ACC89100F87527 /* string.h */ = {
5090
isa = PBXFileReference;
5091
lastKnownFileType = sourcecode.c.h;
5093
path = /Developer/SDKs/MacOSX10.6.sdk/usr/include/string.h;
5094
sourceTree = "<absolute>";
5096
94BCAFC710ACC89100F87527 /* PBXTextBookmark */ = {
5097
isa = PBXTextBookmark;
5098
fRef = 94BCAFC810ACC89100F87527 /* CFBundle.h */;
5099
name = "CFBundle.h: 113";
5106
94BCAFC810ACC89100F87527 /* CFBundle.h */ = {
5107
isa = PBXFileReference;
5108
lastKnownFileType = sourcecode.c.h;
5110
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFBundle.h;
5111
sourceTree = "<absolute>";
5113
94BCAFCA10ACC89100F87527 /* CFURL.h */ = {
5114
isa = PBXFileReference;
5115
lastKnownFileType = sourcecode.c.h;
5117
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFURL.h;
5118
sourceTree = "<absolute>";
5120
94BCE6660DDDEB5000F38F31 /* sqMacHostWindow.h */ = {
5122
sepNavIntBoundsRect = "{{0, 0}, {1279, 936}}";
5123
sepNavSelRange = "{1980, 27}";
5124
sepNavVisRange = "{50, 2646}";
5125
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
5128
94BCE6870DDDECB800F38F31 /* HostWindowPlugin.h */ = {
5130
sepNavIntBoundsRect = "{{0, 0}, {1132, 1040}}";
5131
sepNavSelRange = "{970, 21}";
5132
sepNavVisRange = "{0, 2546}";
5133
sepNavWindowFrame = "{{15, 59}, {1394, 964}}";
5136
94BCE7870DDDF61200F38F31 /* sqUnixUUID.c */ = {
5138
sepNavIntBoundsRect = "{{0, 0}, {1283, 633}}";
5139
sepNavSelRange = "{0, 0}";
5140
sepNavVisRange = "{0, 275}";
5143
94BCE7A60DDDF8F800F38F31 /* sqaio.h */ = {
5145
sepNavIntBoundsRect = "{{0, 0}, {764, 1287}}";
5146
sepNavSelRange = "{4027, 16}";
5147
sepNavVisRange = "{1798, 2290}";
5148
sepNavWindowFrame = "{{84, 127}, {901, 833}}";
5151
94BCE93E0DDE044700F38F31 /* sqSqueakIPhoneApplication+events.h */ = {
5153
sepNavIntBoundsRect = "{{0, 0}, {1338, 637}}";
5154
sepNavSelRange = "{32, 7}";
5155
sepNavVisRange = "{0, 2199}";
5156
sepNavWindowFrame = "{{73, 45}, {905, 983}}";
5159
94BCE93F0DDE044700F38F31 /* sqSqueakIPhoneApplication+events.m */ = {
5161
sepNavIntBoundsRect = "{{0, 0}, {999, 3237}}";
5162
sepNavSelRange = "{2125, 0}";
5163
sepNavVisRange = "{1301, 1753}";
5164
sepNavWindowFrame = "{{310, 45}, {905, 983}}";
5167
94BCEA2B0DDE0C1600F38F31 /* sqMacHostWindow.c */ = {
5169
sepNavIntBoundsRect = "{{0, 0}, {1167, 2756}}";
5170
sepNavSelRange = "{2260, 11}";
5171
sepNavVisRange = "{1052, 1911}";
5172
sepNavWindowFrame = "{{775, 4}, {905, 983}}";
5175
94BCEAF20DDE16B400F38F31 /* sqMacSecurity.c */ = {
5177
sepNavIntBoundsRect = "{{0, 0}, {858, 3341}}";
5178
sepNavSelRange = "{2225, 50}";
5179
sepNavVisRange = "{647, 2896}";
5180
sepNavWindowFrame = "{{15, 40}, {905, 983}}";
5183
94BD816F11C8A58D00556751 /* sqManualSurface.c */ = {
5185
sepNavIntBoundsRect = "{{0, 0}, {1093, 2119}}";
5186
sepNavSelRange = "{360, 20}";
5187
sepNavVisRange = "{0, 2458}";
5188
sepNavWindowFrame = "{{15, 4}, {1140, 1019}}";
5191
94BE8B9C123DA0C900C89FDD /* PBXTextBookmark */ = {
5192
isa = PBXTextBookmark;
5193
fRef = 94BCAD1C10AB942300F87527 /* sqSqueakOSXApplication+attributes.m */;
5194
name = "sqSqueakOSXApplication+attributes.m: 85";
5201
94BE8BAD123DA0EB00C89FDD /* PBXTextBookmark */ = {
5202
isa = PBXTextBookmark;
5203
fRef = 94BCAE6710ACA10100F87527 /* sqSqueakOSXInfoPlistInterface.h */;
5204
name = "sqSqueakOSXInfoPlistInterface.h: 53";
5211
94BE8BD5123DA32300C89FDD /* PBXTextBookmark */ = {
5212
isa = PBXTextBookmark;
5213
fRef = 94BCAE6810ACA10100F87527 /* sqSqueakOSXInfoPlistInterface.m */;
5214
name = "sqSqueakOSXInfoPlistInterface.m: 79";
5221
94BE8BF5123DA42700C89FDD /* PBXTextBookmark */ = {
5222
isa = PBXTextBookmark;
5223
fRef = 94C36A9310B09EE70041953A /* sqSqueakOSXApplication+events.m */;
5224
name = "sqSqueakOSXApplication+events.m: 186";
5231
94C16B42123D72AE00A8622A /* PBXTextBookmark */ = {
5232
isa = PBXTextBookmark;
5233
fRef = 9428BB0510BB478600DAD287 /* sqSqueakOSXApplication+clipboard.m */;
5234
name = "sqSqueakOSXApplication+clipboard.m: 60";
5241
94C16B43123D72AE00A8622A /* PBXTextBookmark */ = {
5242
isa = PBXTextBookmark;
5243
fRef = 9458525B10F043EB001401E7 /* sqSqueakIPhoneApplication+clipboard.m */;
5244
name = "sqSqueakIPhoneApplication+clipboard.m: 24";
5251
94C16B5A123D735F00A8622A /* PBXTextBookmark */ = {
5252
isa = PBXTextBookmark;
5253
fRef = 9452D5E20E044A9D000AD792 /* sqSqueakMainApplication+vmAndImagePath.m */;
5254
name = "sqSqueakMainApplication+vmAndImagePath.m: 87";
5261
94C2068810AF4F53002F4160 /* sqSqueakOSXNSView.h */ = {
5263
sepNavIntBoundsRect = "{{0, 0}, {838, 1157}}";
5264
sepNavSelRange = "{3309, 6}";
5265
sepNavVisRange = "{1747, 1954}";
5266
sepNavWindowFrame = "{{120, 18}, {1326, 1010}}";
5269
94C2068910AF4F53002F4160 /* sqSqueakOSXNSView.m */ = {
5271
sepNavIntBoundsRect = "{{0, 0}, {1132, 9997}}";
5272
sepNavSelRange = "{10089, 0}";
5273
sepNavVisRange = "{6392, 2715}";
5274
sepNavWindowFrame = "{{452, 7}, {1076, 1021}}";
5277
94C206AA10AF5107002F4160 /* NSImageRep.h */ = {
5278
isa = PBXFileReference;
5279
lastKnownFileType = sourcecode.c.h;
5280
name = NSImageRep.h;
5281
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSImageRep.h;
5282
sourceTree = "<absolute>";
5284
94C206D210AF5536002F4160 /* CGImage.h */ = {
5285
isa = PBXFileReference;
5286
lastKnownFileType = sourcecode.c.h;
5288
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGImage.h;
5289
sourceTree = "<absolute>";
5291
94C206D810AF5536002F4160 /* NSGraphicsContext.h */ = {
5292
isa = PBXFileReference;
5293
lastKnownFileType = sourcecode.c.h;
5294
name = NSGraphicsContext.h;
5295
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSGraphicsContext.h;
5296
sourceTree = "<absolute>";
5298
94C206DA10AF5536002F4160 /* CGContext.h */ = {
5299
isa = PBXFileReference;
5300
lastKnownFileType = sourcecode.c.h;
5302
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGContext.h;
5303
sourceTree = "<absolute>";
5305
94C2070610AF5A9E002F4160 /* NSImage.h */ = {
5306
isa = PBXFileReference;
5307
lastKnownFileType = sourcecode.c.h;
5309
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSImage.h;
5310
sourceTree = "<absolute>";
5312
94C2074310AF5FB7002F4160 /* PBXTextBookmark */ = {
5313
isa = PBXTextBookmark;
5314
fRef = 94C206AA10AF5107002F4160 /* NSImageRep.h */;
5315
name = "NSImageRep.h: 45";
5322
94C207E910AF66D7002F4160 /* NSWindow.h */ = {
5323
isa = PBXFileReference;
5324
lastKnownFileType = sourcecode.c.h;
5326
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSWindow.h;
5327
sourceTree = "<absolute>";
5329
94C2091010AF7413002F4160 /* CIImage.h */ = {
5330
isa = PBXFileReference;
5331
lastKnownFileType = sourcecode.c.h;
5333
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/QuartzCore.framework/Versions/A/Headers/CIImage.h;
5334
sourceTree = "<absolute>";
5336
94C2091210AF7413002F4160 /* PBXTextBookmark */ = {
5337
isa = PBXTextBookmark;
5338
fRef = 94C2091310AF7413002F4160 /* NSCIImageRep.h */;
5339
name = "NSCIImageRep.h: 29";
5346
94C2091310AF7413002F4160 /* NSCIImageRep.h */ = {
5347
isa = PBXFileReference;
5348
lastKnownFileType = sourcecode.c.h;
5349
name = NSCIImageRep.h;
5350
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSCIImageRep.h;
5351
sourceTree = "<absolute>";
5353
94C2092A10AF769A002F4160 /* PBXTextBookmark */ = {
5354
isa = PBXTextBookmark;
5355
fRef = 94C2091010AF7413002F4160 /* CIImage.h */;
5356
name = "CIImage.h: 98";
5363
94C2092D10AF769A002F4160 /* PBXTextBookmark */ = {
5364
isa = PBXTextBookmark;
5365
fRef = 94C206D810AF5536002F4160 /* NSGraphicsContext.h */;
5366
name = "NSGraphicsContext.h: 59";
5373
94C367C010AF9C0A0041953A /* PBXTextBookmark */ = {
5374
isa = PBXTextBookmark;
5375
fRef = 94C367C110AF9C0A0041953A /* Aliases.h */;
5376
name = "Aliases.h: 286";
5383
94C367C110AF9C0A0041953A /* Aliases.h */ = {
5384
isa = PBXFileReference;
5385
lastKnownFileType = sourcecode.c.h;
5387
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers/Aliases.h;
5388
sourceTree = "<absolute>";
5390
94C367C210AF9C0A0041953A /* PBXTextBookmark */ = {
5391
isa = PBXTextBookmark;
5392
fRef = 94C367C310AF9C0A0041953A /* LSInfo.h */;
5393
name = "LSInfo.h: 257";
5400
94C367C310AF9C0A0041953A /* LSInfo.h */ = {
5401
isa = PBXFileReference;
5402
lastKnownFileType = sourcecode.c.h;
5404
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Headers/LSInfo.h;
5405
sourceTree = "<absolute>";
5407
94C367D110AF9C830041953A /* PBXTextBookmark */ = {
5408
isa = PBXTextBookmark;
5409
fRef = 94BCAFCA10ACC89100F87527 /* CFURL.h */;
5410
name = "CFURL.h: 636";
5417
94C3682410AFA39A0041953A /* macintoshosxextra.h */ = {
5419
sepNavIntBoundsRect = "{{0, 0}, {996, 770}}";
5420
sepNavSelRange = "{192, 0}";
5421
sepNavVisRange = "{0, 192}";
5424
94C3682510AFA39A0041953A /* macintoshosxextra.c */ = {
5426
sepNavIntBoundsRect = "{{0, 0}, {1338, 572}}";
5427
sepNavSelRange = "{244, 11}";
5428
sepNavVisRange = "{0, 1286}";
5429
sepNavWindowFrame = "{{15, 18}, {1170, 1005}}";
5432
94C3687610AFA77F0041953A /* sqSqueakOSXApplication+cursor.h */ = {
5434
sepNavIntBoundsRect = "{{0, 0}, {1368, 585}}";
5435
sepNavSelRange = "{1874, 6}";
5436
sepNavVisRange = "{0, 2040}";
5437
sepNavWindowFrame = "{{38, 24}, {1017, 978}}";
5440
94C3687710AFA77F0041953A /* sqSqueakOSXApplication+cursor.m */ = {
5442
sepNavIntBoundsRect = "{{0, 0}, {1167, 2041}}";
5443
sepNavSelRange = "{3586, 18}";
5444
sepNavVisRange = "{2779, 1505}";
5445
sepNavWindowFrame = "{{299, 9}, {1426, 1019}}";
5448
94C3687B10AFA8300041953A /* sqSqueakCursorAPI.h */ = {
5450
sepNavIntBoundsRect = "{{0, 0}, {1368, 616}}";
5451
sepNavSelRange = "{9, 12}";
5452
sepNavVisRange = "{0, 1788}";
5455
94C3687C10AFA8300041953A /* sqSqueakCursorAPI.m */ = {
5457
sepNavIntBoundsRect = "{{0, 0}, {1338, 858}}";
5458
sepNavSelRange = "{2250, 19}";
5459
sepNavVisRange = "{640, 2163}";
5460
sepNavWindowFrame = "{{38, 19}, {905, 983}}";
5463
94C3688A10AFA9EF0041953A /* sqSqueakMainApplication+cursor.h */ = {
5465
sepNavIntBoundsRect = "{{0, 0}, {1368, 585}}";
5466
sepNavSelRange = "{1949, 6}";
5467
sepNavVisRange = "{0, 2021}";
5470
94C3688B10AFA9EF0041953A /* sqSqueakMainApplication+cursor.m */ = {
5472
sepNavIntBoundsRect = "{{0, 0}, {1368, 624}}";
5473
sepNavSelRange = "{1961, 6}";
5474
sepNavVisRange = "{62, 1980}";
5477
94C368F610AFAEA60041953A /* QuickdrawTypes.h */ = {
5478
isa = PBXFileReference;
5479
lastKnownFileType = sourcecode.c.h;
5480
name = QuickdrawTypes.h;
5481
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/QD.framework/Versions/A/Headers/QuickdrawTypes.h;
5482
sourceTree = "<absolute>";
5484
94C368F910AFAEA60041953A /* CFByteOrder.h */ = {
5485
isa = PBXFileReference;
5486
lastKnownFileType = sourcecode.c.h;
5487
name = CFByteOrder.h;
5488
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFByteOrder.h;
5489
sourceTree = "<absolute>";
5491
94C3696310AFB7550041953A /* NSGraphics.h */ = {
5492
isa = PBXFileReference;
5493
lastKnownFileType = sourcecode.c.h;
5494
name = NSGraphics.h;
5495
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSGraphics.h;
5496
sourceTree = "<absolute>";
5498
94C3696410AFB7550041953A /* PBXTextBookmark */ = {
5499
isa = PBXTextBookmark;
5500
fRef = 94C368F610AFAEA60041953A /* QuickdrawTypes.h */;
5501
name = "QuickdrawTypes.h: 262";
5508
94C3696610AFB7550041953A /* NSBitmapImageRep.h */ = {
5509
isa = PBXFileReference;
5510
lastKnownFileType = sourcecode.c.h;
5511
name = NSBitmapImageRep.h;
5512
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSBitmapImageRep.h;
5513
sourceTree = "<absolute>";
5515
94C3698D10B082DF0041953A /* PBXTextBookmark */ = {
5516
isa = PBXTextBookmark;
5517
fRef = 94C368F910AFAEA60041953A /* CFByteOrder.h */;
5518
name = "CFByteOrder.h: 78";
5525
94C3699110B082DF0041953A /* PBXTextBookmark */ = {
5526
isa = PBXTextBookmark;
5527
fRef = 94C3699210B082DF0041953A /* NSColor.h */;
5528
name = "NSColor.h: 65";
5535
94C3699210B082DF0041953A /* NSColor.h */ = {
5536
isa = PBXFileReference;
5537
lastKnownFileType = sourcecode.c.h;
5539
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSColor.h;
5540
sourceTree = "<absolute>";
5542
94C36A6D10B091BB0041953A /* NSCursor.h */ = {
5543
isa = PBXFileReference;
5544
lastKnownFileType = sourcecode.c.h;
5546
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSCursor.h;
5547
sourceTree = "<absolute>";
5549
94C36A9210B09EE70041953A /* sqSqueakOSXApplication+events.h */ = {
5551
sepNavIntBoundsRect = "{{0, 0}, {1338, 728}}";
5552
sepNavSelRange = "{1980, 16}";
5553
sepNavVisRange = "{108, 2800}";
5554
sepNavWindowFrame = "{{149, 4}, {905, 983}}";
5557
94C36A9310B09EE70041953A /* sqSqueakOSXApplication+events.m */ = {
5559
sepNavIntBoundsRect = "{{0, 0}, {1412, 5291}}";
5560
sepNavSelRange = "{7917, 0}";
5561
sepNavVisRange = "{6896, 1653}";
5562
sepNavWindowFrame = "{{385, 4}, {1131, 1019}}";
5565
94C36AD910B0AF960041953A /* NSEvent.h */ = {
5566
isa = PBXFileReference;
5567
lastKnownFileType = sourcecode.c.h;
5569
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSEvent.h;
5570
sourceTree = "<absolute>";
5572
94C36C9710B0CF290041953A /* Info-iPhone.plist */ = {
5574
sepNavWindowFrame = "{{15, 55}, {1438, 968}}";
5577
94C3CD4E1235C80200A4E319 /* PBXTextBookmark */ = {
5578
isa = PBXTextBookmark;
5579
fRef = 9402DD6F10CE0E91005C2102 /* SqViewClut.m */;
5580
name = "SqViewClut.m: 13";
5587
94C4B80F10C06C4700CD4F90 /* configx.h */ = {
5589
sepNavIntBoundsRect = "{{0, 0}, {994, 799}}";
5590
sepNavSelRange = "{0, 0}";
5591
sepNavVisRange = "{0, 1946}";
5594
94C4B82E10C06F8800CD4F90 /* sqSqueakOSXSoundCoreAudio.h */ = {
5596
sepNavIntBoundsRect = "{{0, 0}, {1109, 724}}";
5597
sepNavSelRange = "{1876, 22}";
5598
sepNavVisRange = "{0, 1939}";
5601
94C4B82F10C06F8800CD4F90 /* sqSqueakOSXSoundCoreAudio.m */ = {
5603
sepNavIntBoundsRect = "{{0, 0}, {1368, 793}}";
5604
sepNavSelRange = "{1951, 5}";
5605
sepNavVisRange = "{1559, 486}";
5606
sepNavWindowFrame = "{{15, 4}, {1426, 1019}}";
5609
94C7480712333A2900B1F982 /* PBXTextBookmark */ = {
5610
isa = PBXTextBookmark;
5611
fRef = 94A1B21B10B9DE0300C64473 /* keyBoardStrokeDetails.m */;
5612
name = "keyBoardStrokeDetails.m: 42";
5619
94C748E012333EE900B1F982 /* sqMacUIEventsUniversal.c:1113 */ = {
5620
isa = PBXFileBreakpoint;
5623
breakpointStyle = 0;
5624
continueAfterActions = 0;
5626
delayBeforeContinue = 0;
5627
fileReference = 94C748E112333EE900B1F982 /* sqMacUIEventsUniversal.c */;
5628
functionName = "recordKeyboardEventCarbon()";
5632
modificationTime = 308445393.436654;
5633
originalNumberOfMultipleMatches = 1;
5636
94C748E112333EE900B1F982 /* sqMacUIEventsUniversal.c */ = {
5637
isa = PBXFileReference;
5638
lastKnownFileType = sourcecode.c.c;
5639
name = sqMacUIEventsUniversal.c;
5640
path = "/Volumes/330GB Photos/Cog Before Aug 2010 changes/platforms/Mac OS/vm/sqMacUIEventsUniversal.c";
5641
sourceTree = "<absolute>";
5643
94C887D410ADCC0D007CB39E /* PBXTextBookmark */ = {
5644
isa = PBXTextBookmark;
5645
fRef = 94C887D510ADCC0D007CB39E /* NSThread.h */;
5646
name = "NSThread.h: 75";
5653
94C887D510ADCC0D007CB39E /* NSThread.h */ = {
5654
isa = PBXFileReference;
5655
lastKnownFileType = sourcecode.c.h;
5657
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSThread.h;
5658
sourceTree = "<absolute>";
5660
94C887F910ADCEFC007CB39E /* sqSqueakOSXApplication+imageReadWrite.h */ = {
5662
sepNavIntBoundsRect = "{{0, 0}, {908, 585}}";
5663
sepNavSelRange = "{1939, 0}";
5664
sepNavVisRange = "{47, 1963}";
5667
94C887FA10ADCEFC007CB39E /* sqSqueakOSXApplication+imageReadWrite.m */ = {
5669
sepNavIntBoundsRect = "{{0, 0}, {838, 1820}}";
5670
sepNavSelRange = "{2709, 0}";
5671
sepNavVisRange = "{1953, 1821}";
5672
sepNavWindowFrame = "{{685, 4}, {878, 1019}}";
5675
94C888B710ADE75B007CB39E /* PBXTextBookmark */ = {
5676
isa = PBXTextBookmark;
5677
fRef = 94BCAE9D10ACA3A300F87527 /* NSBundle.h */;
5678
name = "NSBundle.h: 11";
5685
94C88B6810AF26F8007CB39E /* PBXTextBookmark */ = {
5686
isa = PBXTextBookmark;
5687
fRef = 94C88B6910AF26F8007CB39E /* squeakProxy.m */;
5688
name = "squeakProxy.m: 124";
5695
94C88B6910AF26F8007CB39E /* squeakProxy.m */ = {
5696
isa = PBXFileReference;
5697
lastKnownFileType = sourcecode.c.objc;
5698
name = squeakProxy.m;
5699
path = "/Volumes/px2/business/SqueakiPhone/SqueakObjCBasedForOSXAndIPhone/Blob/platforms/Mac OSObjC/plugins/SqueakObjectiveC/squeakProxy.m";
5700
sourceTree = "<absolute>";
5702
94C88BDD10AF3C52007CB39E /* sqSqueakOSXScreenAndWindow.h */ = {
5704
sepNavIntBoundsRect = "{{0, 0}, {1345, 891}}";
5705
sepNavSelRange = "{1866, 43}";
5706
sepNavVisRange = "{0, 2111}";
5707
sepNavWindowFrame = "{{15, 4}, {1392, 1019}}";
5710
94C88BDE10AF3C52007CB39E /* sqSqueakOSXScreenAndWindow.m */ = {
5712
sepNavIntBoundsRect = "{{0, 0}, {1167, 962}}";
5713
sepNavSelRange = "{2578, 17}";
5714
sepNavVisRange = "{786, 1864}";
5715
sepNavWindowFrame = "{{15, 49}, {1346, 974}}";
5718
94C88C0E10AF4196007CB39E /* NSGeometry.h */ = {
5719
isa = PBXFileReference;
5720
lastKnownFileType = sourcecode.c.h;
5721
name = NSGeometry.h;
5722
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSGeometry.h;
5723
sourceTree = "<absolute>";
5725
94C8D195123EDACE0019544B /* SqueakUIViewOpenGL.m:135 */ = {
5726
isa = PBXFileBreakpoint;
5729
breakpointStyle = 0;
5730
continueAfterActions = 0;
5732
delayBeforeContinue = 0;
5733
fileReference = 942F48FD123C1C0C002B05DF /* SqueakUIViewOpenGL.m */;
5734
functionName = "-layoutSubviews";
5739
modificationTime = 308445394.455894;
5740
originalNumberOfMultipleMatches = 1;
5743
94C8D197123EDAD30019544B /* PBXTextBookmark */ = {
5744
isa = PBXTextBookmark;
5745
fRef = 9452D7630E0452D3000AD792 /* sqiPhoneScreenAndWindow.h */;
5746
name = "sqiPhoneScreenAndWindow.h: 42";
5753
94C8D19A123EDAD30019544B /* PBXTextBookmark */ = {
5754
isa = PBXTextBookmark;
5755
fRef = 94BCE93F0DDE044700F38F31 /* sqSqueakIPhoneApplication+events.m */;
5756
name = "sqSqueakIPhoneApplication+events.m: 51";
5763
94C8D19B123EDAD30019544B /* PBXTextBookmark */ = {
5764
isa = PBXTextBookmark;
5765
fRef = 1D3623250D0F684500981E51 /* SqueakNoOGLIPhoneAppDelegate.m */;
5766
name = "SqueakNoOGLIPhoneAppDelegate.m: 138";
5773
94C8D19C123EDAD30019544B /* PBXTextBookmark */ = {
5774
isa = PBXTextBookmark;
5775
fRef = 940CE8550DFCE2D200EBA91B /* SqueakUIController.m */;
5776
name = "SqueakUIController.m: 94";
5783
94CAE0ED1230DE6C00AFE487 /* PBXTextBookmark */ = {
5784
isa = PBXTextBookmark;
5785
fRef = 941724420F36624C0031AF33 /* squeakProxy.m */;
5786
name = "squeakProxy.m: 49";
5793
94CFE6A910BE63A900847DF5 /* PBXTextBookmark */ = {
5794
isa = PBXTextBookmark;
5795
fRef = 94C207E910AF66D7002F4160 /* NSWindow.h */;
5796
name = "NSWindow.h: 453";
5803
94CFE6B810BE63A900847DF5 /* PBXTextBookmark */ = {
5804
isa = PBXTextBookmark;
5805
fRef = 9406E87510B66A74002F81F2 /* SqueakInterpreterEventSensor.m */;
5806
name = "SqueakInterpreterEventSensor.m: 54";
5813
94CFE6B910BE63A900847DF5 /* PBXTextBookmark */ = {
5814
isa = PBXTextBookmark;
5815
fRef = 94F89AED10B497F400556475 /* NSResponder.h */;
5816
name = "NSResponder.h: 31";
5823
94CFE6BD10BE63A900847DF5 /* SqViewEventSensor.m */ = {
5824
isa = PBXFileReference;
5825
lastKnownFileType = sourcecode.c.objc;
5826
name = SqViewEventSensor.m;
5827
path = "/Users/johnmci/Work In Progress/smalltalk/CocoaSqueakSource/SqueakAppKit/SqViewEventSensor.m";
5828
sourceTree = "<absolute>";
5830
94CFE6C010BE63A900847DF5 /* PBXTextBookmark */ = {
5831
isa = PBXTextBookmark;
5832
fRef = 945BA53B10B218F700C2020C /* math.h */;
5833
name = "math.h: 379";
5840
94CFE70110BE683800847DF5 /* PBXTextBookmark */ = {
5841
isa = PBXTextBookmark;
5842
fRef = 94C36AD910B0AF960041953A /* NSEvent.h */;
5843
name = "NSEvent.h: 246";
5850
94D16BFC10BCEFEE00A69A89 /* PBXTextBookmark */ = {
5851
isa = PBXTextBookmark;
5852
fRef = 94D16BFD10BCEFEE00A69A89 /* Document.m */;
5853
name = "Document.m: 35";
5860
94D16BFD10BCEFEE00A69A89 /* Document.m */ = {
5861
isa = PBXFileReference;
5862
lastKnownFileType = sourcecode.c.objc;
5864
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/CocoaSqueak/Document.m";
5865
sourceTree = "<absolute>";
5867
94D16BFE10BCEFEE00A69A89 /* PBXTextBookmark */ = {
5868
isa = PBXTextBookmark;
5869
fRef = 942CF46B10BCE44B009BD905 /* NSWindowController.h */;
5870
name = "NSWindowController.h: 13";
5877
94D16C2A10BCF28A00A69A89 /* PBXTextBookmark */ = {
5878
isa = PBXTextBookmark;
5879
fRef = 9428BBE210BB565100DAD287 /* sqUnixQuartz.m */;
5880
name = "sqUnixQuartz.m: 1031";
5887
94D16C4010BCF3E100A69A89 /* PBXTextBookmark */ = {
5888
isa = PBXTextBookmark;
5889
fRef = 94D16C4110BCF3E100A69A89 /* CGDirectDisplay.h */;
5890
name = "CGDirectDisplay.h: 336";
5897
94D16C4110BCF3E100A69A89 /* CGDirectDisplay.h */ = {
5898
isa = PBXFileReference;
5899
lastKnownFileType = sourcecode.c.h;
5900
name = CGDirectDisplay.h;
5901
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGDirectDisplay.h;
5902
sourceTree = "<absolute>";
5904
94D16C6510BCF5B700A69A89 /* NSApplication.h */ = {
5905
isa = PBXFileReference;
5906
lastKnownFileType = sourcecode.c.h;
5907
name = NSApplication.h;
5908
path = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSApplication.h;
5909
sourceTree = "<absolute>";
5911
94D16CA310BCF93000A69A89 /* PBXTextBookmark */ = {
5912
isa = PBXTextBookmark;
5913
fRef = 94D16C6510BCF5B700A69A89 /* NSApplication.h */;
5914
name = "NSApplication.h: 269";
5921
94D16CAF10BCF96B00A69A89 /* Credits.rtf */ = {
5923
sepNavIntBoundsRect = "{{0, 0}, {1140, 649}}";
5924
sepNavSelRange = "{269, 0}";
5925
sepNavVisRect = "{{0, 0}, {1140, 649}}";
5926
sepNavWindowFrame = "{{175, 9}, {878, 1019}}";
5929
94D3654D10CEC86C00805023 /* BitMapConversionLogicFromX11.h */ = {
5931
sepNavIntBoundsRect = "{{0, 0}, {1167, 804}}";
5932
sepNavSelRange = "{581, 14}";
5933
sepNavVisRange = "{0, 1092}";
5934
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
5937
94D3654E10CEC86C00805023 /* BitMapConversionLogicFromX11.c */ = {
5939
sepNavIntBoundsRect = "{{0, 0}, {1167, 3029}}";
5940
sepNavSelRange = "{1749, 84}";
5941
sepNavVisRange = "{1650, 1795}";
5942
sepNavWindowFrame = "{{715, -46}, {1326, 1010}}";
5945
94D3660B10CEE03900805023 /* PBXTextBookmark */ = {
5946
isa = PBXTextBookmark;
5947
fRef = 94D3660C10CEE03900805023 /* CIImage.h */;
5948
name = "CIImage.h: 32";
5955
94D3660C10CEE03900805023 /* CIImage.h */ = {
5956
isa = PBXFileReference;
5957
lastKnownFileType = sourcecode.c.h;
5959
path = /System/Library/Frameworks/QuartzCore.framework/Versions/A/Headers/CIImage.h;
5960
sourceTree = "<absolute>";
5962
94D715CB10B723B200F69A71 /* PBXTextBookmark */ = {
5963
isa = PBXTextBookmark;
5964
fRef = 94D715CC10B723B200F69A71 /* NSData.h */;
5965
name = "NSData.h: 45";
5972
94D715CC10B723B200F69A71 /* NSData.h */ = {
5973
isa = PBXFileReference;
5974
lastKnownFileType = sourcecode.c.h;
5976
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSData.h;
5977
sourceTree = "<absolute>";
5979
94D7173610B72F8800F69A71 /* FunctionKeyNames.strings */ = {
5980
isa = PBXFileReference;
5981
lastKnownFileType = text.plist.strings;
5982
name = FunctionKeyNames.strings;
5983
path = /System/Library/Frameworks/AppKit.framework/Versions/C/Resources/English.lproj/FunctionKeyNames.strings;
5984
sourceTree = "<absolute>";
5986
94D7174110B72FDF00F69A71 /* PBXTextBookmark */ = {
5987
isa = PBXTextBookmark;
5988
fRef = 94D7173610B72F8800F69A71 /* FunctionKeyNames.strings */;
5989
name = "FunctionKeyNames.strings: 2";
5996
94D7177D10B73A3800F69A71 /* PBXTextBookmark */ = {
5997
isa = PBXTextBookmark;
5998
fRef = 94D7177E10B73A3800F69A71 /* SqueakEventQueue.m */;
5999
name = "SqueakEventQueue.m: 90";
6006
94D7177E10B73A3800F69A71 /* SqueakEventQueue.m */ = {
6007
isa = PBXFileReference;
6008
lastKnownFileType = sourcecode.c.objc;
6009
name = SqueakEventQueue.m;
6010
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/Squeak/SqueakEventQueue.m";
6011
sourceTree = "<absolute>";
6013
94D7178010B73A3800F69A71 /* SqueakInterpreterEventSensor.m */ = {
6014
isa = PBXFileReference;
6015
lastKnownFileType = sourcecode.c.objc;
6016
name = SqueakInterpreterEventSensor.m;
6017
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/Squeak/SqueakInterpreterEventSensor.m";
6018
sourceTree = "<absolute>";
6020
94D7178310B73A3800F69A71 /* SqViewInputSensor.m */ = {
6021
isa = PBXFileReference;
6022
lastKnownFileType = sourcecode.c.objc;
6023
name = SqViewInputSensor.m;
6024
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/SqueakAppKit/SqViewInputSensor.m";
6025
sourceTree = "<absolute>";
6027
94D7178410B73A3800F69A71 /* PBXTextBookmark */ = {
6028
isa = PBXTextBookmark;
6029
fRef = 94D7178510B73A3800F69A71 /* SqueakController.m */;
6030
name = "SqueakController.m: 1";
6037
94D7178510B73A3800F69A71 /* SqueakController.m */ = {
6038
isa = PBXFileReference;
6039
lastKnownFileType = sourcecode.c.objc;
6040
name = SqueakController.m;
6041
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/CocoaSqueak/SqueakController.m";
6042
sourceTree = "<absolute>";
6044
94D7178610B73A3800F69A71 /* PBXTextBookmark */ = {
6045
isa = PBXTextBookmark;
6046
fRef = 94D7178710B73A3800F69A71 /* SqViewBitmapConversion.m */;
6047
name = "SqViewBitmapConversion.m: 1";
6054
94D7178710B73A3800F69A71 /* SqViewBitmapConversion.m */ = {
6055
isa = PBXFileReference;
6056
lastKnownFileType = sourcecode.c.objc;
6057
name = SqViewBitmapConversion.m;
6058
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/SqueakAppKit/SqViewBitmapConversion.m";
6059
sourceTree = "<absolute>";
6061
94D7178810B73A3800F69A71 /* PBXTextBookmark */ = {
6062
isa = PBXTextBookmark;
6063
fRef = 94D7178910B73A3800F69A71 /* SqView.m */;
6064
name = "SqView.m: 1";
6071
94D7178910B73A3800F69A71 /* SqView.m */ = {
6072
isa = PBXFileReference;
6073
lastKnownFileType = sourcecode.c.objc;
6075
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/SqueakAppKit/SqView.m";
6076
sourceTree = "<absolute>";
6078
94D7178A10B73A3800F69A71 /* PBXTextBookmark */ = {
6079
isa = PBXTextBookmark;
6080
fRef = 94D7178B10B73A3800F69A71 /* SqClipboardHandler.m */;
6081
name = "SqClipboardHandler.m: 1";
6088
94D7178B10B73A3800F69A71 /* SqClipboardHandler.m */ = {
6089
isa = PBXFileReference;
6090
lastKnownFileType = sourcecode.c.objc;
6091
name = SqClipboardHandler.m;
6092
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/SqueakAppKit/SqClipboardHandler.m";
6093
sourceTree = "<absolute>";
6095
94D7178C10B73A3800F69A71 /* PBXTextBookmark */ = {
6096
isa = PBXTextBookmark;
6097
fRef = 94D7178D10B73A3800F69A71 /* CarbonSound.c */;
6098
name = "CarbonSound.c: 1";
6105
94D7178D10B73A3800F69A71 /* CarbonSound.c */ = {
6106
isa = PBXFileReference;
6107
lastKnownFileType = sourcecode.c.c;
6108
name = CarbonSound.c;
6109
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/SqueakAppKit/CarbonSound.c";
6110
sourceTree = "<absolute>";
6112
94D7178F10B73A3800F69A71 /* SqueakInterpreterEventSensor.h */ = {
6113
isa = PBXFileReference;
6114
lastKnownFileType = sourcecode.c.h;
6115
name = SqueakInterpreterEventSensor.h;
6116
path = "/Users/johnmci/Documents/Squeak/CocoaSqueak-3.0.4/src/Squeak/SqueakInterpreterEventSensor.h";
6117
sourceTree = "<absolute>";
6119
94D7179110B73A3800F69A71 /* PBXTextBookmark */ = {
6120
isa = PBXTextBookmark;
6121
fRef = 94D7179210B73A3800F69A71 /* FScriptTextView.m */;
6122
name = "FScriptTextView.m: 126";
6129
94D7179210B73A3800F69A71 /* FScriptTextView.m */ = {
6130
isa = PBXFileReference;
6131
lastKnownFileType = sourcecode.c.objc;
6132
name = FScriptTextView.m;
6133
path = "/Users/johnmci/Work In Progress/smalltalk/FScriptSources-20031020/FScript/FScriptFramework/FScriptTextView.m";
6134
sourceTree = "<absolute>";
6136
94D717BE10B73DD900F69A71 /* PBXTextBookmark */ = {
6137
isa = PBXTextBookmark;
6138
fRef = 9406E8D110B67499002F81F2 /* NSRange.h */;
6139
name = "NSRange.h: 12";
6146
94D717E610B7421F00F69A71 /* sqUnixQuartz.m */ = {
6147
isa = PBXFileReference;
6148
lastKnownFileType = sourcecode.c.objc;
6149
name = sqUnixQuartz.m;
6150
path = "/Users/johnmci/Documents/SqueakSparklePlugin/platforms/unix/vm-display-Quartz/sqUnixQuartz.m";
6151
sourceTree = "<absolute>";
6153
94D717F810B743B800F69A71 /* PBXTextBookmark */ = {
6154
isa = PBXTextBookmark;
6155
fRef = 94D717E610B7421F00F69A71 /* sqUnixQuartz.m */;
6156
name = "sqUnixQuartz.m: 2301";
6163
94D7183810B74BF300F69A71 /* PBXTextBookmark */ = {
6164
isa = PBXTextBookmark;
6165
fRef = 94D7183910B74BF300F69A71 /* NSInputManager.h */;
6166
name = "NSInputManager.h: 21";
6173
94D7183910B74BF300F69A71 /* NSInputManager.h */ = {
6174
isa = PBXFileReference;
6175
lastKnownFileType = sourcecode.c.h;
6176
name = NSInputManager.h;
6177
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSInputManager.h;
6178
sourceTree = "<absolute>";
6180
94D7183A10B74BF300F69A71 /* PBXTextBookmark */ = {
6181
isa = PBXTextBookmark;
6182
fRef = 94D7183B10B74BF300F69A71 /* NSTextInputClient.h */;
6183
name = "NSTextInputClient.h: 32";
6190
94D7183B10B74BF300F69A71 /* NSTextInputClient.h */ = {
6191
isa = PBXFileReference;
6192
lastKnownFileType = sourcecode.c.h;
6193
name = NSTextInputClient.h;
6194
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSTextInputClient.h;
6195
sourceTree = "<absolute>";
6197
94D73E5210B5B9CE00F8C034 /* PBXTextBookmark */ = {
6198
isa = PBXTextBookmark;
6199
fRef = 94D73E5310B5B9CE00F8C034 /* cl.h */;
6207
94D73E5310B5B9CE00F8C034 /* cl.h */ = {
6208
isa = PBXFileReference;
6209
lastKnownFileType = sourcecode.c.h;
6211
path = /System/Library/Frameworks/OpenCL.framework/Versions/A/Headers/cl.h;
6212
sourceTree = "<absolute>";
6214
94D73E5410B5B9CE00F8C034 /* PBXTextBookmark */ = {
6215
isa = PBXTextBookmark;
6216
fRef = 94D73E5510B5B9CE00F8C034 /* float-i32.h */;
6217
name = "float-i32.h: 20";
6224
94D73E5510B5B9CE00F8C034 /* float-i32.h */ = {
6225
isa = PBXFileReference;
6226
lastKnownFileType = sourcecode.c.h;
6227
name = "float-i32.h";
6228
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/config/float-i32.h";
6229
sourceTree = "<absolute>";
6231
94D73E5610B5B9CE00F8C034 /* PBXTextBookmark */ = {
6232
isa = PBXTextBookmark;
6233
fRef = 94D73E5710B5B9CE00F8C034 /* float-i128.h */;
6234
name = "float-i128.h: 19";
6241
94D73E5710B5B9CE00F8C034 /* float-i128.h */ = {
6242
isa = PBXFileReference;
6243
lastKnownFileType = sourcecode.c.h;
6244
name = "float-i128.h";
6245
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/config/float-i128.h";
6246
sourceTree = "<absolute>";
6248
94D73E5810B5B9CE00F8C034 /* PBXTextBookmark */ = {
6249
isa = PBXTextBookmark;
6250
fRef = 94D73E5910B5B9CE00F8C034 /* float-i386.h */;
6251
name = "float-i386.h: 20";
6258
94D73E5910B5B9CE00F8C034 /* float-i386.h */ = {
6259
isa = PBXFileReference;
6260
lastKnownFileType = sourcecode.c.h;
6261
name = "float-i386.h";
6262
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/config/float-i386.h";
6263
sourceTree = "<absolute>";
6265
94D73E5A10B5B9CE00F8C034 /* PBXTextBookmark */ = {
6266
isa = PBXTextBookmark;
6267
fRef = 94D73E5B10B5B9CE00F8C034 /* float-m68k.h */;
6268
name = "float-m68k.h: 20";
6275
94D73E5B10B5B9CE00F8C034 /* float-m68k.h */ = {
6276
isa = PBXFileReference;
6277
lastKnownFileType = sourcecode.c.h;
6278
name = "float-m68k.h";
6279
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/config/float-m68k.h";
6280
sourceTree = "<absolute>";
6282
94D73E5C10B5B9CE00F8C034 /* PBXTextBookmark */ = {
6283
isa = PBXTextBookmark;
6284
fRef = 94D73E5D10B5B9CE00F8C034 /* float-sh.h */;
6285
name = "float-sh.h: 19";
6292
94D73E5D10B5B9CE00F8C034 /* float-sh.h */ = {
6293
isa = PBXFileReference;
6294
lastKnownFileType = sourcecode.c.h;
6295
name = "float-sh.h";
6296
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/config/float-sh.h";
6297
sourceTree = "<absolute>";
6299
94D73E5E10B5B9CE00F8C034 /* PBXTextBookmark */ = {
6300
isa = PBXTextBookmark;
6301
fRef = 94D73E5F10B5B9CE00F8C034 /* float-sparc.h */;
6302
name = "float-sparc.h: 20";
6309
94D73E5F10B5B9CE00F8C034 /* float-sparc.h */ = {
6310
isa = PBXFileReference;
6311
lastKnownFileType = sourcecode.c.h;
6312
name = "float-sparc.h";
6313
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/config/float-sparc.h";
6314
sourceTree = "<absolute>";
6316
94D73E6010B5B9CE00F8C034 /* PBXTextBookmark */ = {
6317
isa = PBXTextBookmark;
6318
fRef = 94D73E6110B5B9CE00F8C034 /* float-vax.h */;
6319
name = "float-vax.h: 6";
6326
94D73E6110B5B9CE00F8C034 /* float-vax.h */ = {
6327
isa = PBXFileReference;
6328
lastKnownFileType = sourcecode.c.h;
6329
name = "float-vax.h";
6330
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/config/float-vax.h";
6331
sourceTree = "<absolute>";
6333
94D73E6210B5B9CE00F8C034 /* PBXTextBookmark */ = {
6334
isa = PBXTextBookmark;
6335
fRef = 94D73E6310B5B9CE00F8C034 /* float-i64.h */;
6336
name = "float-i64.h: 20";
6343
94D73E6310B5B9CE00F8C034 /* float-i64.h */ = {
6344
isa = PBXFileReference;
6345
lastKnownFileType = sourcecode.c.h;
6346
name = "float-i64.h";
6347
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/config/float-i64.h";
6348
sourceTree = "<absolute>";
6350
94D73E6410B5B9CE00F8C034 /* PBXTextBookmark */ = {
6351
isa = PBXTextBookmark;
6352
fRef = 94D73E6510B5B9CE00F8C034 /* dummyFFI.c */;
6353
name = "dummyFFI.c: 116";
6360
94D73E6510B5B9CE00F8C034 /* dummyFFI.c */ = {
6361
isa = PBXFileReference;
6362
lastKnownFileType = sourcecode.c.c;
6364
path = /Users/johnmci/Shared/plugins/SqueakFFIPrims/dummyFFI.c;
6365
sourceTree = "<absolute>";
6367
94D73E6810B5B9CE00F8C034 /* PBXTextBookmark */ = {
6368
isa = PBXTextBookmark;
6369
fRef = 94D73E6910B5B9CE00F8C034 /* c90-float-1.c */;
6370
name = "c90-float-1.c: 47";
6377
94D73E6910B5B9CE00F8C034 /* c90-float-1.c */ = {
6378
isa = PBXFileReference;
6379
lastKnownFileType = sourcecode.c.c;
6380
name = "c90-float-1.c";
6381
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/testsuite/gcc.dg/c90-float-1.c";
6382
sourceTree = "<absolute>";
6384
94D73E6A10B5B9CE00F8C034 /* PBXTextBookmark */ = {
6385
isa = PBXTextBookmark;
6386
fRef = 94D73E6B10B5B9CE00F8C034 /* enquire.c */;
6387
name = "enquire.c: 1232";
6394
94D73E6B10B5B9CE00F8C034 /* enquire.c */ = {
6395
isa = PBXFileReference;
6396
lastKnownFileType = sourcecode.c.c;
6398
path = "/Users/johnmci/Documents/Files from Lamie/Documents/Darwin/gcc3-1151/gcc/enquire.c";
6399
sourceTree = "<absolute>";
6401
94D73EE610B5CF8400F8C034 /* PBXTextBookmark */ = {
6402
isa = PBXTextBookmark;
6403
fRef = 94F89C5A10B4BF2800556475 /* NSRunLoop.h */;
6404
name = "NSRunLoop.h: 30";
6411
94D73F4910B5DA4E00F8C034 /* PBXTextBookmark */ = {
6412
isa = PBXTextBookmark;
6413
fRef = 942ABE0910AA21270086D908 /* NSView.h */;
6414
name = "NSView.h: 219";
6421
94D73FA010B5E5A200F8C034 /* PBXTextBookmark */ = {
6422
isa = PBXTextBookmark;
6423
fRef = 94D73FA110B5E5A200F8C034 /* CIColor.h */;
6424
name = "CIColor.h: 50";
6431
94D73FA110B5E5A200F8C034 /* CIColor.h */ = {
6432
isa = PBXFileReference;
6433
lastKnownFileType = sourcecode.c.h;
6435
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/QuartzCore.framework/Versions/A/Headers/CIColor.h;
6436
sourceTree = "<absolute>";
6438
94D73FA410B5E5A200F8C034 /* CGColor.h */ = {
6439
isa = PBXFileReference;
6440
lastKnownFileType = sourcecode.c.h;
6442
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGColor.h;
6443
sourceTree = "<absolute>";
6445
94D73FAD10B5E69900F8C034 /* PBXTextBookmark */ = {
6446
isa = PBXTextBookmark;
6447
fRef = 94D73FA410B5E5A200F8C034 /* CGColor.h */;
6448
name = "CGColor.h: 44";
6455
94D73FB510B5E6DA00F8C034 /* PBXTextBookmark */ = {
6456
isa = PBXTextBookmark;
6457
fRef = 94C206DA10AF5536002F4160 /* CGContext.h */;
6458
name = "CGContext.h: 402";
6465
94D7401510B5F8AF00F8C034 /* PBXTextBookmark */ = {
6466
isa = PBXTextBookmark;
6467
fRef = 94C2070610AF5A9E002F4160 /* NSImage.h */;
6468
name = "NSImage.h: 187";
6475
94D7402810B5FA6100F8C034 /* CGDataProvider.h */ = {
6476
isa = PBXFileReference;
6477
lastKnownFileType = sourcecode.c.h;
6478
name = CGDataProvider.h;
6479
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGDataProvider.h;
6480
sourceTree = "<absolute>";
6482
94D7403810B5FDDB00F8C034 /* PBXTextBookmark */ = {
6483
isa = PBXTextBookmark;
6484
fRef = 94C206D210AF5536002F4160 /* CGImage.h */;
6485
name = "CGImage.h: 56";
6492
94D7403A10B5FDDB00F8C034 /* PBXTextBookmark */ = {
6493
isa = PBXTextBookmark;
6494
fRef = 94D7402810B5FA6100F8C034 /* CGDataProvider.h */;
6495
name = "CGDataProvider.h: 114";
6502
94D740B210B6242000F8C034 /* PBXTextBookmark */ = {
6503
isa = PBXTextBookmark;
6504
fRef = 94D740B310B6242000F8C034 /* mman.h */;
6505
name = "mman.h: 161";
6512
94D740B310B6242000F8C034 /* mman.h */ = {
6513
isa = PBXFileReference;
6514
lastKnownFileType = sourcecode.c.h;
6516
path = /Developer/SDKs/MacOSX10.6.sdk/usr/include/sys/mman.h;
6517
sourceTree = "<absolute>";
6519
94E1BDAB11E5A9F400D5B92B /* PBXTextBookmark */ = {
6520
isa = PBXTextBookmark;
6521
fRef = 9452D5DF0E044A9D000AD792 /* sqSqueakMainApp.m */;
6522
name = "sqSqueakMainApp.m: 167";
6529
94E297D10DECA72F009CF73A /* PBXTextBookmark */ = {
6530
isa = PBXTextBookmark;
6531
fRef = 94E297D20DECA72F009CF73A /* config.h */;
6532
name = "config.h: 154";
6539
94E297D20DECA72F009CF73A /* config.h */ = {
6540
isa = PBXFileReference;
6541
lastKnownFileType = sourcecode.c.h;
6543
path = /Users/johnmci/Documents/SqueakGStreamer/platforms/unix/bld/config.h;
6544
sourceTree = "<absolute>";
6546
94E297D30DECA72F009CF73A /* PBXTextBookmark */ = {
6547
isa = PBXTextBookmark;
6548
fRef = 94E297D40DECA72F009CF73A /* version.c */;
6549
name = "version.c: 1";
6556
94E297D40DECA72F009CF73A /* version.c */ = {
6557
isa = PBXFileReference;
6558
lastKnownFileType = sourcecode.c.c;
6560
path = /Users/johnmci/Documents/SqueakHydra/platforms/win32/vm/version.c;
6561
sourceTree = "<absolute>";
6563
94E297D50DECA72F009CF73A /* PBXTextBookmark */ = {
6564
isa = PBXTextBookmark;
6565
fRef = 94E297D60DECA72F009CF73A /* version.h */;
6566
name = "version.h: 1";
6573
94E297D60DECA72F009CF73A /* version.h */ = {
6574
isa = PBXFileReference;
6575
lastKnownFileType = sourcecode.c.h;
6577
path = /Users/johnmci/Documents/SqueakHydra/platforms/win32/vm/version.h;
6578
sourceTree = "<absolute>";
6580
94E297D70DECA72F009CF73A /* PBXTextBookmark */ = {
6581
isa = PBXTextBookmark;
6582
fRef = 949E5B970DE3623B007388E0 /* sqUnixMain.c */;
6583
name = "sqUnixMain.c: 417";
6590
94E2DAD40ED2351B00012E92 /* PBXTextBookmark */ = {
6591
isa = PBXTextBookmark;
6592
fRef = 94E2DAD50ED2351B00012E92 /* sqMacUnixInterfaceSound.c */;
6593
name = "sqMacUnixInterfaceSound.c: 46";
6600
94E2DAD50ED2351B00012E92 /* sqMacUnixInterfaceSound.c */ = {
6601
isa = PBXFileReference;
6602
lastKnownFileType = sourcecode.c.c;
6603
name = sqMacUnixInterfaceSound.c;
6604
path = "/Users/johnmci/Documents/SqueakSpellingPlugin/platforms/Mac OS/plugins/SoundPlugin/sqMacUnixInterfaceSound.c";
6605
sourceTree = "<absolute>";
6607
94E2DADE0ED2351B00012E92 /* sqUnixSound.c */ = {
6608
isa = PBXFileReference;
6609
lastKnownFileType = sourcecode.c.c;
6610
name = sqUnixSound.c;
6611
path = /Users/johnmci/Documents/SqueakServicesPlugin/platforms/unix/plugins/SoundPlugin/sqUnixSound.c;
6612
sourceTree = "<absolute>";
6614
94E2DB270ED2355F00012E92 /* PBXTextBookmark */ = {
6615
isa = PBXTextBookmark;
6616
fRef = 94E2DADE0ED2351B00012E92 /* sqUnixSound.c */;
6617
name = "sqUnixSound.c: 114";
6624
94E4930310BD32D00011AC75 /* PBXTextBookmark */ = {
6625
isa = PBXTextBookmark;
6626
fRef = 9414420010BC817D0088F8AC /* NSPanel.h */;
6627
name = "NSPanel.h: 43";
6634
94E4936F10BD39E20011AC75 /* sqUnixQuartz.m */ = {
6635
isa = PBXFileReference;
6636
lastKnownFileType = sourcecode.c.objc;
6637
name = sqUnixQuartz.m;
6638
path = "/Users/johnmci/Documents/Squeak3.8.0.0CLosureWithEncryption/platforms/unix/vm-display-Quartz/sqUnixQuartz.m";
6639
sourceTree = "<absolute>";
6641
94E5838A10BF3E080073FD63 /* NSTextInputClient.h */ = {
6642
isa = PBXFileReference;
6643
lastKnownFileType = sourcecode.c.h;
6644
name = NSTextInputClient.h;
6645
path = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSTextInputClient.h;
6646
sourceTree = "<absolute>";
6648
94E5838E10BF3E080073FD63 /* AudioQueue.h */ = {
6649
isa = PBXFileReference;
6650
lastKnownFileType = sourcecode.c.h;
6651
name = AudioQueue.h;
6652
path = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AudioToolbox.framework/Versions/A/Headers/AudioQueue.h;
6653
sourceTree = "<absolute>";
6655
94E583DB10BF43970073FD63 /* PBXTextBookmark */ = {
6656
isa = PBXTextBookmark;
6657
fRef = 94E5838A10BF3E080073FD63 /* NSTextInputClient.h */;
6658
name = "NSTextInputClient.h: 20";
6665
94E5846510BF67600073FD63 /* NSResponder.h */ = {
6666
isa = PBXFileReference;
6667
lastKnownFileType = sourcecode.c.h;
6668
name = NSResponder.h;
6669
path = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSResponder.h;
6670
sourceTree = "<absolute>";
6672
94E584AE10BF6EE30073FD63 /* PBXTextBookmark */ = {
6673
isa = PBXTextBookmark;
6674
fRef = 94E5846510BF67600073FD63 /* NSResponder.h */;
6675
name = "NSResponder.h: 99";
6682
94E584FF10BF79AB0073FD63 /* PBXTextBookmark */ = {
6683
isa = PBXTextBookmark;
6684
fRef = 94D7178310B73A3800F69A71 /* SqViewInputSensor.m */;
6685
name = "SqViewInputSensor.m: 34";
6692
94E5850010BF79AB0073FD63 /* PBXTextBookmark */ = {
6693
isa = PBXTextBookmark;
6694
fRef = 9406E87710B66A74002F81F2 /* SqViewEventSensor.m */;
6695
name = "SqViewEventSensor.m: 29";
6702
94E658E10DDD03FE00358328 /* interp.h */ = {
6704
sepNavIntBoundsRect = "{{0, 0}, {1338, 565}}";
6705
sepNavSelRange = "{161, 5}";
6706
sepNavVisRange = "{0, 685}";
6707
sepNavWindowFrame = "{{38, 14}, {799, 988}}";
6710
94E658E40DDD03FE00358328 /* ADPCMCodecPlugin.c */ = {
6712
sepNavIntBoundsRect = "{{0, 0}, {1533, 10348}}";
6713
sepNavSelRange = "{0, 0}";
6714
sepNavVisRange = "{0, 410}";
6717
94E658E60DDD03FE00358328 /* B2DPlugin.c */ = {
6719
sepNavIntBoundsRect = "{{0, 0}, {1482, 166114}}";
6720
sepNavSelRange = "{238472, 12}";
6721
sepNavVisRange = "{237846, 1064}";
6724
94E658EA0DDD03FE00358328 /* BitBltPlugin.c */ = {
6726
sepNavIntBoundsRect = "{{0, 0}, {1405, 85475}}";
6727
sepNavSelRange = "{52607, 0}";
6728
sepNavVisRange = "{52196, 1366}";
6731
94E658EC0DDD03FE00358328 /* BMPReadWriterPlugin.c */ = {
6733
sepNavIntBoundsRect = "{{0, 0}, {1357, 2860}}";
6734
sepNavSelRange = "{0, 0}";
6735
sepNavVisRange = "{0, 261}";
6738
94E658F00DDD03FE00358328 /* DSAPrims.c */ = {
6740
sepNavIntBoundsRect = "{{0, 0}, {1357, 8112}}";
6741
sepNavSelRange = "{0, 0}";
6742
sepNavVisRange = "{0, 261}";
6745
94E658F20DDD03FE00358328 /* FFTPlugin.c */ = {
6747
sepNavIntBoundsRect = "{{0, 0}, {1357, 4641}}";
6748
sepNavSelRange = "{8267, 0}";
6749
sepNavVisRange = "{8149, 272}";
6752
94E658F40DDD03FE00358328 /* FilePlugin.c */ = {
6754
sepNavIntBoundsRect = "{{0, 0}, {1132, 14144}}";
6755
sepNavSelRange = "{27580, 7}";
6756
sepNavVisRange = "{26914, 1464}";
6757
sepNavWindowFrame = "{{21, 20}, {694, 1008}}";
6760
94E658F60DDD03FE00358328 /* FloatArrayPlugin.c */ = {
6762
sepNavIntBoundsRect = "{{0, 0}, {1283, 7592}}";
6763
sepNavSelRange = "{0, 0}";
6764
sepNavVisRange = "{0, 192}";
6767
94E658F80DDD03FE00358328 /* GeniePlugin.c */ = {
6769
sepNavIntBoundsRect = "{{0, 0}, {1283, 5044}}";
6770
sepNavSelRange = "{0, 0}";
6771
sepNavVisRange = "{0, 192}";
6774
94E658FA0DDD03FE00358328 /* HostWindowPlugin.c */ = {
6776
sepNavIntBoundsRect = "{{0, 0}, {1338, 5330}}";
6777
sepNavSelRange = "{9579, 21}";
6778
sepNavVisRange = "{9090, 1206}";
6781
94E658FE0DDD03FE00358328 /* JPEGReaderPlugin.c */ = {
6783
sepNavIntBoundsRect = "{{0, 0}, {1357, 17043}}";
6784
sepNavSelRange = "{9474, 0}";
6785
sepNavVisRange = "{9324, 406}";
6788
94E659000DDD03FE00358328 /* JPEGReadWriter2Plugin.c */ = {
6790
sepNavIntBoundsRect = "{{0, 0}, {1195, 9100}}";
6791
sepNavSelRange = "{21135, 17}";
6792
sepNavVisRange = "{19526, 1968}";
6795
94E659020DDD03FE00358328 /* Klatt.c */ = {
6797
sepNavIntBoundsRect = "{{0, 0}, {1357, 19500}}";
6798
sepNavSelRange = "{44049, 0}";
6799
sepNavVisRange = "{43900, 200}";
6800
sepNavWindowFrame = "{{15, 4}, {1426, 1019}}";
6803
94E659040DDD03FE00358328 /* LargeIntegers.c */ = {
6805
sepNavIntBoundsRect = "{{0, 0}, {1342, 30290}}";
6806
sepNavSelRange = "{0, 0}";
6807
sepNavVisRange = "{0, 869}";
6810
94E659060DDD03FE00358328 /* Matrix2x3Plugin.c */ = {
6812
sepNavIntBoundsRect = "{{0, 0}, {1357, 8814}}";
6813
sepNavSelRange = "{0, 0}";
6814
sepNavVisRange = "{0, 261}";
6817
94E659080DDD03FE00358328 /* MIDIPlugin.c */ = {
6819
sepNavIntBoundsRect = "{{0, 0}, {1867, 4784}}";
6820
sepNavSelRange = "{3309, 0}";
6821
sepNavVisRange = "{3006, 515}";
6822
sepNavWindowFrame = "{{15, 8}, {1012, 1015}}";
6825
94E6590A0DDD03FE00358328 /* MiscPrimitivePlugin.c */ = {
6827
sepNavIntBoundsRect = "{{0, 0}, {1283, 10621}}";
6828
sepNavSelRange = "{0, 0}";
6829
sepNavVisRange = "{0, 850}";
6832
94E6590C0DDD03FE00358328 /* RePlugin.c */ = {
6834
sepNavIntBoundsRect = "{{0, 0}, {3113, 6032}}";
6835
sepNavSelRange = "{0, 0}";
6836
sepNavVisRange = "{0, 871}";
6839
94E6590E0DDD03FE00358328 /* SecurityPlugin.c */ = {
6841
sepNavIntBoundsRect = "{{0, 0}, {1215, 4238}}";
6842
sepNavSelRange = "{5714, 21}";
6843
sepNavVisRange = "{5088, 1429}";
6844
sepNavWindowFrame = "{{15, 45}, {1017, 978}}";
6847
94E659100DDD03FE00358328 /* SocketPlugin.c */ = {
6849
sepNavIntBoundsRect = "{{0, 0}, {1377, 23166}}";
6850
sepNavSelRange = "{5715, 37}";
6851
sepNavVisRange = "{4742, 1976}";
6852
sepNavWindowFrame = "{{15, 8}, {1012, 1015}}";
6855
94E659120DDD03FE00358328 /* SoundCodecPrims.c */ = {
6857
sepNavIntBoundsRect = "{{0, 0}, {1357, 2886}}";
6858
sepNavSelRange = "{2059, 0}";
6859
sepNavVisRange = "{1965, 173}";
6862
94E659140DDD03FE00358328 /* SoundGenerationPlugin.c */ = {
6864
sepNavIntBoundsRect = "{{0, 0}, {1357, 9087}}";
6865
sepNavSelRange = "{0, 0}";
6866
sepNavVisRange = "{0, 261}";
6869
94E659160DDD03FE00358328 /* SoundPlugin.c */ = {
6871
sepNavIntBoundsRect = "{{0, 0}, {1283, 6084}}";
6872
sepNavSelRange = "{5833, 13}";
6873
sepNavVisRange = "{5241, 1174}";
6874
sepNavWindowFrame = "{{38, 28}, {1346, 974}}";
6877
94E659180DDD03FE00358328 /* Squeak3D.c */ = {
6879
sepNavIntBoundsRect = "{{0, 0}, {1440, 39338}}";
6880
sepNavSelRange = "{3704, 6}";
6881
sepNavVisRange = "{2895, 2373}";
6884
94E6591A0DDD03FE00358328 /* StarSqueakPlugin.c */ = {
6886
sepNavIntBoundsRect = "{{0, 0}, {1412, 4316}}";
6887
sepNavSelRange = "{4752, 0}";
6888
sepNavVisRange = "{4329, 952}";
6891
94E6591D0DDD03FE00358328 /* UUIDPlugin.c */ = {
6893
sepNavIntBoundsRect = "{{0, 0}, {1104, 2041}}";
6894
sepNavSelRange = "{2745, 19}";
6895
sepNavVisRange = "{2105, 1164}";
6896
sepNavWindowFrame = "{{38, 17}, {847, 985}}";
6899
94E6591F0DDD03FE00358328 /* ZipPlugin.c */ = {
6901
sepNavIntBoundsRect = "{{0, 0}, {1104, 17446}}";
6902
sepNavSelRange = "{1700, 11}";
6903
sepNavVisRange = "{710, 2153}";
6904
sepNavWindowFrame = "{{15, 22}, {1064, 1001}}";
6907
94E659200DDD03FE00358328 /* sqNamedPrims.h */ = {
6909
sepNavIntBoundsRect = "{{0, 0}, {1338, 1144}}";
6910
sepNavSelRange = "{2312, 0}";
6911
sepNavVisRange = "{1591, 929}";
6912
sepNavWindowFrame = "{{15, 9}, {1078, 1014}}";
6915
94E659430DDD04FA00358328 /* AsynchFilePlugin.h */ = {
6917
sepNavIntBoundsRect = "{{0, 0}, {1215, 501}}";
6918
sepNavSelRange = "{404, 19}";
6919
sepNavVisRange = "{0, 659}";
6922
94E659450DDD04FA00358328 /* FilePlugin.h */ = {
6924
sepNavIntBoundsRect = "{{0, 0}, {1215, 767}}";
6925
sepNavSelRange = "{1735, 10}";
6926
sepNavVisRange = "{440, 1866}";
6927
sepNavWindowFrame = "{{15, 25}, {997, 998}}";
6930
94E659460DDD04FA00358328 /* sqFilePluginBasicPrims.c */ = {
6932
sepNavIntBoundsRect = "{{0, 0}, {1338, 5850}}";
6933
sepNavSelRange = "{11068, 11}";
6934
sepNavVisRange = "{10580, 897}";
6935
sepNavWindowFrame = "{{38, 19}, {905, 983}}";
6938
94E659490DDD053900358328 /* SurfacePlugin.c */ = {
6940
sepNavIntBoundsRect = "{{0, 0}, {784, 2990}}";
6941
sepNavSelRange = "{2333, 0}";
6942
sepNavVisRange = "{1279, 2223}";
6945
94E6594A0DDD053900358328 /* SurfacePlugin.h */ = {
6947
sepNavIntBoundsRect = "{{0, 0}, {784, 1716}}";
6948
sepNavSelRange = "{27, 0}";
6949
sepNavVisRange = "{0, 2637}";
6952
94E6594D0DDD053900358328 /* SecurityPlugin.h */ = {
6954
sepNavIntBoundsRect = "{{0, 0}, {1357, 481}}";
6955
sepNavSelRange = "{290, 3}";
6956
sepNavVisRange = "{117, 443}";
6957
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
6960
94E6594F0DDD053900358328 /* SoundGenerationPlugin.h */ = {
6962
sepNavIntBoundsRect = "{{0, 0}, {1215, 527}}";
6963
sepNavSelRange = "{299, 3}";
6964
sepNavVisRange = "{0, 360}";
6967
94E659530DDD053900358328 /* jcapimin.c */ = {
6969
sepNavIntBoundsRect = "{{0, 0}, {1215, 3822}}";
6970
sepNavSelRange = "{7008, 3}";
6971
sepNavVisRange = "{5989, 1240}";
6974
94E659550DDD053900358328 /* jccoefct.c */ = {
6976
sepNavIntBoundsRect = "{{0, 0}, {1215, 5863}}";
6977
sepNavSelRange = "{9819, 3}";
6978
sepNavVisRange = "{8276, 1834}";
6981
94E659560DDD053900358328 /* jccolor.c */ = {
6983
sepNavIntBoundsRect = "{{0, 0}, {1215, 5889}}";
6984
sepNavSelRange = "{9842, 3}";
6985
sepNavVisRange = "{9173, 1109}";
6988
94E659570DDD053900358328 /* jcdctmgr.c */ = {
6990
sepNavIntBoundsRect = "{{0, 0}, {1215, 4966}}";
6991
sepNavSelRange = "{6549, 3}";
6992
sepNavVisRange = "{5884, 1542}";
6995
94E659580DDD053900358328 /* jchuff.c */ = {
6997
sepNavIntBoundsRect = "{{0, 0}, {1215, 11778}}";
6998
sepNavSelRange = "{22307, 3}";
6999
sepNavVisRange = "{21622, 1607}";
7002
94E6595B0DDD053900358328 /* jcmainct.c */ = {
7004
sepNavIntBoundsRect = "{{0, 0}, {1215, 3783}}";
7005
sepNavSelRange = "{7591, 3}";
7006
sepNavVisRange = "{6975, 964}";
7009
94E6595C0DDD053900358328 /* jcmarker.c */ = {
7011
sepNavIntBoundsRect = "{{0, 0}, {1215, 8866}}";
7012
sepNavSelRange = "{10933, 3}";
7013
sepNavVisRange = "{10271, 1095}";
7016
94E6595D0DDD053900358328 /* jcmaster.c */ = {
7018
sepNavIntBoundsRect = "{{0, 0}, {1215, 7553}}";
7019
sepNavSelRange = "{10789, 3}";
7020
sepNavVisRange = "{10099, 1218}";
7023
94E6595E0DDD053900358328 /* jcomapi.c */ = {
7025
sepNavIntBoundsRect = "{{0, 0}, {1196, 1512}}";
7026
sepNavSelRange = "{2136, 7}";
7027
sepNavVisRange = "{1428, 1392}";
7030
94E659600DDD053900358328 /* jcparam.c */ = {
7032
sepNavIntBoundsRect = "{{0, 0}, {1215, 8164}}";
7033
sepNavSelRange = "{18163, 3}";
7034
sepNavVisRange = "{17732, 1161}";
7037
94E659610DDD053900358328 /* jcphuff.c */ = {
7039
sepNavIntBoundsRect = "{{0, 0}, {1215, 10920}}";
7040
sepNavSelRange = "{18752, 3}";
7041
sepNavVisRange = "{17946, 1058}";
7044
94E659620DDD053900358328 /* jcprepct.c */ = {
7046
sepNavIntBoundsRect = "{{0, 0}, {1215, 4628}}";
7047
sepNavSelRange = "{9095, 3}";
7048
sepNavVisRange = "{8327, 1337}";
7051
94E659630DDD053900358328 /* jcsample.c */ = {
7053
sepNavIntBoundsRect = "{{0, 0}, {1215, 6994}}";
7054
sepNavSelRange = "{7407, 3}";
7055
sepNavVisRange = "{6537, 1530}";
7058
94E659640DDD053900358328 /* jctrans.c */ = {
7060
sepNavIntBoundsRect = "{{0, 0}, {1215, 5187}}";
7061
sepNavSelRange = "{13272, 3}";
7062
sepNavVisRange = "{12530, 1091}";
7065
94E659650DDD053900358328 /* jdapimin.c */ = {
7067
sepNavIntBoundsRect = "{{0, 0}, {1215, 5135}}";
7068
sepNavSelRange = "{7807, 3}";
7069
sepNavVisRange = "{7168, 1550}";
7072
94E659690DDD053900358328 /* jdcoefct.c */ = {
7074
sepNavIntBoundsRect = "{{0, 0}, {1215, 9451}}";
7075
sepNavSelRange = "{21428, 3}";
7076
sepNavVisRange = "{20759, 1160}";
7079
94E6596A0DDD053900358328 /* jdcolor.c */ = {
7081
sepNavIntBoundsRect = "{{0, 0}, {1215, 5057}}";
7082
sepNavSelRange = "{8235, 3}";
7083
sepNavVisRange = "{7573, 1344}";
7086
94E6596B0DDD053900358328 /* jdct.h */ = {
7088
sepNavIntBoundsRect = "{{0, 0}, {1215, 2275}}";
7089
sepNavSelRange = "{693, 3}";
7090
sepNavVisRange = "{0, 1654}";
7093
94E6596D0DDD053900358328 /* jdhuff.c */ = {
7095
sepNavIntBoundsRect = "{{0, 0}, {1215, 8229}}";
7096
sepNavSelRange = "{15652, 3}";
7097
sepNavVisRange = "{14578, 1143}";
7100
94E6596E0DDD053900358328 /* jdhuff.h */ = {
7102
sepNavIntBoundsRect = "{{0, 0}, {1215, 2574}}";
7103
sepNavSelRange = "{4464, 3}";
7104
sepNavVisRange = "{2783, 1780}";
7107
94E6596F0DDD053900358328 /* jdinput.c */ = {
7109
sepNavIntBoundsRect = "{{0, 0}, {1215, 4810}}";
7110
sepNavSelRange = "{6703, 3}";
7111
sepNavVisRange = "{5969, 1701}";
7114
94E659700DDD053900358328 /* jdmainct.c */ = {
7116
sepNavIntBoundsRect = "{{0, 0}, {1215, 6149}}";
7117
sepNavSelRange = "{7953, 3}";
7118
sepNavVisRange = "{7137, 1484}";
7121
94E659710DDD053900358328 /* jdmarker.c */ = {
7123
sepNavIntBoundsRect = "{{0, 0}, {1215, 17706}}";
7124
sepNavSelRange = "{40391, 3}";
7125
sepNavVisRange = "{38997, 1561}";
7128
94E659720DDD053900358328 /* jdmaster.c */ = {
7130
sepNavIntBoundsRect = "{{0, 0}, {1215, 7085}}";
7131
sepNavSelRange = "{14890, 3}";
7132
sepNavVisRange = "{14181, 1516}";
7135
94E659730DDD053900358328 /* jdmerge.c */ = {
7137
sepNavIntBoundsRect = "{{0, 0}, {1215, 5187}}";
7138
sepNavSelRange = "{10331, 3}";
7139
sepNavVisRange = "{9363, 1315}";
7142
94E659740DDD053900358328 /* jdphuff.c */ = {
7144
sepNavIntBoundsRect = "{{0, 0}, {1215, 8606}}";
7145
sepNavSelRange = "{15744, 3}";
7146
sepNavVisRange = "{14845, 1126}";
7149
94E659760DDD053900358328 /* jdsample.c */ = {
7151
sepNavIntBoundsRect = "{{0, 0}, {1215, 6409}}";
7152
sepNavSelRange = "{11463, 3}";
7153
sepNavVisRange = "{10845, 1368}";
7156
94E659770DDD053900358328 /* jdtrans.c */ = {
7158
sepNavIntBoundsRect = "{{0, 0}, {1196, 2002}}";
7159
sepNavSelRange = "{995, 7}";
7160
sepNavVisRange = "{0, 1708}";
7163
94E659790DDD053900358328 /* jerror.h */ = {
7165
sepNavIntBoundsRect = "{{0, 0}, {1338, 4095}}";
7166
sepNavSelRange = "{11163, 7}";
7167
sepNavVisRange = "{10252, 1759}";
7170
94E6597C0DDD053900358328 /* jfdctint.c */ = {
7172
sepNavIntBoundsRect = "{{0, 0}, {1215, 3809}}";
7173
sepNavSelRange = "{5901, 3}";
7174
sepNavVisRange = "{5152, 1247}";
7177
94E6597D0DDD053900358328 /* jidctflt.c */ = {
7179
sepNavIntBoundsRect = "{{0, 0}, {1215, 3094}}";
7180
sepNavSelRange = "{7928, 3}";
7181
sepNavVisRange = "{6879, 1380}";
7184
94E6597E0DDD053900358328 /* jidctfst.c */ = {
7186
sepNavIntBoundsRect = "{{0, 0}, {1215, 4706}}";
7187
sepNavSelRange = "{9786, 3}";
7188
sepNavVisRange = "{8848, 1431}";
7191
94E6597F0DDD053900358328 /* jidctint.c */ = {
7193
sepNavIntBoundsRect = "{{0, 0}, {1215, 5044}}";
7194
sepNavSelRange = "{11723, 3}";
7195
sepNavVisRange = "{10788, 1464}";
7198
94E659800DDD053900358328 /* jidctred.c */ = {
7200
sepNavIntBoundsRect = "{{0, 0}, {1215, 5096}}";
7201
sepNavSelRange = "{11209, 3}";
7202
sepNavVisRange = "{10458, 1488}";
7205
94E659810DDD053900358328 /* jinclude.h */ = {
7207
sepNavIntBoundsRect = "{{0, 0}, {1338, 1248}}";
7208
sepNavSelRange = "{1563, 7}";
7209
sepNavVisRange = "{935, 1320}";
7212
94E659820DDD053900358328 /* jmemdatadst.c */ = {
7214
sepNavIntBoundsRect = "{{0, 0}, {1283, 1924}}";
7215
sepNavSelRange = "{4506, 0}";
7216
sepNavVisRange = "{4026, 877}";
7219
94E659830DDD053900358328 /* jmemdatasrc.c */ = {
7221
sepNavIntBoundsRect = "{{0, 0}, {1283, 2639}}";
7222
sepNavSelRange = "{8018, 0}";
7223
sepNavVisRange = "{7282, 942}";
7224
sepNavWindowFrame = "{{15, 13}, {1326, 1010}}";
7227
94E659840DDD053900358328 /* jmemmgr.c */ = {
7229
sepNavIntBoundsRect = "{{0, 0}, {1215, 14313}}";
7230
sepNavSelRange = "{20872, 3}";
7231
sepNavVisRange = "{20200, 1407}";
7234
94E659860DDD053900358328 /* jmemsys.h */ = {
7236
sepNavIntBoundsRect = "{{0, 0}, {1196, 2730}}";
7237
sepNavSelRange = "{1380, 7}";
7238
sepNavVisRange = "{578, 1969}";
7241
94E659870DDD053900358328 /* jmorecfg.h */ = {
7243
sepNavIntBoundsRect = "{{0, 0}, {1215, 5096}}";
7244
sepNavSelRange = "{4500, 3}";
7245
sepNavVisRange = "{3819, 1298}";
7248
94E659880DDD053900358328 /* jpegint.h */ = {
7250
sepNavIntBoundsRect = "{{0, 0}, {1215, 5135}}";
7251
sepNavSelRange = "{8138, 3}";
7252
sepNavVisRange = "{6999, 1671}";
7255
94E659890DDD053900358328 /* jpeglib.h */ = {
7257
sepNavIntBoundsRect = "{{0, 0}, {1215, 14287}}";
7258
sepNavSelRange = "{44121, 3}";
7259
sepNavVisRange = "{43159, 1631}";
7262
94E6598A0DDD053900358328 /* JPEGReadWriter2Plugin.h */ = {
7264
sepNavIntBoundsRect = "{{0, 0}, {1215, 527}}";
7265
sepNavSelRange = "{400, 3}";
7266
sepNavVisRange = "{0, 606}";
7269
94E6598B0DDD053900358328 /* jquant1.c */ = {
7271
sepNavIntBoundsRect = "{{0, 0}, {1215, 10946}}";
7272
sepNavSelRange = "{23424, 3}";
7273
sepNavVisRange = "{22008, 1505}";
7276
94E6598C0DDD053900358328 /* jquant2.c */ = {
7278
sepNavIntBoundsRect = "{{0, 0}, {1215, 17212}}";
7279
sepNavSelRange = "{35564, 3}";
7280
sepNavVisRange = "{34161, 1581}";
7283
94E6598D0DDD053900358328 /* jutils.c */ = {
7285
sepNavIntBoundsRect = "{{0, 0}, {1215, 2379}}";
7286
sepNavSelRange = "{709, 3}";
7287
sepNavVisRange = "{0, 1126}";
7290
94E659910DDD053900358328 /* UUIDPlugin.h */ = {
7292
sepNavIntBoundsRect = "{{0, 0}, {1357, 141}}";
7293
sepNavSelRange = "{224, 0}";
7294
sepNavVisRange = "{0, 247}";
7297
94E659930DDD053900358328 /* SoundPlugin.h */ = {
7299
sepNavIntBoundsRect = "{{0, 0}, {831, 891}}";
7300
sepNavSelRange = "{209, 89}";
7301
sepNavVisRange = "{0, 1762}";
7302
sepNavWindowFrame = "{{15, 4}, {878, 1019}}";
7305
94E659970DDD053900358328 /* b3d.h */ = {
7307
sepNavIntBoundsRect = "{{0, 0}, {1283, 1547}}";
7308
sepNavSelRange = "{1163, 18}";
7309
sepNavVisRange = "{725, 933}";
7312
94E659990DDD053900358328 /* b3dAlloc.h */ = {
7314
sepNavIntBoundsRect = "{{0, 0}, {1196, 2044}}";
7315
sepNavSelRange = "{2615, 7}";
7316
sepNavVisRange = "{1909, 1488}";
7319
94E6599A0DDD053900358328 /* b3dDraw.c */ = {
7321
sepNavIntBoundsRect = "{{0, 0}, {1283, 6643}}";
7322
sepNavSelRange = "{13439, 0}";
7323
sepNavVisRange = "{12902, 1039}";
7326
94E6599B0DDD053900358328 /* b3dInit.c */ = {
7328
sepNavIntBoundsRect = "{{0, 0}, {725, 9529}}";
7329
sepNavSelRange = "{7571, 26}";
7330
sepNavVisRange = "{6648, 1585}";
7331
sepNavWindowFrame = "{{15, 4}, {772, 1019}}";
7334
94E6599C0DDD053900358328 /* b3dMain.c */ = {
7336
sepNavIntBoundsRect = "{{0, 0}, {1283, 19396}}";
7337
sepNavSelRange = "{0, 0}";
7338
sepNavVisRange = "{0, 931}";
7341
94E6599D0DDD053900358328 /* b3dRemap.c */ = {
7343
sepNavIntBoundsRect = "{{0, 0}, {1283, 3718}}";
7344
sepNavSelRange = "{7538, 0}";
7345
sepNavVisRange = "{6829, 1035}";
7348
94E6599E0DDD053900358328 /* b3dTypes.h */ = {
7350
sepNavIntBoundsRect = "{{0, 0}, {1283, 4420}}";
7351
sepNavSelRange = "{4491, 13}";
7352
sepNavVisRange = "{3977, 898}";
7355
94E659A00DDD053900358328 /* SocketPlugin.h */ = {
7357
sepNavIntBoundsRect = "{{0, 0}, {1601, 1118}}";
7358
sepNavSelRange = "{3647, 30}";
7359
sepNavVisRange = "{757, 4070}";
7362
94E659A30DDD053900358328 /* SoundCodecPrims.h */ = {
7364
sepNavIntBoundsRect = "{{0, 0}, {1215, 527}}";
7365
sepNavSelRange = "{3, 10}";
7366
sepNavVisRange = "{0, 401}";
7369
94E659A40DDD053900358328 /* sqSoundCodecPluginBasicPrims.c */ = {
7371
sepNavIntBoundsRect = "{{0, 0}, {1368, 50453}}";
7372
sepNavSelRange = "{10030, 6}";
7373
sepNavVisRange = "{9384, 1276}";
7376
94E65A290DDD053900358328 /* chartables.c */ = {
7378
sepNavIntBoundsRect = "{{0, 0}, {1283, 2457}}";
7379
sepNavSelRange = "{489, 0}";
7380
sepNavVisRange = "{0, 1280}";
7383
94E65A2B0DDD053900358328 /* get.c */ = {
7385
sepNavIntBoundsRect = "{{0, 0}, {1338, 2730}}";
7386
sepNavSelRange = "{2039, 7}";
7387
sepNavVisRange = "{1268, 1649}";
7390
94E65A2C0DDD053900358328 /* internal.h */ = {
7392
sepNavIntBoundsRect = "{{0, 0}, {1283, 5629}}";
7393
sepNavSelRange = "{1665, 0}";
7394
sepNavVisRange = "{1415, 1340}";
7397
94E65A2E0DDD053900358328 /* pcre.c */ = {
7399
sepNavIntBoundsRect = "{{0, 0}, {950, 66339}}";
7400
sepNavSelRange = "{1763, 31}";
7401
sepNavVisRange = "{781, 2030}";
7402
sepNavWindowFrame = "{{683, 16}, {997, 998}}";
7405
94E65A2F0DDD053900358328 /* pcre.h */ = {
7407
sepNavIntBoundsRect = "{{0, 0}, {1215, 1495}}";
7408
sepNavSelRange = "{2990, 3}";
7409
sepNavVisRange = "{1856, 1482}";
7412
94E65A300DDD053900358328 /* rePlugin.h */ = {
7414
sepNavIntBoundsRect = "{{0, 0}, {1010, 637}}";
7415
sepNavSelRange = "{0, 0}";
7416
sepNavVisRange = "{0, 1259}";
7419
94E65A340DDD053900358328 /* study.c */ = {
7421
sepNavIntBoundsRect = "{{0, 0}, {1215, 5096}}";
7422
sepNavSelRange = "{3001, 3}";
7423
sepNavVisRange = "{2296, 1397}";
7426
94E7F6B812373EB800A03A11 /* PBXTextBookmark */ = {
7427
isa = PBXTextBookmark;
7428
fRef = 94E7F6B912373EB800A03A11 /* sqMacLocaleCarbon.c */;
7429
name = "sqMacLocaleCarbon.c: 104";
7436
94E7F6B912373EB800A03A11 /* sqMacLocaleCarbon.c */ = {
7437
isa = PBXFileReference;
7438
lastKnownFileType = sourcecode.c.c;
7439
name = sqMacLocaleCarbon.c;
7440
path = "/Users/johnmci/Documents/Squeak3.8.0/platforms/Mac OS/plugins/LocalePlugin/sqMacLocaleCarbon.c";
7441
sourceTree = "<absolute>";
7443
94E8EEEA11C94D5D0049D853 /* PBXTextBookmark */ = {
7444
isa = PBXTextBookmark;
7445
fRef = 94E8EEEB11C94D5D0049D853 /* sqUnixQuartz.m */;
7446
name = "sqUnixQuartz.m: 2113";
7453
94E8EEEB11C94D5D0049D853 /* sqUnixQuartz.m */ = {
7454
isa = PBXFileReference;
7455
lastKnownFileType = sourcecode.c.objc;
7456
name = sqUnixQuartz.m;
7457
path = "/Users/johnmci/Documents/Squeak3.8.0/History/4.2.4b1/platforms/unix/vm-display-Quartz/sqUnixQuartz.m";
7458
sourceTree = "<absolute>";
7460
94E8FA3C12258ED500EECD29 /* PBXTextBookmark */ = {
7461
isa = PBXTextBookmark;
7462
fRef = 94D16CAF10BCF96B00A69A89 /* Credits.rtf */;
7463
name = "Credits.rtf: 9";
7470
94E8FA6512258FDF00EECD29 /* sqMacV2Memory.c:191 */ = {
7471
isa = PBXFileBreakpoint;
7474
breakpointStyle = 0;
7475
continueAfterActions = 0;
7477
delayBeforeContinue = 0;
7478
fileReference = 9424FF670DDCB202009912BF /* sqMacV2Memory.c */;
7479
functionName = "sqMakeMemoryExecutableFromTo()";
7484
modificationTime = 308445393.436468;
7485
originalNumberOfMultipleMatches = 1;
7488
94ED7EFA0E6C2ABE00F4DD03 /* PBXTextBookmark */ = {
7489
isa = PBXTextBookmark;
7490
fRef = 94ED7EFB0E6C2ABE00F4DD03 /* Document.m */;
7491
name = "Document.m: 75";
7498
94ED7EFB0E6C2ABE00F4DD03 /* Document.m */ = {
7499
isa = PBXFileReference;
7500
lastKnownFileType = sourcecode.c.objc;
7502
path = "/Users/johnmci/Work In Progress/smalltalk/CocoaSqueakSource/CocoaSqueak/Document.m";
7503
sourceTree = "<absolute>";
7505
94EE1DAA11E57FAB00DC6E8C /* PBXTextBookmark */ = {
7506
isa = PBXTextBookmark;
7507
fRef = 9424FF680DDCB202009912BF /* sqMacV2Memory.h */;
7508
name = "sqMacV2Memory.h: 47";
7515
94EF43151262BFC100817F37 /* PBXTextBookmark */ = {
7516
isa = PBXTextBookmark;
7517
fRef = 94883B400E0C2B9C005A4738 /* sqUnixSocket.c */;
7518
name = "sqUnixSocket.c: 2129";
7525
94EF6CBE11E55947003BA64D /* gcc3x-interp.c */ = {
7527
sepNavIntBoundsRect = "{{0, 0}, {852, 472550}}";
7528
sepNavSelRange = "{0, 0}";
7529
sepNavVisRange = "{50, 1341}";
7530
sepNavWindowFrame = "{{512, 195}, {901, 833}}";
7533
94EF6CC011E55947003BA64D /* interp.h */ = {
7535
sepNavIntBoundsRect = "{{0, 0}, {1132, 597}}";
7536
sepNavSelRange = "{134, 7}";
7537
sepNavVisRange = "{0, 586}";
7540
94F155570E83EA1F001657CE /* PBXTextBookmark */ = {
7541
isa = PBXTextBookmark;
7542
fRef = 94B88C640E81500200C98131 /* SqueakObjcBridge.m */;
7543
name = "SqueakObjcBridge.m: 291";
7550
94F155580E83EA1F001657CE /* PBXTextBookmark */ = {
7551
isa = PBXTextBookmark;
7552
fRef = 94F155590E83EA1F001657CE /* FSNSProxy.m */;
7553
name = "FSNSProxy.m: 24";
7560
94F155590E83EA1F001657CE /* FSNSProxy.m */ = {
7561
isa = PBXFileReference;
7562
lastKnownFileType = sourcecode.c.objc;
7564
path = "/Users/johnmci/Work In Progress/smalltalk/FScriptSources-20031020/FScript/FScriptFramework/FSNSProxy.m";
7565
sourceTree = "<absolute>";
7567
94F1F15C11EB8AB5004B3AE3 /* PBXTextBookmark */ = {
7568
isa = PBXTextBookmark;
7569
fRef = 94F1F15D11EB8AB5004B3AE3 /* project.pbxproj */;
7570
name = "project.pbxproj: 1";
7577
94F1F15D11EB8AB5004B3AE3 /* project.pbxproj */ = {
7578
isa = PBXFileReference;
7579
lastKnownFileType = text.pbxproject;
7580
name = project.pbxproj;
7581
path = /Users/johnmci/Documents/Squeak3.8.0/platforms/iOS/vm/SqueakPureObjcCogVM.xcodeproj/project.pbxproj;
7582
sourceTree = "<absolute>";
7584
94F1F5C910C30C22008DB9CF /* PBXTextBookmark */ = {
7585
isa = PBXTextBookmark;
7586
fRef = 94F1F5CA10C30C22008DB9CF /* mpeg3io.c */;
7587
name = "mpeg3io.c: 5";
7594
94F1F5CA10C30C22008DB9CF /* mpeg3io.c */ = {
7595
isa = PBXFileReference;
7596
lastKnownFileType = sourcecode.c.c;
7598
path = /Users/johnmci/Documents/SqueakmpegFullSource/libmpeg/mpeg3io.c;
7599
sourceTree = "<absolute>";
7601
94F3A9690E6BFA7C00E0B12A /* Squeak.png */ = {
7603
sepNavWindowFrame = "{{61, 124}, {1288, 857}}";
7606
94F5C1870DF26EF200099B11 /* PBXTextBookmark */ = {
7607
isa = PBXTextBookmark;
7608
fRef = 94F5C1880DF26EF200099B11 /* interp.c */;
7609
name = "interp.c: 5170";
7616
94F5C1880DF26EF200099B11 /* interp.c */ = {
7617
isa = PBXFileReference;
7618
lastKnownFileType = sourcecode.c.c;
7620
path = /Users/johnmci/Documents/SqueakSquatSpoon/src/vm/interp.c;
7621
sourceTree = "<absolute>";
7623
94F5C1910DF26EF200099B11 /* gnu-interp.c */ = {
7624
isa = PBXFileReference;
7625
lastKnownFileType = sourcecode.c.c;
7626
name = "gnu-interp.c";
7627
path = "/Volumes/pm/Mail Downloads/gnu-interp.c";
7628
sourceTree = "<absolute>";
7630
94F5C1930DF26EF200099B11 /* gnu-interp.c */ = {
7631
isa = PBXFileReference;
7632
lastKnownFileType = sourcecode.c.c;
7633
name = "gnu-interp.c";
7634
path = "/Users/johnmci/Work In Progress/squeak Bugs/unixcompiletoomanyinstructions]/memoryAllocationNotes/gnu-interp.c";
7635
sourceTree = "<absolute>";
7637
94F5C25F0DF42C7600099B11 /* PBXTextBookmark */ = {
7638
isa = PBXTextBookmark;
7639
fRef = 94F5C1930DF26EF200099B11 /* gnu-interp.c */;
7640
name = "gnu-interp.c: 5409";
7647
94F5C2600DF42C7600099B11 /* PBXTextBookmark */ = {
7648
isa = PBXTextBookmark;
7649
fRef = 94F5C1910DF26EF200099B11 /* gnu-interp.c */;
7650
name = "gnu-interp.c: 5916";
7657
94F5F29110BC518B00847EEE /* PBXTextBookmark */ = {
7658
isa = PBXTextBookmark;
7659
fRef = 94D7178F10B73A3800F69A71 /* SqueakInterpreterEventSensor.h */;
7660
name = "SqueakInterpreterEventSensor.h: 10";
7667
94F5F29210BC518B00847EEE /* PBXTextBookmark */ = {
7668
isa = PBXTextBookmark;
7669
fRef = 94F5F29310BC518B00847EEE /* macXCanvas.m */;
7670
name = "macXCanvas.m: 174";
7677
94F5F29310BC518B00847EEE /* macXCanvas.m */ = {
7678
isa = PBXFileReference;
7679
lastKnownFileType = sourcecode.c.objc;
7680
name = macXCanvas.m;
7681
path = "/Users/johnmci/Work In Progress/cincom/VWSourceCode/721/src/plat/macXCanvas.m";
7682
sourceTree = "<absolute>";
7684
94F5F29410BC518B00847EEE /* PBXTextBookmark */ = {
7685
isa = PBXTextBookmark;
7686
fRef = 94D7178010B73A3800F69A71 /* SqueakInterpreterEventSensor.m */;
7687
name = "SqueakInterpreterEventSensor.m: 40";
7694
94F5F29510BC518B00847EEE /* PBXTextBookmark */ = {
7695
isa = PBXTextBookmark;
7696
fRef = 94F5F29610BC518B00847EEE /* ShellView.m */;
7697
name = "ShellView.m: 121";
7704
94F5F29610BC518B00847EEE /* ShellView.m */ = {
7705
isa = PBXFileReference;
7706
lastKnownFileType = sourcecode.c.objc;
7708
path = "/Users/johnmci/Work In Progress/smalltalk/FScriptSources-20031020/FScript/FScriptFramework/ShellView.m";
7709
sourceTree = "<absolute>";
7711
94F5F2A810BC539700847EEE /* PBXTextBookmark */ = {
7712
isa = PBXTextBookmark;
7713
fRef = 94F5F2A910BC539700847EEE /* NSSet.h */;
7714
name = "NSSet.h: 58";
7721
94F5F2A910BC539700847EEE /* NSSet.h */ = {
7722
isa = PBXFileReference;
7723
lastKnownFileType = sourcecode.c.h;
7725
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSSet.h;
7726
sourceTree = "<absolute>";
7728
94F8798F0E6C0C7E00662DEA /* sqSqueakIPhoneInfoPlistInterface.h */ = {
7730
sepNavIntBoundsRect = "{{0, 0}, {1036, 652}}";
7731
sepNavSelRange = "{1834, 26}";
7732
sepNavVisRange = "{0, 2025}";
7733
sepNavWindowFrame = "{{896, 50}, {1017, 978}}";
7736
94F879900E6C0C7E00662DEA /* sqSqueakIPhoneInfoPlistInterface.m */ = {
7738
sepNavIntBoundsRect = "{{0, 0}, {831, 1443}}";
7739
sepNavSelRange = "{2332, 0}";
7740
sepNavVisRange = "{1214, 2389}";
7741
sepNavWindowFrame = "{{15, 8}, {1012, 1015}}";
7744
94F89AED10B497F400556475 /* NSResponder.h */ = {
7745
isa = PBXFileReference;
7746
lastKnownFileType = sourcecode.c.h;
7747
name = NSResponder.h;
7748
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSResponder.h;
7749
sourceTree = "<absolute>";
7751
94F89AFE10B4997900556475 /* PBXTextBookmark */ = {
7752
isa = PBXTextBookmark;
7753
fRef = 94F89AFF10B4997900556475 /* IOLLEvent.h */;
7754
name = "IOLLEvent.h: 384";
7761
94F89AFF10B4997900556475 /* IOLLEvent.h */ = {
7762
isa = PBXFileReference;
7763
lastKnownFileType = sourcecode.c.h;
7765
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/IOKit.framework/Versions/A/Headers/hidsystem/IOLLEvent.h;
7766
sourceTree = "<absolute>";
7768
94F89BDE10B4B77400556475 /* PBXTextBookmark */ = {
7769
isa = PBXTextBookmark;
7770
fRef = 94F89BDF10B4B77400556475 /* CGBase.h */;
7771
name = "CGBase.h: 105";
7778
94F89BDF10B4B77400556475 /* CGBase.h */ = {
7779
isa = PBXFileReference;
7780
lastKnownFileType = sourcecode.c.h;
7782
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGBase.h;
7783
sourceTree = "<absolute>";
7785
94F89BE010B4B77400556475 /* PBXTextBookmark */ = {
7786
isa = PBXTextBookmark;
7787
fRef = 94BCAEDF10ACAE2500F87527 /* NSValue.h */;
7788
name = "NSValue.h: 52";
7795
94F89C5A10B4BF2800556475 /* NSRunLoop.h */ = {
7796
isa = PBXFileReference;
7797
lastKnownFileType = sourcecode.c.h;
7799
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSRunLoop.h;
7800
sourceTree = "<absolute>";
7802
94F89C9110B4C0B800556475 /* PBXTextBookmark */ = {
7803
isa = PBXTextBookmark;
7804
fRef = 94F89C9210B4C0B800556475 /* NSTimer.h */;
7805
name = "NSTimer.h: 14";
7812
94F89C9210B4C0B800556475 /* NSTimer.h */ = {
7813
isa = PBXFileReference;
7814
lastKnownFileType = sourcecode.c.h;
7816
path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSTimer.h;
7817
sourceTree = "<absolute>";
7819
94F8E42E0DE6129D003F4F53 /* PBXTextBookmark */ = {
7820
isa = PBXTextBookmark;
7821
fRef = 94A0EBB20DE608350071C8B9 /* squeakAudioVideoPipeLineSignalInterface.c */;
7822
name = "squeakAudioVideoPipeLineSignalInterface.c: 1";
7829
94FE53951230323500BA17E1 /* PBXTextBookmark */ = {
7830
isa = PBXTextBookmark;
7831
fRef = 947E64CA10AA16FE00D3B69E /* sqSqueakOSXApplication.h */;
7832
name = "sqSqueakOSXApplication.h: 58";
7839
94FFF7A40EBE2B9C00C69C79 /* SqueakV39.sources */ = {
7841
sepNavFolds = "{\n c = (\n {\n l = \"123>' selector: #zork ] raise: SyntaxErrorNotification.\\n\\t\\n\\tself should: [ self compile: '<foo bar>' selector: #zork ] raise: SyntaxErrorNotification.\\n\\tself should: [ self compile: '<foo 1>' selector: #zork ] raise: SyntaxErrorNotification.\\n\\tself should: [ self compile: '<foo bar zork>' selector: #zork ] raise: SyntaxErrorNotification.\\n\\tself should: [ self compile: '<foo bar 1>' selector: #zork ] raise: SyntaxErrorNotification.\\n\\t\\nself should: [ self compile: '<foo: bar:>' selector: #zork ] raise: SyntaxErrorNotification.\\n\\tself should: [ self compile: '<foo: #bar: zork:>' selector: #zork ] raise: SyntaxErrorNotification.! !\\n\\n!MethodPragmaTest methodsFor: 'testing-compiler' stamp: 'lr 1/20/2006 02:25'!\\ntestCompileNumber\\n\\tself assertPragma: 'foo: 123' givesKeyword: #foo: arguments: #( 123 ).\\n\\tself assertPragma: 'foo: -123' givesKeyword: #foo: arguments: #( -123 ).\\n\\tself assertPragma: 'foo: 12.3' givesKeyword: #foo: arguments: #( 12.3 ).\\n\\tself assertPragma: 'foo: -12.3' givesKeyword: #foo: arguments: #( -12.3 ).! !\\n\\n!MethodPragmaTest methodsFor: 'testing-compiler' stamp: 'lr 1/20/2006 02:25'!\\ntestCompileString\\n\\tself assertPragma: 'foo: ''''' givesKeyword: #foo: arguments: #( '' ).\\n\\tself assertPragma: 'foo: ''bar''' givesKeyword: #foo: arguments: #( 'bar' ).! !\\n\\n!MethodPragmaTest methodsFor: 'testing-compiler' stamp: 'lr 1/20/2006 02:25'!\\ntestCompileSymbol\\n\\tself assertPragma: 'foo: #bar' givesKeyword: #foo: arguments: #( bar ).\\n\\tself assertPragma: 'foo: #bar:' givesKeyword: #foo: arguments: #( bar: ).\\n\\tself assertPragma: 'foo: #bar:zork:' givesKeyword: #foo: arguments: #( bar:zork: ).! !\\n\\n!MethodPragmaTest methodsFor: 'testing-compiler' stamp: 'lr 7/3/2006 15:00'!\\ntestCompileTemps\\n\\t\\\"Pragmas should be placeable before and after temps.\\\"\\n\\t\\n\\tself \\n\\t\\tshouldnt: [\\n\\t\\t\\tself assert: (self compile: '| temps | <foo>' selector: #zork) \\n\\t\\t\\t\\tpragmas notEmpty ]\\n\\t\\traise: SyntaxErrorNotification.\\n\\tself \\n\\t\\tshouldnt: [\\n\\t\\t\\tself assert: (self compile: '<foo> | temps |' selector: #zork) \\n\\t\\t\\t\\tpragmas notEmpty ]\\n\\t\\traise: SyntaxErrorNotification.! !\\n\\n!MethodPragmaTest methodsFor: 'testing-compiler' stamp: 'lr 2/6/2006 21:04'!\\ntestCompileValue\\n\\tself assertPragma: 'foo: true' givesKeyword: #foo: arguments: #( true ).\\n\\tself assertPragma: 'foo: false' givesKeyword: #foo: arguments: #( false ).\\n\\tself assertPragma: 'foo: nil' givesKeyword: #foo: arguments: #( nil ).\\n\\t\\n\\tself assertPragma: 'foo: String' givesKeyword: #foo: arguments: { String }.\\n\\tself assertPragma: 'foo: Pragma' givesKeyword: #foo: arguments: { Pragma }.! !\\n\\n\\n!MethodPragmaTest methodsFor: 'testing-method' stamp: 'lr 1/20/2006 07:54'!\\ntestMethod\\n\\t| pragma |\\n\\tpragma := self pragma: 'foo' selector: #bar.\\n\\tself assert: pragma method == (self class >> #bar).! !\\n\\n!MethodPragmaTest methodsFor: 'testing-method' stamp: 'md 2/18/2006 19:59'!\\ntestMethodClass\\n\\t| pragma |\\n\\tpragma := self pragma: 'foo' selector: #bar.\\n\\tself assert: pragma methodClass == self class.! !\\n\\n!MethodPragmaTest methodsFor: 'testing-method' stamp: 'lr 1/20/2006 07:54'!\\ntestSelector\\n\\t| pragma |\\n\\tpragma := self pragma: 'foo' selector: #bar.\\n\\tself assert: pragma selector == #bar.! !\\n\\n\\n!MethodPragmaTest methodsFor: 'testing-compiled' stamp: 'lr 2/6/2006 21:03'!\\ntestNoPragma\\n\\t| method |\\n\\tmethod := self compile: '' selector: #foo.\\n\\tself assert: method pragmas = #().! !\\n\\n\\n!MethodPragmaTest methodsFor: 'testing-primitives' stamp: 'lr 1/20/2006 02:31'!\\ntestPrimitiveIndexed1\\n\\t\\\"This test useses the #instVarAt: primitive.\\\"\\n\\t\\n\\tself compile: '<primitive: 74> ^ #inst' selector: #inst.\\n\\tself assert: self inst = #inst.! !\\n\\n!MethodPragmaTest methodsFor: 'testing-primitives' stamp: 'lr 1/20/2006 02:31'!\\ntestPrimitiveIndexed2\\n\\t\\\"This test useses the #asOop primitive.\\\"\\n\\n\\tself compile: '<primitive: 75> ^ #oop' selector: #oop.\\n\\tself assert: self oop = self asOop.! !\\n\\n!MethodPragmaTest methodsFor: 'testing-primitives' stamp: 'lr 1/20/2006 02:42'!\\ntestPrimitiveNamed1\\n\\t\\\"This test useses the #primitiveDirectoryLookup primitive.\\\"\\n\\n\\tself compile: '<primitive: ''primitiveDirectoryLookup'' module: ''FilePlugin''> ^ #lookup' selector: #lookup.\\n\\tself assert: self lookup = #lookup.\\n\\t\\n! !\\n\\n!MethodPragmaTest methodsFor: 'testing-primitives' stamp: 'lr 1/20/2006 02:41'!\\ntestPrimitiveNamed2\\n\\t\\\"This test useses the #primPathNameDelimiter primitive.\\\"\\n\\n\\tself compile: '<primitive: ''primitiveDirectoryDelimitor'' module: ''FilePlugin''> ^ #delim' selector: #delim.\\n\\tself assert: self delim = FileDirectory primPathNameDelimiter.\\n\\t\\n! !\\nObject subclass: #MethodProperties\\n\\tinstanceVariableNames: 'properties pragmas selector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Methods'!\\n!MethodProperties commentStamp: 'lr 2/6/2006 19:31' prior: 0!\\nI am class holding state for compiled methods. All my instance variables should be actually part of the CompiledMethod itself, but the current implementation of the VM doesn't allow this.\\n\\nI am a compact class and optimized for size and speed, since every CompiledMethod points onto an instance of myself. I am mostly polymorphic to the protocol of an identity-dictionary, so that key-value pairs can be easily stored and retreived without the need to add new variables. However keep in mind that instantiating a dictionary consumes much more memory than adding an instance-variable, so it might be clever to add a new variable if the property is going to be used by every compiled method.!\\n\\n\\n!MethodProperties methodsFor: 'accessing' stamp: 'lr 2/6/2006 19:11'!\\npragmas\\n\\t^ pragmas! !\\n\\n!MethodProperties methodsFor: 'accessing' stamp: 'md 2/16/2006 17:50'!\\nselector\\n\\t^selector! !\\n\\n!MethodProperties methodsFor: 'accessing' stamp: 'md 2/16/2006 17:50'!\\nselector: aSymbol\\n\\tselector := aSymbol! !\\n\\n\\n!MethodProperties methodsFor: 'initialization' stamp: 'lr 2/6/2006 19:12'!\\ninitialize\\n\\tsuper initialize.\\n\\tpragmas := #().! !\\n\\n\\n!MethodProperties methodsFor: 'properties' stamp: 'lr 2/6/2006 19:04'!\\nat: aKey\\n\\t\\\"Answer the property value associated with aKey.\\\"\\n\\t\\n\\t^ self at: aKey ifAbsent: [ self error: 'Property not found' ].! !\\n\\n!MethodProperties methodsFor: 'properties' stamp: 'lr 2/6/2006 20:47'!\\nat: aKey ifAbsentPut: aBlock\\n\\t\\\"Answer the property associated with aKey or, if aKey isn't found store the result of evaluating aBlock as new value.\\\"\\n\\t\\n\\t^ self at: aKey ifAbsent: [ self at: aKey put: aBlock value ].! !\\n\\n!MethodProperties methodsFor: 'properties' stamp: 'lr 2/6/2006 19:07'!\\nat: aKey ifAbsent: aBlock\\n\\t\\\"Answer the property value associated with aKey or, if aKey isn't found, answer the result of evaluating aBlock.\\\"\\n\\t\\n\\tproperties isNil ifTrue: [ ^ aBlock value ].\\n\\t^ properties at: aKey ifAbsent: aBlock.! !\\n\\n!MethodProperties methodsFor: 'properties' stamp: 'lr 2/6/2006 19:06'!\\nat: aKey put: anObject\\n\\t\\\"Set the property at aKey to be anObject. If aKey is not found, create a new entry for aKey and set is value to anObject. Answer anObject.\\\"\\n\\n\\tproperties ifNil: [ properties := IdentityDictionary new ].\\n\\t^ properties at: aKey put: anObject.! !\\n\\n!MethodProperties methodsFor: 'properties' stamp: 'lr 2/6/2006 19:11'!\\nincludesKey: aKey\\n\\t\\\"Test if the property aKey is present.\\\"\\n\\t\\n\\t^ properties notNil and: [ properties includesKey: aKey ].! !\\n\\n!MethodProperties methodsFor: 'properties' stamp: 'lr 2/6/2006 20:48'!\\nremoveKey: aKey\\n\\t\\\"Remove the property with aKey. Answer the property or raise an error if aKey isn't found.\\\"\\n\\t\\n\\t^ self removeKey: aKey ifAbsent: [ self error: 'Property not found' ].! !\\n\\n!MethodProperties methodsFor: 'properties' stamp: 'lr 2/6/2006 19:07'!\\nremoveKey: aKey ifAbsent: aBlock\\n\\t\\\"Remove the property with aKey. Answer the value or, if aKey isn't found, answer the result of evaluating aBlock.\\\"\\n\\t\\n\\t| answer |\\n\\tproperties isNil ifTrue: [ ^ aBlock value ].\\n\\tanswer := properties removeKey: aKey ifAbsent: aBlock.\\n\\tproperties isEmpty ifTrue: [ properties := nil ].\\n\\t^ answer.! !\\n\\n\\n!MethodProperties methodsFor: 'private' stamp: 'lr 2/6/2006 20:36'!\\naddPragma: aPragma\\n\\tpragmas := pragmas copyWith: aPragma.! !\\n\\n\\n!MethodProperties methodsFor: 'testing' stamp: 'md 2/19/2006 11:24'!\\nisMethodProperties\\n\\t^true! !\\n\\n\\n!MethodProperties methodsFor: 'copying' stamp: 'md 3/1/2006 15:30'!\\npostCopy\\n\\tproperties := properties copy.\\n\\tpragmas := pragmas copy.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMethodProperties class\\n\\tinstanceVariableNames: ''!\\n\\n!MethodProperties class methodsFor: 'class initialization' stamp: 'lr 2/6/2006 22:06'!\\ninitialize\\n\\tself becomeCompact.! !\\nTestCase subclass: #MethodPropertiesTest\\n\\tinstanceVariableNames: 'method'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'KernelTests-Methods'!\\n\\n!MethodPropertiesTest methodsFor: 'private' stamp: 'lr 2/6/2006 20:43'!\\npropertyDictionaryFor: aMethod\\n\\t^ aMethod properties instVarNamed: 'properties'.! !\\n\\n\\n!MethodPropertiesTest methodsFor: 'running' stamp: 'lr 1/20/2006 19:16'!\\nsetUp\\n\\tmethod := Object >> #halt.! !\\n\\n!MethodPropertiesTest methodsFor: 'running' stamp: 'lr 1/20/2006 19:20'!\\ntearDown\\n\\tObject recompile: #halt from: Object.! !\\n\\n\\n!MethodPropertiesTest methodsFor: 'testing' stamp: 'kwl 7/26/2006 11:41'!\\ntestAllMethodsHaveMethodClass\\n\\tSmalltalk garbageCollect.\\n\\tself assert: (CompiledMethod allInstances\\n\\t\\t\\treject: [:cm | cm literals last isVariableBinding\\n\\t\\t\\t\\t\\tand: [cm literals last value isBehavior\\n\\t\\t\\t\\t\\t\\t\\tor: [cm literals last value isTrait]]]) isEmpty\\n\\t\\t\\tdescription: 'CompiledMethods must have methodClass literal'! !\\n\\n!MethodPropertiesTest methodsFor: 'testing' stamp: 'kwl 7/26/2006 11:40'!\\ntestAllMethodsHaveNewPropertyFormat\\n\\tSmalltalk garbageCollect.\\n\\tself assert: (CompiledMethod allInstances\\n\\t\\t\\treject: [:cm | cm hasNewPropertyFormat]) isEmpty\\n\\t\\tdescription: 'CompiledMethods must have new property format'! !\\n\\n!MethodPropertiesTest methodsFor: 'testing' stamp: 'lr 2/6/2006 22:21'!\\ntestAt\\n\\tself should: [ method properties at: #zork ] raise: Error.\\n\\tself assert: (self propertyDictionaryFor: method) isNil.\\n\\tmethod properties at: #zork put: 'hello'.\\n\\tself assert: (method properties at: #zork) = 'hello'.! !\\n\\n!MethodPropertiesTest methodsFor: 'testing' stamp: 'lr 2/6/2006 22:18'!\\ntestAtIfAbsent\\n\\tself assert: (method properties at: #zork ifAbsent: [ 'hello' ]) = 'hello'.\\n\\tself assert: (self propertyDictionaryFor: method) isNil.\\n\\tmethod properties at: #zork put: 'hi'.\\n\\tself assert: (method properties at: #zork ifAbsent: [ 'hello' ]) = 'hi'.! !\\n\\n!MethodPropertiesTest methodsFor: 'testing' stamp: 'lr 2/6/2006 22:18'!\\ntestAtIfAbsentPut\\n\\tself assert: (method properties at: #zork ifAbsentPut: [ 'hello' ]) = 'hello'.\\n\\tself assert: (method properties at: #zork ifAbsentPut: [ 'hi' ]) = 'hello'.! !\\n\\n!MethodPropertiesTest methodsFor: 'testing' stamp: 'lr 2/6/2006 22:18'!\\ntestAtPut\\n\\tself assert: (method properties at: #zork put: 'hello') = 'hello'.\\n\\tself assert: (method properties at: #zork) = 'hello'.! !\\n\\n!MethodPropertiesTest methodsFor: 'testing' stamp: 'lr 2/6/2006 22:19'!\\ntestIncludesKey\\n\\tself deny: (method properties includesKey: #zork).\\n\\tself assert: (self propertyDictionaryFor: method) isNil.\\n\\tmethod properties at: #zork put: 123.\\n\\tself assert: (method properties includesKey: #zork).! !\\n\\n!MethodPropertiesTest methodsFor: 'testing' stamp: 'lr 2/6/2006 22:18'!\\ntestRemoveKey\\n\\tmethod properties at: #zork put: 'hello'.\\n\\tself should: [ method properties removeKey: #halt ] raise: Error.\\n\\tself assert: (method properties removeKey: #zork) = 'hello'.\\n\\tself assert: (self propertyDictionaryFor: method) isNil.\\n\\tself should: [ method properties removeKey: #zork ] raise: Error.\\n\\tself assert: (self propertyDictionaryFor: method) isNil.! !\\n\\n!MethodPropertiesTest methodsFor: 'testing' stamp: 'lr 2/6/2006 22:18'!\\ntestRemoveKeyifAbsent\\n\\tmethod properties at: #zork put: 'hello'.\\n\\tself assert: (method properties removeKey: #halt ifAbsent: [ 'hi' ]) = 'hi'.\\n\\tself assert: (method properties removeKey: #zork ifAbsent: [ 'hi' ]) = 'hello'.\\n\\tself assert: (self propertyDictionaryFor: method) isNil.\\n\\tself should: (method properties removeKey: #zork ifAbsent: [ 'hi' ]) = 'hi'.\\n\\tself assert: (self propertyDictionaryFor: method) isNil.! !\\nObject subclass: #MethodReference\\n\\tinstanceVariableNames: 'classSymbol classIsMeta methodSymbol stringVersion'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Tools'!\\n!MethodReference commentStamp: 'tlk 5/9/2006 18:43' prior: 0!\\nA MethodReference is is a lightweight proxy for a CompiledMethod. Has methods for pointed to the CompileMethod's source statements, byte codes. Is heavily used my Tools.\\n\\nInstance Variables\\n\\tclassIsMeta:\\t\\t Boolean class vs. instance\\n\\tclassSymbol:\\t\\tSymbol for method's class (without class keyword if meta)\\n\\tmethodSymbol:\\t\\tSymbol for method's selector\\n\\tstringVersion:\\t\\t'Class>>selector:' format\\n\\n!\\n\\n\\n!MethodReference methodsFor: 'comparisons' stamp: 'dgd 3/8/2003 11:54'!\\nhash\\n\\t\\\"Answer a SmallInteger whose value is related to the receiver's \\n\\tidentity.\\\"\\n\\t^ (self species hash bitXor: self classSymbol hash)\\n\\t\\tbitXor: self methodSymbol hash! !\\n\\n!MethodReference methodsFor: 'comparisons' stamp: 'RAA 5/28/2001 11:56'!\\n<= anotherMethodReference\\n\\n\\tclassSymbol < anotherMethodReference classSymbol ifTrue: [^true].\\n\\tclassSymbol > anotherMethodReference classSymbol ifTrue: [^false].\\n\\tclassIsMeta = anotherMethodReference classIsMeta ifFalse: [^classIsMeta not].\\n\\t^methodSymbol <= anotherMethodReference methodSymbol\\n! !\\n\\n!MethodReference methodsFor: 'comparisons' stamp: 'dgd 3/7/2003 13:18'!\\n= anotherMethodReference \\n\\t\\\"Answer whether the receiver and the argument represent the \\n\\tsame object.\\\"\\n\\t^ self species == anotherMethodReference species\\n\\t\\tand: [self classSymbol = anotherMethodReference classSymbol]\\n\\t\\tand: [self classIsMeta = anotherMethodReference classIsMeta]\\n\\t\\tand: [self methodSymbol = anotherMethodReference methodSymbol]! !\\n\\n\\n!MethodReference methodsFor: 'queries' stamp: 'RAA 5/28/2001 06:19'!\\nasStringOrText\\n\\n\\t^stringVersion! !\\n\\n!MethodReference methodsFor: 'queries' stamp: 'RAA 5/28/2001 08:11'!\\nclassIsMeta\\n\\n\\t^classIsMeta! !\\n\\n!MethodReference methodsFor: 'queries' stamp: 'RAA 5/28/2001 08:10'!\\nclassSymbol\\n\\n\\t^classSymbol! !\\n\\n!MethodReference methodsFor: 'queries' stamp: 'md 8/27/2005 17:17'!\\nisValid\\n\\t\\\"Answer whether the receiver represents a current selector or Comment\\\"\\n\\n\\t| aClass |\\n\\tmethodSymbol isDoIt ifTrue: [^ false].\\n\\t(aClass _ self actualClass) ifNil: [^ false].\\n\\t^ (aClass includesSelector: methodSymbol) or:\\n\\t\\t[methodSymbol == #Comment]! !\\n\\n!MethodReference methodsFor: 'queries' stamp: 'RAA 5/28/2001 08:10'!\\nmethodSymbol\\n\\n\\t^methodSymbol! !\\n\\n!MethodReference methodsFor: 'queries' stamp: 'sw 11/5/2001 00:53'!\\nprintOn: aStream\\n\\t\\\"Print the receiver on a stream\\\"\\n\\n\\tsuper printOn: aStream.\\n\\taStream nextPutAll: ' ', self actualClass name, ' >> ', methodSymbol! !\\n\\n!MethodReference methodsFor: 'queries' stamp: 'sr 6/4/2004 01:55'!\\nsourceString\\n\\t^ (self actualClass sourceCodeAt: self methodSymbol) asString! !\\n\\n\\n!MethodReference methodsFor: 'setting' stamp: 'RAA 5/28/2001 07:34'!\\nsetClassAndSelectorIn: csBlock\\n\\n\\t^csBlock value: self actualClass value: methodSymbol! !\\n\\n!MethodReference methodsFor: 'setting' stamp: 'RAA 5/28/2001 06:04'!\\nsetClassSymbol: classSym classIsMeta: isMeta methodSymbol: methodSym stringVersion: aString \\n\\n\\tclassSymbol _ classSym.\\n\\tclassIsMeta _ isMeta.\\n\\tmethodSymbol _ methodSym.\\n\\tstringVersion _ aString.! !\\n\\n!MethodReference methodsFor: 'setting' stamp: 'RAA 5/28/2001 08:06'!\\nsetClass: aClass methodSymbol: methodSym stringVersion: aString \\n\\n\\tclassSymbol _ aClass theNonMetaClass name.\\n\\tclassIsMeta _ aClass isMeta.\\n\\tmethodSymbol _ methodSym.\\n\\tstringVersion _ aString.! !\\n\\n!MethodReference methodsFor: 'setting' stamp: 'RAA 5/28/2001 11:34'!\\nsetStandardClass: aClass methodSymbol: methodSym\\n\\n\\tclassSymbol _ aClass theNonMetaClass name.\\n\\tclassIsMeta _ aClass isMeta.\\n\\tmethodSymbol _ methodSym.\\n\\tstringVersion _ aClass name , ' ' , methodSym.! !\\n\\n\\n!MethodReference methodsFor: 'string version' stamp: 'RAA 5/29/2001 14:44'!\\nstringVersion\\n\\n\\t^stringVersion! !\\n\\n!MethodReference methodsFor: 'string version' stamp: 'RAA 5/29/2001 14:44'!\\nstringVersion: aString\\n\\n\\tstringVersion _ aString! !\\n\\n\\n!MethodReference methodsFor: '*fixUnderscores' stamp: 'cmm 5/1/2006 19:38'!\\nfixUnderscores\\n\\t\\\"Replace underscores with :=. Answer true if fixed or no fix necessary, false if manual fix required\\\"\\n\\n\\t| src cm ts |\\n\\t\\\"Check if we do need to do anything\\\"\\n\\tsrc := self actualClass sourceCodeAt: methodSymbol.\\n\\t(src includes: $_) ifFalse: [^true].\\n\\n\\t\\\"Chicken out if there is a literal underscore\\\"\\n\\tcm := self actualClass compiledMethodAt: methodSymbol.\\n\\t(cm hasLiteralSuchThat: [:lit | \\n\\t\\tlit = $_ or: [lit isString and: [lit includes: $_]]]) ifTrue: [^false].\\n\\n\\t\\\"Otherwise, replace underscores with :=\\\"\\n\\tsrc := src copyReplaceAll: '_' with: ':='.\\n\\tts := self timeStamp.\\n\\tts = '' ifTrue: [ts := nil].\\n\\tself actualClass \\n\\t\\tcompile: src\\n\\t\\tclassified: ClassOrganizer default\\n\\t\\twithStamp: ts \\n\\t\\tnotifying: nil.\\n\\n\\t^true\\n! !\\n\\n\\n!MethodReference methodsFor: '*Kernel-Traits' stamp: 'md 3/3/2006 09:25'!\\nactualClass \\n\\n\\t| actualClass |\\n\\n\\tactualClass _ Smalltalk at: classSymbol ifAbsent: [^nil].\\n\\tclassIsMeta ifTrue: [^actualClass classSide].\\n\\t^actualClass\\n\\n! !\\n\\n\\n!MethodReference methodsFor: '*monticello' stamp: 'ab 8/22/2003 17:55'!\\nasMethodDefinition\\n\\t^ MCMethodDefinition forMethodReference: self! !\\n\\n!MethodReference methodsFor: '*monticello' stamp: 'ab 8/22/2003 17:58'!\\ncategory\\n\\t^ self actualClass organization categoryOfElement: methodSymbol! !\\n\\n!MethodReference methodsFor: '*monticello' stamp: 'ab 8/22/2003 17:58'!\\ncompiledMethod\\n\\t^ self actualClass compiledMethodAt: methodSymbol! !\\n\\n!MethodReference methodsFor: '*monticello' stamp: 'al 10/9/2005 20:05'!\\nisLocalSelector\\n\\t^self actualClass\\n\\t\\tincludesLocalSelector: self methodSymbol! !\\n\\n!MethodReference methodsFor: '*monticello' stamp: 'ab 8/22/2003 17:59'!\\nsource\\n\\t^ (self actualClass sourceCodeAt: methodSymbol) asString withSqueakLineEndings! !\\n\\n!MethodReference methodsFor: '*monticello' stamp: 'ab 8/22/2003 17:58'!\\ntimeStamp\\n\\t^ self compiledMethod timeStamp! !\\n\\n\\n!MethodReference methodsFor: '*packageinfo-base' stamp: 'ab 5/23/2003 22:58'!\\nsourceCode\\n\\t^ self actualClass sourceCodeAt: methodSymbol! !\\n\\n\\n!MethodReference methodsFor: '*OB-Standard' stamp: 'dvf 8/19/2005 17:16'!\\nasNode\\n\\t^OBMethodNode on: self! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMethodReference class\\n\\tinstanceVariableNames: ''!\\n\\n!MethodReference class methodsFor: 'instance creation' stamp: 'ab 2/6/2005 16:22'!\\nclass: aClass selector: aSelector\\n\\t^ self new setStandardClass: aClass methodSymbol: aSelector! !\\nClassTestCase subclass: #MethodReferenceTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tools-Browser-Tests'!\\n\\n!MethodReferenceTest methodsFor: 'Running' stamp: 'sd 11/20/2005 21:27'!\\ntestEquals\\n\\t| aMethodReference anotherMethodReference |\\n\\taMethodReference := MethodReference new.\\n\\tanotherMethodReference := MethodReference new.\\n\\t\\\" \\n\\ttwo fresh instances should be equals between them\\\"\\n\\tself\\n\\t\\tshould: [aMethodReference = anotherMethodReference].\\n\\tself\\n\\t\\tshould: [aMethodReference hash = anotherMethodReference hash].\\n\\t\\\" \\n\\ttwo instances representing the same method (same class and \\n\\tsame selector) should be equals\\\"\\n\\taMethodReference setStandardClass: String methodSymbol: #foo.\\n\\tanotherMethodReference setStandardClass: String methodSymbol: #foo.\\n\\tself\\n\\t\\tshould: [aMethodReference = anotherMethodReference].\\n\\tself\\n\\t\\tshould: [aMethodReference hash = anotherMethodReference hash] ! !\\n\\n!MethodReferenceTest methodsFor: 'Running' stamp: 'sd 11/20/2005 21:27'!\\ntestNotEquals\\n\\t| aMethodReference anotherMethodReference |\\n\\taMethodReference := MethodReference new.\\n\\tanotherMethodReference := MethodReference new.\\n\\t\\\"\\\"\\n\\taMethodReference setStandardClass: String methodSymbol: #foo.\\n\\tanotherMethodReference setStandardClass: String class methodSymbol: #foo.\\n\\t\\\" \\n\\tdifferente classes, same selector -> no more equals\\\"\\n\\tself\\n\\t\\tshouldnt: [aMethodReference = anotherMethodReference].\\n\\t\\\" \\n\\tsame classes, diferente selector -> no more equals\\\"\\n\\tanotherMethodReference setStandardClass: String methodSymbol: #bar.\\n\\tself\\n\\t\\tshouldnt: [aMethodReference = anotherMethodReference] ! !\\nParseNode subclass: #MethodTempsNode\\n\\tinstanceVariableNames: 'temporaries'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Compiler-ParseNodes'!\\nMethodInterface subclass: #MethodWithInterface\\n\\tinstanceVariableNames: 'playerClass'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting'!\\n!MethodWithInterface commentStamp: '<historical>' prior: 0!\\nA MethodInterface bound to an actual class.\\n\\n\\tselector\\t\\t\\t\\t\\tA symbol - the selector being described\\n\\targumentSpecifications\\tA list of specifications for the formal arguments of the method\\n\\tresultSpecification \\t\\tA characterization of the return value of the method\\n\\tuserLevel\\t\\t\\t\\t\\n\\tattributeKeywords\\t\\tA list of symbols, comprising keywords that the user wishes to\\n\\t\\t\\t\\t\\t\\t\\t\\tassociate with this method\\n\\tdefaultStatus\\t\\t\\tThe status to apply to new instances of the class by default\\n\\tdefaultFiresPerTick\\t\\tHow many fires per tick, by default, should be allowed if ticking.\\n\\tplayerClass\\t\\t\\t\\tThe actual class with which this script is associated!\\n\\n\\n!MethodWithInterface methodsFor: 'access' stamp: 'sw 3/28/2001 16:25'!\\nplayerClass\\n\\t\\\"Answer the playerClass associated with the receiver. Note: fixes up cases where the playerClass slot was a Playerxxx object because of an earlier bug\\\"\\n\\n\\t^ (playerClass isKindOf: Class)\\n\\t\\tifTrue:\\n\\t\\t\\t[playerClass]\\n\\t\\tifFalse:\\n\\t\\t\\t[playerClass _ playerClass class]! !\\n\\n\\n!MethodWithInterface methodsFor: 'initialization' stamp: 'sw 1/30/2001 11:37'!\\nconvertFromUserScript: aUserScript\\n\\t\\\"The argument represents an old UserScript object. convert it over\\\"\\n\\n\\tdefaultStatus _ aUserScript status.! !\\n\\n!MethodWithInterface methodsFor: 'initialization' stamp: 'sw 1/26/2001 16:44'!\\ninitialize\\n\\t\\\"Initialize the receiver by setting its inst vars to default values\\\"\\n\\n\\tsuper initialize.\\n\\tdefaultStatus _ #normal! !\\n\\n!MethodWithInterface methodsFor: 'initialization' stamp: 'sw 2/20/2001 03:29'!\\nisTextuallyCoded\\n\\t\\\"Answer whether the receiver is in a textually-coded state. A leftover from much earlier times, this is a vacuous backstop\\\"\\n\\n\\t^ false! !\\n\\n!MethodWithInterface methodsFor: 'initialization' stamp: 'sw 9/12/2001 11:59'!\\nplayerClass: aPlayerClass selector: aSelector\\n\\t\\\"Set the playerClass and selector of the receiver\\\"\\n\\n\\tplayerClass _ aPlayerClass.\\n\\tselector _ aSelector.! !\\n\\n!MethodWithInterface methodsFor: 'initialization' stamp: 'nk 7/2/2004 07:18'!\\nstatus\\n\\t^defaultStatus\\n! !\\n\\n\\n!MethodWithInterface methodsFor: 'rename' stamp: 'sw 2/17/2001 04:10'!\\nokayToRename\\n\\t\\\"Answer whether the receiver is in a state to be renamed.\\\"\\n\\n\\t^ true! !\\n\\n!MethodWithInterface methodsFor: 'rename' stamp: 'sw 3/11/2003 00:01'!\\nrenameScript: newSelector fromPlayer: aPlayer\\n\\n\\t\\\"The receiver's selector has changed to the new selector. Get various things right, including the physical appearance of any Scriptor open on this method\\\"\\n\\n\\n\\n\\tself allScriptEditors do:\\n\\n\\t\\t[:aScriptEditor | aScriptEditor renameScriptTo: newSelector].\\n\\n\\n\\n\\t(selector numArgs = 0 and: [newSelector numArgs = 1])\\n\\n\\t\\tifTrue:\\n\\n\\t\\t\\t[self argumentVariables: (OrderedCollection with:\\n\\n\\t\\t\\t\\t(Variable new name: #parameter type: #Number))].\\n\\n\\t(selector numArgs = 1 and: [newSelector numArgs = 0])\\n\\n\\t\\tifTrue:\\n\\n\\t\\t\\t[self argumentVariables: OrderedCollection new].\\n\\n\\n\\n\\tselector _ newSelector asSymbol.\\n\\n\\tself bringUpToDate.\\n\\n\\tself playerClass atSelector: selector putScript: self.\\n\\n\\tself allScriptActivationButtons do:\\n\\n\\t\\t[:aButton | aButton bringUpToDate].\\n\\n\\n\\n! !\\n\\n\\n!MethodWithInterface methodsFor: 'script editor' stamp: 'sw 3/10/2003 23:58'!\\nallScriptActivationButtons\\n\\n\\t\\\"Answer all the script-activation buttons that exist for this interface\\\"\\n\\n\\n\\n\\t^ ScriptActivationButton allInstances select: \\n\\n\\t\\t[:aButton | aButton uniclassScript == self]! !\\n\\n!MethodWithInterface methodsFor: 'script editor' stamp: 'sw 3/28/2001 16:26'!\\nallScriptEditors\\n\\t\\\"Answer all the script editors that exist for the class and selector of this interface\\\"\\n\\n\\t^ ScriptEditorMorph allInstances select: \\n\\t\\t[:aScriptEditor | aScriptEditor playerScripted class == self playerClass and:\\n\\t\\t\\t[aScriptEditor scriptName == selector]]! !\\n\\n!MethodWithInterface methodsFor: 'script editor' stamp: 'sw 2/17/2001 03:28'!\\ncurrentScriptEditor: anEditor\\n\\t\\\"Set the receiver's currentScriptEditor as indicated, if I care. MethodWithInterface does not care, since it does not hold on to a ScriptEditor. A subclass of mine, however does, or did, care\\\"! !\\n\\n!MethodWithInterface methodsFor: 'script editor' stamp: 'sw 3/28/2001 16:26'!\\ninstantiatedScriptEditorForPlayer: aPlayer\\n\\t\\\"Return a new script editor for the player and selector\\\"\\n\\n\\t| aScriptEditor |\\n\\taScriptEditor _ (self playerClass includesSelector: selector) \\n\\t\\t\\tifTrue: [ScriptEditorMorph new \\n\\t\\t\\t\\tfromExistingMethod: selector \\n\\t\\t\\t\\tforPlayer: aPlayer]\\n\\t\\t\\tifFalse: [ScriptEditorMorph new\\n\\t\\t\\t\\tsetMorph: aPlayer costume\\n\\t\\t\\t\\tscriptName: selector].\\n\\t\\tdefaultStatus == #ticking ifTrue:\\n\\t\\t\\t[aPlayer costume arrangeToStartStepping].\\n\\t\\n\\t^ aScriptEditor! !\\n\\n!MethodWithInterface methodsFor: 'script editor' stamp: 'sw 7/28/2001 01:00'!\\nrecompileScriptFromTilesUnlessTextuallyCoded\\n\\t\\\"Recompile Script From Tiles Unless Textually Coded. For the universal-tiles MethodWithInterface case, this is moot. Used only in support of a reintegration of Open-school forked projects from Sept 2000 in 7/01\\\"! !\\n\\n\\n!MethodWithInterface methodsFor: 'updating' stamp: 'sw 3/28/2001 16:26'!\\nbringUpToDate\\n\\t\\\"Bring all scriptors related to this method up to date. Note that this will not change the senders of this method if the selector changed -- that's something still ahead.\\\"\\n\\n\\t(ScriptEditorMorph allInstances select:\\n\\t\\t[:m | (m playerScripted isMemberOf: self playerClass) and: [m scriptName == selector]])\\n\\t\\t\\tdo:\\n\\t\\t\\t\\t[:m | m bringUpToDate]! !\\n\\n!MethodWithInterface methodsFor: 'updating' stamp: 'sw 2/20/2001 03:43'!\\nrevertToLastSavedTileVersionFor: anEditor\\n\\t\\\"revert to the last saved tile version. Only for universal tiles.\\\"\\n\\n\\tanEditor removeAllButFirstSubmorph.\\n\\tanEditor insertUniversalTiles.\\n\\tanEditor showingMethodPane: false! !\\n\\n!MethodWithInterface methodsFor: 'updating' stamp: 'sw 2/20/2001 03:41'!\\nsaveScriptVersion: timeStamp\\n\\t\\\"Save the tile script version if I do that sort of thing\\\"! !\\nAlignmentMorph subclass: #MidiInputMorph\\n\\tinstanceVariableNames: 'midiPortNumber midiSynth instrumentSelector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Scores'!\\n!MidiInputMorph commentStamp: '<historical>' prior: 0!\\nI am the user interface for a simple software MIDI synthesizer that is driven by external MIDI input. I come with controls for a single MIDI channel (channel 1), but allow channel controls for additional MIDI channels to be added by the user. The volume, pan, and instrument of each channel can be controlled independently.\\n!\\n\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\naddChannel\\n\\t\\\"Add a set of controls for another channel. Prompt the user for the channel number.\\\"\\n\\n\\t| menu existingChannels newChannel |\\n\\tmenu := CustomMenu new.\\n\\texistingChannels := Set new.\\n\\t1 to: 16 do: [:ch | (instrumentSelector at: ch) ifNotNil: [existingChannels add: ch]].\\n\\t1 to: 16 do: [:ch |\\n\\t\\t(existingChannels includes: ch) ifFalse: [\\n\\t\\t\\tmenu add: ch printString action: ch]].\\n\\tnewChannel := menu startUp.\\n\\tnewChannel ifNotNil: [self addChannelControlsFor: newChannel].\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\naddChannelControlsFor: channelIndex\\n\\n\\t| r divider col |\\n\\tr := self makeRow\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #shrinkWrap.\\n\\tr addMorphBack: (self channelNumAndMuteButtonFor: channelIndex).\\n\\tr addMorphBack: (Morph new extent: 10@5; color: color). \\\"spacer\\\"\\n\\tr addMorphBack: (self panAndVolControlsFor: channelIndex).\\n\\n\\tdivider := AlignmentMorph new\\n\\t\\textent: 10@1;\\n\\t\\tborderWidth: 1;\\n\\t\\tlayoutInset: 0;\\n\\t\\tborderColor: #raised;\\n\\t\\tcolor: color;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #rigid.\\n\\n\\tcol := self lastSubmorph.\\n\\tcol addMorphBack: divider.\\n\\tcol addMorphBack: r.\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'gm 2/28/2003 00:00'!\\natChannel: channelIndex from: aPopUpChoice selectInstrument: selection \\n\\t| oldSnd name snd instSelector |\\n\\toldSnd := midiSynth instrumentForChannel: channelIndex.\\n\\t(selection beginsWith: 'edit ') \\n\\t\\tifTrue: \\n\\t\\t\\t[name := selection copyFrom: 6 to: selection size.\\n\\t\\t\\taPopUpChoice contentsClipped: name.\\n\\t\\t\\t(oldSnd isKindOf: FMSound) | (oldSnd isKindOf: LoopedSampledSound) \\n\\t\\t\\t\\tifTrue: [EnvelopeEditorMorph openOn: oldSnd title: name].\\n\\t\\t\\t(oldSnd isKindOf: SampledInstrument) \\n\\t\\t\\t\\tifTrue: [EnvelopeEditorMorph openOn: oldSnd allNotes first title: name].\\n\\t\\t\\t^self].\\n\\tsnd := nil.\\n\\t1 to: instrumentSelector size\\n\\t\\tdo: \\n\\t\\t\\t[:i | \\n\\t\\t\\t(channelIndex ~= i and: \\n\\t\\t\\t\\t\\t[(instSelector := instrumentSelector at: i) notNil \\n\\t\\t\\t\\t\\t\\tand: [selection = instSelector contents]]) \\n\\t\\t\\t\\tifTrue: [snd := midiSynth instrumentForChannel: i]].\\t\\\"use existing instrument prototype\\\"\\n\\tsnd ifNil: \\n\\t\\t\\t[snd := (selection = 'clink' \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[(SampledSound samples: SampledSound coffeeCupClink samplingRate: 11025)]\\n\\t\\t\\t\\t\\t\\tifFalse: [(AbstractSound soundNamed: selection) ])copy ].\\n\\tmidiSynth instrumentForChannel: channelIndex put: snd.\\n\\t(instrumentSelector at: channelIndex) contentsClipped: selection! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nchannelNumAndMuteButtonFor: channelIndex\\n\\n\\t| muteButton instSelector r |\\n\\tmuteButton := SimpleSwitchMorph new\\n\\t\\tonColor: (Color r: 1.0 g: 0.6 b: 0.6);\\n\\t\\toffColor: color;\\n\\t\\tcolor: color;\\n\\t\\tlabel: 'Mute';\\n\\t\\ttarget: midiSynth;\\n\\t\\tactionSelector: #mutedForChannel:put:;\\n\\t\\targuments: (Array with: channelIndex).\\n\\tinstSelector := PopUpChoiceMorph new\\n\\t\\textent: 95@14;\\n\\t\\tcontentsClipped: 'oboe1';\\n\\t\\ttarget: self;\\n\\t\\tactionSelector: #atChannel:from:selectInstrument:;\\n\\t\\tgetItemsSelector: #instrumentChoicesForChannel:;\\n\\t\\tgetItemsArgs: (Array with: channelIndex).\\n\\tinstSelector arguments:\\n\\t\\t(Array with: channelIndex with: instSelector).\\n\\tinstrumentSelector at: channelIndex put: instSelector.\\n\\n\\tr := self makeRow\\n\\t\\thResizing: #rigid;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\textent: 70@10.\\n\\tr addMorphBack:\\n\\t\\t(StringMorph\\n\\t\\t\\tcontents: channelIndex printString\\n\\t\\t\\tfont: (TextStyle default fontOfSize: 24)).\\n\\tchannelIndex < 10\\n\\t\\tifTrue: [r addMorphBack: (Morph new color: color; extent: 19@8)] \\\"spacer\\\"\\n\\t\\tifFalse: [r addMorphBack: (Morph new color: color; extent: 8@8)]. \\\"spacer\\\"\\n\\tr addMorphBack: instSelector.\\n\\tr addMorphBack: (AlignmentMorph newRow color: color). \\\"spacer\\\"\\n\\tr addMorphBack: muteButton.\\n\\t^ r\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'jm 1/13/1999 07:33'!\\ncloseMIDIPort\\n\\n\\tmidiSynth isOn ifTrue: [midiSynth stopMIDITracking].\\n\\tmidiSynth closeMIDIPort.\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'jm 1/6/1999 07:55'!\\ndisableReverb: aBoolean\\n\\n\\taBoolean\\n\\t\\tifTrue: [SoundPlayer stopReverb]\\n\\t\\tifFalse: [SoundPlayer startReverb].\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninstrumentChoicesForChannel: channelIndex\\n\\n\\t| names inst |\\n\\tnames := AbstractSound soundNames asOrderedCollection.\\n\\tnames := names collect: [:n |\\n\\t\\tinst := AbstractSound soundNamed: n.\\n\\t\\t(inst isKindOf: UnloadedSound)\\n\\t\\t\\tifTrue: [n, '(out)']\\n\\t\\t\\tifFalse: [n]].\\n\\tnames add: 'clink'.\\n\\tnames add: 'edit ', (instrumentSelector at: channelIndex) contents.\\n\\t^ names asArray\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninvokeMenu\\n\\t\\\"Invoke a menu of additonal commands.\\\"\\n\\n\\t| aMenu |\\n\\taMenu := CustomMenu new.\\n\\taMenu add: 'add channel' translated action: #addChannel.\\n\\taMenu add: 'reload instruments' translated target: AbstractSound selector: #updateScorePlayers.\\n\\tmidiSynth isOn ifFalse: [\\n\\t\\taMenu add: 'set MIDI port' translated action: #setMIDIPort.\\n\\t\\tmidiSynth midiPort\\n\\t\\t\\tifNotNil: [aMenu add: 'close MIDI port' translated action: #closeMIDIPort]].\\t\\n\\taMenu invokeOn: self defaultSelection: nil.\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nmakeControls\\n\\n\\t| bb r reverbSwitch onOffSwitch |\\n\\tbb := SimpleButtonMorph new\\n\\t\\ttarget: self;\\n\\t\\tborderColor: #raised;\\n\\t\\tborderWidth: 2;\\n\\t\\tcolor: color.\\n\\tr := AlignmentMorph newRow.\\n\\tr color: bb color; borderWidth: 0; layoutInset: 0.\\n\\tr hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5@5.\\n\\tr addMorphBack: (\\n\\t\\tbb label: '<>';\\n\\t\\t\\tactWhen: #buttonDown;\\n\\t\\t\\tactionSelector: #invokeMenu).\\n\\tonOffSwitch := SimpleSwitchMorph new\\n\\t\\toffColor: color;\\n\\t\\tonColor: (Color r: 1.0 g: 0.6 b: 0.6);\\n\\t\\tborderWidth: 2;\\n\\t\\tlabel: 'On';\\n\\t\\tactionSelector: #toggleOnOff;\\n\\t\\ttarget: self;\\n\\t\\tsetSwitchState: false.\\n\\tr addMorphBack: onOffSwitch.\\n\\treverbSwitch := SimpleSwitchMorph new\\n\\t\\toffColor: color;\\n\\t\\tonColor: (Color r: 1.0 g: 0.6 b: 0.6);\\n\\t\\tborderWidth: 2;\\n\\t\\tlabel: 'Reverb Disable';\\n\\t\\tactionSelector: #disableReverb:;\\n\\t\\ttarget: self;\\n\\t\\tsetSwitchState: SoundPlayer isReverbOn not.\\n\\tr addMorphBack: reverbSwitch.\\n\\t^ r\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'ar 11/9/2000 21:19'!\\nmakeRow\\n\\n\\t^ AlignmentMorph newRow\\n\\t\\tcolor: color;\\n\\t\\tlayoutInset: 0;\\n\\t\\twrapCentering: #center; cellPositioning: #leftCenter;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #shrinkWrap\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\npanAndVolControlsFor: channelIndex\\n\\n\\t| volSlider panSlider c r middleLine |\\n\\tvolSlider := SimpleSliderMorph new\\n\\t\\tcolor: color;\\n\\t\\textent: 101@2;\\n\\t\\ttarget: midiSynth;\\n\\t\\targuments: (Array with: channelIndex);\\n\\t\\tactionSelector: #volumeForChannel:put:;\\n\\t\\tminVal: 0.0;\\n\\t\\tmaxVal: 1.0;\\n\\t\\tadjustToValue: (midiSynth volumeForChannel: channelIndex).\\n\\tpanSlider := SimpleSliderMorph new\\n\\t\\tcolor: color;\\n\\t\\textent: 101@2;\\n\\t\\ttarget: midiSynth;\\n\\t\\targuments: (Array with: channelIndex);\\n\\t\\tactionSelector: #panForChannel:put:;\\n\\t\\tminVal: 0.0;\\n\\t\\tmaxVal: 1.0;\\t\\t\\n\\t\\tadjustToValue: (midiSynth panForChannel: channelIndex).\\n\\tc := AlignmentMorph newColumn\\n\\t\\tcolor: color;\\n\\t\\tlayoutInset: 0;\\n\\t\\twrapCentering: #center; cellPositioning: #topCenter;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #shrinkWrap.\\n\\tmiddleLine := Morph new \\\"center indicator for pan slider\\\"\\n\\t\\tcolor: (Color r: 0.4 g: 0.4 b: 0.4);\\n\\t\\textent: 1@(panSlider height - 4);\\n\\t\\tposition: panSlider center x@(panSlider top + 2).\\n\\tpanSlider addMorphBack: middleLine.\\n\\tr := self makeRow.\\n\\tr addMorphBack: (StringMorph contents: '0').\\n\\tr addMorphBack: volSlider.\\n\\tr addMorphBack: (StringMorph contents: '10').\\n\\tc addMorphBack: r.\\n\\tr := self makeRow.\\n\\tr addMorphBack: (StringMorph contents: 'L').\\n\\tr addMorphBack: panSlider.\\n\\tr addMorphBack: (StringMorph contents: 'R').\\n\\tc addMorphBack: r.\\n\\t^ c\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsetMIDIPort\\n\\n\\t| portNum |\\n\\tportNum := SimpleMIDIPort outputPortNumFromUser.\\n\\tportNum ifNil: [^ self].\\n\\tmidiPortNumber := portNum.\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ntoggleOnOff\\n\\n\\tmidiSynth isOn\\n\\t\\tifTrue: [\\n\\t\\t\\tmidiSynth stopMIDITracking]\\n\\t\\tifFalse: [\\n\\t\\t\\tmidiPortNumber ifNil: [self setMIDIPort].\\n\\t\\t\\tmidiPortNumber ifNil: [midiPortNumber := 0].\\n\\t\\t\\tmidiSynth midiPort: (SimpleMIDIPort openOnPortNumber: midiPortNumber).\\n\\t\\t\\tmidiSynth startMIDITracking].\\n! !\\n\\n!MidiInputMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nupdateInstrumentsFromLibraryExcept: soundsBeingEdited\\n\\t\\\"The instrument library has been modified. Update my instruments with the new versions from the library. Use a single instrument prototype for all parts with the same name; this allows the envelope editor to edit all the parts by changing a single sound prototype.\\\"\\n\\n\\t\\\"soundsBeingEdited is a collection of sounds being edited (by an EnvelopeEditor). If any of my instruments share one of these, then they will be left alone so as not to disturb that dynamic linkage.\\\"\\n\\n\\t| unloadPostfix myInstruments name displaysAsUnloaded isUnloaded |\\n\\tunloadPostfix := '(out)'.\\n\\tmyInstruments := Dictionary new.\\n\\t1 to: instrumentSelector size do: [:i |\\n\\t\\tname := (instrumentSelector at: i) contents.\\n\\t\\tdisplaysAsUnloaded := name endsWith: unloadPostfix.\\n\\t\\tdisplaysAsUnloaded ifTrue: [\\n\\t\\t\\tname := name copyFrom: 1 to: name size - unloadPostfix size].\\n\\t\\t(myInstruments includesKey: name) ifFalse: [\\n\\t\\t\\tmyInstruments at: name put:\\n\\t\\t\\t\\t(name = 'clink'\\n\\t\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\t\\t(SampledSound\\n\\t\\t\\t\\t\\t\\t\\tsamples: SampledSound coffeeCupClink\\n\\t\\t\\t\\t\\t\\t\\tsamplingRate: 11025) copy]\\n\\t\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\t\\t(AbstractSound\\n\\t\\t\\t\\t\\t\\t\\tsoundNamed: name\\n\\t\\t\\t\\t\\t\\t\\tifAbsent: [\\n\\t\\t\\t\\t\\t\\t\\t\\t(instrumentSelector at: i) contentsClipped: 'default'.\\n\\t\\t\\t\\t\\t\\t\\t\\tFMSound default]) copy])].\\n\\t\\t(soundsBeingEdited includes: (midiSynth instrumentForChannel: i)) ifFalse:\\n\\t\\t\\t[\\\"Do not update any instrument that is currently being edited\\\"\\n\\t\\t\\tmidiSynth instrumentForChannel: i put: (myInstruments at: name)].\\n\\n\\t\\t\\\"update loaded/unloaded status in instrumentSelector if necessary\\\"\\n\\t\\tisUnloaded := (myInstruments at: name) isKindOf: UnloadedSound.\\n\\t\\t(displaysAsUnloaded and: [isUnloaded not])\\n\\t\\t\\tifTrue: [(instrumentSelector at: i) contentsClipped: name].\\n\\t\\t(displaysAsUnloaded not and: [isUnloaded])\\n\\t\\t\\tifTrue: [(instrumentSelector at: i) contentsClipped: name, unloadPostfix]].\\n! !\\n\\n\\n!MidiInputMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:38'!\\ndefaultBorderWidth\\n\\t\\\"answer the default border width for the receiver\\\"\\n\\t^ 2! !\\n\\n!MidiInputMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:28'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color veryLightGray! !\\n\\n!MidiInputMorph methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\tself listDirection: #topToBottom;\\n\\t wrapCentering: #center;\\n\\t\\t cellPositioning: #topCenter;\\n\\t hResizing: #spaceFill;\\n\\t vResizing: #spaceFill;\\n\\t layoutInset: 3.\\n\\tmidiPortNumber := nil.\\n\\tmidiSynth := MIDISynth new.\\n\\tinstrumentSelector := Array new: 16.\\n\\tself removeAllMorphs.\\n\\tself addMorphBack: self makeControls.\\n\\tself addMorphBack: (AlignmentMorph newColumn color: color;\\n\\t\\t\\t layoutInset: 0).\\n\\tself addChannelControlsFor: 1.\\n\\tself extent: 20 @ 20! !\\nObject subclass: #MidiPrimTester\\n\\tinstanceVariableNames: 'port'\\n\\tclassVariableNames: 'CanSetClock CanUseSemaphore ClockTicksPerSec EchoOn EventsAvailable FlushDriver HasBuffer HasDurs HasInputClock Installed UseControllerCache Version'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Serial Port'!\\n!MidiPrimTester commentStamp: '<historical>' prior: 0!\\nThis class simply demonstrates and tests the MIDI primitives. MIDI applications should use Stephen Pope's MIDIPort class, which will replace this one.\\n\\nThe Macintosh, and perhaps some other platforms, can send and receive MIDI data over a serial port by using an external clock signal supplied by an external MIDI adapter to generate the correct MIDI baud rate. Typical clock speeds of such adapters are 1, 2, or 0.5 MHz. This clock speed can be specified when a MIDI port is opened. On other platforms, this clock speed parameter is ignored.\\n!\\n\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIClosePort: portNum\\n\\n\\t<primitive: 'primitiveMIDIClosePort' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIGetClock\\n\\n\\t<primitive: 'primitiveMIDIGetClock' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIGetPortCount\\n\\n\\t<primitive: 'primitiveMIDIGetPortCount' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIGetPortDirectionality: portNum\\n\\n\\t<primitive: 'primitiveMIDIGetPortDirectionality' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIGetPortName: portNum\\n\\n\\t<primitive: 'primitiveMIDIGetPortName' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIOpenPort: portNum readSemaIndex: readSemaIndex interfaceClockRate: interfaceClockRate\\n\\t\\\"Open the given MIDI port. If non-zero, readSemaIndex specifies the index in the external objects array of a semaphore to be signalled when incoming MIDI data is available. Not all platforms support signalling the read semaphore. InterfaceClockRate specifies the clock rate of the external MIDI interface adaptor on Macintosh computers; it is ignored on other platforms.\\\"\\n\\n\\t<primitive: 'primitiveMIDIOpenPort' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIParameterGet: whichParameter\\n\\n\\t<primitive: 'primitiveMIDIParameterGetOrSet' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIParameterSet: whichParameter to: newValue\\n\\n\\t<primitive: 'primitiveMIDIParameterGetOrSet' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIReadPort: portNum into: byteArray\\n\\n\\t<primitive: 'primitiveMIDIRead' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n!MidiPrimTester methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimMIDIWritePort: portNum from: byteArray at: midiClockValue\\n\\n\\t<primitive: 'primitiveMIDIWrite' module: 'MIDIPlugin'>\\n\\tself primitiveFailed.\\n! !\\n\\n\\n!MidiPrimTester methodsFor: 'tests' stamp: 'jm 5/18/1998 10:30'!\\ngetDriverParameters\\n\\t\\\"Return a string that describes this platform's MIDI parameters.\\\"\\n\\t\\\"MidiPrimTester new getDriverParameters\\\"\\n\\n\\t| s parameterNames v |\\n\\tparameterNames _ #(Installed Version HasBuffer HasDurs CanSetClock CanUseSemaphore EchoOn UseControllerCache EventsAvailable FlushDriver ClockTicksPerSec HasInputClock).\\n\\n\\ts _ WriteStream on: String new.\\n\\ts cr.\\n\\t1 to: parameterNames size do: [:i |\\n\\t\\tv _ self primMIDIParameterGet: i.\\n\\t\\ts nextPutAll: (parameterNames at: i).\\n\\t\\ts nextPutAll: ' = '.\\n\\t\\ts print: v; cr].\\n\\n\\ts nextPutAll: 'MIDI Echoing is '.\\n\\t(self canTurnOnParameter: EchoOn)\\n\\t\\tifTrue: [s nextPutAll: 'supported.'; cr]\\n\\t\\tifFalse: [s nextPutAll: 'not supported.'; cr].\\n\\n\\ts nextPutAll: 'Controller Caching is '.\\n\\t(self canTurnOnParameter: UseControllerCache)\\n\\t\\tifTrue: [s nextPutAll: 'supported.'; cr]\\n\\t\\tifFalse: [s nextPutAll: 'not supported.'; cr].\\n\\n\\t^ s contents\\n! !\\n\\n!MidiPrimTester methodsFor: 'tests' stamp: 'jm 5/18/1998 15:33'!\\ngetInputForSeconds: seconds onPort: portNum\\n\\t\\\"Collect MIDI input from the given port for the given number of seconds, and answer a string describing the data read.\\\"\\n\\t\\\"MidiPrimTester new getInputForSeconds: 5 onPort: 0\\\"\\n\\n\\t| buf bufList endTime n midiStartTime s t |\\n\\t\\\"collect the data\\\"\\n\\tself openPort: portNum andDo: [\\n\\t\\tbuf _ ByteArray new: 1000.\\n\\t\\tbufList _ OrderedCollection new.\\n\\t\\tmidiStartTime _ self primMIDIGetClock.\\n\\t\\tendTime _ Time millisecondClockValue + (seconds * 1000).\\n\\t\\t[Time millisecondClockValue < endTime] whileTrue: [\\n\\t\\t\\tn _ self primMIDIReadPort: portNum into: buf.\\n\\t\\t\\tn > 0 ifTrue: [bufList add: (buf copyFrom: 1 to: n)].\\n\\t\\t\\t(Delay forMilliseconds: 5) wait]].\\n\\n\\t\\\"format the data into a string\\\"\\n\\ts _ WriteStream on: String new.\\n\\ts cr.\\n\\tbufList do: [:b |\\n\\t\\tt _ (self bufferTimeStampFrom: b) - midiStartTime.\\n\\t\\ts print: t.\\n\\t\\ts nextPutAll: ': '.\\n\\t\\t5 to: b size do: [:i | s print: (b at: i); space].\\n\\t\\ts cr].\\n\\t^ s contents\\n! !\\n\\n!MidiPrimTester methodsFor: 'tests' stamp: 'jm 5/18/1998 10:05'!\\ngetPortList\\n\\t\\\"Return a string that describes this platform's MIDI ports.\\\"\\n\\t\\\"MidiPrimTester new getPortList\\\"\\n\\n\\t| s portCount dir directionString |\\n\\ts _ WriteStream on: String new.\\n\\ts cr; nextPutAll: 'MIDI Ports:'; cr.\\n\\tportCount _ self primMIDIGetPortCount.\\n\\t0 to: portCount - 1 do: [:i |\\n\\t\\ts tab.\\n\\t\\ts print: i; nextPutAll: ': '. \\n\\t\\ts nextPutAll: (self primMIDIGetPortName: i).\\n\\t\\tdir _ self primMIDIGetPortDirectionality: i.\\n\\t\\tdirectionString _ dir printString. \\\"default\\\"\\n\\t\\tdir = 1 ifTrue: [directionString _ '(in)'].\\n\\t\\tdir = 2 ifTrue: [directionString _ '(out)'].\\n\\t\\tdir = 3 ifTrue: [directionString _ '(in/out)'].\\n\\t\\ts space; nextPutAll: directionString; cr].\\n\\t^ s contents\\n! !\\n\\n!MidiPrimTester methodsFor: 'tests' stamp: 'jm 5/18/1998 11:24'!\\nplayDrumRoll: mSecsBetweenNotes count: tapCount onPort: portNum\\n\\t\\\"MidiPrimTester new playDrumRoll: 75 count: 64 onPort: 0\\\"\\n\\t\\\"Play middle-C tapCount times with the given space between notes. This example works best with a short percussive voice, like a drum.\\\"\\n\\t\\\"Details: This test can be used to investigate the real-time performance of your system. On a 110 MHz PowerPC Mac, this method can genererate very fast and smooth drum rolls up to about 100 beats/sec (10 mSecs between notes). However, many factors can prevent one from seeing this level of performance including a slow CPU, lack of a level-2 cache, networking or other background processes stealing chunks of processor time from Squeak, or a sluggish MIDI synthesizer.\\\"\\n\\t\\\"Details: By default, this method does an incremental GC on every note. While not really needed for this example, it illustrates a useful technique for real-time processing in Squeak: do an incremental GC when you know you have a few milliseconds of idle time to avoid triggering one during a time-critical task. In this case, we're also using the GC time to provide a small delay between the note-on and note-off events. If the GC time is too short, as it could be on a fast machine, the note may not sound at all unless you add a few milliseconds of additional delay!!\\\"\\n\\t\\\"Note: This example works best if the VM's millisecond clock has 1 millisecond resolution.\\\"\\n\\n\\t| gcDuringNote noteOn noteOff endTime waitTime |\\n\\tgcDuringNote _ true.\\n\\t\\\"these events use running status, so the command byte is omitted\\\"\\n\\tnoteOn _ #(60 100) as: ByteArray.\\n\\tnoteOff _ #(60 0) as: ByteArray.\\n\\tself primMIDIOpenPort: portNum readSemaIndex: 0 interfaceClockRate: 1000000.\\n\\n\\t\\\"send an initial event with command byte to initiate running status\\\"\\n\\tself primMIDIWritePort: portNum from: (#(144 60 0) as: ByteArray) at: 0.\\n\\n\\t1 to: tapCount do: [:i |\\n\\t\\tendTime _ Time millisecondClockValue + mSecsBetweenNotes.\\n\\t\\tself primMIDIWritePort: portNum from: noteOn at: 0.\\n\\t\\tgcDuringNote\\n\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\\"do quick GC; takes a few milliseconds and provides the note-down time\\\"\\n\\t\\t\\t\\t\\\"Note: if GC is too fast on your machine, you need to add a few mSecs delay!!\\\"\\n\\t\\t\\t\\tSmalltalk garbageCollectMost]\\n\\t\\t\\tifFalse: [(Delay forMilliseconds: 3) wait].\\n\\n\\t\\tself primMIDIWritePort: portNum from: noteOff at: 0.\\n\\t\\twaitTime _ endTime - Time millisecondClockValue.\\n\\t\\twaitTime > 0 ifTrue: [(Delay forMilliseconds: waitTime) wait]].\\n\\n\\tself primMIDIClosePort: portNum.\\n! !\\n\\n!MidiPrimTester methodsFor: 'tests' stamp: 'jm 5/18/1998 15:16'!\\nplayNoteOnPort: portNum\\n\\t\\\"MidiPrimTester new playNoteOnPort: 0\\\"\\n\\n\\t| noteOn noteOff bytesWritten |\\n\\tnoteOn _ #(144 60 100) as: ByteArray.\\n\\tnoteOff _ #(144 60 0) as: ByteArray.\\n\\tself openPort: portNum andDo: [\\n\\t\\tbytesWritten _ self primMIDIWritePort: portNum from: noteOn at: 0.\\n\\t\\t(Delay forMilliseconds: 500) wait.\\n\\t\\tbytesWritten _ bytesWritten + (self primMIDIWritePort: portNum from: noteOff at: 0)].\\n\\n\\tbytesWritten = 6 ifFalse: [self error: 'not all bytes were sent'].\\n! !\\n\\n!MidiPrimTester methodsFor: 'tests' stamp: 'jm 5/18/1998 15:17'!\\nplayScale: mSecsPerNote onPort: portNum\\n\\t\\\"MidiPrimTester new playScale: 130 onPort: 0\\\"\\n\\n\\t| noteOn noteOff |\\n\\tnoteOn _ #(144 0 100) as: ByteArray.\\n\\tnoteOff _ #(144 0 0) as: ByteArray.\\n\\tself openPort: portNum andDo: [\\n\\t\\t#(60 62 64 65 67 69 71 72 74 72 71 69 67 65 64 62 60) do: [:midiKey | \\n\\t\\t\\tnoteOn at: 2 put: midiKey.\\n\\t\\t\\tnoteOff at: 2 put: midiKey.\\n\\t\\t\\tself primMIDIWritePort: portNum from: noteOn at: 0.\\n\\t\\t\\t(Delay forMilliseconds: mSecsPerNote - 10) wait.\\n\\t\\t\\tself primMIDIWritePort: portNum from: noteOff at: 0.\\n\\t\\t\\t(Delay forMilliseconds: 10) wait]].\\n! !\\n\\n\\n!MidiPrimTester methodsFor: 'private' stamp: 'jm 5/18/1998 12:48'!\\nbufferTimeStampFrom: aByteArray\\n\\t\\\"Return the timestamp from the given MIDI input buffer. Assume the given buffer is at least 4 bytes long.\\\"\\n\\n\\t^ ((aByteArray at: 1) bitShift: 24) +\\n\\t ((aByteArray at: 2) bitShift: 16) +\\n\\t ((aByteArray at: 3) bitShift: 8) +\\n\\t (aByteArray at: 4)\\n! !\\n\\n!MidiPrimTester methodsFor: 'private' stamp: 'jm 5/18/1998 12:48'!\\ncanTurnOnParameter: whichParameter\\n\\t\\\"Return true if the given MIDI parameter can be turned on. Leave the parameter in its orginal state.\\\"\\n\\n\\t| old canSet |\\n\\told _ self primMIDIParameterGet: whichParameter.\\n\\tself primMIDIParameterSet: whichParameter to: 1.\\n\\tcanSet _ (self primMIDIParameterGet: whichParameter) = 1.\\n\\tself primMIDIParameterSet: whichParameter to: old.\\n\\t^ canSet\\n! !\\n\\n!MidiPrimTester methodsFor: 'private' stamp: 'jm 5/18/1998 15:32'!\\nopenPort: portNum andDo: aBlock\\n\\t\\\"Open the given MIDI port, evaluate the block, and close the port again. Answer the value of the block.\\\"\\n\\n\\t| result |\\n\\tself primMIDIClosePort: portNum.\\n\\tself primMIDIOpenPort: portNum readSemaIndex: 0 interfaceClockRate: 1000000.\\n\\tresult _ aBlock value.\\n\\tself primMIDIClosePort: portNum.\\n\\t^ result\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMidiPrimTester class\\n\\tinstanceVariableNames: ''!\\n\\n!MidiPrimTester class methodsFor: 'class initialization' stamp: 'yo 12/3/2004 17:05'!\\ninitialize\\n\\t\\\"Initialize the MIDI parameter constants.\\\"\\n\\t\\\"MidiPrimTester initialize\\\"\\n\\n\\tInstalled _ 1.\\n\\t\\t\\\"Read-only. Return 1 if a MIDI driver is installed, 0 if not.\\n\\t\\t On OMS-based MIDI drivers, this returns 1 only if the OMS\\n\\t\\t system is properly installed and configured.\\\"\\n\\n\\tVersion _ 2.\\n\\t\\t\\\"Read-only. Return the integer version number of this MIDI driver.\\n\\t\\t The version numbering sequence is relative to a particular driver.\\n\\t\\t That is, version 3 of the Macintosh MIDI driver is not necessarily\\n\\t\\t related to version 3 of the Win95 MIDI driver.\\\"\\n\\n\\tHasBuffer _ 3.\\n\\t\\t\\\"Read-only. Return 1 if this MIDI driver has a time-stamped output\\n\\t\\t buffer, 0 otherwise. Such a buffer allows the client to schedule\\n\\t\\t MIDI output packets to be sent later. This can allow more precise\\n\\t\\t timing, since the driver uses timer interrupts to send the data\\n\\t\\t at the right time even if the processor is in the midst of a\\n\\t\\t long-running Squeak primitive or is running some other application\\n\\t\\t or system task.\\\"\\n\\n\\tHasDurs _ 4.\\n\\t\\t\\\"Read-only. Return 1 if this MIDI driver supports an extended\\n\\t\\t primitive for note-playing that includes the note duration and\\n\\t\\t schedules both the note-on and the note-off messages in the\\n\\t\\t driver. Otherwise, return 0.\\\"\\n\\n\\tCanSetClock _ 5.\\n\\t\\t\\\"Read-only. Return 1 if this MIDI driver's clock can be set\\n\\t\\t via an extended primitive, 0 if not.\\\"\\n\\n\\tCanUseSemaphore _ 6.\\n\\t\\t\\\"Read-only. Return 1 if this MIDI driver can signal a semaphore\\n\\t\\t when MIDI input arrives. Otherwise, return 0. If this driver\\n\\t\\t supports controller caching and it is enabled, then incoming\\n\\t\\t controller messages will not signal the semaphore.\\\"\\n\\n\\tEchoOn _ 7.\\n\\t\\t\\\"Read-write. If this flag is set to a non-zero value, and if\\n\\t\\t the driver supports echoing, then incoming MIDI events will\\n\\t\\t be echoed immediately. If this driver does not support echoing,\\n\\t\\t then queries of this parameter will always return 0 and\\n\\t\\t attempts to change its value will do nothing.\\\"\\n\\n\\tUseControllerCache _ 8.\\n\\t\\t\\\"Read-write. If this flag is set to a non-zero value, and if\\n\\t\\t the driver supports a controller cache, then the driver will\\n\\t\\t maintain a cache of the latest value seen for each MIDI controller,\\n\\t\\t and control update messages will be filtered out of the incoming\\n\\t\\t MIDI stream. An extended MIDI primitive allows the client to\\n\\t\\t poll the driver for the current value of each controller. If\\n\\t\\t this driver does not support a controller cache, then queries\\n\\t\\t of this parameter will always return 0 and attempts to change\\n\\t\\t its value will do nothing.\\\"\\n\\n\\tEventsAvailable _ 9.\\n\\t\\t\\\"Read-only. Return the number of MIDI packets in the input queue.\\\"\\n\\n\\tFlushDriver _ 10.\\n\\t\\t\\\"Write-only. Setting this parameter to any value forces the driver\\n\\t\\t to flush its I/0 buffer, discarding all unprocessed data. Reading\\n\\t\\t this parameter returns 0. Setting this parameter will do nothing\\n\\t\\t if the driver does not support buffer flushing.\\\"\\n\\n\\tClockTicksPerSec _ 11.\\n\\t\\t\\\"Read-only. Return the MIDI clock rate in ticks per second.\\\"\\n\\n\\tHasInputClock _ 12.\\n\\t\\t\\\"Read-only. Return 1 if this MIDI driver timestamps incoming\\n\\t\\t MIDI data with the current value of the MIDI clock, 0 otherwise.\\n\\t\\t If the driver does not support such timestamping, then the\\n\\t\\t client must read input data frequently and provide its own\\n\\t\\t timestamping.\\\"\\n! !\\nObject subclass: #MimeConverter\\n\\tinstanceVariableNames: 'dataStream mimeStream'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Collections-Streams'!\\n\\n!MimeConverter methodsFor: 'accessing' stamp: 'tk 12/9/97 13:55'!\\ndataStream\\n\\t^dataStream! !\\n\\n!MimeConverter methodsFor: 'accessing' stamp: 'tk 12/9/97 13:51'!\\ndataStream: anObject\\n\\tdataStream _ anObject! !\\n\\n!MimeConverter methodsFor: 'accessing' stamp: 'tk 12/9/97 13:53'!\\nmimeStream\\n\\t^mimeStream! !\\n\\n!MimeConverter methodsFor: 'accessing' stamp: 'tk 12/9/97 13:51'!\\nmimeStream: anObject\\n\\tmimeStream _ anObject! !\\n\\n\\n!MimeConverter methodsFor: 'conversion' stamp: 'bf 11/12/1998 13:30'!\\nmimeDecode\\n\\t\\\"Do conversion reading from mimeStream writing to dataStream\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n!MimeConverter methodsFor: 'conversion' stamp: 'bf 11/12/1998 13:31'!\\nmimeEncode\\n\\t\\\"Do conversion reading from dataStream writing to mimeStream\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMimeConverter class\\n\\tinstanceVariableNames: ''!\\n\\n!MimeConverter class methodsFor: 'convenience' stamp: 'bf 3/10/2000 14:47'!\\nforEncoding: encodingString\\n\\t\\\"Answer a converter class for the given encoding or nil if unknown\\\"\\n\\tencodingString ifNil: [^nil].\\n\\t^ encodingString asLowercase caseOf: \\n\\t\\t{ ['base64'] -> [Base64MimeConverter].\\n\\t\\t ['quoted-printable'] -> [QuotedPrintableMimeConverter]}\\n\\t\\totherwise: [].\\n! !\\n\\n!MimeConverter class methodsFor: 'convenience' stamp: 'bf 3/10/2000 14:43'!\\nmimeDecode: aStringOrStream as: contentsClass\\n\\t^ contentsClass streamContents: [:out |\\n\\t\\tself mimeDecode: aStringOrStream to: out]! !\\n\\n!MimeConverter class methodsFor: 'convenience' stamp: 'bf 3/10/2000 14:40'!\\nmimeDecode: aStringOrStream to: outStream\\n\\tself new\\n\\t\\tmimeStream: (aStringOrStream isStream\\n\\t\\t\\tifTrue: [aStringOrStream]\\n\\t\\t\\tifFalse: [ReadStream on: aStringOrStream]);\\n\\t\\tdataStream: outStream;\\n\\t\\tmimeDecode! !\\n\\n!MimeConverter class methodsFor: 'convenience' stamp: 'bf 3/10/2000 14:40'!\\nmimeEncode: aCollectionOrStream\\n\\t^ String streamContents: [:out |\\n\\t\\tself mimeEncode: aCollectionOrStream to: out]! !\\n\\n!MimeConverter class methodsFor: 'convenience' stamp: 'bf 3/10/2000 14:40'!\\nmimeEncode: aCollectionOrStream to: outStream\\n\\tself new\\n\\t\\tdataStream: (aCollectionOrStream isStream\\n\\t\\t\\tifTrue: [aCollectionOrStream]\\n\\t\\t\\tifFalse: [ReadStream on: aCollectionOrStream]);\\n\\t\\tmimeStream: outStream;\\n\\t\\tmimeEncode! !\\nPolygonMorph subclass: #MixedCurveMorph\\n\\tinstanceVariableNames: 'slopeClamps'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Basic-NewCurve'!\\n!MixedCurveMorph commentStamp: '<historical>' prior: 0!\\nA MixedCurveMorph is Curve that can be broken up into separately curved segments. It allows for the creation of matching edges( e. g. for jigsaw puzzle pieces).\\n\\nInstance Variables\\n\\tslopeClamps:\\t\\t<Array>\\n\\nslopeClamps\\n\\t- elements of array are either 0 or nil. Indicating whether slope for the corresponding vertex is 0@0 or unknown and therefore to be calculated. There is one element for each vertex.\\n\\t\\n\\t\\n!\\n\\n\\n!MixedCurveMorph methodsFor: 'access' stamp: 'wiz 2/8/2006 18:59'!\\nclamps\\n\\\" Return a collection of clamps the same size as vertices.\\n\\tIf necessary default to unclamped slopes.\\n\\\"\\n\\nslopeClamps \\n\\tifNil: [ ^ slopeClamps := Array new: vertices size ] .\\nslopeClamps size = vertices size\\n\\tifFalse: [ ^ slopeClamps := Array new: vertices size ] . \\n\\t^ slopeClamps ! !\\n\\n!MixedCurveMorph methodsFor: 'access' stamp: 'wiz 2/8/2006 17:44'!\\nhandleColorAt: vertIndex\\n \\\" clamped handles are cyan and \\n\\tunclamped handles are yellow.\\\"\\n\\n(self clamps at: vertIndex ) ifNil: [ ^ Color yellow ] .\\n^ Color cyan \\n! !\\n\\n\\n!MixedCurveMorph methodsFor: 'editing' stamp: 'wiz 2/8/2006 17:50'!\\nclickVertex: ix event: evt fromHandle: handle\\n\\\" Toggle the state of the clamp. \\\"\\n\\\"Note: self clamps assures slopeClamps will be same size as vertices\\\"\\n\\n(self clamps at: ix) \\n\\tifNil:\\t [ slopeClamps at: ix put: 0 ]\\n\\tifNotNil: [ slopeClamps at: ix put: nil ] .\\n\\tself setVertices: vertices .\\n\\t\\n! !\\n\\n!MixedCurveMorph methodsFor: 'editing' stamp: 'wiz 2/8/2006 18:01'!\\ndeleteVertexAt: anIndex\\n\\t\\t\\t(slopeClamps :=\\n\\t\\t\\t\\t\\t\\tslopeClamps\\n\\t\\t\\t\\t\\t\\tcopyReplaceFrom: anIndex\\n\\t\\t\\t\\t\\t\\tto: anIndex\\n\\t\\t\\t\\t\\t\\twith: Array new) .\\n\\t\\t\\tself\\n\\t\\t\\t\\tsetVertices: (vertices\\n\\t\\t\\t\\t\\t\\tcopyReplaceFrom: anIndex\\n\\t\\t\\t\\t\\t\\tto: anIndex\\n\\t\\t\\t\\t\\t\\twith: Array new).\\n\\t\\t\\t\\t\\t\\t! !\\n\\n!MixedCurveMorph methodsFor: 'editing' stamp: 'wiz 2/8/2006 18:29'!\\ninsertVertexAt: anIndex put: aValue\\n\\t\\\"New vertexs are unclamped.\\\"\\n\\t\\\"Note: order is important. \\n\\tThe clamps array must match vertex size before setVertices: is performed.\\\"\\n\\tslopeClamps := slopeClamps \\n\\t\\tcopyReplaceFrom: anIndex + 1 to: anIndex with: (Array with: nil).\\n\\tself setVertices: (vertices copyReplaceFrom: anIndex + 1 to: anIndex \\n\\t\\t\\t\\t\\t\\t\\t\\t\\twith: (Array with: aValue)).! !\\n\\n\\n!MixedCurveMorph methodsFor: 'initialization' stamp: 'wiz 2/12/2006 05:59'!\\ninitialize\\n\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\tself extent: 32@20 .\\n\\n\\tself rectOval.\\n\\tself clamps . \\\"This initializes slopeClamps.\\\"\\n\\tslopeClamps at: 1 put: 0 .\\n\\tslopeClamps at: 4 put: 0 .\\n\\t\\n\\tclosed _ true.\\n\\tsmoothCurve _ true.\\n\\tarrows _ #none.\\n\\tself computeBounds! !\\n\\n\\n!MixedCurveMorph methodsFor: 'smoothing' stamp: 'wiz 2/18/2006 12:53'!\\nslopes: knots \\n\\t\\\"Choose slopes according to state of polygon and preferences\\\"\\n\\tself isCurvy\\n\\t\\tifFalse: [^ knots segmentedSlopes].\\n\\t^ (closed\\n\\t\\t\\tand: [self isCurvier])\\n\\t\\tifTrue: [ knots closedCubicSlopes: self clamps ]\\n\\t\\tifFalse: [knots naturalCubicSlopes: self clamps ]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMixedCurveMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!MixedCurveMorph class methodsFor: 'as yet unclassified' stamp: 'wiz 2/12/2006 17:12'!\\ndescriptionForPartsBin\\n\\t^ self partName:\\t'Mixed'\\n\\t\\tcategories:\\t\\t#('Graphics' 'Basic')\\n\\t\\tdocumentation:\\t'A Curve with optional bends and segments. Shift click to get handles.\\n\\t\\t\\tClick handles to change bends. Move handles to move the points.'! !\\nAbstractSound subclass: #MixedSound\\n\\tinstanceVariableNames: 'sounds leftVols rightVols soundDone'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n\\n!MixedSound methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nduration\\n\\t\\\"Answer the duration of this sound in seconds.\\\"\\n\\n\\t| dur |\\n\\tdur := 0.\\n\\tsounds do: [:snd | dur := dur max: snd duration].\\n\\t^ dur\\n! !\\n\\n!MixedSound methodsFor: 'accessing' stamp: 'jm 12/16/2001 20:23'!\\nisStereo\\n\\n\\t^ true\\n! !\\n\\n!MixedSound methodsFor: 'accessing' stamp: 'jm 2/4/98 13:37'!\\nsounds\\n\\n\\t^ sounds\\n! !\\n\\n\\n!MixedSound methodsFor: 'composition'!\\n+ aSound\\n\\t\\\"Return the mix of the receiver and the argument sound.\\\"\\n\\n\\t^ self add: aSound\\n! !\\n\\n!MixedSound methodsFor: 'composition' stamp: 'jm 1/5/98 13:47'!\\nadd: aSound\\n\\t\\\"Add the given sound with a pan setting of centered and no attenuation.\\\"\\n\\n\\tself add: aSound pan: 0.5 volume: 1.0.\\n! !\\n\\n!MixedSound methodsFor: 'composition' stamp: 'jm 1/5/98 13:47'!\\nadd: aSound pan: leftRightPan\\n\\t\\\"Add the given sound with the given left-right panning and no attenuation.\\\"\\n\\n\\tself add: aSound pan: leftRightPan volume: 1.0.\\n! !\\n\\n!MixedSound methodsFor: 'composition' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nadd: aSound pan: leftRightPan volume: volume\\n\\t\\\"Add the given sound with the given left-right pan, where 0.0 is full left, 1.0 is full right, and 0.5 is centered. The loudness of the sound will be scaled by volume, which ranges from 0 to 1.0.\\\"\\n\\n\\t| pan vol |\\n\\tpan := ((leftRightPan * ScaleFactor) asInteger max: 0) min: ScaleFactor.\\n\\tvol := ((volume * ScaleFactor) asInteger max: 0) min: ScaleFactor.\\n\\tsounds := sounds copyWith: aSound.\\n\\tleftVols := leftVols copyWith: ((ScaleFactor - pan) * vol) // ScaleFactor.\\n\\trightVols := rightVols copyWith: (pan * vol) // ScaleFactor.\\n! !\\n\\n\\n!MixedSound methodsFor: 'copying' stamp: 'jm 12/15/97 19:13'!\\ncopy\\n\\t\\\"Copy my component sounds.\\\"\\n\\n\\t^ super copy copySounds\\n! !\\n\\n!MixedSound methodsFor: 'copying' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncopySounds\\n\\t\\\"Private!! Support for copying. Copy my component sounds and settings array.\\\"\\n\\n\\tsounds := sounds collect: [:s | s copy].\\n\\tleftVols := leftVols copy.\\n\\trightVols := rightVols copy.\\n! !\\n\\n\\n!MixedSound methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitialize\\n\\n\\tsuper initialize.\\n\\tsounds := Array new.\\n\\tleftVols := Array new.\\n\\trightVols := Array new.\\n! !\\n\\n\\n!MixedSound methodsFor: 'sound generation' stamp: 'jm 11/25/97 13:40'!\\ndoControl\\n\\n\\tsuper doControl.\\n\\t1 to: sounds size do: [:i | (sounds at: i) doControl].\\n! !\\n\\n!MixedSound methodsFor: 'sound generation' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nmixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol\\n\\t\\\"Play a number of sounds concurrently. The level of each sound can be set independently for the left and right channels.\\\"\\n\\n\\t| snd left right |\\n\\t1 to: sounds size do: [:i |\\n\\t\\t(soundDone at: i) ifFalse: [\\n\\t\\t\\tsnd := sounds at: i.\\n\\t\\t\\tleft := (leftVol * (leftVols at: i)) // ScaleFactor.\\n\\t\\t\\tright := (rightVol * (rightVols at: i)) // ScaleFactor.\\n\\t\\t\\tsnd samplesRemaining > 0\\n\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\tsnd mixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: left rightVol: right]\\n\\t\\t\\t\\tifFalse: [soundDone at: i put: true]]].\\n! !\\n\\n!MixedSound methodsFor: 'sound generation' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nreset\\n\\n\\tsuper reset.\\n\\tsounds do: [:snd | snd reset].\\n\\tsoundDone := (Array new: sounds size) atAllPut: false.\\n! !\\n\\n!MixedSound methodsFor: 'sound generation' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsamplesRemaining\\n\\n\\t| remaining r |\\n\\tremaining := 0.\\n\\t1 to: sounds size do: [:i |\\n\\t\\tr := (sounds at: i) samplesRemaining.\\n\\t\\tr > remaining ifTrue: [remaining := r]].\\n\\n\\t^ remaining\\n! !\\n\\n!MixedSound methodsFor: 'sound generation' stamp: 'jm 1/10/1999 08:45'!\\nstopGracefully\\n\\t\\\"End this note with a graceful decay. If the note has envelopes, determine the decay time from its envelopes.\\\"\\n\\n\\tsuper stopGracefully.\\n\\tsounds do: [:s | s stopGracefully].\\n! !\\nStream subclass: #MockSocketStream\\n\\tinstanceVariableNames: 'atEnd inStream outStream'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'NetworkTests-Kernel'!\\n\\n!MockSocketStream methodsFor: 'accessing' stamp: 'fbs 3/22/2004 12:51'!\\natEnd: aBoolean\\n\\tatEnd := aBoolean.! !\\n\\n!MockSocketStream methodsFor: 'accessing' stamp: 'fbs 3/22/2004 13:29'!\\ninStream\\n\\t^inStream! !\\n\\n!MockSocketStream methodsFor: 'accessing' stamp: 'fbs 3/22/2004 13:08'!\\noutStream\\n\\t^outStream! !\\n\\n\\n!MockSocketStream methodsFor: 'initialize-release' stamp: 'fbs 3/22/2004 13:29'!\\ninitialize\\n\\tself resetInStream.\\n\\tself resetOutStream.! !\\n\\n\\n!MockSocketStream methodsFor: 'stream in' stamp: 'fbs 3/22/2004 13:10'!\\nnextLine\\n\\t^self nextLineCrLf! !\\n\\n!MockSocketStream methodsFor: 'stream in' stamp: 'fbs 3/22/2004 13:09'!\\nnextLineCrLf\\n\\t^(self upToAll: String crlf).! !\\n\\n!MockSocketStream methodsFor: 'stream in' stamp: 'fbs 3/22/2004 13:28'!\\nresetInStream\\n\\tinStream := WriteStream on: ''.! !\\n\\n!MockSocketStream methodsFor: 'stream in' stamp: 'fbs 3/22/2004 13:09'!\\nupToAll: delims\\n\\t^self inStream upToAll: delims.! !\\n\\n\\n!MockSocketStream methodsFor: 'stream out' stamp: 'fbs 3/22/2004 13:28'!\\nresetOutStream\\n\\toutStream := WriteStream on: ''.! !\\n\\n!MockSocketStream methodsFor: 'stream out' stamp: 'fbs 3/22/2004 13:07'!\\nsendCommand: aString\\n\\tself outStream\\n\\t\\tnextPutAll: aString;\\n\\t\\tnextPutAll: String crlf.! !\\n\\n\\n!MockSocketStream methodsFor: 'testing' stamp: 'fbs 3/22/2004 13:08'!\\natEnd\\n\\t^self inStream atEnd.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMockSocketStream class\\n\\tinstanceVariableNames: ''!\\n\\n!MockSocketStream class methodsFor: 'instance creation' stamp: 'fbs 3/22/2004 12:46'!\\non: socket\\n\\t^self basicNew initialize! !\\nController subclass: #ModalController\\n\\tinstanceVariableNames: 'modeActive'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Framework'!\\n!ModalController commentStamp: '<historical>' prior: 0!\\nI am a controller that puts the poor user into a mode by not relinquishing control. However, I do pass control onto my underlings. Some underling is expected to end the mode by sending me 'close'. Watch out Larry Tesler, the mode lives on...\\n!\\n\\n\\n!ModalController methodsFor: 'as yet unclassified' stamp: 'jm 5/1/1998 07:05'!\\nclose\\n\\t\\\"This is how we leave the mode.\\\" \\n\\n\\tmodeActive _ false.\\n! !\\n\\n!ModalController methodsFor: 'as yet unclassified' stamp: 'jm 5/1/1998 07:02'!\\ncontrolInitialize\\n\\n\\tmodeActive _ true.\\n\\t^ super controlInitialize\\n! !\\n\\n!ModalController methodsFor: 'as yet unclassified' stamp: 'jm 5/1/1998 07:00'!\\nisControlActive\\n\\n\\t^ modeActive\\n! !\\n\\n!ModalController methodsFor: 'as yet unclassified' stamp: 'jm 5/1/1998 07:00'!\\nisControlWanted\\n\\n\\t^ modeActive\\n! !\\nStandardSystemView subclass: #ModalSystemWindowView\\n\\tinstanceVariableNames: 'modalBorder'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-FileList'!\\n!ModalSystemWindowView commentStamp: '<historical>' prior: 0!\\nI am a view for a Modal System Window. I vary from StandardSystemView, of which I am a subclass in a few ways:\\n\\n\\t(1) I use ModalController as my default controller;\\n\\t(2) When asked to update with the symbol #close, I direct the controller to close;\\n\\t(3) I display a slightly different title bar with no control boxes.!\\n\\n\\n!ModalSystemWindowView methodsFor: 'controller access' stamp: 'acg 2/9/2000 00:58'!\\ndefaultControllerClass\\n\\n\\t^ModalController! !\\n\\n\\n!ModalSystemWindowView methodsFor: 'displaying' stamp: 'acg 2/18/2000 20:24'!\\ndisplay\\n\\n\\tsuper display.\\n\\tself displayLabelBackground: false.\\n\\tself displayLabelText.\\n! !\\n\\n!ModalSystemWindowView methodsFor: 'displaying' stamp: 'acg 2/19/2000 00:59'!\\ndisplayBorder\\n\\t\\\"Display the receiver's border (using the receiver's borderColor).\\\"\\n\\n\\tmodalBorder ifFalse: [^super displayBorder].\\n\\n\\tDisplay\\n\\t\\tborder: self displayBox\\n\\t\\twidthRectangle: (1@1 corner: 2@2)\\n\\t\\trule: Form over\\n\\t\\tfillColor: Color black.\\n\\tDisplay\\n\\t\\tborder: (self displayBox insetBy: (1@1 corner: 2@2))\\n\\t\\twidthRectangle: (4@4 corner: 3@3)\\n\\t\\trule: Form over\\n\\t\\tfillColor: (Color r: 16rEA g: 16rEA b: 16rEA).\\n! !\\n\\n!ModalSystemWindowView methodsFor: 'displaying' stamp: 'acg 2/9/2000 07:21'!\\ndisplayLabelBoxes\\n\\t\\\"Modal dialogs don't have closeBox or growBox.\\\"\\n! !\\n\\n\\n!ModalSystemWindowView methodsFor: 'initialize-release' stamp: 'acg 2/18/2000 20:41'!\\nborderWidth: anObject\\n\\n\\tmodalBorder _ false.\\n\\t^super borderWidth: anObject! !\\n\\n!ModalSystemWindowView methodsFor: 'initialize-release' stamp: 'acg 2/19/2000 00:50'!\\ninitialize \\n\\t\\\"Refer to the comment in View|initialize.\\\"\\n\\tsuper initialize.\\n\\tself borderWidth: 5.\\n\\tself noLabel.\\n\\tmodalBorder _ true.! !\\n\\n\\n!ModalSystemWindowView methodsFor: 'label access' stamp: 'acg 2/9/2000 08:35'!\\nbackgroundColor\\n\\t^Color lightYellow! !\\n\\n\\n!ModalSystemWindowView methodsFor: 'modal dialog' stamp: 'BG 12/13/2002 11:33'!\\ndoModalDialog\\n\\n\\t| savedArea |\\n\\tself resizeInitially.\\n\\tself resizeTo: \\n\\t\\t((self windowBox)\\n\\t\\t\\talign: self windowBox center\\n\\t\\t\\twith: Display boundingBox aboveCenter).\\n\\tsavedArea _ Form fromDisplay: self windowBox.\\n\\tself displayEmphasized.\\n\\tself controller startUp.\\n\\tself release.\\n\\tsavedArea displayOn: Display at: self windowOrigin.\\n! !\\n\\n\\n!ModalSystemWindowView methodsFor: 'model access' stamp: 'acg 2/9/2000 00:57'!\\nupdate: aSymbol\\n\\taSymbol = #close\\n\\t\\tifTrue: [^self controller close].\\n\\t^super update: aSymbol! !\\nObject subclass: #Model\\n\\tinstanceVariableNames: 'dependents'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Objects'!\\n!Model commentStamp: '<historical>' prior: 0!\\nProvides a superclass for classes that function as models. The only behavior provided is fast dependents maintenance, which bypasses the generic DependentsFields mechanism. 1/23/96 sw!\\n\\n\\n!Model methodsFor: 'copying' stamp: 'tk 10/21/2002 12:59'!\\nveryDeepFixupWith: deepCopier \\n\\t\\\"See if the dependents are being copied also. If so, point at the new copies. (The dependent has self as its model.)\\n\\tDependents handled in class Object, when the model is not a Model, are fixed up in Object veryDeepCopy.\\\"\\n\\n\\t| originalDependents refs newDependent |\\n\\tsuper veryDeepFixupWith: deepCopier.\\n\\toriginalDependents _ dependents.\\n\\toriginalDependents ifNil: [\\n\\t\\t^self.\\n\\t\\t].\\n\\tdependents _ nil.\\n\\trefs _ deepCopier references.\\n\\toriginalDependents\\n\\t\\tdo: [:originalDependent | \\n\\t\\t\\tnewDependent _ refs\\n\\t\\t\\t\\t\\t\\tat: originalDependent\\n\\t\\t\\t\\t\\t\\tifAbsent: [].\\n\\t\\t\\tnewDependent\\n\\t\\t\\t\\tifNotNil: [self addDependent: newDependent]]!\\n]style[(29 206 19 395)f1b,f1,f1LObject veryDeepCopy;,f1! !\\n\\n!Model methodsFor: 'copying' stamp: 'RB 9/20/2001 16:25'!\\nveryDeepInner: deepCopier\\n\\t\\\"Shallow copy dependents and fix them later\\\"\\n! !\\n\\n\\n!Model methodsFor: 'dependents' stamp: 'sma 2/29/2000 19:26'!\\ncanDiscardEdits\\n\\t\\\"Answer true if none of the views on this model has unaccepted edits that matter.\\\"\\n\\n\\tdependents ifNil: [^ true].\\n\\t^ super canDiscardEdits\\n! !\\n\\n!Model methodsFor: 'dependents' stamp: 'sw 2/6/2001 04:13'!\\ncontainingWindow\\n\\t\\\"Answer the window that holds the receiver. The dependents technique is odious and may not be airtight, if multiple windows have the same model.\\\"\\n\\n\\t^ self dependents detect:\\n\\t\\t[:d | ((d isKindOf: SystemWindow orOf: StandardSystemView) or: [d isKindOf: MVCWiWPasteUpMorph]) and: [d model == self]] ifNone: [nil]! !\\n\\n!Model methodsFor: 'dependents' stamp: 'jm 3/24/98 15:12'!\\nhasUnacceptedEdits\\n\\t\\\"Answer true if any of the views on this model has unaccepted edits.\\\"\\n\\n\\tdependents == nil ifTrue: [^ false].\\n\\t^ super hasUnacceptedEdits\\n! !\\n\\n!Model methodsFor: 'dependents' stamp: 'sma 2/29/2000 19:54'!\\nmyDependents\\n\\t^ dependents! !\\n\\n!Model methodsFor: 'dependents' stamp: 'sma 2/29/2000 19:54'!\\nmyDependents: aCollectionOrNil\\n\\tdependents _ aCollectionOrNil! !\\n\\n!Model methodsFor: 'dependents' stamp: 'gm 2/16/2003 20:37'!\\ntopView\\n\\t\\\"Find the first top view on me. Is there any danger of their being two with the same model? Any danger from ungarbage collected old views? Ask if schedulled?\\\"\\n\\n\\tdependents ifNil: [^nil].\\n\\tSmalltalk isMorphic \\n\\t\\tifTrue: \\n\\t\\t\\t[dependents \\n\\t\\t\\t\\tdo: [:v | ((v isSystemWindow) and: [v isInWorld]) ifTrue: [^v]].\\n\\t\\t\\t^nil].\\n\\tdependents do: [:v | v superView ifNil: [v model == self ifTrue: [^v]]].\\n\\t^nil! !\\n\\n\\n!Model methodsFor: 'keyboard' stamp: 'nk 6/29/2004 14:46'!\\narrowKey: aChar from: view\\n\\t\\\"backstop; all the PluggableList* classes actually handle arrow keys, and the models handle other keys.\\\"\\n\\t^false! !\\n\\n\\n!Model methodsFor: 'menus' stamp: 'di 4/11/98 11:34'!\\nperform: selector orSendTo: otherTarget\\n\\t\\\"Selector was just chosen from a menu by a user. If can respond, then perform it on myself. If not, send it to otherTarget, presumably the editPane from which the menu was invoked.\\\" \\n\\n\\t\\\"default is that the editor does all\\\"\\n\\t^ otherTarget perform: selector.! !\\n\\n!Model methodsFor: 'menus' stamp: 'tk 4/17/1998 17:28'!\\nselectedClass\\n\\t\\\"All owners of TextViews are asked this during a doIt\\\"\\n\\t^ nil! !\\n\\n!Model methodsFor: 'menus' stamp: 'zz 3/2/2004 23:49'!\\nstep\\n\\t\\\"Default for morphic models is no-op\\\"! !\\n\\n!Model methodsFor: 'menus' stamp: 'sw 12/15/2000 13:21'!\\ntrash\\n\\t\\\"What should be displayed if a trash pane is restored to initial state\\\"\\n\\n\\t^ ''! !\\n\\n!Model methodsFor: 'menus' stamp: 'sw 12/15/2000 13:21'!\\ntrash: ignored\\n\\t\\\"Whatever the user submits to the trash, it need not be saved.\\\"\\n\\n\\t^ true! !\\n\\n\\n!Model methodsFor: '*services-base' stamp: 'rr 3/21/2006 11:54'!\\nrequestor\\n\\t^ Requestor default! !\\n\\n\\n!Model methodsFor: '*Tools' stamp: 'ar 9/27/2005 20:59'!\\naddItem: classAndMethod\\n\\t\\\"Make a linked message list and put this method in it\\\"\\n\\t| list |\\n\\n\\tself flag: #mref.\\t\\\"classAndMethod is a String\\\"\\n\\n\\tMessageSet \\n\\t\\tparse: classAndMethod \\n\\t\\ttoClassAndSelector: [ :class :sel |\\n\\t\\t\\tclass ifNil: [^self].\\n\\t\\t\\tlist := OrderedCollection with: (\\n\\t\\t\\t\\tMethodReference new\\n\\t\\t\\t\\t\\tsetClass: class \\n\\t\\t\\t\\t\\tmethodSymbol: sel \\n\\t\\t\\t\\t\\tstringVersion: classAndMethod\\n\\t\\t\\t).\\n\\t\\t\\tMessageSet \\n\\t\\t\\t\\topenMessageList: list \\n\\t\\t\\t\\tname: 'Linked by HyperText'.\\n\\t\\t]\\n\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nModel class\\n\\tinstanceVariableNames: ''!\\n\\n!Model class methodsFor: 'toolbuilder' stamp: 'ar 2/11/2005 16:26'!\\nbuildWith: toolBuilder\\n\\t^self new buildWith: toolBuilder! !\\nObject subclass: #ModelExtension\\n\\tinstanceVariableNames: 'interests lock'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Traits-LocalSends'!\\n\\n!ModelExtension methodsFor: 'access to cache' stamp: 'dvf 9/14/2005 11:27'!\\nhaveInterestsIn: aClass \\n\\tlock critical: [^interests includes: aClass]\\n! !\\n\\n\\n!ModelExtension methodsFor: 'interests' stamp: 'dvf 9/14/2005 11:11'!\\nlostInterest: client inAll: classes\\n\\tlock critical: [interests removeAll: classes]! !\\n\\n!ModelExtension methodsFor: 'interests' stamp: 'dvf 9/2/2005 11:43'!\\nlostInterest: client in: class\\n\\tself lostInterest: client inAll: {class}! !\\n\\n!ModelExtension methodsFor: 'interests' stamp: 'dvf 9/14/2005 11:28'!\\nnoteInterestOf: client inAll: classes\\n\\tlock critical: [interests addAll: classes].! !\\n\\n!ModelExtension methodsFor: 'interests' stamp: 'dvf 9/2/2005 11:44'!\\nnoteInterestOf: client in: class\\n\\tself noteInterestOf: client inAll: {class}! !\\n\\n\\n!ModelExtension methodsFor: 'invalidation' stamp: 'dvf 9/14/2005 11:11'!\\ninitialize\\n\\tlock := Semaphore forMutualExclusion. \\n\\tinterests := IdentityBag new.\\n\\tSystemChangeNotifier uniqueInstance \\n\\t\\tnotify: self\\n\\t\\tofSystemChangesOfItem: #class\\n\\t\\tusing: #classChanged:.\\n\\tSystemChangeNotifier uniqueInstance \\n\\t\\tnotify: self\\n\\t\\tofSystemChangesOfItem: #method\\n\\t\\tusing: #classChanged:.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nModelExtension class\\n\\tinstanceVariableNames: 'current'!\\n\\n!ModelExtension class methodsFor: 'accessing' stamp: 'dvf 9/1/2005 21:16'!\\ncurrent\\n\\t^current! !\\n\\n!ModelExtension class methodsFor: 'accessing' stamp: 'dvf 9/1/2005 21:16'!\\ncurrent: anObject\\n\\t^current := anObject! !\\n\\n\\n!ModelExtension class methodsFor: 'initialize-release' stamp: 'dvf 9/2/2005 12:20'!\\ninitialize\\n\\tself isAbstract not ifTrue:\\n\\t\\t[self current: self new]! !\\n\\n!ModelExtension class methodsFor: 'initialize-release' stamp: 'dvf 9/2/2005 12:20'!\\nisAbstract\\n\\t^self == ModelExtension! !\\n\\n\\n!ModelExtension class methodsFor: 'instance creation' stamp: 'dvf 9/1/2005 21:16'!\\ndoWithTemporaryInstance: aBlock \\n\\t| singleton |\\n\\tsingleton := self current.\\n\\t\\n\\t[self current: self new.\\n\\taBlock value] ensure: [self current: singleton]! !\\nModifiedEvent subclass: #ModifiedClassDefinitionEvent\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Change Notification'!\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'accessing' stamp: 'NS 1/20/2004 19:30'!\\nclassVarNames\\n\\t^ item classVarNames asSet! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'accessing' stamp: 'NS 1/20/2004 19:29'!\\ninstVarNames\\n\\t^ item instVarNames asSet! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'accessing' stamp: 'NS 1/20/2004 19:30'!\\noldClassVarNames\\n\\t^ oldItem classVarNames asSet! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'accessing' stamp: 'NS 1/20/2004 19:29'!\\noldInstVarNames\\n\\t^ oldItem instVarNames asSet! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'accessing' stamp: 'NS 1/20/2004 19:31'!\\noldSharedPools\\n\\t^ oldItem sharedPools! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'accessing' stamp: 'NS 1/20/2004 19:28'!\\noldSuperclass\\n\\t^ oldItem superclass! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'accessing' stamp: 'NS 1/20/2004 19:31'!\\nsharedPools\\n\\t^ item sharedPools! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'accessing' stamp: 'NS 1/20/2004 19:28'!\\nsuperclass\\n\\t^ item superclass! !\\n\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'testing' stamp: 'NS 1/20/2004 19:31'!\\nareClassVarsModified\\n\\t^ self classVarNames ~= self oldClassVarNames! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'testing' stamp: 'NS 1/20/2004 19:30'!\\nareInstVarsModified\\n\\t^ self instVarNames ~= self oldInstVarNames! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'testing' stamp: 'NS 1/20/2004 19:32'!\\nareSharedPoolsModified\\n\\t^ self sharedPools ~= self oldSharedPools! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: 'testing' stamp: 'NS 1/20/2004 19:29'!\\nisSuperclassModified\\n\\t^ item superclass ~~ oldItem superclass! !\\n\\n\\n!ModifiedClassDefinitionEvent methodsFor: '*Kernel-Classes' stamp: 'al 7/17/2004 21:48'!\\nanyChanges\\n\\t^ self isSuperclassModified or: [self areInstVarsModified or: [self areClassVarsModified or: [self areSharedPoolsModified or: [self isTraitCompositionModified]]]]! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: '*Kernel-Classes' stamp: 'al 7/17/2004 21:59'!\\nisTraitCompositionModified\\n\\t^self traitComposition printString ~= self oldTraitComposition printString! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: '*Kernel-Classes' stamp: 'al 7/17/2004 21:50'!\\noldTraitComposition\\n\\t^ oldItem traitComposition! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: '*Kernel-Classes' stamp: 'al 7/18/2004 10:47'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream\\n\\t\\tnextPutAll: ' Super: ';\\n\\t\\tprint: self isSuperclassModified;\\n\\t\\tnextPutAll: ' TraitComposition: ';\\n\\t\\tprint: self isTraitCompositionModified;\\n\\t\\tnextPutAll: ' InstVars: ';\\n\\t\\tprint: self areInstVarsModified;\\n\\t\\tnextPutAll: ' ClassVars: ';\\n\\t\\tprint: self areClassVarsModified;\\n\\t\\tnextPutAll: ' SharedPools: ';\\n\\t\\tprint: self areSharedPoolsModified.! !\\n\\n!ModifiedClassDefinitionEvent methodsFor: '*Kernel-Classes' stamp: 'al 7/17/2004 21:50'!\\ntraitComposition\\n\\t^ item traitComposition! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nModifiedClassDefinitionEvent class\\n\\tinstanceVariableNames: ''!\\n\\n!ModifiedClassDefinitionEvent class methodsFor: 'accessing' stamp: 'NS 1/20/2004 12:26'!\\nsupportedKinds\\n\\t\\\"All the kinds of items that this event can take.\\\"\\n\\t\\n\\t^ Array with: self classKind! !\\n\\n\\n!ModifiedClassDefinitionEvent class methodsFor: 'instance creation' stamp: 'NS 1/20/2004 11:52'!\\nclassDefinitionChangedFrom: oldClass to: newClass\\n\\t| instance |\\n\\tinstance := self item: newClass kind: self classKind.\\n\\tinstance oldItem: oldClass.\\n\\t^instance! !\\nAbstractEvent subclass: #ModifiedEvent\\n\\tinstanceVariableNames: 'oldItem'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Change Notification'!\\n\\n!ModifiedEvent methodsFor: 'accessing' stamp: 'NS 1/19/2004 15:08'!\\noldItem\\n\\t^ oldItem! !\\n\\n\\n!ModifiedEvent methodsFor: 'printing' stamp: 'NS 1/19/2004 15:10'!\\nprintEventKindOn: aStream\\n\\n\\taStream nextPutAll: 'Modified'! !\\n\\n!ModifiedEvent methodsFor: 'printing' stamp: 'NS 1/19/2004 17:57'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream\\n\\t\\tnextPutAll: ' oldItem: ';\\n\\t\\tprint: oldItem.! !\\n\\n\\n!ModifiedEvent methodsFor: 'testing' stamp: 'NS 1/19/2004 15:09'!\\nisModified\\n\\n\\t^true! !\\n\\n\\n!ModifiedEvent methodsFor: 'private-accessing' stamp: 'NS 1/19/2004 15:08'!\\noldItem: anItem\\n\\toldItem _ anItem! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nModifiedEvent class\\n\\tinstanceVariableNames: ''!\\n\\n!ModifiedEvent class methodsFor: 'accessing' stamp: 'NS 1/19/2004 15:10'!\\nchangeKind\\n\\n\\t^#Modified! !\\n\\n!ModifiedEvent class methodsFor: 'accessing' stamp: 'NS 1/20/2004 12:25'!\\nsupportedKinds\\n\\t\\\"All the kinds of items that this event can take.\\\"\\n\\t\\n\\t^ Array with: self classKind with: self methodKind with: self categoryKind with: self protocolKind! !\\n\\n\\n!ModifiedEvent class methodsFor: 'instance creation' stamp: 'NS 1/20/2004 19:37'!\\nclassDefinitionChangedFrom: oldClass to: newClass\\n\\t^ ModifiedClassDefinitionEvent classDefinitionChangedFrom: oldClass to: newClass! !\\n\\n!ModifiedEvent class methodsFor: 'instance creation' stamp: 'NS 1/27/2004 11:40'!\\nmethodChangedFrom: oldMethod to: newMethod selector: aSymbol inClass: aClass\\n\\t| instance |\\n\\tinstance := self method: newMethod selector: aSymbol class: aClass.\\n\\tinstance oldItem: oldMethod.\\n\\t^ instance! !\\n\\n!ModifiedEvent class methodsFor: 'instance creation' stamp: 'NS 1/27/2004 11:40'!\\nmethodChangedFrom: oldMethod to: newMethod selector: aSymbol inClass: aClass requestor: requestor\\n\\t| instance |\\n\\tinstance := self method: newMethod selector: aSymbol class: aClass requestor: requestor.\\n\\tinstance oldItem: oldMethod.\\n\\t^ instance! !\\nModifiedEvent subclass: #ModifiedTraitDefinitionEvent\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Change Notification'!\\n\\n!ModifiedTraitDefinitionEvent methodsFor: 'testing' stamp: 'al 7/18/2004 11:08'!\\nanyChanges\\n\\t^ self isTraitCompositionModified! !\\n\\n!ModifiedTraitDefinitionEvent methodsFor: 'testing' stamp: 'al 7/18/2004 10:43'!\\nisTraitCompositionModified\\n\\t^self traitComposition printString ~= self oldTraitComposition printString! !\\n\\n\\n!ModifiedTraitDefinitionEvent methodsFor: 'accessing' stamp: 'al 7/18/2004 10:43'!\\noldTraitComposition\\n\\t^ oldItem traitComposition! !\\n\\n!ModifiedTraitDefinitionEvent methodsFor: 'accessing' stamp: 'al 7/18/2004 10:43'!\\ntraitComposition\\n\\t^ item traitComposition! !\\n\\n\\n!ModifiedTraitDefinitionEvent methodsFor: 'printing' stamp: 'al 7/18/2004 10:47'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream\\n\\t\\tnextPutAll: ' TraitComposition: ';\\n\\t\\tprint: self isTraitCompositionModified! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nModifiedTraitDefinitionEvent class\\n\\tinstanceVariableNames: ''!\\n\\n!ModifiedTraitDefinitionEvent class methodsFor: 'accessing' stamp: 'al 7/18/2004 10:43'!\\nsupportedKinds\\n\\t\\\"All the kinds of items that this event can take.\\\"\\n\\t\\n\\t^ Array with: self classKind! !\\n\\n\\n!ModifiedTraitDefinitionEvent class methodsFor: 'instance creation' stamp: 'al 7/18/2004 10:50'!\\ntraitDefinitionChangedFrom: oldTrait to: newTrait\\n\\t| instance |\\n\\tinstance _ self item: newTrait kind: self classKind.\\n\\tinstance oldItem: oldTrait.\\n\\t^instance! !\\nObject subclass: #Monitor\\n\\tinstanceVariableNames: 'mutex ownerProcess nestingLevel defaultQueue queueDict queuesMutex'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Processes'!\\n!Monitor commentStamp: 'md 3/3/2006 09:19' prior: 0!\\nA monitor provides process synchronization that is more high level than the one provided by a Semaphore. Similar to the classical definition of a Monitor it has the following properties:\\n\\n1) At any time, only one process can execute code inside a critical section of a monitor.\\n2) A monitor is reentrant, which means that the active process in a monitor never gets blocked when it enters a (nested) critical section of the same monitor.\\n3) Inside a critical section, a process can wait for an event that may be coupled to a certain condition. If the condition is not fulfilled, the process leaves the monitor temporarily (in order to let other processes enter) and waits until another process signals the event. Then, the original process checks the condition again (this is often necessary because the state of the monitor could have changed in the meantime) and continues if it is fulfilled.\\n4) The monitor is fair, which means that the process that is waiting on a signaled condition the longest gets activated first.\\n5) The monitor allows you to define timeouts after which a process gets activated automatically.\\n\\n\\nBasic usage:\\n\\nMonitor>>critical: aBlock\\nCritical section.\\nExecutes aBlock as a critical section. At any time, only one process can execute code in a critical section.\\nNOTE: All the following synchronization operations are only valid inside the critical section of the monitor!!\\n\\nMonitor>>wait\\nUnconditional waiting for the default event.\\nThe current process gets blocked and leaves the monitor, which means that the monitor allows another process to execute critical code. When the default event is signaled, the original process is resumed.\\n\\nMonitor>>waitWhile: aBlock\\nConditional waiting for the default event.\\nThe current process gets blocked and leaves the monitor only if the argument block evaluates to true. This means that another process can enter the monitor. When the default event is signaled, the original process is resumed, which means that the condition (argument block) is checked again. Only if it evaluates to false, does execution proceed. Otherwise, the process gets blocked and leaves the monitor again...\\n\\nMonitor>>waitUntil: aBlock\\nConditional waiting for the default event.\\nSee Monitor>>waitWhile: aBlock.\\n\\nMonitor>>signal\\nOne process waiting for the default event is woken up.\\n\\nMonitor>>signalAll\\nAll processes waiting for the default event are woken up.\\n\\n\\nUsing non-default (specific) events:\\n\\nMonitor>>waitFor: aSymbol\\nUnconditional waiting for the non-default event represented by the argument symbol.\\nSame as Monitor>>wait, but the process gets only reactivated by the specific event and not the default event.\\n\\nMonitor>>waitWhile: aBlock for: aSymbol\\nConfitional waiting for the non-default event represented by the argument symbol.\\nSame as Monitor>>waitWhile:for:, but the process gets only reactivated by the specific event and not the default event.\\n\\nMonitor>>waitUntil: aBlock for: aSymbol\\nConfitional waiting for the non-default event represented by the argument symbol.\\nSee Monitor>>waitWhile:for: aBlock.\\n\\nMonitor>>signal: aSymbol\\nOne process waiting for the given event is woken up. If there is no process waiting for this specific event, a process waiting for the default event gets resumed.\\n\\nMonitor>>signalAll: aSymbol\\nAll process waiting for the given event or the default event are woken up.\\n\\nMonitor>>signalReallyAll\\nAll processes waiting for any events (default or specific) are woken up.\\n\\n\\nUsing timeouts\\n\\nMonitor>>waitMaxMilliseconds: anInteger\\nMonitor>>waitFor: aSymbol maxMilliseconds: anInteger\\nSame as Monitor>>wait (resp. Monitor>>waitFor:), but the process gets automatically woken up when the specified time has passed.\\n\\nMonitor>>waitWhile: aBlock maxMilliseconds: anInteger\\nMonitor>>waitWhile: aBlock for: aSymbol maxMilliseconds: anInteger\\nSame as Monitor>>waitWhile: (resp. Monitor>>waitWhile:for:), but the process gets automatically woken up when the specified time has passed.\\n\\nMonitor>>waitUntil: aBlock maxMilliseconds: anInteger\\nMonitor>>waitUntil: aBlock for: aSymbol maxMilliseconds: anInteger\\nSame as Monitor>>waitUntil: (resp. Monitor>>waitUntil:for:), but the process gets automatically woken up when the specified time has passed.!\\n\\n\\n!Monitor methodsFor: 'accessing' stamp: 'NS 7/1/2002 20:02'!\\ncleanup\\n\\tself checkOwnerProcess.\\n\\tself critical: [self privateCleanup].! !\\n\\n\\n!Monitor methodsFor: 'initialize-release' stamp: 'NS 4/13/2004 16:12'!\\ninitialize\\n\\tmutex _ Semaphore forMutualExclusion.\\n\\tqueuesMutex _ Semaphore forMutualExclusion.\\n\\tnestingLevel _ 0.! !\\n\\n\\n!Monitor methodsFor: 'signaling-default' stamp: 'NS 7/1/2002 21:57'!\\nsignal\\n\\t\\\"One process waiting for the default event is woken up.\\\"\\n\\n\\t^ self signal: nil! !\\n\\n!Monitor methodsFor: 'signaling-default' stamp: 'NS 7/1/2002 21:57'!\\nsignalAll\\n\\t\\\"All processes waiting for the default event are woken up.\\\"\\n\\n\\t^ self signalAll: nil! !\\n\\n\\n!Monitor methodsFor: 'signaling-specific' stamp: 'NS 4/13/2004 15:12'!\\nsignal: aSymbolOrNil\\n\\t\\\"One process waiting for the given event is woken up. If there is no process waiting \\n\\tfor this specific event, a process waiting for the default event gets resumed.\\\"\\n\\n\\t| queue |\\n\\tself checkOwnerProcess.\\n\\tqueue _ self queueFor: aSymbolOrNil.\\n\\tqueue isEmpty ifTrue: [queue _ self defaultQueue].\\n\\tself signalQueue: queue.! !\\n\\n!Monitor methodsFor: 'signaling-specific' stamp: 'NS 7/1/2002 22:02'!\\nsignalAll: aSymbolOrNil\\n\\t\\\"All process waiting for the given event or the default event are woken up.\\\"\\n\\n\\t| queue |\\n\\tself checkOwnerProcess.\\n\\tqueue _ self queueFor: aSymbolOrNil.\\n\\tself signalAllInQueue: self defaultQueue.\\n\\tqueue ~~ self defaultQueue ifTrue: [self signalAllInQueue: queue].! !\\n\\n!Monitor methodsFor: 'signaling-specific' stamp: 'NS 7/1/2002 22:02'!\\nsignalReallyAll\\n\\t\\\"All processes waiting for any events (default or specific) are woken up.\\\"\\n\\n\\tself checkOwnerProcess.\\n\\tself signalAll.\\n\\tself queueDict valuesDo: [:queue |\\n\\t\\tself signalAllInQueue: queue].! !\\n\\n\\n!Monitor methodsFor: 'synchronization' stamp: 'NS 4/14/2004 13:13'!\\ncritical: aBlock\\n\\t\\\"Critical section.\\n\\tExecutes aBlock as a critical section. At any time, only one process can be executing code \\n\\tin a critical section.\\n\\tNOTE: All the following synchronization operations are only valid inside the critical section \\n\\tof the monitor!!\\\"\\n\\n\\t| result |\\n\\t[self enter.\\n\\tresult _ aBlock value] ensure: [self exit].\\n\\t^ result.! !\\n\\n\\n!Monitor methodsFor: 'waiting-basic' stamp: 'NS 7/1/2002 21:55'!\\nwait\\n\\t\\\"Unconditional waiting for the default event.\\n\\tThe current process gets blocked and leaves the monitor, which means that the monitor\\n\\tallows another process to execute critical code. When the default event is signaled, the\\n\\toriginal process is resumed.\\\"\\n\\n\\t^ self waitMaxMilliseconds: nil! !\\n\\n!Monitor methodsFor: 'waiting-basic' stamp: 'NS 7/1/2002 21:56'!\\nwaitUntil: aBlock\\n\\t\\\"Conditional waiting for the default event.\\n\\tSee Monitor>>waitWhile: aBlock.\\\"\\n\\n\\t^ self waitUntil: aBlock for: nil! !\\n\\n!Monitor methodsFor: 'waiting-basic' stamp: 'fbs 3/24/2004 14:39'!\\nwaitWhile: aBlock\\n\\t\\\"Conditional waiting for the default event.\\n\\tThe current process gets blocked and leaves the monitor only if the argument block\\n\\tevaluates to true. This means that another process can enter the monitor. When the \\n\\tdefault event is signaled, the original process is resumed, which means that the condition\\n\\t(argument block) is checked again. Only if it evaluates to false, does execution proceed.\\n\\tOtherwise, the process gets blocked and leaves the monitor again...\\\"\\n\\n\\t^ self waitWhile: aBlock for: nil! !\\n\\n\\n!Monitor methodsFor: 'waiting-specific' stamp: 'NS 7/1/2002 21:58'!\\nwaitFor: aSymbolOrNil\\n\\t\\\"Unconditional waiting for the non-default event represented by the argument symbol.\\n\\tSame as Monitor>>wait, but the process gets only reactivated by the specific event and \\n\\tnot the default event.\\\"\\n\\n\\t^ self waitFor: aSymbolOrNil maxMilliseconds: nil! !\\n\\n!Monitor methodsFor: 'waiting-specific' stamp: 'NS 7/1/2002 22:01'!\\nwaitUntil: aBlock for: aSymbolOrNil\\n\\t\\\"Confitional waiting for the non-default event represented by the argument symbol.\\n\\tSee Monitor>>waitWhile:for: aBlock.\\\"\\n\\n\\t^ self waitUntil: aBlock for: aSymbolOrNil maxMilliseconds: nil! !\\n\\n!Monitor methodsFor: 'waiting-specific' stamp: 'NS 7/1/2002 22:01'!\\nwaitWhile: aBlock for: aSymbolOrNil\\n\\t\\\"Confitional waiting for the non-default event represented by the argument symbol.\\n\\tSame as Monitor>>waitWhile:for:, but the process gets only reactivated by the specific \\n\\tevent and not the default event.\\\"\\n\\n\\t^ self waitWhile: aBlock for: aSymbolOrNil maxMilliseconds: nil! !\\n\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:03'!\\nwaitFor: aSymbolOrNil maxMilliseconds: anIntegerOrNil\\n\\t\\\"Same as Monitor>>waitFor:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\tself checkOwnerProcess.\\n\\tself waitInQueue: (self queueFor: aSymbolOrNil) maxMilliseconds: anIntegerOrNil.! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:04'!\\nwaitFor: aSymbolOrNil maxSeconds: aNumber\\n\\t\\\"Same as Monitor>>waitFor:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitFor: aSymbolOrNil maxMilliseconds: (aNumber * 1000) asInteger! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:04'!\\nwaitMaxMilliseconds: anIntegerOrNil\\n\\t\\\"Same as Monitor>>wait, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitFor: nil maxMilliseconds: anIntegerOrNil! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:05'!\\nwaitMaxSeconds: aNumber\\n\\t\\\"Same as Monitor>>wait, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitMaxMilliseconds: (aNumber * 1000) asInteger! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:05'!\\nwaitUntil: aBlock for: aSymbolOrNil maxMilliseconds: anIntegerOrNil\\n\\t\\\"Same as Monitor>>waitUntil:for:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitWhile: [aBlock value not] for: aSymbolOrNil maxMilliseconds: anIntegerOrNil! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:05'!\\nwaitUntil: aBlock for: aSymbolOrNil maxSeconds: aNumber\\n\\t\\\"Same as Monitor>>waitUntil:for:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitUntil: aBlock for: aSymbolOrNil maxMilliseconds: (aNumber * 1000) asInteger! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:05'!\\nwaitUntil: aBlock maxMilliseconds: anIntegerOrNil\\n\\t\\\"Same as Monitor>>waitUntil:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitUntil: aBlock for: nil maxMilliseconds: anIntegerOrNil! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:06'!\\nwaitUntil: aBlock maxSeconds: aNumber\\n\\t\\\"Same as Monitor>>waitUntil:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitUntil: aBlock maxMilliseconds: (aNumber * 1000) asInteger! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:06'!\\nwaitWhile: aBlock for: aSymbolOrNil maxMilliseconds: anIntegerOrNil\\n\\t\\\"Same as Monitor>>waitWhile:for:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\tself checkOwnerProcess.\\n\\tself waitWhile: aBlock inQueue: (self queueFor: aSymbolOrNil) maxMilliseconds: anIntegerOrNil.! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:06'!\\nwaitWhile: aBlock for: aSymbolOrNil maxSeconds: aNumber\\n\\t\\\"Same as Monitor>>waitWhile:for:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitWhile: aBlock for: aSymbolOrNil maxMilliseconds: (aNumber * 1000) asInteger! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:06'!\\nwaitWhile: aBlock maxMilliseconds: anIntegerOrNil\\n\\t\\\"Same as Monitor>>waitWhile:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitWhile: aBlock for: nil maxMilliseconds: anIntegerOrNil! !\\n\\n!Monitor methodsFor: 'waiting-timeout' stamp: 'NS 7/1/2002 22:06'!\\nwaitWhile: aBlock maxSeconds: aNumber\\n\\t\\\"Same as Monitor>>waitWhile:, but the process gets automatically woken up when the \\n\\tspecified time has passed.\\\"\\n\\n\\t^ self waitWhile: aBlock maxMilliseconds: (aNumber * 1000) asInteger! !\\n\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 4/13/2004 13:40'!\\ncheckOwnerProcess\\n\\tself isOwnerProcess\\n\\t\\tifFalse: [self error: 'Monitor access violation'].! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 7/1/2002 15:06'!\\ndefaultQueue\\n\\tdefaultQueue ifNil: [defaultQueue _ OrderedCollection new].\\n\\t^ defaultQueue! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 4/13/2004 13:37'!\\nenter\\n\\tself isOwnerProcess ifTrue: [\\n\\t\\tnestingLevel _ nestingLevel + 1.\\n\\t] ifFalse: [\\n\\t\\tmutex wait.\\n\\t\\townerProcess _ Processor activeProcess.\\n\\t\\tnestingLevel _ 1.\\n\\t].! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 4/13/2004 13:38'!\\nexit\\n\\tnestingLevel _ nestingLevel - 1.\\n\\tnestingLevel < 1 ifTrue: [\\n\\t\\townerProcess _ nil.\\n\\t\\tmutex signal\\n\\t].! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 4/13/2004 16:32'!\\nexitAndWaitInQueue: anOrderedCollection maxMilliseconds: anIntegerOrNil\\n\\t| lock delay |\\n\\tqueuesMutex \\n\\t\\tcritical: [lock _ anOrderedCollection addLast: Semaphore new].\\n\\tself exit.\\n\\tanIntegerOrNil isNil ifTrue: [\\n\\t\\tlock wait\\n\\t] ifFalse: [\\n\\t\\tdelay _ MonitorDelay signalLock: lock afterMSecs: anIntegerOrNil inMonitor: self queue: anOrderedCollection.\\n\\t\\tlock wait.\\n\\t\\tdelay unschedule.\\n\\t].\\n\\tself enter.! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 7/1/2002 15:42'!\\nisOwnerProcess\\n\\t^ Processor activeProcess == ownerProcess! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 4/13/2004 16:14'!\\nprivateCleanup\\n\\tqueuesMutex critical: [\\n\\t\\tdefaultQueue isEmpty ifTrue: [defaultQueue _ nil].\\n\\t\\tqueueDict ifNotNil: [\\n\\t\\t\\tqueueDict copy keysAndValuesDo: [:id :queue | \\n\\t\\t\\t\\tqueue isEmpty ifTrue: [queueDict removeKey: id]].\\n\\t\\t\\tqueueDict isEmpty ifTrue: [queueDict _ nil].\\n\\t\\t].\\n\\t].! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 7/1/2002 15:10'!\\nqueueDict\\n\\tqueueDict ifNil: [queueDict _ IdentityDictionary new].\\n\\t^ queueDict.! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 7/1/2002 15:12'!\\nqueueFor: aSymbol\\n\\taSymbol ifNil: [^ self defaultQueue].\\n\\t^ self queueDict \\n\\t\\tat: aSymbol \\n\\t\\tifAbsent: [self queueDict at: aSymbol put: OrderedCollection new].! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 4/13/2004 16:10'!\\nsignalAllInQueue: anOrderedCollection\\n\\tqueuesMutex critical: [\\n\\t\\tanOrderedCollection do: [:lock | lock signal].\\n\\t\\tanOrderedCollection removeAllSuchThat: [:each | true].\\n\\t].! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 4/13/2004 16:34'!\\nsignalLock: aSemaphore inQueue: anOrderedCollection\\n\\tqueuesMutex critical: [\\n\\t\\taSemaphore signal.\\n\\t\\tanOrderedCollection remove: aSemaphore ifAbsent: [].\\n\\t].! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 4/13/2004 16:10'!\\nsignalQueue: anOrderedCollection\\n\\tqueuesMutex critical: [\\n\\t\\tanOrderedCollection isEmpty ifTrue: [^ self].\\n\\t\\tanOrderedCollection removeFirst signal.\\n\\t].! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 7/1/2002 13:17'!\\nwaitInQueue: anOrderedCollection maxMilliseconds: anIntegerOrNil\\n\\tself exitAndWaitInQueue: anOrderedCollection maxMilliseconds: anIntegerOrNil.! !\\n\\n!Monitor methodsFor: 'private' stamp: 'NS 7/1/2002 13:17'!\\nwaitWhile: aBlock inQueue: anOrderedCollection maxMilliseconds: anIntegerOrNil\\n\\t[aBlock value] whileTrue: [self exitAndWaitInQueue: anOrderedCollection maxMilliseconds: anIntegerOrNil].! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMonitor class\\n\\tinstanceVariableNames: ''!\\nDelay subclass: #MonitorDelay\\n\\tinstanceVariableNames: 'monitor queue'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Processes'!\\n!MonitorDelay commentStamp: 'NS 4/13/2004 16:51' prior: 0!\\nThis is a specialization of the class Delay that is used for the implementation of the class Monitor.!\\n\\n\\n!MonitorDelay methodsFor: 'private' stamp: 'NS 4/13/2004 16:26'!\\nsetDelay: anInteger forSemaphore: aSemaphore monitor: aMonitor queue: anOrderedCollection\\n\\tmonitor _ aMonitor.\\n\\tqueue _ anOrderedCollection.\\n\\tself setDelay: anInteger forSemaphore: aSemaphore.! !\\n\\n!MonitorDelay methodsFor: 'private' stamp: 'NS 4/13/2004 16:22'!\\nsignalWaitingProcess\\n\\t\\\"The delay time has elapsed; signal the waiting process.\\\"\\n\\n\\tbeingWaitedOn _ false.\\n\\tmonitor signalLock: delaySemaphore inQueue: queue.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMonitorDelay class\\n\\tinstanceVariableNames: ''!\\n\\n!MonitorDelay class methodsFor: 'instance creation' stamp: 'NS 4/13/2004 16:25'!\\nsignalLock: aSemaphore afterMSecs: anInteger inMonitor: aMonitor queue: anOrderedCollection\\n\\tanInteger < 0 ifTrue: [self error: 'delay times cannot be negative'].\\n\\t^ (self new setDelay: anInteger forSemaphore: aSemaphore monitor: aMonitor queue: anOrderedCollection) schedule! !\\nTestCase subclass: #MonitorTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'KernelTests-Processes'!\\n\\n!MonitorTest methodsFor: 'examples' stamp: 'md 3/19/2006 21:15'!\\ntestExample1\\n\\n\\t| producer1 producer2 monitor goal work counter goalReached finished |\\n\\tgoal _ (1 to: 1000) asOrderedCollection.\\n\\twork _ OrderedCollection new.\\n\\tcounter := 0.\\n\\tgoalReached := false.\\n\\tfinished := Semaphore new.\\n\\tmonitor := Monitor new.\\n\\n\\tproducer1 := [\\n [monitor critical:\\n [monitor waitUntil: [counter \\\\\\\\5 = 0].\\n goalReached or: [work add: (counter := counter + 1)].\\n goalReached := counter >= goal size.\\n monitor signal\\n ].\\n goalReached\\n ]\\n whileFalse.\\n finished signal.\\n\\t].\\n\\n\\tproducer2 := [\\n [monitor critical:\\n [monitor waitWhile: [counter \\\\\\\\5 = 0].\\n goalReached or: [work add: (counter := counter + 1)].\\n goalReached := counter >= goal size.\\n monitor signal].\\n goalReached\\n ] whileFalse.\\n finished signal\\n\\t].\\n\\n\\tproducer1 forkAt: Processor userBackgroundPriority.\\n\\tproducer2 forkAt: Processor userBackgroundPriority.\\n\\n\\tfinished wait; wait.\\n\\tself assert: goal = work! !\\n\\n!MonitorTest methodsFor: 'examples' stamp: 'md 3/19/2006 21:19'!\\ntestExample2\\n\\t\\\"Here is a second version that does not use a semaphore to inform the \\n\\tforking process about termination of both forked processes\\\"\\n\\n\\t| producer1 producer2 monitor goal work counter goalReached activeProducers|\\n\\tgoal _ (1 to: 1000) asOrderedCollection.\\n\\twork _ OrderedCollection new.\\n\\tcounter := 0.\\n\\tgoalReached := false.\\n\\tactiveProducers := 0.\\n\\tmonitor := Monitor new.\\n\\n producer1 :=\\n [ monitor critical: [activeProducers := activeProducers + 1].\\n [monitor critical:\\n [monitor waitUntil: [counter \\\\\\\\5 = 0].\\n goalReached or: [work add: (counter := counter + 1)].\\n \\\" Transcript show: 'P1 '; show: counter printString; show: ' ';\\n show: activeProducers printString; cr.\\\"\\n goalReached := counter >= goal size.\\n monitor signal\\n ].\\n goalReached\\n ]\\n whileFalse.\\n monitor critical: [activeProducers := activeProducers - 1.\\n monitor signal: #finish].\\n ] .\\n\\n producer2 :=\\n [monitor critical: [activeProducers := activeProducers + 1].\\n\\n [monitor critical:\\n [monitor waitWhile: [counter \\\\\\\\5 = 0].\\n goalReached or: [work add: (counter := counter + 1)].\\n goalReached := counter >= goal size.\\n monitor signal].\\n goalReached ] whileFalse.\\n monitor critical: [\\n\\t\\tactiveProducers := activeProducers - 1. \\n\\t\\tmonitor signal: #finish].\\n\\t].\\n\\n\\tproducer1 forkAt: Processor userBackgroundPriority.\\n\\tproducer2 forkAt: Processor userBackgroundPriority.\\n\\n\\n\\tmonitor critical: [\\n\\t\\tmonitor waitUntil: [activeProducers = 0 & (goalReached)]\\n\\t\\t\\t\\tfor: #finish.\\n \\t].\\n\\n\\tself assert: goal = work\\n! !\\nTimespan subclass: #Month\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: 'ChronologyConstants'\\n\\tcategory: 'Kernel-Chronology'!\\n!Month commentStamp: 'brp 5/13/2003 09:48' prior: 0!\\nI represent a month.!\\n\\n\\n!Month methodsFor: 'squeak protocol' stamp: 'brp 5/13/2003 09:04'!\\nasMonth\\n\\n\\t^ self\\n! !\\n\\n!Month methodsFor: 'squeak protocol' stamp: 'brp 5/13/2003 09:05'!\\ndaysInMonth\\n\\n\\t^ self duration days.! !\\n\\n!Month methodsFor: 'squeak protocol' stamp: 'brp 5/13/2003 09:05'!\\nindex\\n\\n\\t^ self monthIndex\\n! !\\n\\n!Month methodsFor: 'squeak protocol' stamp: 'brp 5/13/2003 09:05'!\\nname\\n\\n\\n\\t^ self monthName\\n! !\\n\\n!Month methodsFor: 'squeak protocol' stamp: 'brp 5/13/2003 09:05'!\\nprevious\\n\\n\\n\\t^ self class starting: (self start - 1)\\n! !\\n\\n!Month methodsFor: 'squeak protocol' stamp: 'brp 5/13/2003 09:05'!\\nprintOn: aStream\\n\\n\\n\\taStream nextPutAll: self monthName, ' ', self year printString.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMonth class\\n\\tinstanceVariableNames: ''!\\n\\n!Month class methodsFor: 'smalltalk-80' stamp: 'brp 7/27/2003 16:27'!\\ndaysInMonth: indexOrName forYear: yearInteger \\n\\n\\t| index |\\n\\tindex _ indexOrName isInteger \\n\\t\\t\\t\\tifTrue: [indexOrName]\\n\\t\\t\\t\\tifFalse: [self indexOfMonth: indexOrName].\\n\\t^ (DaysInMonth at: index)\\n\\t\\t\\t+ ((index = 2\\n\\t\\t\\t\\t\\tand: [Year isLeapYear: yearInteger])\\n\\t\\t\\t\\t\\t\\tifTrue: [1] ifFalse: [0])! !\\n\\n!Month class methodsFor: 'smalltalk-80' stamp: 'brp 8/23/2003 09:29'!\\nindexOfMonth: aMonthName\\n\\n\\n\\t1 to: 12 do: [ :i | (aMonthName, '*' match: (MonthNames at: i)) ifTrue: [^i] ].\\n\\n\\tself error: aMonthName , ' is not a recognized month name'.! !\\n\\n!Month class methodsFor: 'smalltalk-80' stamp: 'brp 5/13/2003 09:02'!\\nnameOfMonth: anIndex\\n\\n\\t^ MonthNames at: anIndex.! !\\n\\n\\n!Month class methodsFor: 'squeak protocol' stamp: 'brp 7/27/2003 16:22'!\\nmonth: month year: year\\n\\t\\\"Create a Month for the given <year> and <month>.\\n\\t<month> may be a number or a String with the\\n\\tname of the month. <year> should be with 4 digits.\\\"\\n\\n\\t^ self starting: (DateAndTime year: year month: month day: 1)\\n! !\\n\\n!Month class methodsFor: 'squeak protocol' stamp: 'brp 7/27/2003 16:21'!\\nreadFrom: aStream\\n\\n\\t| m y c |\\n\\n\\tm _ (ReadWriteStream with: '') reset.\\n\\n\\t[(c _ aStream next) isSeparator] whileFalse: [m nextPut: c].\\n\\n\\t[(c _ aStream next) isSeparator] whileTrue.\\n\\n\\ty _ (ReadWriteStream with: '') reset.\\n\\n\\ty nextPut: c.\\n\\n\\t[aStream atEnd] whileFalse: [y nextPut: aStream next].\\n\\n\\n\\t^ self \\n\\t\\tmonth: m contents\\n\\t\\tyear: y contents\\n\\n\\\"Month readFrom: 'July 1998' readStream\\\"\\n! !\\n\\n!Month class methodsFor: 'squeak protocol' stamp: 'brp 7/1/2003 13:59'!\\nstarting: aDateAndTime duration: aDuration \\n\\t\\\"Override - a each month has a defined duration\\\"\\n\\t| start adjusted days |\\n\\tstart _ aDateAndTime asDateAndTime.\\n\\tadjusted _ DateAndTime\\n\\t\\t\\t\\tyear: start year\\n\\t\\t\\t\\tmonth: start month\\n\\t\\t\\t\\tday: 1.\\n\\tdays _ self daysInMonth: adjusted month forYear: adjusted year.\\n\\t^ super\\n\\t\\tstarting: adjusted\\n\\t\\tduration: (Duration days: days)! !\\nClassTestCase subclass: #MonthTest\\n\\tinstanceVariableNames: 'month'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'KernelTests-Chronology'!\\n!MonthTest commentStamp: 'brp 7/26/2003 22:44' prior: 0!\\nThis is the unit test for the class Month.\\n!\\n\\n\\n!MonthTest methodsFor: 'Coverage' stamp: 'brp 7/27/2003 12:42'!\\nclassToBeTested\\n\\n\\t^ Month! !\\n\\n!MonthTest methodsFor: 'Coverage' stamp: 'brp 7/26/2003 23:29'!\\nselectorsToBeIgnored\\n\\n\\t| deprecated private special |\\n\\tdeprecated := #().\\n\\tprivate := #( #printOn: ).\\n\\tspecial := #( #next ).\\n\\n\\t^ super selectorsToBeIgnored, deprecated, private, special.! !\\n\\n\\n!MonthTest methodsFor: 'Running' stamp: 'brp 8/6/2003 19:37'!\\nsetUp\\n\\n\\tsuper setUp.\\n\\tmonth _ Month month: 7 year: 1998.! !\\n\\n!MonthTest methodsFor: 'Running' stamp: 'brp 8/6/2003 19:37'!\\ntearDown\\n\\n\\tsuper tearDown.\\n\\tmonth _ nil.! !\\n\\n\\n!MonthTest methodsFor: 'Tests' stamp: 'brp 7/26/2003 22:52'!\\ntestConverting\\n\\n\\tself assert: month asDate = '1 July 1998' asDate! !\\n\\n!MonthTest methodsFor: 'Tests' stamp: 'brp 1/30/2005 09:35'!\\ntestEnumerating\\n\\t| weeks |\\n\\tweeks := OrderedCollection new.\\n\\tmonth weeksDo: [ :w | weeks add: w start ].\\n\\t0 to: 4 do: [ :i | weeks remove: (Week starting: ('29 June 1998' asDate addDays: i * 7)) start ].\\n\\tself assert: weeks isEmpty! !\\n\\n!MonthTest methodsFor: 'Tests' stamp: 'brp 8/23/2003 16:08'!\\ntestInquiries\\n\\n\\tself \\n\\t\\tassert: month index = 7;\\n\\t\\tassert: month name = #July;\\n\\t\\tassert: month duration = (31 days).\\n! !\\n\\n!MonthTest methodsFor: 'Tests' stamp: 'nk 7/30/2004 17:52'!\\ntestInstanceCreation\\n\\t| m1 m2 |\\n\\tm1 := Month starting: '4 July 1998' asDate.\\n\\tm2 := Month month: #July year: 1998.\\n\\tself\\n\\t\\tassert: month = m1;\\n\\t\\tassert: month = m2! !\\n\\n!MonthTest methodsFor: 'Tests' stamp: 'brp 7/26/2003 23:02'!\\ntestPreviousNext\\n\\t| n p |\\n\\tn := month next.\\n\\tp := month previous.\\n\\n\\tself\\n\\t\\tassert: n year = 1998;\\n\\t\\tassert: n index = 8;\\n\\t\\tassert: p year = 1998;\\n\\t\\tassert: p index = 6.\\n\\n! !\\n\\n!MonthTest methodsFor: 'Tests' stamp: 'brp 7/26/2003 22:50'!\\ntestPrinting\\n\\n\\tself \\n\\t\\tassert: month printString = 'July 1998'.\\n! !\\n\\n!MonthTest methodsFor: 'Tests' stamp: 'brp 7/26/2003 22:46'!\\ntestReadFrom\\n\\n\\t| m |\\n\\tm := Month readFrom: 'July 1998' readStream.\\n\\tself \\n\\t\\tassert: m = month! !\\nGesturalEvent subclass: #MoodGesturalEvent\\n\\tinstanceVariableNames: 'state'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Speech-Events'!\\n\\n!MoodGesturalEvent methodsFor: 'accessing' stamp: 'len 9/7/1999 02:22'!\\nstate\\n\\t^ state! !\\n\\n!MoodGesturalEvent methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:22'!\\nstate: aSymbol\\n\\tstate := aSymbol asSymbol! !\\n\\n\\n!MoodGesturalEvent methodsFor: 'playing' stamp: 'len 9/7/1999 02:23'!\\nactOn: aHeadMorph\\n\\taHeadMorph face perform: self state! !\\n\\n\\n!MoodGesturalEvent methodsFor: 'printing' stamp: 'len 9/7/1999 02:26'!\\nprintOn: aStream\\n\\taStream nextPutAll: 'set ', self state, ' mood'! !\\nObject subclass: #Morph\\n\\tinstanceVariableNames: 'bounds owner submorphs fullBounds color extension'\\n\\tclassVariableNames: 'EmptyArray'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Kernel'!\\n!Morph commentStamp: 'efc 2/26/2003 20:01' prior: 0!\\nA Morph (from the Greek \\\"shape\\\" or \\\"form\\\") is an interactive graphical object. General information on the Morphic system can be found at http://minnow.cc.gatech.edu/squeak/30. \\n\\nMorphs exist in a tree, rooted at a World (generally a PasteUpMorph). The morphs owned by a morph are its submorphs. Morphs are drawn recursively; if a Morph has no owner it never gets drawn. To hide a Morph and its submorphs, set its #visible property to false using the #visible: method. \\n\\nThe World (screen) coordinate system is used for most coordinates, but can be changed if there is a TransformMorph somewhere in the owner chain. \\n\\nMy instance variables have accessor methods (e.g., #bounds, #bounds:). Most users should use the accessor methods instead of using the instance variables directly.\\n\\nStructure:\\ninstance var \\tType \\t\\t\\tDescription \\nbounds \\t\\t\\tRectangle \\t\\tA Rectangle indicating my position and a size that will enclose \\t\\t\\t\\t\\t\\t\\t\\t\\tme. \\nowner \\t\\t\\tMorph\\t\\t \\tMy parent Morph, or nil for the top-level Morph, which is a\\n \\t\\t\\t\\tor nil\\t\\t\\tworld, typically a PasteUpMorph.\\nsubmorphs \\t\\tArray \\t\\t\\tMy child Morphs. \\nfullBounds \\t\\tRectangle \\t\\tA Rectangle minimally enclosing me and my submorphs. \\ncolor \\t\\t\\tColor \\t\\t\\tMy primary color. Subclasses can use this in different ways. \\nextension \\t\\tMorphExtension Allows extra properties to be stored without adding a\\n\\t\\t\\t\\tor nil \\t\\t\\t\\tstorage burden to all morphs. \\n\\nBy default, Morphs do not position their submorphs. Morphs may position their submorphs directly or use a LayoutPolicy to automatically control their submorph positioning.\\n\\nAlthough Morph has some support for BorderStyle, most users should use BorderedMorph if they want borders.!\\n]style[(2 5 130 37 59 12 325 14 209 12 2 4 4 11 1 11 9 90 5 123 5 35 9 66 5 78 14 209 12 91 11 24 13 22)f1,f1LMorph Hierarchy;,f1,f1Rhttp://minnow.cc.gatech.edu/squeak/30;,f1,f1LPasteUpMorph Comment;,f1,f1LTransformMorph Comment;,f1,f1u,f1,f1u,f1,f1u,f1i,f1,f1LRectangle Comment;,f1,f1LMorph Comment;,f1,f1LArray Comment;,f1,f1LRectangle Comment;,f1,f1LColor Comment;,f1,f1LMorphExtension Comment;,f1,f1LLayoutPolicy Comment;,f1,f1LBorderStyle Comment;,f1,f1LBorderedMorph Comment;,f1!\\n\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 8/11/1998 16:46'!\\nactorState\\n\\t\\\"This method instantiates actorState as a side-effect.\\n\\tFor simple queries, use actorStateOrNil\\\"\\n\\t| state |\\n\\tstate _ self actorStateOrNil.\\n\\tstate ifNil:\\n\\t\\t[state _ ActorState new initializeFor: self assuredPlayer.\\n\\t\\tself actorState: state].\\n\\t^ state! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 09:51'!\\nactorStateOrNil\\n\\t\\\"answer the redeiver's actorState\\\"\\n\\t^ extension ifNotNil: [extension actorState]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:52'!\\nactorState: anActorState \\n\\t\\\"change the receiver's actorState\\\"\\n\\tself assureExtension actorState: anActorState! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 12/18/2001 20:09'!\\nadoptPaneColor: paneColor\\n\\tself submorphsDo:[:m| m adoptPaneColor: paneColor].! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 09:51'!\\nballoonText\\n\\t\\\"Answer balloon help text or nil, if no help is available. \\n\\tNB: subclasses may override such that they programatically \\n\\tconstruct the text, for economy's sake, such as model phrases in \\n\\ta Viewer\\\"\\n\\n\\t| text balloonSelector aString |\\n\\textension ifNil: [^nil].\\n\\t(text := extension balloonText) ifNotNil: [^text].\\n\\t(balloonSelector := extension balloonTextSelector) ifNotNil: \\n\\t\\t\\t[aString := ScriptingSystem helpStringOrNilFor: balloonSelector.\\n\\t\\t\\t(aString isNil and: [balloonSelector == #methodComment]) \\n\\t\\t\\t\\tifTrue: [aString := self methodCommentAsBalloonHelp].\\n\\t\\t\\t((aString isNil and: [balloonSelector numArgs = 0]) \\n\\t\\t\\t\\tand: [self respondsTo: balloonSelector]) \\n\\t\\t\\t\\t\\tifTrue: [aString := self perform: balloonSelector]].\\n\\t^aString ifNotNil: \\n\\t\\t\\t[aString asString \\n\\t\\t\\t\\twithNoLineLongerThan: Preferences maxBalloonHelpLineLength]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 09:52'!\\nballoonTextSelector\\n\\t\\\"Answer balloon text selector item in the extension, nil if none\\\"\\n\\t^ extension ifNotNil: [extension balloonTextSelector]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:50'!\\nballoonTextSelector: aSelector \\n\\t\\\"change the receiver's balloonTextSelector\\\"\\n\\tself assureExtension balloonTextSelector: aSelector! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 10/31/2001 21:06'!\\nbeFlap: aBool\\n\\t\\\"Mark the receiver with the #flap property, or unmark it\\\"\\n\\n\\taBool\\n\\t\\tifTrue:\\n\\t\\t\\t[self setProperty: #flap toValue: true.\\n\\t\\t\\tself hResizing: #rigid.\\n\\t\\t\\tself vResizing: #rigid]\\n\\t\\tifFalse:\\n\\t\\t\\t[self removeProperty: #flap]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:57'!\\nbeSticky\\n\\t\\\"make the receiver sticky\\\"\\n\\tself assureExtension sticky: true! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 09:52'!\\nbeUnsticky\\n\\t\\\"If the receiver is marked as sticky, make it now be unsticky\\\"\\n\\textension ifNotNil: [extension sticky: false]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 8/25/2001 18:28'!\\nborderColor\\n\\t^self borderStyle color! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'nk 4/15/2004 10:55'!\\nborderColor: aColorOrSymbolOrNil \\n\\t\\\"Unfortunately, the argument to borderColor could be more than \\tjust a color. \\n\\tIt could also be a symbol, in which case it is to be interpreted as a style identifier.\\n\\tBut I might not be able to draw that kind of border, so it may have to be ignored.\\n\\tOr it could be nil, in which case I should revert to the default border.\\\"\\n\\n\\t| style newStyle |\\n\\tstyle := self borderStyle.\\n\\tstyle baseColor = aColorOrSymbolOrNil\\n\\t\\tifTrue: [^ self].\\n\\n\\taColorOrSymbolOrNil isColor\\n\\t\\tifTrue: [style style = #none \\\"default border?\\\"\\n\\t\\t\\t\\tifTrue: [self borderStyle: (SimpleBorder width: 0 color: aColorOrSymbolOrNil)]\\n\\t\\t\\t\\tifFalse: [style baseColor: aColorOrSymbolOrNil.\\n\\t\\t\\t\\t\\tself changed].\\n\\t\\t\\t^ self].\\n\\n\\tself\\n\\t\\tborderStyle: ( ({ nil. #none } includes: aColorOrSymbolOrNil)\\n\\t\\t\\t\\tifTrue: [BorderStyle default]\\n\\t\\t\\t\\tifFalse: [ \\\"a symbol\\\"\\n\\t\\t\\t\\t\\tself doesBevels ifFalse: [ ^self ].\\n\\t\\t\\t\\t\\tnewStyle := (BorderStyle perform: aColorOrSymbolOrNil)\\n\\t\\t\\t\\t\\t\\t\\t\\tcolor: style color;\\n\\t\\t\\t\\t\\t\\t\\t\\twidth: style width;\\n\\t\\t\\t\\t\\t\\t\\t\\tyourself.\\n\\t\\t\\t\\t\\t(self canDrawBorder: newStyle)\\n\\t\\t\\t\\t\\t\\tifTrue: [newStyle]\\n\\t\\t\\t\\t\\t\\tifFalse: [style]])! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 11/26/2001 14:53'!\\nborderStyle\\n\\t^(self valueOfProperty: #borderStyle ifAbsent:[BorderStyle default]) trackColorFrom: self! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 11/26/2001 16:18'!\\nborderStyleForSymbol: aStyleSymbol\\n\\t\\\"Answer a suitable BorderStyle for me of the type represented by a given symbol\\\"\\n\\n\\t| aStyle existing |\\n\\taStyle _ BorderStyle borderStyleForSymbol: aStyleSymbol asSymbol.\\n\\taStyle ifNil: [self error: 'bad style'].\\n\\texisting _ self borderStyle.\\n\\taStyle width: existing width;\\n\\t\\tbaseColor: existing baseColor.\\n\\t^ (self canDrawBorder: aStyle)\\n\\t\\tifTrue:\\n\\t\\t\\t[aStyle]\\n\\t\\tifFalse:\\n\\t\\t\\t[nil]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 12/11/2001 22:14'!\\nborderStyle: newStyle\\n\\tnewStyle = self borderStyle ifFalse:[\\n\\t\\t(self canDrawBorder: newStyle) ifFalse:[\\n\\t\\t\\t\\\"Replace the suggested border with a simple one\\\"\\n\\t\\t\\t^self borderStyle: (BorderStyle width: newStyle width color: (newStyle trackColorFrom: self) color)].\\n\\t\\tself setProperty: #borderStyle toValue: newStyle.\\n\\t\\tself changed].! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 8/25/2001 18:28'!\\nborderWidth\\n\\t^self borderStyle width! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'di 2/6/2001 14:02'!\\nborderWidthForRounding\\n\\n\\t^ self borderWidth! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'nk 4/14/2004 17:48'!\\nborderWidth: aNumber\\n\\t| style |\\n\\tstyle _ self borderStyle.\\n\\tstyle width = aNumber ifTrue: [ ^self ].\\n\\n\\tstyle style = #none\\n\\t\\tifTrue: [ self borderStyle: (SimpleBorder width: aNumber color: Color transparent) ]\\n\\t\\tifFalse: [ style width: aNumber. self changed ].\\n! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 9/1/2004 16:10'!\\nclearArea\\n\\t\\\"Answer the clear area of the receiver. It means the area free \\n\\tof docking bars.\\\"\\n\\t| visTop visBottom visLeft visRight |\\n\\n\\tvisTop := self top.\\n\\tvisBottom := self bottom.\\n\\tvisLeft := self left.\\n\\tvisRight := self right.\\n\\n\\tself dockingBars\\n\\t\\tdo: [:each | \\n\\t\\t\\t(each isAdheringToTop and: [each bottom > visTop])\\n\\t\\t\\t\\tifTrue: [visTop := each bottom].\\n\\n\\t\\t\\t(each isAdheringToBottom and: [each top < visBottom])\\n\\t\\t\\t\\tifTrue: [visBottom := each top].\\n\\n\\t\\t\\t(each isAdheringToLeft and: [each right > visLeft])\\n\\t\\t\\t\\tifTrue: [visLeft := each right].\\n\\n\\t\\t\\t(each isAdheringToRight and: [each left < visRight])\\n\\t\\t\\t\\tifTrue: [visRight := each left]\\n\\t\\t].\\n\\n\\t^ Rectangle\\n\\t\\tleft: visLeft\\n\\t\\tright: visRight\\n\\t\\ttop: visTop\\n\\t\\tbottom: visBottom\\n! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'tk 2/15/2001 15:55'!\\ncolor\\n\\n\\t^ color \\t\\\"has already been set to ((self valueOfProperty: #fillStyle) asColor)\\\"! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 8/15/2001 22:40'!\\ncolorForInsets\\n\\t\\\"Return the color to be used for shading inset borders. The default is my own color, but it might want to be, eg, my owner's color. Whoever's color ends up prevailing, the color itself gets the last chance to determine, so that when, for example, an InfiniteForm serves as the color, callers won't choke on some non-Color object being returned\\\"\\n\\t(color isColor and:[color isTransparent and:[owner notNil]]) ifTrue:[^owner colorForInsets].\\n\\t^ color colorForInsets\\n! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 8/6/2001 09:03'!\\ncolor: aColor\\n\\t\\\"Set the receiver's color. Directly set the color if appropriate, else go by way of fillStyle\\\"\\n\\n\\t(aColor isColor or: [aColor isKindOf: InfiniteForm]) ifFalse:[^ self fillStyle: aColor].\\n\\tcolor = aColor ifFalse:\\n\\t\\t[self removeProperty: #fillStyle.\\n\\t\\tcolor _ aColor.\\n\\t\\tself changed]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 4/4/2006 17:14'!\\nconnections\\n\\t\\\"Empty method in absence of connectors\\\"\\n\\t^ #()! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 12/27/2001 17:56'!\\ncouldHaveRoundedCorners\\n\\t^ true! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'nk 4/15/2004 07:50'!\\ndoesBevels\\n\\t\\\"To return true means that this object can show bevelled borders, and\\n\\ttherefore can accept, eg, #raised or #inset as valid borderColors.\\n\\tMust be overridden by subclasses that do not support bevelled borders.\\\"\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 09:53'!\\neventHandler\\n\\t\\\"answer the receiver's eventHandler\\\"\\n\\t^ extension ifNotNil: [extension eventHandler] ! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 2/16/2003 19:25'!\\neventHandler: anEventHandler \\n\\t\\\"Note that morphs can share eventHandlers and all is OK. \\\"\\n\\tself assureExtension eventHandler: anEventHandler! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 9/22/2000 13:36'!\\nforwardDirection\\n\\t\\\"Return the receiver's forward direction (in eToy terms)\\\"\\n\\t^self valueOfProperty: #forwardDirection ifAbsent:[0.0]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'di 1/3/1999 12:25'!\\nhasTranslucentColor\\n\\t\\\"Answer true if this any of this morph is translucent but not transparent.\\\"\\n\\n\\t^ color isColor and: [color isTranslucentColor]\\n! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 11/30/1998 12:44'!\\nhighlight\\n\\t\\\"The receiver is being asked to appear in a highlighted state. Mostly used for textual morphs\\\"\\n\\tself color: self highlightColor! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 3/6/1999 02:09'!\\nhighlightColor\\n\\t\\n\\t| val |\\n\\t^ (val _ self valueOfProperty: #highlightColor)\\n\\t\\tifNotNil:\\n\\t\\t\\t[val ifNil: [self error: 'nil highlightColor']]\\n\\t\\tifNil:\\n\\t\\t\\t[owner ifNil: [self color] ifNotNil: [owner highlightColor]]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 7/2/1998 13:51'!\\nhighlightColor: aColor\\n\\tself setProperty: #highlightColor toValue: aColor! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'tk 1/31/2002 10:25'!\\ninsetColor\\n\\towner ifNil:[^self color].\\n\\t^ self colorForInsets! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 6/13/2001 01:04'!\\nisFlap\\n\\t\\\"Answer whether the receiver claims to be a flap\\\"\\n\\n\\t^ self hasProperty: #flap! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 09:53'!\\nisLocked\\n\\t\\\"answer whether the receiver is Locked\\\"\\n\\textension ifNil: [^ false].\\n\\t^ extension locked! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 10/27/2000 17:42'!\\nisShared\\n\\t\\\"Answer whether the receiver has the #shared property. This property allows it to be treated as a 'background' item\\\"\\n\\n\\t^ self hasProperty: #shared! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 09:57'!\\nisSticky\\n\\t\\\"answer whether the receiver is Sticky\\\"\\n\\textension ifNil: [^ false].\\n\\t^ extension sticky! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 8/4/97 12:05'!\\nlock\\n\\tself lock: true! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 09:58'!\\nlock: aBoolean \\n\\t\\\"change the receiver's lock property\\\"\\n\\t(extension isNil and: [aBoolean not]) ifTrue: [^ self].\\n\\tself assureExtension locked: aBoolean! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 6/20/2001 15:45'!\\nmethodCommentAsBalloonHelp\\n\\t\\\"Given that I am a morph that is associated with an object and a method, answer a suitable method comment relating to that object & method if possible\\\"\\n\\n\\t| inherentSelector actual |\\n\\t(inherentSelector _ self valueOfProperty: #inherentSelector)\\n\\t\\tifNotNil:\\n\\t\\t\\t[(actual _ (self ownerThatIsA: PhraseTileMorph orA: SyntaxMorph) actualObject) ifNotNil:\\n\\t\\t\\t\\t[^ actual class precodeCommentOrInheritedCommentFor: inherentSelector]].\\n\\t^ nil! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 10/23/1999 22:35'!\\nmodelOrNil\\n\\t^ nil! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 09:54'!\\nplayer\\n\\t\\\"answer the receiver's player\\\"\\n\\t^ extension ifNotNil: [extension player]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 4/4/2006 17:18'!\\nplayerRepresented\\n\\t\\\"Answer the player represented by the receiver. Morphs that serve as references to other morphs reimplement this; be default a morph represents its own player.\\\"\\n\\n\\t^ self player! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:53'!\\nplayer: anObject \\n\\t\\\"change the receiver's player\\\"\\n\\tself assureExtension player: anObject! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 3/3/1999 13:08'!\\npresenter\\n\\t^ owner ifNotNil: [owner presenter] ifNil: [self currentWorld presenter]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 3/7/2003 15:24'!\\nraisedColor\\n\\t\\\"Return the color to be used for shading raised borders. The \\n\\tdefault is my own color, but it might want to be, eg, my \\n\\towner's color. Whoever's color ends up prevailing, the color \\n\\titself gets the last chance to determine, so that when, for \\n\\texample, an InfiniteForm serves as the color, callers won't choke \\n\\ton some non-Color object being returned\\\"\\n\\t(color isColor\\n\\t\\t\\tand: [color isTransparent\\n\\t\\t\\t\\t\\tand: [owner notNil]])\\n\\t\\tifTrue: [^ owner raisedColor].\\n\\t^ color asColor raisedColor!\\n]style[(11 2 355 3 5 18 5 26 5 24 5 18 5 20)f2b,f2,f2c145043000,f2,f2cmagenta;,f2,f2cmagenta;,f2,f2cmagenta;,f2,f2cmagenta;,f2,f2cmagenta;,f2! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 3/6/1999 02:09'!\\nregularColor\\n\\t\\n\\t| val |\\n\\t^ (val _ self valueOfProperty: #regularColor)\\n\\t\\tifNotNil:\\n\\t\\t\\t[val ifNil: [self error: 'nil regularColor']]\\n\\t\\tifNil:\\n\\t\\t\\t[owner ifNil: [self color] ifNotNil: [owner regularColor]]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 7/2/1998 13:51'!\\nregularColor: aColor\\n\\tself setProperty: #regularColor toValue: aColor! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 8/29/2000 14:56'!\\nrememberedColor\\n\\t\\\"Answer a rememberedColor, or nil if none\\\"\\n\\n\\t^ self valueOfProperty: #rememberedColor ifAbsent: [nil]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 8/29/2000 15:47'!\\nrememberedColor: aColor\\n\\t\\\"Place aColor in a property so I can retrieve it later. A tortuous but expedient flow of data\\\"\\n\\n\\t^ self setProperty: #rememberedColor toValue: aColor! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 11/15/2001 16:33'!\\nresistsRemoval\\n\\t\\\"Answer whether the receiver is marked as resisting removal\\\"\\n\\n\\t^ self hasProperty: #resistsRemoval! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 11/15/2001 16:33'!\\nresistsRemoval: aBoolean\\n\\t\\\"Set the receiver's resistsRemoval property as indicated\\\"\\n\\n\\taBoolean\\n\\t\\tifTrue:\\n\\t\\t\\t[self setProperty: #resistsRemoval toValue: true]\\n\\t\\tifFalse:\\n\\t\\t\\t[self removeProperty: #resistsRemoval]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'nk 9/4/2004 10:49'!\\nscaleFactor\\n\\t^self valueOfProperty: #scaleFactor ifAbsent: [ 1.0 ]\\n! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 11/26/2001 16:16'!\\nsetBorderStyle: aSymbol\\n\\t\\\"Set the border style of my costume\\\"\\n\\n\\t| aStyle |\\n\\taStyle _ self borderStyleForSymbol: aSymbol.\\n\\taStyle ifNil: [^ self].\\n\\t(self canDrawBorder: aStyle)\\n\\t\\tifTrue:\\n\\t\\t\\t[self borderStyle: aStyle]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'tk 12/4/1998 13:06'!\\nsqkPage\\n\\t^ self valueOfProperty: #SqueakPage! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 08:33'!\\nsticky: aBoolean \\n\\t\\\"change the receiver's sticky property\\\"\\n\\textension sticky: aBoolean! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'RAA 2/19/2001 17:38'!\\ntoggleLocked\\n\\t\\n\\tself lock: self isLocked not! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 11/15/2001 12:21'!\\ntoggleResistsRemoval\\n\\t\\\"Toggle the resistsRemoval property\\\"\\n\\n\\tself resistsRemoval\\n\\t\\tifTrue:\\n\\t\\t\\t[self removeProperty: #resistsRemoval]\\n\\t\\tifFalse:\\n\\t\\t\\t[self setProperty: #resistsRemoval toValue: true]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'md 2/27/2006 08:53'!\\ntoggleStickiness\\n\\t\\\"togle the receiver's Stickiness\\\"\\n\\textension ifNil: [^ self beSticky].\\n\\textension sticky: extension sticky not! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 11/30/1998 12:44'!\\nunHighlight\\n\\tself color: self regularColor! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'di 8/11/1998 12:33'!\\nunlock\\n\\tself lock: false! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'sw 8/15/97 23:59'!\\nunlockContents\\n\\tself submorphsDo:\\n\\t\\t[:m | m unlock]! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'tk 2/17/1999 11:45'!\\nurl\\n\\t\\\"If I have been assigned a url, return it. For PasteUpMorphs mostly.\\\"\\n\\t| sq |\\n\\t(sq _ self sqkPage) ifNotNil: [^ sq url].\\n\\t^ self valueOfProperty: #url\\n\\t\\t! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'tk 12/16/1998 11:54'!\\nuserString\\n\\t\\\"Do I have a text string to be searched on?\\\"\\n\\n\\t^ nil! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 9/27/2004 11:45'!\\nviewBox\\n\\t^ self pasteUpMorph viewBox! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 9/1/2004 16:14'!\\nvisibleClearArea\\n\\t\\\"Answer the receiver visible clear area. The intersection \\n\\tbetween the clear area and the viewbox.\\\"\\n\\t^ self viewBox intersect: self clearArea! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 4/4/2006 17:14'!\\nwantsEmbeddingsVocabulary\\n\\t\\\"Empty method in absence of connectors\\\"\\n\\t^ false! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'ar 6/23/2001 16:06'!\\nwantsToBeCachedByHand\\n\\t\\\"Return true if the receiver wants to be cached by the hand when it is dragged around.\\n\\tNote: The default implementation queries all submorphs since subclasses may have shapes that do not fill the receiver's bounds completely.\\\"\\n\\tself hasTranslucentColor ifTrue:[^false].\\n\\tself submorphsDo:[:m|\\n\\t\\tm wantsToBeCachedByHand ifFalse:[^false].\\n\\t].\\n\\t^true! !\\n\\n!Morph methodsFor: 'accessing' stamp: 'dgd 8/31/2004 16:21'!\\nwantsToBeTopmost\\n\\t\\\"Answer if the receiver want to be one of the topmost objects in its owner\\\"\\n\\t^ self isFlapOrTab! !\\n\\n\\n!Morph methodsFor: 'accessing - extension' stamp: 'md 2/27/2006 08:46'!\\nassureExtension\\n\\t\\\"creates an extension for the receiver if needed\\\"\\n\\textension ifNil: [self initializeExtension].\\n\\t^ extension! !\\n\\n!Morph methodsFor: 'accessing - extension' stamp: 'dgd 2/16/2003 19:22'!\\nextension\\n\\t\\\"answer the recevier's extension\\\"\\n\\t^ extension! !\\n\\n!Morph methodsFor: 'accessing - extension' stamp: 'md 2/27/2006 08:31'!\\nhasExtension\\n\\t\\\"answer whether the receiver has extention\\\"\\n\\t^ extension notNil! !\\n\\n!Morph methodsFor: 'accessing - extension' stamp: 'md 2/27/2006 08:35'!\\ninitializeExtension\\n\\t\\\"private - initializes the receiver's extension\\\"\\n\\textension := MorphExtension new! !\\n\\n!Morph methodsFor: 'accessing - extension' stamp: 'md 2/27/2006 08:46'!\\nprivateExtension: aMorphExtension\\n\\t\\\"private - change the receiver's extension\\\"\\n\\textension := aMorphExtension! !\\n\\n!Morph methodsFor: 'accessing - extension' stamp: 'md 2/27/2006 08:47'!\\nresetExtension\\n\\t\\\"reset the extension slot if it is not needed\\\"\\n\\t(extension notNil and: [extension isDefault]) ifTrue: [extension := nil] ! !\\n\\n\\n!Morph methodsFor: 'accessing - properties' stamp: 'md 2/27/2006 09:47'!\\nhasProperty: aSymbol \\n\\t\\\"Answer whether the receiver has the property named aSymbol\\\"\\n\\textension ifNil: [^ false].\\n\\t^extension hasProperty: aSymbol! !\\n\\n!Morph methodsFor: 'accessing - properties' stamp: 'md 2/27/2006 09:47'!\\notherProperties\\n\\t\\\"answer the receiver's otherProperties\\\"\\n\\t^ extension ifNotNil: [extension otherProperties]! !\\n\\n!Morph methodsFor: 'accessing - properties' stamp: 'md 2/27/2006 09:48'!\\nremoveProperty: aSymbol \\n\\t\\\"removes the property named aSymbol if it exists\\\"\\n\\textension ifNil: [^ self].\\n\\textension removeProperty: aSymbol! !\\n\\n!Morph methodsFor: 'accessing - properties' stamp: 'tk 10/9/2002 08:30'!\\nsetProperties: aList\\n\\t\\\"Set many properties at once from a list of prop, value, prop, value\\\"\\n\\n\\t1 to: aList size by: 2 do: [:ii |\\n\\t\\tself setProperty: (aList at: ii) toValue: (aList at: ii+1)].! !\\n\\n!Morph methodsFor: 'accessing - properties' stamp: 'md 2/27/2006 09:48'!\\nsetProperty: aSymbol toValue: anObject \\n\\t\\\"change the receiver's property named aSymbol to anObject\\\"\\n\\tanObject ifNil: [^ self removeProperty: aSymbol].\\n\\tself assureExtension setProperty: aSymbol toValue: anObject! !\\n\\n!Morph methodsFor: 'accessing - properties' stamp: 'md 2/27/2006 08:53'!\\nvalueOfProperty: aSymbol \\n\\t\\\"answer the value of the receiver's property named aSymbol\\\"\\n\\t^ extension ifNotNil: [extension valueOfProperty: aSymbol]! !\\n\\n!Morph methodsFor: 'accessing - properties' stamp: 'dgd 2/16/2003 20:55'!\\nvalueOfProperty: aSymbol ifAbsentPut: aBlock \\n\\t\\\"If the receiver possesses a property of the given name, answer \\n\\tits value. If not, then create a property of the given name, give \\n\\tit the value obtained by evaluating aBlock, then answer that \\n\\tvalue\\\"\\n\\t^ self assureExtension valueOfProperty: aSymbol ifAbsentPut: aBlock! !\\n\\n!Morph methodsFor: 'accessing - properties' stamp: 'md 2/27/2006 08:50'!\\nvalueOfProperty: aSymbol ifAbsent: aBlock \\n\\t\\\"if the receiver possesses a property of the given name, answer \\n\\tits value. If not then evaluate aBlock and answer the result of \\n\\tthis block evaluation\\\"\\n\\t^ extension \\n\\t\\tifNotNil: [extension valueOfProperty: aSymbol ifAbsent: aBlock]\\n\\t\\tifNil: [aBlock value]! !\\n\\n!Morph methodsFor: 'accessing - properties' stamp: 'md 2/27/2006 08:49'!\\nvalueOfProperty: aSymbol ifPresentDo: aBlock \\n\\t\\\"If the receiver has a property of the given name, evaluate \\n\\taBlock on behalf of the value of that property\\\"\\n\\textension ifNil: [^ self].\\n\\t^ aBlock value: (extension valueOfProperty: aSymbol ifAbsent: [^ self])! !\\n\\n\\n!Morph methodsFor: 'caching' stamp: 'jm 11/13/97 16:35'!\\nfullLoadCachedState\\n\\t\\\"Load the cached state of the receiver and its full submorph tree.\\\"\\n\\n\\tself allMorphsDo: [:m | m loadCachedState].\\n! !\\n\\n!Morph methodsFor: 'caching' stamp: 'jm 11/13/97 16:34'!\\nfullReleaseCachedState\\n\\t\\\"Release the cached state of the receiver and its full submorph tree.\\\"\\n\\n\\tself allMorphsDo: [:m | m releaseCachedState].\\n! !\\n\\n!Morph methodsFor: 'caching' stamp: 'jm 11/13/97 16:37'!\\nloadCachedState\\n\\t\\\"Load the cached state of this morph. This method may be called to pre-load the cached state of a morph to avoid delays when it is first used. (Cached state can always be recompued on demand, so a morph should not rely on this method being called.) Implementations of this method should do 'super loadCachedState'. This default implementation does nothing.\\\"\\n! !\\n\\n!Morph methodsFor: 'caching' stamp: 'md 4/3/2006 12:02'!\\nreleaseCachedState\\n\\t\\\"Release any state that can be recomputed on demand, such as the pixel values for a color gradient or the editor state for a TextMorph. This method may be called to save space when a morph becomes inaccessible. Implementations of this method should do 'super releaseCachedState'.\\\"\\n\\tself borderStyle releaseCachedState. \\n! !\\n\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'sd 3/30/2005 22:04'!\\nabstractAModel\\n\\t\\\"Find data-containing fields in me. Make a new class, whose instance variables are named for my fields, and whose values are the values I am showing. Use a CardPlayer for now. Force the user to name the fields. Make slots for text, Number Watchers, SketchMorphs, and ImageMorphs.\\\"\\n\\n\\t| instVarNames unnamed ans player twoListsOfMorphs holdsSepData docks oldPlayer iVarName |\\n\\t(oldPlayer := self player) ifNotNil: \\n\\t\\t\\t[oldPlayer belongsToUniClass \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[\\\"Player\\\"\\n\\n\\t\\t\\t\\t\\toldPlayer class instVarNames notEmpty \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[self \\n\\t\\t\\t\\t\\t\\t\\t\\tinform: 'I already have a regular Player, so I can''t have a CardPlayer'.\\n\\t\\t\\t\\t\\t\\t\\t^true]]].\\n\\ttwoListsOfMorphs := StackMorph discoverSlots: self.\\n\\tholdsSepData := twoListsOfMorphs first.\\n\\tinstVarNames := ''.\\n\\tholdsSepData do: \\n\\t\\t\\t[:ea | \\n\\t\\t\\tiVarName := Scanner wellFormedInstanceVariableNameFrom: ea knownName.\\n\\t\\t\\tiVarName = ea knownName ifFalse: [ea name: iVarName].\\n\\t\\t\\tinstVarNames := instVarNames , iVarName , ' '].\\n\\tunnamed := twoListsOfMorphs second.\\t\\\"have default names\\\"\\n\\tinstVarNames isEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[self \\n\\t\\t\\t\\tinform: 'No named fields were found.\\nPlease get a halo on each field and give it a name.\\nLabels or non-data fields should be named \\\"shared xxx\\\".'.\\n\\t\\t\\t^false].\\n\\tunnamed notEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[ans := PopUpMenu \\n\\t\\t\\t\\t\\t\\tconfirm: 'Data fields are ' , instVarNames printString \\n\\t\\t\\t\\t\\t\\t\\t\\t, ('\\\\Some fields are not named. Are they labels or non-data fields?' \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t, '\\\\Please get a halo on each data field and give it a name.') withCRs\\n\\t\\t\\t\\t\\t\\ttrueChoice: 'All other fields are non-data fields'\\n\\t\\t\\t\\t\\t\\tfalseChoice: 'Stop. Let me give a name to some more fields'.\\n\\t\\t\\tans ifFalse: [^false]].\\n\\tunnamed \\n\\t\\twithIndexDo: [:mm :ind | mm setName: 'shared label ' , ind printString].\\n\\t\\\"Make a Player with instVarNames. Make me be the costume\\\"\\n\\tplayer := CardPlayer instanceOfUniqueClassWithInstVarString: instVarNames\\n\\t\\t\\t\\tandClassInstVarString: ''.\\n\\tself player: player.\\n\\tplayer costume: self.\\n\\t\\\"Fill in the instance values. Make docks first.\\\"\\n\\tdocks := OrderedCollection new.\\n\\tholdsSepData do: \\n\\t\\t\\t[:morph | \\n\\t\\t\\tmorph setProperty: #shared toValue: true.\\t\\\"in case it is deeply embedded\\\"\\n\\t\\t\\tmorph setProperty: #holdsSeparateDataForEachInstance toValue: true.\\n\\t\\t\\tplayer class compileInstVarAccessorsFor: morph knownName.\\n\\t\\t\\tmorph isSyntaxMorph ifTrue: [morph setTarget: player].\\t\\\"hookup the UpdatingString!!\\\"\\n\\t\\t\\tdocks addAll: morph variableDocks].\\n\\tplayer class newVariableDocks: docks.\\n\\tdocks do: [:dd | dd storeMorphDataInInstance: player].\\n\\t\\\"oldPlayer class mdict do: [:assoc | move to player].\\tmove methods to new class?\\\"\\n\\t\\\"oldPlayer become: player.\\\"\\n\\t^true\\t\\\"success\\\"! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 11/2/2001 13:31'!\\nbeAStackBackground\\n\\t\\\"Transform the receiver into one that has stack-background behavior. If just becoming a stack, allocate a uniclass to represent the cards (if one does not already exist\\\"\\n\\n\\tself assuredCardPlayer assureUniClass.\\n\\tself setProperty: #tabAmongFields toValue: true.\\n\\tself setProperty: #stackBackground toValue: true.\\n\\t\\\"put my submorphs onto the background\\\"\\n\\tsubmorphs do: [:mm | mm setProperty: #shared toValue: true].\\n\\tself reassessBackgroundShape! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'sw 11/8/2002 14:57'!\\nbecomeSharedBackgroundField\\n\\t\\\"Mark the receiver as holding separate data for each instance (i.e., like a 'background field') and reassess the shape of the corresponding background so that it will be able to accommodate this arrangement.\\\"\\n\\n\\t((self hasProperty: #shared) and: [self hasProperty: #holdsSeparateDataForEachInstance])\\n\\t\\tifFalse: \\n\\t\\t\\t[self setProperty: #shared toValue: true.\\n\\t\\t\\tself setProperty: #holdsSeparateDataForEachInstance toValue: true.\\n\\t\\t\\tself stack reassessBackgroundShape]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 10/30/2001 18:54'!\\ncontainsCard: aCard\\n\\t\\\"Answer whether the given card belongs to the uniclass representing the receiver\\\"\\n\\n\\t^ self isStackBackground and: [aCard isKindOf: self player class baseUniclass]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'sw 10/27/2000 17:36'!\\ncouldHoldSeparateDataForEachInstance\\n\\t\\\"Answer whether this type of morph is inherently capable of holding separate data for each instance ('card data')\\\"\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 10/30/2001 13:32'!\\ncurrentDataInstance\\n\\t\\\"Answer the current data instance\\\"\\n\\n\\t^ self player! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 10/30/2001 13:33'!\\nexplainDesignations\\n\\t\\\"Hand the user an object that contains explanations for the designation feedback used\\\"\\n\\n\\tStackMorph designationsExplainer openInHand\\n\\n\\t\\\"self currentWorld explainDesignations\\\"! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'sw 10/23/2000 14:49'!\\ngoToNextCardInStack\\n\\t\\\"Tell my stack to advance to the next page\\\"\\n\\n\\tself stackDo: [:aStack | aStack goToNextCardInStack]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'sw 10/23/2000 14:52'!\\ngoToPreviousCardInStack\\n\\t\\\"Tell my stack to advance to the previous card\\\"\\n\\t\\n\\tself stackDo: [:aStack | aStack goToPreviousCardInStack]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'sw 10/27/2000 17:41'!\\nholdsSeparateDataForEachInstance\\n\\t\\\"Answer whether the receiver is currently behaving as a 'background field', i.e., whether it is marked as shared (viz. occurring on the background of a stack) *and* is marked as holding separate data for each instance\\\"\\n\\n\\t^ self isShared and: [self hasProperty: #holdsSeparateDataForEachInstance]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'yo 2/17/2005 17:47'!\\ninsertAsStackBackground\\n\\t\\\"I am not yet in a stack. Find a Stack that my reference point (center) overlaps, and insert me as a new background.\\\"\\n\\n\\t| aMorph |\\n\\tself isStackBackground ifTrue: [^ Beeper beep].\\t\\n\\t\\t\\\"already in a stack. Must clear flags when remove.\\\"\\n\\\"\\tself potentialEmbeddingTargets do: [:mm | No, force user to choose a stack. \\n\\t\\t(mm respondsTo: #insertAsBackground:resize:) ifTrue: [\\n\\t\\t\\t^ mm insertAsBackground: self resize: false]].\\n\\\"\\n\\t\\\"None found, ask user\\\"\\n\\tself inform: 'Please click on a Stack' translated.\\n\\tSensor waitNoButton.\\n\\taMorph _ self world chooseClickTarget.\\n\\taMorph ifNil: [^ self].\\n\\t(aMorph ownerThatIsA: StackMorph) insertAsBackground: self resize: false.! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 10/30/2001 13:35'!\\ninsertCard\\n\\t\\\"Insert a new card in the stack, with the receiver as its background, and have it become the current card of the stack\\\"\\n\\n\\tself stackDo: [:aStack | aStack insertCardOfBackground: self]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'sw 11/8/2002 15:16'!\\ninstallAsCurrent: anInstance\\n\\t\\\"Install anInstance as the one currently viewed in the receiver. Dock up all the morphs in the receiver which contain data rooted in the player instance to the instance data. Run any 'opening' scripts that pertain.\\\"\\n\\n\\t| fieldList itsFocus |\\n\\tself player == anInstance ifTrue: [^ self].\\n\\tfieldList _ self allMorphs select:\\n\\t\\t[:aMorph | (aMorph wouldAcceptKeyboardFocusUponTab) and: [aMorph isLocked not]].\\n\\tself currentWorld hands do:\\n\\t\\t[:aHand | (itsFocus _ aHand keyboardFocus) notNil ifTrue:\\n\\t\\t\\t[(fieldList includes: itsFocus) ifTrue: [aHand newKeyboardFocus: nil]]].\\n\\n\\tself player uninstallFrom: self. \\\"out with the old\\\"\\n\\n\\tanInstance installPrivateMorphsInto: self.\\n\\tself changed.\\n\\tanInstance costume: self.\\n\\tself player: anInstance.\\n\\tself player class variableDocks do:\\n\\t\\t[:aVariableDock | aVariableDock dockMorphUpToInstance: anInstance].\\n\\tself currentWorld startSteppingSubmorphsOf: self! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 10/30/2001 13:42'!\\nisStackBackground\\n\\t\\\"Answer whether the receiver serves as a background of a stack\\\"\\n\\n\\t^ ((owner isKindOf: StackMorph) and: [owner currentPage == self]) or:\\n\\t\\t[self hasProperty: #stackBackground]\\n\\n\\t\\\"This odd property-based check is because when a paste-up-morph is not the *current* background of a stack, it is maddeningly ownerlyess\\\"! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 11/2/2001 13:38'!\\nmakeHoldSeparateDataForEachInstance\\n\\t\\\"Mark the receiver as holding separate data for each instance (i.e., like a 'background field') and reassess the shape of the corresponding background so that it will be able to accommodate this arrangement.\\\"\\n\\n\\tself setProperty: #holdsSeparateDataForEachInstance toValue: true.\\n\\tself stack reassessBackgroundShape.! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'nb 6/17/2003 12:25'!\\nnewCard\\n\\t\\\"Create a new card for the receiver and return it\\\"\\n\\n\\t| aNewInstance |\\n\\tself isStackBackground ifFalse: [^ Beeper beep]. \\\"bulletproof against deconstruction\\\"\\n\\taNewInstance _ self player class baseUniclass new.\\n\\t^ aNewInstance! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'md 10/22/2003 15:52'!\\nreassessBackgroundShape\\n\\t\\\"A change has been made which may affect the instance structure of the Card uniclass that holds the instance state, which can also be thought of as the 'card data'.\\\"\\n\\n\\t\\\"Caution: still to be done: the mechanism so that when a new instance variable is added, it gets initialized in all subinstances of the receiver's player, which are the cards of this shape. One needs to take into account here the instance variable names coming in; those that are unchanged should keep their values, but those that have newly arrived should obtain their default values from the morphs on whose behalf they are being maintained in the model\\\"\\n\\n\\t| takenNames uniqueName requestedName variableDocks docks sepDataMorphs sorted existing name1 name2 |\\n\\tself isStackBackground ifFalse: [^Beeper beep].\\t\\\"bulletproof against deconstruction\\\"\\n\\tCursor wait showWhile: \\n\\t\\t\\t[variableDocks := OrderedCollection new.\\t\\\"This will be stored in the uniclass's \\n\\t\\t\\tclass-side inst var #variableDocks\\\"\\n\\t\\t\\ttakenNames := OrderedCollection new.\\n\\t\\t\\tsepDataMorphs := OrderedCollection new.\\t\\\"fields, holders of per-card data\\\"\\n\\t\\t\\tself submorphs do: \\n\\t\\t\\t\\t\\t[:aMorph | \\n\\t\\t\\t\\t\\taMorph renderedMorph holdsSeparateDataForEachInstance \\n\\t\\t\\t\\t\\t\\tifTrue: [sepDataMorphs add: aMorph renderedMorph]\\n\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t[\\\"look for buried fields, inside a frame\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\taMorph renderedMorph isShared \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[aMorph allMorphs do: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[:mm | \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tmm renderedMorph holdsSeparateDataForEachInstance \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [sepDataMorphs add: mm renderedMorph]]]]].\\n\\t\\t\\tsorted := SortedCollection new \\n\\t\\t\\t\\t\\t\\tsortBlock: [:a :b | (a valueOfProperty: #cardInstance) notNil].\\t\\\"puts existing ones first\\\"\\n\\t\\t\\tsorted addAll: sepDataMorphs.\\n\\t\\t\\tsorted do: \\n\\t\\t\\t\\t\\t[:aMorph | \\n\\t\\t\\t\\t\\tdocks := aMorph variableDocks.\\n\\t\\t\\t\\t\\t\\\"Each morph can request multiple variables. \\n\\tThis complicates matters somewhat but creates a generality for Fabrk-like uses.\\n\\tEach spec is an instance of VariableDock, and it provides a point of departure\\n\\tfor the negotiation between the PasteUp and its constitutent morphs\\\"\\n\\t\\t\\t\\t\\tdocks do: \\n\\t\\t\\t\\t\\t\\t\\t[:aVariableDock | \\n\\t\\t\\t\\t\\t\\t\\tuniqueName := self player \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tuniqueInstanceVariableNameLike: (requestedName := aVariableDock \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tvariableName)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\texcluding: takenNames.\\n\\t\\t\\t\\t\\t\\t\\tuniqueName ~= requestedName \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[aVariableDock variableName: uniqueName.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\taMorph noteNegotiatedName: uniqueName for: requestedName].\\n\\t\\t\\t\\t\\t\\t\\ttakenNames add: uniqueName].\\n\\t\\t\\t\\t\\tvariableDocks addAll: docks].\\n\\t\\t\\texisting := self player class instVarNames.\\n\\t\\t\\tvariableDocks := (variableDocks asSortedCollection: \\n\\t\\t\\t\\t\\t\\t\\t[:dock1 :dock2 | \\n\\t\\t\\t\\t\\t\\t\\tname1 := dock1 variableName.\\n\\t\\t\\t\\t\\t\\t\\tname2 := dock2 variableName.\\n\\t\\t\\t\\t\\t\\t\\t(existing indexOf: name1 ifAbsent: [0]) \\n\\t\\t\\t\\t\\t\\t\\t\\t< (existing indexOf: name2 ifAbsent: [variableDocks size])]) \\n\\t\\t\\t\\t\\t\\tasOrderedCollection.\\n\\t\\t\\tself player class setNewInstVarNames: (variableDocks \\n\\t\\t\\t\\t\\t\\tcollect: [:info | info variableName asString]).\\n\\t\\t\\t\\\"NB: sets up accessors, and removes obsolete ones\\\"\\n\\t\\t\\tself player class newVariableDocks: variableDocks]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 10/30/2001 13:46'!\\nrelaxGripOnVariableNames\\n\\t\\\"Abandon any memory of specific variable names that should be preserved. The overall situation here is not yet completely understood, and this relaxation is basically always done on each reassessment of the background shape nowadays. But this doesn't feel quite right, because if the user has somehow intervened to specify certain name preference we should perhaps honored it. Or perhaps that is no longer relevant. ????\\\"\\n\\n\\tself submorphs do:\\n\\t\\t[:m | m removeProperty: #variableName.\\n\\t\\tm removeProperty: #setterSelector].\\n\\tself reassessBackgroundShape\\n! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 10/30/2001 13:47'!\\nreshapeBackground\\n\\t\\\"Abandon any memory of variable-name preferences, and reassess the shape of the background\\\"\\n\\n\\tself relaxGripOnVariableNames.\\n\\t\\\"self reassessBackgroundShape.\\talready done there\\\"! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'sw 10/24/2000 06:30'!\\nsetAsDefaultValueForNewCard\\n\\t\\\"Set the receiver's current value as the one to be used to supply the default value for a variable on a new card. This implementation does not support multiple variables per morph, which is problematical\\\"\\n\\n\\tself setProperty: #defaultValue toValue: self currentDataValue deepCopy! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 10/30/2001 13:48'!\\nshowBackgroundObjects\\n\\t\\\"Momentarily highlight just the background objects on the current playfield\\\"\\n\\n\\tself isStackBackground ifFalse: [^ self].\\n\\tself invalidRect: self bounds.\\n\\tself currentWorld doOneCycle.\\n\\tDisplay restoreAfter:\\n\\t\\t[self submorphsDo:\\n\\t\\t\\t[:aMorph | (aMorph renderedMorph hasProperty: #shared)\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[Display border: (aMorph fullBoundsInWorld insetBy: -6) \\n\\t\\t\\t\\t\\t\\t\\twidth: 6 rule: Form over fillColor: Color blue]]]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'aoy 2/15/2003 21:50'!\\nshowDesignationsOfObjects\\n\\t\\\"Momentarily show the designations of objects on the receiver\\\"\\n\\n\\t| colorToUse aLabel |\\n\\tself isStackBackground ifFalse: [^self].\\n\\tself submorphsDo: \\n\\t\\t\\t[:aMorph | \\n\\t\\t\\taLabel :=aMorph renderedMorph holdsSeparateDataForEachInstance \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[colorToUse := Color orange.\\n\\t\\t\\t\\t\\t aMorph externalName]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[colorToUse := aMorph isShared ifFalse: [Color red] ifTrue: [Color green].\\n\\t\\t\\t\\t\\t nil].\\n\\t\\t\\tDisplay \\n\\t\\t\\t\\tborder: (aMorph fullBoundsInWorld insetBy: -6)\\n\\t\\t\\t\\twidth: 6\\n\\t\\t\\t\\trule: Form over\\n\\t\\t\\t\\tfillColor: colorToUse.\\n\\t\\t\\taLabel ifNotNil: \\n\\t\\t\\t\\t\\t[aLabel asString \\n\\t\\t\\t\\t\\t\\tdisplayOn: Display\\n\\t\\t\\t\\t\\t\\tat: aMorph fullBoundsInWorld bottomLeft + (0 @ 5)\\n\\t\\t\\t\\t\\t\\ttextColor: Color blue]].\\n\\tSensor anyButtonPressed \\n\\t\\tifTrue: [Sensor waitNoButton]\\n\\t\\tifFalse: [Sensor waitButton].\\n\\tWorld fullRepaintNeeded! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 10/30/2001 13:50'!\\nshowForegroundObjects\\n\\t\\\"Temporarily highlight the foreground objects\\\"\\n\\n\\tself isStackBackground ifFalse: [^ self].\\n\\tDisplay restoreAfter:\\n\\t\\t[self submorphsDo:\\n\\t\\t\\t[:aMorph | aMorph renderedMorph isShared\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[Display border: (aMorph fullBoundsInWorld insetBy: -6) \\n\\t\\t\\t\\t\\t\\twidth: 6 rule: Form over fillColor: Color orange]]]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 11/2/2001 13:53'!\\nstack\\n\\t\\\"Answer the nearest containing Stack, or, if none, a stack in the current project, and if still none, nil. The extra messiness is because uninstalled backgrounds don't have an owner pointers to their stack.\\\"\\n\\n\\t| aStack bkgnd |\\n\\tbkgnd _ self orOwnerSuchThat: [:oo | oo hasProperty: #myStack].\\n\\tbkgnd ifNotNil: [^ bkgnd valueOfProperty: #myStack].\\n\\n\\t\\\"fallbacks\\\"\\n\\t(aStack _ self ownerThatIsA: StackMorph) ifNotNil: [^ aStack].\\n\\t^ Project current currentStack! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'sw 10/23/2000 14:38'!\\nstackDo: aBlock\\n\\t\\\"If the receiver has a stack, evaluate aBlock on its behalf\\\"\\n\\n\\t| aStack |\\n\\t(aStack _ self ownerThatIsA: StackMorph) ifNotNil:\\n\\t\\t[^ aBlock value: aStack]! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 11/2/2001 13:38'!\\nstopHoldingSeparateDataForEachInstance\\n\\t\\\"Make the receiver no longer hold separate data for each instance\\\"\\n\\n\\tself removeProperty: #holdsSeparateDataForEachInstance.\\n\\tself stack reassessBackgroundShape.! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'dgd 8/28/2004 19:15'!\\ntabHitWithEvent: anEvent\\n\\t\\\"The tab key was hit. The keyboard focus has referred this event to me, though this perhaps seems rather backwards. Anyway, the assumption is that I have the property #tabAmongFields, so now the task is to tab to the next field.\\\"\\n\\n\\t| currentFocus fieldList anIndex itemToHighlight variableBearingMorphs otherAmenableMorphs |\\n\\tcurrentFocus _ anEvent hand keyboardFocus.\\n\\tfieldList _ self allMorphs select:\\n\\t\\t[:aMorph | (aMorph wouldAcceptKeyboardFocusUponTab) and: [aMorph isLocked not]].\\n\\n\\tfieldList isEmpty ifTrue:[^ self].\\n\\n\\tvariableBearingMorphs _ self player isNil\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue:[#()]\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifFalse:[self player class variableDocks collect: [:vd | vd definingMorph] thenSelect: [:m | m isInWorld]].\\n\\totherAmenableMorphs _ (self allMorphs select:\\n\\t\\t[:aMorph | (aMorph wouldAcceptKeyboardFocusUponTab) and: [aMorph isLocked not]])\\n\\t\\t\\tcopyWithoutAll: variableBearingMorphs.\\n\\tfieldList _ variableBearingMorphs, otherAmenableMorphs.\\n\\n\\tanIndex _ fieldList indexOf: currentFocus ifAbsent: [nil].\\n\\titemToHighlight _ fieldList atWrap: \\n\\t\\t(anIndex ifNotNil: [anEvent shiftPressed ifTrue: [anIndex - 1] ifFalse: [anIndex + 1]]\\n\\t\\t\\t\\tifNil: [1]).\\n\\tanEvent hand newKeyboardFocus: itemToHighlight. self flag: #arNote. \\\"really???\\\"\\n\\titemToHighlight editor selectAll.\\n\\titemToHighlight invalidRect: itemToHighlight bounds ! !\\n\\n!Morph methodsFor: 'card in a stack' stamp: 'tk 11/4/2001 20:57'!\\nwrapWithAStack\\n\\t\\\"Install me as a card inside a new stack. The stack has no border or controls, so I my look is unchanged. If I don't already have a CardPlayer, find my data fields and make one. Be ready to make new cards in the stack that look like me, but hold different field data.\\\"\\n\\n\\tself player class officialClass == CardPlayer ifFalse: [\\n\\t\\tself abstractAModel ifFalse: [^ false]].\\n\\tStackMorph new initializeWith: self.\\n\\tself stack addHalo.\\t\\\"Makes it easier for the user\\\"! !\\n\\n\\n!Morph methodsFor: 'change reporting' stamp: 'ar 8/12/2003 21:50'!\\naddedMorph: aMorph\\n\\t\\\"Notify the receiver that the given morph was just added.\\\"\\n! !\\n\\n!Morph methodsFor: 'change reporting' stamp: 'sw 9/10/1998 08:18'!\\ncolorChangedForSubmorph: aSubmorph\\n\\t\\\"The color associated with aSubmorph was changed through the UI; react if needed\\\"! !\\n\\n!Morph methodsFor: 'change reporting' stamp: 'ar 11/12/2000 18:50'!\\ninvalidRect: damageRect\\n\\t^self invalidRect: damageRect from: self! !\\n\\n!Morph methodsFor: 'change reporting' stamp: 'md 4/3/2006 11:52'!\\ninvalidRect: aRectangle from: aMorph\\n\\t| damageRect |\\n\\taRectangle hasPositiveExtent ifFalse: [ ^self ].\\n\\tdamageRect _ aRectangle.\\n\\taMorph == self ifFalse:[\\n\\t\\t\\\"Clip to receiver's clipping bounds if the damage came from a child\\\"\\n\\t\\tself clipSubmorphs \\n\\t\\t\\tifTrue:[damageRect _ aRectangle intersect: self clippingBounds]].\\n\\towner ifNotNil: [owner invalidRect: damageRect from: self].! !\\n\\n!Morph methodsFor: 'change reporting' stamp: 'sw 7/8/1998 13:21'!\\nownerChanged\\n\\t\\\"The receiver's owner, some kind of a pasteup, has changed its layout.\\\"\\n\\n\\tself snapToEdgeIfAppropriate! !\\n\\n!Morph methodsFor: 'change reporting' stamp: 'ar 8/12/2003 22:26'!\\nprivateInvalidateMorph: aMorph\\n\\t\\\"Private. Invalidate the given morph after adding or removing.\\n\\tThis method is private because a) we're invalidating the morph 'remotely'\\n\\tand b) it forces a fullBounds computation which should not be necessary\\n\\tfor a general morph c) the morph may or may not actually invalidate\\n\\tanything (if it's not in the world nothing will happen) and d) the entire\\n\\tmechanism should be rewritten.\\\"\\n\\taMorph fullBounds.\\n\\taMorph changed! !\\n\\n!Morph methodsFor: 'change reporting' stamp: 'tk 8/24/2001 22:07'!\\nuserSelectedColor: aColor\\n\\t\\\"The user, via the UI, chose aColor to be the color for the receiver; set it, and tell my owner in case he wishes to react\\\"\\n\\tself color: aColor.\\n\\tself world ifNotNil: [owner colorChangedForSubmorph: self]! !\\n\\n\\n!Morph methodsFor: 'classification' stamp: 'sw 2/26/2002 23:29'!\\ndemandsBoolean\\n\\t\\\"Answer whether the receiver will only accept a drop if it is boolean-valued. Particular to tile-scripting.\\\"\\n\\n\\t^ self hasProperty: #demandsBoolean! !\\n\\n!Morph methodsFor: 'classification' stamp: 'di 5/7/1998 01:21'!\\nisAlignmentMorph\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'classification' stamp: 'ar 9/15/2000 17:56'!\\nisBalloonHelp\\n\\t^false! !\\n\\n!Morph methodsFor: 'classification' stamp: 'ar 9/28/2000 13:54'!\\nisFlapOrTab\\n\\t^self isFlap or:[self isFlapTab]! !\\n\\n!Morph methodsFor: 'classification' stamp: 'ar 9/28/2000 13:53'!\\nisFlapTab\\n\\t^false! !\\n\\n!Morph methodsFor: 'classification' stamp: 'jm 4/17/1998 00:44'!\\nisFlexMorph\\n\\n\\t^ false\\n! !\\n\\n!Morph methodsFor: 'classification'!\\nisHandMorph\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'classification' stamp: 'ar 10/3/2000 18:11'!\\nisModalShell\\n\\t^false! !\\n\\n!Morph methodsFor: 'classification' stamp: 'sw 1/29/98 21:51'!\\nisPlayfieldLike\\n\\t^ false! !\\n\\n!Morph methodsFor: 'classification' stamp: 'jm 5/7/1998 13:45'!\\nisRenderer\\n\\t\\\"A *renderer* morph transforms the appearance of its submorph in some manner. For example, it might supply a drop shadow or scale and rotate the morph it encases. Answer true if this morph acts as a renderer. This default implementation returns false.\\\"\\n\\t\\\"Details: A renderer is assumed to have a single submorph. Renderers may be nested to concatenate their transformations. It is useful to be able to find the outer-most renderer. This can be done by ascending the owner chain from the rendered morph. To find the morph being rendered, one can descend through the (singleton) submorph lists of the renderer chain until a non-renderer is encountered.\\\"\\n\\n\\t^ false\\n! !\\n\\n!Morph methodsFor: 'classification' stamp: 'ar 6/30/2001 13:13'!\\nisStandardViewer\\n\\t^false! !\\n\\n!Morph methodsFor: 'classification' stamp: 'di 11/2/2000 13:24'!\\nisSyntaxMorph\\n\\t^false! !\\n\\n!Morph methodsFor: 'classification' stamp: 'ar 12/16/2001 18:28'!\\nisTextMorph\\n\\t^false! !\\n\\n!Morph methodsFor: 'classification'!\\nisWorldMorph\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'classification'!\\nisWorldOrHandMorph\\n\\n\\t^ self isWorldMorph or: [self isHandMorph]! !\\n\\n\\n!Morph methodsFor: 'connectors-scripting' stamp: 'nk 9/10/2004 11:37'!\\nwantsConnectorVocabulary\\n\\t\\\"Answer true if I want to show a 'connector' vocabulary\\\"\\n\\t^false! !\\n\\n\\n!Morph methodsFor: 'converting'!\\nasDraggableMorph\\n\\t^self! !\\n\\n!Morph methodsFor: 'converting' stamp: 'wiz 2/19/2006 19:01'!\\nasSnapshotThumbnail\\n\\t^(ThumbnailImageMorph new newImage: self imageForm ) extent: 90 asPoint .! !\\n\\n\\n!Morph methodsFor: 'copying' stamp: 'tk 2/19/2001 18:21'!\\ncopy\\n\\n\\t^ self veryDeepCopy! !\\n\\n!Morph methodsFor: 'copying' stamp: 'tk 2/14/2001 12:47'!\\ndeepCopy\\n\\n\\tself error: 'Please use veryDeepCopy'.\\n! !\\n\\n!Morph methodsFor: 'copying' stamp: 'sw 4/19/2005 17:02'!\\nduplicate\\n\\t\\\"Make and return a duplicate of the receiver\\\"\\n\\n\\t| newMorph aName w aPlayer topRend |\\n\\t((topRend _ self topRendererOrSelf) ~~ self) ifTrue: [^ topRend duplicate].\\n\\n\\tself okayToDuplicate ifFalse: [^ self].\\n\\taName _ (w _ self world) ifNotNil:\\n\\t\\t[w nameForCopyIfAlreadyNamed: self].\\n\\tnewMorph _ self veryDeepCopy.\\n\\taName ifNotNil: [newMorph setNameTo: aName].\\n\\n\\tnewMorph arrangeToStartStepping.\\n\\tnewMorph privateOwner: nil. \\\"no longer in world\\\"\\n\\tnewMorph isPartsDonor: false. \\\"no longer parts donor\\\"\\n\\t(aPlayer _ newMorph player) belongsToUniClass ifTrue:\\n\\t\\t[aPlayer class bringScriptsUpToDate].\\n\\taPlayer ifNotNil: [ActiveWorld presenter flushPlayerListCache].\\n\\t^ newMorph! !\\n\\n!Morph methodsFor: 'copying' stamp: 'nk 3/12/2001 17:07'!\\nduplicateMorphCollection: aCollection\\n\\t\\\"Make and return a duplicate of the receiver\\\"\\n\\n\\t| newCollection names |\\n\\n\\tnames _ aCollection collect: [ :ea | | newMorph w |\\n\\t\\t(w _ ea world) ifNotNil:\\n\\t\\t\\t[w nameForCopyIfAlreadyNamed: ea].\\n\\t].\\n\\n\\tnewCollection _ aCollection veryDeepCopy.\\n\\n\\tnewCollection with: names do: [ :newMorph :name |\\n\\t\\tname ifNotNil: [ newMorph setNameTo: name ].\\n\\t\\tnewMorph arrangeToStartStepping.\\n\\t\\tnewMorph privateOwner: nil. \\\"no longer in world\\\"\\n\\t\\tnewMorph isPartsDonor: false. \\\"no longer parts donor\\\"\\n\\t].\\n\\n\\t^newCollection! !\\n\\n!Morph methodsFor: 'copying' stamp: 'sw 2/16/2001 16:30'!\\nfullCopy\\n\\t\\\"Deprecated, but maintained for backward compatibility with existing code (no senders in the base 3.0 image). Calls are revectored to #veryDeepCopy, but note that #veryDeepCopy does not do exactly the same thing that the original #fullCopy did, so beware!!\\\"\\n\\n\\t^ self veryDeepCopy! !\\n\\n!Morph methodsFor: 'copying' stamp: 'md 2/27/2006 08:53'!\\nupdateReferencesUsing: aDictionary \\n\\t\\\"Update intra-morph references within a composite morph that \\n\\thas been copied. For example, if a button refers to morph X in \\n\\tthe orginal \\n\\tcomposite then the copy of that button in the new composite \\n\\tshould refer to \\n\\tthe copy of X in new composite, not the original X. This default \\n\\timplementation updates the contents of any morph-bearing slot. \\n\\tIt may be \\n\\toverridden to avoid this behavior if so desired.\\\"\\n\\t| old |\\n\\tMorph instSize + 1\\n\\t\\tto: self class instSize\\n\\t\\tdo: [:i | \\n\\t\\t\\told _ self instVarAt: i.\\n\\t\\t\\told isMorph\\n\\t\\t\\t\\tifTrue: [self\\n\\t\\t\\t\\t\\t\\tinstVarAt: i\\n\\t\\t\\t\\t\\t\\tput: (aDictionary\\n\\t\\t\\t\\t\\t\\t\\t\\tat: old\\n\\t\\t\\t\\t\\t\\t\\t\\tifAbsent: [old])]].\\n\\textension ifNotNil: [extension updateReferencesUsing: aDictionary]! !\\n\\n!Morph methodsFor: 'copying' stamp: 'nk 10/11/2003 16:59'!\\nusableSiblingInstance\\n\\t\\\"Return another similar morph whose Player is of the same class as mine.\\n\\tDo not open it in the world.\\\"\\n\\n\\t| aName usedNames newPlayer newMorph topRenderer |\\n\\t(topRenderer := self topRendererOrSelf) == self \\n\\t\\tifFalse: [^topRenderer usableSiblingInstance].\\n\\tself assuredPlayer assureUniClass.\\n\\tnewMorph := self veryDeepCopySibling.\\n\\tnewPlayer := newMorph player.\\n\\tnewPlayer resetCostumeList.\\n\\t(aName := self knownName) isNil \\n\\t\\tifTrue: [self player notNil ifTrue: [aName := newMorph innocuousName]].\\n\\t\\\"Force a difference here\\\"\\n\\taName notNil \\n\\t\\tifTrue: \\n\\t\\t\\t[usedNames := (self world ifNil: [OrderedCollection new]\\n\\t\\t\\t\\t\\t\\tifNotNil: [self world allKnownNames]) copyWith: aName.\\n\\t\\t\\tnewMorph setNameTo: (Utilities keyLike: aName\\n\\t\\t\\t\\t\\t\\tsatisfying: [:f | (usedNames includes: f) not])].\\n\\tnewMorph privateOwner: nil.\\n\\tnewPlayer assureEventHandlerRepresentsStatus.\\n\\tself presenter flushPlayerListCache.\\n\\t^newMorph! !\\n\\n!Morph methodsFor: 'copying' stamp: 'tk 1/6/1999 17:27'!\\nveryDeepCopyWith: deepCopier\\n\\t\\\"Copy me and the entire tree of objects I point to. An object in the tree twice is copied once, and both references point to him. deepCopier holds a dictionary of objects we have seen. See veryDeepInner:, veryDeepFixupWith:\\\"\\n\\n\\tself prepareToBeSaved.\\n\\t^ super veryDeepCopyWith: deepCopier! !\\n\\n!Morph methodsFor: 'copying' stamp: 'tk 2/3/2001 14:29'!\\nveryDeepFixupWith: deepCopier\\n\\t\\\"If some fields were weakly copied, fix new copy here.\\\"\\n\\n\\t\\\"super veryDeepFixupWith: deepCopier.\\tObject has no fixups, so don't call it\\\"\\n\\n\\t\\\"If my owner is being duplicated too, then store his duplicate.\\n\\t If I am owned outside the duplicated tree, then I am no longer owned!!\\\"\\n\\towner _ deepCopier references at: owner ifAbsent: [nil].\\n\\n! !\\n\\n!Morph methodsFor: 'copying' stamp: 'md 2/27/2006 08:47'!\\nveryDeepInner: deepCopier \\n\\t\\\"The inner loop, so it can be overridden when a field should not \\n\\tbe traced.\\\"\\n\\t\\\"super veryDeepInner: deepCopier.\\tknow Object has no inst vars\\\"\\n\\tbounds _ bounds clone.\\n\\t\\\"Points are shared with original\\\"\\n\\t\\\"owner _ owner.\\tspecial, see veryDeepFixupWith:\\\"\\n\\tsubmorphs _ submorphs veryDeepCopyWith: deepCopier.\\n\\t\\\"each submorph's fixup will install me as the owner\\\"\\n\\t\\\"fullBounds _ fullBounds.\\tfullBounds is shared with original!!\\\"\\n\\tcolor _ color veryDeepCopyWith: deepCopier.\\n\\t\\\"color, if simple, will return self. may be complex\\\"\\n\\textension := (extension veryDeepCopyWith: deepCopier)! !\\n\\n\\n!Morph methodsFor: 'creation' stamp: 'tk 2/6/1999 22:43'!\\nasMorph\\n\\t^ self! !\\n\\n\\n!Morph methodsFor: 'debug and other' stamp: 'dgd 8/30/2003 20:36'!\\naddDebuggingItemsTo: aMenu hand: aHandMorph\\n\\taMenu add: 'debug...' translated subMenu: (self buildDebugMenu: aHandMorph)! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 1/19/2001 07:51'!\\naddMouseActionIndicatorsWidth: anInteger color: aColor\\n\\n\\tself deleteAnyMouseActionIndicators.\\n\\n\\tself changed.\\n\\tself hasRolloverBorder: true.\\n\\tself setProperty: #rolloverWidth toValue: anInteger@anInteger.\\n\\tself setProperty: #rolloverColor toValue: aColor.\\n\\tself layoutChanged.\\n\\tself changed.\\n\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'gm 4/25/2004 14:23'!\\naddMouseUpAction\\n\\t| codeToRun oldCode |\\n\\toldCode := self\\n\\t\\t\\t\\tvalueOfProperty: #mouseUpCodeToRun\\n\\t\\t\\t\\tifAbsent: [''].\\n\\tcodeToRun := FillInTheBlank request: 'MouseUp expression:' translated initialAnswer: oldCode.\\n\\tself addMouseUpActionWith: codeToRun! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'gm 2/22/2003 13:41'!\\naddMouseUpActionWith: codeToRun \\n\\t((codeToRun isMessageSend) not and: [codeToRun isEmptyOrNil]) \\n\\t\\tifTrue: [^self].\\n\\tself setProperty: #mouseUpCodeToRun toValue: codeToRun.\\n\\tself \\n\\t\\ton: #mouseUp\\n\\t\\tsend: #programmedMouseUp:for:\\n\\t\\tto: self.\\n\\tself \\n\\t\\ton: #mouseDown\\n\\t\\tsend: #programmedMouseDown:for:\\n\\t\\tto: self.\\n\\tself \\n\\t\\ton: #mouseEnter\\n\\t\\tsend: #programmedMouseEnter:for:\\n\\t\\tto: self.\\n\\tself \\n\\t\\ton: #mouseLeave\\n\\t\\tsend: #programmedMouseLeave:for:\\n\\t\\tto: self! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'sw 1/3/2001 06:42'!\\naddViewingItemsTo: aMenu\\n\\t\\\"Add viewing-related items to the given menu. If any are added, this method is also responsible for adding a line after them\\\"! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'dgd 2/22/2003 14:27'!\\nallStringsAfter: aSubmorph \\n\\t\\\"return an OrderedCollection of strings of text in my submorphs. If aSubmorph is non-nil, begin with that container.\\\"\\n\\n\\t| list string ok |\\n\\tlist := OrderedCollection new.\\n\\tok := aSubmorph isNil.\\n\\tself allMorphsDo: \\n\\t\\t\\t[:sub | \\n\\t\\t\\tok ifFalse: [ok := sub == aSubmorph].\\t\\\"and do this one too\\\"\\n\\t\\t\\tok \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[(string := sub userString) ifNotNil: \\n\\t\\t\\t\\t\\t\\t\\t[string isString ifTrue: [list add: string] ifFalse: [list addAll: string]]]].\\n\\t^list! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 7/7/2000 16:27'!\\naltSpecialCursor0\\n\\t\\\"an arrow\\\"\\n\\t^(Form\\n\\textent: 16@16\\n\\tdepth: 8\\n\\tfromArray: #( 0 0 0 0 14869218 3806520034 3806520034 3791650816 14848144 2425393296 2425393378 0 14848144 2425393296 2425414144 0 14848144 2425393296 2430730240 0 14848144 2425393296 3791650816 0 14848144 2425393378 3791650816 0 14848144 2425414370 3806461952 0 14848144 2430788322 3806519808 0 14848144 3791651042 3806520034 0 14848226 0 3806520034 3791650816 14868992 0 14869218 3806461952 14811136 0 58082 3806519808 0 0 226 3806520034 0 0 0 3806520034 0 0 0 14869218)\\n\\toffset: 0@0)\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 7/7/2000 16:28'!\\naltSpecialCursor1\\n\\t\\\"a star and an arrow\\\"\\n\\t^(Form\\n\\textent: 31@26\\n\\tdepth: 8\\n\\tfromArray: #( 14417920 0 0 0 0 0 0 0 3705461980 3705461980 3705405440 0 0 0 0 0 3705461980 3705461980 3705461760 0 0 0 0 0 14474460 3705461980 3705405440 0 0 0 0 0 56540 3705461980 3690987520 0 0 3690987520 0 0 220 3705461980 3705461760 0 0 3690987520 0 0 220 3705405440 3705461980 0 0 3705405440 0 0 0 3705461760 56540 3690987520 220 3705405440 0 0 0 3705405440 220 3705461760 220 3705405440 0 0 0 0 0 14474460 220 3705461760 0 0 0 0 0 56540 3691044060 3705461760 0 0 0 0 0 220 3705461980 3705461760 0 0 0 0 56540 3705461980 3705461980 3705461980 3705461980 3705461760 0 0 220 3705461980 3705461980 3705461980 3705461980 3705461760 0 0 0 3705461980 3705461980 3705461980 3705461980 3705405440 0 0 0 14474460 3705461980 3705461980 3705461980 3690987520 0 0 0 56540 3705461980 3705461980 3705461760 0 0 0 0 220 3705461980 3705461980 3705405440 0 0 0 0 0 3705461980 3705461980 3690987520 0 0 0 0 0 3705461980 3705461980 3705405440 0 0 0 0 220 3705461980 3705461980 3705405440 0 0 0 0 220 3705461980 3705461980 3705405440 0 0 0 0 220 3705461980 14474460 3705405440 0 0 0 0 220 3705405440 220 3705461760 0 0 0 0 56540 3690987520 0 3705461760 0 0 0 0 56540 0 0 14474240 0)\\n\\toffset: 0@0)! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 7/7/2000 16:41'!\\naltSpecialCursor2\\n\\t| f |\\n\\t\\\"a blue box with transparent center\\\"\\n\\tf _ Form extent: 32@32 depth: 32.\\n\\tf offset: (f extent // 2) negated.\\n\\tf fill: f boundingBox rule: Form over fillColor: (Color blue alpha: 0.5).\\n\\tf fill: (f boundingBox insetBy: 4) rule: Form over fillColor: Color transparent.\\n\\t^f\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 7/7/2000 16:42'!\\naltSpecialCursor3\\n\\t\\n\\t^self altSpecialCursor3: Color blue! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 7/7/2000 16:41'!\\naltSpecialCursor3: aColor\\n\\t| f box |\\n\\t\\\"a bulls-eye pattern in this color\\\"\\n\\tf _ Form extent: 32@32 depth: 32.\\n\\tf offset: (f extent // 2) negated.\\n\\tbox _ f boundingBox.\\n\\t[ box width > 0] whileTrue: [\\n\\t\\tf fill: box rule: Form over fillColor: aColor.\\n\\t\\tf fill: (box insetBy: 2) rule: Form over fillColor: Color transparent.\\n\\t\\tbox _ box insetBy: 4.\\n\\t].\\n\\t^f\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'nk 6/14/2004 16:14'!\\nbuildDebugMenu: aHand\\n\\t\\\"Answer a debugging menu for the receiver. The hand argument is seemingly historical and plays no role presently\\\"\\n\\n\\t| aMenu aPlayer |\\n\\taMenu _ MenuMorph new defaultTarget: self.\\n\\taMenu addStayUpItem.\\n\\t(self hasProperty: #errorOnDraw) ifTrue:\\n\\t\\t[aMenu add: 'start drawing again' translated action: #resumeAfterDrawError.\\n\\t\\taMenu addLine].\\n\\t(self hasProperty: #errorOnStep) ifTrue:\\n\\t\\t[aMenu add: 'start stepping again' translated action: #resumeAfterStepError.\\n\\t\\taMenu addLine].\\n\\n\\taMenu add: 'inspect morph' translated action: #inspectInMorphic:.\\n\\taMenu add: 'inspect owner chain' translated action: #inspectOwnerChain.\\n\\tSmalltalk isMorphic ifFalse:\\n\\t\\t[aMenu add: 'inspect morph (in MVC)' translated action: #inspect].\\n\\n\\tself isMorphicModel ifTrue:\\n\\t\\t[aMenu add: 'inspect model' translated target: self model action: #inspect].\\n\\t(aPlayer _ self player) ifNotNil:\\n\\t\\t[aMenu add: 'inspect player' translated target: aPlayer action: #inspect].\\n\\n aMenu add: 'explore morph' translated target: self selector: #explore.\\n\\n\\taMenu addLine.\\n\\taPlayer ifNotNil:\\n\\t\\t[ aMenu add: 'viewer for Player' translated target: self player action: #beViewed.\\n\\taMenu balloonTextForLastItem: 'Opens a viewer on my Player -- this is the same thing you get if you click on the cyan \\\"View\\\" halo handle' translated ].\\n\\n\\taMenu add: 'viewer for Morph' translated target: self action: #viewMorphDirectly.\\n\\taMenu balloonTextForLastItem: 'Opens a Viewer on this Morph, rather than on its Player' translated.\\n\\taMenu addLine.\\n\\n\\taPlayer ifNotNil:\\n\\t\\t[aPlayer class isUniClass ifTrue: [\\n\\t\\t\\taMenu add: 'browse player class' translated target: aPlayer action: #browseHierarchy]].\\n\\taMenu add: 'browse morph class' translated target: self selector: #browseHierarchy.\\n\\t(self isMorphicModel)\\n\\t\\tifTrue: [aMenu\\n\\t\\t\\t\\tadd: 'browse model class'\\n\\t\\t\\t\\ttarget: self model\\n\\t\\t\\t\\tselector: #browseHierarchy].\\n\\taMenu addLine.\\n\\n\\taPlayer ifNotNil:\\n\\t\\t[aMenu add: 'player protocol (tiles)' translated target: aPlayer action: #openInstanceBrowserWithTiles\\n\\t\\t\\t\\\"#browseProtocolForPlayer\\\"].\\n\\taMenu add: 'morph protocol (text)' translated target: self selector: #haveFullProtocolBrowsed.\\n\\taMenu add: 'morph protocol (tiles)' translated target: self selector: #openInstanceBrowserWithTiles.\\n\\taMenu addLine.\\n\\n\\tself addViewingItemsTo: aMenu.\\n\\taMenu \\n\\t\\tadd: 'make own subclass' translated action: #subclassMorph;\\n\\t\\tadd: 'internal name ' translated action: #choosePartName;\\n\\t\\tadd: 'save morph in file' translated action: #saveOnFile;\\n\\t\\taddLine;\\n\\t\\tadd: 'call #tempCommand' translated action: #tempCommand;\\n\\t\\tadd: 'define #tempCommand' translated action: #defineTempCommand;\\n\\t\\taddLine;\\n\\n\\t\\tadd: 'control-menu...' translated target: self selector: #invokeMetaMenu:;\\n\\t\\tadd: 'edit balloon help' translated action: #editBalloonHelpText.\\n\\n\\t^ aMenu! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'ar 9/27/2005 20:29'!\\ndefineTempCommand\\n\\t\\\"To use this, comment out what's below here, and substitute your own code.\\nYou will then be able to invoke it from the standard debugging menus. If invoked from the world menu, you'll always get it invoked on behalf of the world, but if invoked from an individual morph's meta-menu, it will be invoked on behalf of that individual morph.\\n\\nNote that you can indeed reimplement tempCommand in an individual morph's class if you wish\\\"\\n\\n\\tToolSet browse: Morph\\n\\t\\tselector: #tempCommand! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 1/19/2001 07:51'!\\ndeleteAnyMouseActionIndicators\\n\\n\\tself changed.\\n\\t(self valueOfProperty: #mouseActionIndicatorMorphs ifAbsent: [#()]) do: [ :each |\\n\\t\\teach deleteWithSiblings\\t\\t\\\"one is probably enough, but be safe\\\"\\n\\t].\\n\\tself removeProperty: #mouseActionIndicatorMorphs.\\n\\tself hasRolloverBorder: false.\\n\\tself removeProperty: #rolloverWidth.\\n\\tself removeProperty: #rolloverColor.\\n\\tself layoutChanged.\\n\\tself changed.\\n\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'sw 7/17/2001 19:08'!\\nhandMeTilesToFire \\n\\t\\\"Construct a phrase of tiles comprising a line of code that will 'fire' this object, and hand it to the user\\\"\\n\\n\\tActiveHand attachMorph: (self assuredPlayer tilesToCall: MethodInterface firingInterface)! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'ar 10/5/2000 17:38'!\\ninspectArgumentsPlayerInMorphic: evt\\n\\tevt hand attachMorph: ((Inspector openAsMorphOn: self player) extent: 300@200)! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'sw 11/5/1998 20:31'!\\ninspectOwnerChain\\n\\tself ownerChain inspectWithLabel: 'Owner chain for ', self printString! !\\n\\n!Morph methodsFor: 'debug and other'!\\ninstallModelIn: ignored\\n\\t\\\"Simple morphs have no model\\\"\\n\\t\\\"See MorphicApp for other behavior\\\"! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'sw 2/6/2001 22:35'!\\nmouseUpCodeOrNil\\n\\t\\\"If the receiver has a mouseUpCodeToRun, return it, else return nil\\\"\\n\\n\\t^ self valueOfProperty: #mouseUpCodeToRun ifAbsent: [nil]! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'dgd 2/22/2003 19:05'!\\nownerChain\\n\\t\\\"Answer a list of objects representing the receiver and all of its owners. The first element is the receiver, and the last one is typically the world in which the receiver resides\\\"\\n\\n\\t| c next |\\n\\tc := OrderedCollection with: self.\\n\\tnext := self.\\n\\t[(next := next owner) notNil] whileTrue: [c add: next].\\n\\t^c asArray! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 7/12/2000 11:16'!\\nprogrammedMouseDown: anEvent for: aMorph\\n\\n\\taMorph addMouseActionIndicatorsWidth: 15 color: (Color blue alpha: 0.7).\\n\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 7/12/2000 11:16'!\\nprogrammedMouseEnter: anEvent for: aMorph\\n\\n\\taMorph addMouseActionIndicatorsWidth: 10 color: (Color blue alpha: 0.3).\\n\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 7/12/2000 11:10'!\\nprogrammedMouseLeave: anEvent for: aMorph\\n\\n\\tself deleteAnyMouseActionIndicators.\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'gm 2/22/2003 13:41'!\\nprogrammedMouseUp: anEvent for: aMorph \\n\\t| aCodeString |\\n\\tself deleteAnyMouseActionIndicators.\\n\\taCodeString := self valueOfProperty: #mouseUpCodeToRun ifAbsent: [^self].\\n\\t(self fullBounds containsPoint: anEvent cursorPoint) ifFalse: [^self].\\n\\t\\n\\t[(aCodeString isMessageSend) \\n\\t\\tifTrue: [aCodeString value]\\n\\t\\tifFalse: \\n\\t\\t\\t[Compiler \\n\\t\\t\\t\\tevaluate: aCodeString\\n\\t\\t\\t\\tfor: self\\n\\t\\t\\t\\tnotifying: nil\\n\\t\\t\\t\\tlogged: false]] \\n\\t\\t\\ton: ProgressTargetRequestNotification\\n\\t\\t\\tdo: [:ex | ex resume: self]\\t\\\"in case a save/load progress display needs a home\\\"! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 7/7/2000 16:43'!\\nremoveMouseUpAction\\n\\n\\tself primaryHand showTemporaryCursor: nil.\\n\\tself removeProperty: #mouseUpCodeToRun.\\n\\t#(mouseUp mouseEnter mouseLeave mouseDown) do: [ :sym |\\n\\t\\tself\\n\\t\\t\\ton: sym \\n\\t\\t\\tsend: #yourself \\n\\t\\t\\tto: nil.\\n\\t]\\n\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 5/24/2000 18:20'!\\nresumeAfterDrawError\\n\\n\\tself changed.\\n\\tself removeProperty:#errorOnDraw.\\n\\tself changed.! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'RAA 5/24/2000 18:20'!\\nresumeAfterStepError\\n\\t\\\"Resume stepping after an error has occured.\\\"\\n\\n\\tself startStepping. \\\"Will #step\\\"\\n\\tself removeProperty:#errorOnStep. \\\"Will remove prop only if #step was okay\\\"\\n! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'dgd 8/30/2003 20:43'!\\ntempCommand\\n\\t\\\"Generic backstop. If you care to, you can comment out what's below here, and substitute your own code, though the intention of design of the feature is that you leave this method as it is, and instead reimplement tempCommand in the class of whatever individual morph you care to. In any case, once you have your own #tempCommand in place, you will then be able to invoke it from the standard debugging menus.\\\"\\n\\n\\tself inform: 'Before calling tempCommand, you\\nshould first give it a definition. To\\ndo this, choose \\\"define tempCommand\\\"\\nfrom the debug menu.' translated! !\\n\\n!Morph methodsFor: 'debug and other' stamp: 'sw 8/4/2001 00:33'!\\nviewMorphDirectly\\n\\t\\\"Open a Viewer directly on the Receiver, i.e. no Player involved\\\"\\n\\n\\tself presenter viewObjectDirectly: self renderedMorph\\n\\n\\t! !\\n\\n\\n!Morph methodsFor: 'dispatching' stamp: 'nk 2/15/2004 09:16'!\\ndisableSubmorphFocusForHand: aHandMorph\\n\\t\\\"Check whether this morph or any of its submorph has the Genie focus.\\n\\tIf yes, disable it.\\\"\\n! !\\n\\n\\n!Morph methodsFor: 'drawing' stamp: 'di 6/24/1998 14:10'!\\nareasRemainingToFill: aRectangle\\n\\t\\\"May be overridden by any subclasses with opaque regions\\\"\\n\\n\\t^ Array with: aRectangle! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'sw 6/4/2000 22:02'!\\nboundingBoxOfSubmorphs\\n\\t| aBox |\\n\\taBox _ bounds origin extent: self minimumExtent. \\\"so won't end up with something empty\\\"\\n\\tsubmorphs do:\\n\\t\\t[:m | m visible ifTrue: [aBox _ aBox quickMerge: m fullBounds]].\\n\\t^ aBox\\n! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'di 2/15/2001 14:51'!\\nboundsWithinCorners\\n\\n\\t^ CornerRounder rectWithinCornersOf: self bounds! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 11/4/2000 23:39'!\\nchangeClipSubmorphs\\n\\tself clipSubmorphs: self clipSubmorphs not.! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'dgd 2/16/2003 20:02'!\\nclipLayoutCells\\n\\t\\\"Drawing/layout specific. If this property is set, clip the \\n\\tsubmorphs of the receiver by its cell bounds.\\\"\\n\\t^ self\\n\\t\\tvalueOfProperty: #clipLayoutCells\\n\\t\\tifAbsent: [false]! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 10/29/2000 19:22'!\\nclipLayoutCells: aBool\\n\\t\\\"Drawing/layout specific. If this property is set, clip the submorphs of the receiver by its cell bounds.\\\"\\n\\taBool == false\\n\\t\\tifTrue:[self removeProperty: #clipLayoutCells]\\n\\t\\tifFalse:[self setProperty: #clipLayoutCells toValue: aBool].\\n\\tself changed.! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 10/29/2000 19:16'!\\nclippingBounds\\n\\t\\\"Return the bounds to which any submorphs should be clipped if the property is set\\\"\\n\\t^self innerBounds! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'md 4/3/2006 11:53'!\\nclipSubmorphs\\n\\t\\\"Drawing specific. If this property is set, clip the receiver's \\n\\tsubmorphs to the receiver's clipping bounds.\\\"\\n\\t\\n\\textension ifNil: [^false].\\n\\t^ self\\n\\t\\tvalueOfProperty: #clipSubmorphs\\n\\t\\tifAbsent: [false]! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 11/12/2000 18:47'!\\nclipSubmorphs: aBool\\n\\t\\\"Drawing specific. If this property is set, clip the receiver's submorphs to the receiver's clipping bounds.\\\"\\n\\tself invalidRect: self fullBounds.\\n\\taBool == false\\n\\t\\tifTrue:[self removeProperty: #clipSubmorphs]\\n\\t\\tifFalse:[self setProperty: #clipSubmorphs toValue: aBool].\\n\\tself invalidRect: self fullBounds.! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'tk 8/2/1998 14:33'!\\ndoesOwnRotation\\n\\t\\\"Some morphs don't want to TransformMorph to rotate their images, but we do\\\"\\n\\t^ false! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'panda 4/28/2000 11:59'!\\ndrawDropHighlightOn: aCanvas\\n\\tself highlightedForDrop ifTrue: [\\n\\t\\taCanvas frameRectangle: self fullBounds color: self dropHighlightColor].! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 12/30/2001 19:17'!\\ndrawDropShadowOn: aCanvas\\n\\n\\taCanvas \\n\\t\\ttranslateBy: self shadowOffset \\n\\t\\tduring: [ :shadowCanvas |\\n\\t\\t\\tshadowCanvas shadowColor: self shadowColor.\\n\\t\\t\\tshadowCanvas roundCornersOf: self during: [ \\n\\t\\t\\t\\t(shadowCanvas isVisible: self bounds) ifTrue:[shadowCanvas drawMorph: self ]]\\n\\t\\t].\\n! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 4/2/1999 13:13'!\\ndrawErrorOn: aCanvas\\n\\t\\\"The morph (or one of its submorphs) had an error in its drawing method.\\\"\\n\\taCanvas\\n\\t\\tframeAndFillRectangle: bounds\\n\\t\\tfillColor: Color red\\n\\t\\tborderWidth: 1\\n\\t\\tborderColor: Color yellow.\\n\\taCanvas line: bounds topLeft to: bounds bottomRight width: 1 color: Color yellow.\\n\\taCanvas line: bounds topRight to: bounds bottomLeft width: 1 color: Color yellow.! !\\n\\n!Morph methodsFor: 'drawing' stamp: ' 9/3/2000 13:55'!\\ndrawMouseDownHighlightOn: aCanvas\\n\\tself highlightedForMouseDown ifTrue: [\\n\\t\\taCanvas frameRectangle: self fullBounds color: self color darker darker].! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 8/25/2001 17:31'!\\ndrawOn: aCanvas\\n\\n\\taCanvas fillRectangle: self bounds fillStyle: self fillStyle borderStyle: self borderStyle.\\n! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'wiz 3/21/2006 20:44'!\\ndrawRolloverBorderOn: aCanvas \\n\\t| colorToUse offsetToUse myShadow newForm f |\\n\\tcolorToUse := self\\n\\t\\t\\t\\tvalueOfProperty: #rolloverColor\\n\\t\\t\\t\\tifAbsent: [Color blue alpha: 0.5].\\n\\toffsetToUse := self\\n\\t\\t\\t\\tvalueOfProperty: #rolloverWidth\\n\\t\\t\\t\\tifAbsent: [10 @ 10].\\n\\tself hasRolloverBorder: false.\\n\\tmyShadow := self shadowForm.\\n\\tself hasRolloverBorder: true.\\n\\tmyShadow offset: 0 @ 0.\\n\\tf := ColorForm extent: myShadow extent depth: 1.\\n\\tmyShadow displayOn: f.\\n\\tf colors: {Color transparent. colorToUse}.\\n\\tnewForm := Form extent: offsetToUse * 2 + myShadow extent depth: 32.\\n\\t(WarpBlt current toForm: newForm) sourceForm: f;\\n\\t\\t cellSize: 1;\\n\\t\\t combinationRule: 3;\\n\\t\\t copyQuad: f boundingBox innerCorners toRect: newForm boundingBox.\\n\\taCanvas\\n\\t\\ttranslateBy: offsetToUse negated\\n\\t\\tduring: [:shadowCanvas | \\n\\t\\t\\tshadowCanvas shadowColor: colorToUse.\\n\\t\\t\\tshadowCanvas paintImage: newForm at: self position]! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'dgd 2/22/2003 14:31'!\\ndrawSubmorphsOn: aCanvas \\n\\t\\\"Display submorphs back to front\\\"\\n\\n\\t| drawBlock |\\n\\tsubmorphs isEmpty ifTrue: [^self].\\n\\tdrawBlock := [:canvas | submorphs reverseDo: [:m | canvas fullDrawMorph: m]].\\n\\tself clipSubmorphs \\n\\t\\tifTrue: [aCanvas clipBy: self clippingBounds during: drawBlock]\\n\\t\\tifFalse: [drawBlock value: aCanvas]! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'RAA 1/6/2001 22:12'!\\nexpandFullBoundsForDropShadow: aRectangle\\n\\t\\\"Return an expanded rectangle for an eventual drop shadow\\\"\\n\\t| delta box |\\n\\n\\tbox _ aRectangle.\\n\\tdelta _ self shadowOffset.\\n\\tbox _ delta x >= 0 \\n\\t\\tifTrue:[box right: aRectangle right + delta x]\\n\\t\\tifFalse:[box left: aRectangle left + delta x].\\n\\tbox _ delta y >= 0\\n\\t\\tifTrue:[box bottom: aRectangle bottom + delta y]\\n\\t\\tifFalse:[box top: aRectangle top + delta y].\\n\\t^box! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 11/8/2000 19:29'!\\nexpandFullBoundsForRolloverBorder: aRectangle\\n\\t| delta |\\n\\tdelta _ self valueOfProperty: #rolloverWidth ifAbsent: [10@10].\\n\\t^aRectangle expandBy: delta.\\n\\n! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'sw 11/26/2003 17:43'!\\nflashBounds\\n\\t\\\"Flash the receiver's bounds -- does not use the receiver's color, thus works with StringMorphs and SketchMorphs, etc., for which #flash is useless. No senders initially, but useful to send this from a debugger or inspector\\\"\\n\\n\\t5 timesRepeat:\\n\\t\\t[Display flash: self boundsInWorld andWait: 120]! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 12/30/2001 15:22'!\\nfullDrawOn: aCanvas\\n\\t\\\"Draw the full Morphic structure on the given Canvas\\\"\\n\\n\\tself visible ifFalse: [^ self].\\n\\t(aCanvas isVisible: self fullBounds) ifFalse:[^self].\\n\\t(self hasProperty: #errorOnDraw) ifTrue:[^self drawErrorOn: aCanvas].\\n\\t\\\"Note: At some point we should generalize this into some sort of \\n\\tmulti-canvas so that we can cross-optimize some drawing operations.\\\"\\n\\t\\\"Pass 1: Draw eventual drop-shadow\\\"\\n\\tself hasDropShadow ifTrue: [self drawDropShadowOn: aCanvas].\\n\\t(self hasRolloverBorder and: [(aCanvas seesNothingOutside: self bounds) not])\\n\\t\\tifTrue: [self drawRolloverBorderOn: aCanvas].\\n\\n\\t\\\"Pass 2: Draw receiver itself\\\"\\n\\taCanvas roundCornersOf: self during:[\\n\\t\\t(aCanvas isVisible: self bounds) ifTrue:[aCanvas drawMorph: self].\\n\\t\\tself drawSubmorphsOn: aCanvas.\\n\\t\\tself drawDropHighlightOn: aCanvas.\\n\\t\\tself drawMouseDownHighlightOn: aCanvas].! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'dgd 8/30/2003 20:20'!\\nhasClipSubmorphsString\\n\\t\\\"Answer a string that represents the clip-submophs checkbox\\\"\\n\\t^ (self clipSubmorphs\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'provide clipping' translated! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'sw 10/30/1998 18:27'!\\nhide\\n\\towner ifNil: [^ self].\\n\\tself visible ifTrue: [self visible: false. self changed]! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'LC 5/18/2000 08:48'!\\nhighlightedForMouseDown\\n\\t^(self valueOfProperty: #highlightedForMouseDown) == true! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'LC 5/18/2000 08:51'!\\nhighlightForMouseDown\\n\\tself highlightForMouseDown: true! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 3/17/2001 15:56'!\\nhighlightForMouseDown: aBoolean\\n\\taBoolean \\n\\t\\tifTrue:[self setProperty: #highlightedForMouseDown toValue: aBoolean]\\n\\t\\tifFalse:[self removeProperty: #highlightedForMouseDown. self resetExtension].\\n\\tself changed! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'jm 6/11/97 17:21'!\\nimageForm\\n\\n\\t^ self imageFormForRectangle: self fullBounds\\n! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'di 7/8/1998 12:42'!\\nimageFormDepth: depth\\n\\n\\t^ self imageForm: depth forRectangle: self fullBounds\\n! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'di 9/9/1998 22:25'!\\nimageFormForRectangle: rect\\n\\n\\t^ self imageForm: Display depth forRectangle: rect\\n! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 9/1/2000 14:23'!\\nimageFormWithout: stopMorph andStopThere: stopThere\\n\\t\\\"Like imageForm, except it does not display stopMorph,\\n\\tand it will not display anything above it if stopThere is true.\\n\\tReturns a pair of the imageForm and a boolean that is true\\n\\t\\tif it has hit stopMorph, and display should stop.\\\"\\n\\t| canvas rect |\\n\\trect _ self fullBounds.\\n\\tcanvas _ ColorPatchCanvas extent: rect extent depth: Display depth.\\n\\tcanvas stopMorph: stopMorph.\\n\\tcanvas doStop: stopThere.\\n\\tcanvas translateBy: rect topLeft negated during:[:tempCanvas| tempCanvas fullDrawMorph: self].\\n\\t^ Array with: (canvas form offset: rect topLeft)\\n\\t\\t\\twith: canvas foundMorph! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'nk 9/1/2004 15:08'!\\nimageForm: depth backgroundColor: aColor forRectangle: rect\\n\\t| canvas |\\n\\tcanvas _ Display defaultCanvasClass extent: rect extent depth: depth.\\n\\tcanvas translateBy: rect topLeft negated\\n\\t\\tduring:[:tempCanvas| \\n\\t\\t\\ttempCanvas fillRectangle: rect color: aColor.\\n\\t\\t\\ttempCanvas fullDrawMorph: self].\\n\\t^ canvas form offset: rect topLeft! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'ar 9/1/2000 14:23'!\\nimageForm: depth forRectangle: rect\\n\\t| canvas |\\n\\tcanvas _ Display defaultCanvasClass extent: rect extent depth: depth.\\n\\tcanvas translateBy: rect topLeft negated\\n\\t\\tduring:[:tempCanvas| tempCanvas fullDrawMorph: self].\\n\\t^ canvas form offset: rect topLeft! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'sw 10/10/1999 23:25'!\\nrefreshWorld\\n\\t| aWorld |\\n\\t(aWorld _ self world) ifNotNil: [aWorld displayWorldSafely]\\n! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'JW 7/12/2005 20:12'!\\nshadowForm\\n\\t\\\"Return a form representing the 'shadow' of the receiver - e.g., all pixels that are occupied by the receiver are one, all others are zero.\\\"\\n\\t| canvas |\\n\\tcanvas := (Display defaultCanvasClass extent: self fullBounds extent depth: 1)\\n\\t\\t\\t\\tasShadowDrawingCanvas: Color black. \\\"Color black represents one for 1bpp\\\"\\n\\tcanvas translateBy: bounds topLeft negated\\n\\t\\tduring:[:tempCanvas| tempCanvas fullDrawMorph: self].\\n\\t^ canvas form offset: bounds topLeft\\n! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'sw 10/22/1998 20:29'!\\nshow\\n\\t\\\"Make sure this morph is on-stage.\\\"\\n\\tself visible ifFalse: [self visible: true. self changed]! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'md 2/27/2006 08:49'!\\nvisible\\n\\t\\\"answer whether the receiver is visible\\\"\\n\\textension ifNil: [^ true].\\n\\t^ extension visible! !\\n\\n!Morph methodsFor: 'drawing' stamp: 'md 2/27/2006 08:49'!\\nvisible: aBoolean \\n\\t\\\"set the 'visible' attribute of the receiver to aBoolean\\\"\\n\\t(extension isNil and:[aBoolean]) ifTrue: [^ self].\\n\\tself visible == aBoolean ifTrue: [^ self].\\n\\tself assureExtension visible: aBoolean.\\n\\tself changed! !\\n\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'RAA 1/19/2001 07:51'!\\naddDropShadow\\n\\n\\tself hasDropShadow ifTrue:[^self].\\n\\tself changed.\\n\\tself hasDropShadow: true.\\n\\tself shadowOffset: 3@3.\\n\\tself layoutChanged.\\n\\tself changed.! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'dgd 8/30/2003 16:48'!\\naddDropShadowMenuItems: aMenu hand: aHand\\n\\t| menu |\\n\\tmenu _ MenuMorph new defaultTarget: self.\\n\\tmenu\\n\\t\\taddUpdating: #hasDropShadowString\\n\\t\\taction: #toggleDropShadow.\\n\\tmenu addLine.\\n\\tmenu add: 'shadow color...' translated target: self selector: #changeShadowColor.\\n\\tmenu add: 'shadow offset...' translated target: self selector: #setShadowOffset:.\\n\\taMenu add: 'drop shadow' translated subMenu: menu.! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 10/26/2000 20:22'!\\nchangeShadowColor\\n\\t\\\"Change the shadow color of the receiver -- triggered, e.g. from a menu\\\"\\n\\n\\tColorPickerMorph new\\n\\t\\tchoseModalityFromPreference;\\n\\t\\tsourceHand: self activeHand;\\n\\t\\ttarget: self;\\n\\t\\tselector: #shadowColor:;\\n\\t\\toriginalColor: self shadowColor;\\n\\t\\tputUpFor: self near: self fullBoundsInWorld! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'dgd 2/16/2003 21:42'!\\nhasDropShadow\\n\\t\\\"answer whether the receiver has DropShadow\\\"\\n\\t^ self\\n\\t\\tvalueOfProperty: #hasDropShadow\\n\\t\\tifAbsent: [false]! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'dgd 8/30/2003 16:49'!\\nhasDropShadowString\\n\\t^ (self hasDropShadow\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'show shadow' translated! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 10/26/2000 19:03'!\\nhasDropShadow: aBool\\n\\taBool\\n\\t\\tifTrue:[self setProperty: #hasDropShadow toValue: true]\\n\\t\\tifFalse:[self removeProperty: #hasDropShadow]! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'dgd 2/16/2003 21:58'!\\nhasRolloverBorder\\n\\t\\\"answer whether the receiver has RolloverBorder\\\"\\n\\t^ self\\n\\t\\tvalueOfProperty: #hasRolloverBorder\\n\\t\\tifAbsent: [false]! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'RAA 11/7/2000 15:54'!\\nhasRolloverBorder: aBool\\n\\taBool\\n\\t\\tifTrue:[self setProperty: #hasRolloverBorder toValue: true]\\n\\t\\tifFalse:[self removeProperty: #hasRolloverBorder]! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 11/12/2000 18:57'!\\nremoveDropShadow\\n\\tself hasDropShadow ifFalse:[^self].\\n\\tself changed.\\n\\tself hasDropShadow: false.\\n\\tfullBounds ifNotNil:[fullBounds _ self privateFullBounds].\\n\\tself changed.! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 10/26/2000 18:58'!\\nsetShadowOffset: evt\\n\\t| handle |\\n\\thandle _ HandleMorph new forEachPointDo:\\n\\t\\t[:newPoint | self shadowPoint: newPoint].\\n\\tevt hand attachMorph: handle.\\n\\thandle startStepping.\\n! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 10/26/2000 18:59'!\\nshadowColor\\n\\t^self valueOfProperty: #shadowColor ifAbsent:[Color black]! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 10/26/2000 20:22'!\\nshadowColor: aColor\\n\\tself shadowColor = aColor ifFalse:[self changed].\\n\\tself setProperty: #shadowColor toValue: aColor.! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 10/26/2000 18:57'!\\nshadowOffset\\n\\t\\\"Return the current shadow offset\\\"\\n\\t^self valueOfProperty: #shadowOffset ifAbsent:[0@0]! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 10/26/2000 19:00'!\\nshadowOffset: aPoint\\n\\t\\\"Set the current shadow offset\\\"\\n\\t(aPoint isNil or:[(aPoint x isZero) & (aPoint y isZero)])\\n\\t\\tifTrue:[self removeProperty: #shadowOffset]\\n\\t\\tifFalse:[self setProperty: #shadowOffset toValue: aPoint].! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 11/12/2000 18:58'!\\nshadowPoint: newPoint\\n\\tself changed.\\n\\tself shadowOffset: newPoint - self center // 5.\\n\\tfullBounds ifNotNil:[fullBounds _ self privateFullBounds].\\n\\tself changed.! !\\n\\n!Morph methodsFor: 'drop shadows' stamp: 'ar 10/26/2000 20:16'!\\ntoggleDropShadow\\n\\tself hasDropShadow\\n\\t\\tifTrue:[self removeDropShadow]\\n\\t\\tifFalse:[self addDropShadow].! !\\n\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/5/2000 20:00'!\\naboutToBeGrabbedBy: aHand\\n\\t\\\"The receiver is being grabbed by a hand.\\n\\tPerform necessary adjustments (if any) and return the actual morph\\n\\tthat should be added to the hand.\\\"\\n\\t| extentToHandToHand cmd |\\n\\tself formerOwner: owner.\\n\\tself formerPosition: self position.\\n\\tcmd _ self undoGrabCommand.\\n\\tcmd ifNotNil:[self setProperty: #undoGrabCommand toValue: cmd].\\n\\t(extentToHandToHand _ self valueOfProperty: #expandedExtent)\\n\\t\\t\\tifNotNil:\\n\\t\\t\\t\\t[self removeProperty: #expandedExtent.\\n\\t\\t\\t\\tself extent: extentToHandToHand].\\n\\t^self \\\"Grab me\\\"! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/25/2000 15:41'!\\ndisableDragNDrop\\n\\tself enableDragNDrop: false! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/25/2000 15:50'!\\ndragEnabled\\n\\t\\\"Get this morph's ability to add and remove morphs via drag-n-drop.\\\"\\n\\t^(self valueOfProperty: #dragEnabled) == true\\n! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/11/2000 18:18'!\\ndragEnabled: aBool\\n\\t^self enableDrag: aBool! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/11/2000 18:20'!\\ndragNDropEnabled\\n\\t\\\"Note: This method is only useful for dragEnabled == dropEnabled at all times\\\"\\n\\tself separateDragAndDrop.\\n\\t^self dragEnabled and:[self dropEnabled]! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/25/2000 18:36'!\\ndragSelectionColor\\n\\t^ Color magenta! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/25/2000 15:51'!\\ndropEnabled\\n\\t\\\"Get this morph's ability to add and remove morphs via drag-n-drop.\\\"\\n\\t^(self valueOfProperty: #dropEnabled) == true\\n! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/11/2000 18:18'!\\ndropEnabled: aBool\\n\\t^self enableDrop: aBool! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/28/2000 10:52'!\\ndropHighlightColor\\n\\t^ Color blue! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/25/2000 18:08'!\\ndropSuccessColor\\n\\t^ Color blue! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/25/2000 15:41'!\\nenableDragNDrop\\n\\tself enableDragNDrop: true! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/11/2000 18:21'!\\nenableDragNDrop: aBoolean\\n\\t\\\"Set both properties at once\\\"\\n\\tself separateDragAndDrop.\\n\\tself enableDrag: aBoolean.\\n\\tself enableDrop: aBoolean.! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/25/2000 15:50'!\\nenableDrag: aBoolean\\n\\tself setProperty: #dragEnabled toValue: aBoolean! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/25/2000 15:51'!\\nenableDrop: aBoolean\\n\\tself setProperty: #dropEnabled toValue: aBoolean! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/5/2000 18:13'!\\nformerOwner\\n\\t^self valueOfProperty: #formerOwner! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'dgd 2/22/2003 14:31'!\\nformerOwner: aMorphOrNil \\n\\taMorphOrNil isNil \\n\\t\\tifTrue: [self removeProperty: #formerOwner]\\n\\t\\tifFalse: [self setProperty: #formerOwner toValue: aMorphOrNil]! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/5/2000 18:13'!\\nformerPosition\\n\\t^self valueOfProperty: #formerPosition! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'dgd 2/22/2003 14:31'!\\nformerPosition: formerPosition \\n\\tformerPosition isNil \\n\\t\\tifTrue: [self removeProperty: #formerPosition]\\n\\t\\tifFalse: [self setProperty: #formerPosition toValue: formerPosition]! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/6/2000 15:13'!\\ngrabTransform\\n\\t\\\"Return the transform for the receiver which should be applied during grabbing\\\"\\n\\t^owner ifNil:[IdentityTransform new] ifNotNil:[owner grabTransform]! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/28/2000 10:53'!\\nhighlightedForDrop\\n\\t^(self valueOfProperty: #highlightedForDrop) == true! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/28/2000 11:51'!\\nhighlightForDrop\\n\\tself highlightForDrop: true! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/28/2000 12:01'!\\nhighlightForDrop: aBoolean\\n\\tself setProperty: #highlightedForDrop toValue: aBoolean.\\n\\tself changed! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'dgd 9/10/2004 13:42'!\\njustDroppedInto: aMorph event: anEvent\\n\\t\\\"This message is sent to a dropped morph after it has been dropped on -- and been accepted by -- a drop-sensitive morph\\\"\\n\\n\\t| aWindow partsBinCase cmd aStack |\\n\\t(self formerOwner notNil and: [self formerOwner ~~ aMorph])\\n\\t\\tifTrue: [self removeHalo].\\n\\tself formerOwner: nil.\\n\\tself formerPosition: nil.\\n\\tcmd _ self valueOfProperty: #undoGrabCommand.\\n\\tcmd ifNotNil:[aMorph rememberCommand: cmd.\\n\\t\\t\\t\\tself removeProperty: #undoGrabCommand].\\n\\t(partsBinCase _ aMorph isPartsBin) ifFalse:\\n\\t\\t[self isPartsDonor: false].\\n\\t(aWindow _ aMorph ownerThatIsA: SystemWindow) ifNotNil:\\n\\t\\t[aWindow isActive ifFalse:\\n\\t\\t\\t[aWindow activate]].\\n\\t(self isInWorld and: [partsBinCase not]) ifTrue:\\n\\t\\t[self world startSteppingSubmorphsOf: self].\\n\\t\\\"Note an unhappy inefficiency here: the startStepping... call will often have already been called in the sequence leading up to entry to this method, but unfortunately the isPartsDonor: call often will not have already happened, with the result that the startStepping... call will not have resulted in the startage of the steppage.\\\"\\n\\n\\t\\\"An object launched by certain parts-launcher mechanisms should end up fully visible...\\\"\\n\\t(self hasProperty: #beFullyVisibleAfterDrop) ifTrue:\\n\\t\\t[aMorph == ActiveWorld ifTrue:\\n\\t\\t\\t[self goHome].\\n\\t\\tself removeProperty: #beFullyVisibleAfterDrop].\\n\\n\\t(self holdsSeparateDataForEachInstance and: [(aStack _ self stack) notNil])\\n\\t\\tifTrue:\\n\\t\\t\\t[aStack reassessBackgroundShape]\\n! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 2/6/2001 22:12'!\\njustGrabbedFrom: formerOwner\\n\\t\\\"The receiver was just grabbed from its former owner and is now attached to the hand. By default, we pass this message on if we're a renderer.\\\"\\n\\t(self isRenderer and:[self hasSubmorphs]) \\n\\t\\tifTrue:[self firstSubmorph justGrabbedFrom: formerOwner].! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'sw 3/27/2001 11:52'!\\nnameForUndoWording\\n\\t\\\"Return wording appropriate to the receiver for use in an undo-related menu item (and perhaps elsewhere)\\\"\\n\\n\\t| aName |\\n\\taName _ self knownName ifNil: [self renderedMorph class name].\\n\\t^ aName truncateTo: 24! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'di 12/12/2000 14:35'!\\nrejectDropMorphEvent: evt\\n\\t\\\"The receiver has been rejected, and must be put back somewhere. There are three cases:\\n\\t(1) It remembers its former owner and position, and goes right back there\\n\\t(2) It remembers its former position only, in which case it was torn off from a parts bin, and the UI is that it floats back to its donor position and then vanishes.\\n\\t(3) Neither former owner nor position is remembered, in which case it is whisked to the Trash\\\"\\n\\n\\tself removeProperty: #undoGrabCommand.\\n\\t(self formerOwner notNil and: [self formerOwner isPartsBin not]) ifTrue:\\n\\t\\t[^ self slideBackToFormerSituation: evt].\\n\\n\\tself formerPosition ifNotNil: \\\"Position but no owner -- can just make it vanish\\\"\\n\\t\\t[^ self vanishAfterSlidingTo: self formerPosition event: evt].\\n\\t\\t\\n\\tself slideToTrash: evt! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'sw 1/11/1999 20:07'!\\nrepelsMorph: aMorph event: ev\\n\\t^ false! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/28/2000 12:02'!\\nresetHighlightForDrop\\n\\tself highlightForDrop: false! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/11/2000 18:24'!\\nseparateDragAndDrop\\n\\t\\\"Conversion only. Separate the old #dragNDropEnabled into #dragEnabled and #dropEnabled and remove the old property.\\\"\\n\\t| dnd |\\n\\t(self hasProperty: #dragNDropEnabled) ifFalse:[^self].\\n\\tdnd _ (self valueOfProperty: #dragNDropEnabled) == true.\\n\\tself dragEnabled: dnd.\\n\\tself dropEnabled: dnd.\\n\\tself removeProperty: #dragNDropEnabled.\\n! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 8/12/2003 23:35'!\\nslideBackToFormerSituation: evt \\n\\t| slideForm formerOwner formerPosition aWorld startPoint endPoint trans |\\n\\tformerOwner := self formerOwner.\\n\\tformerPosition := self formerPosition.\\n\\taWorld := evt hand world.\\n\\ttrans := formerOwner transformFromWorld.\\n\\tslideForm := trans isPureTranslation \\n\\t\\t\\t\\tifTrue: [self imageForm offset: 0 @ 0]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[((TransformationMorph new asFlexOf: self) transform: trans) imageForm \\n\\t\\t\\t\\t\\t\\toffset: 0 @ 0]. \\n\\tstartPoint := evt hand fullBounds origin.\\n\\tendPoint := trans localPointToGlobal: formerPosition.\\n\\towner removeMorph: self.\\n\\taWorld displayWorld.\\n\\tslideForm \\n\\t\\tslideFrom: startPoint\\n\\t\\tto: endPoint\\n\\t\\tnSteps: 12\\n\\t\\tdelay: 15.\\n\\tformerOwner addMorph: self.\\n\\tself position: formerPosition.\\n\\tself justDroppedInto: formerOwner event: evt! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'dgd 4/3/2006 14:12'!\\nslideToTrash: evt\\n\\t\\\"Perhaps slide the receiver across the screen to a trash can and make it disappear into it. In any case, remove the receiver from the screen.\\\"\\n\\n\\t| aForm trash startPoint endPoint morphToSlide |\\n\\t((self renderedMorph == Utilities scrapsBook) or: [self renderedMorph isKindOf: TrashCanMorph]) ifTrue:\\n\\t\\t[self dismissMorph. ^ self].\\n\\tPreferences slideDismissalsToTrash ifTrue:\\n\\t\\t[morphToSlide _ self representativeNoTallerThan: 200 norWiderThan: 200 thumbnailHeight: 100.\\n\\t\\taForm _ morphToSlide imageForm offset: (0@0).\\n\\t\\ttrash _ ActiveWorld\\n\\t\\t\\tfindDeepSubmorphThat:\\n\\t\\t\\t\\t[:aMorph | (aMorph isKindOf: TrashCanMorph) and:\\n\\t\\t\\t\\t\\t[aMorph topRendererOrSelf owner == ActiveWorld]]\\n\\t\\t\\tifAbsent:\\n\\t\\t\\t\\t[trash _ TrashCanMorph new.\\n\\t\\t\\t\\ttrash bottomLeft: ActiveWorld bottomLeft - (-10@10).\\n\\t\\t\\t\\ttrash openInWorld.\\n\\t\\t\\t\\ttrash].\\n\\t\\tendPoint _ trash fullBoundsInWorld center.\\n\\t\\tstartPoint _ self topRendererOrSelf fullBoundsInWorld center - (aForm extent // 2)].\\n\\tself dismissMorph.\\n\\tActiveWorld displayWorld.\\n\\tPreferences slideDismissalsToTrash ifTrue:\\n\\t\\t[aForm slideFrom: startPoint to: endPoint nSteps: 12 delay: 15].\\n\\tUtilities addToTrash: self! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'mir 1/4/2001 11:02'!\\nstartDrag: anItem with: anObject\\n\\tself currentHand attachMorph: anObject! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'panda 4/25/2000 15:46'!\\ntoggleDragNDrop\\n\\t\\\"Toggle this morph's ability to add and remove morphs via drag-n-drop.\\\"\\n\\n\\t\\tself enableDragNDrop: self dragNDropEnabled not.\\n! !\\n\\n!Morph methodsFor: 'dropping/grabbing'!\\ntransportedMorph\\n\\t^self! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'dgd 8/26/2003 21:44'!\\nundoGrabCommand\\n\\t\\\"Return an undo command for grabbing the receiver\\\"\\n\\n\\t| cmd |\\n\\towner ifNil:\\n\\t\\t[^ nil]. \\\"no owner - no undo\\\"\\n\\t^ (cmd _ Command new)\\n\\t\\tcmdWording: 'move ' translated, self nameForUndoWording;\\n\\t\\tundoTarget: self\\n\\t\\tselector: #undoMove:redo:owner:bounds:predecessor:\\n\\t\\targuments: {cmd. false. owner. self bounds. (owner morphPreceding: self)};\\n\\t\\tyourself! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'bf 1/5/2000 19:11'!\\nvanishAfterSlidingTo: aPosition event: evt\\n\\n\\t| aForm aWorld startPoint endPoint |\\n\\taForm _ self imageForm offset: 0@0.\\n\\taWorld _ self world.\\n\\tstartPoint _ evt hand fullBounds origin.\\n\\tself delete.\\n\\taWorld displayWorld.\\n\\tendPoint _ aPosition.\\n\\taForm slideFrom: startPoint to: endPoint nSteps: 12 delay: 15.\\n\\tPreferences soundsEnabled ifTrue: [TrashCanMorph playDeleteSound].\\n! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 10/11/2000 18:24'!\\nwantsDroppedMorph: aMorph event: evt\\n\\t\\\"Return true if the receiver wishes to accept the given morph, which is being dropped by a hand in response to the given event. Note that for a successful drop operation both parties need to agree. The symmetric check is done automatically via aMorph wantsToBeDroppedInto: self.\\\"\\n\\n\\t^self dropEnabled! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 9/18/2000 18:34'!\\nwantsToBeDroppedInto: aMorph\\n\\t\\\"Return true if it's okay to drop the receiver into aMorph. This check is symmetric to #wantsDroppedMorph:event: to give both parties a chance of figuring out whether they like each other.\\\"\\n\\t^true! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'ar 2/10/1999 05:44'!\\nwantsToBeOpenedInWorld\\n\\t\\\"Return true if the receiver wants to be put into the World directly,\\n\\trather than allowing the user to place it (e.g., prevent attaching me\\n\\tto the hand after choosing 'new morph' in the world menu)\\\"\\n\\t^false! !\\n\\n!Morph methodsFor: 'dropping/grabbing' stamp: 'sw 8/15/2000 16:58'!\\nwillingToBeDiscarded\\n\\t^ true! !\\n\\n\\n!Morph methodsFor: 'event handling' stamp: 'tk 9/6/2000 12:42'!\\nclick\\n\\t\\\"Pretend the user clicked on me.\\\"\\n\\n\\t(self handlesMouseDown: nil) ifTrue: [\\n\\t\\tself mouseDown: nil.\\n\\t\\tself mouseUp: nil].! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'LC 5/18/2000 09:54'!\\nclick: evt\\n\\t\\\"Handle a single-click event. This message is only sent to clients that request it by sending #waitForClicksOrDrag:event: to the initiating hand in their mouseDown: method. This default implementation does nothing.\\n\\tLC 2/14/2000 08:32 - added: EventHandler notification\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler click: evt fromMorph: self].! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'sw 3/8/1999 00:17'!\\ncursorPoint\\n\\t^ self currentHand lastEvent cursorPoint! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'jcg 10/2/2001 09:26'!\\ndoubleClickTimeout: evt\\n\\t\\\"Handle a double-click timeout event. This message is only sent to clients that request it by sending #waitForClicksOrDrag:event: to the initiating hand in their mouseDown: method. This default implementation does nothing.\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler doubleClickTimeout: evt fromMorph: self].! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'LC 5/18/2000 09:54'!\\ndoubleClick: evt\\n\\t\\\"Handle a double-click event. This message is only sent to clients that request it by sending #waitForClicksOrDrag:event: to the initiating hand in their mouseDown: method. This default implementation does nothing.\\n\\tLC 2/14/2000 08:32 - added: EventHandler notification\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler doubleClick: evt fromMorph: self].! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'ar 1/10/2001 21:28'!\\ndropFiles: anEvent\\n\\t\\\"Handle a number of files dropped from the OS\\\"\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'RAA 2/12/2001 15:26'!\\nfirstClickTimedOut: evt\\n\\t\\\"Useful for double-click candidates who want to know whether or not the click is a single or double. In this case, ignore the #click: and wait for either this or #doubleClick:\\\"\\n\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'nk 3/10/2004 19:48'!\\nhandlerForYellowButtonDown: anEvent \\n\\t\\\"Return the (prospective) handler for a mouse down event with the yellow button pressed.\\n\\tThe \\thandler is temporarily installed and can be used for morphs further \\n\\tdown the hierarchy to negotiate whether the inner or the outer \\n\\tmorph should finally handle the event.\\\"\\n\\n\\t(self hasYellowButtonMenu or: [ self handlesMouseDown: anEvent ])\\n\\t\\tifFalse: [ ^ nil].\\t\\\"Not interested.\\\"\\n\\n\\tanEvent handler\\n\\t\\tifNil: [^ self].\\t\\\"Nobody else was interested\\\"\\n\\n\\t\\\"Same priority but I am innermost.\\\"\\n\\t^ self mouseDownPriority >= anEvent handler mouseDownPriority\\n\\t\\tifFalse: [nil ]\\n\\t\\tifTrue: [self]! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'ar 10/28/2000 22:18'!\\nhandlesKeyboard: evt\\n\\t\\\"Return true if the receiver wishes to handle the given keyboard event\\\"\\n\\tself eventHandler ifNotNil: [^ self eventHandler handlesKeyboard: evt].\\n\\t^ false\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'nk 2/14/2004 18:42'!\\nhandlesMouseDown: evt\\n\\t\\\"Do I want to receive mouseDown events (mouseDown:, mouseMove:, mouseUp:)?\\\"\\n\\t\\\"NOTE: The default response is false, except if you have added sensitivity to mouseDown events using the on:send:to: mechanism. Subclasses that implement these messages directly should override this one to return true.\\\" \\n\\n\\tself eventHandler ifNotNil: [^ self eventHandler handlesMouseDown: evt].\\n\\t^ false! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'di 9/14/1998 07:31'!\\nhandlesMouseOverDragging: evt\\n\\t\\\"Return true if I want to receive mouseEnterDragging: and mouseLeaveDragging: when the hand drags something over me (button up or button down), or when the mouse button is down but there is no mouseDown recipient. The default response is false, except if you have added sensitivity to mouseEnterLaden: or mouseLeaveLaden:, using the on:send:to: mechanism.\\\"\\n\\t\\\"NOTE: If the hand state matters in these cases, it may be tested by constructs such as\\n\\t\\tevent anyButtonPressed\\n\\t\\tevent hand hasSubmorphs\\\"\\n\\n\\tself eventHandler ifNotNil: [^ self eventHandler handlesMouseOverDragging: evt].\\n\\t^ false! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'di 9/14/1998 07:31'!\\nhandlesMouseOver: evt\\n\\t\\\"Do I want to receive mouseEnter: and mouseLeave: when the button is up and the hand is empty? The default response is false, except if you have added sensitivity to mouseEnter: or mouseLeave:, using the on:send:to: mechanism.\\\" \\n\\n\\tself eventHandler ifNotNil: [^ self eventHandler handlesMouseOver: evt].\\n\\t^ false! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'ar 10/22/2000 17:06'!\\nhandlesMouseStillDown: evt\\n\\t\\\"Return true if the receiver wants to get repeated #mouseStillDown: messages between #mouseDown: and #mouseUp\\\"\\n\\tself eventHandler ifNotNil: [^ self eventHandler handlesMouseStillDown: evt].\\n\\t^ false\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'sw 4/2/98 14:16'!\\nhasFocus\\n\\t^ false! !\\n\\n!Morph methodsFor: 'event handling'!\\nkeyboardFocusChange: aBoolean\\n\\t\\\"The message is sent to a morph when its keyboard focus change. The given argument indicates that the receiver is gaining keyboard focus (versus losing) the keyboard focus. Morphs that accept keystrokes should change their appearance in some way when they are the current keyboard focus. This default implementation does nothing.\\\"! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'ar 9/14/2000 18:23'!\\nkeyDown: anEvent\\n\\t\\\"Handle a key down event. The default response is to do nothing.\\\"! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'tk 8/10/1998 16:05'!\\nkeyStroke: anEvent\\n\\t\\\"Handle a keystroke event. The default response is to let my eventHandler, if any, handle it.\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler keyStroke: anEvent fromMorph: self].\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'KTT 6/1/2004 11:41'!\\nkeyUp: anEvent\\n\\t\\\"Handle a key up event. The default response is to do nothing.\\\"! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'dgd 9/19/2004 13:14'!\\nmouseDown: evt \\n\\t\\\"Handle a mouse down event. The default response is to let my \\n\\teventHandler, if any, handle it.\\\"\\n\\tevt yellowButtonPressed\\n\\t\\tifTrue: [\\\"First check for option (menu) click\\\"\\n\\t\\t\\t^ self yellowButtonActivity: evt shiftPressed].\\n\\tself eventHandler\\n\\t\\tifNotNil: [self eventHandler mouseDown: evt fromMorph: self]\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'di 9/14/1998 07:33'!\\nmouseEnterDragging: evt\\n\\t\\\"Handle a mouseEnterDragging event, meaning the mouse just entered my bounds with a button pressed or laden with submorphs. The default response is to let my eventHandler, if any, handle it, or else to do nothing.\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[^ self eventHandler mouseEnterDragging: evt fromMorph: self].\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'tk 8/10/1998 16:00'!\\nmouseEnter: evt\\n\\t\\\"Handle a mouseEnter event, meaning the mouse just entered my bounds with no button pressed. The default response is to let my eventHandler, if any, handle it.\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler mouseEnter: evt fromMorph: self].\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'di 9/14/1998 07:38'!\\nmouseLeaveDragging: evt\\n\\t\\\"Handle a mouseLeaveLaden event, meaning the mouse just left my bounds with a button pressed or laden with submorphs. The default response is to let my eventHandler, if any, handle it; else to do nothing.\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler mouseLeaveDragging: evt fromMorph: self]! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'tk 8/10/1998 16:01'!\\nmouseLeave: evt\\n\\t\\\"Handle a mouseLeave event, meaning the mouse just left my bounds with no button pressed. The default response is to let my eventHandler, if any, handle it.\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler mouseLeave: evt fromMorph: self].\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'ar 10/25/2000 18:04'!\\nmouseMove: evt\\n\\t\\\"Handle a mouse move event. The default response is to let my eventHandler, if any, handle it.\\\"\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler mouseMove: evt fromMorph: self].\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'ar 10/25/2000 18:02'!\\nmouseStillDownThreshold\\n\\t\\\"Return the number of milliseconds after which mouseStillDown: should be sent\\\"\\n\\t^200! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'ar 10/22/2000 17:08'!\\nmouseStillDown: evt\\n\\t\\\"Handle a mouse move event. The default response is to let my eventHandler, if any, handle it.\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler mouseStillDown: evt fromMorph: self].\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'tk 8/10/1998 16:05'!\\nmouseUp: evt\\n\\t\\\"Handle a mouse up event. The default response is to let my eventHandler, if any, handle it.\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler mouseUp: evt fromMorph: self].\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'dgd 8/28/2004 18:20'!\\nmoveOrResizeFromKeystroke: anEvent \\n\\t\\\"move or resize the receiver based on a keystroke\\\"\\n\\t| dir | \\n\\n\\tanEvent keyValue = 28 ifTrue: [dir := -1 @ 0].\\n\\tanEvent keyValue = 29 ifTrue: [dir := 1 @ 0].\\n\\tanEvent keyValue = 30 ifTrue: [dir := 0 @ -1].\\n\\tanEvent keyValue = 31 ifTrue: [dir := 0 @ 1].\\n\\n\\tdir notNil\\n\\t\\tifTrue:[\\n\\t\\t\\tanEvent controlKeyPressed ifTrue: [dir := dir * 10].\\n\\n\\t\\t\\tanEvent shiftPressed\\n\\t\\t\\t\\tifTrue: [self extent: self extent + dir]\\n\\t\\t\\t\\tifFalse: [self position: self position + dir].\\n\\n\\t\\t\\t\\\"anEvent wasHandled: true.\\\"\\n\\t]\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'tk 8/10/1998 16:01'!\\non: eventName send: selector to: recipient\\n\\tself eventHandler ifNil: [self eventHandler: EventHandler new].\\n\\tself eventHandler on: eventName send: selector to: recipient! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'ar 3/18/2001 17:21'!\\non: eventName send: selector to: recipient withValue: value\\n\\t\\\"NOTE: selector must take 3 arguments, of which value will be the *** FIRST ***\\\"\\n\\n\\tself eventHandler ifNil: [self eventHandler: EventHandler new].\\n\\tself eventHandler on: eventName send: selector to: recipient withValue: value\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'fbs 1/7/2005 15:43'!\\npreferredKeyboardBounds\\n\\n\\t^ self bounds: self bounds in: World.\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'fbs 1/7/2005 15:42'!\\npreferredKeyboardPosition\\n\\n\\t^ (self bounds: self bounds in: World) topLeft.\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'tk 8/10/1998 16:02'!\\nremoveLink: actionCode\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler on: actionCode send: nil to: nil]! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'sw 11/16/1998 08:06'!\\nrestoreSuspendedEventHandler\\n\\t| savedHandler |\\n\\t(savedHandler _ self valueOfProperty: #suspendedEventHandler) ifNotNil:\\n\\t\\t[self eventHandler: savedHandler].\\n\\tsubmorphs do: [:m | m restoreSuspendedEventHandler]\\n! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'mir 5/23/2000 17:43'!\\nstartDrag: evt\\n\\t\\\"Handle a double-click event. This message is only sent to clients that request it by sending #waitForClicksOrDrag:event: to the initiating hand in their mouseDown: method. This default implementation does nothing.\\\"\\n\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler startDrag: evt fromMorph: self].! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'sw 11/16/1998 08:07'!\\nsuspendEventHandler\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self setProperty: #suspendedEventHandler toValue: self eventHandler.\\n\\t\\tself eventHandler: nil].\\n\\tsubmorphs do: [:m | m suspendEventHandler]. \\\"All those rectangles\\\"! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'dgd 8/28/2004 18:42'!\\ntabAmongFields\\n\\t^ Preferences tabAmongFields\\n\\t\\tor: [self hasProperty: #tabAmongFields] ! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'RAA 6/19/2000 07:13'!\\ntransformFromOutermostWorld\\n\\t\\\"Return a transform to map world coordinates into my local coordinates\\\"\\n\\n\\t\\\"self isWorldMorph ifTrue: [^ MorphicTransform identity].\\\"\\n\\t^ self transformFrom: self outermostWorldMorph! !\\n\\n!Morph methodsFor: 'event handling'!\\ntransformFromWorld\\n\\t\\\"Return a transform to map world coordinates into my local coordinates\\\"\\n\\n\\t^ self transformFrom: nil! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'dgd 2/22/2003 14:36'!\\ntransformFrom: uberMorph \\n\\t\\\"Return a transform to be used to map coordinates in a morph above me into my childrens coordinates, or vice-versa. This is used to support scrolling, scaling, and/or rotation. This default implementation just returns my owner's transform or the identity transform if my owner is nil. \\n\\tNote: This method cannot be used to map into the receiver's coordinate system!!\\\"\\n\\n\\t(self == uberMorph or: [owner isNil]) ifTrue: [^IdentityTransform new].\\n\\t^owner transformFrom: uberMorph! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'ar 1/10/2001 21:28'!\\nwantsDropFiles: anEvent\\n\\t\\\"Return true if the receiver wants files dropped from the OS.\\\"\\n\\t^false! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'di 9/14/2000 11:46'!\\nwantsEveryMouseMove\\n\\t\\\"Unless overridden, this method allows processing to skip mouse move events\\n\\twhen processing is lagging. No 'significant' event (down/up, etc) will be skipped.\\\"\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'sw 11/3/97 02:11'!\\nwantsKeyboardFocusFor: aSubmorph\\n\\t\\\"Answer whether a plain mouse click on aSubmorph, a text-edit-capable thing, should result in a text selection there\\\"\\n\\t^ false! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'sw 5/6/1998 12:54'!\\nwouldAcceptKeyboardFocus\\n\\t\\\"Answer whether a plain mouse click on the receiver should result in a text selection there\\\"\\n\\t^ false! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'sw 8/29/2000 14:57'!\\nwouldAcceptKeyboardFocusUponTab\\n\\t\\\"Answer whether the receiver is in the running as the new keyboard focus if the tab key were hit at a meta level. This provides the leverage for tabbing among fields of a card, for example.\\\"\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'event handling' stamp: 'dgd 7/28/2005 13:02'!\\nyellowButtonActivity: shiftState \\n\\t\\\"Find me or my outermost owner that has items to add to a \\n\\tyellow button menu. \\n\\tshiftState is true if the shift was pressed. \\n\\tOtherwise, build a menu that contains the contributions from \\n\\tmyself and my interested submorphs, \\n\\tand present it to the user.\\\"\\n\\t| menu |\\n\\tself isWorldMorph\\n\\t\\tifFalse: [| outerOwner | \\n\\t\\t\\touterOwner := self outermostOwnerWithYellowButtonMenu.\\n\\t\\t\\touterOwner\\n\\t\\t\\t\\tifNil: [^ self].\\n\\t\\t\\touterOwner == self\\n\\t\\t\\t\\tifFalse: [^ outerOwner yellowButtonActivity: shiftState]].\\n\\tmenu := self buildYellowButtonMenu: ActiveHand.\\n\\tmenu\\n\\t\\taddTitle: self externalName\\n\\t\\ticon: (self iconOrThumbnailOfSize: (Preferences tinyDisplay ifTrue: [16] ifFalse: [28])).\\n\\tmenu popUpInWorld: self currentWorld! !\\n\\n\\n!Morph methodsFor: 'events-accessing' stamp: 'rw 4/25/2002 07:18'!\\nactionMap\\n\\t\\\"Answer an action map\\\"\\n\\n\\t| actionMap |\\n\\tactionMap := self valueOfProperty: #actionMap.\\n\\tactionMap ifNil:\\n\\t\\t[actionMap _ self createActionMap].\\n\\t^ actionMap! !\\n\\n!Morph methodsFor: 'events-accessing' stamp: 'rw 4/25/2002 07:17'!\\nupdateableActionMap\\n\\t\\\"Answer an updateable action map, saving it in my #actionMap property\\\"\\n\\t\\n\\t| actionMap |\\n\\tactionMap := self valueOfProperty: #actionMap.\\n\\tactionMap ifNil:\\n\\t\\t[actionMap _ self createActionMap.\\n\\t\\tself setProperty: #actionMap toValue: actionMap].\\n\\t^ actionMap! !\\n\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/11/2000 16:35'!\\naddAlarm: aSelector after: delayTime\\n\\t\\\"Add an alarm (that is an action to be executed once) with the given set of parameters\\\"\\n\\t^self addAlarm: aSelector withArguments: #() after: delayTime! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/11/2000 16:35'!\\naddAlarm: aSelector at: scheduledTime\\n\\t\\\"Add an alarm (that is an action to be executed once) with the given set of parameters\\\"\\n\\t^self addAlarm: aSelector withArguments: #() at: scheduledTime! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/11/2000 16:35'!\\naddAlarm: aSelector withArguments: args after: delayTime\\n\\t\\\"Add an alarm (that is an action to be executed once) with the given set of parameters\\\"\\n\\t^self addAlarm: aSelector withArguments: args at: Time millisecondClockValue + delayTime! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/14/2000 12:15'!\\naddAlarm: aSelector withArguments: args at: scheduledTime\\n\\t\\\"Add an alarm (that is an action to be executed once) with the given set of parameters\\\"\\n\\t| scheduler |\\n\\tscheduler _ self alarmScheduler.\\n\\tscheduler ifNotNil:[scheduler addAlarm: aSelector withArguments: args for: self at: scheduledTime].! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/11/2000 16:35'!\\naddAlarm: aSelector with: arg1 after: delayTime\\n\\t\\\"Add an alarm (that is an action to be executed once) with the given set of parameters\\\"\\n\\t^self addAlarm: aSelector withArguments: (Array with: arg1) after: delayTime! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/11/2000 16:35'!\\naddAlarm: aSelector with: arg1 at: scheduledTime\\n\\t\\\"Add an alarm (that is an action to be executed once) with the given set of parameters\\\"\\n\\t^self addAlarm: aSelector withArguments: (Array with: arg1) at: scheduledTime! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/11/2000 16:35'!\\naddAlarm: aSelector with: arg1 with: arg2 after: delayTime\\n\\t\\\"Add an alarm (that is an action to be executed once) with the given set of parameters\\\"\\n\\t^self addAlarm: aSelector withArguments: (Array with: arg1 with: arg2) after: delayTime! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/11/2000 16:35'!\\naddAlarm: aSelector with: arg1 with: arg2 at: scheduledTime\\n\\t\\\"Add an alarm (that is an action to be executed once) with the given set of parameters\\\"\\n\\t^self addAlarm: aSelector withArguments: (Array with: arg1 with: arg2) at: scheduledTime! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/11/2000 16:34'!\\nalarmScheduler\\n\\t\\\"Return the scheduler being responsible for triggering alarms\\\"\\n\\t^self world! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/14/2000 12:14'!\\nremoveAlarm: aSelector\\n\\t\\\"Remove the given alarm\\\"\\n\\t| scheduler |\\n\\tscheduler _ self alarmScheduler.\\n\\tscheduler ifNotNil:[scheduler removeAlarm: aSelector for: self].! !\\n\\n!Morph methodsFor: 'events-alarms' stamp: 'ar 9/14/2000 12:15'!\\nremoveAlarm: aSelector at: scheduledTime\\n\\t\\\"Remove the given alarm\\\"\\n\\t| scheduler |\\n\\tscheduler _ self alarmScheduler.\\n\\tscheduler ifNotNil:[scheduler removeAlarm: aSelector at: scheduledTime for: self].! !\\n\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/13/2000 17:58'!\\ncontainsPoint: aPoint event: anEvent\\n\\t\\\"Return true if aPoint is considered to be inside the receiver for the given event.\\n\\tThe default implementation treats locked children as integral part of their owners.\\\"\\n\\t(self fullBounds containsPoint: aPoint) ifFalse:[^false].\\n\\t(self containsPoint: aPoint) ifTrue:[^true].\\n\\tself submorphsDo:[:m|\\n\\t\\t(m isLocked and:[m fullContainsPoint: \\n\\t\\t\\t((m transformedFrom: self) globalPointToLocal: aPoint)]) ifTrue:[^true]].\\n\\t^false! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/13/2000 14:51'!\\ndefaultEventDispatcher\\n\\t\\\"Return the default event dispatcher to use with events that are directly sent to the receiver\\\"\\n\\t^MorphicEventDispatcher new! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 1/10/2001 21:35'!\\nhandleDropFiles: anEvent\\n\\t\\\"Handle a drop from the OS.\\\"\\n\\tanEvent wasHandled ifTrue:[^self]. \\\"not interested\\\"\\n\\t(self wantsDropFiles: anEvent) ifFalse:[^self].\\n\\tanEvent wasHandled: true.\\n\\tself dropFiles: anEvent.\\n! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'di 12/12/2000 14:39'!\\nhandleDropMorph: anEvent\\n\\t\\\"Handle a dropping morph.\\\"\\n\\t| aMorph localPt |\\n\\taMorph _ anEvent contents.\\n\\t\\\"Do a symmetric check if both morphs like each other\\\"\\n\\t((self wantsDroppedMorph: aMorph event: anEvent)\\t\\\"I want her\\\"\\n\\t\\tand: [aMorph wantsToBeDroppedInto: self])\\t\\t\\\"she wants me\\\"\\n\\t\\tifFalse: [aMorph removeProperty: #undoGrabCommand.\\n\\t\\t\\t\\t^ self].\\n\\tanEvent wasHandled: true.\\n\\t\\\"Transform the morph into the receiver's coordinate frame. This is currently incomplete since it only takes the offset into account where it really should take the entire transform.\\\"\\n\\tlocalPt _ (self transformedFrom: anEvent hand world) \\\"full transform down\\\"\\n\\t\\t\\t\\tglobalPointToLocal: aMorph referencePosition.\\n\\taMorph referencePosition: localPt.\\n\\tself acceptDroppingMorph: aMorph event: anEvent.\\n\\taMorph justDroppedInto: self event: anEvent.\\n! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/15/2000 21:13'!\\nhandleEvent: anEvent\\n\\t\\\"Handle the given event\\\"\\n\\t^anEvent sentTo: self.! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 10/4/2000 18:48'!\\nhandleFocusEvent: anEvent\\n\\t\\\"Handle the given event. This message is sent if the receiver currently has the focus and is therefore receiving events directly from some hand.\\\"\\n\\t^self handleEvent: anEvent! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/15/2000 23:01'!\\nhandleKeyDown: anEvent\\n\\t\\\"System level event handling.\\\"\\n\\tanEvent wasHandled ifTrue:[^self].\\n\\t(self handlesKeyboard: anEvent) ifFalse:[^self].\\n\\tanEvent wasHandled: true.\\n\\t^self keyDown: anEvent! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/15/2000 23:01'!\\nhandleKeyUp: anEvent\\n\\t\\\"System level event handling.\\\"\\n\\tanEvent wasHandled ifTrue:[^self].\\n\\t(self handlesKeyboard: anEvent) ifFalse:[^self].\\n\\tanEvent wasHandled: true.\\n\\t^self keyUp: anEvent! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'md 8/2/2006 18:57'!\\nhandleKeystroke: anEvent \\n\\t\\\"System level event handling.\\\"\\n\\t\\n\\tanEvent wasHandled\\n\\t\\tifTrue: [^ self].\\n\\t(self handlesKeyboard: anEvent)\\n\\t\\tifFalse: [^ self].\\n\\tanEvent wasHandled: true.\\n\\t^ self keyStroke: anEvent! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/16/2000 14:22'!\\nhandleListenEvent: anEvent\\n\\t\\\"Handle the given event. This message is sent if the receiver is a registered listener for the given event.\\\"\\n\\t^anEvent sentTo: self.! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'dgd 9/10/2004 13:36'!\\nhandleMouseDown: anEvent\\n\\t\\\"System level event handling.\\\"\\n\\tanEvent wasHandled ifTrue:[^self]. \\\"not interested\\\"\\n\\tanEvent hand removePendingBalloonFor: self.\\n\\tanEvent hand removePendingHaloFor: self.\\n\\tanEvent wasHandled: true.\\n\\n\\t(anEvent controlKeyPressed\\n\\t\\t\\tand: [Preferences cmdGesturesEnabled])\\n\\t\\tifTrue: [^ self invokeMetaMenu: anEvent].\\n\\n\\t\\\"Make me modal during mouse transitions\\\"\\n\\tanEvent hand newMouseFocus: self event: anEvent.\\n\\tanEvent blueButtonChanged ifTrue:[^self blueButtonDown: anEvent].\\n\\t\\n\\t\\\"this mouse down could be the start of a gesture, or the end of a gesture focus\\\"\\n\\t(self isGestureStart: anEvent)\\n\\t\\tifTrue: [^ self gestureStart: anEvent].\\n\\n\\tself mouseDown: anEvent.\\n\\n\\tPreferences maintainHalos\\n\\t\\tifFalse:[ anEvent hand removeHaloFromClick: anEvent on: self ].\\n\\n\\t(self handlesMouseStillDown: anEvent) ifTrue:[\\n\\t\\tself startStepping: #handleMouseStillDown: \\n\\t\\t\\tat: Time millisecondClockValue + self mouseStillDownThreshold\\n\\t\\t\\targuments: {anEvent copy resetHandlerFields}\\n\\t\\t\\tstepTime: self mouseStillDownStepRate ].\\n! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 8/8/2001 15:29'!\\nhandleMouseEnter: anEvent\\n\\t\\\"System level event handling.\\\"\\n\\t(anEvent isDraggingEvent) ifTrue:[\\n\\t\\t(self handlesMouseOverDragging: anEvent) ifTrue:[\\n\\t\\t\\tanEvent wasHandled: true.\\n\\t\\t\\tself mouseEnterDragging: anEvent].\\n\\t\\t^self].\\n\\tself wantsHalo \\\"If receiver wants halo and balloon, trigger balloon after halo\\\"\\n\\t\\tifTrue:[anEvent hand triggerHaloFor: self after: self haloDelayTime]\\n\\t\\tifFalse:[self wantsBalloon\\n\\t\\t\\tifTrue:[anEvent hand triggerBalloonFor: self after: self balloonHelpDelayTime]].\\n\\t(self handlesMouseOver: anEvent) ifTrue:[\\n\\t\\tanEvent wasHandled: true.\\n\\t\\tself mouseEnter: anEvent.\\n\\t].! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 10/6/2000 00:15'!\\nhandleMouseLeave: anEvent\\n\\t\\\"System level event handling.\\\"\\n\\tanEvent hand removePendingBalloonFor: self.\\n\\tanEvent hand removePendingHaloFor: self.\\n\\tanEvent isDraggingEvent ifTrue:[\\n\\t\\t(self handlesMouseOverDragging: anEvent) ifTrue:[\\n\\t\\t\\tanEvent wasHandled: true.\\n\\t\\t\\tself mouseLeaveDragging: anEvent].\\n\\t\\t^self].\\n\\t(self handlesMouseOver: anEvent) ifTrue:[\\n\\t\\tanEvent wasHandled: true.\\n\\t\\tself mouseLeave: anEvent.\\n\\t].\\n! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'nk 6/13/2004 09:16'!\\nhandleMouseMove: anEvent\\n\\t\\\"System level event handling.\\\"\\n\\tanEvent wasHandled ifTrue:[^self]. \\\"not interested\\\"\\n\\t\\\"Rules say that by default a morph gets #mouseMove iff\\n\\t\\t* the hand is not dragging anything,\\n\\t\\t\\t+ and some button is down,\\n\\t\\t\\t+ and the receiver is the current mouse focus.\\\"\\n\\t(anEvent hand hasSubmorphs) ifTrue:[^self].\\n\\t(anEvent anyButtonPressed and:[anEvent hand mouseFocus == self]) ifFalse:[^self].\\n\\tanEvent wasHandled: true.\\n\\tself mouseMove: anEvent.\\n\\t(self handlesMouseStillDown: anEvent) ifTrue:[\\n\\t\\t\\\"Step at the new location\\\"\\n\\t\\tself startStepping: #handleMouseStillDown: \\n\\t\\t\\tat: Time millisecondClockValue\\n\\t\\t\\targuments: {anEvent copy resetHandlerFields}\\n\\t\\t\\tstepTime: self mouseStillDownStepRate ].\\n! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 4/23/2001 17:24'!\\nhandleMouseOver: anEvent\\n\\t\\\"System level event handling.\\\"\\n\\tanEvent hand mouseFocus == self ifTrue:[\\n\\t\\t\\\"Got this directly through #handleFocusEvent: so check explicitly\\\"\\n\\t\\t(self containsPoint: anEvent position event: anEvent) ifFalse:[^self]].\\n\\tanEvent hand noticeMouseOver: self event: anEvent! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 10/22/2000 17:11'!\\nhandleMouseStillDown: anEvent\\n\\t\\\"Called from the stepping mechanism for morphs wanting continuously repeated 'yes the mouse is still down, yes it is still down, yes it has not changed yet, no the mouse is still not up, yes the button is down' etc messages\\\"\\n\\t(anEvent hand mouseFocus == self) \\n\\t\\tifFalse:[^self stopSteppingSelector: #handleMouseStillDown:].\\n\\tself mouseStillDown: anEvent.\\n! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 10/22/2000 17:09'!\\nhandleMouseUp: anEvent\\n\\t\\\"System level event handling.\\\"\\n\\tanEvent wasHandled ifTrue:[^self]. \\\"not interested\\\"\\n\\tanEvent hand mouseFocus == self ifFalse:[^self]. \\\"Not interested in other parties\\\"\\n\\tanEvent hand releaseMouseFocus: self.\\n\\tanEvent wasHandled: true.\\n\\tanEvent blueButtonChanged\\n\\t\\tifTrue:[self blueButtonUp: anEvent]\\n\\t\\tifFalse:[self mouseUp: anEvent.\\n\\t\\t\\t\\tself stopSteppingSelector: #handleMouseStillDown:].! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'md 10/22/2003 15:55'!\\nhandleUnknownEvent: anEvent\\n\\t\\\"An event of an unknown type was sent to the receiver. What shall we do?!!\\\"\\n\\tBeeper beep. \\n\\tanEvent printString displayAt: 0@0.\\n\\tanEvent wasHandled: true.! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'sw 10/5/2002 01:47'!\\nmouseDownPriority\\n\\t\\\"Return the default mouse down priority for the receiver\\\"\\n\\n\\t^ (self isPartsDonor or: [self isPartsBin])\\n\\t\\tifTrue:\\t[50]\\n\\t\\tifFalse:\\t[0]\\n\\n\\t\\\"The above is a workaround for the complete confusion between parts donors and parts bins. Morphs residing in a parts bin may or may not have the parts donor property set; if they have they may or may not actually handle events. To work around this, parts bins get an equal priority to parts donors so that when a morph in the parts bin does have the property set but does not handle the event we still get a copy from picking it up through the parts bin. Argh. This just *cries* for a cleanup.\\\"\\n\\t\\\"And the above comment is Andreas's from 10/2000, which was formerly retrievable by a #flag: call which however caused a problem when trying to recompile the method from decompiled source.\\\"! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/13/2000 17:14'!\\nprocessEvent: anEvent\\n\\t\\\"Process the given event using the default event dispatcher.\\\"\\n\\t^self processEvent: anEvent using: self defaultEventDispatcher! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/18/2000 19:14'!\\nprocessEvent: anEvent using: defaultDispatcher\\n\\t\\\"This is the central entry for dispatching events in morphic. Given some event and a default dispatch strategy, find the right receiver and let him handle it.\\n\\tWARNING: This is a powerful hook. If you want to use a different event dispatcher from the default, here is the place to hook it in. Depending on how the dispatcher is written (e.g., whether it calls simply #processEvent: or #processEvent:using:) you can change the dispatch strategy for entire trees of morphs. Similarly, you can disable entire trees of morphs from receiving any events whatsoever. Read the documentation in class MorphicEventDispatcher before playing with it. \\\"\\n\\t(self rejectsEvent: anEvent) ifTrue:[^#rejected].\\n\\t^defaultDispatcher dispatchEvent: anEvent with: self! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 10/5/2000 19:25'!\\nrejectDropEvent: anEvent\\n\\t\\\"This hook allows the receiver to repel a drop operation currently executed. The method is called prior to checking children so the receiver must validate that the event was really designated for it.\\n\\tNote that the ordering of the tests below is designed to avoid a (possibly expensive) #fullContainsPoint: test. If the receiver doesn't want to repel the morph anyways we don't need to check after all.\\\"\\n\\t(self repelsMorph: anEvent contents event: anEvent) ifFalse:[^self]. \\\"not repelled\\\"\\n\\t(self fullContainsPoint: anEvent position) ifFalse:[^self]. \\\"not for me\\\"\\n\\t\\\"Throw it away\\\"\\n\\tanEvent wasHandled: true.\\n\\tanEvent contents rejectDropMorphEvent: anEvent.! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/12/2000 23:40'!\\nrejectsEvent: anEvent\\n\\t\\\"Return true to reject the given event. Rejecting an event means neither the receiver nor any of it's submorphs will be given any chance to handle it.\\\"\\n\\t^self isLocked or:[self visible not]! !\\n\\n!Morph methodsFor: 'events-processing' stamp: 'ar 9/15/2000 21:09'!\\ntransformedFrom: uberMorph\\n\\t\\\"Return a transform to map coordinates of uberMorph, a morph above me in my owner chain, into the coordinates of MYSELF not any of my children.\\\"\\n\\tself flag: #arNote. \\\"rename this method\\\"\\n\\towner ifNil:[^IdentityTransform new].\\n\\t^ (owner transformFrom: uberMorph)! !\\n\\n\\n!Morph methodsFor: 'events-removing' stamp: 'rw 4/25/2002 07:18'!\\nreleaseActionMap\\n\\t\\\"Release the action map\\\"\\n\\t\\n \\tself removeProperty: #actionMap! !\\n\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'di 11/18/1999 08:35'!\\nattachToResource\\n\\t\\\"Produce a morph from a file -- either a saved .morph file or a graphics file\\\"\\n\\n\\t| pathName |\\n\\tpathName _ Utilities chooseFileWithSuffixFromList: (#('.morph'), Utilities graphicsFileSuffixes)\\n\\t\\t\\twithCaption: 'Choose a file\\nto load'.\\n\\tpathName ifNil: [^ self]. \\\"User made no choice\\\"\\n\\tpathName == #none ifTrue: [^ self inform: \\n'Sorry, no suitable files found\\n(names should end with .morph, .gif,\\n.bmp, .jpeg, .jpe, .jp, or .form)'].\\n\\n\\tself setProperty: #resourceFilePath toValue: pathName! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'tak 2/10/2006 02:24'!\\nprepareToBeSaved\\n\\t\\\"Prepare this morph to be saved to disk. Subclasses should nil out any instance variables that holds state that should not be saved, such as cached Forms. Note that this operation may take more drastic measures than releaseCachedState; for example, it might discard the transcript of an interactive chat session.\\\"\\n\\n\\tself releaseCachedState.\\n\\tself formerOwner: nil.\\n\\tself formerPosition: nil.\\n\\tself removeProperty: #undoGrabCommand.\\n\\tfullBounds _ nil! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'tk 2/17/1999 17:50'!\\nreserveUrl: urlString\\n\\t\\\"Write a dummy object to the server to hold a name and place for this object.\\\"\\n\\n\\t| dummy ext str |\\n\\tdummy _ PasteUpMorph new.\\n\\tdummy borderWidth: 2.\\n\\tdummy setProperty: #initialExtent toValue: (ext _ 300@100).\\n\\tdummy topLeft: 50@50; extent: ext.\\t\\\"reset when comes in\\\"\\n\\tstr _ (TextMorph new) topLeft: dummy topLeft + (10@10); \\n\\t\\textent: dummy width - 15 @ 30.\\n\\tdummy addMorph: str.\\n\\tstr contents: 'This is a place holder only. Please \\\\find the original page and choose \\\\\\\"send this page to server\\\"' withCRs.\\n\\tstr extent: dummy width - 15 @ 30.\\n\\tdummy saveOnURL: urlString.\\n\\n\\t\\\"Claim that url myself\\\"\\n\\tself setProperty: #SqueakPage toValue: dummy sqkPage.\\n\\t(dummy sqkPage) contentsMorph: self; dirty: true.\\n\\t^ self url! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'di 11/18/1999 08:52'!\\nsaveAsResource\\n\\n\\t| pathName |\\n\\t(self hasProperty: #resourceFilePath) ifFalse: [^ self].\\n\\tpathName _ self valueOfProperty: #resourceFilePath.\\n\\t(pathName asLowercase endsWith: '.morph') ifFalse:\\n\\t\\t[^ self error: 'Can only update morphic resources'].\\n\\t(FileStream newFileNamed: pathName) fileOutClass: nil andObject: self.! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'ar 9/27/2005 21:02'!\\nsaveDocPane\\n\\n\\tSmalltalk at: #DocLibrary ifPresent:[:dl| dl external saveDocCheck: self]! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'yo 7/2/2004 13:14'!\\nsaveOnFile\\n\\t\\\"Ask the user for a filename and save myself on a SmartReferenceStream file. Writes out the version and class structure. The file is fileIn-able. UniClasses will be filed out.\\\"\\n\\n\\t| aFileName fileStream ok |\\n\\taFileName _ ('my {1}' translated format: {self class name}) asFileName.\\t\\\"do better?\\\"\\n\\taFileName _ FillInTheBlank request: 'File name? (\\\".morph\\\" will be added to end)' translated \\n\\t\\t\\tinitialAnswer: aFileName.\\n\\taFileName isEmpty ifTrue: [^ Beeper beep].\\n\\tself allMorphsDo: [:m | m prepareToBeSaved].\\n\\n\\tok _ aFileName endsWith: '.morph'.\\t\\\"don't double them\\\"\\n\\tok _ ok | (aFileName endsWith: '.sp').\\n\\tok ifFalse: [aFileName _ aFileName,'.morph'].\\n\\tfileStream _ FileStream newFileNamed: aFileName asFileName.\\n\\tfileStream fileOutClass: nil andObject: self.\\t\\\"Puts UniClass definitions out anyway\\\"! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'tk 7/16/1999 13:03'!\\nsaveOnURL\\n\\t\\\"Ask the user for a url and save myself on a SmartReferenceStream file. Writes out the version and class structure. The file is fileIn-able. UniClasses will be filed out.\\\"\\n\\n\\t| um pg |\\n\\t(pg _ self saveOnURLbasic) == #cancel ifTrue: [^ self].\\n\\tum _ URLMorph newForURL: pg url.\\n\\tum setURL: pg url page: pg.\\n\\tpg isContentsInMemory ifTrue: [pg computeThumbnail].\\n\\tum isBookmark: true.\\n\\tum removeAllMorphs.\\n\\tum color: Color transparent.\\n\\tself primaryHand attachMorph: um.! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'dgd 2/22/2003 14:35'!\\nsaveOnURLbasic\\n\\t\\\"Ask the user for a url and save myself on a SmartReferenceStream file. Writes out the version and class structure. The file is fileIn-able. UniClasses will be filed out.\\\"\\n\\n\\t| url pg stamp pol |\\n\\t(pg := self valueOfProperty: #SqueakPage) ifNil: [pg := SqueakPage new]\\n\\t\\tifNotNil: \\n\\t\\t\\t[pg contentsMorph ~~ self \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[self inform: 'morph''s SqueakPage property is out of date'.\\n\\t\\t\\t\\t\\tpg := SqueakPage new]].\\n\\t(url := pg url) ifNil: \\n\\t\\t\\t[url := ServerDirectory defaultStemUrl , '1.sp'.\\t\\\"A new legal place\\\"\\n\\t\\t\\turl := FillInTheBlank \\n\\t\\t\\t\\t\\t\\trequest: 'url of a place to store this object.\\nMust begin with file:// or ftp://'\\n\\t\\t\\t\\t\\t\\tinitialAnswer: url.\\n\\t\\t\\turl isEmpty ifTrue: [^#cancel]].\\n\\tstamp := Utilities authorInitialsPerSe ifNil: ['*'].\\n\\tpg saveMorph: self author: stamp.\\n\\tSqueakPageCache atURL: url put: pg.\\t\\\"setProperty: #SqueakPage\\\"\\n\\t(pol := pg policy) ifNil: [pol := #neverWrite].\\n\\tpg\\n\\t\\tpolicy: #now;\\n\\t\\tdirty: true.\\n\\tpg write.\\t\\\"force the write\\\"\\n\\tpg policy: pol.\\n\\t^pg! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'tk 11/20/1998 11:47'!\\nsaveOnURL: suggestedUrlString\\n\\t\\\"Save myself on a SmartReferenceStream file. If I don't already have a url, use the suggested one. Writes out the version and class structure. The file is fileIn-able. UniClasses will be filed out.\\\"\\n\\n\\t| url pg stamp pol |\\n\\t(pg _ self valueOfProperty: #SqueakPage) ifNil: [pg _ SqueakPage new]\\n\\t\\tifNotNil: [pg contentsMorph ~~ self ifTrue: [\\n\\t\\t\\t\\tself inform: 'morph''s SqueakPage property is out of date'.\\n\\t\\t\\t\\tpg _ SqueakPage new]].\\n\\t(url _ pg url) ifNil: [url _ pg urlNoOverwrite: suggestedUrlString].\\n\\tstamp _ Utilities authorInitialsPerSe ifNil: ['*'].\\n\\tpg saveMorph: self author: stamp.\\n\\tSqueakPageCache atURL: url put: pg.\\t\\\"setProperty: #SqueakPage\\\"\\n\\t(pol _ pg policy) ifNil: [pol _ #neverWrite].\\n\\tpg policy: #now; dirty: true. pg write.\\t\\\"force the write\\\"\\n\\tpg policy: pol.\\n\\t^ pg! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'di 11/18/1999 09:15'!\\nupdateAllFromResources\\n\\n\\tself allMorphsDo: [:m | m updateFromResource]! !\\n\\n!Morph methodsFor: 'fileIn/out' stamp: 'nk 1/6/2004 12:38'!\\nupdateFromResource\\n\\t| pathName newMorph f |\\n\\t(pathName := self valueOfProperty: #resourceFilePath) ifNil: [^self].\\n\\t(pathName asLowercase endsWith: '.morph') \\n\\t\\tifTrue: \\n\\t\\t\\t[newMorph := (FileStream readOnlyFileNamed: pathName) fileInObjectAndCode.\\n\\t\\t\\t(newMorph isMorph) \\n\\t\\t\\t\\tifFalse: [^self error: 'Resource not a single morph']]\\n\\t\\tifFalse: \\n\\t\\t\\t[f := Form fromFileNamed: pathName.\\n\\t\\t\\tf ifNil: [^self error: 'unrecognized image file format'].\\n\\t\\t\\tnewMorph := World drawingClass withForm: f].\\n\\tnewMorph setProperty: #resourceFilePath toValue: pathName.\\n\\tself owner replaceSubmorph: self by: newMorph! !\\n\\n\\n!Morph methodsFor: 'filter streaming' stamp: 'ar 10/26/2000 19:55'!\\ndrawOnCanvas: aCanvas\\n\\t^aCanvas fullDraw: self.\\n! !\\n\\n\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 7/24/97 11:55'!\\nalign: aPoint1 with: aPoint2\\n\\t\\\"Translate by aPoint2 - aPoint1.\\\"\\n\\n\\t^ self position: self position + (aPoint2 - aPoint1)! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:17'!\\nbottom\\n\\t\\\" Return the y-coordinate of my bottom side \\\"\\n\\n\\t^ bounds bottom! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 3/6/2002 13:06'!\\nbottomCenter\\n\\n\\t^ bounds bottomCenter! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'tk 9/8/97 10:44'!\\nbottomLeft\\n\\n\\t^ bounds bottomLeft! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:08'!\\nbottomLeft: aPoint\\n\\t\\\" Move me so that my bottom left corner is at aPoint. My extent (width & height) are unchanged \\\"\\n\\n\\tself position: ((aPoint x) @ (aPoint y - self height)).\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 6/12/97 11:17'!\\nbottomRight\\n\\n\\t^ bounds bottomRight! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:09'!\\nbottomRight: aPoint\\n\\t\\\" Move me so that my bottom right corner is at aPoint. My extent (width & height) are unchanged \\\"\\n\\n\\tself position: ((aPoint x - bounds width) @ (aPoint y - self height))\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:14'!\\nbottom: aNumber\\n\\t\\\" Move me so that my bottom is at the y-coordinate aNumber. My extent (width & height) are unchanged \\\"\\n\\n\\tself position: (bounds left @ (aNumber - self height))! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'jm 8/3/97 15:50'!\\nbounds\\n\\t\\\"Return the bounds of this morph.\\\"\\n\\t\\\"Note: It is best not to override this method because many methods in Morph and its subclasses use the instance variable directly rather than 'self bounds'. Instead, subclasses should be sure that the bounds instance variable is correct.\\\"\\n\\n\\t^ bounds\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:05'!\\nboundsInWorld\\n\\t^self bounds: self bounds in: self world! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:04'!\\nboundsIn: referenceMorph\\n\\t\\\"Return the receiver's bounds as seen by aMorphs coordinate frame\\\"\\n\\t^self bounds: self bounds in: referenceMorph! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 12/14/2000 13:48'!\\nbounds: newBounds\\n\\t| oldExtent newExtent |\\n\\toldExtent _ self extent.\\n\\tnewExtent _ newBounds extent.\\n\\t(oldExtent dotProduct: oldExtent) <= (newExtent dotProduct: newExtent) ifTrue:[\\n\\t\\t\\\"We're growing. First move then resize.\\\"\\n\\t\\tself position: newBounds topLeft; extent: newExtent.\\n\\t] ifFalse:[\\n\\t\\t\\\"We're shrinking. First resize then move.\\\"\\n\\t\\tself extent: newExtent; position: newBounds topLeft.\\n\\t].! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:04'!\\nbounds: aRectangle from: referenceMorph\\n\\t\\\"Return the receiver's bounds as seen by aMorphs coordinate frame\\\"\\n\\towner ifNil: [^ aRectangle].\\n\\t^(owner transformFrom: referenceMorph) globalBoundsToLocal: aRectangle\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:04'!\\nbounds: aRectangle in: referenceMorph\\n\\t\\\"Return the receiver's bounds as seen by aMorphs coordinate frame\\\"\\n\\towner ifNil: [^ aRectangle].\\n\\t^(owner transformFrom: referenceMorph) localBoundsToGlobal: aRectangle\\n! !\\n\\n!Morph methodsFor: 'geometry'!\\ncenter\\n\\n\\t^ bounds center! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'sw 6/11/1999 18:48'!\\ncenter: aPoint\\n\\tself position: (aPoint - (self extent // 2))! !\\n\\n!Morph methodsFor: 'geometry'!\\nextent\\n\\n\\t^ bounds extent! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'laza 3/25/2004 21:31'!\\nextent: aPoint\\n\\n\\tbounds extent = aPoint ifTrue: [^ self].\\n\\tself changed.\\n\\tbounds _ (bounds topLeft extent: aPoint) rounded.\\n\\tself layoutChanged.\\n\\tself changed.\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:06'!\\nfullBoundsInWorld\\n\\t^self bounds: self fullBounds in: self world! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:06'!\\nglobalPointToLocal: aPoint\\n\\t^self point: aPoint from: nil! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 9/15/2000 14:21'!\\ngriddedPoint: ungriddedPoint\\n\\n\\t| griddingContext |\\n\\tself flag: #arNote. \\\"Used by event handling - should transform to pasteUp for gridding\\\"\\n\\t(griddingContext _ self pasteUpMorph) ifNil: [^ ungriddedPoint].\\n\\t^ griddingContext gridPoint: ungriddedPoint! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 8/25/2000 00:35'!\\ngridPoint: ungriddedPoint\\n\\n\\t^ ungriddedPoint! !\\n\\n!Morph methodsFor: 'geometry'!\\nheight\\n\\n\\t^ bounds height! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:22'!\\nheight: aNumber\\n\\t\\\" Set my height; my position (top-left corner) and width will remain the same \\\"\\n\\n\\tself extent: self width@aNumber asInteger.\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 12/22/2001 22:43'!\\ninnerBounds\\n\\t\\\"Return the inner rectangle enclosed by the bounds of this morph excluding the space taken by its borders. For an unbordered morph, this is just its bounds.\\\"\\n\\n\\t^ self bounds insetBy: self borderWidth! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:16'!\\nleft\\n\\t\\\" Return the x-coordinate of my left side \\\"\\n\\n\\t^ bounds left! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 3/6/2002 13:06'!\\nleftCenter\\n\\n\\t^ bounds leftCenter! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:15'!\\nleft: aNumber\\n\\t\\\" Move me so that my left side is at the x-coordinate aNumber. My extent (width & height) are unchanged \\\"\\n\\n\\tself position: (aNumber @ bounds top)! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:07'!\\nlocalPointToGlobal: aPoint\\n\\t^self point: aPoint in: nil! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'sw 6/4/2000 21:59'!\\nminimumExtent\\n\\t| ext |\\n\\t\\\"This returns the minimum extent that the morph may be shrunk to. Not honored in too many places yet, but respected by the resizeToFit feature, at least. copied up from SystemWindow 6/00\\\"\\n\\t(ext _ self valueOfProperty: #minimumExtent)\\n\\t\\tifNotNil:\\n\\t\\t\\t[^ ext].\\n\\t^ 100 @ 80! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'sw 6/4/2000 22:00'!\\nminimumExtent: aPoint\\n\\t\\\"Remember a minimumExtent, for possible future use\\\"\\n\\n\\tself setProperty: #minimumExtent toValue: aPoint\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'sw 7/10/1999 17:26'!\\nnextOwnerPage\\n\\t\\\"Tell my container to advance to the next page\\\"\\n\\t| targ |\\n\\ttarg _ self ownerThatIsA: BookMorph.\\n\\ttarg ifNotNil: [targ nextPage]! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 11/12/2000 22:06'!\\nouterBounds\\n\\t\\\"Return the 'outer' bounds of the receiver, e.g., the bounds that need to be invalidated when the receiver changes.\\\"\\n\\t| box |\\n\\tbox _ self bounds.\\n\\tself hasDropShadow ifTrue:[box _ self expandFullBoundsForDropShadow: box].\\n\\tself hasRolloverBorder ifTrue:[box _ self expandFullBoundsForRolloverBorder: box].\\n\\t^box! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'nk 5/19/2003 20:39'!\\noverlapsShadowForm: itsShadow bounds: itsBounds\\n\\t\\\"Answer true if itsShadow and my shadow overlap at all\\\"\\n\\t| andForm overlapExtent |\\n\\toverlapExtent _ (itsBounds intersect: self fullBounds) extent.\\n\\toverlapExtent > (0 @ 0)\\n\\t\\tifFalse: [^ false].\\n\\tandForm _ self shadowForm.\\n\\toverlapExtent ~= self fullBounds extent\\n\\t\\tifTrue: [andForm _ andForm\\n\\t\\t\\t\\t\\t\\tcontentsOfArea: (0 @ 0 extent: overlapExtent)].\\n\\tandForm _ andForm\\n\\t\\t\\t\\tcopyBits: (self fullBounds translateBy: itsShadow offset negated)\\n\\t\\t\\t\\tfrom: itsShadow\\n\\t\\t\\t\\tat: 0 @ 0\\n\\t\\t\\t\\tclippingBox: (0 @ 0 extent: overlapExtent)\\n\\t\\t\\t\\trule: Form and\\n\\t\\t\\t\\tfillColor: nil.\\n\\t^ andForm bits\\n\\t\\tanySatisfy: [:w | w ~= 0]! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:02'!\\npointFromWorld: aPoint\\n\\t^self point: aPoint from: self world! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:03'!\\npointInWorld: aPoint\\n\\t^self point: aPoint in: self world! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:01'!\\npoint: aPoint from: aReferenceMorph\\n\\n\\towner ifNil: [^ aPoint].\\n\\t^ (owner transformFrom: aReferenceMorph) globalPointToLocal: aPoint.\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/25/2000 15:01'!\\npoint: aPoint in: aReferenceMorph\\n\\n\\towner ifNil: [^ aPoint].\\n\\t^ (owner transformFrom: aReferenceMorph) localPointToGlobal: aPoint.\\n! !\\n\\n!Morph methodsFor: 'geometry'!\\nposition\\n\\n\\t^ bounds topLeft! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 9/30/1998 12:11'!\\npositionInWorld\\n\\n\\t^ self pointInWorld: self position.\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'sw 10/9/1998 08:56'!\\npositionSubmorphs\\n\\tself submorphsDo:\\n\\t\\t[:aMorph | aMorph snapToEdgeIfAppropriate]! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'wiz 11/25/2004 12:54'!\\nposition: aPoint \\n\\t\\\"Change the position of this morph and and all of its\\n\\tsubmorphs. \\\"\\n\\t| delta box |\\n\\tdelta := aPoint asNonFractionalPoint - bounds topLeft.\\n\\t(delta x = 0\\n\\t\\t\\tand: [delta y = 0])\\n\\t\\tifTrue: [^ self].\\n\\t\\\"Null change\\\"\\n\\tbox := self fullBounds.\\n\\t(delta dotProduct: delta)\\n\\t\\t\\t> 100\\n\\t\\tifTrue: [\\\"e.g., more than 10 pixels moved\\\"\\n\\t\\t\\tself invalidRect: box.\\n\\t\\t\\tself\\n\\t\\t\\t\\tinvalidRect: (box translateBy: delta)]\\n\\t\\tifFalse: [self\\n\\t\\t\\t\\tinvalidRect: (box\\n\\t\\t\\t\\t\\t\\tmerge: (box translateBy: delta))].\\n\\tself privateFullMoveBy: delta.\\n\\towner\\n\\t\\tifNotNil: [owner layoutChanged]! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'sw 7/10/1999 17:27'!\\npreviousOwnerPage\\n\\t\\\"Tell my container to advance to the previous page\\\"\\n\\t| targ |\\n\\ttarg _ self ownerThatIsA: BookMorph.\\n\\ttarg ifNotNil: [targ previousPage]! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:16'!\\nright\\n\\t\\\" Return the x-coordinate of my right side \\\"\\n\\t^ bounds right! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 3/6/2002 13:06'!\\nrightCenter\\n\\n\\t^ bounds rightCenter! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:15'!\\nright: aNumber\\n\\t\\\" Move me so that my right side is at the x-coordinate aNumber. My extent (width & height) are unchanged \\\"\\n\\n\\tself position: ((aNumber - bounds width) @ bounds top)! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'bf 1/5/2000 19:08'!\\nscreenLocation\\n\\t\\\"For compatibility only\\\"\\n\\n\\t^ self fullBounds origin! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'sma 2/5/2000 13:58'!\\nscreenRectangle\\n\\t\\\"For compatibility only\\\"\\n\\n\\t^ self fullBounds! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'tk 7/14/2001 11:11'!\\nsetConstrainedPosition: aPoint hangOut: partiallyOutside\\n\\t\\\"Change the position of this morph and and all of its submorphs to aPoint, but don't let me go outside my owner's bounds. Let me go within two pixels of completely outside if partiallyOutside is true.\\\"\\n\\n\\t| trialRect delta boundingMorph bRect |\\n\\towner ifNil:[^self].\\n\\ttrialRect _ aPoint extent: self bounds extent.\\n\\tboundingMorph _ self topRendererOrSelf owner.\\n\\tdelta _ boundingMorph\\n\\t\\t\\tifNil: [0@0]\\n\\t\\t\\tifNotNil: [\\n\\t\\t\\t\\tbRect _ partiallyOutside \\n\\t\\t\\t\\t\\tifTrue: [boundingMorph bounds insetBy: \\n\\t\\t\\t\\t\\t\\t\\t\\tself extent negated + boundingMorph borderWidth + (2@2)]\\n\\t\\t\\t\\t\\tifFalse: [boundingMorph bounds].\\n\\t\\t\\t\\ttrialRect amountToTranslateWithin: bRect].\\n\\tself position: aPoint + delta.\\n\\tself layoutChanged \\\"So that, eg, surrounding text will readjust\\\"\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'sw 2/16/1999 22:05'!\\nshiftSubmorphsOtherThan: listNotToShift by: delta\\n\\t| rejectList |\\n\\trejectList _ listNotToShift ifNil: [OrderedCollection new].\\n\\t(submorphs copyWithoutAll: rejectList) do:\\n\\t\\t[:m | m position: (m position + delta)]! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:17'!\\ntop\\n\\t\\\" Return the y-coordinate of my top side \\\"\\n\\n\\t^ bounds top! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 3/6/2002 13:06'!\\ntopCenter\\n\\n\\t^ bounds topCenter! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 6/12/97 11:07'!\\ntopLeft\\n\\n\\t^ bounds topLeft! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:10'!\\ntopLeft: aPoint\\n\\t\\\" Move me so that my top left corner is at aPoint. My extent (width & height) are unchanged \\\"\\n\\n\\tself position: aPoint\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'sw 8/20/97 23:04'!\\ntopRight\\n\\n\\t^ bounds topRight! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:12'!\\ntopRight: aPoint\\n\\t\\\" Move me so that my top right corner is at aPoint. My extent (width & height) are unchanged \\\"\\n\\n\\tself position: ((aPoint x - bounds width) @ (aPoint y))\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:14'!\\ntop: aNumber\\n\\t\\\" Move me so that my top is at the y-coordinate aNumber. My extent (width & height) are unchanged \\\"\\n\\n\\tself position: (bounds left @ aNumber)! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'ar 10/22/2000 18:03'!\\ntransformedBy: aTransform\\n\\taTransform isIdentity ifTrue:[^self].\\n\\taTransform isPureTranslation ifTrue:[\\n\\t\\t^self position: (aTransform localPointToGlobal: self position).\\n\\t].\\n\\t^self addFlexShell transformedBy: aTransform! !\\n\\n!Morph methodsFor: 'geometry'!\\nwidth\\n\\n\\t^ bounds width! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'efc 2/13/2003 18:22'!\\nwidth: aNumber\\n\\t\\\" Set my width; my position (top-left corner) and height will remain the same \\\"\\n\\n\\tself extent: aNumber asInteger@self height.\\n! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'di 2/23/98 11:36'!\\nworldBounds\\n\\t^ self world bounds! !\\n\\n!Morph methodsFor: 'geometry' stamp: 'dgd 9/10/2004 12:37'!\\nworldBoundsForHalo\\n\\t\\\"Answer the rectangle to be used as the inner dimension of my halos.\\n\\tAllow for showing either bounds or fullBounds, and compensate for the optional bounds rectangle.\\\"\\n\\n\\t| r |\\n\\tr _ (Preferences haloEnclosesFullBounds)\\n\\t\\tifFalse: [ self boundsIn: nil ]\\n\\t\\tifTrue: [ self fullBoundsInWorld ].\\n\\tPreferences showBoundsInHalo ifTrue: [ ^r outsetBy: 2 ].\\n\\t^r! !\\n\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'sw 10/23/1998 12:00'!\\naddTransparentSpacerOfSize: aPoint\\n\\tself addMorphBack: (self transparentSpacerOfSize: aPoint)! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'sw 10/23/1998 12:01'!\\nbeTransparent\\n\\tself color: Color transparent! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'RAA 11/8/2000 18:29'!\\ncartesianBoundsTopLeft\\n\\t\\\"Answer the origin of this morph relative to it's container's cartesian origin. \\n\\tNOTE: y DECREASES toward the bottom of the screen\\\"\\n\\n\\t| w container |\\n\\n\\tw _ self world ifNil: [^ bounds origin].\\n\\tcontainer _ self referencePlayfield ifNil: [w].\\n\\t^ (bounds left - container cartesianOrigin x) @\\n\\t\\t(container cartesianOrigin y - bounds top)! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'sw 1/17/2000 20:55'!\\ncartesianXY: coords\\n\\t^ self x: coords x y: coords y\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'di 9/9/1998 22:49'!\\ncolorUnder\\n\\t\\\"Return the color of under the receiver's center.\\\"\\n\\n\\tself isInWorld\\n\\t\\tifTrue: [^ self world colorAt: (self pointInWorld: self referencePosition) belowMorph: self]\\n\\t\\tifFalse: [^ Color black].\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'nk 7/7/2003 17:18'!\\ncolor: sensitiveColor sees: soughtColor \\n\\t\\\"Return true if any of my pixels of sensitiveColor intersect with pixels of soughtColor.\\\"\\n\\n\\t\\\"Make a mask with black where sensitiveColor is, white elsewhere\\\"\\n\\n\\t| myImage sensitivePixelMask map patchBelowMe tfm morphAsFlexed i1 pasteUp |\\n\\tpasteUp _ self world ifNil: [ ^false ].\\n\\ttfm := self transformFrom: pasteUp.\\n\\tmorphAsFlexed := tfm isIdentity \\n\\t\\t\\t\\tifTrue: [self]\\n\\t\\t\\t\\tifFalse: [TransformationMorph new flexing: self clone byTransformation: tfm].\\n\\tmyImage := morphAsFlexed imageForm offset: 0 @ 0.\\n\\tsensitivePixelMask := Form extent: myImage extent depth: 1.\\n\\t\\\"ensure at most a 16-bit map\\\"\\n\\tmap := Bitmap new: (1 bitShift: (myImage depth - 1 min: 15)).\\n\\tmap at: (i1 := sensitiveColor indexInMap: map) put: 1.\\n\\tsensitivePixelMask \\n\\t\\tcopyBits: sensitivePixelMask boundingBox\\n\\t\\tfrom: myImage form\\n\\t\\tat: 0 @ 0\\n\\t\\tcolorMap: map.\\n\\n\\t\\\"get an image of the world below me\\\"\\n\\tpatchBelowMe := pasteUp \\n\\t\\t\\t\\tpatchAt: morphAsFlexed fullBounds\\n\\t\\t\\t\\twithout: self\\n\\t\\t\\t\\tandNothingAbove: false.\\n\\t\\\"\\nsensitivePixelMask displayAt: 0@0.\\npatchBelowMe displayAt: 100@0.\\n\\\"\\n\\t\\\"intersect world pixels of the color we're looking for with the sensitive pixels\\\"\\n\\tmap at: i1 put: 0.\\t\\\"clear map and reuse it\\\"\\n\\tmap at: (soughtColor indexInMap: map) put: 1.\\n\\tsensitivePixelMask \\n\\t\\tcopyBits: patchBelowMe boundingBox\\n\\t\\tfrom: patchBelowMe\\n\\t\\tat: 0 @ 0\\n\\t\\tclippingBox: patchBelowMe boundingBox\\n\\t\\trule: Form and\\n\\t\\tfillColor: nil\\n\\t\\tmap: map.\\n\\t\\\"\\nsensitivePixelMask displayAt: 200@0.\\n\\\"\\n\\t^(sensitivePixelMask tallyPixelValues second) > 0! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'di 10/1/2000 11:54'!\\ndegreesOfFlex\\n\\t\\\"Return any rotation due to flexing\\\"\\n\\t\\\"NOTE: because renderedMorph, which is used by the halo to set heading, goes down through dropShadows as well as transformations, we need this method (and its other implems) to come back up through such a chain.\\\"\\n\\t^ 0.0! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'ar 9/22/2000 14:29'!\\nforwardDirection: newDirection\\n\\t\\\"Set the receiver's forward direction (in eToy terms)\\\"\\n\\tself setProperty: #forwardDirection toValue: newDirection.! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'sw 9/8/2000 16:35'!\\ngetIndexInOwner\\n\\t\\\"Answer which position the receiver holds in its owner's hierarchy\\\"\\n\\n\\t\\\"NB: There is some concern about submorphs that aren't really to be counted, such as a background morph of a playfield.\\\"\\n\\n\\t| container topRenderer |\\n\\tcontainer _ (topRenderer _ self topRendererOrSelf) owner.\\n\\t^ container submorphIndexOf: topRenderer.! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'dgd 9/20/2004 14:15'!\\ngoHome\\n\\t| box fb |\\n\\towner isInMemory ifFalse: [^ self].\\n\\towner isNil ifTrue: [^ self].\\n\\tself visible ifFalse: [^ self].\\n\\n\\tbox := owner visibleClearArea.\\n\\tfb := self fullBounds.\\n\\n\\tfb left < box left\\n\\t\\tifTrue: [self left: box left - fb left + self left].\\n\\tfb right > box right\\n\\t\\tifTrue: [self right: box right - fb right + self right].\\n\\n\\tfb top < box top\\n\\t\\tifTrue: [self top: box top - fb top + self top].\\n\\tfb bottom > box bottom\\n\\t\\tifTrue: [self bottom: box bottom - fb bottom + self bottom].\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'di 10/1/2000 11:50'!\\nheading\\n\\t\\\"Return the receiver's heading (in eToy terms)\\\"\\n\\towner ifNil: [^ self forwardDirection].\\n\\t^ self forwardDirection + owner degreesOfFlex! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'ar 9/22/2000 13:37'!\\nheading: newHeading\\n\\t\\\"Set the receiver's heading (in eToy terms)\\\"\\n\\tself isFlexed ifFalse:[self addFlexShell].\\n\\towner rotationDegrees: (newHeading - self forwardDirection).! !\\n\\n!Morph methodsFor: 'geometry eToy'!\\nmove: aMorph toPosition: aPointOrNumber\\n\\t\\\"Support for e-toy demo. Move the given submorph to the given position. Allows the morph's owner to determine the policy for motion. For example, moving forward through a table might mean motion only in the x-axis with wrapping modulo the table size.\\\"\\n\\n\\taMorph position: aPointOrNumber asPoint.\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'ar 9/22/2000 20:12'!\\nreferencePosition\\n\\t\\\"Return the current reference position of the receiver\\\"\\n\\t| box |\\n\\tbox _ self bounds.\\n\\t^box origin + (self rotationCenter * box extent).\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'sw 10/25/1999 16:49'!\\nreferencePositionInWorld\\n\\n\\t^ self pointInWorld: self referencePosition\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'sw 10/25/1999 23:33'!\\nreferencePositionInWorld: aPoint\\n\\t| localPosition |\\n\\tlocalPosition _ owner\\n\\t\\tifNil: [aPoint]\\n\\t\\tifNotNil: [(owner transformFrom: self world) globalPointToLocal: aPoint].\\n\\n\\tself referencePosition: localPosition\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'ar 9/27/2000 14:04'!\\nreferencePosition: aPosition\\n\\t\\\"Move the receiver to match its reference position with aPosition\\\"\\n\\t| newPos intPos |\\n\\tnewPos _ self position + (aPosition - self referencePosition).\\n\\tintPos _ newPos asIntegerPoint.\\n\\tnewPos = intPos \\n\\t\\tifTrue:[self position: intPos]\\n\\t\\tifFalse:[self position: newPos].! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'ar 9/22/2000 20:10'!\\nrotationCenter\\n\\t\\\"Return the rotation center of the receiver. The rotation center defines the relative offset inside the receiver's bounds for locating the reference position.\\\"\\n\\t^self valueOfProperty: #rotationCenter ifAbsent:[0.5@0.5]\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'ar 9/22/2000 20:11'!\\nrotationCenter: aPointOrNil\\n\\t\\\"Set the new rotation center of the receiver. The rotation center defines the relative offset inside the receiver's bounds for locating the reference position.\\\"\\n\\taPointOrNil isNil\\n\\t\\tifTrue:[self removeProperty: #rotationCenter]\\n\\t\\tifFalse:[self setProperty: #rotationCenter toValue: aPointOrNil]\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'nk 9/4/2004 11:04'!\\nscaleFactor: newScale \\n\\t\\\"Backstop for morphs that don't have to do something special to set their \\n\\tscale \\\"\\n\\t| toBeScaled |\\n\\ttoBeScaled := self.\\n\\tnewScale = 1.0\\n\\t\\tifTrue: [(self heading isZero\\n\\t\\t\\t\\t\\tand: [self isFlexMorph])\\n\\t\\t\\t\\tifTrue: [toBeScaled := self removeFlexShell]]\\n\\t\\tifFalse: [self isFlexMorph\\n\\t\\t\\t\\tifFalse: [toBeScaled := self addFlexShellIfNecessary]].\\n\\n\\ttoBeScaled scale: newScale.\\n\\n\\ttoBeScaled == self ifTrue: [\\n\\t\\tnewScale = 1.0\\n\\t\\t\\tifTrue: [ self removeProperty: #scaleFactor ]\\n\\t\\t\\tifFalse: [ self setProperty: #scaleFactor toValue: newScale ]]! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'nk 9/4/2004 11:00'!\\nscale: newScale\\n\\t\\\"Backstop for morphs that don't have to do something special to set their scale\\\"\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'ar 6/12/2001 05:23'!\\nsetDirectionFrom: aPoint\\n\\t| delta degrees |\\n\\tdelta _ (self transformFromWorld globalPointToLocal: aPoint) - self referencePosition.\\n\\tdegrees _ delta degrees + 90.0.\\n\\tself forwardDirection: (degrees \\\\\\\\ 360) rounded.\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'sw 8/31/2000 11:18'!\\nsetIndexInOwner: anInteger\\n\\t\\\"Answer which position the receiver holds in its owner's hierarchy\\\"\\n\\n\\t\\\"There is some concern about submorphs that aren't really to be counted, such as a background morph of a playfield.\\\"\\n\\t| container topRenderer indexToUse |\\n\\tcontainer _ (topRenderer _ self topRendererOrSelf) owner.\\n\\tindexToUse _ (anInteger min: container submorphCount) max: 1.\\n\\tcontainer addMorph: topRenderer asElementNumber: indexToUse! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'wiz 11/6/2005 17:10'!\\nsimplySetVisible: aBoolean\\n\\t\\\"Set the receiver's visibility property. This mild circumlocution is because my TransfomationMorph #visible: method would also set the visibility flag of my flexee, which in this case is pointless because it's the flexee that calls this.\\n\\tThis appears in morph as a backstop for morphs that don't inherit from TFMorph\\\"\\n\\n\\tself visible: aBoolean! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'nk 7/7/2003 17:19'!\\ntouchesColor: soughtColor \\n\\t\\\"Return true if any of my pixels overlap pixels of soughtColor.\\\"\\n\\n\\t\\\"Make a shadow mask with black in my shape, white elsewhere\\\"\\n\\n\\t| map patchBelowMe shadowForm tfm morphAsFlexed pasteUp |\\n\\tpasteUp := self world ifNil: [ ^false ].\\n\\n\\ttfm := self transformFrom: pasteUp.\\n\\tmorphAsFlexed := tfm isIdentity \\n\\t\\t\\t\\tifTrue: [self]\\n\\t\\t\\t\\tifFalse: [TransformationMorph new flexing: self clone byTransformation: tfm].\\n\\tshadowForm := morphAsFlexed shadowForm offset: 0 @ 0.\\n\\n\\t\\\"get an image of the world below me\\\"\\n\\tpatchBelowMe := (pasteUp \\n\\t\\t\\t\\tpatchAt: morphAsFlexed fullBounds\\n\\t\\t\\t\\twithout: self\\n\\t\\t\\t\\tandNothingAbove: false) offset: 0 @ 0.\\n\\t\\\"\\nshadowForm displayAt: 0@0.\\npatchBelowMe displayAt: 100@0.\\n\\\"\\n\\t\\\"intersect world pixels of the color we're looking for with our shape.\\\"\\n\\t\\\"ensure a maximum 16-bit map\\\"\\n\\tmap := Bitmap new: (1 bitShift: (patchBelowMe depth - 1 min: 15)).\\n\\tmap at: (soughtColor indexInMap: map) put: 1.\\n\\tshadowForm \\n\\t\\tcopyBits: patchBelowMe boundingBox\\n\\t\\tfrom: patchBelowMe\\n\\t\\tat: 0 @ 0\\n\\t\\tclippingBox: patchBelowMe boundingBox\\n\\t\\trule: Form and\\n\\t\\tfillColor: nil\\n\\t\\tmap: map.\\n\\t\\\"\\nshadowForm displayAt: 200@0.\\n\\\"\\n\\t^(shadowForm tallyPixelValues second) > 0! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'sw 10/23/1998 11:50'!\\ntransparentSpacerOfSize: aPoint\\n\\t^ (Morph new extent: aPoint) color: Color transparent! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'tk 7/8/1998 23:47'!\\nwrap\\n\\n\\t| myBox box newX newY wrapped |\\n\\towner ifNil: [^ self].\\n\\tmyBox _ self fullBounds.\\n\\tmyBox corner < (50000@50000) ifFalse: [\\n\\t\\tself inform: 'Who is trying to wrap a hidden object?'. ^ self].\\n\\tbox _ owner bounds.\\n\\tnewX _ self position x.\\n\\tnewY _ self position y.\\n\\twrapped _ false.\\n\\t((myBox right < box left) or: [myBox left > box right]) ifTrue: [\\n\\t\\tnewX _ box left + ((self position x - box left) \\\\\\\\ box width).\\n\\t\\twrapped _ true].\\n\\t((myBox bottom < box top) or: [myBox top > box bottom]) ifTrue: [\\n\\t\\tnewY _ box top + ((self position y - box top) \\\\\\\\ box height).\\n\\t\\twrapped _ true].\\n\\tself position: newX@newY.\\n\\t(wrapped and: [owner isPlayfieldLike])\\n\\t\\tifTrue: [owner changed]. \\\"redraw all turtle trails if wrapped\\\"\\n\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'dgd 2/22/2003 14:37'!\\nx\\n\\t\\\"Return my horizontal position relative to the cartesian origin of a relevant playfield\\\"\\n\\n\\t| aPlayfield |\\n\\taPlayfield := self referencePlayfield.\\n\\t^aPlayfield isNil \\n\\t\\tifTrue: [self referencePosition x]\\n\\t\\tifFalse: [self referencePosition x - aPlayfield cartesianOrigin x]! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'aoy 2/17/2003 01:00'!\\nx: aNumber \\n\\t\\\"Set my horizontal position relative to the cartesian origin of the playfield or the world.\\\"\\n\\n\\t| offset aPlayfield newX |\\n\\taPlayfield := self referencePlayfield.\\n\\toffset := self left - self referencePosition x.\\n\\tnewX := aPlayfield isNil\\n\\t\\t\\t\\tifTrue: [aNumber + offset]\\n\\t\\t\\t\\tifFalse: [aPlayfield cartesianOrigin x + aNumber + offset].\\n\\tself position: newX @ bounds top! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'sw 1/17/2000 20:04'!\\nx: xCoord y: yCoord\\n\\t| aWorld xyOffset delta aPlayfield |\\n\\t(aWorld _ self world) ifNil: [^ self position: xCoord @ yCoord].\\n\\txyOffset _ self topLeft - self referencePosition.\\n\\tdelta _ (aPlayfield _ self referencePlayfield)\\n\\t\\tifNil:\\n\\t\\t\\t[xCoord @ (aWorld bottom - yCoord)]\\n\\t\\tifNotNil:\\n\\t\\t\\t[aPlayfield cartesianOrigin + (xCoord @ (yCoord negated))].\\n\\tself position: (xyOffset + delta)\\n! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'dgd 2/22/2003 14:37'!\\ny\\n\\t\\\"Return my vertical position relative to the cartesian origin of the playfield or the world. Note that larger y values are closer to the top of the screen.\\\"\\n\\n\\t| w aPlayfield |\\n\\tw := self world.\\n\\tw ifNil: [^bounds top].\\n\\taPlayfield := self referencePlayfield.\\n\\t^aPlayfield isNil \\n\\t\\tifTrue: [w cartesianOrigin y - self referencePosition y]\\n\\t\\tifFalse: [aPlayfield cartesianOrigin y - self referencePosition y]! !\\n\\n!Morph methodsFor: 'geometry eToy' stamp: 'aoy 2/17/2003 01:00'!\\ny: aNumber \\n\\t\\\"Set my vertical position relative to the cartesian origin of the playfield or the world. Note that larger y values are closer to the top of the screen.\\\"\\n\\n\\t| w offset newY aPlayfield |\\n\\tw := self world.\\n\\tw ifNil: [^self position: bounds left @ aNumber].\\n\\taPlayfield := self referencePlayfield.\\n\\toffset := self top - self referencePosition y.\\n\\tnewY := aPlayfield isNil\\n\\t\\t\\t\\tifTrue: [w bottom - aNumber + offset]\\n\\t\\t\\t\\tifFalse: [aPlayfield cartesianOrigin y - aNumber + offset].\\n\\tself position: bounds left @ newY! !\\n\\n\\n!Morph methodsFor: 'geometry testing'!\\ncontainsPoint: aPoint\\n\\n\\t^ self bounds containsPoint: aPoint! !\\n\\n!Morph methodsFor: 'geometry testing' stamp: 'di 5/3/2000 19:05'!\\nfullContainsPoint: aPoint\\n\\n\\t(self fullBounds containsPoint: aPoint) ifFalse: [^ false]. \\\"quick elimination\\\"\\n\\t(self containsPoint: aPoint) ifTrue: [^ true]. \\\"quick acceptance\\\"\\n\\tsubmorphs do: [:m | (m fullContainsPoint: aPoint) ifTrue: [^ true]].\\n\\t^ false\\n! !\\n\\n!Morph methodsFor: 'geometry testing' stamp: 'dgd 2/22/2003 14:33'!\\nobtrudesBeyondContainer\\n\\t\\\"Answer whether the receiver obtrudes beyond the bounds of its container\\\"\\n\\n\\t| top |\\n\\ttop := self topRendererOrSelf.\\n\\t(top owner isNil or: [top owner isHandMorph]) ifTrue: [^false].\\n\\t^(top owner bounds containsRect: top bounds) not! !\\n\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 11/7/1999 18:57'!\\naddHalo\\n\\t\\\"Invoke a halo programatically (e.g., not from a meta gesture)\\\"\\n\\t^self addHalo: nil! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 10/10/2000 19:03'!\\naddHalo: evt\\n\\t| halo prospectiveHaloClass |\\n\\tprospectiveHaloClass _ Smalltalk at: self haloClass ifAbsent: [HaloMorph].\\n\\thalo _ prospectiveHaloClass new bounds: self worldBoundsForHalo.\\n\\thalo popUpFor: self event: evt.\\n\\t^halo! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 11/7/1999 21:55'!\\naddHalo: evt from: formerHaloOwner\\n\\t\\\"Transfer a halo from the former halo owner to the receiver\\\"\\n\\t^self addHalo: evt! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 12/30/2004 02:53'!\\naddHandlesTo: aHaloMorph box: box\\n\\t\\\"Add halo handles to the halo. Apply the halo filter if appropriate\\\"\\n\\n\\t| wantsIt aSelector |\\n\\taHaloMorph haloBox: box.\\n\\tPreferences haloSpecifications do:\\n\\t\\t[:aSpec | \\n\\t\\t\\taSelector _ aSpec addHandleSelector.\\n\\t\\t\\twantsIt _ Preferences selectiveHalos\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[self wantsHaloHandleWithSelector: aSelector inHalo: aHaloMorph]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[true].\\n\\t\\t\\twantsIt ifTrue:\\n\\t\\t\\t\\t[(#(addMakeSiblingHandle: addDupHandle:) includes: aSelector) ifTrue:\\n\\t\\t\\t\\t\\t[wantsIt _ self preferredDuplicationHandleSelector = aSelector].\\n\\t\\t\\twantsIt ifTrue:\\n\\t\\t\\t\\t[aHaloMorph perform: aSelector with: aSpec]]].\\n\\n\\taHaloMorph innerTarget addOptionalHandlesTo: aHaloMorph box: box! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 8/8/2001 17:31'!\\naddMagicHaloFor: aHand\\n\\t| halo prospectiveHaloClass |\\n\\taHand halo ifNotNil:[\\n\\t\\taHand halo target == self ifTrue:[^self].\\n\\t\\taHand halo isMagicHalo ifFalse:[^self]].\\n\\tprospectiveHaloClass _ Smalltalk at: self haloClass ifAbsent: [HaloMorph].\\n\\thalo _ prospectiveHaloClass new bounds: self worldBoundsForHalo.\\n\\thalo popUpMagicallyFor: self hand: aHand.! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 9/22/2000 20:41'!\\naddOptionalHandlesTo: aHalo box: box\\n\\taHalo addDirectionHandles! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 12/21/1999 17:52'!\\naddSimpleHandlesTo: aHaloMorph box: aBox\\n\\t^ aHaloMorph addSimpleHandlesTo: aHaloMorph box: aBox! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 1/26/2000 19:37'!\\naddWorldHandlesTo: aHaloMorph box: box\\n\\taHaloMorph haloBox: box.\\n\\tPreferences haloSpecificationsForWorld do:\\n\\t\\t[:aSpec | \\n\\t\\t\\taHaloMorph perform: aSpec addHandleSelector with: aSpec].\\n\\taHaloMorph innerTarget addOptionalHandlesTo: aHaloMorph box: box! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sma 11/11/2000 14:54'!\\nballoonColor\\n\\t^ self\\n\\t\\tvalueOfProperty: #balloonColor\\n\\t\\tifAbsent: [self defaultBalloonColor]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sma 11/11/2000 14:55'!\\nballoonColor: aColor\\n\\t^ self\\n\\t\\tsetProperty: #balloonColor\\n\\t\\ttoValue: aColor! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sd 12/5/2001 20:29'!\\nballoonFont\\n\\t^ self\\n\\t\\tvalueOfProperty: #balloonFont\\n\\t\\tifAbsent: [self defaultBalloonFont]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sd 12/5/2001 20:30'!\\nballoonFont: aFont \\n\\t^ self setProperty: #balloonFont toValue: aFont! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 2/7/2000 11:27'!\\nballoonHelpAligner\\n\\t\\\"Answer the morph to which the receiver's balloon help should point\\\"\\n\\t^ (self valueOfProperty: #balloonTarget) ifNil: [self]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'dgd 9/7/2004 18:35'!\\nballoonHelpDelayTime\\n\\t\\\"Return the number of milliseconds before a balloon help should be put up on the receiver. The balloon help will only be put up if the receiver responds to #wantsBalloon by returning true.\\\"\\n\\t^ Preferences balloonHelpDelayTime! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'dgd 4/3/2006 14:15'!\\nballoonHelpTextForHandle: aHandle\\n\\t\\\"Answer a string providing balloon help for the given halo handle\\\"\\n\\n\\t| itsSelector |\\n\\titsSelector _ aHandle eventHandler firstMouseSelector.\\n\\n\\t(itsSelector == #doRecolor:with:) ifTrue:\\n\\t\\t[^ Preferences propertySheetFromHalo\\n\\t\\t\\tifTrue: ['Open a property sheet.']\\n\\t\\t\\tifFalse: ['Change color']].\\n\\n\\t(itsSelector == #mouseDownInDimissHandle:with:) ifTrue:\\n\\t\\t[^ Preferences preserveTrash\\n\\t\\t\\tifTrue: ['Move to trash']\\n\\t\\t\\tifFalse: ['Remove from screen']].\\n\\n\\t#(\\t(addFullHandles\\t\\t\\t\\t\\t\\t\\t'More halo handles')\\n\\t\\t(addSimpleHandles\\t\\t\\t\\t\\t\\t'Fewer halo handles')\\n\\t\\t(chooseEmphasisOrAlignment\\t\\t\\t\\t'Emphasis & alignment')\\n\\t\\t(chooseFont\\t\\t\\t\\t\\t\\t\\t\\t'Change font')\\n\\t\\t(chooseNewGraphicFromHalo\\t\\t\\t\\t'Choose a new graphic')\\n\\t\\t(chooseStyle\\t\\t\\t\\t\\t\\t\\t\\t'Change style')\\n\\t\\t(dismiss\\t\\t\\t\\t\\t\\t\\t\\t\\t'Remove')\\n\\t\\t(doDebug:with:\\t\\t\\t\\t\\t\\t\\t'Debug')\\n\\t\\t(doDirection:with:\\t\\t\\t\\t\\t\\t'Choose forward direction')\\n\\t\\t(doDup:with:\\t\\t\\t\\t\\t\\t\\t'Duplicate')\\n\\t\\t(doMakeSibling:with: \\t\\t\\t\\t\\t'Make a sibling')\\n\\t\\t(doMenu:with:\\t\\t\\t\\t\\t\\t\\t'Menu')\\n\\t\\t(doGrab:with:\\t\\t\\t\\t\\t\\t\\t'Pick up')\\n\\t\\t(editButtonsScript\\t\\t\\t\\t\\t\\t'See the script for this button')\\n\\t\\t(editDrawing\\t\\t\\t\\t\\t\\t\\t'Repaint')\\n\\t\\t(maybeDoDup:with:\\t\\t\\t\\t\\t\\t'Duplicate')\\n\\t\\t(makeNascentScript\\t\\t\\t\\t\\t\\t'Make a scratch script')\\n\\t\\t(makeNewDrawingWithin\\t\\t\\t\\t'Paint new object')\\n\\t\\t(mouseDownInCollapseHandle:with:\\t\\t'Collapse')\\n\\t\\t(mouseDownOnHelpHandle:\\t\\t\\t\\t'Help')\\n\\t\\t(openViewerForArgument\\t\\t\\t\\t'Open a Viewer for me. Press shift for a snapshot.')\\n\\t\\t(openViewerForTarget:with:\\t\\t\\t\\t'Open a Viewer for me. Press shift for a snapshot.')\\n\\t\\t(paintBackground\\t\\t\\t\\t\\t\\t'Paint background')\\n\\t\\t(prepareToTrackCenterOfRotation:with:\\t'Move object or set center of rotation')\\n\\t\\t(presentViewMenu\\t\\t\\t\\t\\t\\t'Present the Viewing menu')\\n\\t\\t(startDrag:with:\\t\\t\\t\\t\\t\\t\\t'Move')\\n\\t\\t(startGrow:with:\\t\\t\\t\\t\\t\\t\\t'Change size') \\n\\t\\t(startRot:with:\\t\\t\\t\\t\\t\\t\\t'Rotate')\\n\\t\\t(startScale:with:\\t\\t\\t\\t\\t\\t\\t'Change scale') \\n\\t\\t(tearOffTile\\t\\t\\t\\t\\t\\t\\t\\t'Make a tile representing this object')\\n\\t\\t(tearOffTileForTarget:with:\\t\\t\\t\\t'Make a tile representing this object')\\n\\t\\t(trackCenterOfRotation:with:\\t\\t\\t\\t'Set center of rotation')\\n\\t) \\n\\tdo:\\n\\t\\t[:pair | itsSelector == pair first ifTrue: [^ pair last]].\\n\\n\\t^ 'unknown halo handle'! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'RAA 7/21/2000 11:10'!\\nboundsForBalloon\\n\\n\\t\\\"some morphs have bounds that are way too big\\\"\\n\\t^self boundsInWorld! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 3/1/2000 11:39'!\\ncomeToFrontAndAddHalo\\n\\tself comeToFront.\\n\\tself addHalo! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sma 11/11/2000 16:15'!\\ndefaultBalloonColor\\n\\t^ Display depth <= 2\\n\\t\\tifTrue: [Color white]\\n\\t\\tifFalse: [BalloonMorph balloonColor]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sd 12/5/2001 20:23'!\\ndefaultBalloonFont\\n\\t^ BalloonMorph balloonFont! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 1/11/2000 18:24'!\\ndefersHaloOnClickTo: aSubMorph\\n\\t\\\"If a cmd-click on aSubMorph would make it a preferred recipient of the halo, answer true\\\"\\n\\t\\\"May want to add a way (via a property) for morphs to assert true here -- this would let certain kinds of morphs that are unusually reluctant to take the halo on initial click\\\"\\n\\n\\t^ false\\n\\t! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 10/3/2000 17:03'!\\ndeleteBalloon\\n\\t\\\"If I am showing a balloon, delete it.\\\"\\n\\t| w |\\n\\tw _ self world ifNil:[^self].\\n\\tw deleteBalloonTarget: self.! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'em 3/24/2005 10:02'!\\neditBalloonHelpContent: aString\\n\\t| reply |\\n\\treply _ FillInTheBlank\\n\\t\\tmultiLineRequest: 'Edit the balloon help text for ' translated, self externalName\\n\\t\\tcenterAt: Sensor cursorPoint\\n\\t\\tinitialAnswer: (aString ifNil: [self noHelpString] ifNotNil: [aString])\\n\\t\\tanswerHeight: 200.\\n\\treply ifNil: [^ self]. \\\"User cancelled out of the dialog\\\"\\n\\t(reply isEmpty or: [reply asString = self noHelpString])\\n\\t\\tifTrue: [self setBalloonText: nil]\\n\\t\\tifFalse: [self setBalloonText: reply]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sma 12/23/1999 13:24'!\\neditBalloonHelpText\\n\\t\\\"Modify the receiver's balloon help text.\\\"\\n\\n\\tself editBalloonHelpContent: self balloonText! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 3/17/2001 13:19'!\\nhalo\\n\\n\\t(self outermostWorldMorph ifNil: [^nil]) haloMorphs do: [:h | h target == self ifTrue: [^ h]].\\n\\t^ nil! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 9/15/2000 16:13'!\\nhaloClass\\n\\t\\\"Answer the name of the desired kind of HaloMorph to launch on behalf of the receiver\\\"\\n\\n\\t^ #HaloMorph\\n! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 8/8/2001 15:40'!\\nhaloDelayTime\\n\\t\\\"Return the number of milliseconds before a halo should be put up on the receiver. The halo will only be put up if the receiver responds to #wantsHalo by returning true.\\\"\\n\\t^800! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 9/15/2000 16:16'!\\nhasHalo\\n\\t^self hasProperty: #hasHalo.! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 9/28/2000 17:54'!\\nhasHalo: aBool\\n\\taBool\\n\\t\\tifTrue:[self setProperty: #hasHalo toValue: true]\\n\\t\\tifFalse:[self removeProperty: #hasHalo]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'dgd 2/22/2003 19:05'!\\nisLikelyRecipientForMouseOverHalos\\n\\t^self player notNil! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 10/3/2000 17:05'!\\nmouseDownOnHelpHandle: anEvent\\n\\t\\\"The mouse went down in the show-balloon handle\\\"\\n\\t\\n\\t| str |\\n\\tanEvent shiftPressed ifTrue: [^ self editBalloonHelpText].\\n\\tstr _ self balloonText.\\n\\tstr ifNil: [str _ self noHelpString].\\n\\tself showBalloon: str hand: anEvent hand.\\n! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'em 3/24/2005 10:05'!\\nnoHelpString\\n\\t^ 'Help not yet supplied' translated! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/15/2001 12:23'!\\nokayToAddDismissHandle\\n\\t\\\"Answer whether a halo on the receiver should offer a dismiss handle. This provides a hook for making it harder to disassemble some strucures even momentarily\\\"\\n\\n\\t^ self holdsSeparateDataForEachInstance not and:\\n\\t\\t[self resistsRemoval not]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 10/26/2000 12:11'!\\nokayToAddGrabHandle\\n\\t\\\"Answer whether a halo on the receiver should offer a grab handle. This provides a hook for making it harder to deconstruct some strucures even momentarily\\\"\\n\\n\\t^ self holdsSeparateDataForEachInstance not ! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/27/2001 14:50'!\\nokayToBrownDragEasily\\n\\t\\\"Answer whether it it okay for the receiver to be brown-dragged easily -- i.e. repositioned within its container without extracting it. At present this is just a hook -- nobody declines.\\\"\\n\\n\\t^ true\\n\\n\\n\\n\\\"\\n\\t^ (self topRendererOrSelf owner isKindOf: PasteUpMorph) and:\\n\\t\\t[self layoutPolicy isNil]\\\"! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/27/2001 15:02'!\\nokayToExtractEasily\\n\\t\\\"Answer whether it it okay for the receiver to be extracted easily. Not yet hooked up to the halo-permissions mechanism.\\\"\\n\\n\\t^ self topRendererOrSelf owner dragNDropEnabled! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/29/2001 06:29'!\\nokayToResizeEasily\\n\\t\\\"Answer whether it is appropriate to have the receiver be easily resized by the user from the halo\\\"\\n\\n\\t^ true\\n\\n\\t\\\"This one was too jarring, not that it didn't most of the time do the right thing but because some of the time it didn't, such as in a holder. If we pursue this path, the test needs to be airtight, obviously...\\n\\t^ (self topRendererOrSelf owner isKindOf: PasteUpMorph) and:\\n\\t\\t[self layoutPolicy isNil]\\\"! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/27/2001 14:44'!\\nokayToRotateEasily\\n\\t\\\"Answer whether it is appropriate for a rotation handle to be shown for the receiver. This is a hook -- at present nobody declines.\\\"\\n\\n\\t^ true! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 12/31/2004 03:30'!\\npreferredDuplicationHandleSelector\\n\\t\\\"Answer the selector, either #addMakeSiblingHandle: or addDupHandle:, to be offered as the default in a halo open on me\\\"\\n\\n\\tPreferences oliveHandleForScriptedObjects ifFalse:\\n\\t\\t[^ #addDupHandle:].\\n\\t^ self renderedMorph valueOfProperty: #preferredDuplicationHandleSelector ifAbsent:\\n\\t\\t[self player class isUniClass\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[#addMakeSiblingHandle:]\\n\\t\\t\\tifFalse:\\n\\t\\t\\t\\t[#addDupHandle:]]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'dgd 9/9/2004 22:43'!\\nremoveHalo\\n\\t\\\"remove the surrounding halo (if any)\\\"\\n\\tself halo isNil\\n\\t\\tifFalse: [self primaryHand removeHalo]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sma 12/23/1999 13:32'!\\nsetBalloonText: stringOrText\\n\\t\\\"Set receiver's balloon help text. Pass nil to remove the help.\\\"\\n\\n\\tself setBalloonText: stringOrText maxLineLength: Preferences maxBalloonHelpLineLength! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'md 2/27/2006 09:54'!\\nsetBalloonText: stringOrText maxLineLength: aLength \\n\\t\\\"Set receiver's balloon help text. Pass nil to remove the help.\\\"\\n\\t(extension isNil and: [stringOrText isNil]) ifTrue: [^ self].\\n\\tself assureExtension balloonText: \\n\\t\\t(stringOrText ifNotNil: [stringOrText asString withNoLineLongerThan: aLength])! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 10/29/1999 17:38'!\\nsetCenteredBalloonText: aString\\n\\tself setBalloonText: aString.\\n\\tself setProperty: #helpAtCenter toValue: true! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 10/3/2000 17:06'!\\nshowBalloon: msgString\\n\\t\\\"Pop up a balloon containing the given string,\\n\\tfirst removing any existing BalloonMorphs in the world.\\\"\\n\\t| w |\\n\\tself showBalloon: msgString hand: ((w _ self world) ifNotNil:[w activeHand]).! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'bf 11/1/2000 15:58'!\\nshowBalloon: msgString hand: aHand\\n\\t\\\"Pop up a balloon containing the given string,\\n\\tfirst removing any existing BalloonMorphs in the world.\\\"\\n\\n\\t| w balloon h |\\n\\t(w _ self world) ifNil: [^ self].\\n\\th _ aHand.\\n\\th ifNil:[\\n\\t\\th _ w activeHand].\\n\\tballoon _ BalloonMorph string: msgString for: self balloonHelpAligner.\\n\\tballoon popUpFor: self hand: h.! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'dgd 9/10/2004 13:59'!\\ntransferHalo: event from: formerHaloOwner\\n\\t\\\"Progressively transfer the halo to the next likely recipient\\\"\\n\\t| localEvt w target |\\n\\n\\tself flag: #workAround. \\\"For halo's distinction between 'target' and 'innerTarget' we need to bypass any renderers.\\\"\\n\\t(formerHaloOwner == self and:[self isRenderer and:[self wantsHaloFromClick not]]) ifTrue:[\\n\\t\\tevent shiftPressed ifTrue:[\\n\\t\\t\\ttarget _ owner.\\n\\t\\t\\tlocalEvt _ event transformedBy: (self transformedFrom: owner).\\n\\t\\t] ifFalse:[\\n\\t\\t\\ttarget _ self renderedMorph.\\n\\t\\t\\tlocalEvt _ event transformedBy: (target transformedFrom: self).\\n\\t\\t].\\n\\t\\t^target transferHalo: localEvt from: target].\\n\\n\\\"\\tformerHaloOwner == self ifTrue:[^ self removeHalo].\\\"\\n\\n\\t\\\"Never transfer halo to top-most world\\\"\\n\\t(self isWorldMorph and:[owner isNil]) ifFalse:[\\n\\t\\t(self wantsHaloFromClick and:[formerHaloOwner ~~ self]) \\n\\t\\t\\tifTrue:[^self addHalo: event from: formerHaloOwner]].\\n\\n\\tevent shiftPressed ifTrue:[\\n\\t\\t\\\"Pass it outwards\\\"\\n\\t\\towner ifNotNil:[^owner transferHalo: event from: formerHaloOwner].\\n\\t\\t\\\"We're at the top level; throw the event back in to find recipient\\\"\\n\\t\\tformerHaloOwner removeHalo.\\n\\t\\t^self processEvent: event copy resetHandlerFields.\\n\\t].\\n\\tself submorphsDo:[:m|\\n\\t\\tlocalEvt _ event transformedBy: (m transformedFrom: self).\\n\\t\\t(m fullContainsPoint: localEvt position) \\n\\t\\t\\tifTrue:[^m transferHalo: event from: formerHaloOwner].\\n\\t].\\n\\t\\\"We're at the bottom most level; throw the event back up to the root to find recipient\\\"\\n\\tformerHaloOwner removeHalo.\\n\\n\\tPreferences maintainHalos ifFalse:[\\n\\t\\t(w _ self world) ifNil: [ ^self ].\\n\\t\\tlocalEvt _ event transformedBy: (self transformedFrom: w) inverseTransformation.\\n\\t\\t^w processEvent: localEvt resetHandlerFields.\\n\\t].\\n! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'rhi 10/5/2001 20:49'!\\nwantsBalloon\\n\\t\\\"Answer true if receiver wants to show a balloon help text is a few moments.\\\"\\n\\n\\t^ (self balloonText notNil) and: [Preferences balloonHelpEnabled]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 11/29/2001 19:50'!\\nwantsDirectionHandles\\n\\t^self valueOfProperty: #wantsDirectionHandles ifAbsent:[Preferences showDirectionHandles]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'ar 11/29/2001 19:52'!\\nwantsDirectionHandles: aBool\\n\\taBool == Preferences showDirectionHandles\\n\\t\\tifTrue:[self removeProperty: #wantsDirectionHandles]\\n\\t\\tifFalse:[self setProperty: #wantsDirectionHandles toValue: aBool].\\n! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'dgd 2/22/2003 19:06'!\\nwantsHalo\\n\\t| topOwner |\\n\\t^(topOwner := self topRendererOrSelf owner) notNil \\n\\t\\tand: [topOwner wantsHaloFor: self]! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 4/8/98 13:26'!\\nwantsHaloFor: aSubMorph\\n\\t^ false! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 1/25/2000 17:43'!\\nwantsHaloFromClick\\n\\t^ true! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/27/2001 14:49'!\\nwantsHaloHandleWithSelector: aSelector inHalo: aHaloMorph\\n\\t\\\"Answer whether the receiver would like to offer the halo handle with the given selector (e.g. #addCollapseHandle:)\\\"\\n\\n\\t(#(addDismissHandle:) includes: aSelector) ifTrue:\\n\\t\\t[^ self resistsRemoval not].\\n\\n\\t(#( addDragHandle: ) includes: aSelector) ifTrue:\\n\\t\\t[^ self okayToBrownDragEasily].\\n\\n\\t(#(addGrowHandle: addScaleHandle:) includes: aSelector) ifTrue:\\n\\t\\t[^ self okayToResizeEasily].\\n\\n\\t(#( addRotateHandle: ) includes: aSelector) ifTrue:\\n\\t\\t[^ self okayToRotateEasily].\\n\\n\\t(#(addRecolorHandle:) includes: aSelector) ifTrue:\\n\\t\\t[^ self renderedMorph wantsRecolorHandle].\\n\\n\\ttrue ifTrue: [^ true]\\n\\t! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'sw 10/9/2000 16:56'!\\nwantsScriptorHaloHandle\\n\\t\\\"Answer whether the receiver would like to have a Scriptor halo handle put up on its behalf. Initially, only the ScriptableButton says yes\\\"\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'halos and balloon help' stamp: 'nk 6/12/2004 09:32'!\\nwantsSimpleSketchMorphHandles\\n\\t\\\"Answer true if my halo's simple handles should include the simple sketch morph handles.\\\"\\n\\t^false! !\\n\\n\\n!Morph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:00'!\\nbasicInitialize\\n\\t\\\"Do basic generic initialization of the instance variables: \\n\\tSet up the receiver, created by a #basicNew and now ready to \\n\\tbe initialized, by placing initial values in the instance variables \\n\\tas appropriate\\\"\\nowner _ nil.\\n\\tsubmorphs _ EmptyArray.\\n\\tbounds _ self defaultBounds.\\n\\t\\n\\tcolor _ self defaultColor! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 15:06'!\\ndefaultBounds\\n\\\"answer the default bounds for the receiver\\\"\\n\\t^ 0 @ 0 corner: 50 @ 40! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:28'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color blue! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'fbs 1/5/2005 09:17'!\\ninAScrollPane\\n\\t\\\"Answer a scroll pane that allows the user to scroll the receiver in either direction. It will have permanent scroll bars unless you take some special action.\\\"\\n\\n\\t| widget |\\n\\twidget _ ScrollPane new.\\n\\twidget extent: ((self width min: 300 max: 100) @ (self height min: 150 max: 100));\\n\\t\\tborderWidth: 0.\\n\\twidget scroller addMorph: self.\\n\\twidget setScrollDeltas.\\n\\twidget color: self color darker darker.\\n\\t^ widget! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'sw 6/26/2001 10:56'!\\ninATwoWayScrollPane\\n\\t\\\"Answer a two-way scroll pane that allows the user to scroll the receiver in either direction. It will have permanent scroll bars unless you take some special action.\\\"\\n\\n\\t| widget |\\n\\twidget _ TwoWayScrollPane new.\\n\\twidget extent: ((self width min: 300 max: 100) @ (self height min: 150 max: 100));\\n\\t\\tborderWidth: 0.\\n\\twidget scroller addMorph: self.\\n\\twidget setScrollDeltas.\\n\\twidget color: self color darker darker.\\n\\t^ widget! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 17:30'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\nowner _ nil.\\n\\tsubmorphs _ EmptyArray.\\n\\tbounds _ self defaultBounds.\\n\\t\\n\\tcolor _ self defaultColor! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'ar 1/31/2001 13:57'!\\nintoWorld: aWorld\\n\\t\\\"The receiver has just appeared in a new world. Note:\\n\\t\\t* aWorld can be nil (due to optimizations in other places)\\n\\t\\t* owner is already set\\n\\t\\t* owner's submorphs may not include receiver yet.\\n\\tImportant: Keep this method fast - it is run whenever morphs are added.\\\"\\n\\taWorld ifNil:[^self].\\n\\tself wantsSteps ifTrue:[aWorld startStepping: self].\\n\\tself submorphsDo:[:m| m intoWorld: aWorld].\\n! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'RAA 10/18/2000 12:33'!\\nopenCenteredInWorld\\n\\n\\tself \\n\\t\\tfullBounds;\\n\\t\\tposition: Display extent - self extent // 2;\\n\\t\\topenInWorld.! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'sw 3/21/2000 14:46'!\\nopenInHand\\n\\t\\\"Attach the receiver to the current hand in the current morphic world\\\"\\n\\n\\tself currentHand attachMorph: self! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'jm 7/5/1998 12:40'!\\nopenInMVC\\n\\n\\tMorphWorldView\\n\\t\\topenWorldWith: self\\n\\t\\tlabelled: self defaultLabelForInspector.\\n! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'djp 10/24/1999 17:13'!\\nopenInWindow\\n\\n\\t^self openInWindowLabeled: self defaultLabelForInspector\\n! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'sma 4/22/2000 20:28'!\\nopenInWindowLabeled: aString\\n\\n\\t^self openInWindowLabeled: aString inWorld: self currentWorld! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'RAA 5/25/2000 08:12'!\\nopenInWindowLabeled: aString inWorld: aWorld\\n\\n\\t| window extent |\\n\\n\\twindow _ (SystemWindow labelled: aString) model: nil.\\n\\twindow \\n\\t\\t\\\" guess at initial extent\\\"\\n\\t\\tbounds: (RealEstateAgent initialFrameFor: window initialExtent: self fullBounds extent world: aWorld);\\n\\t\\taddMorph: self frame: (0@0 extent: 1@1);\\n\\t\\tupdatePaneColors.\\n\\t\\\" calculate extent after adding in case any size related attributes were changed. Use\\n\\tfullBounds in order to trigger re-layout of layout morphs\\\"\\n\\textent _ self fullBounds extent + \\n\\t\\t\\t(window borderWidth@window labelHeight) + window borderWidth.\\n\\twindow extent: extent.\\n\\taWorld addMorph: window.\\n\\twindow activate.\\n\\taWorld startSteppingSubmorphsOf: window.\\n\\t^window\\n! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'RAA 6/14/2000 18:09'!\\nopenInWorld\\n \\\"Add this morph to the world. If in MVC, then provide a Morphic window for it.\\\"\\n\\n self couldOpenInMorphic\\n ifTrue: [self openInWorld: self currentWorld]\\n ifFalse: [self openInMVC]! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'dgd 9/1/2004 16:12'!\\nopenInWorld: aWorld\\n\\t\\\"Add this morph to the requested World.\\\"\\n\\t(aWorld visibleClearArea origin ~= (0@0) and: [self position = (0@0)]) ifTrue:\\n\\t\\t[self position: aWorld visibleClearArea origin].\\n\\taWorld addMorph: self.\\n\\taWorld startSteppingSubmorphsOf: self! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'ar 1/31/2001 13:58'!\\noutOfWorld: aWorld\\n\\t\\\"The receiver has just appeared in a new world. Notes:\\n\\t\\t* aWorld can be nil (due to optimizations in other places)\\n\\t\\t* owner is still valid\\n\\tImportant: Keep this method fast - it is run whenever morphs are removed.\\\"\\n\\taWorld ifNil:[^self].\\n\\t\\\"ar 1/31/2001: We could explicitly stop stepping the receiver here but for the sake of speed I'm for now relying on the lazy machinery in the world itself.\\\"\\n\\t\\\"aWorld stopStepping: self.\\\"\\n\\tself submorphsDo:[:m| m outOfWorld: aWorld].\\n! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'ar 3/3/2001 15:28'!\\nresourceJustLoaded\\n\\t\\\"In case resource relates to me\\\"\\n\\tself releaseCachedState.! !\\n\\n!Morph methodsFor: 'initialization' stamp: 'sw 9/11/1998 11:13'!\\nstandardPalette\\n\\t\\\"Answer a standard palette forced by some level of enclosing presenter, or nil if none\\\"\\n\\t| pal aPresenter itsOwner |\\n\\t(aPresenter _ self presenter) ifNil: [^ nil].\\n\\t^ (pal _ aPresenter ownStandardPalette)\\n\\t\\tifNotNil: [pal]\\n\\t\\tifNil:\\t[(itsOwner _ aPresenter associatedMorph owner)\\n\\t\\t\\t\\t\\tifNotNil:\\n\\t\\t\\t\\t\\t\\t[itsOwner standardPalette]\\n\\t\\t\\t\\t\\tifNil:\\n\\t\\t\\t\\t\\t\\t[nil]]! !\\n\\n\\n!Morph methodsFor: 'latter day support' stamp: 'sw 1/6/2005 01:26'!\\nisEtoyReadout\\n\\t\\\"Answer whether the receiver can serve as an etoy readout\\\"\\n\\n\\t^ false! !\\n\\n\\n!Morph methodsFor: 'layout' stamp: 'ar 11/12/2000 17:33'!\\nacceptDroppingMorph: aMorph event: evt\\n\\t\\\"This message is sent when a morph is dropped onto a morph that has agreed to accept the dropped morph by responding 'true' to the wantsDroppedMorph:Event: message. This default implementation just adds the given morph to the receiver.\\\"\\n\\t| layout |\\n\\tlayout _ self layoutPolicy.\\n\\tlayout ifNil:[^self addMorph: aMorph].\\n\\tself privateAddMorph: aMorph \\n\\t\\tatIndex: (layout indexForInserting: aMorph at: evt position in: self).! !\\n\\n!Morph methodsFor: 'layout' stamp: 'ar 11/12/2000 17:34'!\\nadjustLayoutBounds\\n\\t\\\"Adjust the receivers bounds depending on the resizing strategy imposed\\\"\\n\\t| hFit vFit box myExtent extent |\\n\\thFit _ self hResizing.\\n\\tvFit _ self vResizing.\\n\\t(hFit == #shrinkWrap or:[vFit == #shrinkWrap]) ifFalse:[^self]. \\\"not needed\\\"\\n\\tbox _ self layoutBounds.\\n\\tmyExtent _ box extent.\\n\\textent _ self submorphBounds corner - box origin.\\n\\thFit == #shrinkWrap ifTrue:[myExtent _ extent x @ myExtent y].\\n\\tvFit == #shrinkWrap ifTrue:[myExtent _ myExtent x @ extent y].\\n\\t\\\"Make sure we don't get smaller than minWidth/minHeight\\\"\\n\\tmyExtent x < self minWidth ifTrue:[\\n\\t\\tmyExtent _ (myExtent x max: \\n\\t\\t\\t(self minWidth - self bounds width + self layoutBounds width)) @ myExtent y].\\n\\tmyExtent y < self minHeight ifTrue:[\\n\\t\\tmyExtent _ myExtent x @ (myExtent y max:\\n\\t\\t\\t(self minHeight - self bounds height + self layoutBounds height))].\\n\\tself layoutBounds: (box origin extent: myExtent).! !\\n\\n!Morph methodsFor: 'layout' stamp: 'dgd 2/22/2003 14:31'!\\ndoLayoutIn: layoutBounds \\n\\t\\\"Compute a new layout based on the given layout bounds.\\\"\\n\\n\\t\\\"Note: Testing for #bounds or #layoutBounds would be sufficient to\\n\\tfigure out if we need an invalidation afterwards but #outerBounds\\n\\tis what we need for all leaf nodes so we use that.\\\"\\n\\n\\t| layout box priorBounds |\\n\\tpriorBounds := self outerBounds.\\n\\tsubmorphs isEmpty ifTrue: [^fullBounds := priorBounds].\\n\\t\\\"Send #ownerChanged to our children\\\"\\n\\tsubmorphs do: [:m | m ownerChanged].\\n\\tlayout := self layoutPolicy.\\n\\tlayout ifNotNil: [layout layout: self in: layoutBounds].\\n\\tself adjustLayoutBounds.\\n\\tfullBounds := self privateFullBounds.\\n\\tbox := self outerBounds.\\n\\tbox = priorBounds \\n\\t\\tifFalse: [self invalidRect: (priorBounds quickMerge: box)]! !\\n\\n!Morph methodsFor: 'layout' stamp: 'ar 1/1/2002 20:00'!\\nfullBounds\\n\\t\\\"Return the bounding box of the receiver and all its children. Recompute the layout if necessary.\\\"\\n\\tfullBounds ifNotNil:[^fullBounds].\\n\\t\\\"Errors at this point can be critical so make sure we catch 'em all right\\\"\\n\\t[self doLayoutIn: self layoutBounds] on: Error do:[:ex|\\n\\t\\t\\\"This should do it unless you don't screw up the bounds\\\"\\n\\t\\tfullBounds _ bounds.\\n\\t\\tex pass].\\n\\t^fullBounds! !\\n\\n!Morph methodsFor: 'layout' stamp: 'ar 11/12/2000 23:10'!\\nlayoutBounds\\n\\t\\\"Return the bounds for laying out children of the receiver\\\"\\n\\t| inset box |\\n\\tinset _ self layoutInset.\\n\\tbox _ self innerBounds.\\n\\tinset isZero ifTrue:[^box].\\n\\t^box insetBy: inset.! !\\n\\n!Morph methodsFor: 'layout' stamp: 'ar 10/31/2000 21:09'!\\nlayoutBounds: aRectangle\\n\\t\\\"Set the bounds for laying out children of the receiver.\\n\\tNote: written so that #layoutBounds can be changed without touching this method\\\"\\n\\t| outer inner |\\n\\touter _ self bounds.\\n\\tinner _ self layoutBounds.\\n\\tbounds _ aRectangle origin + (outer origin - inner origin) corner:\\n\\t\\t\\t\\taRectangle corner + (outer corner - inner corner).! !\\n\\n!Morph methodsFor: 'layout' stamp: 'ar 1/27/2001 14:41'!\\nlayoutChanged\\n\\t| layout |\\n\\tfullBounds ifNil:[^self]. \\\"layout will be recomputed so don't bother\\\"\\n\\tfullBounds _ nil.\\n\\tlayout _ self layoutPolicy.\\n\\tlayout ifNotNil:[layout flushLayoutCache].\\n\\towner ifNotNil: [owner layoutChanged].\\n\\t\\\"note: does not send #ownerChanged here - we'll do this when computing the new layout\\\"! !\\n\\n!Morph methodsFor: 'layout' stamp: 'ar 8/6/2001 09:55'!\\nlayoutInBounds: cellBounds\\n\\t\\\"Layout specific. Apply the given bounds to the receiver after being layed out in its owner.\\\"\\n\\t| box aSymbol delta |\\n\\tfullBounds ifNil:[\\\"We are getting new bounds here but we haven't computed the receiver's layout yet. Although the receiver has reported its minimal size before the actual size it has may differ from what would be after the layout. Normally, this isn't a real problem, but if we have #shrinkWrap constraints then the receiver's bounds may be larger than the cellBounds. THAT is a problem because the centering may not work correctly if the receiver shrinks after the owner layout has been computed. To avoid this problem, we compute the receiver's layout now. Note that the layout computation is based on the new cell bounds rather than the receiver's current bounds.\\\"\\n\\t\\tcellBounds origin = self bounds origin ifFalse:[\\n\\t\\t\\tbox _ self outerBounds.\\n\\t\\t\\tdelta _ cellBounds origin - self bounds origin.\\n\\t\\t\\tself invalidRect: (box merge: (box translateBy: delta)).\\n\\t\\t\\tself privateFullMoveBy: delta]. \\\"sigh...\\\"\\n\\t\\tbox _ cellBounds origin extent: \\\"adjust for #rigid receiver\\\"\\n\\t\\t\\t(self hResizing == #rigid ifTrue:[self bounds extent x] ifFalse:[cellBounds extent x]) @\\n\\t\\t\\t(self vResizing == #rigid ifTrue:[self bounds extent y] ifFalse:[cellBounds extent y]).\\n\\t\\t\\\"Compute inset of layout bounds\\\"\\n\\t\\tbox _ box origin - (self bounds origin - self layoutBounds origin) corner:\\n\\t\\t\\t\\t\\tbox corner - (self bounds corner - self layoutBounds corner).\\n\\t\\t\\\"And do the layout within the new bounds\\\"\\n\\t\\tself layoutBounds: box.\\n\\t\\tself doLayoutIn: box].\\n\\tcellBounds = self fullBounds ifTrue:[^self]. \\\"already up to date\\\"\\n\\tcellBounds extent = self fullBounds extent \\\"nice fit\\\"\\n\\t\\tifTrue:[^self position: cellBounds origin].\\n\\tbox _ bounds.\\n\\t\\\"match #spaceFill constraints\\\"\\n\\tself hResizing == #spaceFill \\n\\t\\tifTrue:[box _ box origin extent: cellBounds width @ box height].\\n\\tself vResizing == #spaceFill\\n\\t\\tifTrue:[box _ box origin extent: box width @ cellBounds height].\\n\\t\\\"align accordingly\\\"\\n\\taSymbol _ (owner ifNil:[self]) cellPositioning.\\n\\tbox _ box align: (box perform: aSymbol) with: (cellBounds perform: aSymbol).\\n\\t\\\"and install new bounds\\\"\\n\\tself bounds: box.! !\\n\\n!Morph methodsFor: 'layout' stamp: 'ar 11/12/2000 17:35'!\\nlayoutProportionallyIn: newBounds\\n\\t\\\"Layout specific. Apply the given bounds to the receiver.\\\"\\n\\t| box frame |\\n\\tframe _ self layoutFrame ifNil:[^self].\\n\\t\\\"before applying the proportional values make sure the receiver's layout is computed\\\"\\n\\tself fullBounds. \\\"sigh...\\\"\\n\\t\\\"compute the cell size the receiver has given its layout frame\\\"\\n\\tbox _ frame layout: self bounds in: newBounds.\\n\\t(box = self bounds) ifTrue:[^self]. \\\"no change\\\"\\n\\t^self layoutInBounds: box.! !\\n\\n!Morph methodsFor: 'layout' stamp: 'dgd 2/22/2003 14:32'!\\nminExtent\\n\\t\\\"Layout specific. Return the minimum size the receiver can be represented in.\\n\\tImplementation note: When this message is sent from an owner trying to lay out its children it will traverse down the morph tree and recompute the minimal arrangement of the morphs based on which the minimal extent is returned. When a morph with some layout strategy is encountered, the morph will ask its strategy to compute the new arrangement. However, since the final size given to the receiver is unknown at the point of the query, the assumption is made that the current bounds of the receiver are the base on which the layout should be computed. This scheme prevents strange layout changes when for instance, a table is contained in another table. Unless the inner table has been resized manually (which means its bounds are already enlarged) the arrangement of the inner table will not change here. Thus the entire layout computation is basically an iterative process which may have different results depending on the incremental changes applied.\\\"\\n\\n\\t| layout minExtent extra hFit vFit |\\n\\thFit := self hResizing.\\n\\tvFit := self vResizing.\\n\\t(hFit == #spaceFill or: [vFit == #spaceFill]) \\n\\t\\tifFalse: \\n\\t\\t\\t[\\\"The receiver will not adjust to parents layout by growing or shrinking,\\n\\t\\twhich means that an accurate layout defines the minimum size.\\\"\\n\\n\\t\\t\\t^self fullBounds extent].\\n\\n\\t\\\"An exception -- a receiver with #shrinkWrap constraints but no children is being treated #rigid (the equivalent to a #spaceFill receiver in a non-layouting owner)\\\"\\n\\tself hasSubmorphs \\n\\t\\tifFalse: \\n\\t\\t\\t[hFit == #shrinkWrap ifTrue: [hFit := #rigid].\\n\\t\\t\\tvFit == #shrinkWrap ifTrue: [vFit := #rigid]].\\n\\tlayout := self layoutPolicy.\\n\\tlayout isNil \\n\\t\\tifTrue: [minExtent := 0 @ 0]\\n\\t\\tifFalse: [minExtent := layout minExtentOf: self in: self layoutBounds].\\n\\thFit == #rigid \\n\\t\\tifTrue: [minExtent := self fullBounds extent x @ minExtent y]\\n\\t\\tifFalse: \\n\\t\\t\\t[extra := self bounds width - self layoutBounds width.\\n\\t\\t\\tminExtent := (minExtent x + extra) @ minExtent y].\\n\\tminExtent := vFit == #rigid \\n\\t\\t\\t\\tifTrue: [minExtent x @ self fullBounds extent y]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[extra := self bounds height - self layoutBounds height.\\n\\t\\t\\t\\t\\tminExtent x @ (minExtent y + extra)].\\n\\tminExtent := minExtent max: self minWidth @ self minHeight.\\n\\t^minExtent! !\\n\\n!Morph methodsFor: 'layout' stamp: 'dgd 2/16/2003 21:52'!\\nminHeight\\n\\t\\\"answer the receiver's minHeight\\\"\\n\\t^ self\\n\\t\\tvalueOfProperty: #minHeight\\n\\t\\tifAbsent: [2]! !\\n\\n!Morph methodsFor: 'layout' stamp: 'dgd 2/22/2003 14:32'!\\nminHeight: aNumber \\n\\taNumber isNil \\n\\t\\tifTrue: [self removeProperty: #minHeight]\\n\\t\\tifFalse: [self setProperty: #minHeight toValue: aNumber].\\n\\tself layoutChanged! !\\n\\n!Morph methodsFor: 'layout' stamp: 'dgd 2/16/2003 21:54'!\\nminWidth\\n\\t\\\"answer the receiver's minWidth\\\"\\n\\t^ self\\n\\t\\tvalueOfProperty: #minWidth\\n\\t\\tifAbsent: [2]! !\\n\\n!Morph methodsFor: 'layout' stamp: 'dgd 2/22/2003 14:32'!\\nminWidth: aNumber \\n\\taNumber isNil \\n\\t\\tifTrue: [self removeProperty: #minWidth]\\n\\t\\tifFalse: [self setProperty: #minWidth toValue: aNumber].\\n\\tself layoutChanged! !\\n\\n!Morph methodsFor: 'layout' stamp: 'dgd 2/22/2003 14:33'!\\nprivateFullBounds\\n\\t\\\"Private. Compute the actual full bounds of the receiver\\\"\\n\\n\\t| box |\\n\\tsubmorphs isEmpty ifTrue: [^self outerBounds].\\n\\tbox := self outerBounds copy.\\n\\tbox := box quickMerge: (self clipSubmorphs \\n\\t\\t\\t\\t\\t\\tifTrue: [self submorphBounds intersect: self clippingBounds]\\n\\t\\t\\t\\t\\t\\tifFalse: [self submorphBounds]).\\n\\t^box origin asIntegerPoint corner: box corner asIntegerPoint! !\\n\\n!Morph methodsFor: 'layout' stamp: 'ar 11/2/2000 17:42'!\\nsubmorphBounds\\n\\t\\\"Private. Compute the actual full bounds of the receiver\\\"\\n\\t| box subBox |\\n\\tsubmorphs do: [:m | \\n\\t\\t(m visible) ifTrue: [\\n\\t\\t\\tsubBox _ m fullBounds.\\n\\t\\t\\tbox \\n\\t\\t\\t\\tifNil:[box _ subBox copy]\\n\\t\\t\\t\\tifNotNil:[box _ box quickMerge: subBox]]].\\n\\tbox ifNil:[^self bounds]. \\\"e.g., having submorphs but not visible\\\"\\n\\t^ box origin asIntegerPoint corner: box corner asIntegerPoint\\n! !\\n\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 8/30/2003 16:57'!\\naddCellLayoutMenuItems: aMenu hand: aHand\\n\\t\\\"Cell (e.g., child) related items\\\"\\n\\t| menu sub |\\n\\tmenu _ MenuMorph new defaultTarget: self.\\n\\t\\tmenu addUpdating: #hasDisableTableLayoutString action: #changeDisableTableLayout.\\n\\t\\tmenu addLine.\\n\\n\\t\\tsub _ MenuMorph new defaultTarget: self.\\n\\t\\t#(rigid shrinkWrap spaceFill) do:[:sym|\\n\\t\\t\\tsub addUpdating: #hResizingString: target: self selector: #hResizing: argumentList: (Array with: sym)].\\n\\t\\tmenu add:'horizontal resizing' translated subMenu: sub.\\n\\n\\t\\tsub _ MenuMorph new defaultTarget: self.\\n\\t\\t#(rigid shrinkWrap spaceFill) do:[:sym|\\n\\t\\t\\tsub addUpdating: #vResizingString: target: self selector: #vResizing: argumentList: (Array with: sym)].\\n\\t\\tmenu add:'vertical resizing' translated subMenu: sub.\\n\\n\\taMenu ifNotNil:[aMenu add: 'child layout' translated subMenu: menu].\\n\\t^menu! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 8/30/2003 16:51'!\\naddLayoutMenuItems: topMenu hand: aHand\\n\\t| aMenu |\\n\\taMenu _ MenuMorph new defaultTarget: self.\\n\\taMenu addUpdating: #hasNoLayoutString action: #changeNoLayout.\\n\\taMenu addUpdating: #hasProportionalLayoutString action: #changeProportionalLayout.\\n\\taMenu addUpdating: #hasTableLayoutString action: #changeTableLayout.\\n\\taMenu addLine.\\n\\taMenu add: 'change layout inset...' translated action: #changeLayoutInset:.\\n\\taMenu addLine.\\n\\tself addCellLayoutMenuItems: aMenu hand: aHand.\\n\\tself addTableLayoutMenuItems: aMenu hand: aHand.\\n\\ttopMenu ifNotNil:[topMenu add: 'layout' translated subMenu: aMenu].\\n\\t^aMenu! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 8/30/2003 20:07'!\\naddTableLayoutMenuItems: aMenu hand: aHand\\n\\t| menu sub |\\n\\tmenu _ MenuMorph new defaultTarget: self.\\n\\tmenu addUpdating: #hasReverseCellsString action: #changeReverseCells.\\n\\tmenu addUpdating: #hasClipLayoutCellsString action: #changeClipLayoutCells.\\n\\tmenu addUpdating: #hasRubberBandCellsString action: #changeRubberBandCells.\\n\\tmenu addLine.\\n\\tmenu add: 'change cell inset...' translated action: #changeCellInset:.\\n\\tmenu add: 'change min cell size...' translated action: #changeMinCellSize:.\\n\\tmenu add: 'change max cell size...' translated action: #changeMaxCellSize:.\\n\\tmenu addLine.\\n\\n\\tsub _ MenuMorph new defaultTarget: self.\\n\\t#(leftToRight rightToLeft topToBottom bottomToTop) do:[:sym|\\n\\t\\tsub addUpdating: #listDirectionString: target: self selector: #changeListDirection: argumentList: (Array with: sym)].\\n\\tmenu add: 'list direction' translated subMenu: sub.\\n\\n\\tsub _ MenuMorph new defaultTarget: self.\\n\\t#(none leftToRight rightToLeft topToBottom bottomToTop) do:[:sym|\\n\\t\\tsub addUpdating: #wrapDirectionString: target: self selector: #wrapDirection: argumentList: (Array with: sym)].\\n\\tmenu add: 'wrap direction' translated subMenu: sub.\\n\\n\\tsub _ MenuMorph new defaultTarget: self.\\n\\t#(center topLeft topRight bottomLeft bottomRight topCenter leftCenter rightCenter bottomCenter) do:[:sym|\\n\\t\\tsub addUpdating: #cellPositioningString: target: self selector: #cellPositioning: argumentList: (Array with: sym)].\\n\\tmenu add: 'cell positioning' translated subMenu: sub.\\n\\n\\tsub _ MenuMorph new defaultTarget: self.\\n\\t#(topLeft bottomRight center justified) do:[:sym|\\n\\t\\tsub addUpdating: #listCenteringString: target: self selector: #listCentering: argumentList: (Array with: sym)].\\n\\tmenu add: 'list centering' translated subMenu: sub.\\n\\n\\tsub _ MenuMorph new defaultTarget: self.\\n\\t#(topLeft bottomRight center justified) do:[:sym|\\n\\t\\tsub addUpdating: #wrapCenteringString: target: self selector: #wrapCentering: argumentList: (Array with: sym)].\\n\\tmenu add: 'wrap centering' translated subMenu: sub.\\n\\n\\tsub _ MenuMorph new defaultTarget: self.\\n\\t#(none equal) do:[:sym|\\n\\t\\tsub addUpdating: #listSpacingString: target: self selector: #listSpacing: argumentList: (Array with: sym)].\\n\\tmenu add: 'list spacing' translated subMenu: sub.\\n\\n\\tsub _ MenuMorph new defaultTarget: self.\\n\\t#(none localRect localSquare globalRect globalSquare) do:[:sym|\\n\\t\\tsub addUpdating: #cellSpacingString: target: self selector: #cellSpacing: argumentList: (Array with: sym)].\\n\\tmenu add: 'cell spacing' translated subMenu: sub.\\n\\n\\taMenu ifNotNil:[aMenu add: 'table layout' translated subMenu: menu].\\n\\t^menu! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 11/13/2000 19:08'!\\nchangeCellInset: evt\\n\\t| handle |\\n\\thandle _ HandleMorph new forEachPointDo:[:newPoint |\\n\\t\\tself cellInset: (newPoint - evt cursorPoint) asIntegerPoint // 5].\\n\\tevt hand attachMorph: handle.\\n\\thandle startStepping.\\n! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 11/13/2000 18:54'!\\nchangeClipLayoutCells\\n\\tself invalidRect: self fullBounds.\\n\\tself clipLayoutCells: self clipLayoutCells not.\\n\\tself invalidRect: self fullBounds.! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 10/31/2000 19:19'!\\nchangeDisableTableLayout\\n\\tself disableTableLayout: self disableTableLayout not.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 11/13/2000 19:09'!\\nchangeLayoutInset: evt\\n\\t| handle |\\n\\thandle _ HandleMorph new forEachPointDo:[:newPoint |\\n\\t\\tself layoutInset: (newPoint - evt cursorPoint) asIntegerPoint // 5].\\n\\tevt hand attachMorph: handle.\\n\\thandle startStepping.\\n! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 11/13/2000 19:10'!\\nchangeListDirection: aSymbol\\n\\t| listDir wrapDir |\\n\\tself listDirection: aSymbol.\\n\\t(self wrapDirection == #none) ifTrue:[^self].\\n\\t\\\"otherwise automatically keep a valid table layout\\\"\\n\\tlistDir _ self listDirection.\\n\\twrapDir _ self wrapDirection.\\n\\t(listDir == #leftToRight or:[listDir == #rightToLeft]) ifTrue:[\\n\\t\\twrapDir == #leftToRight ifTrue:[^self wrapDirection: #topToBottom].\\n\\t\\twrapDir == #rightToLeft ifTrue:[^self wrapDirection: #bottomToTop].\\n\\t] ifFalse:[\\n\\t\\twrapDir == #topToBottom ifTrue:[^self wrapDirection: #leftToRight].\\n\\t\\twrapDir == #bottomToTop ifTrue:[^self wrapDirection: #rightToLeft].\\n\\t].\\n! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 11/13/2000 19:10'!\\nchangeMaxCellSize: evt\\n\\t| handle |\\n\\thandle _ HandleMorph new forEachPointDo:[:newPoint |\\n\\t\\tself maxCellSize: (newPoint - evt cursorPoint) asIntegerPoint].\\n\\tevt hand attachMorph: handle.\\n\\thandle startStepping.\\n! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 11/13/2000 19:10'!\\nchangeMinCellSize: evt\\n\\t| handle |\\n\\thandle _ HandleMorph new forEachPointDo:[:newPoint |\\n\\t\\tself minCellSize: (newPoint - evt cursorPoint) asIntegerPoint].\\n\\tevt hand attachMorph: handle.\\n\\thandle startStepping.\\n! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 10/31/2000 19:19'!\\nchangeNoLayout\\n\\tself layoutPolicy ifNil:[^self]. \\\"already no layout\\\"\\n\\tself layoutPolicy: nil.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 10/31/2000 19:19'!\\nchangeProportionalLayout\\n\\t| layout |\\n\\t((layout _ self layoutPolicy) notNil and:[layout isProportionalLayout])\\n\\t\\tifTrue:[^self]. \\\"already proportional layout\\\"\\n\\tself layoutPolicy: ProportionalLayout new.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 11/13/2000 19:10'!\\nchangeReverseCells\\n\\tself reverseTableCells: self reverseTableCells not.! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 11/13/2000 19:10'!\\nchangeRubberBandCells\\n\\tself rubberBandCells: self rubberBandCells not.! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'ar 10/31/2000 19:20'!\\nchangeTableLayout\\n\\t| layout |\\n\\t((layout _ self layoutPolicy) notNil and:[layout isTableLayout])\\n\\t\\tifTrue:[^self]. \\\"already table layout\\\"\\n\\tself layoutPolicy: TableLayout new.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 8/30/2003 20:09'!\\nhasClipLayoutCellsString\\n\\t^ (self clipLayoutCells\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>']), 'clip to cell size' translated! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 8/30/2003 16:58'!\\nhasDisableTableLayoutString\\n\\t^ (self disableTableLayout\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'disable layout in tables' translated! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 10/8/2003 19:23'!\\nhasNoLayoutString\\n\\t^ (self layoutPolicy isNil\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'no layout' translated! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 8/30/2003 16:55'!\\nhasProportionalLayoutString\\n\\t| layout |\\n\\t^ (((layout := self layoutPolicy) notNil\\n\\t\\t\\tand: [layout isProportionalLayout])\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'proportional layout' translated! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 8/30/2003 20:08'!\\nhasReverseCellsString\\n\\t^ (self reverseTableCells\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>']), 'reverse table cells' translated! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 8/30/2003 20:09'!\\nhasRubberBandCellsString\\n\\t^ (self rubberBandCells\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>']), 'rubber band cells' translated! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 8/30/2003 16:59'!\\nhasTableLayoutString\\n\\t| layout |\\n\\t^ (((layout := self layoutPolicy) notNil\\n\\t\\t\\tand: [layout isTableLayout])\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'table layout' translated! !\\n\\n!Morph methodsFor: 'layout-menu' stamp: 'dgd 10/19/2003 11:23'!\\nlayoutMenuPropertyString: aSymbol from: currentSetting \\n\\t| onOff wording |\\n\\tonOff := aSymbol == currentSetting\\n\\t\\t\\t\\tifTrue: ['<on>']\\n\\t\\t\\t\\tifFalse: ['<off>'].\\n\\t\\\"\\\"\\n\\twording := String\\n\\t\\t\\t\\tstreamContents: [:stream | \\n\\t\\t\\t\\t\\t| index | \\n\\t\\t\\t\\t\\tindex := 1.\\n\\t\\t\\t\\t\\taSymbol\\n\\t\\t\\t\\t\\t\\tkeysAndValuesDo: [:idx :ch | ch isUppercase\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [\\\"\\\"stream nextPutAll: (aSymbol copyFrom: index to: idx - 1) asLowercase.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tstream nextPutAll: ' '.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tindex := idx]].\\n\\t\\t\\t\\t\\tindex < aSymbol size\\n\\t\\t\\t\\t\\t\\tifTrue: [stream nextPutAll: (aSymbol copyFrom: index to: aSymbol size) asLowercase]].\\n\\t\\\"\\\"\\n\\t^ onOff , wording translated! !\\n\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/14/2000 17:56'!\\nassureLayoutProperties\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\tprops == self ifTrue:[props _ nil].\\n\\tprops ifNil:[\\n\\t\\tprops _ LayoutProperties new initializeFrom: self.\\n\\t\\tself layoutProperties: props].\\n\\t^props! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/14/2000 17:57'!\\nassureTableProperties\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\tprops == self ifTrue:[props _ nil].\\n\\tprops ifNil:[\\n\\t\\tprops _ TableLayoutProperties new initializeFrom: self.\\n\\t\\tself layoutProperties: props].\\n\\tprops includesTableProperties \\n\\t\\tifFalse:[self layoutProperties: (props _ props asTableLayoutProperties)].\\n\\t^props! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:54'!\\ncellInset\\n\\t\\\"Layout specific. This property specifies an extra inset for each cell in the layout.\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[0] ifNotNil:[props cellInset].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:54'!\\ncellInset: aNumber\\n\\t\\\"Layout specific. This property specifies an extra inset for each cell in the layout.\\\"\\n\\tself assureTableProperties cellInset: aNumber.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:54'!\\ncellPositioning\\n\\t\\\"Layout specific. This property describes how the receiver should be layed out in its owner when the bounds of the cell assigned to the receiver do not exactly match its bounds. Possible values are:\\n\\t\\t#topLeft, #topRight, #bottomLeft, #bottomRight, #topCenter, #leftCenter, #rightCenter, #bottomCenter, #center \\n\\twhich align the receiver's bounds with the cell at the given point.\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[#center] ifNotNil:[props cellPositioning].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 10/29/2000 02:48'!\\ncellPositioningString: aSymbol\\n\\t^self layoutMenuPropertyString: aSymbol from: self cellPositioning! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/14/2000 17:39'!\\ncellPositioning: aSymbol\\n\\t\\\"Layout specific. This property describes how the receiver should be layed out in its owner when the bounds of the cell assigned to the receiver do not exactly match its bounds. Possible values are:\\n\\t\\t#topLeft, #topRight, #bottomLeft, #bottomRight, #topCenter, #leftCenter, #rightCenter, #bottomCenter, #center \\n\\twhich align the receiver's bounds with the cell at the given point.\\\"\\n\\tself assureTableProperties cellPositioning: aSymbol.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:55'!\\ncellSpacing\\n\\t\\\"Layout specific. This property describes how the cell size for each element in a list should be computed.\\n\\t\\t#globalRect - globally equal rectangular cells\\n\\t\\t#globalSquare - globally equal square cells\\n\\t\\t#localRect - locally (e.g., per row/column) equal rectangular cells\\n\\t\\t#localSquare - locally (e.g., per row/column) equal square cells\\n\\t\\t#none - cells are sized based on available row/column constraints\\n\\t\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[#none] ifNotNil:[props cellSpacing].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 10/29/2000 02:47'!\\ncellSpacingString: aSymbol\\n\\t^self layoutMenuPropertyString: aSymbol from: self cellSpacing! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:56'!\\ncellSpacing: aSymbol\\n\\t\\\"Layout specific. This property describes how the cell size for each element in a list should be computed.\\n\\t\\t#globalRect - globally equal rectangular cells\\n\\t\\t#globalSquare - globally equal square cells\\n\\t\\t#localRect - locally (e.g., per row/column) equal rectangular cells\\n\\t\\t#localSquare - locally (e.g., per row/column) equal square cells\\n\\t\\t#none - cells are sized based on available row/column constraints\\n\\t\\\"\\n\\tself assureTableProperties cellSpacing: aSymbol.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:56'!\\ndisableTableLayout\\n\\t\\\"Layout specific. Disable laying out the receiver in table layout\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[false] ifNotNil:[props disableTableLayout].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:06'!\\ndisableTableLayout: aBool\\n\\t\\\"Layout specific. Disable laying out the receiver in table layout\\\"\\n\\tself assureLayoutProperties disableTableLayout: aBool.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:57'!\\nhResizing\\n\\t\\\"Layout specific. This property describes how the receiver should be resized with respect to its owner and its children. Possible values are:\\n\\t\\t#rigid\\t\\t\\t-\\tdo not resize the receiver\\n\\t\\t#spaceFill\\t\\t-\\tresize to fill owner's available space\\n\\t\\t#shrinkWrap\\t- resize to fit children\\n\\t\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[#rigid] ifNotNil:[props hResizing].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 10/31/2000 20:45'!\\nhResizingString: aSymbol\\n\\t^self layoutMenuPropertyString: aSymbol from: self hResizing! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:06'!\\nhResizing: aSymbol\\n\\t\\\"Layout specific. This property describes how the receiver should be resized with respect to its owner and its children. Possible values are:\\n\\t\\t#rigid\\t\\t\\t-\\tdo not resize the receiver\\n\\t\\t#spaceFill\\t\\t-\\tresize to fill owner's available space\\n\\t\\t#shrinkWrap\\t- resize to fit children\\n\\t\\\"\\n\\tself assureLayoutProperties hResizing: aSymbol.\\n\\tself layoutChanged.\\n! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'md 2/27/2006 09:59'!\\nlayoutFrame\\n\\t\\\"Layout specific. Return the layout frame describing where the \\n\\treceiver should appear in a proportional layout\\\"\\n\\t^ extension ifNotNil: [extension layoutFrame]! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/14/2000 17:20'!\\nlayoutFrame: aLayoutFrame\\n\\t\\\"Layout specific. Return the layout frame describing where the receiver should appear in a proportional layout\\\"\\n\\tself layoutFrame == aLayoutFrame ifTrue:[^self].\\n\\tself assureExtension layoutFrame: aLayoutFrame.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/14/2000 16:38'!\\nlayoutInset\\n\\t\\\"Return the extra inset for layouts\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[0] ifNotNil:[props layoutInset].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/14/2000 16:38'!\\nlayoutInset: aNumber\\n\\t\\\"Return the extra inset for layouts\\\"\\n\\tself assureTableProperties layoutInset: aNumber.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'md 2/27/2006 10:00'!\\nlayoutPolicy\\n\\t\\\"Layout specific. Return the layout policy describing how children \\n\\tof the receiver should appear.\\\"\\n\\t^ extension ifNotNil: [ extension layoutPolicy]! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/14/2000 17:21'!\\nlayoutPolicy: aLayoutPolicy\\n\\t\\\"Layout specific. Return the layout policy describing how children of the receiver should appear.\\\"\\n\\tself layoutPolicy == aLayoutPolicy ifTrue:[^self].\\n\\tself assureExtension layoutPolicy: aLayoutPolicy.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'md 2/27/2006 09:58'!\\nlayoutProperties\\n\\t\\\"Return the current layout properties associated with the \\n\\treceiver\\\"\\n\\t^ extension ifNotNil: [ extension layoutProperties]! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/14/2000 17:21'!\\nlayoutProperties: newProperties\\n\\t\\\"Return the current layout properties associated with the receiver\\\"\\n\\tself layoutProperties == newProperties ifTrue:[^self].\\n\\tself assureExtension layoutProperties: newProperties.\\n! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:58'!\\nlistCentering\\n\\t\\\"Layout specific. This property describes how the rows/columns in a list-like layout should be centered.\\n\\t\\t#topLeft - center at start of primary direction\\n\\t\\t#bottomRight - center at end of primary direction\\n\\t\\t#center - center in the middle of primary direction\\n\\t\\t#justified - insert extra space inbetween rows/columns\\n\\t\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[#topLeft] ifNotNil:[props listCentering].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 10/29/2000 02:47'!\\nlistCenteringString: aSymbol\\n\\t^self layoutMenuPropertyString: aSymbol from: self listCentering! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:05'!\\nlistCentering: aSymbol\\n\\t\\\"Layout specific. This property describes how the rows/columns in a list-like layout should be centered.\\n\\t\\t#topLeft - center at start of primary direction\\n\\t\\t#bottomRight - center at end of primary direction\\n\\t\\t#center - center in the middle of primary direction\\n\\t\\t#justified - insert extra space inbetween rows/columns\\n\\t\\\"\\n\\tself assureTableProperties listCentering: aSymbol.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:59'!\\nlistDirection\\n\\t\\\"Layout specific. This property describes the direction in which a list-like layout should be applied. Possible values are:\\n\\t\\t#leftToRight\\n\\t\\t#rightToLeft\\n\\t\\t#topToBottom\\n\\t\\t#bottomToTop\\n\\tindicating the direction in which any layout should take place\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[#topToBottom] ifNotNil:[props listDirection].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 10/29/2000 02:47'!\\nlistDirectionString: aSymbol\\n\\t^self layoutMenuPropertyString: aSymbol from: self listDirection! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:04'!\\nlistDirection: aSymbol\\n\\t\\\"Layout specific. This property describes the direction in which a list-like layout should be applied. Possible values are:\\n\\t\\t#leftToRight\\n\\t\\t#rightToLeft\\n\\t\\t#topToBottom\\n\\t\\t#bottomToTop\\n\\tindicating the direction in which any layout should take place\\\"\\n\\tself assureTableProperties listDirection: aSymbol.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:59'!\\nlistSpacing\\n\\t\\\"Layout specific. This property describes how the heights for different rows in a table layout should be handled.\\n\\t\\t#equal - all rows have the same height\\n\\t\\t#none - all rows may have different heights\\n\\t\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[#none] ifNotNil:[props listSpacing].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 10/29/2000 02:47'!\\nlistSpacingString: aSymbol\\n\\t^self layoutMenuPropertyString: aSymbol from: self listSpacing! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:04'!\\nlistSpacing: aSymbol\\n\\t\\\"Layout specific. This property describes how the heights for different rows in a table layout should be handled.\\n\\t\\t#equal - all rows have the same height\\n\\t\\t#none - all rows may have different heights\\n\\t\\\"\\n\\tself assureTableProperties listSpacing: aSymbol.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 19:59'!\\nmaxCellSize\\n\\t\\\"Layout specific. This property specifies the maximum size of a table cell.\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[SmallInteger maxVal] ifNotNil:[props maxCellSize].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:04'!\\nmaxCellSize: aPoint\\n\\t\\\"Layout specific. This property specifies the maximum size of a table cell.\\\"\\n\\tself assureTableProperties maxCellSize: aPoint.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:00'!\\nminCellSize\\n\\t\\\"Layout specific. This property specifies the minimal size of a table cell.\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[0] ifNotNil:[props minCellSize].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:04'!\\nminCellSize: aPoint\\n\\t\\\"Layout specific. This property specifies the minimal size of a table cell.\\\"\\n\\tself assureTableProperties minCellSize: aPoint.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:01'!\\nreverseTableCells\\n\\t\\\"Layout specific. This property describes if the cells should be treated in reverse order of submorphs.\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[false] ifNotNil:[props reverseTableCells].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:04'!\\nreverseTableCells: aBool\\n\\t\\\"Layout specific. This property describes if the cells should be treated in reverse order of submorphs.\\\"\\n\\tself assureTableProperties reverseTableCells: aBool.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:01'!\\nrubberBandCells\\n\\t\\\"Layout specific. This property describes if a parent that is #shrinkWrapped around its children should ignore any #spaceFill children. E.g., when #rubberBandCells is true, the compound layout will always stay at the smallest available size, even though some child may be able to grow.\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[false] ifNotNil:[props rubberBandCells].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:04'!\\nrubberBandCells: aBool\\n\\t\\\"Layout specific. This property describes if a parent that is #shrinkWrapped around its children should ignore any #spaceFill children. E.g., when #rubberBandCells is true, the compound layout will always stay at the smallest available size, even though some child may be able to grow.\\\"\\n\\tself assureTableProperties rubberBandCells: aBool.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'dgd 2/16/2003 20:02'!\\nspaceFillWeight\\n\\t\\\"Layout specific. This property describes the relative weight that \\n\\tshould be given to the receiver when extra space is distributed \\n\\tbetween different #spaceFill cells.\\\"\\n\\n\\t^ self\\n\\t\\tvalueOfProperty: #spaceFillWeight\\n\\t\\tifAbsent: [1]! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/15/2000 14:16'!\\nspaceFillWeight: aNumber\\n\\t\\\"Layout specific. This property describes the relative weight that should be given to the receiver when extra space is distributed between different #spaceFill cells.\\\"\\n\\taNumber = 1\\n\\t\\tifTrue:[self removeProperty: #spaceFillWeight]\\n\\t\\tifFalse:[self setProperty: #spaceFillWeight toValue: aNumber].\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'tk 10/30/2001 18:39'!\\nvResizeToFit: aBoolean\\n\\taBoolean ifTrue:[\\n\\t\\tself vResizing: #shrinkWrap.\\n\\t] ifFalse:[\\n\\t\\tself vResizing: #rigid.\\n\\t].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:02'!\\nvResizing\\n\\t\\\"Layout specific. This property describes how the receiver should be resized with respect to its owner and its children. Possible values are:\\n\\t\\t#rigid\\t\\t\\t-\\tdo not resize the receiver\\n\\t\\t#spaceFill\\t\\t-\\tresize to fill owner's available space\\n\\t\\t#shrinkWrap\\t- resize to fit children\\n\\t\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[#rigid] ifNotNil:[props vResizing].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 10/31/2000 20:45'!\\nvResizingString: aSymbol\\n\\t^self layoutMenuPropertyString: aSymbol from: self vResizing! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:03'!\\nvResizing: aSymbol\\n\\t\\\"Layout specific. This property describes how the receiver should be resized with respect to its owner and its children. Possible values are:\\n\\t\\t#rigid\\t\\t\\t-\\tdo not resize the receiver\\n\\t\\t#spaceFill\\t\\t-\\tresize to fill owner's available space\\n\\t\\t#shrinkWrap\\t- resize to fit children\\n\\t\\\"\\n\\tself assureLayoutProperties vResizing: aSymbol.\\n\\tself layoutChanged.\\n! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:02'!\\nwrapCentering\\n\\t\\\"Layout specific. This property describes how the rows/columns in a list-like layout should be centered.\\n\\t\\t#topLeft - center at start of secondary direction\\n\\t\\t#bottomRight - center at end of secondary direction\\n\\t\\t#center - center in the middle of secondary direction\\n\\t\\t#justified - insert extra space inbetween rows/columns\\n\\t\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[#topLeft] ifNotNil:[props wrapCentering].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 10/29/2000 03:00'!\\nwrapCenteringString: aSymbol\\n\\t^self layoutMenuPropertyString: aSymbol from: self wrapCentering! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:03'!\\nwrapCentering: aSymbol\\n\\t\\\"Layout specific. This property describes how the rows/columns in a list-like layout should be centered.\\n\\t\\t#topLeft - center at start of secondary direction\\n\\t\\t#bottomRight - center at end of secondary direction\\n\\t\\t#center - center in the middle of secondary direction\\n\\t\\t#justified - insert extra space inbetween rows/columns\\n\\t\\\"\\n\\tself assureTableProperties wrapCentering: aSymbol.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:03'!\\nwrapDirection\\n\\t\\\"Layout specific. This property describes the direction along which a list-like layout should be wrapped. Possible values are:\\n\\t\\t#leftToRight\\n\\t\\t#rightToLeft\\n\\t\\t#topToBottom\\n\\t\\t#bottomToTop\\n\\t\\t#none\\n\\tindicating in which direction wrapping should occur. This direction must be orthogonal to the list direction, that is if listDirection is #leftToRight or #rightToLeft then wrapDirection must be #topToBottom or #bottomToTop and vice versa.\\\"\\n\\t| props |\\n\\tprops _ self layoutProperties.\\n\\t^props ifNil:[#none] ifNotNil:[props wrapDirection].! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 10/29/2000 03:00'!\\nwrapDirectionString: aSymbol\\n\\t^self layoutMenuPropertyString: aSymbol from: self wrapDirection ! !\\n\\n!Morph methodsFor: 'layout-properties' stamp: 'ar 11/13/2000 20:03'!\\nwrapDirection: aSymbol\\n\\t\\\"Layout specific. This property describes the direction along which a list-like layout should be wrapped. Possible values are:\\n\\t\\t#leftToRight\\n\\t\\t#rightToLeft\\n\\t\\t#topToBottom\\n\\t\\t#bottomToTop\\n\\t\\t#none\\n\\tindicating in which direction wrapping should occur. This direction must be orthogonal to the list direction, that is if listDirection is #leftToRight or #rightToLeft then wrapDirection must be #topToBottom or #bottomToTop and vice versa.\\\"\\n\\tself assureTableProperties wrapDirection: aSymbol.\\n\\tself layoutChanged.\\n! !\\n\\n\\n!Morph methodsFor: 'macpal' stamp: 'sw 5/17/2001 17:57'!\\ncurrentVocabulary\\n\\t\\\"Answer the receiver's current vocabulary\\\"\\n\\n\\t| outer |\\n\\t^ (outer _ self ownerThatIsA: StandardViewer orA: ScriptEditorMorph) \\n\\t\\t\\tifNotNil:\\n\\t\\t\\t\\t[outer currentVocabulary]\\n\\t\\t\\tifNil:\\n\\t\\t\\t\\t[super currentVocabulary]! !\\n\\n!Morph methodsFor: 'macpal' stamp: 'sw 10/10/1999 10:23'!\\nflash\\n\\t| c w |\\n\\tc _ self color.\\n\\tself color: Color black.\\n\\t(w _ self world) ifNotNil: [w displayWorldSafely].\\n\\tself color: c\\n! !\\n\\n!Morph methodsFor: 'macpal' stamp: 'sw 7/20/1999 08:13'!\\nscriptPerformer\\n\\t^ self topRendererOrSelf player ifNil: [self]! !\\n\\n\\n!Morph methodsFor: 'menu' stamp: 'sw 11/27/2001 15:21'!\\naddBorderStyleMenuItems: aMenu hand: aHandMorph\\n\\t\\\"Probably one could offer border-style items even if it's not a borderedMorph, so this remains a loose end for the moment\\\"\\n! !\\n\\n!Morph methodsFor: 'menu' stamp: 'nk 2/15/2004 09:08'!\\naddGestureMenuItems: aMenu hand: aHandMorph\\n\\t\\\"If the receiver wishes the Genie menu items, add a line to the menu and then those Genie items, else do nothing\\\"! !\\n\\n!Morph methodsFor: 'menu' stamp: 'nk 6/15/2004 07:11'!\\naddGraphModelYellowButtonItemsTo: aCustomMenu event: evt\\n\\t^aCustomMenu! !\\n\\n!Morph methodsFor: 'menu' stamp: 'dgd 9/18/2004 17:47'!\\naddModelYellowButtonItemsTo: aCustomMenu event: evt \\n\\t\\\"Give my models a chance to add their context-menu items to \\n\\taCustomMenu.\\\"\\n\\tself model\\n\\t\\tifNotNilDo: [:mod |\\n\\t\\t\\tmod\\n\\t\\t\\t\\taddModelYellowButtonMenuItemsTo: aCustomMenu\\n\\t\\t\\t\\tforMorph: self\\n\\t\\t\\t\\thand: evt hand]! !\\n\\n!Morph methodsFor: 'menu' stamp: 'nk 3/10/2004 19:49'!\\naddMyYellowButtonMenuItemsToSubmorphMenus\\n\\t\\\"Answer true if I have items to add to the context menus of my submorphs\\\"\\n\\n\\t^true! !\\n\\n!Morph methodsFor: 'menu' stamp: 'dgd 9/13/2004 19:23'!\\naddNestedYellowButtonItemsTo: aMenu event: evt \\n\\t\\\"Add items to aMenu starting with me and proceeding down \\n\\tthrough my submorph chain, \\n\\tletting any submorphs that include the event position \\n\\tcontribute their items to the bottom of the menu, separated by \\n\\ta line.\\\"\\n\\t| underMouse |\\n\\n\\tself addYellowButtonMenuItemsTo: aMenu event: evt.\\n\\n\\tunderMouse := self\\n\\t\\t\\t\\tsubmorphThat: [:each | each containsPoint: evt position]\\n\\t\\t\\t\\tifNone: [^ self].\\n\\n\\t(underMouse addMyYellowButtonMenuItemsToSubmorphMenus\\n\\t\\t\\tand: [underMouse hasYellowButtonMenu])\\n\\t\\tifTrue: [| submenu |\\n\\t\\t\\taMenu addLine.\\n\\t\\t\\tsubmenu := MenuMorph new defaultTarget: underMouse.\\n\\t\\t\\tunderMouse addNestedYellowButtonItemsTo: submenu event: evt.\\n\\t\\t\\taMenu\\n\\t\\t\\t\\tadd: underMouse externalName\\n\\t\\t\\t\\ticon: (underMouse iconOrThumbnailOfSize: 16)\\n\\t\\t\\t\\tsubMenu: submenu\\n\\t\\t]\\n! !\\n\\n!Morph methodsFor: 'menu' stamp: 'dgd 7/28/2005 13:02'!\\naddTitleForHaloMenu: aMenu \\n\\taMenu\\n\\t\\taddTitle: self externalName\\n\\t\\ticon: (self iconOrThumbnailOfSize: (Preferences tinyDisplay ifFalse:[28] ifTrue:[16]))! !\\n\\n!Morph methodsFor: 'menu' stamp: 'dgd 10/13/2004 13:47'!\\naddYellowButtonMenuItemsTo: aMenu event: evt \\n\\t\\\"Populate aMenu with appropriate menu items for a \\n\\tyellow-button (context menu) click.\\\"\\n\\taMenu defaultTarget: self.\\n\\t\\\"\\\"\\n\\tPreferences noviceMode\\n\\t\\tifFalse: [aMenu addStayUpItem].\\n\\t\\\"\\\"\\n\\tself addModelYellowButtonItemsTo: aMenu event: evt.\\n\\t\\\"\\\"\\n\\tPreferences generalizedYellowButtonMenu\\n\\t\\tifFalse: [^ self].\\n\\t\\\"\\\"\\n\\tPreferences cmdGesturesEnabled\\n\\t\\tifTrue: [\\\"\\\"\\n\\t\\t\\taMenu addLine.\\n\\t\\t\\taMenu add: 'inspect' translated action: #inspect].\\n\\t\\\"\\\"\\n\\taMenu addLine.\\n\\tself world selectedObject == self\\n\\t\\tifTrue: [aMenu add: 'deselect' translated action: #removeHalo]\\n\\t\\tifFalse: [aMenu add: 'select' translated action: #addHalo].\\n\\t\\\"\\\"\\n\\t(self isWorldMorph\\n\\t\\t\\tor: [self mustBeBackmost]\\n\\t\\t\\tor: [self wantsToBeTopmost])\\n\\t\\tifFalse: [\\\"\\\"\\n\\t\\t\\taMenu addLine.\\n\\t\\t\\taMenu add: 'send to back' translated action: #goBehind.\\n\\t\\t\\taMenu add: 'bring to front' translated action: #comeToFront.\\n\\t\\t\\tself addEmbeddingMenuItemsTo: aMenu hand: evt hand].\\n\\t\\\"\\\"\\n\\tself isWorldMorph\\n\\t\\tifFalse: [\\\"\\\"\\n\\tSmalltalk\\n\\t\\tat: #NCAAConnectorMorph\\n\\t\\tifPresent: [:connectorClass | \\n\\t\\t\\taMenu addLine.\\n\\t\\t\\taMenu add: 'connect to' translated action: #startWiring.\\n\\t\\t\\taMenu addLine].\\n\\t\\\"\\\"\\n\\n\\t\\t\\tself isFullOnScreen\\n\\t\\t\\t\\tifFalse: [aMenu add: 'move onscreen' translated action: #goHome]].\\n\\t\\\"\\\"\\n\\tPreferences noviceMode\\n\\t\\tifFalse: [\\\"\\\"\\n\\t\\t\\tself addLayoutMenuItems: aMenu hand: evt hand.\\n\\t\\t\\t(owner notNil\\n\\t\\t\\t\\t\\tand: [owner isTextMorph])\\n\\t\\t\\t\\tifTrue: [self addTextAnchorMenuItems: aMenu hand: evt hand]].\\n\\t\\\"\\\"\\n\\tself isWorldMorph\\n\\t\\tifFalse: [\\\"\\\"\\n\\t\\t\\taMenu addLine.\\n\\t\\t\\tself addToggleItemsToHaloMenu: aMenu].\\n\\t\\\"\\\"\\n\\taMenu addLine.\\n\\tself isWorldMorph\\n\\t\\tifFalse: [aMenu add: 'copy to paste buffer' translated action: #copyToPasteBuffer:].\\n\\t(self allStringsAfter: nil) isEmpty\\n\\t\\tifFalse: [aMenu add: 'copy text' translated action: #clipText].\\n\\t\\\"\\\"\\n\\tself addExportMenuItems: aMenu hand: evt hand.\\n\\t\\\"\\\"\\n\\t(Preferences noviceMode not\\n\\t\\t\\tand: [self isWorldMorph not])\\n\\t\\tifTrue: [\\\"\\\"\\n\\t\\t\\taMenu addLine.\\n\\t\\t\\taMenu add: 'adhere to edge...' translated action: #adhereToEdge].\\n\\t\\\"\\\"\\n\\tself addCustomMenuItems: aMenu hand: evt hand! !\\n\\n!Morph methodsFor: 'menu' stamp: 'dgd 9/18/2004 17:23'!\\nbuildYellowButtonMenu: aHand \\n\\t\\\"build the morph menu for the yellow button\\\"\\n\\t| menu |\\n\\tmenu := MenuMorph new defaultTarget: self.\\n\\tself addNestedYellowButtonItemsTo: menu event: ActiveEvent.\\n\\tMenuIcons decorateMenu: menu.\\n\\t^ menu! !\\n\\n!Morph methodsFor: 'menu' stamp: 'dgd 4/4/2006 14:43'!\\nhasYellowButtonMenu\\n\\t\\\"Answer true if I have any items at all for a context (yellow \\n\\tbutton) menu.\\\"\\n\\t^ self wantsYellowButtonMenu\\n\\t\\t\\tor: [self models anySatisfy: [:each | each hasModelYellowButtonMenuItems]]! !\\n\\n!Morph methodsFor: 'menu' stamp: 'tak 7/17/2004 18:20'!\\nofferCostumeViewerMenu: aMenu\\n\\t\\\"do nothing\\\"! !\\n\\n!Morph methodsFor: 'menu' stamp: 'nk 3/10/2004 19:51'!\\noutermostOwnerWithYellowButtonMenu\\n\\t\\\"Answer me or my outermost owner that is willing to contribute menu items to a context menu.\\n\\tDon't include the world.\\\"\\n\\n\\t| outermost |\\n\\toutermost _ self outermostMorphThat: [ :ea |\\n\\t\\tea isWorldMorph not and: [ ea hasYellowButtonMenu ]].\\n\\t^outermost ifNil: [ self hasYellowButtonMenu ifTrue: [ self ] ifFalse: []] ! !\\n\\n!Morph methodsFor: 'menu' stamp: 'dgd 9/29/2004 13:26'!\\nstartWiring\\n\\tSmalltalk\\n\\t\\tat: #NCAAConnectorMorph\\n\\t\\tifPresent: [:connectorClass | connectorClass newCurvyArrow startWiringFrom: self] ! !\\n\\n!Morph methodsFor: 'menu' stamp: 'dgd 9/18/2004 18:20'!\\nwantsYellowButtonMenu\\n\\t\\\"Answer true if the receiver wants a yellow button menu\\\"\\n\\tself\\n\\t\\tvalueOfProperty: #wantsYellowButtonMenu\\n\\t\\tifPresentDo: [:value | ^ value].\\n\\t\\\"\\\"\\n\\tself isInSystemWindow\\n\\t\\tifTrue: [^ false].\\\"\\\"\\n\\t(Preferences noviceMode\\n\\t\\t\\tand: [self isInDockingBar])\\n\\t\\tifTrue: [^ false].\\\"\\\"\\n\\t^ Preferences generalizedYellowButtonMenu! !\\n\\n!Morph methodsFor: 'menu' stamp: 'dgd 9/18/2004 18:35'!\\nwantsYellowButtonMenu: aBoolean \\n\\t\\\"Change the receiver to wants or not a yellow button menu\\\"\\n\\tself setProperty: #wantsYellowButtonMenu toValue: aBoolean! !\\n\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 10/6/2004 11:38'!\\nabsorbStateFromRenderer: aRenderer \\n\\t\\\"Transfer knownName, actorState, visible, and player info over from aRenderer, which was formerly imposed above me as a transformation shell but is now going away.\\\"\\n\\n\\t| current |\\n\\t(current _ aRenderer actorStateOrNil) ifNotNil:\\n\\t\\t[self actorState: current.\\n\\t\\taRenderer actorState: nil].\\n\\n\\t(current _ aRenderer knownName) ifNotNil:\\n\\t\\t[self setNameTo: current.\\n\\t\\taRenderer setNameTo: nil].\\n\\n\\t(current _ aRenderer player) ifNotNil:\\n\\t\\t[self player: current.\\n\\t\\tcurrent rawCostume: self.\\n\\t\\taRenderer player: nil].\\n\\n\\tself visible: aRenderer visible! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 14:36'!\\naddAddHandMenuItemsForHalo: aMenu hand: aHandMorph\\n\\t\\\"The former charter of this method was to add halo menu items that pertained specifically to the hand. Over time this charter has withered, and most morphs reimplement this method simply to add their morph-specific menu items. So in the latest round, all other implementors in the standard image have been removed. However, this is left here as a hook for the benefit of existing code in client uses.\\\"\\n\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 11/15/2003 19:25'!\\naddCopyItemsTo: aMenu\\n\\t\\\"Add copy-like items to the halo menu\\\"\\n\\n\\t| subMenu |\\n\\tsubMenu _ MenuMorph new defaultTarget: self.\\n\\tsubMenu add: 'copy to paste buffer' translated action: #copyToPasteBuffer:.\\n\\tsubMenu add: 'copy text' translated action: #clipText.\\n\\tsubMenu add: 'copy Postscript' translated action: #clipPostscript.\\n\\tsubMenu add: 'print Postscript to file...' translated target: self selector: #printPSToFile.\\n\\taMenu add: 'copy & print...' translated subMenu: subMenu! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 4/27/1998 03:44'!\\naddCustomHaloMenuItems: aMenu hand: aHandMorph\\n\\t\\\"Add morph-specific items to the given menu which was invoked by the given hand from the halo. To get started, we defer to the counterpart method used with the option-menu, but in time we can have separate menu choices for halo-menus and for option-menus\\\"\\n\\n\\tself addCustomMenuItems: aMenu hand: aHandMorph! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 07:17'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\t\\\"Add morph-specific items to the given menu which was invoked by the given hand. This method provides is invoked both from the halo-menu and from the control-menu regimes.\\\"\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'nk 2/16/2004 13:29'!\\naddExportMenuItems: aMenu hand: aHandMorph\\n\\t\\\"Add export items to the menu\\\"\\n\\n\\taMenu ifNotNil:\\n\\t\\t[ | aSubMenu |\\n\\t\\taSubMenu _ MenuMorph new defaultTarget: self.\\n\\t\\taSubMenu add: 'BMP file' translated action: #exportAsBMP.\\n\\t\\taSubMenu add: 'GIF file' translated action: #exportAsGIF.\\n\\t\\taSubMenu add: 'JPEG file' translated action: #exportAsJPEG.\\n\\t\\taSubMenu add: 'PNG file' translated action: #exportAsPNG.\\n\\t\\taMenu add: 'export...' translated subMenu: aSubMenu]\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 8/30/2003 16:44'!\\naddFillStyleMenuItems: aMenu hand: aHand\\n\\t\\\"Add the items for changing the current fill style of the Morph\\\"\\n\\t| menu |\\n\\tself canHaveFillStyles ifFalse:[^aMenu add: 'change color...' translated target: self action: #changeColor].\\n\\tmenu _ MenuMorph new defaultTarget: self.\\n\\tself fillStyle addFillStyleMenuItems: menu hand: aHand from: self.\\n\\tmenu addLine.\\n\\tmenu add: 'solid fill' translated action: #useSolidFill.\\n\\tmenu add: 'gradient fill' translated action: #useGradientFill.\\n\\tmenu add: 'bitmap fill' translated action: #useBitmapFill.\\n\\tmenu add: 'default fill' translated action: #useDefaultFill.\\n\\taMenu add: 'fill style' translated subMenu: menu.\\n\\t\\\"aMenu add: 'change color...' translated action: #changeColor\\\"! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 4/12/2005 23:13'!\\naddHaloActionsTo: aMenu\\n\\t\\\"Add items to aMenu representing actions requestable via halo\\\"\\n\\n\\t| subMenu |\\n\\tsubMenu _ MenuMorph new defaultTarget: self.\\n\\tsubMenu addTitle: self externalName.\\n\\tsubMenu addStayUpItemSpecial.\\n\\tsubMenu addLine.\\n\\tsubMenu add: 'delete' translated action: #dismissViaHalo.\\n\\tsubMenu balloonTextForLastItem: 'Delete this object -- warning -- can be destructive!!' translated.\\n\\n\\tself maybeAddCollapseItemTo: subMenu.\\n\\tsubMenu add: 'grab' translated action: #openInHand.\\n\\tsubMenu balloonTextForLastItem: 'Pick this object up -- warning, since this removes it from its container, it can have adverse effects.' translated.\\n\\n\\tsubMenu addLine.\\n\\n\\tsubMenu add: 'resize' translated action: #resizeFromMenu.\\n\\tsubMenu balloonTextForLastItem: 'Change the size of this object' translated.\\n\\n\\tsubMenu add: 'duplicate' translated action: #maybeDuplicateMorph.\\n\\tsubMenu balloonTextForLastItem: 'Hand me a copy of this object' translated.\\n\\t\\\"Note that this allows access to the non-instancing duplicate even when this is a uniclass instance\\\"\\n\\n\\tself couldMakeSibling ifTrue:\\n\\t\\t[subMenu add: 'make a sibling' translated action: #handUserASibling.\\n\\t\\tsubMenu balloonTextForLastItem: 'Make a new sibling of this object and hand it to me' translated].\\n\\n\\tsubMenu addLine.\\n\\tsubMenu add: 'property sheet' translated target: self renderedMorph action: #openAPropertySheet.\\n\\tsubMenu balloonTextForLastItem: 'Open a property sheet for me. Allows changing lots of stuff at once.' translated.\\n\\n\\tsubMenu add: 'set color' translated target: self renderedMorph action: #changeColor.\\n\\tsubMenu balloonTextForLastItem: 'Change the color of this object' translated.\\n\\n\\tsubMenu add: 'viewer' translated target: self action: #beViewed.\\n\\tsubMenu balloonTextForLastItem: 'Open a Viewer that will allow everything about this object to be seen and controlled.' translated.\\n\\n\\tsubMenu add: 'tile browser' translated target: self action: #openInstanceBrowserWithTiles.\\n\\tsubMenu balloonTextForLastItem: 'Open a tool that will facilitate tile scripting of this object.' translated.\\n\\n\\tsubMenu add: 'hand me a tile' translated target: self action: #tearOffTile.\\n\\tsubMenu balloonTextForLastItem: 'Hand me a tile represting this object' translated.\\n\\tsubMenu addLine.\\n\\n\\tsubMenu add: 'inspect' translated target: self action: #inspect.\\n\\tsubMenu balloonTextForLastItem: 'Open an Inspector on this object' translated.\\n\\n\\taMenu add: 'halo actions...' translated subMenu: subMenu\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 3/2/2004 22:11'!\\naddMiscExtrasTo: aMenu\\n\\n\\t\\\"Add a submenu of miscellaneous extra items to the menu.\\\"\\n\\n\\n\\n\\t| realOwner realMorph subMenu |\\n\\n\\tsubMenu _ MenuMorph new defaultTarget: self.\\n\\n\\t(self isWorldMorph not and: [(self renderedMorph isSystemWindow) not])\\n\\n\\t\\tifTrue: [subMenu add: 'put in a window' translated action: #embedInWindow].\\n\\n\\n\\n\\tself isWorldMorph ifFalse:\\n\\n\\t\\t[subMenu add: 'adhere to edge...' translated action: #adhereToEdge.\\n\\n\\t\\tsubMenu addLine].\\n\\n\\n\\n\\trealOwner _ (realMorph _ self topRendererOrSelf) owner.\\n\\n\\t(realOwner isKindOf: TextPlusPasteUpMorph) ifTrue:\\n\\n\\t\\t[subMenu add: 'GeeMail stuff...' translated subMenu: (realOwner textPlusMenuFor: realMorph)].\\n\\n\\n\\n\\tsubMenu\\n\\n\\t\\tadd: 'add mouse up action' translated action: #addMouseUpAction;\\n\\n\\t\\tadd: 'remove mouse up action' translated action: #removeMouseUpAction;\\n\\n\\t\\tadd: 'hand me tiles to fire this button' translated action: #handMeTilesToFire.\\n\\n\\tsubMenu addLine.\\n\\n\\tsubMenu add: 'arrowheads on pen trails...' translated action: #setArrowheads.\\n\\n\\tsubMenu addLine.\\n\\n\\n\\n\\tsubMenu defaultTarget: self topRendererOrSelf.\\n\\n\\tsubMenu add: 'draw new path' translated action: #definePath.\\n\\n\\tsubMenu add: 'follow existing path' translated action: #followPath.\\n\\n\\tsubMenu add: 'delete existing path' translated action: #deletePath.\\n\\n\\tsubMenu addLine.\\n\\n\\n\\n\\tself addGestureMenuItems: subMenu hand: ActiveHand.\\n\\n\\n\\n\\taMenu add: 'extras...' translated subMenu: subMenu! !\\n\\n!Morph methodsFor: 'menus' stamp: 'nk 1/6/2004 12:53'!\\naddPaintingItemsTo: aMenu hand: aHandMorph \\n\\t| subMenu movies |\\n\\tsubMenu := MenuMorph new defaultTarget: self.\\n\\tsubMenu add: 'repaint' translated action: #editDrawing.\\n\\tsubMenu add: 'set rotation center' translated action: #setRotationCenter.\\n\\tsubMenu add: 'reset forward-direction' translated\\n\\t\\taction: #resetForwardDirection.\\n\\tsubMenu add: 'set rotation style' translated action: #setRotationStyle.\\n\\tsubMenu add: 'erase pixels of color' translated\\n\\t\\taction: #erasePixelsOfColor:.\\n\\tsubMenu add: 'recolor pixels of color' translated\\n\\t\\taction: #recolorPixelsOfColor:.\\n\\tsubMenu add: 'reduce color palette' translated action: #reduceColorPalette:.\\n\\tsubMenu add: 'add a border around this shape...' translated\\n\\t\\taction: #addBorderToShape:.\\n\\tmovies := (self world rootMorphsAt: aHandMorph targetOffset) \\n\\t\\t\\t\\tselect: [:m | (m isKindOf: MovieMorph) or: [m isSketchMorph]].\\n\\tmovies size > 1 \\n\\t\\tifTrue: \\n\\t\\t\\t[subMenu add: 'insert into movie' translated action: #insertIntoMovie:].\\n\\taMenu add: 'painting...' translated subMenu: subMenu! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 4/12/2005 23:12'!\\naddPlayerItemsTo: aMenu\\n\\t\\\"Add player-related items to the menu if appropriate\\\"\\n\\n\\t| aPlayer subMenu |\\n\\tself couldMakeSibling ifFalse: [^ self].\\n\\taPlayer _ self topRendererOrSelf player.\\n\\tsubMenu _ MenuMorph new defaultTarget: self.\\n\\tsubMenu add: 'make a sibling instance' translated target: self action: #makeNewPlayerInstance:.\\n\\tsubMenu balloonTextForLastItem: 'Makes another morph whose player is of the same class as this one. Both siblings will share the same scripts' translated.\\n\\n\\tsubMenu add: 'make multiple siblings...' translated target: self action: #makeMultipleSiblings:.\\n\\tsubMenu balloonTextForLastItem: 'Make any number of sibling instances all at once' translated.\\n\\n\\t(aPlayer belongsToUniClass and: [aPlayer class instanceCount > 1]) ifTrue:\\n\\t\\t[subMenu addLine.\\n\\t\\tsubMenu add: 'make all siblings look like me' translated target: self action: #makeSiblingsLookLikeMe:.\\n\\t\\tsubMenu balloonTextForLastItem: 'make all my sibling instances look like me.' translated.\\n\\n\\t\\tsubMenu add: 'bring all siblings to my location' translated target: self action: #bringAllSiblingsToMe:.\\n\\t\\tsubMenu balloonTextForLastItem: 'find all sibling instances and bring them to me' translated.\\n\\n\\t\\tsubMenu add: 'apply status to all siblngs' translated target: self action: #applyStatusToAllSiblings:.\\n\\t\\tsubMenu balloonTextForLastItem: 'apply the current status of all of my scripts to the scripts of all my siblings' translated].\\n\\n\\t\\tsubMenu add: 'indicate all siblings' translated target: self action: #indicateAllSiblings.\\n\\t\\tsubMenu balloonTextForLastItem: 'momentarily show, by flashing , all of my visible siblings.'.\\n\\n\\t\\taMenu add: 'siblings...' translated subMenu: subMenu\\n\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 8/30/2003 20:34'!\\naddStackItemsTo: aMenu\\n\\t\\\"Add stack-related items to the menu\\\"\\n\\n\\t| stackSubMenu |\\n\\tstackSubMenu _ MenuMorph new defaultTarget: self.\\n\\t(owner notNil and: [owner isStackBackground]) ifTrue:\\n\\t\\t[self isShared\\n\\t\\t\\tifFalse:\\n\\t\\t\\t\\t[self couldHoldSeparateDataForEachInstance\\n\\t\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t\\t[stackSubMenu add: 'Background field, shared value' translated target: self action: #putOnBackground.\\n\\t\\t\\t\\t\\t\\tstackSubMenu add: 'Background field, individual values' translated target: self action: #becomeSharedBackgroundField]\\n\\t\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t\\t[stackSubMenu add: 'put onto Background' translated target: self action: #putOnBackground]]\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[stackSubMenu add: 'remove from Background' translated target: self action: #putOnForeground.\\n\\t\\t\\t\\tself couldHoldSeparateDataForEachInstance ifTrue:\\n\\t\\t\\t\\t\\t[self holdsSeparateDataForEachInstance\\n\\t\\t\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t\\t\\t[stackSubMenu add: 'start holding separate data for each instance' translated target: self action: #makeHoldSeparateDataForEachInstance]\\n\\t\\t\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t\\t\\t[stackSubMenu add: 'stop holding separate data for each instance' translated target: self action: #stopHoldingSeparateDataForEachInstance].\\n\\t\\t\\t\\t\\t\\t\\tstackSubMenu add: 'be default value on new card' translated target: self action: #setAsDefaultValueForNewCard.\\n\\t\\t\\t\\t\\t\\t\\t(self hasProperty: #thumbnailImage)\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[stackSubMenu add: 'stop using for reference thumbnail' translated target: self action: #stopUsingForReferenceThumbnail]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[stackSubMenu add: 'start using for reference thumbnail' translated target: self action: #startUsingForReferenceThumbnail]]].\\n\\t\\t\\t\\tstackSubMenu addLine].\\n\\n\\t(self isStackBackground) ifFalse:\\n\\t\\t[stackSubMenu add: 'be a card in an existing stack...' translated action: #insertAsStackBackground].\\n\\tstackSubMenu add: 'make an instance for my data' translated action: #abstractAModel.\\n\\t(self isStackBackground) ifFalse:\\n\\t\\t[stackSubMenu add: 'become a stack of cards' translated action: #wrapWithAStack].\\n\\taMenu add: 'stacks and cards...' translated subMenu: stackSubMenu\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'nk 2/15/2004 08:19'!\\naddStandardHaloMenuItemsTo: aMenu hand: aHandMorph\\n\\t\\\"Add standard halo items to the menu\\\"\\n\\n\\t| unlockables |\\n\\n\\tself isWorldMorph ifTrue:\\n\\t\\t[^ self addWorldHaloMenuItemsTo: aMenu hand: aHandMorph].\\n\\n\\tself mustBeBackmost ifFalse:\\n\\t\\t[aMenu add: 'send to back' translated action: #goBehind.\\n\\t\\taMenu add: 'bring to front' translated action: #comeToFront.\\n\\t\\tself addEmbeddingMenuItemsTo: aMenu hand: aHandMorph.\\n\\t\\taMenu addLine].\\n\\n\\tself addFillStyleMenuItems: aMenu hand: aHandMorph.\\n\\tself addBorderStyleMenuItems: aMenu hand: aHandMorph.\\n\\tself addDropShadowMenuItems: aMenu hand: aHandMorph.\\n\\tself addLayoutMenuItems: aMenu hand: aHandMorph.\\n\\tself addHaloActionsTo: aMenu.\\n\\towner isTextMorph ifTrue:[self addTextAnchorMenuItems: aMenu hand: aHandMorph].\\n\\taMenu addLine.\\n\\tself addToggleItemsToHaloMenu: aMenu.\\n\\taMenu addLine.\\n\\tself addCopyItemsTo: aMenu.\\n\\tself addPlayerItemsTo: aMenu.\\n\\tself addExportMenuItems: aMenu hand: aHandMorph.\\n\\tself addStackItemsTo: aMenu.\\n\\tself addMiscExtrasTo: aMenu.\\n\\tPreferences noviceMode ifFalse:\\n\\t\\t[self addDebuggingItemsTo: aMenu hand: aHandMorph].\\n\\n\\taMenu addLine.\\n\\taMenu defaultTarget: self.\\n\\n\\taMenu addLine.\\n\\n\\tunlockables _ self submorphs select:\\n\\t\\t[:m | m isLocked].\\n\\tunlockables size == 1 ifTrue:\\n\\t\\t[aMenu\\n\\t\\t\\tadd: ('unlock \\\"{1}\\\"' translated format: unlockables first externalName)\\n\\t\\t\\taction: #unlockContents].\\n\\tunlockables size > 1 ifTrue:\\n\\t\\t[aMenu add: 'unlock all contents' translated action: #unlockContents.\\n\\t\\taMenu add: 'unlock...' translated action: #unlockOneSubpart].\\n\\n\\taMenu defaultTarget: aHandMorph.\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 4/3/2006 14:11'!\\naddToggleItemsToHaloMenu: aMenu\\n\\t\\\"Add standard true/false-checkbox items to the memu\\\"\\n\\n\\t#(\\n\\t\\t(resistsRemovalString toggleResistsRemoval 'whether I should be reistant to easy deletion via the pink X handle' true)\\n\\t\\t(stickinessString toggleStickiness 'whether I should be resistant to a drag done by mousing down on me' true)\\n\\t\\t(lockedString lockUnlockMorph 'when \\\"locked\\\", I am inert to all user interactions' true)\\n\\t\\t(hasClipSubmorphsString changeClipSubmorphs 'whether the parts of objects within me that are outside my bounds should be masked.' false)\\n\\t\\t(hasDirectionHandlesString changeDirectionHandles 'whether direction handles are shown with the halo' false)\\n\\t\\t(hasDragAndDropEnabledString changeDragAndDrop 'whether I am open to having objects dropped into me' false)\\n\\t)\\n\\t\\tselect:[:each | Preferences noviceMode not or:[each fourth]]\\n\\t\\tthenDo:\\n\\t\\t[:each |\\n\\t\\t\\taMenu addUpdating: each first action: each second.\\n\\t\\t\\taMenu balloonTextForLastItem: each third translated].\\n\\n\\tself couldHaveRoundedCorners ifTrue:\\n\\t\\t[aMenu addUpdating: #roundedCornersString action: #toggleCornerRounding.\\n\\t\\taMenu balloonTextForLastItem: 'whether my corners should be rounded' translated]! !\\n\\n!Morph methodsFor: 'menus' stamp: 'wiz 2/14/2006 18:54'!\\naddWorldTargetSightingItems: aCustomMenu hand: aHandMorph\\n\\\"Use cursor to select a point on screen.\\nSet target from all possible morphs under cursor sight.\\\" \\n\\t\\n\\taCustomMenu addLine.\\n\\t\\n\\taCustomMenu add: 'sight target' translated action: #sightWorldTargets:.\\n\\t! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 10/17/2003 22:51'!\\nadhereToEdge\\n\\t| menu |\\n\\tmenu _ MenuMorph new defaultTarget: self.\\n\\t#(top right bottom left - center - topLeft topRight bottomRight bottomLeft - none)\\n\\t\\tdo: [:each |\\n\\t\\t\\teach == #-\\n\\t\\t\\t\\tifTrue: [menu addLine]\\n\\t\\t\\t\\tifFalse: [menu add: each asString translated selector: #setToAdhereToEdge: argument: each]].\\n\\tmenu popUpEvent: self currentEvent in: self world! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 2/22/2003 14:26'!\\nadhereToEdge: edgeSymbol \\n\\t(owner isNil or: [owner isHandMorph]) ifTrue: [^self].\\n\\tself perform: (edgeSymbol , ':') asSymbol\\n\\t\\twithArguments: (Array with: (owner perform: edgeSymbol))! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 2/3/2000 00:14'!\\nadjustedCenter\\n\\t\\\"Provides a hook for objects to provide a reference point other than the receiver's center,for the purpose of centering a submorph under special circumstances, such as BalloonMorph\\\"\\n\\n\\t^ self center! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 2/3/2000 00:12'!\\nadjustedCenter: c\\n\\t\\\"Set the receiver's position based on the #adjustedCenter protocol for adhereToEdge. By default this simply sets the receiver's center. Though there are (at its inception anyway) no other implementors of this method, it is required in use with the #adhereToEdge when the centering of a submorph is to be with reference to a rectangle other than the receiver's center.\\\"\\n\\n\\tself center: c! !\\n\\n!Morph methodsFor: 'menus' stamp: 'ar 10/5/2000 17:20'!\\nallMenuWordings\\n\\t| tempMenu |\\n\\ttempMenu _ self buildHandleMenu: self currentHand.\\n\\ttempMenu allMorphsDo: [:m | m step]. \\\"Get wordings current\\\"\\n\\t^ tempMenu allWordings! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 9/6/2000 18:45'!\\nchangeColor\\n\\t\\\"Change the color of the receiver -- triggered, e.g. from a menu\\\"\\n\\n\\tColorPickerMorph new\\n\\t\\tchoseModalityFromPreference;\\n\\t\\tsourceHand: self activeHand;\\n\\t\\ttarget: self;\\n\\t\\tselector: #fillStyle:;\\n\\t\\toriginalColor: self color;\\n\\t\\tputUpFor: self near: self fullBoundsInWorld! !\\n\\n!Morph methodsFor: 'menus' stamp: 'ar 11/29/2001 19:57'!\\nchangeDirectionHandles\\n\\t^self wantsDirectionHandles: self wantsDirectionHandles not! !\\n\\n!Morph methodsFor: 'menus' stamp: 'ar 11/2/2000 15:04'!\\nchangeDragAndDrop\\n\\t^self enableDragNDrop: self dragNDropEnabled not! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 12/17/1998 12:09'!\\nchooseNewGraphic\\n\\t\\\"Used by any morph that can be represented by a graphic\\\"\\n\\tself chooseNewGraphicCoexisting: false\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'nk 6/12/2004 09:58'!\\nchooseNewGraphicCoexisting: aBoolean \\n\\t\\\"Allow the user to choose a different form for her form-based morph\\\"\\n\\t| replacee aGraphicalMenu |\\n\\taGraphicalMenu := GraphicalMenu new\\n\\t\\t\\t\\tinitializeFor: self\\n\\t\\t\\t\\twithForms: self reasonableForms\\n\\t\\t\\t\\tcoexist: aBoolean.\\n\\taBoolean\\n\\t\\tifTrue: [self primaryHand attachMorph: aGraphicalMenu]\\n\\t\\tifFalse: [replacee := self topRendererOrSelf.\\n\\t\\t\\treplacee owner replaceSubmorph: replacee by: aGraphicalMenu]! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 10/27/2000 17:34'!\\nchooseNewGraphicFromHalo\\n\\t\\\"Allow the user to select a changed graphic to replace the one in the receiver\\\"\\n\\n\\tself currentWorld abandonAllHalos.\\n\\tself chooseNewGraphicCoexisting: true\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 2/21/2000 15:21'!\\ncollapse\\n\\tCollapsedMorph new beReplacementFor: self! !\\n\\n!Morph methodsFor: 'menus'!\\ndefaultArrowheadSize\\n\\t\\n\\t^ self class defaultArrowheadSize! !\\n\\n!Morph methodsFor: 'menus' stamp: 'ar 10/25/2000 23:17'!\\ndoMenuItem: menuString\\n\\t| aMenu anItem aNominalEvent aHand |\\n\\taMenu _ self buildHandleMenu: (aHand _ self currentHand).\\n\\taMenu allMorphsDo: [:m | m step]. \\\"Get wordings current\\\"\\n\\tanItem _ aMenu itemWithWording: menuString.\\n\\tanItem ifNil:\\n\\t\\t[^ self player scriptingError: 'Menu item not found: ', menuString].\\n\\taNominalEvent _ MouseButtonEvent new\\n\\t\\tsetType: #mouseDown\\n\\t\\tposition: anItem bounds center\\n\\t\\twhich: 4 \\\"red\\\"\\n\\t\\tbuttons: 4 \\\"red\\\"\\n\\t\\thand: aHand\\n\\t\\tstamp: nil.\\n\\tanItem invokeWithEvent: aNominalEvent! !\\n\\n!Morph methodsFor: 'menus' stamp: 'yo 2/17/2005 17:50'!\\nexportAsBMP\\n\\t| fName |\\n\\tfName _ FillInTheBlank request:'Please enter the name' translated initialAnswer: self externalName,'.bmp'.\\n\\tfName isEmpty ifTrue:[^self].\\n\\tself imageForm writeBMPfileNamed: fName.! !\\n\\n!Morph methodsFor: 'menus' stamp: 'yo 2/17/2005 17:50'!\\nexportAsGIF\\n\\t| fName |\\n\\tfName _ FillInTheBlank request:'Please enter the name' translated initialAnswer: self externalName,'.gif'.\\n\\tfName isEmpty ifTrue:[^self].\\n\\tGIFReadWriter putForm: self imageForm onFileNamed: fName.! !\\n\\n!Morph methodsFor: 'menus' stamp: 'yo 2/17/2005 17:51'!\\nexportAsJPEG\\n\\t\\\"Export the receiver's image as a JPEG\\\"\\n\\n\\t| fName |\\n\\tfName _ FillInTheBlank request: 'Please enter the name' translated initialAnswer: self externalName,'.jpeg'.\\n\\tfName isEmpty ifTrue: [^ self].\\n\\tself imageForm writeJPEGfileNamed: fName! !\\n\\n!Morph methodsFor: 'menus' stamp: 'yo 2/17/2005 17:51'!\\nexportAsPNG\\n\\t| fName |\\n\\tfName _ FillInTheBlank request:'Please enter the name' translated initialAnswer: self externalName,'.png'.\\n\\tfName isEmpty ifTrue:[^self].\\n\\tPNGReadWriter putForm: self imageForm onFileNamed: fName.! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 8/30/2003 20:23'!\\nhasDirectionHandlesString\\n\\t^ (self wantsDirectionHandles\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'direction handles' translated! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 8/30/2003 20:24'!\\nhasDragAndDropEnabledString\\n\\t\\\"Answer a string to characterize the drag & drop status of the \\n\\treceiver\\\"\\n\\t^ (self dragNDropEnabled\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'accept drops' translated! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 4/3/2006 14:09'!\\nhelpButton\\n\\t\\\"Answer a button whose action would be to put up help concerning the receiver\\\"\\n\\n\\t| aButton |\\n\\taButton _ SimpleButtonMorph new.\\n\\taButton\\n\\t\\ttarget: self;\\n\\t\\tcolor: ColorTheme current helpColor;\\n\\t\\tborderColor: ColorTheme current helpColor muchDarker;\\n\\t\\tborderWidth: 1;\\n\\t\\tlabel: '?' translated font: Preferences standardButtonFont;\\n\\t\\tactionSelector: #presentHelp;\\n\\t\\tsetBalloonText: 'click here for help' translated.\\n\\t^ aButton! !\\n\\n!Morph methodsFor: 'menus' stamp: 'ar 9/27/2005 21:01'!\\ninspectInMorphic\\n\\tself currentHand attachMorph: ((ToolSet inspect: self) extent: 300@200)! !\\n\\n!Morph methodsFor: 'menus' stamp: 'ar 9/27/2005 21:01'!\\ninspectInMorphic: evt\\n\\tevt hand attachMorph: ((ToolSet inspect: self) extent: 300@200)! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 8/30/2003 20:20'!\\nlockedString\\n\\t\\\"Answer the string to be shown in a menu to represent the \\n\\t'locked' status\\\"\\n\\t^ (self isLocked\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>']), 'be locked' translated! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 9/21/2000 22:50'!\\nlockUnlockMorph\\n\\t\\\"If the receiver is locked, unlock it; if unlocked, lock it\\\"\\n\\n\\tself isLocked ifTrue: [self unlock] ifFalse: [self lock]! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 10/29/1999 15:34'!\\nmakeNascentScript\\n\\t^ self notYetImplemented! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 8/30/2003 20:15'!\\nmaybeAddCollapseItemTo: aMenu\\n\\t\\\"If appropriate, add a collapse item to the given menu\\\"\\n\\n\\t| anOwner |\\n\\t(anOwner _ self topRendererOrSelf owner) ifNotNil:\\n\\t\\t\\t[anOwner isWorldMorph ifTrue:\\n\\t\\t\\t\\t[aMenu add: 'collapse' translated target: self action: #collapse]]! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 11/22/1999 12:13'!\\nmenuItemAfter: menuString\\n\\t| allWordings |\\n\\tallWordings _ self allMenuWordings.\\n\\t^ allWordings atWrap: ((allWordings indexOf: menuString) + 1)! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 11/22/1999 12:14'!\\nmenuItemBefore: menuString\\n\\t| allWordings |\\n\\tallWordings _ self allMenuWordings.\\n\\t^ allWordings atWrap: ((allWordings indexOf: menuString) - 1)! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 9/22/2004 20:30'!\\nmodel\\n\\t^ nil ! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 6/12/2001 21:08'!\\npresentHelp\\n\\t\\\"Present a help message if there is one available\\\"\\n\\n\\tself inform: 'Sorry, no help has been\\nprovided here yet.'! !\\n\\n!Morph methodsFor: 'menus' stamp: 'yo 2/17/2005 18:03'!\\nprintPSToFileNamed: aString \\n\\t\\\"Ask the user for a filename and print this morph as postscript.\\\"\\n\\t| fileName rotateFlag psCanvasType psExtension |\\n\\tfileName := aString asFileName.\\n\\tpsCanvasType _ PostscriptCanvas defaultCanvasType.\\n\\tpsExtension _ psCanvasType defaultExtension.\\n\\tfileName := FillInTheBlank request: (String streamContents: [ :s |\\n\\t\\ts nextPutAll: ('File name? (\\\"{1}\\\" will be added to end)' translated format: {psExtension})])\\n\\t\\t\\tinitialAnswer: fileName.\\n\\tfileName isEmpty\\n\\t\\tifTrue: [^ Beeper beep].\\n\\t(fileName endsWith: psExtension)\\n\\t\\tifFalse: [fileName := fileName , psExtension].\\n\\trotateFlag := ((PopUpMenu labels: 'portrait (tall)\\nlandscape (wide)' translated)\\n\\t\\t\\t\\tstartUpWithCaption: 'Choose orientation...' translated)\\n\\t\\t\\t\\t= 2.\\n\\t((FileStream newFileNamed: fileName asFileName) converter: TextConverter defaultSystemConverter)\\n\\t\\tnextPutAll: (psCanvasType morphAsPostscript: self rotated: rotateFlag);\\n\\t\\t close! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 10/27/2000 06:39'!\\nputOnBackground\\n\\t\\\"Place the receiver, formerly private to its card, onto the shared background. If the receiver needs data carried on its behalf by the card, such data will be represented on every card.\\\"\\n\\n\\t(self hasProperty: #shared) ifTrue: [^ self]. \\\"Already done\\\"\\n\\n\\tself setProperty: #shared toValue: true.\\n\\tself stack ifNotNil: [self stack reassessBackgroundShape]! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 9/5/2003 18:25'!\\nputOnForeground\\n\\t\\\"Place the receiver, formerly on the background, onto the foreground. If the receiver needs data carried on its behalf by the card, those data will be lost, so in this case get user confirmation before proceeding.\\\"\\n\\n\\tself holdsSeparateDataForEachInstance \\\"later add the refinement of not putting up the following confirmer if only a single instance of the current background's uniclass exists\\\"\\n\\t\\tifTrue:\\n\\t\\t\\t[self confirm: 'Caution -- every card of this background\\nformerly had its own value for this\\nitem. If you put it on the foreground,\\nthe values of this item on all other\\ncards will be lost' translated\\n\\t\\t\\t\\torCancel: [^ self]].\\n\\n\\tself removeProperty: #shared.\\n\\tself stack reassessBackgroundShape.\\n\\t\\\"still work to be done here!!\\\"! !\\n\\n!Morph methodsFor: 'menus' stamp: 'nk 6/12/2004 22:42'!\\nreasonableBitmapFillForms\\n\\t\\\"Answer an OrderedCollection of forms that could be used to replace my bitmap fill, with my current form first.\\\"\\n\\t| reasonableForms myGraphic |\\n\\treasonableForms := self class allSketchMorphForms.\\n\\treasonableForms addAll: Imports default images.\\n\\treasonableForms addAll: (BitmapFillStyle allSubInstances collect:[:f| f form]).\\n\\treasonableForms\\n\\t\\tremove: (myGraphic := self fillStyle form)\\n\\t\\tifAbsent: [].\\n\\treasonableForms := reasonableForms asOrderedCollection.\\n\\treasonableForms addFirst: myGraphic.\\n\\t^reasonableForms! !\\n\\n!Morph methodsFor: 'menus' stamp: 'nk 6/12/2004 09:55'!\\nreasonableForms\\n\\t\\\"Answer an OrderedCollection of forms that could be used to replace my form, with my current form first.\\\"\\n\\t| reasonableForms myGraphic |\\n\\treasonableForms := self class allSketchMorphForms.\\n\\treasonableForms addAll: Imports default images.\\n\\treasonableForms\\n\\t\\tremove: (myGraphic := self form)\\n\\t\\tifAbsent: [].\\n\\treasonableForms := reasonableForms asOrderedCollection.\\n\\treasonableForms addFirst: myGraphic.\\n\\t^reasonableForms! !\\n\\n!Morph methodsFor: 'menus' stamp: 'ar 9/22/2000 20:36'!\\nresetForwardDirection\\n\\tself forwardDirection: 0.! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 8/30/2003 20:18'!\\nresistsRemovalString\\n\\t\\\"Answer the string to be shown in a menu to represent the \\n\\t'resistsRemoval' status\\\"\\n\\t^ (self resistsRemoval\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>']), 'resist being deleted' translated! !\\n\\n!Morph methodsFor: 'menus' stamp: 'yo 2/17/2005 16:58'!\\nsetArrowheads\\n\\t\\\"Let the user edit the size of arrowheads for this object\\\"\\n\\n\\t| aParameter result |\\n\\taParameter _ self renderedMorph valueOfProperty: #arrowSpec ifAbsent:\\n\\t\\t[Preferences parameterAt: #arrowSpec ifAbsent: [5 @ 4]].\\n\\tresult _ Morph obtainArrowheadFor: 'Head size for arrowheads: ' translated defaultValue: aParameter asString.\\n\\tresult ifNotNil:\\n\\t\\t\\t[self renderedMorph setProperty: #arrowSpec toValue: result]\\n\\t\\tifNil:\\n\\t\\t\\t[Beeper beep]! !\\n\\n!Morph methodsFor: 'menus' stamp: 'ar 9/22/2000 20:15'!\\nsetRotationCenter\\n\\t| p |\\n\\tself world displayWorld.\\n\\tCursor crossHair showWhile:\\n\\t\\t[p _ Sensor waitButton].\\n\\tSensor waitNoButton.\\n\\tself setRotationCenterFrom: (self transformFromWorld globalPointToLocal: p).\\n\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'ar 9/22/2000 20:14'!\\nsetRotationCenterFrom: aPoint\\n\\tself rotationCenter: (aPoint - self bounds origin) / self bounds extent asFloatPoint.! !\\n\\n!Morph methodsFor: 'menus' stamp: 'di 12/21/2000 17:18'!\\nsetToAdhereToEdge: anEdge\\n\\tanEdge ifNil: [^ self].\\n\\tanEdge == #none ifTrue: [^ self removeProperty: #edgeToAdhereTo].\\n\\tself setProperty: #edgeToAdhereTo toValue: anEdge.\\n! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 8/30/1998 09:42'!\\nsnapToEdgeIfAppropriate\\n\\t| edgeSymbol oldBounds aWorld |\\n\\t(edgeSymbol _ self valueOfProperty: #edgeToAdhereTo) ifNotNil:\\n\\t\\t[oldBounds _ bounds.\\n\\t\\tself adhereToEdge: edgeSymbol.\\n\\t\\tbounds ~= oldBounds ifTrue: [(aWorld _ self world) ifNotNil: [aWorld viewBox ifNotNil:\\n\\t\\t\\t[aWorld displayWorld]]]]! !\\n\\n!Morph methodsFor: 'menus' stamp: 'dgd 8/30/2003 20:19'!\\nstickinessString\\n\\t\\\"Answer the string to be shown in a menu to represent the \\n\\tstickiness status\\\"\\n\\t^ (self isSticky\\n\\t\\tifTrue: ['<yes>']\\n\\t\\tifFalse: ['<no>'])\\n\\t\\t, 'resist being picked up' translated! !\\n\\n!Morph methodsFor: 'menus' stamp: 'sw 10/6/2004 12:16'!\\ntransferStateToRenderer: aRenderer\\n\\t\\\"Transfer knownName, actorState, visible, and player info over to aRenderer, which is being imposed above me as a transformation shell\\\"\\n\\n\\t| current |\\n\\t(current _ self actorStateOrNil) ifNotNil:\\n\\t\\t[aRenderer actorState: current.\\n\\t\\tself actorState: nil].\\n\\n\\t(current _ self knownName) ifNotNil:\\n\\t\\t[aRenderer setNameTo: current.\\n\\t\\tself setNameTo: nil].\\n\\n\\t(current _ self player) ifNotNil:\\n\\t\\t[aRenderer player: current.\\n\\t\\tself player rawCostume: aRenderer.\\n\\t\\t\\\"NB player is redundantly pointed to in the extension of both the renderer and the rendee; this is regrettable but many years ago occasionally people tried to make that clean but always ran into problems iirc\\\"\\n\\t\\t\\\"self player: nil\\\"].\\n\\n\\taRenderer simplySetVisible: self visible\\n\\n\\n\\n \\n\\n\\t\\t! !\\n\\n!Morph methodsFor: 'menus' stamp: 'RAA 11/14/2000 13:46'!\\nuncollapseSketch\\n\\n\\t| uncollapsedVersion w whomToDelete |\\n\\n\\t(w _ self world) ifNil: [^self].\\n\\tuncollapsedVersion _ self valueOfProperty: #uncollapsedMorph.\\n\\tuncollapsedVersion ifNil: [^self].\\n\\twhomToDelete _ self valueOfProperty: #collapsedMorphCarrier.\\n\\tuncollapsedVersion setProperty: #collapsedPosition toValue: whomToDelete position.\\n\\n\\twhomToDelete delete.\\n\\tw addMorphFront: uncollapsedVersion.\\n\\n! !\\n\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'dgd 9/18/2004 16:24'!\\naddEmbeddingMenuItemsTo: aMenu hand: aHandMorph\\n\\t\\\"Construct a menu offerring embed targets for the receiver. If the incoming menu is is not degenerate, add the constructed menu as a submenu; in any case, answer the embed-target menu\\\"\\n\\n\\t| menu potentialEmbeddingTargets |\\n\\n\\tpotentialEmbeddingTargets := self potentialEmbeddingTargets.\\n\\tpotentialEmbeddingTargets size > 1 ifFalse:[^ self].\\n\\n\\tmenu := MenuMorph new defaultTarget: self.\\n\\n\\tpotentialEmbeddingTargets reverseDo: [:m | \\n\\t\\t\\tmenu\\n\\t\\t\\t\\tadd: (m knownName ifNil:[m class name asString])\\n\\t\\t\\t\\ttarget: m\\n\\t\\t\\t\\tselector: #addMorphFrontFromWorldPosition:\\n\\t\\t\\t\\targument: self topRendererOrSelf.\\n\\n\\t\\t\\tmenu lastItem icon: (m iconOrThumbnailOfSize: 16).\\n\\n\\t\\t\\tself owner == m ifTrue:[menu lastItem emphasis: 1].\\n\\t\\t].\\n\\n\\taMenu add:'embed into' translated subMenu: menu.\\n\\n\\t^ menu! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'sw 1/29/2001 02:50'!\\napplyStatusToAllSiblings: evt\\n\\t\\\"Apply the statuses of all my scripts to the script status of all my siblings\\\"\\n\\n\\t| aPlayer |\\n\\t(aPlayer _ self topRendererOrSelf player) belongsToUniClass ifFalse: [self error: 'not uniclass'].\\n\\taPlayer instantiatedUserScriptsDo: \\n\\t\\t[:aScriptInstantiation | aScriptInstantiation assignStatusToAllSiblings]! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/5/2000 16:51'!\\nbeThisWorldsModel\\n\\n\\tself world setModel: self.\\n\\tself model: nil slotName: nil.\\t\\\"A world's model cannot have another model\\\"! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'yo 3/15/2005 14:45'!\\nblueButtonDown: anEvent\\n\\t\\\"Special gestures (cmd-mouse on the Macintosh; Alt-mouse on Windows and Unix) allow a mouse-sensitive morph to be moved or bring up a halo for the morph.\\\"\\n\\t| h tfm doNotDrag |\\n\\th _ anEvent hand halo.\\n\\t\\\"Prevent wrap around halo transfers originating from throwing the event back in\\\"\\n\\tdoNotDrag _ false.\\n\\th ifNotNil:[\\n\\t\\t(h innerTarget == self) ifTrue:[doNotDrag _ true].\\n\\t\\t(h innerTarget hasOwner: self) ifTrue:[doNotDrag _ true].\\n\\t\\t(self hasOwner: h target) ifTrue:[doNotDrag _ true]].\\n\\n\\ttfm _ (self transformedFrom: nil) inverseTransformation.\\n\\n\\t\\\"cmd-drag on flexed morphs works better this way\\\"\\n\\th _ self addHalo: (anEvent transformedBy: tfm).\\n\\th ifNil: [^ self].\\n\\tdoNotDrag ifTrue:[^self].\\n\\t\\\"Initiate drag transition if requested\\\"\\n\\tanEvent hand \\n\\t\\twaitForClicksOrDrag: h\\n\\t\\tevent: (anEvent transformedBy: tfm)\\n\\t\\tselectors: { nil. nil. nil. #dragTarget:. }\\n\\t\\tthreshold: 5.\\n\\t\\\"Pass focus explicitly here\\\"\\n\\tanEvent hand newMouseFocus: h.! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 9/15/2000 20:25'!\\nblueButtonUp: anEvent\\n\\t\\\"Ignored. Theoretically we should never get here since control is transferred to the halo on #blueButtonDown: but subclasses may implement this differently.\\\"! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'sw 1/19/2001 18:10'!\\nbringAllSiblingsToMe: evt\\n\\t\\\"bring all siblings of the receiver's player found in the same container to the receiver's location.\\\"\\n\\n\\t| aPlayer aPosition aContainer |\\n\\t(aPlayer _ self topRendererOrSelf player) belongsToUniClass ifFalse: [self error: 'not uniclass'].\\n\\taPosition _ self topRendererOrSelf position.\\n\\taContainer _ self topRendererOrSelf owner.\\n\\t(aPlayer class allInstances copyWithout: aPlayer) do:\\n\\t\\t[:each |\\n\\t\\t\\t(aContainer submorphs includes: each costume) ifTrue:\\n\\t\\t\\t\\t[each costume position: aPosition]]! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'dgd 9/18/2004 17:23'!\\nbuildHandleMenu: aHand\\n\\t\\\"Build the morph menu for the given morph's halo's menu handle. This menu has two sections. The first section contains commands that are interpreted by the hand; the second contains commands provided by the target morph. This method allows the morph to decide which items should be included in the hand's section of the menu.\\\"\\n\\n\\t| menu |\\n\\n\\t(Preferences generalizedYellowButtonMenu\\n\\t\\t\\tand: [Preferences noviceMode])\\n\\t\\tifTrue: [^ self buildYellowButtonMenu: aHand].\\n\\n\\tmenu _ MenuMorph new defaultTarget: self.\\n\\tmenu addStayUpItem.\\n\\tmenu addLine.\\n\\tself addStandardHaloMenuItemsTo: menu hand: aHand.\\n\\tmenu defaultTarget: aHand.\\n\\tself addAddHandMenuItemsForHalo: menu hand: aHand.\\n\\tmenu defaultTarget: self.\\n\\tself addCustomHaloMenuItems: menu hand: aHand.\\n\\tmenu defaultTarget: aHand.\\n\\t^ menu\\n! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'dgd 11/15/2003 19:29'!\\nbuildMetaMenu: evt\\n\\t\\\"Build the morph menu. This menu has two sections. The first section contains commands that are handled by the hand; the second contains commands handled by the argument morph.\\\"\\n\\t| menu |\\n\\tmenu _ MenuMorph new defaultTarget: self.\\n\\tmenu addStayUpItem.\\n\\tmenu add: 'grab' translated action: #grabMorph:.\\n\\tmenu add: 'copy to paste buffer' translated action: #copyToPasteBuffer:.\\n\\tself maybeAddCollapseItemTo: menu.\\n\\tmenu add: 'delete' translated action: #dismissMorph:.\\n\\tmenu addLine.\\n\\tmenu add: 'copy text' translated action: #clipText.\\n\\tmenu add: 'copy Postscript' translated action: #clipPostscript.\\n\\tmenu add: 'print Postscript to file...' translated action: #printPSToFile.\\n\\tmenu addLine.\\n\\tmenu add: 'go behind' translated action: #goBehind.\\n\\tmenu add: 'add halo' translated action: #addHalo:.\\n\\tmenu add: 'duplicate' translated action: #maybeDuplicateMorph:.\\n\\n\\tself addEmbeddingMenuItemsTo: menu hand: evt hand.\\n\\n\\tmenu add: 'resize' translated action: #resizeMorph:.\\n\\t\\\"Give the argument control over what should be done about fill styles\\\"\\n\\tself addFillStyleMenuItems: menu hand: evt hand.\\n\\tself addDropShadowMenuItems: menu hand: evt hand.\\n\\tself addLayoutMenuItems: menu hand: evt hand.\\n\\tmenu addUpdating: #hasClipSubmorphsString target: self selector: #changeClipSubmorphs argumentList: #().\\n\\tmenu addLine.\\n\\n\\t(self morphsAt: evt position) size > 1 ifTrue:\\n\\t\\t[menu add: 'submorphs...' translated\\n\\t\\t\\ttarget: self\\n\\t\\t\\tselector: #invokeMetaMenuAt:event:\\n\\t\\t\\targument: evt position].\\n\\tmenu addLine.\\n\\tmenu add: 'inspect' translated selector: #inspectAt:event: argument: evt position.\\n\\tmenu add: 'explore' translated action: #explore.\\n\\tmenu add: 'browse hierarchy' translated action: #browseHierarchy.\\n\\tmenu add: 'make own subclass' translated action: #subclassMorph.\\n\\tmenu addLine.\\n\\tmenu add: 'set variable name...' translated action: #choosePartName.\\n\\t(self isMorphicModel) ifTrue:\\n\\t\\t[menu add: 'save morph as prototype' translated action: #saveAsPrototype.\\n\\t\\t(self ~~ self world modelOrNil) ifTrue:\\n\\t\\t\\t [menu add: 'become this world''s model' translated action: #beThisWorldsModel]].\\n\\tmenu add: 'save morph in file' translated action: #saveOnFile.\\n\\t(self hasProperty: #resourceFilePath)\\n\\t\\tifTrue: [((self valueOfProperty: #resourceFilePath) endsWith: '.morph')\\n\\t\\t\\t\\tifTrue: [menu add: 'save as resource' translated action: #saveAsResource].\\n\\t\\t\\t\\tmenu add: 'update from resource' translated action: #updateFromResource]\\n\\t\\tifFalse: [menu add: 'attach to resource' translated action: #attachToResource].\\n\\tmenu add: 'show actions' translated action: #showActions.\\n\\tmenu addLine.\\n\\tself addDebuggingItemsTo: menu hand: evt hand.\\n\\n\\tself addCustomMenuItems: menu hand: evt hand.\\n\\t^ menu\\n! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/5/2000 18:54'!\\nchangeColorTarget: anObject selector: aSymbol originalColor: aColor hand: aHand\\n\\t\\\"Put up a color picker for changing some kind of color. May be modal or modeless, depending on #modalColorPickers setting\\\"\\n\\tself flag: #arNote. \\\"Simplify this due to anObject == self for almost all cases\\\"\\n\\t^ ColorPickerMorph new\\n\\t\\tchoseModalityFromPreference;\\n\\t\\tsourceHand: aHand;\\n\\t\\ttarget: anObject;\\n\\t\\tselector: aSymbol;\\n\\t\\toriginalColor: aColor;\\n\\t\\tputUpFor: anObject near: (anObject isMorph\\n\\t\\t\\t\\t\\tifTrue:\\t [Rectangle center: self position extent: 20]\\n\\t\\t\\t\\t\\tifFalse: [anObject == self world\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [anObject viewBox bottomLeft + (20@-20) extent: 200]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [anObject fullBoundsInWorld]]);\\n\\t\\tyourself! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/5/2000 16:44'!\\ncopyToPasteBuffer: evt\\n\\tself okayToDuplicate ifTrue:[evt hand copyToPasteBuffer: self].! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'mir 3/17/2006 18:02'!\\ndismissMorph\\n\\t\\\"This is called from an explicit halo destroy/delete action.\\\"\\n\\n\\t| w |\\n\\tw _ self world ifNil:[^self].\\n\\tw abandonAllHalos; stopStepping: self.\\n\\tself delete! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'mir 3/17/2006 18:01'!\\ndismissMorph: evt\\n\\tself dismissMorph! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'wiz 2/19/2006 12:41'!\\nduplicateMorphImage: evt \\n\\t\\\"Make and return a imageMorph of the receiver's argument imageForm\\\"\\n\\t| dup |\\n\\tdup := self asSnapshotThumbnail withSnapshotBorder.\\n\\tdup bounds: self bounds.\\n\\tevt hand grabMorph: dup from: owner.\\n\\t\\\"duplicate was ownerless so use #grabMorph:from: here\\\"\\n\\t^ dup! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 11/4/2000 17:56'!\\nduplicateMorph: evt\\n\\t\\\"Make and return a duplicate of the receiver's argument\\\"\\n\\t| dup |\\n\\tdup _ self duplicate.\\n\\tevt hand grabMorph: dup from: owner. \\\"duplicate was ownerless so use #grabMorph:from: here\\\"\\n\\t^dup! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/7/2000 20:53'!\\nembedInto: evt\\n\\t\\\"Embed the receiver into some other morph\\\"\\n\\t| menu target |\\n\\tmenu _ CustomMenu new.\\n\\tself potentialEmbeddingTargets do: [:m | \\n\\t\\tmenu add: (m knownName ifNil:[m class name asString]) action: m].\\n\\ttarget _ menu startUpWithCaption: ('Place ', self externalName, ' in...').\\n\\ttarget ifNil:[^self].\\n\\ttarget addMorphFront: self fromWorldPosition: self positionInWorld.! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/6/2000 16:37'!\\ngrabMorph: evt\\n\\n\\tevt hand grabMorph: self! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/7/2000 18:44'!\\nhandlerForBlueButtonDown: anEvent\\n\\t\\\"Return the (prospective) handler for a mouse down event. The handler is temporarily installed and can be used for morphs further down the hierarchy to negotiate whether the inner or the outer morph should finally handle the event.\\n\\tNote: Halos handle blue button events themselves so we will only be asked if there is currently no halo on top of us.\\\"\\n\\tself wantsHaloFromClick ifFalse:[^nil].\\n\\tanEvent handler ifNil:[^self].\\n\\tanEvent handler isPlayfieldLike ifTrue:[^self]. \\\"by default exclude playfields\\\"\\n\\t(anEvent shiftPressed)\\n\\t\\tifFalse:[^nil] \\\"let outer guy have it\\\"\\n\\t\\tifTrue:[^self] \\\"let me have it\\\"\\n! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/12/2000 17:07'!\\nhandlerForMetaMenu: evt\\n\\t\\\"Return the prospective handler for invoking the meta menu. By default, the top-most morph in the innermost world gets this menu\\\"\\n\\tself isWorldMorph ifTrue:[^self].\\n\\tevt handler ifNotNil:[evt handler isWorldMorph ifTrue:[^self]].\\n\\t^nil! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'yo 2/12/2005 15:25'!\\nindicateAllSiblings\\n\\t\\\"Indicate all the receiver and all its siblings by flashing momentarily.\\\"\\n\\n\\t| aPlayer allBoxes |\\n\\t(aPlayer _ self topRendererOrSelf player) belongsToUniClass ifFalse: [^ self \\\"error: 'not uniclass'\\\"].\\n\\tallBoxes _ aPlayer class allInstances\\n\\t\\tselect: [:m | m costume world == ActiveWorld]\\n\\t\\tthenCollect: [:m | m costume boundsInWorld].\\n\\n\\t5 timesRepeat:\\n\\t\\t[Display flashAll: allBoxes andWait: 120]! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/10/2000 14:09'!\\ninspectAt: aPoint event: evt\\n\\t| menu morphs target |\\n\\tmenu _ CustomMenu new.\\n\\tmorphs _ self morphsAt: aPoint.\\n\\t(morphs includes: self) ifFalse:[morphs _ morphs copyWith: self].\\n\\tmorphs do: [:m | \\n\\t\\tmenu add: (m knownName ifNil:[m class name asString]) action: m].\\n\\ttarget _ menu startUpWithCaption: ('inspect whom?\\n(deepest at top)').\\n\\ttarget ifNil:[^self].\\n\\ttarget inspectInMorphic: evt! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/10/2000 14:26'!\\ninvokeMetaMenuAt: aPoint event: evt\\n\\t| menu morphs target |\\n\\tmenu _ CustomMenu new.\\n\\tmorphs _ self morphsAt: aPoint.\\n\\t(morphs includes: self) ifFalse:[morphs _ morphs copyWith: self].\\n\\tmorphs size = 1 ifTrue:[morphs first invokeMetaMenu: evt].\\n\\tmorphs do: [:m | \\n\\t\\tmenu add: (m knownName ifNil:[m class name asString]) action: m].\\n\\ttarget _ menu startUp.\\n\\ttarget ifNil:[^self].\\n\\ttarget invokeMetaMenu: evt! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'fc 4/27/2004 21:54'!\\ninvokeMetaMenu: evt\\n\\t| menu |\\n\\tmenu _ self buildMetaMenu: evt.\\n\\tmenu addTitle: self externalName.\\n\\tself world ifNotNil: [\\n\\t\\tmenu popUpEvent: evt in: self world\\n\\t]! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'sw 4/12/2005 23:09'!\\nmakeMultipleSiblings: evt\\n\\t\\\"Make multiple siblings, first prompting the user for how many\\\"\\n\\n\\t| result |\\n\\tself topRendererOrSelf couldMakeSibling ifFalse: [^ Beeper beep].\\n\\tresult _ FillInTheBlank request: 'how many siblings do you want?' translated initialAnswer: '2'.\\n\\tresult isEmptyOrNil ifTrue: [^ self].\\n\\tresult first isDigit ifFalse: [^ Beeper beep].\\n\\tself topRendererOrSelf makeSiblings: result asInteger.! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/5/2000 19:20'!\\nmakeNewPlayerInstance: evt\\n\\t\\\"Make a duplicate of the receiver's argument. This is called only where the argument has an associated Player as its costumee, and the intent here is to make another instance of the same uniclass as the donor Player itself. Much works, but there are flaws so this shouldn't be used without recognizing the risks\\\"\\n\\n\\tevt hand attachMorph: self usableSiblingInstance! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'sw 1/12/2001 22:47'!\\nmakeSiblingsLookLikeMe: evt\\n\\t\\\"Make all my siblings wear the same costume that I am wearing.\\\"\\n\\n\\t| aPlayer |\\n\\t(aPlayer _ self topRendererOrSelf player) belongsToUniClass ifFalse: [self error: 'not uniclass'].\\n\\taPlayer class allInstancesDo:\\n\\t\\t[:anInstance | anInstance == aPlayer ifFalse:\\n\\t\\t\\t[anInstance wearCostumeOf: aPlayer]]! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'sw 1/29/2001 17:11'!\\nmakeSiblings: count\\n\\t\\\"Make multiple sibling, and return the list\\\"\\n\\n\\t| aPosition anInstance listOfNewborns |\\n\\taPosition _ self position.\\n\\tlistOfNewborns _ (1 to: count asInteger) asArray collect: \\n\\t\\t[:anIndex |\\n\\t\\t\\tanInstance _ self usableSiblingInstance.\\n\\t\\t\\towner addMorphFront: anInstance.\\n\\t\\t\\taPosition _ aPosition + (10@10).\\n\\t\\t\\tanInstance position: aPosition.\\n\\t\\t\\tanInstance].\\n\\tself currentWorld startSteppingSubmorphsOf: self topRendererOrSelf owner.\\n\\t^ listOfNewborns! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'sw 4/19/2005 14:55'!\\nmaybeDuplicateMorph\\n\\t\\\"Maybe duplicate the morph\\\"\\n\\n\\tself okayToDuplicate ifTrue:\\n\\t\\t[self topRendererOrSelf duplicate openInHand]! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/5/2000 17:32'!\\nmaybeDuplicateMorph: evt\\n\\tself okayToDuplicate ifTrue:[^self duplicateMorph: evt]! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'RAA 2/19/2001 16:52'!\\nopenAPropertySheet\\n\\n\\tObjectPropertiesMorph basicNew\\n\\t\\ttargetMorph: self;\\n\\t\\tinitialize;\\n\\t\\topenNearTarget! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'RAA 3/15/2001 12:56'!\\nopenATextPropertySheet\\n\\n\\t\\\"should only be sent to morphs that are actually supportive\\\"\\n\\n\\tTextPropertiesMorph basicNew\\n\\t\\ttargetMorph: self;\\n\\t\\tinitialize;\\n\\t\\topenNearTarget! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'wiz 1/2/2005 01:06'!\\npotentialEmbeddingTargets\\n\\t\\\"Return the potential targets for embedding the receiver\\\"\\n\\n\\t| oneUp topRend |\\n\\t(oneUp _ (topRend _ self topRendererOrSelf) owner) ifNil:[^#()].\\n\\t^ (oneUp morphsAt: topRend referencePosition behind: topRend unlocked: true) select:\\n\\t\\t[:m | m isFlexMorph not]! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'wiz 7/17/2004 22:17'!\\npotentialTargets\\n\\t\\\"Return the potential targets for the receiver.\\n\\tThis is derived from Morph>>potentialEmbeddingTargets.\\\"\\n\\towner ifNil:[^#()].\\n\\t^owner morphsAt: self referencePosition behind: self unlocked: true not! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'wiz 7/20/2004 02:46'!\\npotentialTargetsAt: aPoint \\n\\t\\\"Return the potential targets for the receiver. \\n\\tThis is derived from Morph>>potentialEmbeddingTargets.\\\"\\n\\towner\\n\\t\\tifNil: [^ #()].\\n\\t^ owner\\n\\t\\tmorphsAt: aPoint\\n\\t\\t! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'sw 11/27/2001 14:59'!\\nresizeFromMenu\\n\\t\\\"Commence an interaction that will resize the receiver\\\"\\n\\n\\tself resizeMorph: ActiveEvent! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'st 9/14/2004 12:30'!\\nresizeMorph: evt\\n\\t| handle |\\n\\thandle _ HandleMorph new forEachPointDo: [:newPoint | \\n\\t\\tself extent: (self griddedPoint: newPoint) - self bounds topLeft].\\n\\tevt hand attachMorph: handle.\\n\\thandle startStepping.\\n! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/5/2000 16:50'!\\nsaveAsPrototype\\n\\t(SelectionMenu confirm: 'Make this morph the prototype for ', self class printString, '?')\\n\\t\\tifFalse: [^ self].\\n\\tself class prototype: self.\\n! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 9/27/2005 20:29'!\\nshowActions\\n\\t\\\"Put up a message list browser of all the code that this morph \\n\\twould run for mouseUp, mouseDown, mouseMove, mouseEnter, \\n\\tmouseLeave, and \\n\\tmouseLinger. tk 9/13/97\\\"\\n\\t| list cls selector adder |\\n\\tlist := SortedCollection new.\\n\\tadder := [:mrClass :mrSel | list\\n\\t\\t\\t\\tadd: (MethodReference new setStandardClass: mrClass methodSymbol: mrSel)].\\n\\t\\\"the eventHandler\\\"\\n\\tself eventHandler\\n\\t\\tifNotNil: [list := self eventHandler methodRefList.\\n\\t\\t\\t(self eventHandler handlesMouseDown: nil)\\n\\t\\t\\t\\tifFalse: [adder value: HandMorph value: #grabMorph:]].\\n\\t\\\"If not those, then non-default raw events\\\"\\n\\t#(#keyStroke: #mouseDown: #mouseEnter: #mouseLeave: #mouseMove: #mouseUp: #doButtonAction )\\n\\t\\tdo: [:sel | \\n\\t\\t\\tcls := self class whichClassIncludesSelector: sel.\\n\\t\\t\\tcls\\n\\t\\t\\t\\tifNotNil: [\\\"want more than default behavior\\\"\\n\\t\\t\\t\\t\\tcls == Morph\\n\\t\\t\\t\\t\\t\\tifFalse: [adder value: cls value: sel]]].\\n\\t\\\"The mechanism on a Button\\\"\\n\\t(self respondsTo: #actionSelector)\\n\\t\\tifTrue: [\\\"A button\\\"\\n\\t\\t\\tselector := self actionSelector.\\n\\t\\t\\tcls := self target class whichClassIncludesSelector: selector.\\n\\t\\t\\tcls\\n\\t\\t\\t\\tifNotNil: [\\\"want more than default behavior\\\"\\n\\t\\t\\t\\t\\tcls == Morph\\n\\t\\t\\t\\t\\t\\tifFalse: [adder value: cls value: selector]]].\\n\\tToolSet openMessageList: list name: 'Actions of ' , self printString autoSelect: false! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/5/2000 19:21'!\\nshowHiders\\n\\tself allMorphsDo:[:m | m show]! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'wiz 7/13/2006 22:09'!\\nsightTargets: event \\n\\t\\\"Return the potential targets for the receiver. \\n\\tThis is derived from Morph>>potentialEmbeddingTargets.\\\"\\n\\t| bullseye |\\n\\towner\\n\\t\\tifNil: [^ #()].\\n\\tbullseye := Point fromUserWithCursor: Cursor target.\\n\\tself targetFromMenu: (self potentialTargetsAt: bullseye) asKnownNameMenu popupAt: bullseye! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'wiz 7/13/2006 22:10'!\\nsightWorldTargets: event \\n\\t\\\"Return the potential targets for the receiver. \\n\\tThis is derived from Morph>>potentialEmbeddingTargets.\\\"\\n\\t| bullseye myWorld |\\n\\tmyWorld := self world\\n\\t\\tifNil: [^ #()].\\n\\tbullseye := Point fromUserWithCursor: Cursor target.\\n\\tself targetFromMenu: ( myWorld morphsAt: bullseye) asKnownNameMenu popupAt: bullseye! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'ar 10/5/2000 16:50'!\\nsubclassMorph\\n\\t\\\"Create a new subclass of this morph's class and make this morph be an instance of it.\\\"\\n\\n\\t| oldClass newClassName newClass newMorph |\\n\\toldClass _ self class.\\n\\tnewClassName _ FillInTheBlank\\n\\t\\trequest: 'Please give this new class a name'\\n\\t\\tinitialAnswer: oldClass name.\\n\\tnewClassName = '' ifTrue: [^ self].\\n\\t(Smalltalk includesKey: newClassName)\\n\\t\\tifTrue: [^ self inform: 'Sorry, there is already a class of that name'].\\n\\n\\tnewClass _ oldClass subclass: newClassName asSymbol\\n\\t\\tinstanceVariableNames: ''\\n\\t\\tclassVariableNames: ''\\n\\t\\tpoolDictionaries: ''\\n\\t\\tcategory: oldClass category asString.\\n\\tnewMorph _ self as: newClass.\\n\\tself become: newMorph.\\n! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'wiz 7/20/2004 01:25'!\\ntargetFromMenu: aMenu \\n\\t\\\"Some other morph become target of the receiver\\\"\\n\\t| newTarget |\\n\\t\\n\\tnewTarget := aMenu startUpWithCaption: self externalName , ' targets...'.\\n\\tnewTarget\\n\\t\\tifNil: [^ self].\\n\\tself target: newTarget! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'wiz 7/20/2004 12:22'!\\ntargetFromMenu: aMenu popupAt: aPoint \\n\\t\\\"Some other morph become target of the receiver\\\"\\n\\t| newTarget |\\n\\tnewTarget := aMenu startUpWithCaption: self externalName , ' targets... '\\n\\tat: aPoint .\\n\\t\\\"self halt .\\\"\\n\\tnewTarget\\n\\t\\tifNil: [^ self].\\n\\tself target: newTarget! !\\n\\n!Morph methodsFor: 'meta-actions' stamp: 'wiz 7/17/2004 23:27'!\\ntargetWith: evt\\n\\t\\\"Some other morph become target of the receiver\\\"\\n\\t| menu newTarget |\\n\\tmenu _ CustomMenu new.\\n\\tself potentialTargets do: [:m | \\n\\t\\tmenu add: (m knownName ifNil:[m class name asString]) action: m].\\n\\tnewTarget _ menu startUpWithCaption: ( self externalName, ' targets...').\\n\\tnewTarget ifNil:[^self].\\n\\tself target: newTarget.! !\\n\\n\\n!Morph methodsFor: 'miscellaneous' stamp: 'dgd 9/27/2004 12:12'!\\nroundUpStrays\\n\\tself submorphs\\n\\t\\tdo: [:each | each roundUpStrays]! !\\n\\n!Morph methodsFor: 'miscellaneous' stamp: 'sw 7/20/2001 00:15'!\\nsetExtentFromHalo: anExtent\\n\\t\\\"The user has dragged the grow box such that the receiver's extent would be anExtent. Do what's needed\\\"\\n\\n\\tself extent: anExtent! !\\n\\n!Morph methodsFor: 'miscellaneous' stamp: 'sw 2/2/2006 00:43'!\\nsetFlexExtentFromHalo: anExtent\\n\\t\\\"The user has dragged the grow box such that the receiver's extent would be anExtent. Do what's needed. Set the extent of the top renderer as indicated.\\\"\\n\\n\\tself addFlexShellIfNecessary.\\n\\tself topRendererOrSelf extent: anExtent! !\\n\\n\\n!Morph methodsFor: 'naming' stamp: 'fc 4/27/2004 21:58'!\\nchoosePartName\\n\\t\\\"Pick an unused name for this morph.\\\"\\n\\t| className |\\n\\tself world ifNil: [^nil].\\n\\t(self world model isKindOf: Component) ifTrue:\\n\\t\\t[self knownName ifNil: [^ self nameMeIn: self world]\\n\\t\\t\\t\\t\\tifNotNil: [^ self renameMe]].\\n\\tclassName _ self class name.\\n\\t(className size > 5 and: [className endsWith: 'Morph'])\\n\\t\\tifTrue: [className _ className copyFrom: 1 to: className size - 5].\\n\\t^ self world model addPartNameLike: className withValue: self! !\\n\\n!Morph methodsFor: 'naming' stamp: 'sw 10/31/2000 09:28'!\\ndownshiftedNameOfObjectRepresented\\n\\t\\\"Answer the downshiped version of the external name of the object represented\\\"\\n\\n\\t^ self nameOfObjectRepresented asLowercase! !\\n\\n!Morph methodsFor: 'naming' stamp: 'dgd 8/30/2003 15:52'!\\ninnocuousName\\n\\t\\\"Choose an innocuous name for the receiver -- one that does not end in the word Morph\\\"\\n\\n\\t| className allKnownNames |\\n\\tclassName _ self defaultNameStemForInstances.\\n\\t(className size > 5 and: [className endsWith: 'Morph'])\\n\\t\\tifTrue: [className _ className copyFrom: 1 to: className size - 5].\\n\\tclassName _ className asString translated.\\n\\tallKnownNames _ self world ifNil: [OrderedCollection new] ifNotNil: [self world allKnownNames].\\n\\t^ Utilities keyLike: className asString satisfying:\\n\\t\\t[:aName | (allKnownNames includes: aName) not]! !\\n\\n!Morph methodsFor: 'naming' stamp: 'sw 9/21/2000 13:18'!\\nnameForFindWindowFeature\\n\\t\\\"Answer the name to show in a list of windows-and-morphs to represent the receiver\\\"\\n\\n\\t^ self knownName ifNil: [self class name]! !\\n\\n!Morph methodsFor: 'naming' stamp: 'dgd 2/22/2003 14:33'!\\nnameInModel\\n\\t\\\"Return the name for this morph in the underlying model or nil.\\\"\\n\\n\\t| w |\\n\\tw := self world.\\n\\tw isNil ifTrue: [^nil] ifFalse: [^w model nameFor: self]! !\\n\\n!Morph methodsFor: 'naming' stamp: 'sw 10/31/2000 09:24'!\\nnameOfObjectRepresented\\n\\t\\\"Answer the external name of the object represented\\\"\\n\\n\\t^ self externalName! !\\n\\n!Morph methodsFor: 'naming' stamp: 'gm 2/22/2003 13:16'!\\nname: aName \\n\\t(aName isString) ifTrue: [self setNameTo: aName]! !\\n\\n!Morph methodsFor: 'naming' stamp: 'dgd 2/16/2003 21:57'!\\nsetNamePropertyTo: aName \\n\\t\\\"change the receiver's externalName\\\"\\n\\tself assureExtension externalName: aName! !\\n\\n!Morph methodsFor: 'naming' stamp: 'yo 12/3/2004 17:02'!\\nsetNameTo: aName \\n\\t| nameToUse nameString |\\n\\tnameToUse := aName ifNotNil: \\n\\t\\t\\t\\t\\t[(nameString := aName asString) notEmpty ifTrue: [nameString] ifFalse: ['*']].\\n\\tself setNamePropertyTo: nameToUse\\t\\\"no Texts here!!\\\"! !\\n\\n!Morph methodsFor: 'naming' stamp: 'gm 2/22/2003 13:16'!\\nspecialNameInModel\\n\\t\\\"Return the name for this morph in the underlying model or nil.\\\"\\n\\n\\t\\\"Not an easy problem. For now, take the first part of the mouseDownSelector symbol in my eventHandler (fillBrushMouseUp:morph: gives 'fillBrush'). 5/26/97 tk\\\"\\n\\n\\t| hh |\\n\\t(self isMorphicModel) \\n\\t\\tifTrue: [^self slotName]\\n\\t\\tifFalse: \\n\\t\\t\\t[self eventHandler ifNotNil: \\n\\t\\t\\t\\t\\t[self eventHandler mouseDownSelector ifNotNil: \\n\\t\\t\\t\\t\\t\\t\\t[hh := self eventHandler mouseDownSelector indexOfSubCollection: 'Mouse'\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tstartingAt: 1.\\n\\t\\t\\t\\t\\t\\t\\thh > 0 \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [^self eventHandler mouseDownSelector copyFrom: 1 to: hh - 1]].\\n\\t\\t\\t\\t\\tself eventHandler mouseUpSelector ifNotNil: \\n\\t\\t\\t\\t\\t\\t\\t[hh := self eventHandler mouseUpSelector indexOfSubCollection: 'Mouse'\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tstartingAt: 1.\\n\\t\\t\\t\\t\\t\\t\\thh > 0 ifTrue: [^self eventHandler mouseUpSelector copyFrom: 1 to: hh - 1]]]].\\n\\n\\t\\\"\\t(self eventHandler mouseDownRecipient respondsTo: #nameFor:) ifTrue: [\\n\\t\\t\\t\\t\\t^ self eventHandler mouseDownRecipient nameFor: self]]].\\t\\\"\\n\\t\\\"myModel _ self findA: MorphicModel.\\n\\t\\t\\tmyModel ifNotNil: [^ myModel slotName]\\\"\\n\\t^self world specialNameInModelFor: self! !\\n\\n!Morph methodsFor: 'naming' stamp: 'sw 10/27/2000 17:47'!\\ntryToRenameTo: aName\\n\\t\\\"A new name has been submited; make sure it's appropriate, and react accordingly. This circumlocution provides the hook by which the simple renaming of a field can result in a change to variable names in a stack, etc. There are some problems to worry about here.\\\"\\n\\n\\t| aStack |\\n\\t(self holdsSeparateDataForEachInstance and: [(aStack _ self stack) notNil])\\n\\t\\tifTrue:\\n\\t\\t\\t[self topRendererOrSelf setNameTo: aName.\\n\\t\\t\\taStack reassessBackgroundShape]\\n\\t\\tifFalse:\\n\\t\\t\\t[self renameTo: aName]! !\\n\\n!Morph methodsFor: 'naming' stamp: 'sw 1/29/2001 02:49'!\\nupdateAllScriptingElements\\n\\t\\\"A sledge-hammer sweep from the world down to make sure that all live scripting elements are up to date. Presently in eclipse, not sent at the moment.\\\"\\n\\n\\t| aPasteUp |\\n\\t(aPasteUp _ self topPasteUp) ifNotNil:\\n\\t\\t[aPasteUp allTileScriptingElements do: [:m | m bringUpToDate]]! !\\n\\n\\n!Morph methodsFor: 'objects from disk' stamp: 'tk 11/26/2004 06:02'!\\nconvertToCurrentVersion: varDict refStream: smartRefStrm\\n\\n\\n\\n\\t(varDict at: #ClassName) == #DropShadowMorph ifTrue: [\\n\\n\\t\\tvarDict at: #ClassName put: #Morph.\\t\\\"so we don't\\n\\nrepeat this\\\"\\n\\n\\t\\t^ self convertNovember2000DropShadow: varDict using:\\n\\nsmartRefStrm\\n\\n\\t\\t\\t\\\"always returns a new object of a different class\\\"\\n\\n\\t].\\n\\n\\tvarDict at: 'costumee' ifPresent: [ :x |\\n\\n\\t\\tself convertAugust1998: varDict using: smartRefStrm].\\n\\n\\t\\t\\\"never returns a different object\\\"\\n\\n\\n\\n\\t\\\"5/18/2000\\\"\\n\\n\\tvarDict at: 'openToDragNDrop' ifPresent: [ :x | self\\n\\nenableDragNDrop: x ].\\n\\n\\t^super convertToCurrentVersion: varDict refStream: smartRefStrm.\\n\\n\\n\\n\\n\\n! !\\n\\n!Morph methodsFor: 'objects from disk' stamp: 'dgd 2/22/2003 14:33'!\\nobjectForDataStream: refStrm \\n\\t\\\"I am being written out on an object file\\\"\\n\\n\\t| dp |\\n\\tself sqkPage ifNotNil: \\n\\t\\t\\t[refStrm rootObject == self | (refStrm rootObject == self sqkPage) \\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[self url notEmpty \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[dp := self sqkPage copyForSaving.\\t\\\"be careful touching this object!!\\\"\\n\\t\\t\\t\\t\\t\\t\\trefStrm replace: self with: dp.\\n\\t\\t\\t\\t\\t\\t\\t^dp]]].\\n\\tself prepareToBeSaved.\\t\\\"Amen\\\"\\n\\t^self! !\\n\\n!Morph methodsFor: 'objects from disk' stamp: 'tk 7/11/1998 18:53'!\\nstoreDataOn: aDataStream\\n\\t\\\"Let all Morphs be written out. All owners are weak references. They only go out if the owner is in the tree being written.\\\"\\n\\t| cntInstVars cntIndexedVars ti localInstVars |\\n\\n\\t\\\"block my owner unless he is written out by someone else\\\"\\n\\tcntInstVars _ self class instSize.\\n\\tcntIndexedVars _ self basicSize.\\n\\tlocalInstVars _ Morph instVarNames.\\n\\tti _ 2. \\n\\t((localInstVars at: ti) = 'owner') & (Morph superclass == Object) ifFalse:\\n\\t\\t\\t[self error: 'this method is out of date'].\\n\\taDataStream\\n\\t\\tbeginInstance: self class\\n\\t\\tsize: cntInstVars + cntIndexedVars.\\n\\t1 to: ti-1 do:\\n\\t\\t[:i | aDataStream nextPut: (self instVarAt: i)].\\n\\taDataStream nextPutWeak: owner.\\t\\\"owner only written if in our tree\\\"\\n\\tti+1 to: cntInstVars do:\\n\\t\\t[:i | aDataStream nextPut: (self instVarAt: i)].\\n\\t1 to: cntIndexedVars do:\\n\\t\\t[:i | aDataStream nextPut: (self basicAt: i)]! !\\n\\n\\n!Morph methodsFor: 'other events' stamp: 'sw 8/1/2001 14:08'!\\nmenuButtonMouseEnter: event\\n\\t\\\"The mouse entered a menu-button area; show the menu cursor temporarily\\\"\\n\\n\\tevent hand showTemporaryCursor: Cursor menu! !\\n\\n!Morph methodsFor: 'other events' stamp: 'sw 8/1/2001 14:09'!\\nmenuButtonMouseLeave: event\\n\\t\\\"The mouse left a menu-button area; restore standard cursor\\\"\\n\\n\\tevent hand showTemporaryCursor: nil! !\\n\\n\\n!Morph methodsFor: 'parts bin' stamp: 'sw 8/12/2001 02:07'!\\ninitializeToStandAlone\\n\\t\\\"Set up the receiver, created by a #basicNew and now ready to be initialized, as a fully-formed morph suitable for providing a graphic for a parts bin surrogate, and, when such a parts-bin surrogate is clicked on, for attaching to the hand as a viable stand-alone morph. Because of historical precedent, #initialize has been expected to handle this burden, though a great number of morphs actually cannot stand alone. In any case, by default we call the historical #initialize, though unhappily, so that all existing morphs will work no worse than before when using this protocol.\\\"\\n\\n\\tself initialize! !\\n\\n!Morph methodsFor: 'parts bin' stamp: 'di 11/13/2000 00:49'!\\ninPartsBin\\n\\n\\tself isPartsDonor ifTrue: [^ true].\\n\\tself allOwnersDo: [:m | m isPartsBin ifTrue: [^ true]].\\n\\t^ false\\n! !\\n\\n!Morph methodsFor: 'parts bin' stamp: 'sw 8/12/97 14:16'!\\nisPartsBin\\n\\t^ false! !\\n\\n!Morph methodsFor: 'parts bin' stamp: 'md 2/27/2006 09:53'!\\nisPartsDonor\\n\\t\\\"answer whether the receiver is PartsDonor\\\"\\n\\textension ifNil: [^ false].\\n\\t^ extension isPartsDonor! !\\n\\n!Morph methodsFor: 'parts bin' stamp: 'md 2/27/2006 09:59'!\\nisPartsDonor: aBoolean \\n\\t\\\"change the receiver's isPartDonor property\\\"\\n\\t(extension isNil and: [aBoolean not]) ifTrue: [^ self].\\n\\tself assureExtension isPartsDonor: aBoolean! !\\n\\n!Morph methodsFor: 'parts bin' stamp: 'di 8/11/1998 13:02'!\\nmarkAsPartsDonor\\n\\t\\\"Mark the receiver specially so that mouse actions on it are interpreted as 'tearing off a copy'\\\"\\n\\n\\tself isPartsDonor: true! !\\n\\n!Morph methodsFor: 'parts bin' stamp: 'ar 10/6/2000 22:45'!\\npartRepresented\\n\\t^self! !\\n\\n!Morph methodsFor: 'parts bin' stamp: 'sw 4/22/1998 14:45'!\\nresidesInPartsBin\\n\\t\\\"Answer true if the receiver is, or has some ancestor owner who is, a parts bin\\\"\\n\\t^ owner ifNotNil: [owner residesInPartsBin] ifNil: [false]! !\\n\\n\\n!Morph methodsFor: 'pen' stamp: 'sw 8/11/1998 16:46'!\\nchoosePenColor: evt\\n\\tself assuredPlayer choosePenColor: evt! !\\n\\n!Morph methodsFor: 'pen' stamp: 'sw 8/11/1998 16:46'!\\nchoosePenSize\\n\\tself assuredPlayer choosePenSize! !\\n\\n!Morph methodsFor: 'pen' stamp: 'sw 8/11/1998 16:53'!\\ngetPenColor\\n\\t^ self player ifNotNil: [self actorState getPenColor] ifNil: [Color green]! !\\n\\n!Morph methodsFor: 'pen' stamp: 'sw 8/11/1998 16:53'!\\ngetPenDown\\n\\tself player ifNil: [^ false].\\n\\t^ self actorState getPenDown! !\\n\\n!Morph methodsFor: 'pen' stamp: 'sw 8/11/1998 16:53'!\\ngetPenSize\\n\\tself player ifNil: [^ 1].\\n\\t^ self actorState getPenSize! !\\n\\n!Morph methodsFor: 'pen' stamp: 'sw 8/11/1998 16:46'!\\nliftPen\\n\\tself assuredPlayer liftPen! !\\n\\n!Morph methodsFor: 'pen' stamp: 'sw 8/11/1998 16:46'!\\nlowerPen\\n\\tself assuredPlayer lowerPen! !\\n\\n!Morph methodsFor: 'pen' stamp: 'sw 8/11/1998 16:46'!\\npenColor: aColor\\n\\tself assuredPlayer penColor: aColor! !\\n\\n!Morph methodsFor: 'pen' stamp: 'di 9/3/1998 10:38'!\\npenUpWhile: changeBlock \\n\\t\\\"Suppress any possible pen trail during the execution of changeBlock\\\"\\n\\tself getPenDown\\n\\t\\tifTrue: [\\\"If this is a costume for a player with its pen down, suppress any line.\\\"\\n\\t\\t\\t\\tself liftPen.\\n\\t\\t\\t\\tchangeBlock value.\\n\\t\\t\\t\\tself lowerPen]\\n\\t\\tifFalse: [\\\"But usually, just do it.\\\"\\n\\t\\t\\t\\tchangeBlock value]! !\\n\\n!Morph methodsFor: 'pen' stamp: 'dgd 2/22/2003 14:36'!\\ntrailMorph\\n\\t\\\"You can't draw trails on me, but try my owner.\\\"\\n\\n\\towner isNil ifTrue: [^nil].\\n\\t^owner trailMorph! !\\n\\n\\n!Morph methodsFor: 'printing' stamp: 'bf 7/17/2003 12:53'!\\nclipText\\n\\t\\\"Copy the text in the receiver or in its submorphs to the clipboard\\\"\\n\\t| content |\\n\\t\\\"My own text\\\"\\n\\tcontent _ self userString.\\n\\t\\\"Or in my submorphs\\\"\\n\\tcontent ifNil: [\\n\\t\\t| list |\\n\\t\\tlist _ self allStringsAfter: nil.\\n\\t\\tlist notEmpty ifTrue: [\\n\\t\\t\\tcontent _ String streamContents: [:stream |\\n\\t\\t\\t\\tlist do: [:each | stream nextPutAll: each; cr]]]].\\n\\t\\\"Did we find something?\\\"\\n\\tcontent\\n\\t\\tifNil: [self flash \\\"provide feedback\\\"]\\n\\t\\tifNotNil: [Clipboard clipboardText: content].! !\\n\\n!Morph methodsFor: 'printing' stamp: 'dgd 2/22/2003 14:27'!\\ncolorString: aColor \\n\\taColor isNil ifTrue: [^'nil'].\\n\\tColor colorNames \\n\\t\\tdo: [:colorName | aColor = (Color perform: colorName) ifTrue: [^'Color ' , colorName]].\\n\\t^aColor storeString! !\\n\\n!Morph methodsFor: 'printing'!\\nconstructorString\\n\\n\\t^ String streamContents: [:s | self printConstructorOn: s indent: 0].\\n! !\\n\\n!Morph methodsFor: 'printing'!\\nfullPrintOn: aStream\\n\\n\\taStream nextPutAll: self class name , ' newBounds: (';\\n\\t\\tprint: bounds;\\n\\t\\tnextPutAll: ') color: ' , (self colorString: color)! !\\n\\n!Morph methodsFor: 'printing'!\\ninitString\\n\\n\\t^ String streamContents: [:s | self fullPrintOn: s]! !\\n\\n!Morph methodsFor: 'printing' stamp: 'RAA 2/26/2001 07:22'!\\nmorphReport\\n\\n\\t^self morphReportFor: #(hResizing vResizing bounds)! !\\n\\n!Morph methodsFor: 'printing' stamp: 'RAA 2/25/2001 17:47'!\\nmorphReportFor: attributeList\\n\\n\\t| s |\\n\\n\\ts _ WriteStream on: String new.\\n\\tself\\n\\t\\tmorphReportFor: attributeList \\n\\t\\ton: s \\n\\t\\tindent: 0.\\n\\tStringHolder new contents: s contents; openLabel: 'morph report'! !\\n\\n!Morph methodsFor: 'printing' stamp: 'RAA 2/25/2001 17:48'!\\nmorphReportFor: attributeList on: aStream indent: anInteger\\n\\n\\tanInteger timesRepeat: [aStream tab].\\n\\taStream print: self; space.\\n\\tattributeList do: [ :a | aStream print: (self perform: a); space].\\n\\taStream cr.\\n\\tsubmorphs do: [ :sub |\\n\\t\\tsub morphReportFor: attributeList on: aStream indent: anInteger + 1\\n\\t].! !\\n\\n!Morph methodsFor: 'printing' stamp: 'RAA 2/1/2001 17:42'!\\npagesHandledAutomatically\\n\\n\\t^false! !\\n\\n!Morph methodsFor: 'printing'!\\nprintConstructorOn: aStream indent: level\\n\\n\\t^ self printConstructorOn: aStream indent: level nodeDict: IdentityDictionary new\\n! !\\n\\n!Morph methodsFor: 'printing'!\\nprintConstructorOn: aStream indent: level nodeDict: nodeDict\\n\\t| nodeString |\\n\\t(nodeString _ nodeDict at: self ifAbsent: [nil])\\n\\t\\tifNotNil: [^ aStream nextPutAll: nodeString].\\n\\tsubmorphs isEmpty ifFalse: [aStream nextPutAll: '('].\\n\\taStream nextPutAll: '('.\\n\\tself fullPrintOn: aStream.\\n\\taStream nextPutAll: ')'.\\n\\tsubmorphs isEmpty ifTrue: [^ self].\\n\\tsubmorphs size <= 4\\n\\tifTrue:\\n\\t\\t[aStream crtab: level+1;\\n\\t\\t\\tnextPutAll: 'addAllMorphs: (Array'.\\n\\t\\t1 to: submorphs size do:\\n\\t\\t\\t[:i | aStream crtab: level+1; nextPutAll: 'with: '.\\n\\t\\t\\t(submorphs at: i) printConstructorOn: aStream indent: level+1 nodeDict: nodeDict].\\n\\t\\taStream nextPutAll: '))']\\n\\tifFalse:\\n\\t\\t[aStream crtab: level+1;\\n\\t\\t\\tnextPutAll: 'addAllMorphs: ((Array new: ', submorphs size printString, ')'.\\n\\t\\t1 to: submorphs size do:\\n\\t\\t\\t[:i |\\n\\t\\t\\taStream crtab: level+1; nextPutAll: 'at: ', i printString, ' put: '.\\n\\t\\t\\t(submorphs at: i) printConstructorOn: aStream indent: level+1 nodeDict: nodeDict.\\n\\t\\t\\taStream nextPutAll: ';'].\\n\\t\\taStream crtab: level+1; nextPutAll: 'yourself))']! !\\n\\n!Morph methodsFor: 'printing' stamp: 'dgd 2/22/2003 19:05'!\\nprintOn: aStream \\n\\t| aName |\\n\\tsuper printOn: aStream.\\n\\t(aName := self knownName) notNil \\n\\t\\tifTrue: [aStream nextPutAll: '<' , aName , '>'].\\n\\taStream nextPutAll: '('.\\n\\taStream\\n\\t\\tprint: self identityHash;\\n\\t\\tnextPutAll: ')'! !\\n\\n!Morph methodsFor: 'printing' stamp: 'RAA 9/18/2000 10:22'!\\nprintSpecs\\n\\n\\t| printSpecs |\\n\\n\\tprintSpecs _ self valueOfProperty: #PrintSpecifications.\\n\\tprintSpecs ifNil: [\\n\\t\\tprintSpecs _ PrintSpecifications defaultSpecs.\\n\\t\\tself printSpecs: printSpecs.\\n\\t].\\n\\t^printSpecs! !\\n\\n!Morph methodsFor: 'printing' stamp: 'RAA 9/18/2000 10:21'!\\nprintSpecs: aPrintSecification\\n\\n\\tself setProperty: #PrintSpecifications toValue: aPrintSecification.\\n! !\\n\\n!Morph methodsFor: 'printing' stamp: 'jm 5/28/1998 18:00'!\\nprintStructureOn: aStream indent: tabCount\\n\\n\\ttabCount timesRepeat: [aStream tab].\\n\\tself printOn: aStream.\\n\\taStream cr.\\n\\tself submorphsDo: [:m | m printStructureOn: aStream indent: tabCount + 1].\\n! !\\n\\n!Morph methodsFor: 'printing' stamp: 'sw 10/27/2000 17:45'!\\nreportableSize\\n\\t\\\"Answer a size worth reporting as the receiver's size in a list view\\\"\\n\\n\\t| total |\\n\\ttotal _ super reportableSize.\\n\\tsubmorphs do:\\n\\t\\t[:m | total _ total + m reportableSize].\\n\\t^ total! !\\n\\n!Morph methodsFor: 'printing' stamp: 'jm 5/28/1998 17:58'!\\nstructureString\\n\\t\\\"Return a string that showing this morph and all its submorphs in an indented list that reflects its structure.\\\"\\n\\n\\t| s |\\n\\ts _ WriteStream on: (String new: 1000).\\n\\tself printStructureOn: s indent: 0.\\n\\t^ s contents\\n! !\\n\\n!Morph methodsFor: 'printing' stamp: 'sw 10/27/2000 17:47'!\\ntextToPaste\\n\\t\\\"If the receiver has text to offer pasting, answer it, else answer nil\\\"\\n\\n\\t^ nil! !\\n\\n\\n!Morph methodsFor: 'rotate scale and flex' stamp: 'sw 3/30/2005 03:44'!\\naddFlexShell\\n\\t\\\"Wrap a rotating and scaling shell around this morph.\\\"\\n\\n\\t| oldHalo flexMorph myWorld anIndex |\\n\\n\\tmyWorld _ self world.\\n\\toldHalo _ self halo.\\n\\tanIndex _ self owner submorphIndexOf: self.\\n\\tself owner addMorph: (flexMorph _ self newTransformationMorph asFlexOf: self)\\n\\t\\tasElementNumber: anIndex.\\n\\tself transferStateToRenderer: flexMorph.\\n\\toldHalo ifNotNil: [oldHalo setTarget: flexMorph].\\n\\tmyWorld ifNotNil: [myWorld startSteppingSubmorphsOf: flexMorph].\\n\\n\\t^ flexMorph! !\\n\\n!Morph methodsFor: 'rotate scale and flex' stamp: 'di 11/28/2001 18:22'!\\naddFlexShellIfNecessary\\n\\t\\\"If this morph requires a flex shell to scale or rotate,\\n\\t\\tthen wrap it in one and return it.\\n\\tPolygons, eg, may override to return themselves.\\\"\\n\\n\\t^ self addFlexShell! !\\n\\n!Morph methodsFor: 'rotate scale and flex' stamp: 'ar 11/24/1998 14:19'!\\nkeepsTransform\\n\\t\\\"Return true if the receiver will keep it's transform while being grabbed by a hand.\\\"\\n\\t^false! !\\n\\n!Morph methodsFor: 'rotate scale and flex' stamp: 'ar 2/16/1999 18:59'!\\nnewTransformationMorph\\n\\t^TransformationMorph new! !\\n\\n!Morph methodsFor: 'rotate scale and flex' stamp: 'mu 3/29/2004 17:33'!\\nremoveFlexShell\\n\\tself isFlexed\\n\\t\\tifTrue: [self owner removeFlexShell]! !\\n\\n!Morph methodsFor: 'rotate scale and flex' stamp: 'jm 4/25/1998 05:19'!\\nrotationDegrees\\n\\t\\\"Default implementation.\\\"\\n\\n\\t^ 0.0\\n! !\\n\\n\\n!Morph methodsFor: 'rounding' stamp: 'mk 8/7/2005 10:03'!\\ncornerStyle: aSymbol\\n\\t\\\"This method makes it possible to set up desired corner style. aSymbol has to be one of:\\n\\t\\t#square\\n\\t\\t#rounded\\\"\\n\\n\\taSymbol == #square\\n\\t\\tifTrue:[self removeProperty: #cornerStyle]\\n\\t\\tifFalse:[self setProperty: #cornerStyle toValue: aSymbol].\\n\\tself changed! !\\n\\n!Morph methodsFor: 'rounding' stamp: 'mk 8/14/2005 13:31'!\\nroundedCorners\\n\\t\\\"Return a list of those corners to round.\\n\\n\\t\\t1-4\\n\\t\\t| |\\n\\t\\t2-3\\n\\n\\tReturned array contains `codes' of those corners, which should be rounded.\\n\\n\\t1 denotes top-left corner\\n\\t2 denotes bottom-left corner\\n\\t3 denotes bottom-right corner\\n\\t4 denotes top-right corner.\\n\\n\\tThus, if this method returned #(2 3) that would mean that bottom (left and right)\\n\\tcorners would be rounded whereas top (left and right) corners wouldn't be rounded.\\n\\n\\tThis method returns #(1 2 3 4) and that means that all the corners should be rounded.\\\"\\n\\n\\t^ #(1 2 3 4)! !\\n\\n!Morph methodsFor: 'rounding' stamp: 'dgd 9/6/2003 18:27'!\\nroundedCornersString\\n\\t\\\"Answer the string to put in a menu that will invite the user to \\n\\tswitch to the opposite corner-rounding mode\\\"\\n\\t^ (self wantsRoundedCorners\\n\\t\\tifTrue: ['<yes>']\\n\\t\\tifFalse: ['<no>'])\\n\\t\\t, 'round corners' translated! !\\n\\n!Morph methodsFor: 'rounding' stamp: 'ar 12/25/2001 19:44'!\\ntoggleCornerRounding\\n\\tself cornerStyle == #rounded\\n\\t\\tifTrue: [self cornerStyle: #square]\\n\\t\\tifFalse: [self cornerStyle: #rounded].\\n\\tself changed! !\\n\\n!Morph methodsFor: 'rounding' stamp: 'ar 12/22/2001 22:45'!\\nwantsRoundedCorners\\n\\t\\\"Return true if the receiver wants its corners rounded\\\"\\n\\t^ self cornerStyle == #rounded! !\\n\\n\\n\\n\\n\\n\\n!Morph methodsFor: 'scripting' stamp: 'dgd 7/4/2004 12:41'!\\narrowDeltaFor: aGetSelector \\n\\t\\\"Answer a number indicating the default arrow delta to be \\n\\tused in a numeric readout with the given get-selector. This is \\n\\ta hook that subclasses of Morph can reimplement.\\\"\\n\\taGetSelector == #getScaleFactor\\n\\t\\tifTrue: [^ 0.1].\\n\\t^ 1! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'ar 1/25/2001 12:50'!\\nasEmptyPermanentScriptor\\n\\t\\\"Answer a new empty permanent scriptor derived from info deftly secreted in the receiver. Good grief\\\"\\n\\n\\t| aScriptor aPlayer |\\n\\taPlayer _ self valueOfProperty: #newPermanentPlayer.\\n\\taPlayer assureUniClass.\\n\\taScriptor _ aPlayer newScriptorAround: nil.\\n\\taScriptor position: (self world primaryHand position - (10 @ 10)).\\n\\taPlayer updateAllViewersAndForceToShow: #scripts.\\n\\t^ aScriptor! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'sw 10/17/2001 09:46'!\\nbringTileScriptingElementsUpToDate\\n\\t\\\"Send #bringUpToDate to every tile-scripting element of the receiver, including possibly the receiver itself\\\"\\n\\n\\t(self allMorphs select: [:s | s isTileScriptingElement]) do:\\n\\t\\t[:el | el bringUpToDate]! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'RAA 3/9/2001 11:39'!\\nbringUpToDate\\n\\n\\t(self buttonProperties ifNil: [^self]) bringUpToDate! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'sw 7/19/2005 01:55'!\\ndefaultFloatPrecisionFor: aGetSelector\\n\\t\\\"Answer a number indicating the default float precision to be used in a numeric readout for which the receiver provides the data. Individual morphs can override this. Showing fractional values for readouts of getCursor was in response to an explicit request from ack\\\"\\n\\n\\t(self renderedMorph decimalPlacesForGetter: aGetSelector) ifNotNilDo: [:places | ^ (Utilities floatPrecisionForDecimalPlaces: places)].\\n\\n\\t(#(getCursor getNumericValue getNumberAtCursor getCursorWrapped getScaleFactor getUnitVector getAlpha) includes: aGetSelector)\\n\\t\\tifTrue:\\n\\t\\t\\t[^ 0.01].\\n\\t^ 1! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'sw 8/12/2005 13:26'!\\nfilterViewerCategoryDictionary: dict\\n\\t\\\"dict has keys of categories and values of priority.\\n\\tYou can re-order or remove categories here.\\\"\\n\\n\\tself wantsConnectionVocabulary\\n\\t\\tifFalse: [ dict removeKey: #'connections to me' ifAbsent: [].\\n\\t\\t\\tdict removeKey: #connection ifAbsent: []].\\n\\tself wantsConnectorVocabulary\\n\\t\\tifFalse: [ dict removeKey: #connector ifAbsent: [] ].\\n\\tself wantsEmbeddingsVocabulary\\n\\t\\tifFalse: [dict removeKey: #embeddings ifAbsent: []].\\n\\tPreferences eToyFriendly\\n\\t\\tifTrue:\\n\\t\\t\\t[dict removeKey: #layout ifAbsent: []].\\n\\t(Preferences eToyFriendly or: [self isWorldMorph not]) ifTrue:\\n\\t\\t[dict removeKey: #preferences ifAbsent: []].! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'tk 10/1/97 18:23'!\\nisTileLike\\n\\t\\\"Cannot be dropped into a script\\\"\\n\\t^ false! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'RAA 3/9/2001 11:47'!\\nisTileScriptingElement\\n\\n\\t^ self hasButtonProperties and: [self buttonProperties isTileScriptingElement]! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'sw 8/11/1998 16:53'!\\njettisonScripts\\n\\tself player ifNotNil: [self player class jettisonScripts]! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'LC 9/28/1999 21:57'!\\nmakeAllTilesColored\\n\\tself allMorphsDo: \\n\\t\\t[:m | m restoreTypeColor]! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'LC 9/28/1999 21:57'!\\nmakeAllTilesGreen\\n\\tself allMorphsDo: \\n\\t\\t[:m | m useUniformTileColor]! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'sw 8/11/1998 16:59'!\\nrestoreTypeColor\\n\\tself player ifNotNil: [self player allScriptEditors do:\\n\\t\\t[:anEditor | anEditor allMorphsDo:\\n\\t\\t\\t[:m | m restoreTypeColor]]]! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'sw 8/11/1998 16:46'!\\nscriptEditorFor: aScriptName\\n\\t^ self assuredPlayer scriptEditorFor: aScriptName! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'sw 7/5/2005 00:31'!\\ntearOffTile\\n\\t\\\"Tear off a tile representing the player associated with the receiver. This is obtained from the top renderer\\\"\\n\\n\\t^ self topRendererOrSelf assuredPlayer tearOffTileForSelf! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'nk 8/21/2004 12:17'!\\ntriggerScript: aSymbol\\n\\t\\\"Have my player perform the script of the given name, which is guaranteed to exist.\\\"\\n\\n\\t^self assuredPlayer triggerScript: aSymbol! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'sw 8/11/1998 16:55'!\\nuseUniformTileColor\\n\\tself player ifNotNil:\\n\\t\\t[self player allScriptEditors do:\\n\\t\\t\\t[:anEditor | anEditor allMorphsDo:\\n\\t\\t\\t\\t[:m | m useUniformTileColor]]]! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'sw 10/18/2000 10:32'!\\nviewAfreshIn: aPasteUp showingScript: aScriptName at: aPosition\\n\\t\\\"Obtain a smartly updated ScriptEditor for the given script name and zap it into place at aPosition\\\"\\n\\n\\t| anEditor |\\n\\tself player updateAllViewersAndForceToShow: #scripts.\\n\\tanEditor _ self player scriptEditorFor: aScriptName.\\n\\taPasteUp ifNotNil: [aPasteUp addMorph: anEditor].\\n\\tanEditor position: aPosition.\\n\\tanEditor currentWorld startSteppingSubmorphsOf: anEditor! !\\n\\n!Morph methodsFor: 'scripting' stamp: 'nk 8/21/2004 08:39'!\\nwantsConnectionVocabulary\\n\\tsubmorphs ifNil: [ ^true ].\\t\\\"called from EToyVocabulary>>initialize after basicNew\\\"\\n\\n\\t^ (Preferences valueOfFlag: #alwaysShowConnectionVocabulary)\\n\\t\\tor: [ self connections isEmpty not ]! !\\n\\n\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'sw 3/22/2000 14:27'!\\narrangeToStartStepping\\n\\t\\\"Arrange to start getting sent the 'step' message, but don't do that initial #step call that startStepping does\\\"\\n\\n\\tself arrangeToStartSteppingIn: self world! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'sw 3/22/2000 14:26'!\\narrangeToStartSteppingIn: aWorld\\n\\t\\\"Start getting sent the 'step' message in aWorld. Like startSteppingIn:, but without the initial one to get started'\\\"\\n\\taWorld ifNotNil:\\n\\t\\t[aWorld startStepping: self.\\n\\t\\tself changed]! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'sw 3/22/2000 14:28'!\\nisStepping\\n\\t\\\"Return true if the receiver is currently stepping in its world\\\"\\n\\t| aWorld |\\n\\t^ (aWorld _ self world)\\n\\t\\tifNil:\\t\\t[false]\\n\\t\\tifNotNil:\\t[aWorld isStepping: self]! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'ar 10/22/2000 16:43'!\\nisSteppingSelector: aSelector\\n\\t\\\"Return true if the receiver is currently stepping in its world\\\"\\n\\t| aWorld |\\n\\t^ (aWorld _ self world)\\n\\t\\tifNil:\\t\\t[false]\\n\\t\\tifNotNil:\\t[aWorld isStepping: self selector: aSelector]! !\\n\\n!Morph methodsFor: 'stepping and presenter'!\\nstart\\n\\t\\\"Start running my script. For ordinary morphs, this means start stepping.\\\"\\n\\n\\tself startStepping.\\n! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'ar 1/31/2001 13:07'!\\nstartStepping\\n\\t\\\"Start getting sent the 'step' message.\\\"\\n\\tself startStepping: #stepAt: at: Time millisecondClockValue arguments: nil stepTime: nil.! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'sw 7/19/1998 11:51'!\\nstartSteppingIn: aWorld\\n\\t\\\"Start getting sent the 'step' message in aWorld\\\"\\n\\n\\tself step. \\\"one to get started!!\\\"\\n\\taWorld ifNotNil: [aWorld startStepping: self].\\n\\tself changed! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'ar 10/22/2000 16:42'!\\nstartSteppingSelector: aSelector\\n\\t\\\"Start getting sent the 'step' message.\\\"\\n\\tself startStepping: aSelector at: Time millisecondClockValue arguments: nil stepTime: nil.! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'ar 10/22/2000 16:36'!\\nstartStepping: aSelector at: scheduledTime arguments: args stepTime: stepTime\\n\\t\\\"Start stepping the receiver\\\"\\n\\t| w |\\n\\tw _ self world.\\n\\tw ifNotNil: [\\n\\t\\tw startStepping: self at: scheduledTime selector: aSelector arguments: args stepTime: stepTime.\\n\\t\\tself changed].! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'ar 2/12/2001 17:04'!\\nstep\\n\\t\\\"Do some periodic activity. Use startStepping/stopStepping to start and stop getting sent this message. The time between steps is specified by this morph's answer to the stepTime message. The generic version dispatches control to the player, if any. The nasty circumlocation about owner's transformation is necessitated by the flexing problem that the player remains in the properties dictionary both of the flex and the real morph. In the current architecture, only the top renderer's pointer to the player should actually be honored for the purpose of firing.\\\"\\n! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'ar 2/12/2001 18:05'!\\nstepAt: millisecondClockValue\\n\\t\\\"Do some periodic activity. Use startStepping/stopStepping to start and stop getting sent this message. The time between steps is specified by this morph's answer to the stepTime message.\\n\\tThe millisecondClockValue parameter gives the value of the millisecond clock at the moment of dispatch.\\n\\tDefault is to dispatch to the parameterless step method for the morph, but this protocol makes it possible for some morphs to do differing things depending on the clock value\\\"\\n\\tself player ifNotNilDo:[:p| p stepAt: millisecondClockValue].\\n\\tself step\\n! !\\n\\n!Morph methodsFor: 'stepping and presenter'!\\nstop\\n\\t\\\"Stop running my script. For ordinary morphs, this means stop stepping.\\\"\\n\\n\\tself stopStepping.\\n! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'ar 12/15/2000 00:00'!\\nstopStepping\\n\\t\\\"Stop getting sent the 'step' message.\\\"\\n\\n\\t| w |\\n\\tw _ self world.\\n\\tw ifNotNil: [w stopStepping: self].\\n! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'ar 12/15/2000 00:00'!\\nstopSteppingSelector: aSelector\\n\\t\\\"Stop getting sent the given message.\\\"\\n\\t| w |\\n\\tw _ self world.\\n\\tw ifNotNil: [w stopStepping: self selector: aSelector].\\n! !\\n\\n!Morph methodsFor: 'stepping and presenter' stamp: 'sw 10/11/1999 12:59'!\\nstopSteppingSelfAndSubmorphs\\n\\tself allMorphsDo: [:m | m stopStepping]\\n! !\\n\\n\\n!Morph methodsFor: 'structure' stamp: 'ar 3/18/2001 00:11'!\\nactiveHand\\n\\t^ActiveHand! !\\n\\n!Morph methodsFor: 'structure' stamp: 'di 11/13/2000 01:00'!\\nallOwners\\n\\t\\\"Return the owners of the reciever\\\"\\n\\n\\t^ Array streamContents: [:strm | self allOwnersDo: [:m | strm nextPut: m]]! !\\n\\n!Morph methodsFor: 'structure' stamp: 'ar 9/14/2000 16:47'!\\nallOwnersDo: aBlock\\n\\t\\\"Evaluate aBlock with all owners of the receiver\\\"\\n\\towner ifNotNil:[^owner withAllOwnersDo: aBlock].! !\\n\\n!Morph methodsFor: 'structure' stamp: 'di 11/13/2000 00:48'!\\nfirstOwnerSuchThat: conditionBlock\\n\\n\\tself allOwnersDo: [:m | (conditionBlock value: m) ifTrue: [^ m]].\\n\\t^ nil\\n! !\\n\\n!Morph methodsFor: 'structure' stamp: 'ar 10/3/2000 15:36'!\\nhasOwner: aMorph\\n\\t\\\"Return true if the receiver has aMorph in its owner chain\\\"\\n\\taMorph ifNil:[^true].\\n\\tself allOwnersDo:[:m| m = aMorph ifTrue:[^true]].\\n\\t^false! !\\n\\n!Morph methodsFor: 'structure' stamp: 'dgd 9/1/2004 17:17'!\\nisInDockingBar\\n\\t\\\"answer if the receiver is in a menu bar\\\"\\n\\t^ (owner notNil) and: [owner isDockingBar]! !\\n\\n!Morph methodsFor: 'structure' stamp: 'dgd 9/18/2004 15:56'!\\nisInSystemWindow\\n\\t\\\"answer if the receiver is in a system window\\\"\\n\\t^ owner isMorph and:[owner isSystemWindow or:[owner isInSystemWindow]]! !\\n\\n!Morph methodsFor: 'structure' stamp: 'dgd 2/22/2003 19:05'!\\nisInWorld\\n\\t\\\"Return true if this morph is in a world.\\\"\\n\\n\\t^self world notNil! !\\n\\n!Morph methodsFor: 'structure' stamp: 'sw 8/29/2000 14:55'!\\nmorphPreceding: aSubmorph\\n\\t\\\"Answer the morph immediately preceding aSubmorph, or nil if none\\\"\\n\\n\\t| anIndex |\\n\\tanIndex _ submorphs indexOf: aSubmorph ifAbsent: [^ nil].\\n\\t^ anIndex > 1\\n\\t\\tifTrue:\\n\\t\\t\\t[submorphs at: (anIndex - 1)]\\n\\t\\tifFalse:\\n\\t\\t\\t[nil]! !\\n\\n!Morph methodsFor: 'structure' stamp: 'di 11/12/2000 16:13'!\\nnearestOwnerThat: conditionBlock\\n\\t\\\"Return the first enclosing morph for which aBlock evaluates to true, or nil if none\\\"\\n\\n\\t^ self firstOwnerSuchThat: conditionBlock\\n! !\\n\\n!Morph methodsFor: 'structure' stamp: 'di 11/13/2000 00:49'!\\norOwnerSuchThat: conditionBlock\\n\\n\\t(conditionBlock value: self) ifTrue: [^ self].\\n\\tself allOwnersDo: [:m | (conditionBlock value: m) ifTrue: [^ m]].\\n\\t^ nil\\n\\n! !\\n\\n!Morph methodsFor: 'structure' stamp: 'di 11/13/2000 00:50'!\\noutermostMorphThat: conditionBlock\\n\\t\\\"Return the outermost containing morph for which aBlock is true, or nil if none\\\"\\n\\n\\t| outermost |\\n\\tself allOwnersDo: [:m | (conditionBlock value: m) ifTrue: [outermost _ m]].\\n\\t^ outermost! !\\n\\n!Morph methodsFor: 'structure' stamp: 'ar 3/18/2001 00:12'!\\noutermostWorldMorph\\n\\n\\t| outer |\\n\\tWorld ifNotNil:[^World].\\n\\tself flag: #arNote. \\\"stuff below is really only for MVC\\\"\\n\\touter _ self outermostMorphThat: [ :x | x isWorldMorph].\\n\\touter ifNotNil: [^outer].\\n\\tself isWorldMorph ifTrue: [^self].\\n\\t^nil! !\\n\\n!Morph methodsFor: 'structure'!\\nowner\\n\\t\\\"Returns the owner of this morph, which may be nil.\\\"\\n\\n\\t^ owner! !\\n\\n!Morph methodsFor: 'structure' stamp: 'di 11/12/2000 16:18'!\\nownerThatIsA: aClass\\n\\t\\\"Return the first enclosing morph that is a kind of aClass, or nil if none\\\"\\n\\n\\t^ self firstOwnerSuchThat: [:m | m isKindOf: aClass]! !\\n\\n!Morph methodsFor: 'structure' stamp: 'di 11/12/2000 16:20'!\\nownerThatIsA: firstClass orA: secondClass\\n\\t\\\"Return the first enclosing morph that is a kind of one of the two classes given, or nil if none\\\"\\n\\n\\t^ self firstOwnerSuchThat: [:m | (m isKindOf: firstClass) or: [m isKindOf: secondClass]]! !\\n\\n!Morph methodsFor: 'structure' stamp: 'sw 7/1/1998 18:02'!\\npasteUpMorph\\n\\t\\\"Answer the closest containing morph that is a PasteUp morph\\\"\\n\\t^ self ownerThatIsA: PasteUpMorph! !\\n\\n!Morph methodsFor: 'structure' stamp: 'dgd 8/28/2004 18:43'!\\npasteUpMorphHandlingTabAmongFields\\n\\t\\\"Answer the nearest PasteUpMorph in my owner chain that has the tabAmongFields property, or nil if none\\\"\\n\\n\\t| aPasteUp |\\n\\taPasteUp _ self owner.\\n\\t[aPasteUp notNil] whileTrue:\\n\\t\\t[aPasteUp tabAmongFields ifTrue:\\n\\t\\t\\t[^ aPasteUp].\\n\\t\\taPasteUp _ aPasteUp owner].\\n\\t^ nil! !\\n\\n!Morph methodsFor: 'structure' stamp: 'RAA 6/13/2000 15:01'!\\nprimaryHand\\n\\n | outer |\\n outer _ self outermostWorldMorph ifNil: [^ nil].\\n ^ outer activeHand ifNil: [outer firstHand]! !\\n\\n!Morph methodsFor: 'structure' stamp: 'dgd 2/22/2003 14:34'!\\nrenderedMorph\\n\\t\\\"If the receiver is a renderer morph, answer the rendered morph. Otherwise, answer the receiver. A renderer morph with no submorphs answers itself. See the comment in Morph>isRenderer.\\\"\\n\\n\\tself isRenderer ifFalse: [^self].\\n\\tsubmorphs isEmpty ifTrue: [^self].\\n\\t^self firstSubmorph renderedMorph! !\\n\\n!Morph methodsFor: 'structure' stamp: 'dgd 2/22/2003 14:34'!\\nroot\\n\\t\\\"Return the root of the composite morph containing the receiver. The owner of the root is either nil, a WorldMorph, or a HandMorph. If the receiver's owner is nil, the root is the receiver itself. This method always returns a morph.\\\"\\n\\n\\t(owner isNil or: [owner isWorldOrHandMorph]) ifTrue: [^self].\\n\\t^owner root! !\\n\\n!Morph methodsFor: 'structure' stamp: 'di 8/4/1999 15:41'!\\nrootAt: location\\n\\t\\\"Just return myself, unless I am a WorldWindow.\\n\\tIf so, then return the appropriate root in that world\\\"\\n\\n\\t^ self! !\\n\\n!Morph methodsFor: 'structure' stamp: 'sw 8/30/1998 09:47'!\\ntopPasteUp\\n\\t\\\"If the receiver is in a world, return that; otherwise return the outermost pasteup morph\\\"\\n\\t^ self outermostMorphThat: [:m | m isKindOf: PasteUpMorph]! !\\n\\n!Morph methodsFor: 'structure' stamp: 'dgd 2/22/2003 19:06'!\\ntopRendererOrSelf\\n\\t\\\"Answer the topmost renderer for this morph, or this morph itself if it has no renderer. See the comment in Morph>isRenderer.\\\"\\n\\n\\t| top topsOwner |\\n\\towner ifNil: [^self].\\n\\tself isWorldMorph ifTrue: [^self].\\t\\\"ignore scaling of this world\\\"\\n\\ttop := self.\\n\\ttopsOwner := top owner.\\n\\t[topsOwner notNil and: [topsOwner isRenderer]] whileTrue: \\n\\t\\t\\t[top := topsOwner.\\n\\t\\t\\ttopsOwner := top owner].\\n\\t^top! !\\n\\n!Morph methodsFor: 'structure' stamp: 'di 11/13/2000 00:59'!\\nwithAllOwners\\n\\t\\\"Return the receiver and all its owners\\\"\\n\\n\\t^ Array streamContents: [:strm | self withAllOwnersDo: [:m | strm nextPut: m]]! !\\n\\n!Morph methodsFor: 'structure' stamp: 'ar 9/14/2000 16:48'!\\nwithAllOwnersDo: aBlock\\n\\t\\\"Evaluate aBlock with the receiver and all of its owners\\\"\\n\\taBlock value: self.\\n\\towner ifNotNil:[^owner withAllOwnersDo: aBlock].! !\\n\\n!Morph methodsFor: 'structure' stamp: 'dgd 2/22/2003 14:36'!\\nworld\\n\\t^owner isNil ifTrue: [nil] ifFalse: [owner world]! !\\n\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'di 11/14/2001 12:50'!\\nallKnownNames\\n\\t\\\"Return a list of all known names based on the scope of the receiver. Does not include the name of the receiver itself. Items in parts bins are excluded. Reimplementors (q.v.) can extend the list\\\"\\n\\n\\t^ Array streamContents:\\n\\t\\t[:s | self allSubmorphNamesDo: [:n | s nextPut: n]]\\n! !\\n\\n!Morph methodsFor: 'submorphs-accessing'!\\nallMorphs\\n\\t\\\"Return a collection containing all morphs in this composite morph (including the receiver).\\\"\\n\\n\\t| all |\\n\\tall _ OrderedCollection new: 100.\\n\\tself allMorphsDo: [: m | all add: m].\\n\\t^ all! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'dgd 2/22/2003 14:27'!\\nallMorphsDo: aBlock \\n\\t\\\"Evaluate the given block for all morphs in this composite morph (including the receiver).\\\"\\n\\n\\tsubmorphs do: [:m | m allMorphsDo: aBlock].\\n\\taBlock value: self! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'sw 10/31/97 20:05'!\\nallNonSubmorphMorphs\\n\\t\\\"Return a collection containing all morphs in this morph which are not currently in the submorph containment hierarchy (put in primarily for bookmorphs)\\\"\\n\\n\\t^ OrderedCollection new! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'di 11/14/2001 12:44'!\\nallSubmorphNamesDo: nameBlock\\n\\t\\\"Return a list of all known names of submorphs and nested submorphs of the receiver, based on the scope of the receiver. Items in parts bins are excluded\\\"\\n\\n\\tself isPartsBin ifTrue: [^ self]. \\\"Don't report names from parts bins\\\"\\n\\tself submorphsDo: \\n\\t\\t[:m | m knownName ifNotNilDo: [:n | nameBlock value: n].\\n\\t\\tm allSubmorphNamesDo: nameBlock].\\n! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'dgd 8/31/2004 16:53'!\\ndockingBars\\n\\t\\\"Answer the receiver's dockingBars\\\"\\n\\t^ self submorphs\\n\\t\\tselect: [:each | each isDockingBar]\\n! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'rhi 9/10/2000 12:12'!\\nfindA: aClass\\n\\t\\\"Return the first submorph of the receiver that is descended from the given class. Return nil if there is no such submorph. Clients of this code should always check for a nil return value so that the code will be robust if the user takes the morph apart.\\\"\\n\\n\\t^self submorphs\\n\\t\\tdetect: [:p | p isKindOf: aClass]\\n\\t\\tifNone: [nil]! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'sw 1/9/2001 12:30'!\\nfindDeeplyA: aClass\\n\\t\\\"Return a morph in the submorph tree of the receiver that is descended from the given class. Return nil if there is no such morph. Clients of this code should always check for a nil return value so that the code will be robust if the user takes the morph apart.\\\"\\n\\n\\t^ (self allMorphs copyWithout: self)\\n\\t\\tdetect: [:p | p isKindOf: aClass]\\n\\t\\tifNone: [nil]! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'LC 9/28/1999 19:12'!\\nfindDeepSubmorphThat: block1 ifAbsent: block2 \\n\\tself\\n\\t\\tallMorphsDo: [:m | (block1 value: m)\\n\\t\\t\\t\\t== true ifTrue: [^ m]].\\n\\t^ block2 value! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'ar 3/17/2001 15:32'!\\nfindSubmorphBinary: aBlock\\n\\t\\\"Use binary search for finding a specific submorph of the receiver. Caller must be certain that the ordering holds for the submorphs.\\\"\\n\\t^submorphs findBinary: aBlock ifNone:[nil].! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'dgd 2/22/2003 14:31'!\\nfirstSubmorph\\n\\t^submorphs first! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'dgd 2/22/2003 14:32'!\\nhasSubmorphs\\n\\t^submorphs notEmpty! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'sw 7/3/1998 17:11'!\\nhasSubmorphWithProperty: aSymbol\\n\\tsubmorphs detect: [:m | m hasProperty: aSymbol] ifNone: [^ false].\\n\\t^ true! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'tk 10/31/2000 11:04'!\\nindexOfMorphAbove: aPoint\\n\\t\\\"Return index of lowest morph whose bottom is above aPoint.\\n\\tWill return 0 if the first morph is not above aPoint.\\\"\\n\\n\\tsubmorphs withIndexDo: [:mm :ii | \\n\\t\\tmm fullBounds bottom >= aPoint y ifTrue: [^ ii - 1]].\\n\\t^ submorphs size! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'dgd 2/22/2003 14:32'!\\nlastSubmorph\\n\\t^submorphs last! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'dgd 9/6/2004 14:17'!\\nmainDockingBars\\n\\t\\\"Answer the receiver's main dockingBars\\\"\\n\\t^ self dockingBars\\n\\t\\tselect: [:each | each hasProperty: #mainDockingBarTimeStamp]! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'ar 10/8/2000 15:40'!\\nmorphsAt: aPoint\\n\\t\\\"Return a collection of all morphs in this morph structure that contain the given point, possibly including the receiver itself. The order is deepest embedding first.\\\"\\n\\t^self morphsAt: aPoint unlocked: false! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'dgd 2/22/2003 14:32'!\\nmorphsAt: aPoint behind: aMorph unlocked: aBool \\n\\t\\\"Return all morphs at aPoint that are behind frontMorph; if aBool is true return only unlocked, visible morphs.\\\"\\n\\n\\t| isBack found all tfm |\\n\\tall := (aMorph isNil or: [owner isNil]) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[\\\"Traverse down\\\"\\n\\n\\t\\t\\t\\t\\t(self fullBounds containsPoint: aPoint) ifFalse: [^#()].\\n\\t\\t\\t\\t\\t(aBool and: [self isLocked or: [self visible not]]) ifTrue: [^#()].\\n\\t\\t\\t\\t\\tnil]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[\\\"Traverse up\\\"\\n\\n\\t\\t\\t\\t\\ttfm := self transformedFrom: owner.\\n\\t\\t\\t\\t\\tall := owner \\n\\t\\t\\t\\t\\t\\t\\t\\tmorphsAt: (tfm localPointToGlobal: aPoint)\\n\\t\\t\\t\\t\\t\\t\\t\\tbehind: self\\n\\t\\t\\t\\t\\t\\t\\t\\tunlocked: aBool.\\n\\t\\t\\t\\t\\tWriteStream with: all].\\n\\tisBack := aMorph isNil.\\n\\tself submorphsDo: \\n\\t\\t\\t[:m | \\n\\t\\t\\tisBack \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[tfm := m transformedFrom: self.\\n\\t\\t\\t\\t\\tfound := m \\n\\t\\t\\t\\t\\t\\t\\t\\tmorphsAt: (tfm globalPointToLocal: aPoint)\\n\\t\\t\\t\\t\\t\\t\\t\\tbehind: nil\\n\\t\\t\\t\\t\\t\\t\\t\\tunlocked: aBool.\\n\\t\\t\\t\\t\\tfound notEmpty \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[all ifNil: [all := WriteStream on: #()].\\n\\t\\t\\t\\t\\t\\t\\tall nextPutAll: found]].\\n\\t\\t\\tm == aMorph ifTrue: [isBack := true]].\\n\\t(isBack and: [self containsPoint: aPoint]) \\n\\t\\tifTrue: \\n\\t\\t\\t[all ifNil: [^Array with: self].\\n\\t\\t\\tall nextPut: self].\\n\\t^all ifNil: [#()] ifNotNil: [all contents]! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'ar 10/8/2000 15:40'!\\nmorphsAt: aPoint unlocked: aBool\\n\\t\\\"Return a collection of all morphs in this morph structure that contain the given point, possibly including the receiver itself. The order is deepest embedding first.\\\"\\n\\t| mList |\\n\\tmList _ WriteStream on: #().\\n\\tself morphsAt: aPoint unlocked: aBool do:[:m| mList nextPut: m].\\n\\t^mList contents! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'ar 10/8/2000 15:37'!\\nmorphsAt: aPoint unlocked: aBool do: aBlock\\n\\t\\\"Evaluate aBlock with all the morphs starting at the receiver which appear at aPoint. If aBool is true take only visible, unlocked morphs into account.\\\"\\n\\t| tfm |\\n\\t(self fullBounds containsPoint: aPoint) ifFalse:[^self].\\n\\t(aBool and:[self isLocked or:[self visible not]]) ifTrue:[^self].\\n\\tself submorphsDo:[:m|\\n\\t\\ttfm _ m transformedFrom: self.\\n\\t\\tm morphsAt: (tfm globalPointToLocal: aPoint) unlocked: aBool do: aBlock].\\n\\t(self containsPoint: aPoint) ifTrue:[aBlock value: self].! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'ar 9/9/2000 17:31'!\\nmorphsInFrontOf: someMorph overlapping: aRectangle do: aBlock\\n\\t\\\"Evaluate aBlock with all top-level morphs in front of someMorph that overlap with the given rectangle. someMorph is either an immediate child of the receiver or nil (in which case all submorphs of the receiver are enumerated).\\\"\\n\\tself submorphsDo:[:m|\\n\\t\\tm == someMorph ifTrue:[\\\"Try getting out quickly\\\"\\n\\t\\t\\towner ifNil:[^self].\\n\\t\\t\\t^owner morphsInFrontOf: self overlapping: aRectangle do: aBlock].\\n\\t\\t(m fullBoundsInWorld intersects: aRectangle)\\n\\t\\t\\tifTrue:[aBlock value: m]].\\n\\towner ifNil:[^self].\\n\\t^owner morphsInFrontOf: self overlapping: aRectangle do: aBlock.! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'ar 9/9/2000 17:31'!\\nmorphsInFrontOverlapping: aRectangle\\n\\t\\\"Return all top-level morphs in front of someMorph that overlap with the given rectangle.\\\"\\n\\t| morphList |\\n\\tmorphList _ WriteStream on: Array new.\\n\\tself morphsInFrontOf: nil overlapping: aRectangle do:[:m | morphList nextPut: m].\\n\\t^morphList contents! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'ar 9/9/2000 17:31'!\\nmorphsInFrontOverlapping: aRectangle do: aBlock\\n\\t\\\"Evaluate aBlock with all top-level morphs in front of someMorph that overlap with the given rectangle.\\\"\\n\\t^self morphsInFrontOf: nil overlapping: aRectangle do: aBlock! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'ar 8/13/2003 11:32'!\\nnoteNewOwner: aMorph\\n\\t\\\"I have just been added as a submorph of aMorph\\\"! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'RAA 6/11/2000 20:41'!\\nrootMorphsAtGlobal: aPoint\\n\\t\\\"Return the list of root morphs containing the given point, excluding the receiver.\\n\\tar 11/8/1999: Moved into morph for an incredibly ugly hack in 3D worlds\\\"\\n\\n\\t^ self rootMorphsAt: (self pointFromWorld: aPoint)! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'ar 10/8/2000 15:44'!\\nrootMorphsAt: aPoint\\n\\t\\\"Return the list of root morphs containing the given point, excluding the receiver.\\n\\tar 11/8/1999: Moved into morph for an incredibly ugly hack in 3D worlds\\\"\\nself flag: #arNote. \\\"check this at some point\\\"\\n\\t^ self submorphs select:\\n\\t\\t[:m | (m fullContainsPoint: aPoint) and: [m isLocked not]]! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'dgd 2/22/2003 14:35'!\\nshuffleSubmorphs\\n\\t\\\"Randomly shuffle the order of my submorphs. Don't call this method lightly!!\\\"\\n\\n\\t| bg |\\n\\tself invalidRect: self fullBounds.\\n\\t(submorphs notEmpty and: [submorphs last mustBeBackmost]) \\n\\t\\tifTrue: \\n\\t\\t\\t[bg := submorphs last.\\n\\t\\t\\tbg privateDelete].\\n\\tsubmorphs := submorphs shuffled.\\n\\tbg ifNotNil: [self addMorphBack: bg].\\n\\tself layoutChanged! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'tk 10/20/2000 13:12'!\\nsubmorphAfter\\n\\t\\\"Return the submorph after (behind) me, or nil\\\"\\n\\t| ii |\\n\\towner ifNil: [^ nil].\\n\\t^ (ii _ owner submorphIndexOf: self) = owner submorphs size \\n\\t\\tifTrue: [nil]\\n\\t\\tifFalse: [owner submorphs at: ii+1].\\n\\t\\n! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'tk 10/20/2000 13:13'!\\nsubmorphBefore\\n\\t\\\"Return the submorph after (behind) me, or nil\\\"\\n\\t| ii |\\n\\towner ifNil: [^ nil].\\n\\t^ (ii _ owner submorphIndexOf: self) = 1 \\n\\t\\tifTrue: [nil]\\n\\t\\tifFalse: [owner submorphs at: ii-1].\\n\\t\\n! !\\n\\n!Morph methodsFor: 'submorphs-accessing'!\\nsubmorphCount\\n\\n\\t^ submorphs size! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'sw 4/9/98 14:26'!\\nsubmorphNamed: aName\\n\\t^ self submorphNamed: aName ifNone: [nil]! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'gm 2/22/2003 13:16'!\\nsubmorphNamed: aName ifNone: aBlock \\n\\t\\\"Find the first submorph with this name, or a button with an action selector of that name\\\"\\n\\n\\t| sub args |\\n\\tself submorphs do: [:p | p knownName = aName ifTrue: [^p]].\\n\\tself submorphs do: \\n\\t\\t\\t[:button | \\n\\t\\t\\t(button respondsTo: #actionSelector) \\n\\t\\t\\t\\tifTrue: [button actionSelector == aName ifTrue: [^button]].\\n\\t\\t\\t((button respondsTo: #arguments) and: [(args := button arguments) notNil]) \\n\\t\\t\\t\\tifTrue: [(args at: 2 ifAbsent: [nil]) == aName ifTrue: [^button]].\\n\\t\\t\\t(button isAlignmentMorph) \\n\\t\\t\\t\\tifTrue: [(sub := button submorphNamed: aName ifNone: [nil]) ifNotNil: [^sub]]].\\n\\t^aBlock value! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'rhi 9/10/2000 12:12'!\\nsubmorphOfClass: aClass\\n\\n\\t^self findA: aClass! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'efc 8/6/2005 11:35'!\\nsubmorphs\\n\\t\\\"This method returns my actual submorphs collection. Modifying the collection directly could be dangerous; make a copy if you need to alter it.\\\"\\n\\t^ submorphs ! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'di 11/4/97 14:30'!\\nsubmorphsBehind: aMorph do: aBlock\\n\\t| behind |\\n\\tbehind _ false.\\n\\tsubmorphs do:\\n\\t\\t[:m | m == aMorph ifTrue: [behind _ true]\\n\\t\\t\\t\\t\\t\\tifFalse: [behind ifTrue: [aBlock value: m]]].\\n! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'dgd 2/22/2003 14:35'!\\nsubmorphsDo: aBlock \\n\\tsubmorphs do: aBlock! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'di 11/4/97 14:29'!\\nsubmorphsInFrontOf: aMorph do: aBlock\\n\\t| behind |\\n\\tbehind _ false.\\n\\tsubmorphs do:\\n\\t\\t[:m | m == aMorph ifTrue: [behind _ true]\\n\\t\\t\\t\\t\\t\\tifFalse: [behind ifFalse: [aBlock value: m]]].\\n! !\\n\\n!Morph methodsFor: 'submorphs-accessing'!\\nsubmorphsReverseDo: aBlock\\n\\n\\tsubmorphs reverseDo: aBlock.! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'sw 8/15/97 22:03'!\\nsubmorphsSatisfying: aBlock\\n\\t^ submorphs select: [:m | (aBlock value: m) == true]! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'sw 10/26/1999 23:42'!\\nsubmorphThat: block1 ifNone: block2\\n\\t^ submorphs detect: [:m | (block1 value: m) == true] ifNone: [block2 value]\\n\\t! !\\n\\n!Morph methodsFor: 'submorphs-accessing' stamp: 'sw 7/3/1998 18:47'!\\nsubmorphWithProperty: aSymbol\\n\\t^ submorphs detect: [:aMorph | aMorph hasProperty: aSymbol] ifNone: [nil]! !\\n\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'tk 12/15/1998 14:23'!\\nabandon\\n\\t\\\"Like delete, but we really intend not to use this morph again. Clean up a few things.\\\"\\n\\n\\tself delete! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'sw 9/28/2001 08:39'!\\nactWhen\\n\\t\\\"Answer when the receiver, probably being used as a button, should have its action triggered\\\"\\n\\n\\t^ self valueOfProperty: #actWhen ifAbsentPut: [#buttonDown]! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'sw 9/25/2001 10:23'!\\nactWhen: aButtonPhase\\n\\t\\\"Set the receiver's actWhen trait\\\"\\n\\n\\tself setProperty: #actWhen toValue: aButtonPhase! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 8/12/2003 23:28'!\\naddAllMorphs: aCollection\\n\\t^self privateAddAllMorphs: aCollection atIndex: submorphs size! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 8/12/2003 23:29'!\\naddAllMorphs: aCollection after: anotherMorph\\n\\t^self privateAddAllMorphs: aCollection \\n\\t\\t\\tatIndex: (submorphs indexOf: anotherMorph ifAbsent: [submorphs size])! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 1/31/2001 12:55'!\\naddMorphBack: aMorph\\n\\t^self privateAddMorph: aMorph atIndex: submorphs size+1! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'RAA 12/15/2000 19:34'!\\naddMorphCentered: aMorph\\n\\n\\taMorph position: bounds center - (aMorph extent // 2).\\n\\tself addMorphFront: aMorph.\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 12/16/2001 21:08'!\\naddMorphFrontFromWorldPosition: aMorph\\n\\t^self addMorphFront: aMorph fromWorldPosition: aMorph positionInWorld.! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 1/31/2001 12:54'!\\naddMorphFront: aMorph\\n\\t^self privateAddMorph: aMorph atIndex: 1! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 11/15/1998 23:42'!\\naddMorphFront: aMorph fromWorldPosition: wp\\n\\n\\tself addMorphFront: aMorph.\\n\\taMorph position: (self transformFromWorld globalPointToLocal: wp)! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'dgd 2/22/2003 14:26'!\\naddMorphNearBack: aMorph \\n\\t| bg |\\n\\t(submorphs notEmpty and: [submorphs last mustBeBackmost]) \\n\\t\\tifTrue: \\n\\t\\t\\t[bg := submorphs last.\\n\\t\\t\\tbg privateDelete].\\n\\tself addMorphBack: aMorph.\\n\\tbg ifNotNil: [self addMorphBack: bg]! !\\n\\n!Morph methodsFor: 'submorphs-add/remove'!\\naddMorph: aMorph\\n\\n\\tself addMorphFront: aMorph.! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 1/31/2001 12:54'!\\naddMorph: newMorph after: aMorph\\n\\t\\\"Add the given morph as one of my submorphs, inserting it after anotherMorph\\\"\\n\\t^self privateAddMorph: newMorph atIndex: (submorphs indexOf: aMorph)+1! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'sw 9/7/2000 08:29'!\\naddMorph: aMorph asElementNumber: aNumber\\n\\t\\\"Add the given morph so that it becomes the aNumber'th element of my submorph list. If aMorph is already one of my submorphs, reposition it\\\"\\n\\n\\t(submorphs includes: aMorph) ifTrue:\\n\\t\\t[aMorph privateDelete].\\n\\t(aNumber <= submorphs size)\\n\\t\\tifTrue:\\n\\t\\t\\t[self addMorph: aMorph inFrontOf: (submorphs at: aNumber)]\\n\\t\\tifFalse:\\n\\t\\t\\t[self addMorphBack: aMorph]\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 1/31/2001 12:44'!\\naddMorph: newMorph behind: aMorph\\n\\t\\\"Add a morph to the list of submorphs behind the specified morph\\\"\\n\\t^self privateAddMorph: newMorph atIndex: (submorphs indexOf: aMorph) + 1.\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'JW 2/1/2001 12:52'!\\naddMorph: aMorph fullFrame: aLayoutFrame\\n\\n\\taMorph layoutFrame: aLayoutFrame.\\n\\taMorph hResizing: #spaceFill; vResizing: #spaceFill.\\n\\tself addMorph: aMorph.\\n\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 1/31/2001 12:45'!\\naddMorph: newMorph inFrontOf: aMorph\\n\\t\\\"Add a morph to the list of submorphs in front of the specified morph\\\"\\n\\t^self privateAddMorph: newMorph atIndex: ((submorphs indexOf: aMorph) max: 1).! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'dgd 4/4/2006 17:17'!\\nallMorphsWithPlayersDo: aTwoArgumentBlock \\n\\t\\\"Evaluate the given block for all morphs in this composite morph that have non-nil players.\\n\\tAlso evaluate the block for the receiver if it has a player.\\\"\\n\\n\\tsubmorphs do: [:m | m allMorphsWithPlayersDo: aTwoArgumentBlock ].\\n\\tself playerRepresented ifNotNilDo: [ :p | aTwoArgumentBlock value: self value: p ].\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'dgd 2/22/2003 14:30'!\\ncomeToFront\\n\\t| outerMorph |\\n\\touterMorph := self topRendererOrSelf.\\n\\t(outerMorph owner isNil or: [outerMorph owner hasSubmorphs not]) \\n\\t\\tifTrue: [^self].\\n\\touterMorph owner firstSubmorph == outerMorph \\n\\t\\tifFalse: [outerMorph owner addMorphFront: outerMorph]! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'di 10/27/97 23:26'!\\ncopyWithoutSubmorph: sub\\n\\t\\\"Needed to get a morph to draw without one of its submorphs.\\n\\tNOTE: This must be thrown away immediately after use.\\\"\\n\\t^ self clone privateSubmorphs: (submorphs copyWithout: sub)! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'dgd 9/10/2004 19:02'!\\ndelete\\n\\t\\\"Remove the receiver as a submorph of its owner and make its \\n\\tnew owner be nil.\\\"\\n\\n\\t| aWorld |\\n\\tself removeHalo.\\n\\taWorld := self world ifNil: [World].\\n\\t\\\"Terminate genie recognition focus\\\"\\n\\t\\\"I encountered a case where the hand was nil, so I put in a little \\n\\tprotection - raa \\\"\\n\\t\\\" This happens when we are in an MVC project and open\\n\\t a morphic window. - BG \\\"\\n\\taWorld ifNotNil:\\n\\t [self disableSubmorphFocusForHand: self activeHand.\\n\\t self activeHand releaseKeyboardFocus: self;\\n\\t\\t releaseMouseFocus: self.].\\n\\towner ifNotNil:[ self privateDelete.\\n\\t\\tself player ifNotNilDo: [ :player |\\n\\t\\t\\t\\\"Player must be notified\\\"\\n\\t\\t\\tplayer noteDeletionOf: self fromWorld: aWorld]].! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'dgd 9/1/2004 16:26'!\\ndeleteDockingBars\\n\\t\\\"Delete the receiver's docking bars\\\"\\n\\tself dockingBars\\n\\t\\tdo: [:each | each delete]! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'sw 7/3/1998 11:02'!\\ndeleteSubmorphsWithProperty: aSymbol\\n\\tsubmorphs copy do:\\n\\t\\t[:m | (m hasProperty: aSymbol) ifTrue: [m delete]]! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'sw 2/2/2006 02:39'!\\ndismissViaHalo\\n\\t\\\"The user has clicked in the delete halo-handle. This provides a hook in case some concomitant action should be taken, or if the particular morph is not one which should be put in the trash can, for example.\\\"\\n\\n\\t| cmd |\\n\\tself setProperty: #lastPosition toValue: self positionInWorld.\\n\\tself dismissMorph.\\n\\tPreferences preserveTrash ifTrue: [ \\n\\t\\tPreferences slideDismissalsToTrash\\n\\t\\t\\tifTrue:[self slideToTrash: nil]\\n\\t\\t\\tifFalse:[TrashCanMorph moveToTrash: self].\\n\\t].\\n\\n\\tcmd _ Command new cmdWording: 'dismiss ' translated, self externalName.\\n\\tcmd undoTarget: ActiveWorld selector: #reintroduceIntoWorld: argument: self.\\n\\tcmd redoTarget: ActiveWorld selector: #onceAgainDismiss: argument: self.\\n\\tActiveWorld rememberCommand: cmd! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'sw 4/9/98 22:44'!\\ngoBehind\\n\\n\\towner addMorphNearBack: self.\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 8/10/2003 18:31'!\\nprivateDelete\\n\\t\\\"Remove the receiver as a submorph of its owner\\\"\\n\\towner ifNotNil:[owner removeMorph: self].! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'nk 10/16/2003 14:08'!\\nremoveAllMorphs\\n\\t| oldMorphs myWorld |\\n\\tmyWorld _ self world.\\n\\t(fullBounds notNil or:[myWorld notNil]) ifTrue:[self invalidRect: self fullBounds].\\n\\tsubmorphs do: [:m | myWorld ifNotNil: [ m outOfWorld: myWorld ]. m privateOwner: nil].\\n\\toldMorphs _ submorphs.\\n\\tsubmorphs _ EmptyArray.\\n\\toldMorphs do: [ :m | self removedMorph: m ].\\n\\tself layoutChanged.\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'nk 10/16/2003 14:02'!\\nremoveAllMorphsIn: aCollection\\n\\t\\\"greatly speeds up the removal of *lots* of submorphs\\\"\\n\\t| set myWorld |\\n\\tset _ IdentitySet new: aCollection size * 4 // 3.\\n\\taCollection do: [:each | each owner == self ifTrue: [ set add: each]].\\n\\tmyWorld _ self world.\\n\\t(fullBounds notNil or:[myWorld notNil]) ifTrue:[self invalidRect: self fullBounds].\\n\\tset do: [:m | myWorld ifNotNil: [ m outOfWorld: myWorld ]. m privateOwner: nil].\\n\\tsubmorphs _ submorphs reject: [ :each | set includes: each].\\n\\tset do: [ :m | self removedMorph: m ].\\n\\tself layoutChanged.\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'ar 8/12/2003 22:01'!\\nremovedMorph: aMorph\\n\\t\\\"Notify the receiver that aMorph was just removed from its children\\\"\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'di 10/18/2004 21:50'!\\nremoveMorph: aMorph\\n\\t\\\"Remove the given morph from my submorphs\\\"\\n\\t| aWorld |\\n\\taMorph owner == self ifFalse:[^self].\\n\\taWorld := self world.\\n\\taWorld ifNotNil:[\\n\\t\\taMorph outOfWorld: aWorld.\\n\\t\\tself privateInvalidateMorph: aMorph.\\n\\t].\\n\\tself privateRemove: aMorph.\\n\\taMorph privateOwner: nil.\\n\\tself removedMorph: aMorph.\\n! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'sw 10/25/1999 23:34'!\\nreplaceSubmorph: oldMorph by: newMorph\\n\\t| index itsPosition w |\\n\\toldMorph stopStepping.\\n\\titsPosition _ oldMorph referencePositionInWorld.\\n\\tindex _ submorphs indexOf: oldMorph.\\n\\toldMorph privateDelete.\\n\\tself privateAddMorph: newMorph atIndex: index.\\n\\tnewMorph referencePositionInWorld: itsPosition.\\n\\t(w _ newMorph world) ifNotNil:\\n\\t\\t[w startSteppingSubmorphsOf: newMorph]! !\\n\\n!Morph methodsFor: 'submorphs-add/remove' stamp: 'sw 9/1/2000 10:16'!\\nsubmorphIndexOf: aMorph\\n\\t\\\"Assuming aMorph to be one of my submorphs, answer where it occurs in my submorph list\\\"\\n\\n\\t^ submorphs indexOf: aMorph ifAbsent: [nil]! !\\n\\n\\n!Morph methodsFor: 'testing' stamp: 'RAA 12/4/2000 10:44'!\\ncanDrawAtHigherResolution\\n\\n\\t^false! !\\n\\n!Morph methodsFor: 'testing' stamp: 'ar 8/25/2001 19:14'!\\ncanDrawBorder: aBorderStyle\\n\\t\\\"Return true if the receiver can be drawn with the given border style.\\\"\\n\\t^true! !\\n\\n!Morph methodsFor: 'testing' stamp: 'RAA 10/20/2000 14:47'!\\ncompleteModificationHash\\n\\n\\\"World completeModificationHash\\\"\\n\\n\\t| resultSize result here i |\\n\\tresultSize _ 10.\\n\\tresult _ ByteArray new: resultSize.\\n\\tself allMorphsDo: [ :each | \\n\\t\\there _ each modificationHash.\\n\\t\\there withIndexDo: [ :ch :index |\\n\\t\\t\\ti _ index \\\\\\\\ resultSize + 1.\\n\\t\\t\\tresult at: i put: ((result at: i) bitXor: ch asciiValue)\\n\\t\\t].\\n\\t].\\n\\t^result! !\\n\\n!Morph methodsFor: 'testing' stamp: 'sw 3/30/2005 04:17'!\\ncouldMakeSibling\\n\\t\\\"Answer whether it is appropriate to ask the receiver to make a sibling\\\"\\n\\n\\t^ true! !\\n\\n!Morph methodsFor: 'testing' stamp: 'dgd 8/31/2004 15:00'!\\nisDockingBar\\n\\t\\\"Return true if the receiver is a docking bar\\\"\\n\\t^ false! !\\n\\n!Morph methodsFor: 'testing' stamp: 'ar 9/22/2000 13:44'!\\nisFlexed\\n\\t\\\"Return true if the receiver is currently flexed\\\"\\n\\towner ifNil:[^false].\\n\\t^owner isFlexMorph! !\\n\\n!Morph methodsFor: 'testing' stamp: 'dgd 9/20/2004 14:31'!\\nisFullOnScreen\\n\\t\\\"Answer if the receiver is full contained in the owner visible \\n\\tarea.\\\"\\n\\towner isInMemory\\n\\t\\tifFalse: [^ true].\\n\\towner isNil\\n\\t\\tifTrue: [^ true].\\n\\tself visible\\n\\t\\tifFalse: [^ true].\\n\\t^ owner clearArea containsRect: self fullBounds! !\\n\\n!Morph methodsFor: 'testing' stamp: 'nk 10/13/2003 18:36'!\\nisLineMorph\\n\\t^false! !\\n\\n!Morph methodsFor: 'testing'!\\nisMorph\\n\\n\\t^ true! !\\n\\n!Morph methodsFor: 'testing' stamp: 'nk 6/12/2004 09:17'!\\nisSketchMorph\\n\\t^self class isSketchMorphClass! !\\n\\n!Morph methodsFor: 'testing' stamp: 'md 2/27/2006 09:59'!\\nknownName\\n\\t\\\"answer a name by which the receiver is known, or nil if none\\\"\\n\\t^ extension ifNotNil: [extension externalName]! !\\n\\n!Morph methodsFor: 'testing' stamp: 'RAA 10/20/2000 14:47'!\\nmodificationHash\\n\\n\\t^String \\n\\t\\tstreamContents: [ :strm |\\n\\t\\t\\tself longPrintOn: strm\\n\\t\\t]\\n\\t\\tlimitedTo: 25\\n! !\\n\\n!Morph methodsFor: 'testing' stamp: 'tk 7/28/2005 04:46'!\\nrenameInternal: aName \\n\\t\\\"Change the internal name (because of a conflict) but leave the external name unchanged. Change Player class name, but do not change the names that appear in tiles. When coming in from disk, and have name conflict, References will already have the new name. \\\"\\n\\n\\tself knownName = aName ifTrue: [^ aName].\\n\\tself topRendererOrSelf setNameTo: aName.\\n\\t\\n\\t\\\"References dictionary already has key aName\\\"\\n\\n\\t\\\"If this player has a viewer flap, it will remain present\\\"\\n\\n\\t\\\"Tiles in scripts all stay the same\\\"\\n\\n\\t\\\"Compiled methods for scripts have been fixed up because the same association was reused\\\"\\n\\t\\n\\t^ aName! !\\n\\n!Morph methodsFor: 'testing' stamp: 'dvf 8/23/2003 11:50'!\\nrenameTo: aName \\n\\t\\\"Set Player name in costume. Update Viewers. Fix all tiles (old style). fix \\n\\tReferences. New tiles: recompile, and recreate open scripts. If coming in \\n\\tfrom disk, and have name conflict, References will already have new \\n\\tname. \\\"\\n\\n\\t| aPresenter putInViewer aPasteUp renderer oldKey assoc classes oldName |\\n\\toldName := self knownName.\\n\\t(renderer := self topRendererOrSelf) setNameTo: aName.\\n\\tputInViewer := false.\\n\\t((aPresenter := self presenter) isNil or: [renderer player isNil]) \\n\\t\\tifFalse: \\n\\t\\t\\t[putInViewer := aPresenter currentlyViewing: renderer player.\\n\\t\\t\\tputInViewer ifTrue: [renderer player viewerFlapTab hibernate]].\\n\\t\\\"empty it temporarily\\\"\\n\\t(aPasteUp := self topPasteUp) \\n\\t\\tifNotNil: [aPasteUp allTileScriptingElements do: [:m | m bringUpToDate]].\\n\\t\\\"Fix References dictionary. See restoreReferences to know why oldKey is \\n\\talready aName, but oldName is the old name.\\\"\\n\\toldKey := References keyAtIdentityValue: renderer player ifAbsent: [].\\n\\toldKey ifNotNil: \\n\\t\\t\\t[assoc := References associationAt: oldKey.\\n\\t\\t\\toldKey = aName \\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[\\\"normal rename\\\"\\n\\n\\t\\t\\t\\t\\tassoc key: (renderer player uniqueNameForReferenceFrom: aName).\\n\\t\\t\\t\\t\\tReferences rehash]].\\n\\tputInViewer ifTrue: [aPresenter viewMorph: self].\\n\\t\\\"recreate my viewer\\\"\\n\\toldKey ifNil: [^aName].\\n\\t\\\"Force strings in tiles to be remade with new name. New tiles only.\\\"\\n\\tPreferences universalTiles ifFalse: [^aName].\\n\\tclasses := (self systemNavigation allCallsOn: assoc) \\n\\t\\t\\t\\tcollect: [:each | each classSymbol].\\n\\tclasses asSet \\n\\t\\tdo: [:clsName | (Smalltalk at: clsName) replaceSilently: oldName to: aName].\\n\\t\\\"replace in text body of all methods. Can be wrong!!\\\"\\n\\t\\\"Redo the tiles that are showing. This is also done in caller in \\n\\tunhibernate. \\\"\\n\\taPasteUp ifNotNil: \\n\\t\\t\\t[aPasteUp allTileScriptingElements do: \\n\\t\\t\\t\\t\\t[:mm | \\n\\t\\t\\t\\t\\t\\\"just ScriptEditorMorphs\\\"\\n\\n\\t\\t\\t\\t\\tnil.\\n\\t\\t\\t\\t\\t(mm isKindOf: ScriptEditorMorph) \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[((mm playerScripted class compiledMethodAt: mm scriptName) \\n\\t\\t\\t\\t\\t\\t\\t\\thasLiteral: assoc) \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[mm\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\thibernate;\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tunhibernate]]]].\\n\\t^aName! !\\n\\n!Morph methodsFor: 'testing' stamp: 'ar 12/3/2001 12:33'!\\nshouldDropOnMouseUp\\n\\t| former |\\n\\tformer _ self formerPosition ifNil:[^false].\\n\\t^(former dist: self position) > 10! !\\n\\n!Morph methodsFor: 'testing' stamp: 'RAA 1/16/2001 17:20'!\\nstepTime\\n\\t\\\"Answer the desired time between steps in milliseconds. This default implementation requests that the 'step' method be called once every second.\\\"\\n\\n\\t^ self topRendererOrSelf player ifNotNil: [10] ifNil: [1000]! !\\n\\n!Morph methodsFor: 'testing' stamp: 'sw 10/24/2004 15:28'!\\nwantsSteps\\n\\t\\\"Return true if the receiver overrides the default Morph step method.\\\"\\n\\t\\\"Details: Find first class in superclass chain that implements #step and return true if it isn't class Morph.\\\"\\n\\n\\t| c |\\n\\tself isPartsDonor ifTrue: [^ false].\\n\\t(self == self topRendererOrSelf) ifTrue: [self player wantsSteps ifTrue: [^ true]].\\n\\tc _ self class.\\n\\t[c includesSelector: #step] whileFalse: [c _ c superclass].\\n\\t^ c ~= Morph! !\\n\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'ar 12/17/2001 12:45'!\\naddTextAnchorMenuItems: topMenu hand: aHand\\n\\t| aMenu |\\n\\taMenu _ MenuMorph new defaultTarget: self.\\n\\taMenu addUpdating: #hasInlineAnchorString action: #changeInlineAnchor.\\n\\taMenu addUpdating: #hasParagraphAnchorString action: #changeParagraphAnchor.\\n\\taMenu addUpdating: #hasDocumentAnchorString action: #changeDocumentAnchor.\\n\\ttopMenu ifNotNil:[topMenu add: 'text anchor' subMenu: aMenu].\\n\\t^aMenu! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'aoy 2/15/2003 21:47'!\\nchangeDocumentAnchor\\n\\t\\\"Change the anchor from/to document anchoring\\\"\\n\\n\\t| newType |\\n\\tnewType := self textAnchorType == #document \\n\\t\\tifTrue: [#paragraph]\\n\\t\\tifFalse: [ #document].\\n\\towner isTextMorph \\n\\t\\tifTrue: \\n\\t\\t\\t[owner \\n\\t\\t\\t\\tanchorMorph: self\\n\\t\\t\\t\\tat: self position\\n\\t\\t\\t\\ttype: newType]! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'aoy 2/15/2003 21:48'!\\nchangeInlineAnchor\\n\\t\\\"Change the anchor from/to line anchoring\\\"\\n\\n\\t| newType |\\n\\tnewType := self textAnchorType == #inline \\n\\t\\t\\t\\tifTrue: [#paragraph]\\n\\t\\t\\t\\tifFalse: [#inline]. \\n\\towner isTextMorph \\n\\t\\tifTrue: \\n\\t\\t\\t[owner \\n\\t\\t\\t\\tanchorMorph: self\\n\\t\\t\\t\\tat: self position\\n\\t\\t\\t\\ttype: newType]! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'aoy 2/15/2003 21:48'!\\nchangeParagraphAnchor\\n\\t\\\"Change the anchor from/to paragraph anchoring\\\"\\n\\n\\t| newType |\\n\\tnewType := self textAnchorType == #paragraph \\n\\t\\tifTrue: [#document]\\n\\t\\tifFalse: [#paragraph].\\n\\towner isTextMorph \\n\\t\\tifTrue: \\n\\t\\t\\t[owner \\n\\t\\t\\t\\tanchorMorph: self\\n\\t\\t\\t\\tat: self position\\n\\t\\t\\t\\ttype: newType]! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'dgd 9/6/2003 18:14'!\\nhasDocumentAnchorString\\n\\t^ (self textAnchorType == #document\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'Document' translated! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'dgd 9/6/2003 18:14'!\\nhasInlineAnchorString\\n\\t^ (self textAnchorType == #inline\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'Inline' translated! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'dgd 9/6/2003 18:14'!\\nhasParagraphAnchorString\\n\\t^ (self textAnchorType == #paragraph\\n\\t\\tifTrue: ['<on>']\\n\\t\\tifFalse: ['<off>'])\\n\\t\\t, 'Paragraph' translated! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'ar 12/16/2001 19:47'!\\nrelativeTextAnchorPosition\\n\\t^self valueOfProperty: #relativeTextAnchorPosition! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'ar 12/16/2001 19:22'!\\nrelativeTextAnchorPosition: aPoint\\n\\t^self setProperty: #relativeTextAnchorPosition toValue: aPoint! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'ar 12/16/2001 18:36'!\\ntextAnchorType\\n\\t^self valueOfProperty: #textAnchorType ifAbsent:[#document]! !\\n\\n!Morph methodsFor: 'text-anchor' stamp: 'ar 12/16/2001 18:37'!\\ntextAnchorType: aSymbol\\n\\taSymbol == #document\\n\\t\\tifTrue:[^self removeProperty: #textAnchorType]\\n\\t\\tifFalse:[^self setProperty: #textAnchorType toValue: aSymbol].! !\\n\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'sw 10/26/2000 08:32'!\\ndemandsThumbnailing\\n\\t\\\"Answer whether the receiver, if in a thumbnailable parts bin, wants to be thumbnailed whether or not size requires it\\\"\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'dgd 9/12/2004 21:12'!\\nicon\\n\\t\\\"Answer a form with an icon to represent the receiver\\\"\\n\\t^ self valueOfProperty: #icon! !\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'dgd 9/12/2004 20:33'!\\niconOrThumbnail\\n\\t\\\"Answer an appropiate form to represent the receiver\\\"\\n\\n\\t^ self icon\\n\\t\\tifNil: [ | maxExtent fb |maxExtent := 320 @ 240.\\n\\t\\t\\tfb := self fullBounds.\\n\\t\\t\\tfb area <= (maxExtent x * maxExtent y)\\n\\t\\t\\t\\tifTrue: [self imageForm]\\n\\t\\t\\t\\tifFalse: [self imageFormForRectangle: (fb topLeft extent: maxExtent)]\\n\\t\\t]\\n! !\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'dgd 9/13/2004 12:43'!\\niconOrThumbnailOfSize: aNumberOrPoint \\n\\t\\\"Answer an appropiate form to represent the receiver\\\"\\n\\n\\t^ self iconOrThumbnail scaledIntoFormOfSize: aNumberOrPoint\\n! !\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'sw 8/16/2000 17:40'!\\nmorphRepresented\\n\\t\\\"If the receiver is an alias, answer the morph it represents; else answer self\\\"\\n\\n\\t^ self! !\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'sw 6/16/1999 11:29'!\\npermitsThumbnailing\\n\\t^ true! !\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'ar 11/9/2000 20:42'!\\nreadoutForField: fieldSym\\n\\t\\\"Provide a readout that will show the value of the slot/pseudoslot of the receiver generated by sending fieldSym to the receiver\\\"\\n\\n\\t| aContainer |\\n\\t\\\"still need to get this right\\\"\\n\\taContainer _ AlignmentMorph newColumn.\\n\\taContainer layoutInset: 0; hResizing: #rigid; vResizing: #shrinkWrap.\\n\\taContainer addMorphBack: (StringMorph new contents: (self perform: fieldSym) asString).\\n\\t^ aContainer! !\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'sw 12/6/2000 21:28'!\\nrepresentativeNoTallerThan: maxHeight norWiderThan: maxWidth thumbnailHeight: thumbnailHeight\\n\\t\\\"Return a morph representing the receiver but which is no taller than aHeight. If the receiver is already small enough, just return it, else return a MorphThumbnail companioned to the receiver, enforcing the maxWidth. If the receiver personally *demands* thumbnailing, do it even if there is no size-related reason to do it.\\\"\\n\\n\\tself demandsThumbnailing ifFalse:\\n\\t\\t[self permitsThumbnailing ifFalse: [^ self].\\n\\t\\t(self fullBounds height <= maxHeight and: [self fullBounds width <= maxWidth]) ifTrue: [^ self]].\\n\\n\\t^ MorphThumbnail new extent: maxWidth @ (thumbnailHeight min: self fullBounds height); morphRepresented: self! !\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'tk 3/28/2000 11:08'!\\nupdateThumbnailUrl\\n\\t\\\"If I have a cached thumbnail, then update it's urls.\\\"\\n\\t| cachedThumbnail |\\n\\n\\t(cachedThumbnail _ self valueOfProperty: #cachedThumbnail) ifNotNil:\\n\\t\\t[(cachedThumbnail respondsTo: #computeThumbnail) \\n\\t\\t\\tifTrue: [cachedThumbnail pageMorph: self url inBook: owner url]\\n\\t\\t\\tifFalse: [self removeProperty: #computeThumbnail]].\\n\\t\\t\\t\\\"Test and removal are because the thumbnail is being replaced \\n\\t\\t\\tby another Morph. We don't know why. Need to fix that at \\n\\t\\t\\tthe source.\\\"! !\\n\\n!Morph methodsFor: 'thumbnail' stamp: 'tk 3/28/2000 21:55'!\\nupdateThumbnailUrlInBook: bookUrl\\n\\t\\\"If I have a cached thumbnail, then update it's urls.\\\"\\n\\t| cachedThumbnail |\\n\\n\\t(cachedThumbnail _ self valueOfProperty: #cachedThumbnail) ifNotNil:\\n\\t\\t[(cachedThumbnail respondsTo: #computeThumbnail) \\n\\t\\t\\tifTrue: [cachedThumbnail pageMorph: self url inBook: bookUrl]\\n\\t\\t\\tifFalse: [self removeProperty: #computeThumbnail]].\\n\\t\\t\\t\\\"Test and removal are because the thumbnail is being replaced \\n\\t\\t\\tby another Morph. We don't know why. Need to fix that at \\n\\t\\t\\tthe source.\\\"! !\\n\\n\\n!Morph methodsFor: 'undo' stamp: 'ar 8/31/2000 23:15'!\\ncommandHistory\\n\\t\\\"Return the command history for the receiver\\\"\\n\\t| w |\\n\\t(w _ self world) ifNotNil:[^w commandHistory].\\n\\t(w _ self currentWorld) ifNotNil:[^w commandHistory].\\n\\t^CommandHistory new. \\\"won't really record anything but prevent breaking things\\\"! !\\n\\n!Morph methodsFor: 'undo' stamp: 'md 10/22/2003 15:56'!\\nundoMove: cmd redo: redo owner: formerOwner bounds: formerBounds predecessor: formerPredecessor \\n\\t\\\"Handle undo and redo of move commands in morphic\\\"\\n\\n\\tself owner ifNil: [^Beeper beep].\\n\\tredo \\n\\t\\tifFalse: \\n\\t\\t\\t[\\\"undo sets up the redo state first\\\"\\n\\n\\t\\t\\tcmd \\n\\t\\t\\t\\tredoTarget: self\\n\\t\\t\\t\\tselector: #undoMove:redo:owner:bounds:predecessor:\\n\\t\\t\\t\\targuments: { \\n\\t\\t\\t\\t\\t\\tcmd.\\n\\t\\t\\t\\t\\t\\ttrue.\\n\\t\\t\\t\\t\\t\\towner.\\n\\t\\t\\t\\t\\t\\tbounds.\\n\\t\\t\\t\\t\\t\\towner morphPreceding: self}].\\n\\tformerOwner ifNotNil: \\n\\t\\t\\t[formerPredecessor ifNil: [formerOwner addMorphFront: self]\\n\\t\\t\\t\\tifNotNil: [formerOwner addMorph: self after: formerPredecessor]].\\n\\tself bounds: formerBounds.\\n\\t(self isSystemWindow) ifTrue: [self activate]! !\\n\\n\\n!Morph methodsFor: 'updating' stamp: 'ar 6/25/2001 19:46'!\\nchanged\\n\\t\\\"Report that the area occupied by this morph should be redrawn.\\\"\\n\\t^fullBounds \\n\\t\\tifNil:[self invalidRect: self outerBounds]\\n\\t\\tifNotNil:[self invalidRect: fullBounds]! !\\n\\n\\n!Morph methodsFor: 'user interface' stamp: 'tak 3/15/2005 17:36'!\\nbecomeModal\\n\\tself currentWorld\\n\\t\\tifNotNil: [self currentWorld modalWindow: self]! !\\n\\n!Morph methodsFor: 'user interface' stamp: 'sw 5/29/2000 00:41'!\\ndefaultLabelForInspector\\n\\t\\\"Answer the default label to be used for an Inspector window on the receiver.\\\"\\n\\t^ super printString truncateTo: 40! !\\n\\n!Morph methodsFor: 'user interface' stamp: 'tak 3/15/2005 17:10'!\\ndoCancel\\n\\tself delete! !\\n\\n!Morph methodsFor: 'user interface' stamp: 'sw 10/2/97 23:08'!\\ninitialExtent\\n\\t| ext |\\n\\t(ext _ self valueOfProperty: #initialExtent)\\n\\t\\tifNotNil:\\n\\t\\t\\t[^ ext].\\n\\t^ super initialExtent! !\\n\\n\\n!Morph methodsFor: 'viewer' stamp: 'sw 10/30/1998 14:46'!\\nexternalName\\n\\t^ self knownName ifNil: [self innocuousName]! !\\n\\n\\n!Morph methodsFor: 'visual properties' stamp: 'ar 6/25/1999 11:11'!\\ncanHaveFillStyles\\n\\t\\\"Return true if the receiver can have general fill styles; not just colors.\\n\\tThis method is for gradually converting old morphs.\\\"\\n\\t^self class == Morph \\\"no subclasses\\\"! !\\n\\n!Morph methodsFor: 'visual properties' stamp: 'mk 8/7/2005 10:02'!\\ncornerStyle\\n\\t\\\"Returns one of the following symbols:\\n\\t\\t#square\\n\\t\\t#rounded\\n\\taccording to the current corner style.\\\"\\n\\n\\t^ self valueOfProperty: #cornerStyle ifAbsent: [#square]! !\\n\\n!Morph methodsFor: 'visual properties' stamp: 'nk 8/28/2003 15:56'!\\ndefaultBitmapFillForm\\n\\t^ImageMorph defaultForm.\\n! !\\n\\n!Morph methodsFor: 'visual properties' stamp: 'dgd 2/16/2003 20:02'!\\nfillStyle\\n\\t\\\"Return the current fillStyle of the receiver.\\\"\\n\\t^ self\\n\\t\\tvalueOfProperty: #fillStyle\\n\\t\\tifAbsent: [\\\"Workaround already converted morphs\\\"\\n\\t\\t\\tcolor\\n\\t\\t\\t\\tifNil: [self defaultColor]]! !\\n\\n!Morph methodsFor: 'visual properties' stamp: 'ar 6/18/1999 07:05'!\\nfillStyle: aFillStyle\\n\\t\\\"Set the current fillStyle of the receiver.\\\"\\n\\tself setProperty: #fillStyle toValue: aFillStyle.\\n\\t\\\"Workaround for Morphs not yet converted\\\"\\n\\tcolor _ aFillStyle asColor.\\n\\tself changed.! !\\n\\n!Morph methodsFor: 'visual properties' stamp: 'dgd 1/7/2005 19:31'!\\nfillWithRamp: rampSpecsOrColor oriented: aRatio \\n\\trampSpecsOrColor isColor\\n\\t\\tifTrue: [self color: rampSpecsOrColor\\\".\\n\\t\\t\\tself borderColor: rampSpecsOrColor muchDarker\\\"]\\n\\t\\tifFalse: [| fill | \\n\\t\\t\\tfill := GradientFillStyle ramp: rampSpecsOrColor.\\n\\t\\t\\tfill origin: self bounds topLeft.\\n\\t\\t\\tfill direction: (self bounds extent * aRatio) truncated.\\n\\t\\t\\tfill radial: false.\\n\\t\\t\\tself fillStyle: fill.\\n\\t\\t\\tself borderColor: (rampSpecsOrColor first value mixed: 0.5 with: rampSpecsOrColor last value) muchDarker]! !\\n\\n!Morph methodsFor: 'visual properties' stamp: 'nk 8/28/2003 15:57'!\\nuseBitmapFill\\n\\t\\\"Make receiver use a solid fill style (e.g., a simple color)\\\"\\n\\t| fill |\\n\\tself fillStyle isBitmapFill ifTrue:[^self]. \\\"Already done\\\"\\n\\tfill _ BitmapFillStyle fromForm: self defaultBitmapFillForm.\\n\\t\\\"Note: Must fix the origin due to global coordinates\\\"\\n\\tfill origin: self bounds origin.\\n\\tself fillStyle: fill.! !\\n\\n!Morph methodsFor: 'visual properties' stamp: 'ar 6/25/1999 11:11'!\\nuseDefaultFill\\n\\t\\\"Make receiver use a solid fill style (e.g., a simple color)\\\"\\n\\tself fillStyle: self defaultColor.! !\\n\\n!Morph methodsFor: 'visual properties' stamp: 'nk 2/27/2003 11:48'!\\nuseGradientFill\\n\\t\\\"Make receiver use a solid fill style (e.g., a simple color)\\\"\\n\\t| fill color1 color2 |\\n\\tself fillStyle isGradientFill ifTrue:[^self]. \\\"Already done\\\"\\n\\tcolor1 _ self color asColor.\\n\\tcolor2 _ color1 negated.\\n\\tfill _ GradientFillStyle ramp: {0.0 -> color1. 1.0 -> color2}.\\n\\tfill origin: self topLeft.\\n\\tfill direction: 0 @ self bounds extent y.\\n\\tfill normal: self bounds extent x @ 0.\\n\\tfill radial: false.\\n\\tself fillStyle: fill! !\\n\\n!Morph methodsFor: 'visual properties' stamp: 'ar 6/18/1999 06:57'!\\nuseSolidFill\\n\\t\\\"Make receiver use a solid fill style (e.g., a simple color)\\\"\\n\\tself fillStyle isSolidFill ifTrue:[^self]. \\\"Already done\\\"\\n\\tself fillStyle: self fillStyle asColor. \\\"Try minimizing changes\\\"! !\\n\\n\\n!Morph methodsFor: 'WiW support' stamp: 'RAA 2/16/2001 13:57'!\\naddMorphInFrontOfLayer: aMorph\\n\\n\\t| targetLayer layerHere |\\n\\n\\ttargetLayer _ aMorph morphicLayerNumberWithin: self.\\n\\tsubmorphs do: [ :each |\\n\\t\\teach == aMorph ifTrue: [^self].\\n\\t\\tlayerHere _ each morphicLayerNumberWithin: self.\\n\\t\\t\\\"the <= is the difference - it insures we go to the front of our layer\\\"\\n\\t\\ttargetLayer <= layerHere ifTrue: [\\n\\t\\t\\t^self addMorph: aMorph inFrontOf: each\\n\\t\\t].\\n\\t].\\n\\tself addMorphBack: aMorph.\\n! !\\n\\n!Morph methodsFor: 'WiW support' stamp: 'RAA 6/29/2000 10:49'!\\naddMorphInLayer: aMorph\\n\\n\\tsubmorphs do: [ :each |\\n\\t\\teach == aMorph ifTrue: [^self].\\n\\t\\taMorph morphicLayerNumber < each morphicLayerNumber ifTrue: [\\n\\t\\t\\t^self addMorph: aMorph inFrontOf: each\\n\\t\\t].\\n\\t].\\n\\tself addMorphBack: aMorph\\n! !\\n\\n!Morph methodsFor: 'WiW support' stamp: 'gk 5/24/2004 15:43'!\\neToyRejectDropMorph: morphToDrop event: evt\\n\\n\\t| tm am |\\n\\n\\ttm _ TextMorph new \\n\\t\\tbeAllFont: ((TextStyle named: Preferences standardEToysFont familyName) fontOfSize: 24);\\n\\t\\tcontents: 'GOT IT!!'.\\n\\t(am _ AlignmentMorph new)\\n\\t\\tcolor: Color yellow;\\n\\t\\tlayoutInset: 10;\\n\\t\\tuseRoundedCorners;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\taddMorph: tm;\\n\\t\\tfullBounds;\\n\\t\\tposition: (self bounds center - (am extent // 2));\\n\\t\\topenInWorld: self world.\\n\\tSoundService default playSoundNamed: 'yum' ifAbsentReadFrom: 'yum.aif'.\\n\\tmorphToDrop rejectDropMorphEvent: evt.\\t\\t\\\"send it back where it came from\\\"\\n\\tam delete\\n! !\\n\\n!Morph methodsFor: 'WiW support' stamp: 'RAA 7/19/2000 20:44'!\\nmorphicLayerNumber\\n\\n\\t\\\"helpful for insuring some morphs always appear in front of or behind others.\\n\\tsmaller numbers are in front\\\"\\n\\n\\t^(owner isNil or: [owner isWorldMorph]) ifTrue: [\\n\\t\\tself valueOfProperty: #morphicLayerNumber ifAbsent: [100]\\n\\t] ifFalse: [\\n\\t\\towner morphicLayerNumber\\n\\t].\\n\\n\\t\\\"leave lots of room for special things\\\"! !\\n\\n!Morph methodsFor: 'WiW support' stamp: 'RAA 2/16/2001 13:54'!\\nmorphicLayerNumberWithin: anOwner\\n\\n\\t\\\"helpful for insuring some morphs always appear in front of or behind others.\\n\\tsmaller numbers are in front\\\"\\n\\n\\t^(owner isNil or: [owner isWorldMorph or: [anOwner == owner]]) ifTrue: [\\n\\t\\tself valueOfProperty: #morphicLayerNumber ifAbsent: [100]\\n\\t] ifFalse: [\\n\\t\\towner morphicLayerNumber\\n\\t].\\n\\n\\t\\\"leave lots of room for special things\\\"! !\\n\\n!Morph methodsFor: 'WiW support' stamp: 'RAA 7/16/2000 13:54'!\\nrandomBoundsFor: aMorph\\n\\n\\t| trialRect |\\n\\ttrialRect _ (\\n\\t\\tself topLeft + \\n\\t\\t\\t((self width * (15 + 75 atRandom/100)) rounded @\\n\\t\\t\\t(self height * (15 + 75 atRandom/100)) rounded)\\n\\t) extent: aMorph extent.\\n\\t^trialRect translateBy: (trialRect amountToTranslateWithin: self bounds)\\n! !\\n\\n!Morph methodsFor: 'WiW support' stamp: 'ar 3/18/2001 00:14'!\\nshouldGetStepsFrom: aWorld\\n\\t^self world == aWorld! !\\n\\n\\n\\n\\n\\n\\n\\n!Morph methodsFor: '*eToys-customevents-scripting' stamp: 'nk 9/24/2003 17:31'!\\ninstantiatedUserScriptsDo: aBlock\\n\\tself actorStateOrNil ifNotNilDo: [ :aState | aState instantiatedUserScriptsDictionary do: aBlock]! !\\n\\n!Morph methodsFor: '*eToys-customevents-scripting' stamp: 'nk 9/25/2003 11:36'!\\nremoveAllEventTriggers\\n\\t\\\"Remove all the event registrations for my Player.\\n\\tUser custom events are triggered at the World,\\n\\twhile system custom events are triggered on individual Morphs.\\\"\\n\\n\\t| player |\\n\\t(player _ self player) ifNil: [ ^self ].\\n\\tself removeAllEventTriggersFor: player.\\n\\tself currentWorld removeAllEventTriggersFor: player.! !\\n\\n!Morph methodsFor: '*eToys-customevents-scripting' stamp: 'nk 9/24/2003 17:46'!\\nremoveAllEventTriggersFor: aPlayer\\n\\t\\\"Remove all the event registrations for aPlayer.\\n\\tUser custom events are triggered at the World,\\n\\twhile system custom events are triggered on individual Morphs.\\\"\\n\\n\\tself removeActionsSatisfying: \\n\\t\\t\\t[:action | action receiver == aPlayer and: [(#(#doScript: #triggerScript:) includes: action selector) ]].! !\\n\\n!Morph methodsFor: '*eToys-customevents-scripting' stamp: 'nk 9/25/2003 11:37'!\\nremoveEventTrigger: aSymbol\\n\\t\\\"Remove all the event registrations for my Player that are triggered by aSymbol.\\n\\tUser custom events are triggered at the World,\\n\\twhile system custom events are triggered on individual Morphs.\\\"\\n\\n\\t| player |\\n\\t(player _ self player) ifNil: [ ^self ].\\n\\tself removeEventTrigger: aSymbol for: player.\\n\\tself currentWorld removeEventTrigger: aSymbol for: player.! !\\n\\n!Morph methodsFor: '*eToys-customevents-scripting' stamp: 'nk 9/25/2003 11:24'!\\nremoveEventTrigger: aSymbol for: aPlayer \\n\\t\\\"Remove all the event registrations for aPlayer that are triggered by \\n\\taSymbol. User custom events are triggered at the World, \\n\\twhile system custom events are triggered on individual Morphs.\\\"\\n\\tself removeActionsSatisfying: [:action | action receiver == aPlayer\\n\\t\\t\\t\\tand: [(#(#doScript: #triggerScript: ) includes: action selector)\\n\\t\\t\\t\\t\\t\\tand: [action arguments first == aSymbol]]]! !\\n\\n!Morph methodsFor: '*eToys-customevents-scripting' stamp: 'nk 9/25/2003 11:11'!\\nrenameScriptActionsFor: aPlayer from: oldSelector to: newSelector\\n\\n\\tself updateableActionMap keysAndValuesDo: [ :event :sequence |\\n\\t\\tsequence asActionSequence do: [ :action |\\n\\t\\t\\t((action receiver == aPlayer)\\n\\t\\t\\t\\tand: [ (#(doScript: triggerScript:) includes: action selector)\\n\\t\\t\\t\\t\\tand: [ action arguments first == oldSelector ]])\\n\\t\\t\\t\\t\\t\\tifTrue: [ action arguments at: 1 put: newSelector ]]]\\n! !\\n\\n!Morph methodsFor: '*eToys-customevents-scripting' stamp: 'nk 11/1/2004 11:00'!\\ntriggerCustomEvent: aSymbol\\n\\t\\\"Trigger whatever scripts may be connected to the custom event named aSymbol\\\"\\n\\n\\tself currentWorld triggerEtoyEvent: aSymbol from: self! !\\n\\n!Morph methodsFor: '*eToys-customevents-scripting' stamp: 'nk 11/1/2004 10:54'!\\ntriggerEtoyEvent: aSymbol\\n\\t\\\"Trigger whatever scripts may be connected to the event named aSymbol.\\n\\tIf anyone comes back to ask who sent it, return our player.\\\"\\n\\n\\t[ self triggerEvent: aSymbol ]\\n\\t\\ton: GetTriggeringObjectNotification do: [ :ex |\\n\\t\\t\\tex isNested\\n\\t\\t\\t\\tifTrue: [ ex pass ]\\n\\t\\t\\t\\tifFalse: [ ex resume: self assuredPlayer ]]\\n! !\\n\\n!Morph methodsFor: '*eToys-customevents-scripting' stamp: 'nk 11/1/2004 10:58'!\\ntriggerEtoyEvent: aSymbol from: aMorph\\n\\t\\\"Trigger whatever scripts may be connected to the event named aSymbol.\\n\\tIf anyone comes back to ask who sent it, return aMorph's player.\\\"\\n\\n\\t[ self triggerEvent: aSymbol ]\\n\\t\\ton: GetTriggeringObjectNotification do: [ :ex |\\n\\t\\t\\tex isNested\\n\\t\\t\\t\\tifTrue: [ ex pass ]\\n\\t\\t\\t\\tifFalse: [ ex resume: aMorph assuredPlayer ]]\\n! !\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n!Morph methodsFor: '*Flash-classification' stamp: 'ar 8/10/1998 18:50'!\\nisFlashMorph\\n\\t^false! !\\n\\n\\n!Morph methodsFor: '*flexibleVocabularies-flexiblevocabularies-scripting' stamp: 'nk 9/11/2004 17:31'!\\nunfilteredCategoriesForViewer\\n\\t\\\"Answer a list of symbols representing the categories to offer in the viewer, in order of:\\n\\t- masterOrderingOfCategorySymbols first\\n\\t- others last in order by translated wording\\\"\\n\\t\\\"\\n\\tMorph basicNew unfilteredCategoriesForViewer\\n\\t\\\"\\n\\t^self renderedMorph class unfilteredCategoriesForViewer.\\n! !\\n\\n\\n!Morph methodsFor: '*MorphicExtras-accessing' stamp: 'dgd 1/7/2005 19:07'!\\nhighlightOnlySubmorph: aMorph\\n\\t\\\"Distinguish only aMorph with border highlighting (2-pixel wide red); make all my other submorphs have one-pixel-black highlighting. This is a rather special-purpose and hard-coded highlighting regime, of course. Later, if someone cared to do it, we could parameterize the widths and colors via properties, or some such.\\\"\\n\\n\\tself submorphs do:\\n\\t\\t[:m |\\n\\t\\t\\tm == aMorph\\n\\t\\t\\t\\tifTrue: [m borderWidth: 1; borderColor: Color red. m firstSubmorph color: Color red]\\n\\t\\t\\t\\tifFalse: [m borderWidth: 1; borderColor: Color black. m firstSubmorph color: Color black]\\n\\t\\t].\\n! !\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n!Morph methodsFor: '*MorphicExtras-geometry' stamp: 'dgd 8/31/2004 16:22'!\\nshiftSubmorphsBy: delta\\n\\tself shiftSubmorphsOtherThan: (submorphs select: [:m | m wantsToBeTopmost]) by: delta! !\\n\\n\\n\\n\\n\\n\\n\\n!Morph methodsFor: '*MorphicExtras-menus' stamp: 'dgd 4/3/2006 14:18'!\\ndismissButton\\n\\t\\\"Answer a button whose action would be to dismiss the receiver, and whose action is to send #delete to the receiver\\\"\\n\\n\\t| aButton |\\n\\taButton _ SimpleButtonMorph new.\\n\\taButton\\n\\t\\ttarget: self topRendererOrSelf;\\n\\t\\tcolor: ColorTheme current cancelColor;\\n\\t\\tborderColor: ColorTheme current cancelColor muchDarker;\\n\\t\\tborderWidth: 1;\\n\\t\\tlabel: 'X' font: Preferences standardButtonFont;\\n\\t\\tactionSelector: #delete;\\n\\t\\tsetBalloonText: 'dismiss' translated.\\n\\t^ aButton! !\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n!Morph methodsFor: '*services-base' stamp: 'rr 6/10/2005 11:30'!\\nrequestor\\n\\t^ owner ifNil: [super requestor] ifNotNil: [owner requestor]! !\\n\\n\\n!Morph methodsFor: '*sound-piano rolls' stamp: 'RAA 12/11/2000 17:29'!\\naddMorphsTo: morphList pianoRoll: pianoRoll eventTime: t betweenTime: leftTime and: rightTime\\n\\n\\t\\\"a hack to allow for abitrary morphs to be dropped into piano roll\\\"\\n\\tt > rightTime ifTrue: [^ self]. \\n\\tt < leftTime ifTrue: [^ self].\\n\\tmorphList add: (self left: (pianoRoll xForTime: t)).\\n! !\\n\\n!Morph methodsFor: '*sound-piano rolls' stamp: 'RAA 12/11/2000 15:48'!\\nencounteredAtTime: ticks inScorePlayer: scorePlayer atIndex: index inEventTrack: track secsPerTick: secsPerTick\\n\\n\\t\\\"a hack to allow for abitrary morphs to be dropped into piano roll\\\"\\n\\tself triggerActionFromPianoRoll.! !\\n\\n!Morph methodsFor: '*sound-piano rolls' stamp: 'stephaneducasse 2/4/2006 20:40'!\\njustDroppedIntoPianoRoll: pianoRoll event: evt\\n\\t\\n\\t| ambientEvent startTimeInScore |\\n\\tstartTimeInScore := pianoRoll timeForX: self left.\\n\\n\\tambientEvent := AmbientEvent new \\n\\t\\tmorph: self;\\n\\t\\ttime: startTimeInScore.\\n\\n\\tpianoRoll score addAmbientEvent: ambientEvent.\\n\\n\\t\\\"self endTime > pianoRoll scorePlayer durationInTicks ifTrue:\\n\\t\\t[pianoRoll scorePlayer updateDuration]\\\"\\n! !\\n\\n!Morph methodsFor: '*sound-piano rolls' stamp: 'RAA 12/11/2000 23:21'!\\npauseFrom: scorePlayer\\n\\n\\t\\\"subclasses should take five\\\"! !\\n\\n!Morph methodsFor: '*sound-piano rolls' stamp: 'RAA 12/11/2000 23:22'!\\nresetFrom: scorePlayer\\n\\n\\t\\\"subclasses should revert to their initial state\\\"! !\\n\\n!Morph methodsFor: '*sound-piano rolls' stamp: 'RAA 12/11/2000 23:21'!\\nresumeFrom: scorePlayer\\n\\n\\t\\\"subclasses should continue from their current position\\\"\\n\\t\\\"a hack to allow for abitrary morphs to be dropped into piano roll\\\"! !\\n\\n!Morph methodsFor: '*sound-piano rolls' stamp: 'stephaneducasse 2/4/2006 20:40'!\\ntriggerActionFromPianoRoll\\n\\n\\t| evt |\\n\\t\\\"a hack to allow for abitrary morphs to be dropped into piano roll\\\"\\n\\tself world ifNil: [^self].\\n\\tevt := MouseEvent new setType: nil position: self center buttons: 0 hand: self world activeHand.\\n\\tself programmedMouseUp: evt for: self.\\n\\n! !\\n\\n\\n!Morph methodsFor: 'private' stamp: 'sw 10/25/2000 06:11'!\\nmoveWithPenDownBy: delta\\n\\t\\\"If this is a costume for a player with its pen down, draw a line.\\\"\\n\\n\\t| trailMorph tfm start tfmEnd |\\n\\t(trailMorph _ self trailMorph) ifNotNil:\\n\\t\\t[tfm _ self owner transformFrom: trailMorph.\\n\\t\\tstart _ self referencePosition.\\n\\t\\ttrailMorph batchPenTrails\\n\\t\\t\\tifTrue: [trailMorph notePenDown: true\\n\\t\\t\\t\\t\\t\\t\\t\\tforPlayer: self player\\n\\t\\t\\t\\t\\t\\t\\t\\tat: (tfm localPointToGlobal: start)]\\n\\t\\t\\tifFalse: [trailMorph drawPenTrailFor: self\\n\\t\\t\\t\\t\\t\\t\\t\\tfrom: (tfm localPointToGlobal: start)\\n\\t\\t\\t\\t\\t\\t\\t\\tto: (tfmEnd _ tfm localPointToGlobal: start + delta).\\n\\t\\t\\t\\t\\ttrailMorph noteNewLocation: tfmEnd forPlayer: self player]]\\n! !\\n\\n!Morph methodsFor: 'private' stamp: 'nk 10/11/2003 16:08'!\\nprivateAddAllMorphs: aCollection atIndex: index\\n\\t\\\"Private. Add aCollection of morphs to the receiver\\\"\\n\\t| myWorld itsWorld otherSubmorphs |\\n\\tmyWorld _ self world.\\n\\totherSubmorphs _ submorphs copyWithoutAll: aCollection.\\n\\t(index between: 0 and: otherSubmorphs size)\\n\\t\\tifFalse: [^ self error: 'index out of range'].\\n\\tindex = 0\\n\\t\\tifTrue:[\\tsubmorphs _ aCollection asArray, otherSubmorphs]\\n\\t\\tifFalse:[\\tindex = otherSubmorphs size\\n\\t\\t\\tifTrue:[\\tsubmorphs _ otherSubmorphs, aCollection]\\n\\t\\t\\tifFalse:[\\tsubmorphs _ otherSubmorphs copyReplaceFrom: index + 1 to: index with: aCollection ]].\\n\\taCollection do: [:m | | itsOwner |\\n\\t\\titsOwner _ m owner.\\n\\t\\titsOwner ifNotNil: [\\n\\t\\t\\titsWorld _ m world.\\n\\t\\t\\t(itsWorld == myWorld) ifFalse: [\\n\\t\\t\\t\\titsWorld ifNotNil: [self privateInvalidateMorph: m].\\n\\t\\t\\t\\tm outOfWorld: itsWorld].\\n\\t\\t\\t(itsOwner ~~ self) ifTrue: [\\n\\t\\t\\t\\tm owner privateRemove: m.\\n\\t\\t\\t\\tm owner removedMorph: m ]].\\n\\t\\tm privateOwner: self.\\n\\t\\tmyWorld ifNotNil: [self privateInvalidateMorph: m].\\n\\t\\t(myWorld == itsWorld) ifFalse: [m intoWorld: myWorld].\\n\\t\\titsOwner == self ifFalse: [\\n\\t\\t\\tself addedMorph: m.\\n\\t\\t\\tm noteNewOwner: self ].\\n\\t].\\n\\tself layoutChanged.\\n! !\\n\\n!Morph methodsFor: 'private' stamp: 'nk 10/11/2003 16:08'!\\nprivateAddMorph: aMorph atIndex: index\\n\\n\\t| oldIndex myWorld itsWorld oldOwner |\\n\\t((index >= 1) and: [index <= (submorphs size + 1)])\\n\\t\\tifFalse: [^ self error: 'index out of range'].\\n\\tmyWorld _ self world.\\n\\toldOwner _ aMorph owner.\\n\\t(oldOwner == self and: [(oldIndex _ submorphs indexOf: aMorph) > 0]) ifTrue:[\\n\\t\\t\\\"aMorph's position changes within in the submorph chain\\\"\\n\\t\\toldIndex < index ifTrue:[\\n\\t\\t\\t\\\"moving aMorph to back\\\"\\n\\t\\t\\tsubmorphs replaceFrom: oldIndex to: index-2 with: submorphs startingAt: oldIndex+1.\\n\\t\\t\\tsubmorphs at: index-1 put: aMorph.\\n\\t\\t] ifFalse:[\\n\\t\\t\\t\\\"moving aMorph to front\\\"\\n\\t\\t\\toldIndex-1 to: index by: -1 do:[:i|\\n\\t\\t\\t\\tsubmorphs at: i+1 put: (submorphs at: i)].\\n\\t\\t\\tsubmorphs at: index put: aMorph.\\n\\t\\t].\\n\\t] ifFalse:[\\n\\t\\t\\\"adding a new morph\\\"\\n\\t\\toldOwner ifNotNil:[\\n\\t\\t\\titsWorld _ aMorph world.\\n\\t\\t\\titsWorld ifNotNil: [self privateInvalidateMorph: aMorph].\\n\\t\\t\\t(itsWorld == myWorld) ifFalse: [aMorph outOfWorld: itsWorld].\\n\\t\\t\\toldOwner privateRemove: aMorph.\\n\\t\\t\\toldOwner removedMorph: aMorph.\\n\\t\\t].\\n\\t\\taMorph privateOwner: self.\\n\\t\\tsubmorphs _ submorphs copyReplaceFrom: index to: index-1 with: (Array with: aMorph).\\n\\t\\t(itsWorld == myWorld) ifFalse: [aMorph intoWorld: myWorld].\\n\\t].\\n\\tmyWorld ifNotNil:[self privateInvalidateMorph: aMorph].\\n\\tself layoutChanged.\\n\\toldOwner == self ifFalse: [\\n\\t\\tself addedMorph: aMorph.\\n\\t\\taMorph noteNewOwner: self ].\\n! !\\n\\n!Morph methodsFor: 'private'!\\nprivateBounds: boundsRect\\n\\t\\\"Private!! Use position: and/or extent: instead.\\\"\\n\\n\\tfullBounds _ nil.\\n\\tbounds _ boundsRect.! !\\n\\n!Morph methodsFor: 'private' stamp: 'jm 5/29/1998 21:28'!\\nprivateColor: aColor\\n\\n\\tcolor _ aColor.\\n! !\\n\\n!Morph methodsFor: 'private' stamp: 'RAA 5/23/2000 11:31'!\\nprivateDeleteWithAbsolutelyNoSideEffects\\n\\t\\\"Private!! Should only be used by methods that maintain the ower/submorph invariant.\\\"\\n\\t\\\"used to delete a morph from an inactive world\\\"\\n\\n\\towner ifNil: [^self].\\n\\towner privateRemoveMorphWithAbsolutelyNoSideEffects: self.\\n\\towner _ nil.\\n\\n! !\\n\\n!Morph methodsFor: 'private' stamp: 'tk 8/30/1998 09:58'!\\nprivateFullBounds: boundsRect\\n\\t\\\"Private!! Computed automatically.\\\"\\n\\n\\tfullBounds _ boundsRect.! !\\n\\n!Morph methodsFor: 'private' stamp: 'ar 12/16/2001 21:47'!\\nprivateFullMoveBy: delta\\n\\t\\\"Private!! Relocate me and all of my subMorphs by recursion. Subclasses that implement different coordinate systems may override this method.\\\"\\n\\n\\tself privateMoveBy: delta.\\n\\t1 to: submorphs size do: [:i |\\n\\t\\t(submorphs at: i) privateFullMoveBy: delta].\\n\\towner ifNotNil:[\\n\\t\\towner isTextMorph ifTrue:[owner adjustTextAnchor: self]].! !\\n\\n!Morph methodsFor: 'private' stamp: 'md 2/27/2006 08:55'!\\nprivateMoveBy: delta \\n\\t\\\"Private!! Use 'position:' instead.\\\"\\n\\t| fill |\\n\\textension ifNotNil: [extension player\\n\\t\\t\\t\\tifNotNil: [\\\"Most cases eliminated fast by above test\\\"\\n\\t\\t\\t\\t\\tself getPenDown\\n\\t\\t\\t\\t\\t\\tifTrue: [\\\"If this is a costume for a player with its \\n\\t\\t\\t\\t\\t\\t\\tpen down, draw a line.\\\"\\n\\t\\t\\t\\t\\t\\t\\tself moveWithPenDownBy: delta]]].\\n\\tbounds _ bounds translateBy: delta.\\n\\tfullBounds ifNotNil: [fullBounds _ fullBounds translateBy: delta].\\n\\tfill _ self fillStyle.\\n\\tfill isOrientedFill ifTrue: [fill origin: fill origin + delta]! !\\n\\n!Morph methodsFor: 'private'!\\nprivateOwner: aMorph\\n\\t\\\"Private!! Should only be used by methods that maintain the ower/submorph invariant.\\\"\\n\\n\\towner _ aMorph.! !\\n\\n!Morph methodsFor: 'private' stamp: 'RAA 5/23/2000 11:30'!\\nprivateRemoveMorphWithAbsolutelyNoSideEffects: aMorph\\n\\t\\\"Private!! Should only be used by methods that maintain the ower/submorph invariant.\\\"\\n\\t\\\"used to delete a morph from an inactive world\\\"\\n\\n\\tsubmorphs _ submorphs copyWithout: aMorph.\\n\\n! !\\n\\n!Morph methodsFor: 'private' stamp: 'di 10/18/2004 21:49'!\\nprivateRemove: aMorph\\n\\t\\\"Private!! Should only be used by methods that maintain the ower/submorph invariant.\\\"\\n\\n\\tsubmorphs _ submorphs copyWithout: aMorph.\\n\\tself layoutChanged.! !\\n\\n!Morph methodsFor: 'private'!\\nprivateSubmorphs\\n\\t\\\"Private!! Use 'submorphs' instead.\\\"\\n\\n\\t^ submorphs! !\\n\\n!Morph methodsFor: 'private'!\\nprivateSubmorphs: aCollection\\n\\t\\\"Private!! Should only be used by methods that maintain the ower/submorph invariant.\\\"\\n\\n\\tsubmorphs _ aCollection.! !\\n\\n\\n!Morph methodsFor: 'accessing-backstop' stamp: 'wiz 2/14/2006 19:02'!\\ntarget: aMorph\\n\\\"Morphs with targets will override. This backstop does nothing.\\\"\\n\\\"This is here because targeting meta-actions are taken at morph level. \\nDo not remove.\\\"! !\\n\\n\\n!Morph methodsFor: 'translation' stamp: 'yo 1/27/2005 23:29'!\\naccumlatePlayersInto: aCollection andSelectorsInto: selectorsCollection\\n\\n\\tsubmorphs do: [:tile |\\n\\t\\t(tile isMemberOf: TileMorph) ifTrue: [\\n\\t\\t\\t(tile type = #objRef and: [tile actualObject isKindOf: Player]) ifTrue: [\\n\\t\\t\\t\\taCollection add: tile actualObject\\n\\t\\t\\t]\\n\\t\\t].\\n\\t\\t(tile isKindOf: AssignmentTileMorph) ifTrue: [\\n\\t\\t\\t(tile type = #operator) ifTrue: [\\n\\t\\t\\t\\tselectorsCollection add: tile operatorOrExpression\\n\\t\\t\\t]\\n\\t\\t].\\n\\t\\ttile accumlatePlayersInto: aCollection andSelectorsInto: selectorsCollection\\n\\t].\\n! !\\n\\n!Morph methodsFor: 'translation' stamp: 'sw 3/7/2004 13:03'!\\nisPlayer: aPlayer ofReferencingTile: tile\\n\\t\\\"Answer whether the given player is the object referred to by the given tile, or a sibling of that object. This theoretically is only sent to PhraseTileMorphs, so this version is theoretically never reached\\\"\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'translation' stamp: 'yo 1/27/2005 23:33'!\\nisTurtleRow\\n\\n\\t| aCollection selectorCollection |\\n\\taCollection _ Set new.\\n\\tselectorCollection _ Set new.\\n\\tself accumlatePlayersInto: aCollection andSelectorsInto: selectorCollection.\\n\\t#(turtleCount: turtleCount grouped: grouped) do: [:sel |\\n\\t\\t(selectorCollection includes: sel) ifTrue: [^ false].\\n\\t].\\n\\n\\taCollection do: [:e |\\n\\t\\t(e isKindOf: KedamaExamplerPlayer) ifTrue: [^ true].\\n\\t].\\n\\t^ false.\\n! !\\n\\n!Morph methodsFor: 'translation' stamp: 'yo 1/18/2004 10:31'!\\ntraverseRowTranslateSlotOld: oldSlotName of: aPlayer to: newSlotName\\n\\t\\\"Traverse my submorphs, translating submorphs appropriately given the slot rename\\\"\\n\\n\\tsubmorphs do: [:tile |\\n\\t\\t(tile isKindOf: AssignmentTileMorph) ifTrue:\\n\\t\\t\\t[tile assignmentRoot = oldSlotName ifTrue:\\n\\t\\t\\t\\t[(self isPlayer: aPlayer ofReferencingTile: tile) ifTrue:\\n\\t\\t\\t\\t\\t[tile setRoot: newSlotName]]].\\n\\t\\t(tile isMemberOf: TileMorph) ifTrue:\\n\\t\\t\\t[(tile operatorOrExpression = (Utilities getterSelectorFor: oldSlotName)) ifTrue:\\n\\t\\t\\t\\t[(self isPlayer: aPlayer ofReferencingTile: tile) ifTrue:\\n\\t\\t\\t\\t\\t[tile setOperator: (Utilities getterSelectorFor: newSlotName)]]].\\n\\t\\ttile traverseRowTranslateSlotOld: oldSlotName of: aPlayer to: newSlotName]! !\\n\\n!Morph methodsFor: 'translation' stamp: 'yo 1/18/2004 10:32'!\\ntraverseRowTranslateSlotOld: oldSlotName to: newSlotName\\n\\t\\\"Traverse my submorphs, translating submorphs appropriately given the slot rename\\\"\\n\\n\\tsubmorphs do: [:tile |\\n\\t\\t(tile isKindOf: AssignmentTileMorph) ifTrue: \\n\\t\\t\\t[tile assignmentRoot = oldSlotName ifTrue: [tile setRoot: newSlotName]].\\n\\t\\t(tile isMemberOf: TileMorph) ifTrue:\\n\\t\\t\\t[(tile operatorOrExpression = (Utilities getterSelectorFor: oldSlotName)) ifTrue:\\n\\t\\t\\t\\t[tile setOperator: (Utilities getterSelectorFor: newSlotName)]].\\n\\t\\ttile traverseRowTranslateSlotOld: oldSlotName to: newSlotName]! !\\n\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 2/9/1999 17:43'!\\nadaptToWorld: aWorld\\n\\t\\\"The receiver finds itself operating in a possibly-different new world. If any of the receiver's parts are world-dependent (such as a target of a SimpleButtonMorph, etc.), then have them adapt accordingly\\\"\\n\\tsubmorphs do: [:m | m adaptToWorld: aWorld].\\n\\tself eventHandler ifNotNil:\\n\\t\\t[self eventHandler adaptToWorld: aWorld]! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 5/17/2001 12:47'!\\nadoptVocabulary: aVocabulary\\n\\t\\\"Make aVocabulary be the one used by me and my submorphs\\\"\\n\\n\\tself submorphsDo: [:m | m adoptVocabulary: aVocabulary]! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'yo 1/9/2004 16:10'!\\nallMorphsAndBookPagesInto: aSet\\n\\t\\\"Return a set of all submorphs. Don't forget the hidden ones like BookMorph pages that are not showing. Consider only objects that are in memory (see allNonSubmorphMorphs).\\\" \\n\\n\\tsubmorphs do: [:m | m allMorphsAndBookPagesInto: aSet].\\n\\tself allNonSubmorphMorphs do: [:m | \\n\\t\\t\\t(aSet includes: m) ifFalse: [\\\"Stop infinite recursion\\\"\\n\\t\\t\\t\\tm allMorphsAndBookPagesInto: aSet]].\\n\\taSet add: self.\\n\\tself player ifNotNil:\\n\\t\\t[self player allScriptEditors do: [:e | e allMorphsAndBookPagesInto: aSet]].\\n\\t^ aSet! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'RAA 1/13/2001 11:27'!\\nappearsToBeSameCostumeAs: aMorph\\n\\n\\t^false\\n! !\\n\\n!Morph methodsFor: 'e-toy support'!\\nasNumber: aPointOrNumber\\n\\t\\\"Support for e-toy demo.\\\"\\n\\n\\taPointOrNumber class = Point\\n\\t\\tifTrue: [^ aPointOrNumber r]\\n\\t\\tifFalse: [^ aPointOrNumber].\\n! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'nk 1/6/2004 12:37'!\\nasWearableCostume\\n\\t\\\"Return a wearable costume for some player\\\"\\n\\t^(World drawingClass withForm: self imageForm) copyCostumeStateFrom: self! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'mir 6/13/2001 14:34'!\\nasWearableCostumeOfExtent: extent\\n\\t\\\"Return a wearable costume for some player\\\"\\n\\t^self asWearableCostume! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 12/20/1999 17:36'!\\nautomaticViewing\\n\\t\\\"Backstop, in case this message gets sent to an owner that is not a playfield\\\"\\n\\t^ false! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 5/18/2001 11:17'!\\nchangeAllBorderColorsFrom: oldColor to: newColor\\n\\t\\\"Set any occurrence of oldColor as a border color in my entire submorph tree to be newColor\\\"\\n\\n\\t(self allMorphs select: [:m | m respondsTo: #borderColor:]) do:\\n\\t\\t[:aMorph | aMorph borderColor = oldColor ifTrue: [aMorph borderColor: newColor]]! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 10/1/97 00:18'!\\nconfigureForKids\\n\\tsubmorphs ifNotNil:\\n\\t\\t[submorphs do: [:m | m configureForKids]]! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 2/6/2001 04:21'!\\ncontainingWindow\\n\\t\\\"Answer a window or window-with-mvc that contains the receiver\\\"\\n\\n\\t^ self ownerThatIsA: SystemWindow orA: MVCWiWPasteUpMorph! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'ar 9/23/2000 22:38'!\\ncopyCostumeStateFrom: aMorph\\n\\t\\\"Copy all state that should be persistant for costumes from aMorph\\\"\\n\\tself rotationCenter: aMorph rotationCenter.\\n\\tself rotationStyle: aMorph rotationStyle.\\n\\tself referencePosition: aMorph referencePosition.\\n\\tself forwardDirection: aMorph forwardDirection.\\n! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 10/22/1998 20:28'!\\ncurrentPlayerDo: aBlock\\n\\t\\\"If the receiver is a viewer/scriptor associated with a current Player object, evaluate the given block against that object\\\"! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 9/8/2000 16:34'!\\ncursor\\n\\t\\\"vacuous backstop in case it gets sent to a morph that doesn't know what to do with it\\\"\\n\\n\\t^ 1! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 9/7/2000 09:28'!\\ncursor: aNumber\\n\\t\\\"vacuous backstop in case it gets sent to a morph that doesn't know what to do with it\\\"\\n! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 9/13/2002 17:44'!\\ndecimalPlacesForGetter: aGetter\\n\\t\\\"Answer the decimal places I prefer for showing a slot with the given getter, or nil if none\\\"\\n\\n\\t| decimalPrefs |\\n\\tdecimalPrefs _ self renderedMorph valueOfProperty: #decimalPlacePreferences ifAbsent: [^ nil].\\n\\t^ decimalPrefs at: aGetter ifAbsent: [nil]! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 10/24/2000 05:52'!\\ndefaultValueOrNil\\n\\t\\\"If the receiver has a property named #defaultValue, return that property's value, else return nil\\\"\\n\\n\\t^ self valueOfProperty: #defaultValue ifAbsent: [nil]! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sd 3/30/2005 22:04'!\\ndefaultVariableName\\n\\t\\\"If the receiver is of the sort that wants a variable maintained on its behalf in the 'card' data, then return a variable name to be used for that datum. What is returned here is only a point of departure in the forthcoming negotiation\\\"\\n\\n\\t^ Scanner wellFormedInstanceVariableNameFrom: (self valueOfProperty: #variableName ifAbsent: [self externalName])! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'nb 6/17/2003 12:25'!\\ndefinePath\\n\\t| points lastPoint aForm offset currentPoint dwell ownerPosition |\\n\\tpoints _ OrderedCollection new: 70.\\n\\tlastPoint _ nil.\\n\\taForm _ self imageForm.\\n\\toffset _ aForm extent // 2.\\n\\townerPosition _ owner position.\\n\\tCursor move show.\\n\\tSensor waitButton.\\n\\t[Sensor anyButtonPressed and: [points size < 100]] whileTrue:\\n\\t\\t[currentPoint _ Sensor cursorPoint.\\n\\t\\tdwell _ 0.\\n\\t\\tcurrentPoint = lastPoint\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[dwell _ dwell + 1.\\n\\t\\t\\t\\t((dwell \\\\\\\\ 1000) = 0) ifTrue:\\n\\t\\t\\t\\t\\t[Beeper beep]]\\n\\t\\t\\tifFalse:\\n\\t\\t\\t\\t[self position: (currentPoint - offset).\\n\\t\\t\\t\\tself world displayWorld.\\n\\t\\t\\t\\t(Delay forMilliseconds: 20) wait.\\n\\t\\t\\t\\tpoints add: currentPoint.\\n\\t\\t\\t\\tlastPoint _ currentPoint]].\\n\\tpoints size > 1\\n\\t\\tifFalse:\\n\\t\\t\\t[self inform: 'no path obtained']\\n\\t\\tifTrue:\\n\\t\\t\\t[points size = 100 ifTrue: [self playSoundNamed: 'croak'].\\n\\n\\t\\t\\tTranscript cr; show: 'path defined with\\n', points size printString, ' points'.\\n\\t\\t\\tself renderedMorph setProperty: #pathPoints toValue: \\n\\t\\t\\t\\t(points collect: [:p | p - ownerPosition])].\\n\\n\\tCursor normal show\\n\\t\\t! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 1/5/1999 10:05'!\\ndeletePath\\n\\tself removeProperty: #pathPoints! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 10/26/1999 23:32'!\\nembeddedInMorphicWindowLabeled: labelString\\n\\t| window |\\n\\twindow _ (SystemWindow labelled: labelString) model: nil.\\n\\twindow setStripeColorsFrom: nil defaultBackgroundColor.\\n\\twindow addMorph: self frame: (0@0 extent: 1@1).\\n\\t^ window! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'RAA 5/25/2000 09:06'!\\nembedInWindow\\n\\n\\t| window worldToUse |\\n\\n\\tworldToUse _ self world.\\t\\t\\\"I'm assuming we are already in a world\\\"\\n\\twindow _ (SystemWindow labelled: self defaultLabelForInspector) model: nil.\\n\\twindow bounds: ((self position - ((0@window labelHeight) + window borderWidth))\\n\\t\\t\\t\\t\\t\\tcorner: self bottomRight + window borderWidth).\\n\\twindow addMorph: self frame: (0@0 extent: 1@1).\\n\\twindow updatePaneColors.\\n\\tworldToUse addMorph: window.\\n\\twindow activate! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'dgd 2/22/2003 14:31'!\\nenclosingEditor\\n\\t\\\"Return the next editor around the receiver\\\"\\n\\n\\t| tested |\\n\\ttested := owner.\\n\\t[tested isNil] whileFalse: \\n\\t\\t\\t[tested isTileEditor ifTrue: [^tested].\\n\\t\\t\\ttested := tested owner].\\n\\t^nil! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 2/15/1999 19:38'!\\nenforceTileColorPolicy\\n\\tPreferences coloredTilesEnabled\\n\\t\\tifTrue:\\n\\t\\t\\t[self makeAllTilesColored]\\n\\t\\tifFalse:\\n\\t\\t\\t[self makeAllTilesGreen]! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'RAA 10/4/2000 08:29'!\\nfenceEnabled\\n\\n\\t\\\"in case a non-pasteUp is used as a container\\\"\\n\\n\\t^Preferences fenceEnabled! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'nb 6/17/2003 12:25'!\\nfollowPath\\n\\t| pathPoints offset |\\n\\t(pathPoints _ self renderedMorph valueOfProperty: #pathPoints) ifNil: [^ Beeper beep].\\n\\toffset _ owner position - (self extent // 2).\\n\\tpathPoints do:\\n\\t\\t[:aPoint |\\n\\t\\t\\tself position: aPoint + offset.\\n\\t\\t\\tself world displayWorld.\\n\\t\\t\\t(Delay forMilliseconds: 20) wait]! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 2/18/2003 02:54'!\\ngetCharacters\\n\\t\\\"obtain a string value from the receiver. The default generic response is simply the name of the object.\\\"\\n\\n\\t^ self externalName! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 9/1/2000 10:15'!\\ngetNumericValue\\n\\t\\\"Only certain kinds of morphs know how to deal with this frontally; here we provide support for a numeric property of any morph\\\"\\n\\n\\t^ self valueOfProperty: #numericValue ifAbsent: [0]! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'kfr 9/4/2004 15:22'!\\ngridFormOrigin: origin grid: smallGrid background: backColor line: lineColor\\n\\n\\t| bigGrid gridForm gridOrigin |\\n\\tgridOrigin _ origin \\\\\\\\ smallGrid.\\n\\tbigGrid _ (smallGrid asPoint x) @ (smallGrid asPoint y).\\n\\tgridForm _ Form extent: bigGrid depth: Display depth.\\n\\tbackColor ifNotNil: [gridForm fillWithColor: backColor].\\n\\tgridOrigin x to: gridForm width by: smallGrid x do:\\n\\t\\t[:x | gridForm fill: (x@0 extent: 1@gridForm height) fillColor: lineColor].\\n\\tgridOrigin y to: gridForm height by: smallGrid y do:\\n\\t\\t[:y | gridForm fill: (0@y extent: gridForm width@1) fillColor: lineColor].\\n\\t^ InfiniteForm with: gridForm\\n! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 4/12/2005 23:07'!\\nhandUserASibling\\n\\t\\\"Make and hand the user a sibling instance. Force the creation of a uniclass at this point if one does not already exist for the receiver.\\\"\\n\\n\\t| topRend |\\n\\ttopRend _ self topRendererOrSelf.\\n\\ttopRend couldMakeSibling ifFalse: [^ Beeper beep].\\n\\n\\ttopRend assuredPlayer assureUniClass.\\n\\t(topRend makeSiblings: 1) first openInHand! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 10/21/1998 15:54'!\\nisAViewer\\n\\t^ false! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 6/30/1999 20:29'!\\nisCandidateForAutomaticViewing\\n\\t^ true! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'ar 2/7/2001 17:58'!\\nisTileEditor\\n\\t\\\"No, I'm not\\\"\\n\\t^false! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 10/9/2000 16:48'!\\nlistViewLineForFieldList: aFieldList\\n\\t\\\"Answer a ListLineView object which describes the receiver\\\"\\n\\n\\t| aLine |\\n\\taLine _ ListViewLine new objectRepresented: self.\\n\\taFieldList do:\\n\\t\\t[:fieldSym | aLine addMorphBack: (self readoutForField: fieldSym).\\n\\t\\taLine addTransparentSpacerOfSize: (7 @ 0)].\\n\\t^ aLine! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'dgd 9/6/2003 18:10'!\\nmakeGraphPaper\\n\\t| smallGrid backColor lineColor |\\n\\tsmallGrid _ Compiler evaluate: (FillInTheBlank request: 'Enter grid size' translated initialAnswer: '16').\\n\\tsmallGrid ifNil: [^ self].\\n\\tUtilities informUser: 'Choose a background color' translated during: [backColor _ Color fromUser].\\n\\tUtilities informUser: 'Choose a line color' translated during: [lineColor _ Color fromUser].\\n\\tself makeGraphPaperGrid: smallGrid background: backColor line: lineColor.! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'di 9/7/2000 20:44'!\\nmakeGraphPaperGrid: smallGrid background: backColor line: lineColor\\n\\n\\t| gridForm |\\n\\tgridForm _ self gridFormOrigin: 0@0 grid: smallGrid asPoint background: backColor line: lineColor.\\n\\tself color: gridForm.\\n\\tself world ifNotNil: [self world fullRepaintNeeded].\\n\\tself changed: #newColor. \\\"propagate to view\\\"\\n! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 4/16/1998 13:46'!\\nmustBeBackmost\\n\\t\\\"Answer whether the receiver needs to be the backmost morph in its owner's submorph list\\\"\\n\\n\\t^ false! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 9/13/2002 17:45'!\\nnoteDecimalPlaces: aNumber forGetter: aGetter\\n\\t\\\"Make a mental note of the user's preference for a particular number of decimal places to be associated with the slot with the given getter\\\"\\n\\n\\t(self renderedMorph valueOfProperty: #decimalPlacePreferences ifAbsentPut: [IdentityDictionary new])\\n\\t\\tat: aGetter put: aNumber! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 10/26/2000 11:37'!\\nnoteNegotiatedName: uniqueName for: requestedName\\n\\t\\\"This works, kind of, for morphs that have a single variable. Still holding out for generality of morphs being able to have multiple variables, but need a driving example\\\"\\n\\n\\tself setProperty: #variableName toValue: uniqueName.\\n\\tself setProperty: #setterSelector toValue: (Utilities setterSelectorFor: uniqueName).\\n\\tself setNameTo: uniqueName! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 10/9/2000 06:43'!\\nobjectViewed\\n\\t\\\"Answer the morph associated with the player that the structure the receiver currently finds itself within represents.\\\"\\n\\n\\t^ (self outermostMorphThat: [:o | o isKindOf: Viewer orOf: ScriptEditorMorph]) objectViewed! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 8/31/2004 14:11'!\\npinkXButton\\n\\t\\\"Answer a button with the old X on a pink background, targeted to self\\\"\\n\\n\\t| aButton |\\n\\taButton _ IconicButton new labelGraphic: (ScriptingSystem formAtKey: #PinkX).\\n\\taButton color: Color transparent; borderWidth: 0; shedSelvedge; actWhen: #buttonUp.\\n\\taButton target: self.\\n\\t^ aButton! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 9/11/2004 16:23'!\\nreferencePlayfield\\n\\t\\\"Answer the PasteUpMorph to be used for cartesian-coordinate reference\\\"\\n\\n\\t| former |\\n\\towner ifNotNil:\\n\\t\\t[(self topRendererOrSelf owner isHandMorph and: [(former _ self formerOwner) notNil])\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[former _ former renderedMorph.\\n\\t\\t\\t\\t^ former isPlayfieldLike \\n\\t\\t\\t\\t\\tifTrue: [former]\\n\\t\\t\\t\\t\\tifFalse: [former referencePlayfield]]].\\n\\n\\tself allOwnersDo: [:o | o isPlayfieldLike ifTrue: [^ o]].\\n\\t^ ActiveWorld! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'ar 9/23/2000 22:40'!\\nrotationStyle\\n\\t\\\"Return the 'rotation style' of the receiver\\\"\\n\\t^#normal! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'ar 9/23/2000 22:40'!\\nrotationStyle: aSymbol\\n\\t\\\"Set the 'rotation style' of the receiver; this is ignored for non-sketches\\\"! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'RAA 3/9/2001 14:37'!\\nsetAsActionInButtonProperties: buttonProperties\\n\\n\\t^false\\t\\\"means I don't know how to be set as a button action\\\"! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 9/15/2000 06:26'!\\nsetNumericValue: aValue\\n\\t\\\"Set the receiver's contents to reflect the given numeric value. Only certain kinds of morphs know what to do with this, the rest, for now, stash the number in a property, where it may not be visible but at least it won't be lost, and can be retrieved by the companion getter. This code is never reached under normal circumstances, because the #numericValue slot is not shown in Viewers for most kinds of morphs, and those kinds of morphs that do show it also reimplement this method. However, this code *could* be reached via a user script which sends #setNumericValue: but whose receiver has been changed, via tile-scripting drag and drop for example, to one that doesn't directly handle numbers\\\"\\n\\n\\tScriptingSystem informScriptingUser: 'an unusual setNumericValue: call was made'.\\n\\tself renderedMorph setProperty: #numericValue toValue: aValue\\n! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 7/21/1998 21:18'!\\nsetStandardTexture\\n\\t| parms |\\n\\tparms _ self textureParameters.\\n\\tself makeGraphPaperGrid: parms first\\n\\t\\tbackground: parms second\\n\\t\\tline: parms third! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 10/27/2000 17:46'!\\nslotSpecifications\\n\\t\\\"A once and possibly future feature; retained here for backward-compatibility bulletproofing.\\\"\\n\\n\\t^ #()! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 8/11/1998 16:55'!\\nsucceededInRevealing: aPlayer\\n\\taPlayer == self player ifTrue: [^ true].\\n\\tsubmorphs do:\\n\\t\\t[:m | (m succeededInRevealing: aPlayer) ifTrue: [^ true]].\\n\\t^ false! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 8/31/2004 14:06'!\\ntanOButton\\n\\t\\\"Answer a button with the old O on a tan background, targeted to self\\\"\\n\\n\\t| aButton |\\n\\taButton _ IconicButton new labelGraphic: (ScriptingSystem formAtKey: #TanO).\\n\\taButton color: Color transparent; borderWidth: 0; shedSelvedge; actWhen: #buttonUp.\\n\\taButton target: self.\\n\\t^ aButton! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 7/21/1998 21:17'!\\ntextureParameters\\n\\t\\\"Answer a triplet giving the preferred grid size, background color, and line color. The choices here are as suggested by Alan, 9/13/97\\\"\\n\\n\\t^ Array with: 16 with: Color lightYellow with: Color lightGreen lighter lighter! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'dgd 2/22/2003 14:35'!\\ntopEditor\\n\\t\\\"Return the top-most editor around the receiver\\\"\\n\\n\\t| found tested |\\n\\ttested := self.\\n\\t[tested isNil] whileFalse: \\n\\t\\t\\t[tested isTileEditor ifTrue: [found := tested].\\n\\t\\t\\ttested := tested owner].\\n\\t^found! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'dgd 10/8/2003 19:30'!\\nunlockOneSubpart\\n\\t| unlockables aMenu reply |\\n\\tunlockables _ self submorphs select:\\n\\t\\t[:m | m isLocked].\\n\\tunlockables size <= 1 ifTrue: [^ self unlockContents].\\n\\taMenu _ SelectionMenu labelList: (unlockables collect: [:m | m externalName]) selections: unlockables.\\n\\treply _ aMenu startUpWithCaption: 'Who should be be unlocked?' translated.\\n\\treply isNil ifTrue: [^ self].\\n\\treply unlock! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'tk 10/19/1999 07:16'!\\nupdateCachedThumbnail\\n\\t\\\"If I have a cached thumbnail, then update it. Copied up from Dan's original version in PasteUpMorph so it can be used by all morphs.\\\"\\n\\t| cachedThumbnail |\\n\\n\\t(cachedThumbnail _ self valueOfProperty: #cachedThumbnail) ifNotNil:\\n\\t\\t[(cachedThumbnail respondsTo: #computeThumbnail) \\n\\t\\t\\tifTrue: [cachedThumbnail computeThumbnail]\\n\\t\\t\\tifFalse: [self removeProperty: #computeThumbnail]].\\n\\t\\t\\\"Test and removal are because the thumbnail is being replaced by another Morph. We don't know why. Need to fix that at the source.\\\"! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'sw 11/27/2001 14:52'!\\nwantsRecolorHandle\\n\\t\\\"Answer whether the receiver would like a recoloring halo handle to be put up. Since this handle also presently affords access to the property-sheet, it is presently always allowed, even though SketchMorphs don't like regular recoloring\\\"\\n\\n\\t^ true\\n\\t\\n! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'RAA 2/5/2001 15:35'!\\nwrappedInWindowWithTitle: aTitle\\n\\t| aWindow w2 |\\n\\taWindow _ (SystemWindow labelled: aTitle) model: Model new.\\n\\taWindow addMorph: self frame: (0@0 extent: 1@1).\\n\\tw2 _ aWindow borderWidth * 2.\\n\\tw2 _ 3.\\t\\t\\\"oh, well\\\"\\n\\taWindow extent: self fullBounds extent + (0 @ aWindow labelHeight) + (w2 @ w2).\\n\\t^ aWindow! !\\n\\n!Morph methodsFor: 'e-toy support' stamp: 'tk 9/3/1999 11:46'!\\nwrappedInWindow: aSystemWindow\\n\\t| aWindow |\\n\\taWindow _ aSystemWindow model: Model new.\\n\\taWindow addMorph: self frame: (0@0 extent: 1@1).\\n\\taWindow extent: self extent.\\n\\t^ aWindow! !\\n\\n\\n!Morph methodsFor: 'messenger' stamp: 'sw 11/3/2001 12:23'!\\naffiliatedSelector\\n\\t\\\"Answer a selector affiliated with the receiver for the purposes of launching a messenger. Reimplement this to plug into the messenger service\\\"\\n\\n\\t^ nil! !\\n\\n\\n!Morph methodsFor: 'geniestubs' stamp: 'nk 3/10/2004 09:58'!\\nallowsGestureStart: evt\\n\\t^false! !\\n\\n!Morph methodsFor: 'geniestubs' stamp: 'nk 3/11/2004 17:45'!\\nisGestureStart: anEvent\\n\\t\\\"This mouse down could be the start of a gesture, or the end of a gesture focus\\\"\\n\\n\\tanEvent hand isGenieEnabled\\n\\t\\tifFalse: [ ^false ].\\n\\n\\t(self allowsGestureStart: anEvent)\\n\\t\\tifTrue: [^ true ].\\t\\t\\\"could be the start of a gesture\\\"\\n\\n\\t\\\"otherwise, check for whether it's time to disable the Genie auto-focus\\\"\\n\\t(anEvent hand isGenieFocused\\n\\t\\tand: [anEvent whichButton ~= anEvent hand focusStartEvent whichButton])\\n\\t\\t\\tifTrue: [anEvent hand disableGenieFocus].\\n\\n\\t^false! !\\n\\n!Morph methodsFor: 'geniestubs' stamp: 'nk 3/11/2004 17:30'!\\nmouseStillDownStepRate\\n\\t\\\"At what rate do I want to receive #mouseStillDown: notifications?\\\"\\n\\t^1! !\\n\\n!Morph methodsFor: 'geniestubs' stamp: 'nk 3/10/2004 06:38'!\\nredButtonGestureDictionaryOrName: aSymbolOrDictionary! !\\n\\n!Morph methodsFor: 'geniestubs' stamp: 'nk 3/10/2004 06:38'!\\nyellowButtonGestureDictionaryOrName: aSymbolOrDictionary! !\\n\\n\\n!Morph methodsFor: '*morphic-Postscript Canvases' stamp: 'di 9/22/1999 08:45'!\\nasEPS\\n\\n\\t^ EPSCanvas morphAsPostscript: self rotated: false.\\n! !\\n\\n!Morph methodsFor: '*morphic-Postscript Canvases'!\\nasPostscript\\n\\t^self asEPS.\\n! !\\n\\n!Morph methodsFor: '*morphic-Postscript Canvases' stamp: 'di 9/22/1999 08:45'!\\nasPostscriptPrintJob\\n\\n\\t^ DSCPostscriptCanvas morphAsPostscript: self rotated: false.\\n! !\\n\\n!Morph methodsFor: '*morphic-Postscript Canvases' stamp: 'ar 1/16/2001 17:06'!\\nclipPostscript\\n\\t^Clipboard clipboardText: self asPostscript.\\n\\n! !\\n\\n!Morph methodsFor: '*morphic-Postscript Canvases' stamp: 'mpw 8/10/1930 05:21'!\\ndrawPostscriptOn: aCanvas\\n\\n\\tself drawOn:aCanvas.\\n! !\\n\\n!Morph methodsFor: '*morphic-Postscript Canvases' stamp: 'mpw 8/10/1930 05:25'!\\nfullDrawPostscriptOn: aCanvas\\n\\n\\tself fullDrawOn:aCanvas.\\n! !\\n\\n!Morph methodsFor: '*morphic-Postscript Canvases' stamp: 'nk 12/29/2003 10:55'!\\nprintPSToFile\\n\\t\\n\\tself printPSToFileNamed: self externalName! !\\n\\n\\n!Morph methodsFor: 'player' stamp: 'tk 10/30/2001 12:13'!\\nassuredCardPlayer\\n\\t\\\"Answer the receiver's player, creating a new one if none currently exists\\\"\\n\\n\\t| aPlayer |\\n\\t(aPlayer _ self player) ifNotNil: [\\n\\t\\t(aPlayer isKindOf: CardPlayer) \\n\\t\\t\\t\\tifTrue: [^ aPlayer]\\n\\t\\t\\t\\tifFalse: [self error: 'Must convert to a CardPlayer']\\n\\t\\t\\t\\t\\t\\\"later convert using as: and remove the error\\\"].\\n\\tself assureExternalName. \\\"a default may be given if not named yet\\\"\\n\\tself player: (aPlayer _ UnscriptedCardPlayer newUserInstance).\\n\\t\\t\\\"Force it to be a CardPlayer. Morph class no longer dictates what kind of player\\\"\\n\\taPlayer costume: self.\\n\\tself presenter ifNotNil: [self presenter flushPlayerListCache].\\n\\t^ aPlayer! !\\n\\n!Morph methodsFor: 'player' stamp: 'sw 2/19/1999 09:06'!\\nassuredPlayer\\n\\t\\\"Answer the receiver's player, creating a new one if none currently exists\\\"\\n\\n\\t| aPlayer |\\n\\t(aPlayer _ self player) ifNil:\\n\\t\\t[self assureExternalName. \\\"a default may be given if not named yet\\\"\\n\\t\\tself player: (aPlayer _ self newPlayerInstance). \\n\\t\\t\\t\\\"Different morphs may demand different player types\\\"\\n\\t\\taPlayer costume: self.\\n\\t\\tself presenter ifNotNil: [self presenter flushPlayerListCache]].\\n\\t^ aPlayer! !\\n\\n!Morph methodsFor: 'player' stamp: 'sw 8/10/2000 00:06'!\\nassureExternalName\\n\\t| aName |\\n\\t^ (aName _ self knownName) ifNil:\\n\\t\\t[self setNameTo: (aName _ self externalName).\\n\\t\\t^ aName]! !\\n\\n!Morph methodsFor: 'player' stamp: 'sw 10/27/2000 17:38'!\\ncurrentDataValue\\n\\t\\\"Answer the data value associated with the receiver. Useful in conjunction with default-value setting\\\"\\n\\n\\t^ nil! !\\n\\n!Morph methodsFor: 'player' stamp: 'sw 9/15/1998 13:33'!\\nnewPlayerInstance\\n\\t^ UnscriptedPlayer newUserInstance! !\\n\\n!Morph methodsFor: 'player' stamp: 'sw 1/22/2001 14:25'!\\nokayToDuplicate\\n\\t\\\"Formerly this protocol was used to guard against awkward situations when there were anonymous scripts in the etoy system. Nowadays we just always allow duplication\\\"\\n\\n\\t^ true! !\\n\\n!Morph methodsFor: 'player' stamp: 'mir 6/13/2001 14:45'!\\nshouldRememberCostumes\\n\\t^true! !\\n\\n!Morph methodsFor: 'player' stamp: 'sw 8/11/1998 16:54'!\\nshowPlayerMenu\\n\\tself player ifNotNil:\\n\\t\\t[self player showPlayerMenu]! !\\n\\n!Morph methodsFor: 'player' stamp: 'sw 10/6/2000 07:37'!\\nvariableDocks\\n\\t\\\"Answer a list of VariableDocker objects for docking up my data with an instance held in my containing playfield. The simple presence of some objects on a Playfield will result in the maintenance of instance data on the corresponding Card. This is a generalization of the HyperCard 'field' idea. If there is already a cachedVariableDocks cached, use that. For this all to work happily, one must be certain to invalidate the #cachedVariableDocks cache when that's appropriate.\\\"\\n\\n\\t^ self valueOfProperty: #cachedVariableDocks ifAbsent: [#()]! !\\n\\n\\n!Morph methodsFor: 'player commands' stamp: 'nb 6/17/2003 12:25'!\\nbeep: soundName\\n\\n\\tself playSoundNamed: soundName\\n! !\\n\\n!Morph methodsFor: 'player commands'!\\njumpTo: aPoint\\n\\t\\\"Let my owner decide how I move.\\\"\\n\\n\\towner move: self toPosition: aPoint.\\n! !\\n\\n!Morph methodsFor: 'player commands' stamp: 'sw 2/16/1999 11:33'!\\nmakeFenceSound\\n\\tPreferences soundsEnabled ifTrue:\\n\\t\\t[self playSoundNamed: 'scratch'].\\n! !\\n\\n!Morph methodsFor: 'player commands' stamp: 'gk 2/23/2004 21:08'!\\nplaySoundNamed: soundName\\n\\t\\\"Play the sound with the given name.\\n\\tDoes nothing if this image lacks sound playing facilities.\\\"\\n\\n\\tSoundService default playSoundNamed: soundName asString! !\\n\\n!Morph methodsFor: 'player commands'!\\nset: aPointOrNumber\\n\\t\\\"Set my position.\\\"\\n\\n\\tself jumpTo: aPointOrNumber.\\n! !\\n\\n\\n!Morph methodsFor: 'button properties' stamp: 'RAA 3/8/2001 14:45'!\\nbuttonProperties\\n\\n\\t^self valueOfProperty: #universalButtonProperties! !\\n\\n!Morph methodsFor: 'button properties' stamp: 'RAA 3/8/2001 14:45'!\\nbuttonProperties: propertiesOrNil\\n\\n\\tpropertiesOrNil ifNil: [\\n\\t\\tself removeProperty: #universalButtonProperties\\n\\t] ifNotNil: [\\n\\t\\tself setProperty: #universalButtonProperties toValue: propertiesOrNil\\n\\t].! !\\n\\n!Morph methodsFor: 'button properties' stamp: 'RAA 3/8/2001 07:49'!\\nensuredButtonProperties\\n\\n\\tself hasButtonProperties ifFalse: [\\n\\t\\tself buttonProperties: (ButtonProperties new visibleMorph: self)\\n\\t].\\n\\t^self buttonProperties! !\\n\\n!Morph methodsFor: 'button properties' stamp: 'RAA 3/8/2001 07:18'!\\nhasButtonProperties\\n\\n\\t^self hasProperty: #universalButtonProperties! !\\n\\n\\n!Morph methodsFor: '*flexiblevocabularies-scripting' stamp: 'nk 9/11/2004 17:12'!\\ncategoriesForViewer\\n\\t\\\"Answer a list of symbols representing the categories to offer in the \\n\\tviewer, in order\\\"\\n\\t| dict aList |\\n\\tdict := Dictionary new.\\n\\tself unfilteredCategoriesForViewer\\n\\t\\twithIndexDo: [:cat :index | dict at: cat put: index].\\n\\tself filterViewerCategoryDictionary: dict.\\n\\taList := SortedCollection\\n\\t\\t\\t\\tsortBlock: [:a :b | (dict at: a)\\n\\t\\t\\t\\t\\t\\t< (dict at: b)].\\n\\taList addAll: dict keys.\\n\\t^ aList asArray! !\\n\\n!Morph methodsFor: '*flexiblevocabularies-scripting' stamp: 'nk 8/29/2004 17:09'!\\nselectorsForViewer\\n\\t\\\"Answer a list of symbols representing all the selectors available in all my viewer categories\\\"\\n\\n\\t| aClass aList itsAdditions added addBlock |\\n\\taClass := self renderedMorph class.\\n\\taList := OrderedCollection new.\\n\\tadded := Set new.\\n\\taddBlock := [ :sym | (added includes: sym) ifFalse: [ added add: sym. aList add: sym ]].\\n\\n\\t[aClass == Morph superclass] whileFalse: \\n\\t\\t\\t[(aClass hasAdditionsToViewerCategories) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[itsAdditions := aClass allAdditionsToViewerCategories.\\n\\t\\t\\t\\t\\titsAdditions do: [ :add | add do: [:aSpec |\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\\"the spec list\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\taSpec first == #command ifTrue: [ addBlock value: aSpec second].\\n\\t\\t\\t\\t\\t\\t\\t\\t\\taSpec first == #slot \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[ addBlock value: (aSpec seventh).\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t addBlock value: aSpec ninth]]]].\\n\\t\\t\\taClass := aClass superclass].\\n\\n\\t^aList copyWithoutAll: #(#unused #dummy)\\n\\n\\t\\\"SimpleSliderMorph basicNew selectorsForViewer\\\"! !\\n\\n!Morph methodsFor: '*flexiblevocabularies-scripting' stamp: 'nk 8/29/2004 17:14'!\\nselectorsForViewerIn: aCollection\\n\\t\\\"Answer a list of symbols representing all the selectors available in all my viewer categories, selecting only the ones in aCollection\\\"\\n\\n\\t| aClass aList itsAdditions added addBlock |\\n\\taClass := self renderedMorph class.\\n\\taList := OrderedCollection new.\\n\\tadded := Set new.\\n\\taddBlock := [ :sym |\\n\\t\\t(added includes: sym) ifFalse: [ (aCollection includes: sym)\\n\\t\\t\\tifTrue: [ added add: sym. aList add: sym ]]].\\n\\n\\t[aClass == Morph superclass] whileFalse: \\n\\t\\t\\t[(aClass hasAdditionsToViewerCategories) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[itsAdditions := aClass allAdditionsToViewerCategories.\\n\\t\\t\\t\\t\\titsAdditions do: [ :add | add do: [:aSpec |\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\\"the spec list\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\taSpec first == #command ifTrue: [ addBlock value: aSpec second].\\n\\t\\t\\t\\t\\t\\t\\t\\t\\taSpec first == #slot \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[ addBlock value: (aSpec seventh).\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t addBlock value: aSpec ninth]]]].\\n\\t\\t\\taClass := aClass superclass].\\n\\n\\t^aList copyWithoutAll: #(#unused #dummy)\\n\\n\\t\\\"SimpleSliderMorph basicNew selectorsForViewerIn: \\n\\t#(setTruncate: getColor setColor: getKnobColor setKnobColor: getWidth setWidth: getHeight setHeight: getDropEnabled setDropEnabled:)\\n\\t\\\"! !\\n\\n!Morph methodsFor: '*flexiblevocabularies-scripting' stamp: 'nk 9/4/2004 11:47'!\\nunderstandsBorderVocabulary\\n\\t\\\"Replace the 'isKindOf: BorderedMorph' so that (for instance) Connectors can have their border vocabulary visible in viewers.\\\"\\n\\t^false! !\\n\\n\\n!Morph methodsFor: 'object fileIn' stamp: 'dgd 2/22/2003 14:30'!\\nconvertAugust1998: varDict using: smartRefStrm \\n\\t\\\"These variables are automatically stored into the new instance \\n\\t('bounds' 'owner' 'submorphs' 'fullBounds' 'color' ). \\n\\tThis method is for additional changes. Use statements like (foo _ \\n\\tvarDict at: 'foo').\\\"\\n\\n\\t\\\"Be sure to to fill in ('extension' ) and deal with the information \\n\\tin ('eventHandler' 'properties' 'costumee' )\\\"\\n\\n\\t\\\"This method moves all property variables as well as \\n\\teventHandler, and costumee into a morphicExtension.\\\"\\n\\n\\t\\\"Move refs to eventhandler and costumee into extension\\\"\\n\\n\\t| propVal |\\n\\t(varDict at: 'eventHandler') isNil \\n\\t\\tifFalse: [self eventHandler: (varDict at: 'eventHandler')].\\n\\t(varDict at: 'costumee') isNil \\n\\t\\tifFalse: [self player: (varDict at: 'costumee')].\\n\\t(varDict at: 'properties') isNil \\n\\t\\tifFalse: \\n\\t\\t\\t[(varDict at: 'properties') keys do: \\n\\t\\t\\t\\t\\t[:key | \\n\\t\\t\\t\\t\\t\\\"Move property extensions into extension\\\"\\n\\n\\t\\t\\t\\t\\tpropVal := (varDict at: 'properties') at: key.\\n\\t\\t\\t\\t\\tpropVal ifNotNil: \\n\\t\\t\\t\\t\\t\\t\\t[key == #possessive \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [propVal == true ifTrue: [self bePossessive]]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[key ifNotNil: [self assureExtension convertProperty: key toValue: propVal]]]]]! !\\n\\n!Morph methodsFor: 'object fileIn' stamp: 'md 2/27/2006 09:56'!\\nconvertNovember2000DropShadow: varDict using: smartRefStrm \\n\\t\\\"Work hard to eliminate the DropShadow. Inst vars are already \\n\\tstored into.\\\"\\n\\n\\t| rend |\\n\\tsubmorphs notEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[rend := submorphs first renderedMorph.\\n\\t\\t\\t\\\"a text?\\\"\\n\\t\\t\\trend setProperty: #hasDropShadow toValue: true.\\n\\t\\t\\trend setProperty: #shadowColor toValue: (varDict at: 'color').\\n\\t\\t\\trend setProperty: #shadowOffset toValue: (varDict at: 'shadowOffset').\\n\\t\\t\\t\\\"ds owner ifNotNil: [ds owner addAllMorphs: ds \\n\\t\\t\\tsubmorphs]. ^rend does this\\\"\\n\\t\\t\\trend privateOwner: owner.\\n\\t\\t\\textension ifNotNil: [\\n\\t\\t\\t\\textension actorState ifNotNil: [rend actorState: self extension actorState].\\n\\t\\t\\t\\textension externalName ifNotNil: [rend setNameTo: self extension externalName].\\n\\t\\t\\t\\textension player ifNotNil: [\\n\\t\\t\\t\\t\\t\\t\\trend player: extension player.\\n\\t\\t\\t\\t\\t\\t\\textension player rawCostume: rend]].\\n\\t\\t\\t^rend].\\n\\t(rend := Morph new) color: Color transparent.\\n\\t^rend! !\\n\\n\\n!Morph methodsFor: 'system primitives' stamp: 'sw 10/27/2000 17:37'!\\ncreationStamp\\n\\t\\\"Answer the creation stamp stored within the receiver, if any\\\"\\n\\n\\t^ self valueOfProperty: #creationStamp ifAbsent: [super creationStamp]! !\\n\\n\\n!Morph methodsFor: 'button' stamp: 'sw 2/6/2001 23:09'!\\ndoButtonAction\\n\\t\\\"If the receiver has a button-action defined, do it now. The default button action of any morph is, well, to do nothing. Note that there are several ways -- too many ways -- for morphs to have button-like actions. This one refers not to the #mouseUpCodeToRun feature, nor does it refer to the Player-scripting mechanism. Instead it is intended for morph classes whose very nature is to be buttons -- this method provides glue so that arbitrary buttons on the UI can be 'fired' programatticaly from user scripts\\\"! !\\n\\n!Morph methodsFor: 'button' stamp: 'sw 2/6/2001 23:22'!\\nfire\\n\\t\\\"If the receiver has any kind of button-action defined, fire that action now. Any morph can have special, personal mouseUpCodeToRun, and that will be triggered by this. Additionally, some morphs have specific buttonness, and these get sent the #doButtonAction message to carry out their firing. Finally, some morphs have mouse behaviors associated with one or more Player scripts.\\n\\tFor the present, we'll try out doing *all* the firings this object can do. \\\"\\n\\n\\tself firedMouseUpCode. \\t\\\"This will run the mouseUpCodeToRun, if any\\\"\\n\\n\\tself player ifNotNil:\\t\\t\\n\\t\\t[self player fireOnce]. \\\"Run mouseDown and mouseUp scripts\\\"\\n\\n\\tself doButtonAction\\t\\t\\t\\\"Do my native button action, if any\\\"! !\\n\\n!Morph methodsFor: 'button' stamp: 'dgd 2/22/2003 14:31'!\\nfiredMouseUpCode\\n\\t\\\"If the user has special mouseUpCodeToRun, then fire it once right now and return true, else return false\\\"\\n\\n\\t| evt |\\n\\t(self world isNil or: [self mouseUpCodeOrNil isNil]) ifTrue: [^false].\\n\\tevt := MouseEvent new \\n\\t\\t\\t\\tsetType: nil\\n\\t\\t\\t\\tposition: self center\\n\\t\\t\\t\\tbuttons: 0\\n\\t\\t\\t\\thand: self world activeHand.\\n\\tself programmedMouseUp: evt for: self.\\n\\t^true! !\\n\\n\\n!Morph methodsFor: 'event handling-override' stamp: 'nk 3/10/2004 19:47'!\\nhandlerForMouseDown: anEvent \\n\\t\\\"Return the (prospective) handler for a mouse down event. The handler is temporarily \\n\\tinstalled and can be used for morphs further down the hierarchy to negotiate whether \\n\\tthe inner or the outer morph should finally handle the event.\\\"\\n\\n\\tanEvent blueButtonPressed\\n\\t\\tifTrue: [^ self handlerForBlueButtonDown: anEvent].\\n\\tanEvent yellowButtonPressed\\n\\t\\tifTrue: [^ self handlerForYellowButtonDown: anEvent].\\n\\tanEvent controlKeyPressed\\n\\t\\tifTrue: [^ self handlerForMetaMenu: anEvent].\\n\\t(self handlesMouseDown: anEvent)\\n\\t\\tifFalse: [^ nil].\\t\\\"not interested\\\"\\n\\n\\tanEvent handler\\n\\t\\tifNil: [^ self ].\\t\\\"Same priority but I am innermost\\\"\\n\\n\\t\\\"Nobody else was interested\\\"\\n\\t^self mouseDownPriority >= anEvent handler mouseDownPriority\\n\\t\\tifTrue: [ self]\\n\\t\\tifFalse: [ nil]! !\\n\\n\\n!Morph methodsFor: 'texture support' stamp: 'dgd 2/16/2003 20:02'!\\nisValidWonderlandTexture\\n\\t\\\"Return true if the receiver is a valid wonderland texture\\\"\\n\\t^ self\\n\\t\\tvalueOfProperty: #isValidWonderlandTexture\\n\\t\\tifAbsent: [true]! !\\n\\n\\n!Morph methodsFor: 'model access' stamp: 'nk 3/10/2004 19:51'!\\nmodels\\n\\t\\\"Answer a collection of whatever models I may have.\\\"\\n\\n\\tself modelOrNil ifNil: [ ^EmptyArray ].\\n\\t^Array with: self modelOrNil! !\\n\\n\\n!Morph methodsFor: 'player viewer' stamp: 'wiz 1/1/2006 12:58'!\\nopenViewerForArgument\\n\\t\\\"Open up a viewer for a player associated with the morph in question. \\\"\\n\\tself presenter viewMorph: self! !\\n\\n!Morph methodsFor: 'player viewer' stamp: 'sw 3/13/98 17:40'!\\nupdateLiteralLabel\\n\\t\\\"Backstop -- updatingStringMorphs inform their owners with this message when they've changed; some Morphs care, others don't\\\"! !\\n\\n\\n!Morph methodsFor: 'other' stamp: 'sw 10/30/2001 13:12'!\\nremoveAllButFirstSubmorph\\n\\t\\\"Remove all of the receiver's submorphs other than the first one.\\\"\\n\\n\\tself submorphs allButFirst do: [:m | m delete]! !\\n\\n\\n!Morph methodsFor: 'selected object' stamp: 'dgd 8/28/2004 16:30'!\\nselectedObject\\n\\t\\\"answer the selected object for the hand or nil is none\\\"\\n\\t^ self primaryHand selectedObject! !\\n\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!Morph class methodsFor: 'class initialization' stamp: 'hg 8/3/2000 16:43'!\\ninitialize\\n\\t\\\"Morph initialize\\\"\\n\\n\\t\\\"this empty array object is shared by all morphs with no submorphs:\\\"\\n\\tEmptyArray _ Array new.\\n\\tFileList registerFileReader: self! !\\n\\n\\n!Morph class methodsFor: 'connectors-scripting' stamp: 'nk 9/10/2004 11:34'!\\nadditionsToViewerCategoryConnection\\n\\t\\\"Answer viewer additions for the 'connection' category\\\"\\n\\t\\\"Vocabulary initialize\\\"\\n\\n\\t^{\\n\\t\\t#'connections to me'.\\n\\t\\t#(\\n\\t\\t(command tellAllPredecessors: 'Send a message to all graph predecessors' ScriptName)\\n\\t\\t(command tellAllSuccessors: 'Send a message to all graph predecessors' ScriptName)\\n\\t\\t(command tellAllIncomingConnections: 'Send a message to all the connectors whose destination end is connected to me' ScriptName)\\n\\t\\t(command tellAllOutgoingConnections: 'Send a message to all the connectors whose source end is connected to me' ScriptName)\\n\\t\\t(slot incomingConnectionCount 'The number of connectors whose destination end is connected to me' Number readOnly Player getIncomingConnectionCount unused unused)\\n\\t\\t(slot outgoingConnectionCount 'The number of connectors whose source end is connected to me' Number readOnly Player getOutgoingConnectionCount unused unused)\\n\\t\\t)\\n\\t}\\n! !\\n\\n\\n!Morph class methodsFor: 'fileIn/Out' stamp: 'nk 7/16/2003 15:54'!\\nfileReaderServicesForFile: fullName suffix: suffix\\n\\n\\t^({ 'morph'. 'morphs'. 'sp'. '*' } includes: suffix)\\n\\t\\tifTrue: [\\n\\t\\t\\t{SimpleServiceEntry \\n\\t\\t\\t\\tprovider: self \\n\\t\\t\\t\\tlabel: 'load as morph'\\n\\t\\t\\t\\tselector: #fromFileName:\\n\\t\\t\\t\\tdescription: 'load as morph'}]\\n\\t\\tifFalse: [#()]! !\\n\\n!Morph class methodsFor: 'fileIn/Out' stamp: 'yo 8/7/2003 11:02'!\\nfromFileName: fullName\\n\\t\\\"Reconstitute a Morph from the file, presumed to be represent a Morph saved\\n\\tvia the SmartRefStream mechanism, and open it in an appropriate Morphic world\\\"\\n\\n \\t| aFileStream morphOrList |\\n\\taFileStream _ (MultiByteBinaryOrTextStream with: ((FileStream readOnlyFileNamed: fullName) binary contentsOfEntireFile)) binary reset.\\n\\tmorphOrList _ aFileStream fileInObjectAndCode.\\n\\t(morphOrList isKindOf: SqueakPage) ifTrue: [morphOrList _ morphOrList contentsMorph].\\n\\tSmalltalk isMorphic\\n\\t\\tifTrue: [ActiveWorld addMorphsAndModel: morphOrList]\\n\\t\\tifFalse:\\n\\t\\t\\t[morphOrList isMorph ifFalse: [self inform: 'Can only load a single morph\\ninto an mvc project via this mechanism.'].\\n\\t\\t\\tmorphOrList openInWorld]! !\\n\\n!Morph class methodsFor: 'fileIn/Out' stamp: 'sw 2/17/2002 02:43'!\\nserviceLoadMorphFromFile\\n\\t\\\"Answer a service for loading a .morph file\\\"\\n\\n\\t^ SimpleServiceEntry \\n\\t\\tprovider: self \\n\\t\\tlabel: 'load as morph'\\n\\t\\tselector: #fromFileName:\\n\\t\\tdescription: 'load as morph'\\n\\t\\tbuttonLabel: 'load'! !\\n\\n!Morph class methodsFor: 'fileIn/Out' stamp: 'sd 2/1/2002 21:45'!\\nservices\\n\\n\\t^ Array with: self serviceLoadMorphFromFile! !\\n\\n\\n!Morph class methodsFor: 'initialize-release' stamp: 'SD 11/15/2001 22:22'!\\nunload\\n\\n\\tFileList unregisterFileReader: self ! !\\n\\n\\n!Morph class methodsFor: 'instance creation' stamp: 'efo 5/3/2002 14:59'!\\ninitializedInstance\\n\\t\\\"Answer an instance of the receiver which in some sense is initialized. In the case of Morphs, this will yield an instance that can be attached to the Hand after having received the same kind of basic initialization that would be obtained from an instance chosen from the 'new morph' menu.\\n\\tReturn nil if the receiver is reluctant for some reason to return such a thing\\\"\\n\\n\\t^ (self class includesSelector: #descriptionForPartsBin)\\n\\t\\tifTrue:\\n\\t\\t\\t[self newStandAlone]\\n\\t\\tifFalse:\\n\\t\\t\\t[self new]! !\\n\\n!Morph class methodsFor: 'instance creation'!\\nnewBounds: bounds\\n\\n\\t^ self new privateBounds: bounds! !\\n\\n!Morph class methodsFor: 'instance creation' stamp: 'jm 5/29/1998 21:28'!\\nnewBounds: bounds color: color\\n\\n\\t^ (self new privateBounds: bounds) privateColor: color\\n! !\\n\\n!Morph class methodsFor: 'instance creation' stamp: 'sw 8/4/97 12:05'!\\nnewSticky\\n\\n\\t^ self new beSticky! !\\n\\n\\n!Morph class methodsFor: 'misc' stamp: 'sw 8/4/1998 16:51'!\\nmorphsUnknownToTheirOwners\\n\\t\\\"Return a list of all morphs (other than HandMorphs) whose owners do not contain them in their submorph lists\\\"\\n\\t\\\"Morph morphsUnknownToTheirOwners\\\"\\n\\t| problemMorphs itsOwner |\\n\\tproblemMorphs _ OrderedCollection new.\\n\\tself allSubInstances do:\\n\\t\\t[:m | (m isHandMorph not and: [((itsOwner _ m owner) ~~ nil and: [(itsOwner submorphs includes: m) not])])\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[problemMorphs add: m]].\\n\\t^ problemMorphs! !\\n\\n\\n!Morph class methodsFor: 'new-morph participation' stamp: 'di 6/22/97 09:07'!\\nincludeInNewMorphMenu\\n\\t\\\"Return true for all classes that can be instantiated from the menu\\\"\\n\\t^ true! !\\n\\n!Morph class methodsFor: 'new-morph participation' stamp: 'sw 6/28/2001 11:33'!\\nnewStandAlone\\n\\t\\\"Answer an instance capable of standing by itself as a usable morph.\\\"\\n\\n\\t^ self basicNew initializeToStandAlone! !\\n\\n!Morph class methodsFor: 'new-morph participation' stamp: 'sw 8/2/2001 12:01'!\\npartName: aName categories: aList documentation: aDoc\\n\\t\\\"Answer a DescriptionForPartsBin which will represent a launch of a new instance of my class via the #newStandAlone protocol sent to my class. Use the category-list and documentation provided\\\"\\n\\n\\n\\t^ DescriptionForPartsBin new\\n\\t\\tformalName: aName\\n\\t\\tcategoryList: aList\\n\\t\\tdocumentation: aDoc\\n\\t\\tglobalReceiverSymbol: self name\\n\\t\\tnativitySelector: #newStandAlone! !\\n\\n\\n!Morph class methodsFor: 'scripting' stamp: 'sw 7/20/2005 01:20'!\\nadditionsToViewerCategoryColorAndBorder\\n\\t\\\"Answer viewer additions for the 'color & border' category\\\"\\n\\n\\t^#(\\n\\t\\t#'color & border' \\n\\t\\t(\\n\\t\\t\\t(slot color 'The color of the object' Color readWrite Player getColor Player setColor:)\\n\\t\\t\\t(slot opacity '0 means completely transparent, 1 means completely opaque' Number readWrite Player getAlpha Player setAlpha:)\\n\\t\\t\\t(slot borderStyle 'The style of the object''s border' BorderStyle readWrite Player getBorderStyle player setBorderStyle:)\\n\\t\\t\\t(slot borderColor 'The color of the object''s border' Color readWrite Player getBorderColor Player setBorderColor:)\\n\\t\\t\\t(slot borderWidth 'The width of the object''s border' Number readWrite Player getBorderWidth Player setBorderWidth:)\\n\\t\\t\\t(slot roundedCorners 'Whether corners should be rounded' Boolean readWrite Player getRoundedCorners Player setRoundedCorners:)\\n\\n\\t\\t\\t(slot gradientFill 'Whether a gradient fill should be used' Boolean readWrite Player getUseGradientFill Player setUseGradientFill:)\\n\\t\\t\\t(slot secondColor 'The second color used when gradientFill is in effect' Color readWrite Player getSecondColor Player setSecondColor:)\\n\\n\\t\\t\\t(slot radialFill 'Whether the gradient fill, if used, should be radial' Boolean readWrite Player getRadialGradientFill Player setRadialGradientFill:)\\n\\n\\t\\t\\t(slot dropShadow 'Whether a drop shadow is shown' Boolean readWrite Player getDropShadow Player setDropShadow:)\\n\\t\\t\\t(slot shadowColor 'The color of the drop shadow' Color readWrite Player getShadowColor Player setShadowColor:)\\n\\t\\t)\\n\\t)\\n\\n! !\\n\\n!Morph class methodsFor: 'scripting' stamp: 'sw 8/11/97 13:17'!\\nauthoringPrototype\\n\\t\\\"Answer an instance of the receiver suitable for placing in a parts bin for authors\\\"\\n\\t\\n\\t^ self new markAsPartsDonor! !\\n\\n!Morph class methodsFor: 'scripting' stamp: 'bf 9/11/2004 17:18'!\\nhasAdditionsToViewerCategories\\n\\t^ self class selectors\\n\\t\\tanySatisfy: [:each | each == #additionsToViewerCategories\\n\\t\\t\\t\\tor: [(each beginsWith: 'additionsToViewerCategory')\\n\\t\\t\\t\\t\\t\\tand: [(each at: 26 ifAbsent: []) ~= $:]]]! !\\n\\n!Morph class methodsFor: 'scripting' stamp: 'yo 3/15/2005 14:10'!\\nhelpContributions\\n\\t\\\"Answer a list of pairs of the form (<symbol> <help message> ) to contribute to the system help dictionary\\\"\\n\\t\\n\\\"NB: Many of the items here are not needed any more since they're specified as part of command definitions now. Someone needs to take the time to go through the list and remove items no longer needed. But who's got that kind of time?\\\"\\n\\n\\t^ #(\\n\\t\\t(acceptScript:for:\\n\\t\\t\\t'submit the contents of the given script editor as the code defining the given selector')\\n\\t\\t(actorState\\n\\t\\t\\t'return the ActorState object for the receiver, creating it if necessary')\\n\\t\\t(addInstanceVariable\\n\\t\\t\\t'start the interaction for adding a new variable to the object')\\n\\t\\t(addPlayerMenuItemsTo:hand:\\n\\t\\t\\t'add player-specific menu items to the given menu, on behalf of the given hand. At present, these are only commands relating to the turtle')\\n\\t\\t(addYesNoToHand\\n\\t\\t\\t'Press here to tear off a TEST/YES/NO unit which you can drop into your script')\\n\\t\\t(allScriptEditors\\n\\t\\t\\t'answer a list off the extant ScriptEditors for the receiver')\\n\\t\\t(amount\\n\\t\\t\\t'The amount of displacement')\\n\\t\\t(angle\\t\\n\\t\\t\\t'The angular displacement')\\n\\t\\t(anonymousScriptEditorFor:\\n\\t\\t\\t'answer a new ScriptEditor object to serve as the place for scripting an anonymous (unnamed, unsaved) script for the receiver')\\n\\t\\t(append:\\n\\t\\t\\t'add an object to this container')\\n\\t\\t(prepend:\\n\\t\\t\\t'add an object to this container')\\n\\t\\t(assignDecrGetter:setter:amt:\\n\\t\\t\\t'evaluate the decrement variant of assignment')\\n\\t\\t(assignGetter:setter:amt:\\n\\t\\t\\t'evaluate the vanilla variant of assignment')\\n\\t\\t(assignIncrGetter:setter:amt:\\n\\t\\t\\t'evalute the increment version of assignment')\\n\\t\\t(assignMultGetter:setter:amt:\\n\\t\\t\\t'evaluate the multiplicative version of assignment')\\n\\t\\t(assureEventHandlerRepresentsStatus\\n\\t\\t\\t'make certain that the event handler associated with my current costume is set up to conform to my current script-status')\\n\\t\\t(assureExternalName\\n\\t\\t\\t'If I do not currently have an external name assigned, get one now')\\n\\t\\t(assureUniClass\\n\\t\\t\\t'make certain that I am a member a uniclass (i.e. a unique subclass); if I am not, create one now and become me into an instance of it')\\n\\t\\t(availableCostumeNames\\n\\t\\t\\t'answer a list of strings representing the names of all costumes currently available for me')\\n\\t\\t(availableCostumesForArrows\\n\\t\\t\\t'answer a list of actual, instantiated costumes for me, which can be cycled through as the user hits a next-costume or previous-costume button in a viewer')\\n\\t\\t(beep:\\n\\t\\t\\t'make the specified sound')\\n\\t\\t(borderColor\\n\\t\\t\\t'The color of the object''s border')\\n\\t\\t(borderWidth\\n\\t\\t\\t'The width of the object''s border')\\n\\t\\t(bottom\\n\\t\\t\\t'My bottom edge, measured downward from the top edge of the world')\\n\\t\\t(bounce:\\n\\t\\t\\t'If object strayed beyond the boundaries of its container, make it reflect back into it, making the specified noise while doing so.')\\n\\t\\t(bounce\\n\\t\\t\\t'If object strayed beyond the boundaries of its container, make it reflect back into it')\\n\\t\\t(chooseTrigger\\n'When this script should run.\\n\\\"normal\\\" means \\\"only when called\\\"')\\n\\t\\t(clearTurtleTrails\\n\\t\\t\\t'Clear all the pen trails in the interior.')\\n\\t\\t(clearOwnersPenTrails\\n\\t\\t\\t'Clear all the pen trails in my container.')\\n\\t\\t(color\\t\\n\\t\\t\\t'The object''s interior color')\\n\\t\\t(colorSees\\n\\t\\t\\t'Whether a given color in the object is over another given color')\\n\\t\\t(colorUnder\\n\\t\\t\\t'The color under the center of the object')\\n\\t\\t(copy\\n\\t\\t\\t'Return a new object that is very much like this one')\\n\\t\\t(cursor\\t\\n\\t\\t\\t'The index of the chosen element')\\n\\t\\t(deleteCard\\n\\t\\t\\t'Delete the current card.')\\n\\t\\t(dismiss\\n\\t\\t\\t'Click here to dismiss me')\\n\\t\\t(doMenuItem:\\n\\t\\t\\t'Do a menu item, the same way as if it were chosen manually')\\n\\t\\t(doScript:\\n\\t\\t\\t'Perform the given script once, on the next tick.')\\n\\t\\t(elementNumber\\n\\t\\t\\t'My element number as seen by my owner')\\n\\t\\t(fire\\n\\t\\t\\t'Run any and all button-firing scripts of this object')\\n\\t\\t(firstPage\\n\\t\\t\\t'Go to first page of book')\\n\\t\\t(followPath\\n\\t\\t\\t\\t'Retrace the path the object has memorized, if any.')\\n\\t\\t(forward:\\n\\t\\t\\t'Moves the object forward in the direction it is heading') \\n\\t\\t(goto:\\n\\t\\t\\t'Go to the specfied book page')\\n\\t\\t(goToNextCardInStack\\n\\t\\t\\t'Go to the next card')\\n\\t\\t(goToPreviousCardInStack\\n\\t\\t\\t'Go to the previous card.')\\n\\t\\t(goToRightOf:\\n\\t\\t\\t'Align the object just to the right of any specified object.')\\n\\t\\t(heading\\n\\t\\t\\t'Which direction the object is facing. 0 is straight up') \\n\\t\\t(height\\t\\n\\t\\t\\t'The distance between the top and bottom edges of the object')\\n\\t\\t(hide\\n\\t\\t\\t'Make the object so that it does not display and cannot handle input')\\n\\t\\t(initiatePainting\\t\\n\\t\\t\\t'Initiate painting of a new object in the standard playfield.')\\n\\t\\t(initiatePaintingIn:\\n\\t\\t\\t'Initiate painting of a new object in the given place.')\\n\\t\\t(isOverColor\\n\\t\\t\\t'Whether any part of this object is directly over the specified color')\\n\\t\\t(isUnderMouse\\n\\t\\t\\t'Whether any part of this object is beneath the current mouse-cursor position')\\n\\t\\t(lastPage\\n\\t\\t\\t'Go to the last page of the book.')\\n\\t\\t(left\\n\\t\\t\\t'My left edge, measured from the left edge of the World')\\n\\t\\t(leftRight\\n\\t\\t\\t'The horizontal displacement')\\n\\t\\t(liftAllPens\\n\\t\\t\\t'Lift the pens on all the objects in my interior.')\\n\\t\\t(lowerAllPens\\n\\t\\t\\t'Lower the pens on all the objects in my interior.')\\n\\t\\t(mouseX\\n\\t\\t\\t'The x coordinate of the mouse pointer')\\n\\t\\t(mouseY\\n\\t\\t\\t'The y coordinate of the mouse pointer')\\n\\t\\t(moveToward:\\n\\t\\t\\t'Move in the direction of another object.')\\n\\t\\t(insertCard\\n\\t\\t\\t'Create a new card.')\\n\\t\\t(nextPage\\n\\t\\t\\t'Go to next page.')\\n\\t\\t(numberAtCursor\\n\\t\\t\\t'The number held by the object at the chosen element')\\n\\t\\t(objectNameInHalo\\n\\t\\t\\t'Object''s name -- To change: click here, edit, hit ENTER')\\n\\t\\t(obtrudes\\n\\t\\t\\t'Whether any part of the object sticks out beyond its container''s borders')\\n\\t\\t(offerScriptorMenu\\n\\t\\t\\t'The Scriptee.\\nPress here to get a menu')\\n\\t\\t(pauseScript:\\n\\t\\t\\t'Make a running script become paused.')\\n\\t\\t(penDown\\n\\t\\t\\t'Whether the object''s pen is down (true) or up (false)')\\n\\t\\t(penColor\\n\\t\\t\\t'The color of the object''s pen')\\n\\t\\t(penSize\\t\\n\\t\\t\\t'The size of the object''s pen')\\n\\t\\t(clearPenTrails\\n\\t\\t\\t'Clear all pen trails in the current playfield')\\n\\t\\t(playerSeeingColorPhrase\\n\\t\\t\\t'The player who \\\"sees\\\" a given color')\\n\\t\\t(previousPage\\n\\t\\t\\t'Go to previous page')\\n\\n\\t\\t(show\\n\\t\\t\\t'If object was hidden, make it show itself again.')\\n\\t\\t(startScript:\\n\\t\\t\\t'Make a script start running.')\\n\\t\\t(stopScript:\\n\\t\\t\\t'Make a script stop running.')\\n\\t\\t(top\\n\\t\\t\\t'My top edge, measured downward from the top edge of the world')\\n\\t\\t(right\\n\\t\\t\\t'My right edge, measured from the left edge of the world')\\n\\t\\t(roundUpStrays\\n\\t\\t\\t'Bring all out-of-container subparts back into view.')\\n\\t\\t(scaleFactor\\n\\t\\t\\t'The amount by which the object is scaled')\\n\\t\\t(stopScript:\\n\\t\\t\\t'make the specified script stop running')\\n\\t\\t(tellAllSiblings:\\n\\t\\t\\t'send a message to all of my sibling instances')\\n\\t\\t(try\\n\\t\\t\\t'Run this command once.')\\n\\t\\t(tryMe\\n\\t\\t\\t'Click here to run this script once; hold button down to run repeatedly')\\n\\t\\t(turn:\\t\\t\\t\\t\\n\\t\\t\\t'Change the heading of the object by the specified amount')\\n\\t\\t(unhideHiddenObjects\\n\\t\\t\\t'Unhide all hidden objects.')\\n\\t\\t(upDown\\n\\t\\t\\t'The vertical displacement')\\n\\t\\t(userScript\\n\\t\\t\\t'This is a script defined by you.')\\n\\t\\t(userSlot\\n\\t\\t\\t'This is a variable defined by you. Click here to change its type')\\n\\t\\t(valueAtCursor\\n\\t\\t\\t'The chosen element')\\n\\t\\t(wearCostumeOf:\\n\\t\\t\\t'Wear the same kind of costume as the other object')\\n\\t\\t(width\\t\\n\\t\\t\\t'The distance between the left and right edges of the object')\\n\\t\\t(wrap\\n\\t\\t\\t'If object has strayed beond the boundaries of its container, make it reappear from the opposite edge.')\\n\\t\\t(x\\n\\t\\t\\t'The x coordinate, measured from the left of the container')\\n\\t\\t(y\\n\\t\\t\\t'The y-coordinate, measured upward from the bottom of the container')\\n\\n\\t\\t)\\n! !\\n\\n\\n!Morph class methodsFor: 'testing' stamp: 'nk 6/12/2004 09:20'!\\nallSketchMorphClasses\\n\\t\\\"Morph allSketchMorphClasses\\\"\\n\\t^ Array\\n\\t\\tstreamContents: [:s | self\\n\\t\\t\\t\\twithAllSubclassesDo: [:cls | cls isSketchMorphClass\\n\\t\\t\\t\\t\\t\\tifTrue: [s nextPut: cls ]]]\\n! !\\n\\n!Morph class methodsFor: 'testing' stamp: 'yo 3/17/2005 09:07'!\\nallSketchMorphForms\\n\\t\\\"Answer a Set of forms of SketchMorph (sub) instances, except those \\n\\tused as button images, ones being edited, and those with 0 extent.\\\"\\n\\n\\t| reasonableForms form |\\n\\treasonableForms := Set new.\\n\\tMorph allSketchMorphClasses do:\\n\\t\\t[:cls | cls allInstances do:\\n\\t\\t\\t[:m | (m owner isKindOf: SketchEditorMorph orOf: IconicButton)\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[form _ m form.\\n\\t\\t\\t\\t\\t((form width > 0) and: [form height > 0]) ifTrue: [reasonableForms add: form]]]].\\n\\t^ reasonableForms! !\\n\\n!Morph class methodsFor: 'testing' stamp: 'nk 6/12/2004 09:17'!\\nisSketchMorphClass\\n\\t^false! !\\n\\n\\n!Morph class methodsFor: '*eToys-customevents-user events' stamp: 'sw 6/16/2005 01:26'!\\nadditionsToViewerCategoryUserEvents\\n\\t\\\"Answer further viewer additions relating to user-defined events; these appear in the 'scripting' category\\\"\\n\\n\\t^ Preferences allowEtoyUserCustomEvents\\n\\t\\tifTrue: [ #(scripting (\\n\\t\\t\\t(command triggerCustomEvent: 'trigger a user-defined (global) event' CustomEvents)\\n\\t\\t\\t(slot triggeringObject 'the object that is triggering an event, either user-defined or pre-defined' Player readOnly Player getTriggeringObject unused unused)))]\\n\\t\\tifFalse: [#(scripting ())]! !\\n\\n\\n!Morph class methodsFor: '*eToys-new-morph participation' stamp: 'sw 10/24/2001 15:51'!\\npartName: aName categories: aList documentation: aDoc sampleImageForm: aForm\\n\\t\\\"Answer a DescriptionForPartsBin which will represent a launch of a new instance of my class via the #newStandAlone protocol sent to my class. Use the category-list and documentation provided. This variant allows an overriding image form to be provided, useful in cases where we don't want to launch a sample instance just to get the form\\\"\\n\\n\\n\\t| descr |\\n\\tdescr _ DescriptionForPartsBin new\\n\\t\\tformalName: aName\\n\\t\\tcategoryList: aList\\n\\t\\tdocumentation: aDoc\\n\\t\\tglobalReceiverSymbol: self name\\n\\t\\tnativitySelector: #newStandAlone.\\n\\tdescr sampleImageForm: aForm.\\n\\t^ descr\\n! !\\n\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'sw 9/27/2001 17:40'!\\nadditionsToViewerCategoryBasic\\n\\t\\\"Answer viewer additions for the 'basic' category\\\"\\n\\n\\t^#(\\n\\t\\tbasic \\n\\t\\t(\\n\\t\\t\\t(slot x 'The x coordinate' Number readWrite Player getX Player setX:)\\n\\t\\t\\t(slot y \\t'The y coordinate' Number readWrite Player \\tgetY Player setY:)\\n\\t\\t\\t(slot heading 'Which direction the object is facing. 0 is straight up' Number readWrite Player getHeading Player setHeading:)\\n\\t\\t\\t(command forward: 'Moves the object forward in the direction it is heading' Number)\\n\\t\\t\\t(command turn: 'Change the heading of the object by the specified amount' Number)\\n\\t\\t\\t(command beep: 'Make the specified sound' Sound)\\n\\t\\t)\\n\\t)\\n! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'sw 4/20/2002 00:47'!\\nadditionsToViewerCategoryDragAndDrop\\n\\t\\\"Answer viewer additions for the 'drag & drop' category\\\"\\n\\n\\t^#(\\n\\t\\t#'drag & drop'\\n \\n\\t\\t(\\n\\t\\t\\t(slot 'drop enabled' 'Whether drop is enabled' Boolean readWrite Player getDropEnabled Player setDropEnabled:)\\n\\t\\t\\t(slot 'resist being picked up' 'Whether a simple mouse-drag on this object should allow it to be picked up' Boolean readWrite Player getSticky Player setSticky:)\\n\\t\\t\\t(slot 'resist deletion' 'Whether this is resistant to easy removal via the pink X halo handle.' Boolean readWrite Player getResistsRemoval Player setResistsRemoval:)\\n\\t\\t\\t(slot 'be locked' 'Whether this object should be blind to all input' Boolean readWrite Player getIsLocked Player setIsLocked:)\\n\\t\\t\\n\\t\\t))! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'sw 9/17/2002 13:58'!\\nadditionsToViewerCategoryGeometry\\n\\t\\\"answer additions to the geometry viewer category\\\"\\n\\n\\t^ #(geometry \\n\\t\\t(\\n\\t\\t\\t(slot x 'The x coordinate' Number readWrite Player getX Player setX:)\\n\\t\\t\\t(slot y 'The y coordinate' Number readWrite Player getY Player setY:)\\n\\t\\t\\t(slot heading 'Which direction the object is facing. 0 is straight up' Number readWrite Player getHeading Player setHeading:)\\n\\n\\t\\t\\t(slot scaleFactor 'The factor by which the object is magnified' Number readWrite Player getScaleFactor Player setScaleFactor:)\\n\\t\\t\\t(slot left 'The left edge' Number readWrite Player getLeft Player setLeft:)\\n\\t\\t\\t(slot right 'The right edge' Number readWrite Player getRight Player setRight:)\\n\\t\\t\\t(slot top 'The top edge' Number readWrite Player getTop Player setTop:) \\n\\t\\t\\t(slot bottom 'The bottom edge' Number readWrite Player getBottom Player setBottom:) \\n\\t\\t\\t(slot length 'The length' Number readWrite Player getLength Player setLength:) \\n\\t\\t\\t(slot width 'The width' Number readWrite Player getWidth Player setWidth:)\\n\\n\\t\\t\\t(slot headingTheta 'The angle, in degrees, that my heading vector makes with the positive x-axis' Number readWrite Player getHeadingTheta Player setHeadingTheta:)\\n\\n\\t\\t\\t(slot distance 'The length of the vector connecting the origin to the object''s position' Number readWrite Player getDistance Player setDistance:)\\n\\t\\t\\t(slot theta 'The angle between the positive x-axis and the vector connecting the origin to the object''s position' Number readWrite Player getTheta Player setTheta: )\\n\\t\\t)\\n\\t)\\n\\n\\n! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'sw 11/16/2001 10:21'!\\nadditionsToViewerCategoryLayout\\n\\t\\\"Answer viewer additions for the 'layout' category\\\"\\n\\n\\t^#(\\n\\t\\tlayout \\n\\t\\t(\\n\\t\\t\\t(slot clipSubmorphs 'Whether or not to clip my submorphs' Boolean readWrite Player getClipSubmorphs Player setClipSubmorphs:)\\n\\n\\t\\t))\\n! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'sw 7/8/2004 00:20'!\\nadditionsToViewerCategoryMiscellaneous\\n\\t\\\"Answer viewer additions for the 'miscellaneous' category\\\"\\n\\n\\t^#(\\n\\t\\tmiscellaneous \\n\\t\\t(\\n\\t\\t\\t(command doMenuItem: 'do the menu item' Menu)\\n\\t\\t\\t(command show 'make the object visible')\\n\\t\\t\\t(command hide 'make the object invisible')\\n\\t\\t\\t(command wearCostumeOf: 'wear the costume of...' Player)\\n\\n\\t\\t\\t(command fire 'trigger any and all of this object''s button actions')\\n\\t\\t\\t(slot copy 'returns a copy of this object' Player readOnly Player getNewClone\\t unused unused)\\n\\t\\t\\t(slot elementNumber 'my index in my container' Number readWrite Player getIndexInOwner Player setIndexInOwner:)\\n\\t\\t\\t(slot holder 'the object''s container' Player readOnly Player getHolder Player setHolder:)\\n\\t\\t\\t(command stamp 'add my image to the pen trails')\\n\\t\\t\\t(command erase 'remove this object from the screen')\\n\\t\\t\\t(command stampAndErase 'add my image to the pen trails and go away')\\n\\t\\t)\\n\\t)\\n\\n! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'dgd 8/8/2003 22:17'!\\nadditionsToViewerCategoryMotion\\n\\t\\\"Answer viewer additions for the 'motion' category\\\"\\n\\n\\t^#(\\n\\t\\tmotion \\n\\t\\t(\\n\\t\\t\\t(slot x 'The x coordinate' Number readWrite Player getX Player setX:)\\n\\t\\t\\t(slot y \\t'The y coordinate' Number readWrite Player \\tgetY Player setY:)\\n\\t\\t\\t(slot heading 'Which direction the object is facing. 0 is straight up' Number readWrite Player getHeading Player setHeading:)\\n\\t\\t\\t(command forward: 'Moves the object forward in the direction it is heading' Number)\\n\\t\\t\\t(slot obtrudes 'whether the object sticks out over its container''s edge' Boolean readOnly Player getObtrudes unused unused) \\n\\t\\t\\t(command turnToward: 'turn toward the given object' Player) \\n\\t\\t\\t(command moveToward: 'move toward the given object' Player) \\n\\t\\t\\t(command turn: 'Change the heading of the object by the specified amount' Number)\\n\\t\\t\\t(command bounce: 'bounce off the edge if hit' Sound) \\n\\t\\t\\t(command wrap 'wrap off the edge if appropriate') \\n\\t\\t\\t(command followPath 'follow the yellow brick road') \\n\\t\\t\\t(command goToRightOf: 'place this object to the right of another' Player)\\n\\t\\t)\\n\\t)\\n\\n! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'sw 12/9/2001 23:26'!\\nadditionsToViewerCategoryObservation\\n\\t\\\"Answer viewer additions for the 'observations' category\\\"\\n\\n\\t^#(\\n\\t\\tobservation\\n \\n\\t\\t(\\n\\t\\t\\t(slot colorUnder 'The color under the center of the object' Color readOnly Player getColorUnder unused unused )\\n\\t\\t\\t(slot brightnessUnder 'The brightness under the center of the object' Number readOnly Player getBrightnessUnder unused unused)\\n\\t\\t\\t(slot luminanceUnder 'The luminance under the center of the object' Number readOnly Player getLuminanceUnder unused unused)\\n\\t\\t\\t(slot saturationUnder 'The saturation under the center of the object' Number readOnly Player getSaturationUnder unused unused)\\n\\t\\t\\n\\t\\t))\\n! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'sw 4/17/2003 12:05'!\\nadditionsToViewerCategoryPenUse\\n\\t\\\"Answer viewer additions for the 'pen use' category\\\"\\n\\n\\t^#(\\n\\t\\t#'pen use' \\n\\t\\t(\\n\\t\\t\\t(slot penColor 'the color of ink used by the pen' Color readWrite Player getPenColor Player setPenColor:) \\n\\t\\t\\t(slot penSize 'the width of the pen' Number readWrite Player getPenSize Player setPenSize:) \\n\\t\\t\\t(slot penDown 'whether the pen is currently down' Boolean readWrite Player getPenDown Player setPenDown:)\\n\\t\\t\\t(slot trailStyle 'determines whether lines, arrows, arrowheads, or dots are used when I put down a pen trail' TrailStyle readWrite Player getTrailStyle Player setTrailStyle:)\\n\\t\\t\\t(slot dotSize 'diameter of dot to use when trailStyle is dots' Number readWrite Player getDotSize Player setDotSize:)\\n\\t\\t\\t(command clearOwnersPenTrails 'clear all pen trails in my containing playfield')\\n\\t\\t)\\n\\t)\\n! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'sw 2/19/2003 18:04'!\\nadditionsToViewerCategoryScripting\\n\\t\\\"Answer viewer additions for the 'scripting' category\\\"\\n\\n\\t^#(\\n\\t\\tscripting \\n\\t\\t(\\n\\n\\t\\t\\t(command startScript: 'start the given script ticking' ScriptName)\\n\\t\\t\\t(command pauseScript: 'make the given script be \\\"paused\\\"' ScriptName)\\n\\t\\t\\t(command stopScript: 'make the given script be \\\"normal\\\"' ScriptName)\\n\\n\\t\\t\\t(command startAll: 'start the given script ticking in the object and all of its siblings.' ScriptName)\\n\\t\\t\\t(command pauseAll: 'make the given script be \\\"paused\\\" in the object and all of its siblings' ScriptName)\\n\\t\\t\\t(command stopAll: 'make the given script be \\\"normal\\\" in the object and all of its siblings' ScriptName)\\n\\n\\t\\t\\t(command doScript: 'run the given script once, on the next tick' ScriptName)\\n\\t\\t\\t(command tellSelfAndAllSiblings: 'run the given script in the object and in all of its siblings' ScriptName)\\n\\t\\t\\t(command tellAllSiblings: 'send a message to all siblings' ScriptName)))! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'RAA 5/18/2001 12:48'!\\nadditionsToViewerCategoryScripts\\n\\n\\t\\\"note: if you change the thing below you also need to change #tileScriptCommands.\\\"\\n\\n\\t^#(\\n\\t\\tscripts \\n\\t\\t(\\n\\t\\t\\t(command emptyScript 'an empty script')\\n\\t\\t)\\n\\t)\\n\\n! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'nk 10/14/2004 10:59'!\\nadditionsToViewerCategoryTests\\n\\t\\\"Answer viewer additions for the 'tests' category.\\\"\\n\\n\\\"Note: Because of intractable performance problems in continuously evaluating isOverColor in a Viewer, the isOverColor entry is not given a readout\\\"\\n\\n\\t^#(\\n\\t\\t#tests \\n\\t\\t(\\n\\t\\t\\t(slot isOverColor 'whether any part of the object is over the given color' Boolean\\treadOnly Player seesColor: unused unused)\\n\\t\\t\\t(slot isUnderMouse 'whether the object is under the current mouse position' Boolean readOnly\\tPlayer getIsUnderMouse unused unused)\\n\\t\\t\\t(slot colorSees\\t'whether the given color sees the given color' Boolean readOnly\\tPlayer color:sees:\\tunused\\tunused)\\n\\t\\t\\t(slot overlaps 'whether I overlap a given object' Boolean readOnly Player overlaps: unused unused)\\n\\t\\t\\t(slot overlapsAny 'whether I overlap a given object or one of its siblings or similar objects' Boolean readOnly Player overlapsAny: unused unused)\\n\\t\\t\\t(slot touchesA\\t'whether I overlap any Sketch that is showing the same picture as a particular prototype.' Boolean readOnly Player touchesA:\\tunused\\tunused)\\n\\t\\t\\t(slot obtrudes 'whether the object sticks out over its container''s edge' Boolean readOnly Player getObtrudes unused unused)\\n\\t\\t)\\n\\t)\\n! !\\n\\n!Morph class methodsFor: '*eToys-scripting' stamp: 'sw 9/17/2002 10:00'!\\nvectorAdditions\\n\\t\\\"Answer slot/command definitions for the vector experiment\\\"\\n\\n\\t^ # (\\n(slot x 'The x coordinate' Number readWrite Player getX Player setX:)\\n(slot y 'The y coordinate' Number readWrite Player getY Player setY:)\\n(slot heading 'Which direction the object is facing. 0 is straight up' Number readWrite Player getHeading Player setHeading:)\\n(slot distance 'The length of the vector connecting the origin to the object''s position' Number readWrite Player getDistance Player setDistance:)\\n(slot theta 'The angle between the positive x-axis and the vector connecting the origin to the object''s position' Number readWrite Player getTheta Player setTheta: )\\n(slot headingTheta 'The angle that my heading vector makes with the positive x-axis' Number readWrite Player getHeadingTheta Player setHeadingTheta:)\\n\\n(command + 'Adds two players together, treating each as a vector from the origin.' Player)\\n(command - 'Subtracts one player from another, treating each as a vector from the origin.' Player)\\n(command * 'Multiply a player by a Number, treating the Player as a vector from the origin.' Number)\\n(command / 'Divide a player by a Number, treating the Player as a vector from the origin.' Number)\\n\\n(command incr: 'Each Player is a vector from the origin. Increase one by the amount of the other.' Player)\\n(command decr: 'Each Player is a vector from the origin. Decrease one by the amount of the other.' Player)\\n(command multBy: 'A Player is a vector from the origin. Multiply its length by the factor.' Number)\\n(command dividedBy: 'A Player is a vector from the origin. Divide its length by the factor.' Number)\\n\\t)! !\\n\\n\\n!Morph class methodsFor: '*flexibleVocabularies-flexiblevocabularies-scripting' stamp: 'nk 10/11/2003 18:17'!\\nadditionsToViewerCategories\\n\\t\\\"Answer a list of (<categoryName> <list of category specs>) pairs that characterize the\\n\\tphrases this kind of morph wishes to add to various Viewer categories.\\n\\n\\tThis version factors each category definition into a separate method.\\n\\n\\tSubclasses that have additions can either:\\n\\t\\t- override this method, or\\n\\t\\t- (preferably) define one or more additionToViewerCategory* methods.\\n\\n\\tThe advantage of the latter technique is that class extensions may be added\\n\\tby external packages without having to re-define additionsToViewerCategories.\\n\\t\\\"\\n\\t^#()! !\\n\\n!Morph class methodsFor: '*flexibleVocabularies-flexiblevocabularies-scripting' stamp: 'nk 8/29/2004 16:35'!\\nadditionsToViewerCategory: aCategoryName\\n\\t\\\"Answer a list of viewer specs for items to be added to the given category on behalf of the receiver. Each class in a morph's superclass chain is given the opportunity to add more things\\\"\\n\\n\\taCategoryName == #vector ifTrue:\\n\\t\\t[^ self vectorAdditions].\\n\\t^self allAdditionsToViewerCategories at: aCategoryName ifAbsent: [ #() ].! !\\n\\n!Morph class methodsFor: '*flexibleVocabularies-flexiblevocabularies-scripting' stamp: 'nk 10/11/2003 18:06'!\\nadditionToViewerCategorySelectors\\n\\t\\\"Answer the list of my selectors matching additionsToViewerCategory*\\\"\\n\\t^self class organization allMethodSelectors select: [ :ea |\\n\\t\\t(ea beginsWith: 'additionsToViewerCategory')\\n\\t\\t\\t\\t\\tand: [ (ea at: 26 ifAbsent: []) ~= $: ]]! !\\n\\n!Morph class methodsFor: '*flexibleVocabularies-flexiblevocabularies-scripting' stamp: 'nk 9/11/2004 16:56'!\\nallAdditionsToViewerCategories\\n\\t\\\"Answer a Dictionary of (<categoryName> <list of category specs>) that \\n\\tdefines the phrases this kind of morph wishes to add to various Viewer categories. \\n\\t \\n\\tThis version allows each category definition to be defined in one or more separate methods. \\n\\t \\n\\tSubclasses that have additions can either:\\n\\t- override #additionsToViewerCategories, or\\n\\t- (preferably) define one or more additionToViewerCategory* methods.\\n\\n\\tThe advantage of the latter technique is that class extensions may be added by\\n\\texternal packages without having to re-define additionsToViewerCategories.\\\"\\n\\n\\t\\\"\\n\\tMorph allAdditionsToViewerCategories\\n\\t\\\"\\n\\t| dict |\\n\\tdict := IdentityDictionary new.\\n\\t(self class includesSelector: #additionsToViewerCategories)\\n\\t\\tifTrue: [self additionsToViewerCategories\\n\\t\\t\\t\\tdo: [:group | group\\n\\t\\t\\t\\t\\t\\tpairsDo: [:key :list | (dict\\n\\t\\t\\t\\t\\t\\t\\t\\tat: key\\n\\t\\t\\t\\t\\t\\t\\t\\tifAbsentPut: [OrderedCollection new])\\n\\t\\t\\t\\t\\t\\t\\t\\taddAll: list]]].\\n\\tself class selectors\\n\\t\\tdo: [:aSelector | ((aSelector beginsWith: 'additionsToViewerCategory')\\n\\t\\t\\t\\t\\tand: [(aSelector at: 26 ifAbsent: []) ~= $:])\\n\\t\\t\\t\\tifTrue: [(self perform: aSelector)\\n\\t\\t\\t\\t\\t\\tpairsDo: [:key :list | (dict\\n\\t\\t\\t\\t\\t\\t\\t\\tat: key\\n\\t\\t\\t\\t\\t\\t\\t\\tifAbsentPut: [OrderedCollection new])\\n\\t\\t\\t\\t\\t\\t\\t\\taddAll: list]]].\\n\\t^ dict! !\\n\\n!Morph class methodsFor: '*flexibleVocabularies-flexiblevocabularies-scripting' stamp: 'stephaneducasse 2/4/2006 20:33'!\\nunfilteredCategoriesForViewer\\n\\t\\\"Answer a list of symbols representing the categories to offer in the viewer for one of my instances, in order of:\\n\\t- masterOrderingOfCategorySymbols first\\n\\t- others last in order by translated wording\\\"\\n\\t\\\"\\n\\tMorph unfilteredCategoriesForViewer\\n\\t\\\"\\n\\n\\t| aClass additions masterOrder |\\n\\taClass := self.\\n\\tadditions := OrderedCollection new.\\n\\t[aClass == Morph superclass ] whileFalse: [\\n\\t\\tadditions addAll: (aClass allAdditionsToViewerCategories keys\\n\\t\\t\\tasSortedCollection: [ :a :b | a translated < b translated ]).\\n\\t\\taClass := aClass superclass ]. \\n\\n\\tmasterOrder := EToyVocabulary masterOrderingOfCategorySymbols.\\n\\n\\t^(masterOrder intersection: additions), (additions difference: masterOrder).! !\\n\\n\\n!Morph class methodsFor: '*MorphicExtras-arrow head size'!\\ndefaultArrowheadSize\\n\\t\\n\\t^ 5 @ 4! !\\n\\n!Morph class methodsFor: '*MorphicExtras-arrow head size'!\\nobtainArrowheadFor: aPrompt defaultValue: defaultPoint\\n\\t\\\"Allow the user to supply a point to serve as an arrowhead size. Answer nil if we fail to get a good point\\\"\\n\\n\\t| result |\\n\\tresult := FillInTheBlank request: aPrompt initialAnswer: defaultPoint asString.\\n\\tresult isEmptyOrNil ifTrue: [^ nil].\\n\\t^ [(Point readFrom: (ReadStream on: result))]\\n\\t\\ton: Error do: [:ex | nil].! !\\n\\n\\n!Morph class methodsFor: '*MorphicExtras-new-morph participation' stamp: 'sw 11/27/2001 13:20'!\\naddPartsDescriptorQuadsTo: aList if: aBlock\\n\\t\\\"For each of the standard objects to be put into parts bins based on declarations in this class, add a parts-launching quintuplet to aList, provided that the boolean-valued-block-with-one-argument supplied evaluates to true when provided the DescriptionForPartsBin\\\"\\n\\n\\t| info more |\\n\\t(self class includesSelector: #descriptionForPartsBin) ifTrue:\\n\\t\\t[info _ self descriptionForPartsBin.\\n\\t\\t(aBlock value: info) ifTrue:\\n\\t\\t\\t[aList add:\\n\\t\\t\\t\\t{info globalReceiverSymbol.\\n\\t\\t\\t\\tinfo nativitySelector.\\n\\t\\t\\t\\tinfo formalName.\\n\\t\\t\\t\\tinfo documentation.\\n\\t\\t\\t\\tinfo sampleImageFormOrNil}]].\\n\\n\\t(self class includesSelector: #supplementaryPartsDescriptions)\\n\\t\\tifTrue:\\n\\t\\t\\t[more _ self supplementaryPartsDescriptions.\\n\\t\\t\\t(more isKindOf: DescriptionForPartsBin) ifTrue: [more _ Array with: more].\\n\\t\\t\\t\\t\\\"The above being a mild bit of forgiveness, so that in the usual only-one\\n\\t\\t\\t\\tcase, the user need not return a collection\\\"\\n\\t\\t\\tmore do:\\n\\t\\t\\t\\t[:aPartsDescription | (aBlock value: aPartsDescription) ifTrue:\\n\\t\\t\\t\\t\\t[aList add:\\n\\t\\t\\t\\t\\t\\t{aPartsDescription globalReceiverSymbol.\\n\\t\\t\\t\\t\\t\\taPartsDescription nativitySelector.\\n\\t\\t\\t\\t\\t\\taPartsDescription formalName.\\n\\t\\t\\t\\t\\t\\taPartsDescription documentation.\\n\\t\\t\\t\\t\\t\\taPartsDescription sampleImageFormOrNil}]]]! !\\n\\n\\n!Morph class methodsFor: '*MorphicExtras-parts bin' stamp: 'sw 8/12/2001 14:26'!\\nsupplementaryPartsDescriptions\\n\\t\\\"Answer a list of DescriptionForPartsBin objects that characterize objects that this class wishes to contribute to Stationery bins *other* than by the standard default #newStandAlone protocol\\\"\\n\\n\\t^ {\\tDescriptionForPartsBin\\n\\t\\t\\tformalName: 'Status'\\n\\t\\t\\tcategoryList: #(Scripting)\\n\\t\\t\\tdocumentation: 'Buttons to run, stop, or single-step scripts'\\n\\t\\t\\tglobalReceiverSymbol: #ScriptingSystem\\n\\t\\t\\tnativitySelector: #scriptControlButtons.\\n\\t\\tDescriptionForPartsBin\\n\\t\\t\\tformalName: 'Scripting'\\n\\t\\t\\tcategoryList: #(Scripting)\\n\\t\\t\\tdocumentation: 'A confined place for drawing and scripting, with its own private stop/step/go buttons.'\\n\\t\\t\\tglobalReceiverSymbol: #ScriptingSystem\\n\\t\\t\\tnativitySelector: #newScriptingSpace.\\n\\t\\tDescriptionForPartsBin\\n\\t\\t\\tformalName: 'Random'\\n\\t\\t\\tcategoryList: #(Scripting)\\n\\t\\t\\tdocumentation: 'A tile that will produce a random number in a given range'\\n\\t\\t\\tglobalReceiverSymbol: #RandomNumberTile\\n\\t\\t\\tnativitySelector: #new.\\n\\t\\tDescriptionForPartsBin\\n\\t\\t\\tformalName: 'ButtonDown?'\\n\\t\\t\\tcategoryList: #(Scripting)\\n\\t\\t\\tdocumentation: 'Tiles for querying whether the mouse button is down'\\n\\t\\t\\tglobalReceiverSymbol: #ScriptingSystem\\n\\t\\t\\tnativitySelector: #anyButtonPressedTiles.\\n\\t\\tDescriptionForPartsBin\\n\\t\\t\\tformalName: 'ButtonUp?'\\n\\t\\t\\tcategoryList: #(Scripting)\\n\\t\\t\\tdocumentation: 'Tiles for querying whether the mouse button is up'\\n\\t\\t\\tglobalReceiverSymbol: #ScriptingSystem\\n\\t\\t\\tnativitySelector: #noButtonPressedTiles.\\n\\t\\tDescriptionForPartsBin\\n\\t\\t\\tformalName: 'NextPage'\\n\\t\\t\\tcategoryList: #(Presentation)\\n\\t\\t\\tdocumentation: 'A button which, when clicked, takes the reader to the next page of a book'\\n\\t\\t\\tglobalReceiverSymbol: #BookMorph\\n\\t\\t\\tnativitySelector: #nextPageButton.\\n\\t\\tDescriptionForPartsBin\\n\\t\\t\\tformalName: 'PreviousPage'\\n\\t\\t\\tcategoryList: #(Presentation)\\n\\t\\t\\tdocumentation: 'A button which, when clicked, takes the reader to the next page of a book'\\n\\t\\t\\tglobalReceiverSymbol: #BookMorph\\n\\t\\t\\tnativitySelector: #previousPageButton.},\\n\\n\\t(Flaps quadsDefiningToolsFlap collect:\\n\\t\\t[:aQuad | DescriptionForPartsBin fromQuad: aQuad categoryList: #(Tools)])! !\\n\\n\\n\\n!Morph class methodsFor: '*flexibleVocabularies-flexibleVocabularies' stamp: 'al 11/28/2005 16:46'!\\nnoteAddedSelector: aSelector meta: isMeta\\n\\t\\\"Any change to an additionsToViewer... method can invalidate existing etoy vocabularies.\\n\\tThe #respondsTo: test is to allow loading the FlexibleVocabularies change set without having to worry about method ordering.\\\"\\n\\t(isMeta\\n\\t\\t\\tand: [(aSelector beginsWith: 'additionsToViewer')\\n\\t\\t\\t\\t\\tand: [self respondsTo: #hasAdditionsToViewerCategories]])\\n\\t\\tifTrue: [Vocabulary changeMadeToViewerAdditions].\\n\\tsuper noteCompilationOf: aSelector meta: isMeta! !\\n\\n!Morph class methodsFor: '*flexibleVocabularies-flexibleVocabularies' stamp: 'NS 4/15/2004 12:40'!\\nnoteCompilationOf: aSelector meta: isMeta\\n\\t\\\"This method does nothing and should be removed!!\\\"\\n\\n\\t^ super noteCompilationOf: aSelector meta: isMeta! !\\nRectangleMorph subclass: #MorphExample\\n\\tinstanceVariableNames: 'phase ball star'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Demo'!\\n!MorphExample commentStamp: 'kfr 10/26/2003 18:38' prior: 0!\\nThis is a example of how to use a morph. It consists of only two \\nmethods, initialize and step.\\n\\nDoIt:\\nMorphExample new openInWorld.\\n\\n\\n\\n!\\n\\n\\n!MorphExample methodsFor: 'initialization' stamp: 'dgd 2/21/2003 19:59'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\tphase _ 1.\\n\\tself extent: 200 @ 200.\\n\\tball _ EllipseMorph new extent: 30 @ 30.\\n\\tself\\n\\t\\taddMorph: ((star _ StarMorph new extent: 150 @ 150) center: self center)! !\\n\\n\\n!MorphExample methodsFor: 'stepping and presenter' stamp: 'kfr 10/26/2003 18:33'!\\nstep\\n\\tphase _ phase\\\\\\\\8 + 1.\\n\\tphase = 1 ifTrue: [^ ball delete].\\n\\tphase < 4 ifTrue:[^self].\\n\\tphase = 4 ifTrue: [self addMorph: ball].\\n\\tball align: ball center with: (star vertices at: (phase-3*2)).! !\\nObject subclass: #MorphExtension\\n\\tinstanceVariableNames: 'locked visible sticky balloonText balloonTextSelector externalName isPartsDonor actorState player eventHandler otherProperties'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Kernel'!\\n!MorphExtension commentStamp: '<historical>' prior: 0!\\nMorphExtension provides access to extra instance state that is not required in most simple morphs. This allows simple morphs to remain relatively lightweight while still admitting more complex structures as necessary. The otherProperties field takes this policy to the extreme of allowing any number of additional named attributes, albeit at a certain cost in speed and space.!\\n\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'di 8/10/1998 12:52'!\\nballoonText\\n\\t^ balloonText! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'di 8/10/1998 12:52'!\\nballoonTextSelector\\n\\t^ balloonTextSelector! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:51'!\\nballoonTextSelector: aSymbol \\n\\t\\\"change the receiver's balloonTextSelector\\\"\\n\\tballoonTextSelector _ aSymbol! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'di 8/10/1998 12:55'!\\nballoonText: newValue\\n\\tballoonText _ newValue! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:51'!\\neventHandler\\n\\t\\\"answer the receiver's eventHandler\\\"\\n\\t^ eventHandler ! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'di 8/10/1998 12:56'!\\neventHandler: newValue\\n\\teventHandler _ newValue! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:57'!\\nexternalName: aString \\n\\t\\\"change the receiver's externalName\\\"\\n\\texternalName _ aString! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:38'!\\nlocked\\n\\t\\\"answer whether the receiver is Locked\\\"\\n\\t^ locked! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:48'!\\nlocked: aBoolean \\n\\t\\\"change the receiver's locked property\\\"\\n\\tlocked _ aBoolean! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'di 8/14/1998 13:07'!\\nsticky\\n\\t^ sticky! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:47'!\\nsticky: aBoolean \\n\\t\\\"change the receiver's sticky property\\\"\\n\\tsticky _ aBoolean! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'dgd 2/16/2003 21:41'!\\nvisible\\n\\t\\\"answer whether the receiver is visible\\\"\\n\\t^ visible! !\\n\\n!MorphExtension methodsFor: 'accessing' stamp: 'di 8/10/1998 12:55'!\\nvisible: newValue\\n\\tvisible _ newValue! !\\n\\n\\n!MorphExtension methodsFor: 'accessing - layout properties' stamp: 'ar 11/14/2000 17:17'!\\nlayoutFrame\\n\\t^self valueOfProperty: #layoutFrame ifAbsent:[nil]! !\\n\\n!MorphExtension methodsFor: 'accessing - layout properties' stamp: 'dgd 2/22/2003 13:32'!\\nlayoutFrame: aLayoutFrame \\n\\taLayoutFrame isNil\\n\\t\\tifTrue: [self removeProperty: #layoutFrame]\\n\\t\\tifFalse: [self setProperty: #layoutFrame toValue: aLayoutFrame]! !\\n\\n!MorphExtension methodsFor: 'accessing - layout properties' stamp: 'ar 11/14/2000 17:17'!\\nlayoutPolicy\\n\\t^self valueOfProperty: #layoutPolicy ifAbsent:[nil]! !\\n\\n!MorphExtension methodsFor: 'accessing - layout properties' stamp: 'dgd 2/22/2003 13:32'!\\nlayoutPolicy: aLayoutPolicy \\n\\taLayoutPolicy isNil\\n\\t\\tifTrue: [self removeProperty: #layoutPolicy]\\n\\t\\tifFalse: [self setProperty: #layoutPolicy toValue: aLayoutPolicy]! !\\n\\n!MorphExtension methodsFor: 'accessing - layout properties' stamp: 'ar 11/14/2000 17:18'!\\nlayoutProperties\\n\\t^self valueOfProperty: #layoutProperties ifAbsent:[nil]! !\\n\\n!MorphExtension methodsFor: 'accessing - layout properties' stamp: 'dgd 2/22/2003 13:32'!\\nlayoutProperties: newProperties \\n\\t\\\"Return the current layout properties associated with the receiver\\\"\\n\\n\\tnewProperties isNil\\n\\t\\tifTrue: [self removeProperty: #layoutProperties]\\n\\t\\tifFalse: [self setProperty: #layoutProperties toValue: newProperties]! !\\n\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'md 2/27/2006 08:41'!\\nassureOtherProperties\\n\\t\\\"creates an otherProperties for the receiver if needed\\\"\\n\\totherProperties ifNil: [self initializeOtherProperties].\\n\\t^ otherProperties! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'md 2/27/2006 08:36'!\\nhasOtherProperties\\n\\t\\\"answer whether the receiver has otherProperties\\\"\\n\\t^ otherProperties notNil! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'md 2/27/2006 08:42'!\\nhasProperty: aSymbol \\n\\t\\\"Answer whether the receiver has the property named aSymbol\\\"\\n\\t| property |\\n\\totherProperties ifNil: [^ false].\\n\\tproperty := otherProperties at: aSymbol ifAbsent: [].\\n\\tproperty isNil ifTrue: [^ false].\\n\\tproperty == false ifTrue: [^ false].\\n\\t^ true! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'md 2/27/2006 08:36'!\\ninitializeOtherProperties\\n\\t\\\"private - initializes the receiver's otherProperties\\\"\\n\\totherProperties := IdentityDictionary new! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'dgd 2/16/2003 21:04'!\\notherProperties\\n\\t\\\"answer the receiver's otherProperties\\\"\\n\\t^ otherProperties! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'dgd 2/16/2003 21:20'!\\nprivateOtherProperties: anIndentityDictionary \\n\\t\\\"private - change the receiver's otherProperties\\\"\\n\\totherProperties _ anIndentityDictionary ! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'md 2/27/2006 08:37'!\\nremoveOtherProperties\\n\\t\\\"Remove the 'other' properties\\\"\\n\\totherProperties := nil! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'md 2/27/2006 08:43'!\\nremoveProperty: aSymbol \\n\\t\\\"removes the property named aSymbol if it exists\\\"\\n\\totherProperties ifNil: [^ self].\\n\\totherProperties removeKey: aSymbol ifAbsent: [].\\n\\totherProperties isEmpty ifTrue: [self removeOtherProperties]! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'dgd 2/16/2003 21:49'!\\nsetProperty: aSymbol toValue: abObject \\n\\t\\\"change the receiver's property named aSymbol to anObject\\\"\\n\\tself assureOtherProperties at: aSymbol put: abObject! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'md 2/27/2006 08:45'!\\nsortedPropertyNames\\n\\t\\\"answer the receiver's property names in a sorted way\\\"\\n\\n\\t| props |\\n\\tprops := WriteStream on: (Array new: 10).\\n\\tlocked == true ifTrue: [props nextPut: #locked].\\n\\tvisible == false ifTrue: [props nextPut: #visible].\\n\\tsticky == true ifTrue: [props nextPut: #sticky].\\n\\tballoonText isNil ifFalse: [props nextPut: #balloonText].\\n\\tballoonTextSelector isNil ifFalse: [props nextPut: #balloonTextSelector].\\n\\texternalName isNil ifFalse: [props nextPut: #externalName].\\n\\tisPartsDonor == true ifTrue: [props nextPut: #isPartsDonor].\\n\\tactorState isNil ifFalse: [props nextPut: #actorState].\\n\\tplayer isNil ifFalse: [props nextPut: #player].\\n\\teventHandler isNil ifFalse: [props nextPut: #eventHandler].\\n\\t otherProperties ifNotNil: [otherProperties associationsDo: [:a | props nextPut: a key]].\\n\\t^props contents sort: [:s1 :s2 | s1 <= s2]! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'dgd 2/16/2003 21:00'!\\nvalueOfProperty: aSymbol \\n\\\"answer the value of the receiver's property named aSymbol\\\"\\n\\t^ self\\n\\t\\tvalueOfProperty: aSymbol\\n\\t\\tifAbsent: []! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'dgd 2/16/2003 21:28'!\\nvalueOfProperty: aSymbol ifAbsentPut: aBlock \\n\\t\\\"If the receiver possesses a property of the given name, answer \\n\\tits value. If not, then create a property of the given name, give \\n\\tit the value obtained by evaluating aBlock, then answer that \\n\\tvalue\\\"\\n\\t^self assureOtherProperties at: aSymbol ifAbsentPut: aBlock! !\\n\\n!MorphExtension methodsFor: 'accessing - other properties' stamp: 'md 2/27/2006 08:43'!\\nvalueOfProperty: aSymbol ifAbsent: aBlock \\n\\t\\\"if the receiver possesses a property of the given name, answer \\n\\tits value. If not then evaluate aBlock and answer the result of \\n\\tthis block evaluation\\\"\\n\\totherProperties ifNil: [^ aBlock value].\\n\\t^ otherProperties at: aSymbol ifAbsent: [^ aBlock value]! !\\n\\n\\n!MorphExtension methodsFor: 'connectors-copying' stamp: 'nk 5/1/2004 17:20'!\\ncopyWeakly\\n\\t\\\"list of names of properties whose values should be weak-copied when veryDeepCopying a morph. See DeepCopier.\\\"\\n\\n\\t^ #(formerOwner newPermanentPlayer logger graphModel gestureDictionaryOrName)\\n\\t\\\"add yours to this list\\\" \\n\\n\\t\\\"formerOwner should really be nil at the time of the copy, but this will work just fine.\\\"! !\\n\\n!MorphExtension methodsFor: 'connectors-copying' stamp: 'nk 5/1/2004 17:23'!\\npropertyNamesNotCopied\\n\\t\\\"list of names of properties whose values should be deleted when veryDeepCopying a morph.\\n\\tSee DeepCopier.\\\"\\n\\n\\t^ #(connectedConstraints connectionHighlights highlightedTargets)\\n\\t\\\"add yours to this list\\\" \\n! !\\n\\n!MorphExtension methodsFor: 'connectors-copying' stamp: 'nk 5/1/2004 17:39'!\\nveryDeepFixupWith: deepCopier \\n\\t\\\"If target and arguments fields were weakly copied, fix them here.\\n\\tIf they were in the tree being copied, fix them up, otherwise point to the originals!!!!\\\"\\n\\n\\tsuper veryDeepFixupWith: deepCopier.\\n\\totherProperties ifNil: [ ^self ].\\n\\n\\t\\\"Properties whose values are only copied weakly replace those values if they were copied via another path\\\"\\n\\tself copyWeakly do: [ :propertyName |\\n\\t\\totherProperties at: propertyName ifPresent: [ :property |\\n\\t\\t\\totherProperties at: propertyName\\n\\t\\t\\t\\tput: (deepCopier references at: property ifAbsent: [ property ])]].\\n! !\\n\\n!MorphExtension methodsFor: 'connectors-copying' stamp: 'nk 5/1/2004 17:45'!\\nveryDeepInner: deepCopier \\n\\t\\\"Copy all of my instance variables.\\n\\tSome otherProperties need to be not copied at all, but shared. Their names are given by copyWeakly.\\n\\tSome otherProperties should not be copied or shared. Their names are given by propertyNamesNotCopied.\\n\\tThis is special code for the dictionary. See DeepCopier, and veryDeepFixupWith:.\\\"\\n\\n\\t| namesOfWeaklyCopiedProperties weaklyCopiedValues |\\n\\tsuper veryDeepInner: deepCopier.\\n\\tlocked _ locked veryDeepCopyWith: deepCopier.\\n\\tvisible _ visible veryDeepCopyWith: deepCopier.\\n\\tsticky _ sticky veryDeepCopyWith: deepCopier.\\n\\tballoonText _ balloonText veryDeepCopyWith: deepCopier.\\n\\tballoonTextSelector _ balloonTextSelector veryDeepCopyWith: deepCopier.\\n\\texternalName _ externalName veryDeepCopyWith: deepCopier.\\n\\tisPartsDonor _ isPartsDonor veryDeepCopyWith: deepCopier.\\n\\tactorState _ actorState veryDeepCopyWith: deepCopier.\\n\\tplayer _ player veryDeepCopyWith: deepCopier.\\t\\t\\\"Do copy the player of this morph\\\"\\n\\teventHandler _ eventHandler veryDeepCopyWith: deepCopier. \\t\\\"has its own restrictions\\\"\\n\\n\\totherProperties ifNil: [ ^self ].\\n\\n\\totherProperties := otherProperties copy.\\n\\tself propertyNamesNotCopied do: [ :propName | otherProperties removeKey: propName ifAbsent: [] ].\\n\\n\\tnamesOfWeaklyCopiedProperties _ self copyWeakly.\\n\\tweaklyCopiedValues _ namesOfWeaklyCopiedProperties collect: [ :propName | otherProperties removeKey: propName ifAbsent: [] ].\\n\\n\\t\\\"Now copy all the others.\\\"\\n\\totherProperties := otherProperties veryDeepCopyWith: deepCopier.\\n\\n\\t\\\"And replace the weak ones.\\\"\\n\\tnamesOfWeaklyCopiedProperties with: weaklyCopiedValues do: [ :name :value | value ifNotNil: [ otherProperties at: name put: value ]].\\n! !\\n\\n\\n!MorphExtension methodsFor: 'initialization' stamp: 'di 8/16/1998 12:02'!\\ninitialize\\n\\t\\\"Init all booleans to default values\\\"\\n\\tlocked _ false.\\n\\tvisible _ true.\\n\\tsticky _ false.\\n\\tisPartsDonor _ false.\\n! !\\n\\n\\n!MorphExtension methodsFor: 'object fileIn' stamp: 'dgd 2/16/2003 21:06'!\\nconvertProperty: aSymbol toValue: anObject \\n\\t\\\"These special cases move old properties into named fields of the \\n\\textension\\\"\\n\\taSymbol == #locked\\n\\t\\tifTrue: [^ locked _ anObject].\\n\\taSymbol == #visible\\n\\t\\tifTrue: [^ visible _ anObject].\\n\\taSymbol == #sticky\\n\\t\\tifTrue: [^ sticky _ anObject].\\n\\taSymbol == #balloonText\\n\\t\\tifTrue: [^ balloonText _ anObject].\\n\\taSymbol == #balloonTextSelector\\n\\t\\tifTrue: [^ balloonTextSelector _ anObject].\\n\\taSymbol == #actorState\\n\\t\\tifTrue: [^ actorState _ anObject].\\n\\taSymbol == #player\\n\\t\\tifTrue: [^ player _ anObject].\\n\\taSymbol == #name\\n\\t\\tifTrue: [^ externalName _ anObject].\\n\\t\\\"*renamed*\\\"\\n\\taSymbol == #partsDonor\\n\\t\\tifTrue: [^ isPartsDonor _ anObject].\\n\\t\\\"*renamed*\\\"\\n\\tself assureOtherProperties at: aSymbol put: anObject! !\\n\\n\\n!MorphExtension methodsFor: 'objects from disk' stamp: 'tk 4/8/1999 12:45'!\\ncomeFullyUpOnReload: smartRefStream\\n\\t\\\"inst vars have default booplean values.\\\"\\n\\n\\tlocked ifNil: [locked _ false].\\n\\tvisible ifNil: [visible _ true].\\n\\tsticky ifNil: [sticky _ false].\\n\\tisPartsDonor ifNil: [isPartsDonor _ false].\\n\\t^ self! !\\n\\n\\n!MorphExtension methodsFor: 'other' stamp: 'md 2/27/2006 08:39'!\\ninspectElement\\n\\t\\\"Create and schedule an Inspector on the otherProperties and the \\n\\tnamed properties.\\\"\\n\\t| key obj |\\n\\tkey _ (SelectionMenu selections: self sortedPropertyNames)\\n\\t\\t\\t\\tstartUpWithCaption: 'Inspect which property?'.\\n\\tkey\\n\\t\\tifNil: [^ self].\\n\\tobj _ otherProperties\\n\\t\\t\\t\\tat: key\\n\\t\\t\\t\\tifAbsent: ['nOT a vALuE'].\\n\\tobj = 'nOT a vALuE'\\n\\t\\tifTrue: [(self perform: key) inspect\\n\\t\\t\\t\\\"named properties\\\"]\\n\\t\\tifFalse: [obj inspect]! !\\n\\n!MorphExtension methodsFor: 'other' stamp: 'md 2/27/2006 08:42'!\\nisDefault\\n\\t\\\"Return true if the receiver is a default and can be omitted\\\"\\n\\tlocked == true\\n\\t\\tifTrue: [^ false].\\n\\tvisible == false\\n\\t\\tifTrue: [^ false].\\n\\tsticky == true\\n\\t\\tifTrue: [^ false].\\n\\tballoonText isNil\\n\\t\\tifFalse: [^ false].\\n\\tballoonTextSelector isNil\\n\\t\\tifFalse: [^ false].\\n\\texternalName isNil\\n\\t\\tifFalse: [^ false].\\n\\tisPartsDonor == true\\n\\t\\tifTrue: [^ false].\\n\\tactorState isNil\\n\\t\\tifFalse: [^ false].\\n\\tplayer isNil\\n\\t\\tifFalse: [^ false].\\n\\teventHandler isNil\\n\\t\\tifFalse: [^ false].\\n\\totherProperties ifNotNil: [otherProperties isEmpty ifFalse: [^ false]].\\n\\t^ true! !\\n\\n\\n!MorphExtension methodsFor: 'printing' stamp: 'md 2/27/2006 08:45'!\\nprintOn: aStream \\n\\t\\\"Append to the argument, aStream, a sequence of characters that \\n\\tidentifies the receiver.\\\" \\n\\tsuper printOn: aStream.\\n\\taStream nextPutAll: ' ' , self identityHashPrintString.\\n\\tlocked == true\\n\\t\\tifTrue: [aStream nextPutAll: ' [locked] '].\\n\\tvisible == false\\n\\t\\tifTrue: [aStream nextPutAll: '[not visible] '].\\n\\tsticky == true\\n\\t\\tifTrue: [aStream nextPutAll: ' [sticky] '].\\n\\tballoonText\\n\\t\\tifNotNil: [aStream nextPutAll: ' [balloonText] '].\\n\\tballoonTextSelector\\n\\t\\tifNotNil: [aStream nextPutAll: ' [balloonTextSelector: ' , balloonTextSelector printString , '] '].\\n\\texternalName\\n\\t\\tifNotNil: [aStream nextPutAll: ' [externalName = ' , externalName , ' ] '].\\n\\tisPartsDonor == true\\n\\t\\tifTrue: [aStream nextPutAll: ' [isPartsDonor] '].\\n\\tplayer\\n\\t\\tifNotNil: [aStream nextPutAll: ' [player = ' , player printString , '] '].\\n\\teventHandler\\n\\t\\tifNotNil: [aStream nextPutAll: ' [eventHandler = ' , eventHandler printString , '] '].\\n\\t(otherProperties isNil or: [otherProperties isEmpty ]) ifTrue: [^ self].\\n\\taStream nextPutAll: ' [other: '.\\n\\tself otherProperties\\n\\t\\tkeysDo: [:aKey | aStream nextPutAll: ' (' , aKey , ' -> ' , (self otherProperties at: aKey) printString , ')'].\\n\\taStream nextPut: $]! !\\n\\n\\n!MorphExtension methodsFor: 'viewer' stamp: 'di 8/10/1998 14:47'!\\nexternalName\\n\\t^ externalName! !\\n\\n\\n!MorphExtension methodsFor: '*eToys-accessing' stamp: 'dgd 2/16/2003 21:56'!\\nactorState\\n\\t\\\"answer the redeiver's actorState\\\"\\n\\t^ actorState ! !\\n\\n!MorphExtension methodsFor: '*eToys-accessing' stamp: 'dgd 2/16/2003 21:53'!\\nactorState: anActorState \\n\\\"change the receiver's actorState\\\"\\n\\tactorState _ anActorState! !\\n\\n!MorphExtension methodsFor: '*eToys-accessing' stamp: 'dgd 2/16/2003 21:42'!\\nplayer\\n\\t\\\"answer the receiver's player\\\"\\n\\t^ player! !\\n\\n!MorphExtension methodsFor: '*eToys-accessing' stamp: 'dgd 2/16/2003 21:53'!\\nplayer: anObject \\n\\t\\\"change the receiver's player\\\"\\n\\tplayer _ anObject ! !\\n\\n\\n!MorphExtension methodsFor: '*MorphicExtras-accessing' stamp: 'dgd 2/16/2003 21:37'!\\nisPartsDonor\\n\\t\\\"answer whether the receiver is PartsDonor\\\"\\n\\t^ isPartsDonor! !\\n\\n!MorphExtension methodsFor: '*MorphicExtras-accessing' stamp: 'dgd 2/16/2003 21:40'!\\nisPartsDonor: aBoolean \\n\\t\\\"change the receiver's isPartDonor property\\\"\\n\\tisPartsDonor _ aBoolean! !\\n\\n\\n!MorphExtension methodsFor: '*MorphicExtras-copying' stamp: 'md 2/27/2006 08:44'!\\nupdateReferencesUsing: aDictionary \\n\\t\\\"Update intra-morph references within a composite morph that \\n\\thas been copied. For example, if a button refers to morph X in \\n\\tthe orginal \\n\\tcomposite then the copy of that button in the new composite \\n\\tshould refer to \\n\\tthe copy of X in new composite, not the original X. This default \\n\\timplementation updates the contents of any morph-bearing slot.\\\"\\n\\n\\t| old |\\n\\teventHandler isNil \\n\\t\\tifFalse: \\n\\t\\t\\t[self eventHandler: self eventHandler copy.\\n\\t\\t\\t1 to: self eventHandler class instSize\\n\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t[:i | \\n\\t\\t\\t\\t\\told := eventHandler instVarAt: i.\\n\\t\\t\\t\\t\\told isMorph \\n\\t\\t\\t\\t\\t\\tifTrue: [eventHandler instVarAt: i put: (aDictionary at: old ifAbsent: [old])]]].\\n\\totherProperties ifNotNil: [otherProperties associationsDo: [:assn | \\n\\t\\t\\t\\t\\tassn value: (aDictionary at: assn value ifAbsent: [assn value])]]! !\\nObject subclass: #MorphHierarchy\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Widgets'!\\n\\n!MorphHierarchy methodsFor: 'private' stamp: 'dgd 9/26/2004 18:28'!\\nasMorph\\n\\t\\\"Answer the morph version of the receiver\\\"\\n\\t| morph |\\n\\tmorph := MorphHierarchyListMorph\\n\\t\\t\\t\\ton: self\\n\\t\\t\\t\\tlist: #roots\\n\\t\\t\\t\\tselected: nil\\n\\t\\t\\t\\tchangeSelected: #selected:.\\n\\t\\\"\\\"\\n\\t^ morph inAContainer! !\\n\\n\\n!MorphHierarchy methodsFor: 'accessing' stamp: 'dgd 9/26/2004 18:29'!\\nroots\\n\\t\\\"Answer the roots for the Object Hierarchy, that means answer the World\\\"\\n\\t^ {MorphListItemWrapper with: World}! !\\n\\n!MorphHierarchy methodsFor: 'accessing' stamp: 'dgd 9/26/2004 18:30'!\\nselected: aMorphListItemWrapper \\n\\t\\\"Change the selected object\\\"\\n\\t| newSelection |\\n\\taMorphListItemWrapper isNil\\n\\t\\tifTrue: [^ self].\\n\\tnewSelection := aMorphListItemWrapper withoutListWrapper.\\n\\tnewSelection == World selectedObject\\n\\t\\tifTrue: [newSelection removeHalo]\\n\\t\\tifFalse: [newSelection addHalo].\\n\\tself changed: #selected! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphHierarchy class\\n\\tinstanceVariableNames: ''!\\n\\n!MorphHierarchy class methodsFor: 'opening' stamp: 'dgd 9/25/2004 21:50'!\\nopenOrDelete\\n\\t| oldMorph |\\n\\toldMorph := World submorphs\\n\\t\\t\\t\\tdetect: [:each | each hasProperty: #morphHierarchy]\\n\\t\\t\\t\\tifNone: [| newMorph | \\n\\t\\t\\t\\t\\tnewMorph := self new asMorph.\\n\\t\\t\\t\\t\\tnewMorph bottomLeft: ActiveHand position.\\n\\t\\t\\t\\t\\tnewMorph openInWorld.\\n\\t\\t\\t\\t\\tnewMorph isFullOnScreen\\n\\t\\t\\t\\t\\t\\tifFalse: [newMorph goHome].\\n\\t\\t\\t\\t\\t^ self].\\n\\t\\\"\\\"\\n\\toldMorph delete! !\\nSimpleHierarchicalListMorph subclass: #MorphHierarchyListMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Widgets'!\\n\\n!MorphHierarchyListMorph methodsFor: 'private' stamp: 'dgd 9/26/2004 18:57'!\\ncreateContainer\\n\\t\\\"Private - Create a container\\\"\\n\\t| container |\\n\\tcontainer := BorderedMorph new.\\n\\tcontainer extent: (World extent * (1 / 4 @ (2 / 3))) rounded.\\n\\tcontainer layoutPolicy: TableLayout new.\\n\\tcontainer hResizing: #rigid.\\n\\tcontainer vResizing: #rigid.\\n\\tcontainer\\n\\t\\tsetColor: Preferences menuColor\\n\\t\\tborderWidth: Preferences menuBorderWidth\\n\\t\\tborderColor: Preferences menuBorderColor.\\n\\tcontainer layoutInset: 0.\\n\\t\\\"container useRoundedCorners.\\\"\\n\\t\\\"\\\"\\n\\tcontainer setProperty: #morphHierarchy toValue: true.\\n\\tcontainer setNameTo: 'Objects Hierarchy' translated.\\n\\t\\\"\\\"\\n\\t^ container! !\\n\\n!MorphHierarchyListMorph methodsFor: 'private' stamp: 'dgd 9/26/2004 18:27'!\\ninAContainer\\n\\t\\\"Answer the receiver contained in a proper container\\\"\\n\\t| container |\\n\\tcontainer := self createContainer.\\n\\tcontainer addMorphBack: self.\\n\\t\\\" \\n\\tnasty hack to force the scroolbar recreation\\\"\\n\\tself extent: container extent - container borderWidth.\\n\\t\\\"\\\"\\n\\t^ container! !\\n\\n\\n!MorphHierarchyListMorph methodsFor: 'initialization' stamp: 'dgd 9/26/2004 18:18'!\\non: anObject list: getListSel selected: getSelectionSel changeSelected: setSelectionSel menu: getMenuSel keystroke: keyActionSel \\n\\tsuper\\n\\t\\ton: anObject\\n\\t\\tlist: getListSel\\n\\t\\tselected: getSelectionSel\\n\\t\\tchangeSelected: setSelectionSel\\n\\t\\tmenu: getMenuSel\\n\\t\\tkeystroke: keyActionSel.\\n\\t\\\"\\\"\\n\\tself borderWidth: 0.\\n\\tself autoDeselect: false.\\n\\tself enableDrag: false.\\n\\tself enableDrop: true.\\n\\tself hResizing: #spaceFill.\\n\\tself vResizing: #spaceFill.\\nself expandRoots! !\\n\\n\\n!MorphHierarchyListMorph methodsFor: 'selection' stamp: 'dgd 9/25/2004 21:28'!\\nsetSelectedMorph: aMorph \\n\\tsuper setSelectedMorph: aMorph.\\nself owner isNil ifFalse:[self owner delete]! !\\nListItemWrapper subclass: #MorphListItemWrapper\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Widgets'!\\n\\n!MorphListItemWrapper methodsFor: 'converting' stamp: 'dgd 9/26/2004 18:26'!\\nasString\\n\\t\\\"Answer the string representation of the receiver\\\"\\n\\t^ item externalName! !\\n\\n\\n!MorphListItemWrapper methodsFor: 'accessing' stamp: 'dgd 1/7/2005 20:01'!\\ncontents\\n\\t\\\"Answer the receiver's contents\\\"\\n\\n\\t| tentative submorphs |\\n\\ttentative := item submorphs\\n\\t\\t\\t\\tcollect: [:each | each renderedMorph].\\n\\n\\tsubmorphs := Preferences noviceMode\\n\\t\\t\\t\\tifTrue: [\\\"\\\"\\n\\t\\t\\t\\t\\ttentative\\n\\t\\t\\t\\t\\t\\treject: [:each | \\\"\\\"\\n\\t\\t\\t\\t\\t\\t\\teach isSystemWindow\\n\\t\\t\\t\\t\\t\\t\\t\\tor: [each isDockingBar]\\n\\t\\t\\t\\t\\t\\t\\t\\tor: [each isKindOf: HaloMorph]\\n\\t\\t\\t\\t\\t\\t\\t\\tor: [each hasProperty: #morphHierarchy]\\n\\t\\t\\t\\t\\t\\t\\t\\tor: [each isFlapOrTab]\\n\\t\\t\\t\\t\\t\\t\\t\\tor: [each isObjectsTool]]]\\n\\t\\t\\t\\tifFalse: [\\\"\\\"\\n\\t\\t\\t\\t\\ttentative\\n\\t\\t\\t\\t\\t\\treject: [:each | each isKindOf: HaloMorph]].\\n\\n\\t^ submorphs\\n\\t\\tcollect: [:each | self class with: each]! !\\n\\n!MorphListItemWrapper methodsFor: 'accessing' stamp: 'dgd 7/28/2005 13:03'!\\nicon\\n\\t\\\"Answer a form to be used as icon\\\"\\n\\t^ item iconOrThumbnailOfSize: ((Preferences tinyDisplay ifTrue: [16] ifFalse: [28]))! !\\nObjectOut subclass: #MorphObjectOut\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SqueakPage'!\\n\\n!MorphObjectOut methodsFor: 'as yet unclassified' stamp: 'tk 4/6/1999 10:00'!\\ndoesNotUnderstand: aMessage \\n\\t\\\"Bring in the object, install, then resend aMessage\\\"\\n\\t| aMorph myUrl oldFlag response |\\n\\t\\\"Transcript show: thisContext sender selector; cr.\\\" \\\"useful for debugging\\\"\\n\\toldFlag _ recursionFlag.\\n\\trecursionFlag _ true.\\n\\tmyUrl _ url.\\t\\\"can't use inst vars after become\\\"\\n\\t\\\"fetch the object\\\"\\n\\taMorph _ self xxxFetch.\\t\\t\\\"watch out for the become!!\\\"\\n\\t\\t\\t\\\"Now we ARE a MORPH\\\"\\n\\toldFlag == true ifTrue: [\\n\\t\\tresponse _ (PopUpMenu labels: 'proceed normally\\\\debug' withCRs)\\n\\t\\t\\tstartUpWithCaption: 'Object being fetched for a second time.\\nShould not happen, and needs to be fixed later.'.\\n\\t\\tresponse = 2 ifTrue: [self halt]].\\t\\\"We are already the new object\\\"\\n\\n\\taMorph setProperty: #SqueakPage toValue: \\n\\t\\t\\t(SqueakPageCache pageCache at: myUrl).\\n\\t\\\"Can't be a super message, since this is the first message sent to this object\\\"\\n\\t^ aMorph perform: aMessage selector withArguments: aMessage arguments\\n! !\\n\\n!MorphObjectOut methodsFor: 'as yet unclassified' stamp: 'tk 10/22/1998 15:43'!\\nfullReleaseCachedState\\n\\t\\\"do nothing, especially don't bring in my object!!\\\"! !\\n\\n!MorphObjectOut methodsFor: 'as yet unclassified' stamp: 'tk 2/24/1999 00:08'!\\nsmallThumbnailForPageSorter\\n\\n\\t^ self sqkPage thumbnail! !\\n\\n!MorphObjectOut methodsFor: 'as yet unclassified' stamp: 'tk 2/24/1999 00:09'!\\nthumbnailForPageSorter\\n\\n\\t^ self sqkPage thumbnail! !\\nTestCase subclass: #MorphTest\\n\\tinstanceVariableNames: 'morph world'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicTests-Kernel'!\\n!MorphTest commentStamp: '<historical>' prior: 0!\\nThis is the unit test for the class Morph. Unit tests are a good way to exercise the functionality of your system in a repeatable and automatic manner. They are therefore recommended if you plan to release anything. For more information, see: \\n\\t- http://www.c2.com/cgi/wiki?UnitTest\\n\\t- http://minnow.cc.gatech.edu/squeak/1547\\n\\t- the sunit class category!\\n\\n\\n!MorphTest methodsFor: 'initialize-release' stamp: 'tak 1/21/2005 11:12'!\\ngetWorld\\n\\t^ world\\n\\t\\tifNil: [world := Project newMorphic world]! !\\n\\n!MorphTest methodsFor: 'initialize-release' stamp: 'tak 1/21/2005 11:12'!\\nsetUp\\n\\tmorph := Morph new! !\\n\\n!MorphTest methodsFor: 'initialize-release' stamp: 'tak 1/21/2005 11:12'!\\ntearDown\\n\\tmorph delete.\\n\\tworld\\n\\t\\tifNotNil: [Project deletingProject: world project]! !\\n\\n\\n!MorphTest methodsFor: 'testing - classification' stamp: 'md 4/16/2003 17:11'!\\ntestIsMorph\\n\\tself assert: (morph isMorph).! !\\n\\n\\n!MorphTest methodsFor: 'testing - etoys' stamp: 'tak 1/21/2005 11:31'!\\ntestOverlapAny\\n\\t\\\"self debug: #testOverlapAny\\\"\\n\\t| p1 p2 |\\n\\tp1 _ Morph new assuredPlayer.\\n\\tp2 _ EllipseMorph new assuredPlayer.\\n\\t\\\"Same position\\\"\\n\\tp1 costume position: 0@0.\\n\\tp2 costume position: 0@0.\\n\\tself assert: (p1 overlapsAny: p2).\\n\\t\\\"Different position\\\"\\n\\tp1 costume position: 0@0.\\n\\tp2 costume position: 500@0.\\n\\tself assert: (p1 overlapsAny: p2) not.! !\\n\\n!MorphTest methodsFor: 'testing - etoys' stamp: 'tak 1/21/2005 11:56'!\\ntestOverlapAnyDeletedPlayer\\n\\t\\\"self debug: #testOverlapAnyDeletedPlayer\\\"\\n\\t| me friend sibling |\\n\\tme := Morph new assuredPlayer assureUniClass; yourself.\\n\\tfriend := EllipseMorph new assuredPlayer assureUniClass; yourself.\\n\\tsibling := friend getNewClone.\\n\\tsibling costume delete.\\n\\tself getWorld addMorph: me costume.\\n\\t\\\"Same position but deleted\\\"\\n\\tme costume position: 0 @ 0.\\n\\tfriend costume position: 0 @ 0.\\n\\tsibling costume position: 0 @ 0.\\n\\tself assert: (me overlapsAny: friend) not.\\n\\tself assert: (me overlapsAny: sibling) not! !\\n\\n!MorphTest methodsFor: 'testing - etoys' stamp: 'tak 1/21/2005 11:40'!\\ntestOverlapAnyScriptedPlayer\\n\\t\\\"self debug: #testOverlapAnyScriptedPlayer\\\"\\n\\t| me friend other sibling |\\n\\tme := Morph new assuredPlayer assureUniClass; yourself.\\n\\tfriend := EllipseMorph new assuredPlayer assureUniClass; yourself.\\n\\tsibling := friend getNewClone.\\n\\tother := EllipseMorph new assuredPlayer assureUniClass; yourself.\\n\\tself getWorld addMorph: me costume;\\n\\t\\t addMorph: friend costume;\\n\\t\\t addMorph: other costume;\\n\\t\\t addMorph: sibling costume.\\n\\t\\\"myself\\\"\\n\\tself assert: (me overlapsAny: me) not.\\n\\t\\\"Same position with sibling\\\"\\n\\tme costume position: 0 @ 0.\\n\\tfriend costume position: 500 @ 0.\\n\\tother costume position: 500 @ 0.\\n\\tsibling costume position: 0@0.\\n\\tself assert: (me overlapsAny: friend).\\n\\t\\\"Different position with sibling but same class\\\"\\n\\tme costume position: 0 @ 0.\\n\\tfriend costume position: 500 @ 0.\\n\\tsibling costume position: 500@ 0.\\n\\tother costume position: 0 @ 0.\\n\\tself assert: (me overlapsAny: friend) not! !\\n\\n!MorphTest methodsFor: 'testing - etoys' stamp: 'tak 1/21/2005 11:32'!\\ntestOverlapAnyUnscriptedPlayer\\n\\t\\\"self debug: #testOverlapAnyUnscriptedPlayer\\\"\\n\\t| p1 p2 p3 |\\n\\tp1 := Morph new assuredPlayer.\\n\\tp2 := EllipseMorph new assuredPlayer.\\n\\tp3 := EllipseMorph new assuredPlayer.\\n\\tself getWorld addMorph: p1 costume;\\n\\t\\t addMorph: p2 costume;\\n\\t\\t addMorph: p3 costume.\\n\\t\\\"Same class, same position\\\"\\n\\tp1 costume position: 0 @ 0.\\n\\tp2 costume position: 500 @ 0.\\n\\tp3 costume position: 0 @ 0.\\n\\tself\\n\\t\\tassert: (p1 overlapsAny: p2).\\n\\t\\\"Same class, different position\\\"\\n\\tp1 costume position: 0 @ 0.\\n\\tp2 costume position: 1000 @ 0.\\n\\tp3 costume position: 500 @ 0.\\n\\tself assert: (p1 overlapsAny: p2) not.\\n! !\\n\\n\\n!MorphTest methodsFor: 'testing - initialization' stamp: 'md 4/16/2003 17:10'!\\ntestOpenInWorld\\n\\tself shouldnt: [morph openInWorld] raise: Error.! !\\n\\n\\n!MorphTest methodsFor: 'testing - into/outOf World' stamp: 'ar 8/4/2003 00:11'!\\ntestIntoWorldCollapseOutOfWorld\\n\\t| m1 m2 collapsed |\\n\\t\\\"Create the guys\\\"\\n\\tm1 := TestInWorldMorph new.\\n\\tm2 := TestInWorldMorph new.\\n\\tself assert: (m1 intoWorldCount = 0).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 0).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\t\\\"add them to basic morph\\\"\\n\\tmorph addMorphFront: m1.\\n\\tm1 addMorphFront: m2.\\n\\tself assert: (m1 intoWorldCount = 0).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 0).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\t\\\"open the guy\\\"\\n\\tmorph openInWorld.\\n\\tself assert: (m1 intoWorldCount = 1).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 1).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\t\\\"collapse it\\\"\\n\\tcollapsed := \\tCollapsedMorph new beReplacementFor: morph.\\n\\tself assert: (m1 intoWorldCount = 1).\\n\\tself assert: (m1 outOfWorldCount = 1).\\n\\tself assert: (m2 intoWorldCount = 1).\\n\\tself assert: (m2 outOfWorldCount = 1).\\n\\n\\t\\\"expand it\\\"\\n\\tcollapsed collapseOrExpand.\\n\\tself assert: (m1 intoWorldCount = 2).\\n\\tself assert: (m1 outOfWorldCount = 1).\\n\\tself assert: (m2 intoWorldCount = 2).\\n\\tself assert: (m2 outOfWorldCount = 1).\\n\\n\\t\\\"delete it\\\"\\n\\tmorph delete.\\n\\tself assert: (m1 intoWorldCount = 2).\\n\\tself assert: (m1 outOfWorldCount = 2).\\n\\tself assert: (m2 intoWorldCount = 2).\\n\\tself assert: (m2 outOfWorldCount = 2).\\n! !\\n\\n!MorphTest methodsFor: 'testing - into/outOf World' stamp: 'ar 8/4/2003 00:12'!\\ntestIntoWorldDeleteOutOfWorld\\n\\t| m1 m2 |\\n\\t\\\"Create the guys\\\"\\n\\tm1 := TestInWorldMorph new.\\n\\tm2 := TestInWorldMorph new.\\n\\tself assert: (m1 intoWorldCount = 0).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 0).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\tmorph addMorphFront: m1.\\n\\tm1 addMorphFront: m2.\\n\\tself assert: (m1 intoWorldCount = 0).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 0).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\tmorph openInWorld.\\n\\tself assert: (m1 intoWorldCount = 1).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 1).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\tmorph delete.\\n\\tself assert: (m1 intoWorldCount = 1).\\n\\tself assert: (m1 outOfWorldCount = 1).\\n\\tself assert: (m2 intoWorldCount = 1).\\n\\tself assert: (m2 outOfWorldCount = 1).\\n\\t! !\\n\\n!MorphTest methodsFor: 'testing - into/outOf World' stamp: 'ar 8/10/2003 18:30'!\\ntestIntoWorldTransferToNewGuy\\n\\t| m1 m2 |\\n\\t\\\"Create the guys\\\"\\n\\tm1 := TestInWorldMorph new.\\n\\tm2 := TestInWorldMorph new.\\n\\tself assert: (m1 intoWorldCount = 0).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 0).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\tmorph addMorphFront: m1.\\n\\tm1 addMorphFront: m2.\\n\\tself assert: (m1 intoWorldCount = 0).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 0).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\tmorph openInWorld.\\n\\tself assert: (m1 intoWorldCount = 1).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 1).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\tmorph addMorphFront: m2.\\n\\tself assert: (m1 intoWorldCount = 1).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 1).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\tmorph addMorphFront: m1.\\n\\tself assert: (m1 intoWorldCount = 1).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 1).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\tm2 addMorphFront: m1.\\n\\tself assert: (m1 intoWorldCount = 1).\\n\\tself assert: (m1 outOfWorldCount = 0).\\n\\tself assert: (m2 intoWorldCount = 1).\\n\\tself assert: (m2 outOfWorldCount = 0).\\n\\n\\tmorph delete.\\n\\tself assert: (m1 intoWorldCount = 1).\\n\\tself assert: (m1 outOfWorldCount = 1).\\n\\tself assert: (m2 intoWorldCount = 1).\\n\\tself assert: (m2 outOfWorldCount = 1).\\n! !\\nSketchMorph subclass: #MorphThumbnail\\n\\tinstanceVariableNames: 'morphRepresented'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Books'!\\n!MorphThumbnail commentStamp: '<historical>' prior: 0!\\nA morph whose appearance is a thumbnail of some other morph.!\\n\\n\\n!MorphThumbnail methodsFor: 'as yet unclassified' stamp: 'sw 11/13/1998 09:53'!\\ncomputeThumbnail\\n\\t\\\"Assumption on entry:\\n The receiver's width represents the maximum width allowable.\\n The receiver's height represents the exact height desired.\\\"\\n\\n\\t| f scaleX scaleY |\\n\\tf _ morphRepresented imageForm.\\n\\tmorphRepresented fullReleaseCachedState.\\n\\tscaleY _ self height / f height. \\\"keep height invariant\\\"\\n\\tscaleX _ ((morphRepresented width * scaleY) <= self width)\\n\\t\\tifTrue:\\n\\t\\t\\t[scaleY] \\\"the usual case; same scale factor, to preserve aspect ratio\\\"\\n\\t\\tifFalse:\\n\\t\\t\\t[self width / f width].\\n\\tself form: (f magnify: f boundingBox by: (scaleX @ scaleY) smoothing: 2).\\n\\tself extent: originalForm extent! !\\n\\n!MorphThumbnail methodsFor: 'as yet unclassified' stamp: 'sw 7/6/1998 22:08'!\\ngrabOriginal\\n\\tself primaryHand attachMorph: morphRepresented! !\\n\\n!MorphThumbnail methodsFor: 'as yet unclassified' stamp: 'ar 10/7/2000 15:38'!\\nmorphRepresented: aMorph\\n\\n\\tmorphRepresented _ aMorph.\\n\\tself computeThumbnail.\\n! !\\n\\n!MorphThumbnail methodsFor: 'as yet unclassified' stamp: 'md 10/22/2003 15:24'!\\nrevealOriginal\\n\\t((owner isKindOf: PasteUpMorph) and: [owner alwaysShowThumbnail]) \\n\\t\\tifTrue: [^Beeper beep].\\n\\tmorphRepresented owner isNil \\n\\t\\tifTrue: [^owner replaceSubmorph: self by: morphRepresented].\\n\\tBeeper beep! !\\n\\n!MorphThumbnail methodsFor: 'as yet unclassified' stamp: 'sw 8/10/1998 07:05'!\\nsmaller\\n\\tself form: (self form copy: (0@0 extent: self form extent // 2))! !\\n\\n\\n!MorphThumbnail methodsFor: 'copying' stamp: 'tk 1/8/1999 09:39'!\\nveryDeepFixupWith: deepCopier\\n\\t\\\"If target and arguments fields were weakly copied, fix them here. If they were in the tree being copied, fix them up, otherwise point to the originals!!!!\\\"\\n\\nsuper veryDeepFixupWith: deepCopier.\\nmorphRepresented _ deepCopier references at: morphRepresented \\n\\t\\tifAbsent: [morphRepresented].! !\\n\\n!MorphThumbnail methodsFor: 'copying' stamp: 'tk 1/8/1999 09:39'!\\nveryDeepInner: deepCopier\\n\\t\\\"Copy all of my instance variables. Some need to be not copied at all, but shared. \\tWarning!!!! Every instance variable defined in this class must be handled. We must also implement veryDeepFixupWith:. See DeepCopier class comment.\\\"\\n\\nsuper veryDeepInner: deepCopier.\\nmorphRepresented _ morphRepresented.\\t\\t\\\"Weakly copied\\\"! !\\n\\n\\n!MorphThumbnail methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:28'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color lightGray! !\\n\\n!MorphThumbnail methodsFor: 'initialization' stamp: 'dgd 2/14/2003 21:51'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\t| f |\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\n\\tf _ Form extent: 60 @ 80 depth: Display depth.\\n\\tf fill: f boundingBox fillColor: color.\\n\\tself form: f! !\\n\\n\\n!MorphThumbnail methodsFor: 'menus' stamp: 'dgd 8/30/2003 21:53'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\tsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.\\n\\taCustomMenu add: 'reveal original morph' translated action: #revealOriginal.\\n\\taCustomMenu add: 'grab original morph' translated action: #grabOriginal.\\n! !\\n\\n\\n!MorphThumbnail methodsFor: 'naming' stamp: 'bf 3/31/1999 12:24'!\\ninnocuousName\\n\\t^ morphRepresented isNil\\n\\t\\tifTrue: [super innocuousName]\\n\\t\\tifFalse: [morphRepresented innocuousName]! !\\n\\n\\n!MorphThumbnail methodsFor: 'parts bin' stamp: 'dgd 2/16/2003 21:37'!\\nisPartsDonor\\n\\t\\\"answer whether the receiver is PartsDonor\\\"\\n\\t^ self partRepresented isPartsDonor! !\\n\\n!MorphThumbnail methodsFor: 'parts bin' stamp: 'dgd 2/16/2003 21:40'!\\nisPartsDonor: aBoolean\\n\\t\\\"change the receiver's isPartDonor property\\\"\\n\\tself partRepresented isPartsDonor: aBoolean! !\\n\\n!MorphThumbnail methodsFor: 'parts bin' stamp: 'ar 10/6/2000 22:46'!\\npartRepresented\\n\\t^self morphRepresented! !\\n\\n\\n!MorphThumbnail methodsFor: 'thumbnail' stamp: 'jm 11/17/97 17:30'!\\nmorphRepresented\\n\\n\\t^ morphRepresented\\n! !\\n\\n!MorphThumbnail methodsFor: 'thumbnail' stamp: 'bf 3/31/1999 07:54'!\\nrepresentativeNoTallerThan: maxHeight norWiderThan: maxWidth thumbnailHeight: thumbnailHeight\\n\\n\\t\\\"Return a morph representing the receiver but which is no taller than aHeight. If the receiver is already small enough, just return it, else return a MorphThumbnail companioned to the receiver, enforcing the maxWidth\\\"\\n\\n\\t(self height <= maxHeight and: [self width <= maxWidth]) ifTrue: [^ self].\\n\\n\\t^ MorphThumbnail new\\n\\t\\textent: maxWidth @ (thumbnailHeight min: self height);\\n\\t\\tmorphRepresented: morphRepresented! !\\nListItemWrapper subclass: #MorphWithSubmorphsWrapper\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Explorer'!\\n!MorphWithSubmorphsWrapper commentStamp: 'ls 3/1/2004 17:32' prior: 0!\\nDisplay a morph in a SimpleHierarchicalListMorph, and arrange to recursively display the morph's submorphs. The \\\"item\\\" that is wrapped is the morph to display.!\\n\\n\\n!MorphWithSubmorphsWrapper methodsFor: 'hierarchy' stamp: 'ls 3/1/2004 17:34'!\\ncontents\\n\\t^item submorphs collect: [ :m |\\n\\t\\tself class with: m ]! !\\nController subclass: #MorphWorldController\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-ST80'!\\n!MorphWorldController commentStamp: '<historical>' prior: 0!\\nI am a controller for SceneViews. I support gestures for scrolling, click-selection, and area selection of scene glyphs. (See the class comment in GestureController for more details about gestures.) I also support construction operations such as inserting new glyphs and merging glyphs to make them share a common point.\\n\\nThe mapping of gestures to actions is as follows (see GestureController comment for more about gestures):\\n\\n Click:\\n\\tclick on glyph\\t\\t\\t\\tselect glyph\\n\\tshift-click on glyph\\t\\t\\ttoggle selection of that glyph\\n\\tclick on background\\t\\t\\tclear selection\\n Double click:\\n\\tdouble-click on glyph\\t\\t\\tinspect glyph\\n\\tdouble-click on background\\t\\tselect all\\n Hold/Drag/Sweep:\\n\\thold (no movement)\\t\\t\\tyellow-button menu\\n\\tdrag (up/left movement)\\t\\tscrolling hand\\n\\tsweep (down/right movement)\\tselect glyphs in region\\n\\tshift-sweep\\t\\t\\t\\t\\ttoggle selection of glyphs in region\\n!\\n\\n\\n!MorphWorldController methodsFor: 'basic control sequence' stamp: 'di 11/26/1999 10:00'!\\ncontrolInitialize\\n\\t\\\"This window is becoming active.\\\"\\n\\n\\ttrue ifTrue: [model becomeTheActiveWorldWith: nil].\\n\\n\\tmodel canvas ifNil: [ \\\"i.e., only on first entry\\\"\\n\\t\\t\\\"In case of, eg, inspect during balloon help...\\\"\\n\\t\\tmodel submorphsDo: [:m | \\\"delete any existing balloons\\\"\\n\\t\\t\\t(m isKindOf: BalloonMorph) ifTrue: [m delete]].\\n\\n\\t\\tmodel handsDo: [:h | h initForEvents].\\n\\t\\tview displayView]. \\\"initializes the WorldMorph's canvas\\\"\\n! !\\n\\n!MorphWorldController methodsFor: 'basic control sequence' stamp: 'di 11/16/2001 22:43'!\\ncontrolLoop \\n\\t\\\"Overridden to keep control active when the hand goes out of the view\\\"\\n\\n\\t| db |\\n\\t[self viewHasCursor \\\"working in the window\\\"\\n\\t\\tor: [Sensor noButtonPressed \\\"wandering with no button pressed\\\"\\n\\t\\tor: [model primaryHand submorphs size > 0 \\\"dragging something outside\\\"]]]\\n\\t\\twhileTrue: \\\"... in other words anything but clicking outside\\\"\\n\\t\\t\\t[self controlActivity.\\n\\n\\t\\t\\t\\\"Check for reframing since we hold control here\\\"\\n\\t\\t\\tdb _ view superView displayBox.\\n\\t\\t\\tview superView controller checkForReframe.\\n\\t\\t\\tdb = view superView displayBox ifFalse:\\n\\t\\t\\t\\t[self controlInitialize \\\"reframe world if bounds changed\\\"]].\\n! !\\n\\n!MorphWorldController methodsFor: 'basic control sequence' stamp: 'di 11/16/2001 13:58'!\\ncontrolTerminate \\n\\t\\\"This window is becoming inactive; restore the normal cursor.\\\"\\n\\n\\tCursor normal show.\\n\\tActiveWorld _ ActiveHand _ ActiveEvent _ nil! !\\n\\n\\n!MorphWorldController methodsFor: 'control defaults' stamp: 'jm 2/20/98 13:37'!\\ncontrolActivity\\n\\t\\\"Do one step of the Morphic interaction loop. Called repeatedly while window is active.\\\"\\n\\n\\tmodel doOneCycle.\\n! !\\n\\n!MorphWorldController methodsFor: 'control defaults' stamp: 'jm 6/17/97 10:29'!\\nisControlActive\\n\\n\\t^ sensor redButtonPressed or: [self viewHasCursor]! !\\nView subclass: #MorphWorldView\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'FullColorWhenInactive'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-ST80'!\\n!MorphWorldView commentStamp: '<historical>' prior: 0!\\nI am a view used to display a Scene. I may be scrolled by adjusting my offset. My default controller is SceneController.\\n\\nSceneViews encapsulate the notion of a changing foreground and a fixed background during interactive updates. During an interaction (such as dragging), some of the glyphs will not change location or appearance. These are part of the \\\"background\\\". All glyphs that may change (the \\\"foreground\\\" glyphs) are painted against this unchanging backdrop during the interaction.\\n\\nInstance Variables:\\n\\toffset\\t\\t\\t\\tthe current offset of this view (used for scrolling)\\n\\tenclosingRect \\t\\ta rectangle large enough to contain all the objects in the scene, plus a small border (this is a cache that must be recomputed when glyphs are moved, added, or removed from the scene)\\n\\tbackgroundForm\\t\\ta <Form> containing the fixed background\\n\\tvisibleForeground\\t\\tthe glyphs that are changing but not selected during an interaction\\n\\tselectedForeground\\tthe selected glyphs that are changing during an interaction!\\n\\n\\n!MorphWorldView methodsFor: 'as yet unclassified' stamp: 'md 2/24/2006 21:24'!\\nupdateSubWindowExtent\\n\\t\\\"If this MorphWorldView represents a single Morphic SystemWindow, then update that window to match the size of the WorldView.\\\"\\n\\n\\t| numMorphs subWindow |\\n\\tnumMorphs := model submorphs size.\\n\\t\\\"(Allow for the existence of an extra NewHandleMorph (for resizing).)\\\"\\n\\t(numMorphs = 0 or: [numMorphs > 2]) ifTrue: [^self].\\n\\tsubWindow := model submorphs detect: [:ea | ea respondsTo: #label]\\n\\t\\t\\t\\tifNone: [^self].\\n\\tsuperView label = subWindow label ifFalse: [^self].\\n\\tsubWindow position: model position + (0 @ -16).\\t\\\"adjust for WiW changes\\\"\\n\\tsubWindow extent: model extent - (0 @ -16).\\n\\tsubWindow isActive ifFalse: [subWindow activate]! !\\n\\n\\n!MorphWorldView methodsFor: 'controller access'!\\ndefaultControllerClass\\n\\n\\t^ MorphWorldController! !\\n\\n\\n!MorphWorldView methodsFor: 'deEmphasizing' stamp: 'RAA 5/24/2000 10:34'!\\ndeEmphasizeView \\n\\t\\\"This window is becoming inactive.\\\"\\n\\n\\tCursor normal show. \\\"restore the normal cursor\\\"\\n\\tmodel deEmphasizeViewMVC: self topView cacheBitsAsTwoTone.\\n! !\\n\\n\\n!MorphWorldView methodsFor: 'displaying' stamp: 'dew 11/8/1999 02:01'!\\ndisplayView\\n\\t\\\"This method is called by the system when the top view is framed or moved.\\\"\\n\\t| topView |\\n\\tmodel viewBox: self insetDisplayBox.\\n\\tself updateSubWindowExtent.\\n\\ttopView _ self topView.\\n\\t(topView == ScheduledControllers scheduledControllers first view\\n\\t\\tor: [topView cacheBitsAsTwoTone not])\\n\\t\\tifTrue: [model displayWorldSafely]\\n\\t\\tifFalse: [model displayWorldAsTwoTone]. \\\"just restoring the screen\\\"! !\\n\\n\\n!MorphWorldView methodsFor: 'updating' stamp: 'sw 9/26/97 20:56'!\\nupdate: symbol\\n\\n\\t^ symbol == #newColor\\n\\t\\tifTrue: [self topView backgroundColor: model color dominantColor; uncacheBits; display]\\n\\t\\tifFalse: [super update: symbol].\\n! !\\n\\n\\n!MorphWorldView methodsFor: 'private' stamp: 'dew 11/8/1999 02:00'!\\ncomputeInsetDisplayBox\\n\\t\\\"This overrides the same method in View. (It avoids using displayTransform: because it can return inaccurate results, causing a MorphWorldView's inset display box to creep inward when resized.)\\\"\\n\\n\\t^superView insetDisplayBox insetBy: borderWidth! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphWorldView class\\n\\tinstanceVariableNames: ''!\\n\\n!MorphWorldView class methodsFor: 'instance creation' stamp: 'nk 7/30/2004 21:52'!\\nconvertToMVCWiWPasteUpMorph\\n\\t\\\"\\nMorphWorldView convertToMVCWiWPasteUpMorph\\n\\\"\\n\\n\\t| current w newModel topView |\\n\\tSmalltalk isMorphic ifTrue: [^self inform: 'do this in MVC'].\\n\\tcurrent := self allInstances \\n\\t\\t\\t\\tselect: [:each | each model class == PasteUpMorph].\\n\\tcurrent do: \\n\\t\\t\\t[:oldWorldView | \\n\\t\\t\\tw := MVCWiWPasteUpMorph newWorldForProject: nil.\\n\\t\\t\\tw\\n\\t\\t\\t\\tcolor: oldWorldView model color;\\n\\t\\t\\t\\taddAllMorphs: oldWorldView model submorphs.\\n\\t\\t\\tnewModel := CautiousModel new initialExtent: 300 @ 300.\\n\\t\\t\\ttopView := self fullColorWhenInactive \\n\\t\\t\\t\\t\\t\\tifTrue: [ColorSystemView new]\\n\\t\\t\\t\\t\\t\\tifFalse: [StandardSystemView new].\\n\\t\\t\\ttopView\\n\\t\\t\\t\\tmodel: newModel;\\n\\t\\t\\t\\tlabel: oldWorldView topView label;\\n\\t\\t\\t\\tborderWidth: 1;\\n\\t\\t\\t\\taddSubView: (self new model: w);\\n\\t\\t\\t\\tbackgroundColor: w color.\\n\\t\\t\\ttopView controller openNoTerminate.\\n\\t\\t\\ttopView reframeTo: (oldWorldView topView expandedFrame \\n\\t\\t\\t\\t\\t\\texpandBy: (0 @ 0 extent: 0 @ topView labelHeight)).\\n\\t\\t\\toldWorldView topView controller closeAndUnscheduleNoTerminate].\\n\\tScheduledControllers restore.\\n\\tProcessor terminateActive! !\\n\\n!MorphWorldView class methodsFor: 'instance creation'!\\nfullColorWhenInactive\\n\\n\\tFullColorWhenInactive ifNil: [FullColorWhenInactive _ true].\\n\\t^ FullColorWhenInactive\\n! !\\n\\n!MorphWorldView class methodsFor: 'instance creation' stamp: 'di 2/26/98 09:17'!\\nfullColorWhenInactive: fullColor\\n\\t\\\"MorphWorldView fullColorWhenInactive: true\\\"\\n\\t\\\"If FullColorWhenInactive is true then WorldMorphViews will created inside StandardSystemViews that cache their contents in full-color when the window is inactive. If it is false, only a half-tone gray approximation of the colors will be cached to save space.\\\"\\n\\n\\tFullColorWhenInactive _ fullColor.\\n\\n\\t\\\"Retroactively convert all extant windows\\\"\\n\\t((fullColor ifTrue: [StandardSystemView] ifFalse: [ColorSystemView])\\n\\t\\tallInstances select:\\n\\t\\t\\t[:v | v subViews notNil and: [v subViews isEmpty not and: [v firstSubView isKindOf: MorphWorldView]]])\\n\\t\\tdo: [:v | v uncacheBits.\\n\\t\\t\\tv controller toggleTwoTone]! !\\n\\n!MorphWorldView class methodsFor: 'instance creation'!\\nopenOn: aMorphWorld\\n\\t\\\"Open a view on the given WorldMorph.\\\"\\n\\n\\tself openOn: aMorphWorld label: 'A Morphic World'.! !\\n\\n!MorphWorldView class methodsFor: 'instance creation' stamp: 'sw 10/2/97 23:17'!\\nopenOn: aWorldMorph label: aString\\n\\t\\\"Open a view with the given label on the given WorldMorph.\\\"\\n\\t^ self openOn: aWorldMorph label: aString model: (CautiousModel new initialExtent: aWorldMorph initialExtent)! !\\n\\n!MorphWorldView class methodsFor: 'instance creation' stamp: 'sw 9/21/1998 17:54'!\\nopenOn: aWorldMorph label: aString cautionOnClose: aBoolean\\n\\t\\\"Open a view with the given label on the given WorldMorph.\\\"\\n\\t| aModel |\\n\\taModel _ aBoolean\\n\\t\\tifTrue:\\t\\t[CautiousModel new]\\n\\t\\tifFalse:\\t\\t[WorldViewModel new].\\n\\t^ self openOn: aWorldMorph label: aString model: (aModel initialExtent: aWorldMorph initialExtent)! !\\n\\n!MorphWorldView class methodsFor: 'instance creation' stamp: 'jm 1/31/98 20:24'!\\nopenOn: aWorldMorph label: aString extent: aPoint\\n\\t\\\"Open a view with the given label and extent on the given WorldMorph.\\\"\\n\\n\\t^ self openOn: aWorldMorph\\n\\t\\tlabel: aString\\n\\t\\tmodel: (CautiousModel new initialExtent: aPoint)\\n! !\\n\\n!MorphWorldView class methodsFor: 'instance creation' stamp: 'nk 7/30/2004 22:37'!\\nopenOn: aWorldMorph label: aString model: aModel \\n\\t\\\"Open a view with the given label on the given WorldMorph.\\\"\\n\\n\\t| topView |\\n\\ttopView := self fullColorWhenInactive \\n\\t\\t\\t\\tifTrue: [topView := ColorSystemView new]\\n\\t\\t\\t\\tifFalse: [topView := StandardSystemView new].\\n\\ttopView\\n\\t\\tmodel: aModel;\\n\\t\\tlabel: aString;\\n\\t\\tborderWidth: 1;\\n\\t\\taddSubView: (self new model: aWorldMorph);\\n\\t\\tbackgroundColor: aWorldMorph color.\\n\\t\\\"minimumSize: aWorldMorph extent + (2@2); \\\"\\t\\\"add border width\\\"\\n\\ttopView controller open! !\\n\\n!MorphWorldView class methodsFor: 'instance creation' stamp: 'di 11/26/1999 11:46'!\\nopenWorld\\n\\n\\t| w |\\n\\t(w _ MVCWiWPasteUpMorph newWorldForProject: nil).\\n\\tw bounds: (0@0 extent: 400@300).\\n\\tself openOn: w\\n\\t\\tlabel: 'A Morphic World'\\n\\t\\textent: w fullBounds extent + 2.\\n! !\\n\\n!MorphWorldView class methodsFor: 'instance creation' stamp: 'sma 6/12/2000 14:18'!\\nopenWorldWith: aMorph labelled: labelString\\n\\n\\t| w |\\n\\t(w _ MVCWiWPasteUpMorph newWorldForProject: nil) addMorph: aMorph.\\n\\tw extent: aMorph fullBounds extent.\\n\\tw startSteppingSubmorphsOf: aMorph.\\n\\tself openOn: w\\n\\t\\tlabel: labelString\\n\\t\\textent: w fullBounds extent + 2.\\n! !\\nMessageSend subclass: #MorphicAlarm\\n\\tinstanceVariableNames: 'scheduledTime numArgs'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Events'!\\n\\n!MorphicAlarm methodsFor: 'accessing' stamp: 'ar 9/11/2000 16:44'!\\nscheduledTime\\n\\t\\\"Return the time (in milliseconds) that the receiver is scheduled to be executed\\\"\\n\\t^scheduledTime! !\\n\\n!MorphicAlarm methodsFor: 'accessing' stamp: 'ar 9/11/2000 16:45'!\\nscheduledTime: msecs\\n\\t\\\"Set the time (in milliseconds) that the receiver is scheduled to be executed\\\"\\n\\tscheduledTime _ msecs! !\\n\\n\\n!MorphicAlarm methodsFor: 'evaluating' stamp: 'ar 10/22/2000 17:36'!\\nvalue: anArgument\\n\\t| nArgs |\\n\\tnumArgs ifNil:[numArgs _ selector numArgs].\\n\\tnArgs _ arguments ifNil:[0] ifNotNil:[arguments size].\\n\\tnArgs = numArgs ifTrue:[\\n\\t\\t\\\"Ignore extra argument\\\"\\n\\t\\t^self value].\\n\\t^arguments isNil\\n\\t\\tifTrue: [receiver perform: selector with: anArgument]\\n\\t\\tifFalse: [receiver perform: selector withArguments: (arguments copyWith: anArgument)]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphicAlarm class\\n\\tinstanceVariableNames: ''!\\n\\n!MorphicAlarm class methodsFor: 'instance creation' stamp: 'ar 9/11/2000 16:44'!\\nscheduledAt: scheduledTime receiver: aTarget selector: aSelector arguments: argArray\\n\\t^(self receiver: aTarget selector: aSelector arguments: argArray)\\n\\t\\tscheduledTime: scheduledTime.! !\\nObject subclass: #MorphicEvent\\n\\tinstanceVariableNames: 'timeStamp source'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Events'!\\n!MorphicEvent commentStamp: '<historical>' prior: 0!\\nThis class represents the base for all events.\\n\\nInstance variables:\\n\\tstamp\\t<Integer>\\tThe millisecond clock time stamp (based on Time millisecondClock)\\n\\tsource\\t<Hand | nil>\\tIf non-nil the hand that generated the event.!\\n\\n\\n!MorphicEvent methodsFor: 'accessing' stamp: 'ar 10/10/2000 21:28'!\\ncursorPoint\\n\\t\\\"Backward compatibility. Use #position instead\\\"\\n\\t^ self position! !\\n\\n!MorphicEvent methodsFor: 'accessing' stamp: 'ar 9/13/2000 16:48'!\\nhand\\n\\t\\\"Return the source that generated the event\\\"\\n\\t^source! !\\n\\n!MorphicEvent methodsFor: 'accessing' stamp: 'wiz 12/8/2004 23:13'!\\nposition\\n\\t\\\"Since cursorPoint is defined and refers to position it should be defined\\n\\there as well\\\"\\n\\t^ self subclassResponsibility! !\\n\\n!MorphicEvent methodsFor: 'accessing' stamp: 'ar 9/13/2000 15:29'!\\ntimeStamp\\n\\t\\\"Return the millisecond clock value at which the event was generated\\\"\\n\\t^timeStamp ifNil:[timeStamp _ Time millisecondClockValue]! !\\n\\n!MorphicEvent methodsFor: 'accessing' stamp: 'ar 9/13/2000 15:34'!\\ntype\\n\\t\\\"Return a symbol indicating the type this event.\\\"\\n\\t^self subclassResponsibility! !\\n\\n!MorphicEvent methodsFor: 'accessing' stamp: 'ar 10/10/2000 01:19'!\\nwasHandled\\n\\t\\\"Return true if this event was handled. May be ignored for some types of events.\\\"\\n\\t^false! !\\n\\n!MorphicEvent methodsFor: 'accessing' stamp: 'ar 10/10/2000 01:20'!\\nwasHandled: aBool\\n\\t\\\"Determine if this event was handled. May be ignored for some types of events.\\\"! !\\n\\n\\n!MorphicEvent methodsFor: 'comparing' stamp: 'ar 9/13/2000 15:36'!\\n= anEvent\\n\\tanEvent isMorphicEvent ifFalse:[^false].\\n\\t^self type = anEvent type! !\\n\\n!MorphicEvent methodsFor: 'comparing' stamp: 'ar 9/13/2000 15:36'!\\nhash\\n\\t^self type hash! !\\n\\n\\n!MorphicEvent methodsFor: 'dispatching' stamp: 'ar 9/15/2000 21:12'!\\nsentTo: anObject\\n\\t\\\"Dispatch the receiver into anObject\\\"\\n\\t^anObject handleUnknownEvent: self! !\\n\\n\\n!MorphicEvent methodsFor: 'initialize' stamp: 'ar 10/10/2000 01:18'!\\ncopyHandlerState: anEvent\\n\\t\\\"Copy the handler state from anEvent. Used for quickly transferring handler information between transformed events.\\\"\\n! !\\n\\n!MorphicEvent methodsFor: 'initialize' stamp: 'ar 10/10/2000 01:18'!\\nresetHandlerFields\\n\\t\\\"Reset anything that is used to cross-communicate between two eventual handlers during event dispatch\\\"! !\\n\\n!MorphicEvent methodsFor: 'initialize' stamp: 'ar 10/24/2000 16:21'!\\ntype: eventType readFrom: aStream\\n\\t\\\"Read a MorphicEvent from the given stream.\\\"\\n! !\\n\\n\\n!MorphicEvent methodsFor: 'object fileIn' stamp: 'RAA 12/20/2000 16:05'!\\nconvertOctober2000: varDict using: smartRefStrm\\n\\t\\\"ar 10/25/2000: This method is used to convert OLD MorphicEvents into new ones.\\\"\\n\\t\\\"These are going away #('type' 'cursorPoint' 'buttons' 'keyValue' 'sourceHand'). Possibly store their info in another variable?\\\"\\n\\t| type cursorPoint buttons keyValue sourceHand |\\n\\ttype _ varDict at: 'type'.\\n\\tcursorPoint _ varDict at: 'cursorPoint'.\\n\\tbuttons _ varDict at: 'buttons'.\\n\\tkeyValue _ varDict at: 'keyValue'.\\n\\tsourceHand _ varDict at: 'sourceHand'.\\n\\ttype == #mouseMove ifTrue:[\\n\\t\\t^MouseMoveEvent new\\n\\t\\t\\tsetType: #mouseMove \\n\\t\\t\\tstartPoint: cursorPoint\\n\\t\\t\\tendPoint: cursorPoint\\n\\t\\t\\ttrail: #() \\n\\t\\t\\tbuttons: buttons \\n\\t\\t\\thand: sourceHand \\n\\t\\t\\tstamp: nil].\\n\\t(type == #mouseDown) | (type == #mouseUp) ifTrue:[\\n\\t\\t\\t^MouseButtonEvent new\\n\\t\\t\\t\\tsetType: type\\n\\t\\t\\t\\tposition: cursorPoint\\n\\t\\t\\t\\twhich: 0\\n\\t\\t\\t\\tbuttons: buttons\\n\\t\\t\\t\\thand: sourceHand\\n\\t\\t\\t\\tstamp: nil].\\n\\t(type == #keystroke) | (type == #keyDown) | (type == #keyUp) ifTrue:[\\n\\t\\t^KeyboardEvent new\\n\\t\\t\\tsetType: type\\n\\t\\t\\tbuttons: buttons\\n\\t\\t\\tposition: cursorPoint\\n\\t\\t\\tkeyValue: keyValue\\n\\t\\t\\thand: sourceHand\\n\\t\\t\\tstamp: nil].\\n\\t\\\"All others will be handled there\\\"\\n\\t^MorphicUnknownEvent new! !\\n\\n\\n!MorphicEvent methodsFor: 'objects from disk' stamp: 'RAA 12/21/2000 11:35'!\\nconvertToCurrentVersion: varDict refStream: smartRefStrm\\n\\t\\n\\t| answer |\\n\\n\\t\\\"ar 10/25/2000: This method is used to convert OLD MorphicEvents into new ones.\\\"\\n\\tvarDict at: 'cursorPoint' ifPresent: [ :x | \\n\\t\\tanswer _ self convertOctober2000: varDict using: smartRefStrm.\\n\\t\\tvarDict removeKey: 'cursorPoint'.\\t\\\"avoid doing this again\\\"\\n\\t\\t^answer\\n\\t].\\n\\t^super convertToCurrentVersion: varDict refStream: smartRefStrm.\\n\\n\\n! !\\n\\n\\n!MorphicEvent methodsFor: 'testing' stamp: 'ar 9/22/2000 10:36'!\\nisDraggingEvent\\n\\t^false! !\\n\\n!MorphicEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 19:17'!\\nisDropEvent\\n\\t^false! !\\n\\n!MorphicEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 19:19'!\\nisKeyboard\\n\\t^false! !\\n\\n!MorphicEvent methodsFor: 'testing' stamp: 'ar 10/10/2000 21:27'!\\nisKeystroke\\n\\t^false! !\\n\\n!MorphicEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 15:37'!\\nisMorphicEvent\\n\\t^true! !\\n\\n!MorphicEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 19:19'!\\nisMouse\\n\\t^false! !\\n\\n!MorphicEvent methodsFor: 'testing' stamp: 'ar 9/14/2000 18:21'!\\nisMouseOver\\n\\t^self type == #mouseOver! !\\n\\n\\n!MorphicEvent methodsFor: 'transforming' stamp: 'ar 9/13/2000 15:47'!\\ntransformedBy: aMorphicTransform\\n\\t\\\"Return the receiver transformed by the given transform into a local coordinate system.\\\"\\n! !\\n\\n\\n!MorphicEvent methodsFor: 'private' stamp: 'ar 10/25/2000 21:26'!\\nsetHand: aHand\\n\\tsource _ aHand! !\\n\\n!MorphicEvent methodsFor: 'private' stamp: 'ar 10/25/2000 20:53'!\\nsetTimeStamp: stamp\\n\\ttimeStamp _ stamp.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphicEvent class\\n\\tinstanceVariableNames: ''!\\n\\n!MorphicEvent class methodsFor: 'instance creation' stamp: 'ar 10/26/2000 00:44'!\\nconvertObsolete: anEvent\\n\\t\\\"ar 10/25/2000: This method is used to convert OLD MorphicEvents into new ones.\\\"\\n\\t| type cursorPoint buttons keyValue sourceHand |\\n\\ttype _ anEvent type.\\n\\tcursorPoint _ anEvent cursorPoint.\\n\\tbuttons _ anEvent buttons.\\n\\tkeyValue _ anEvent keyValue.\\n\\tsourceHand _ anEvent hand.\\n\\ttype == #mouseMove ifTrue:[\\n\\t\\t^MouseMoveEvent new\\n\\t\\t\\tsetType: #mouseMove \\n\\t\\t\\tstartPoint: cursorPoint\\n\\t\\t\\tendPoint: cursorPoint\\n\\t\\t\\ttrail: #() \\n\\t\\t\\tbuttons: buttons \\n\\t\\t\\thand: sourceHand \\n\\t\\t\\tstamp: nil].\\n\\t(type == #mouseDown) | (type == #mouseUp) ifTrue:[\\n\\t\\t\\t^MouseButtonEvent new\\n\\t\\t\\t\\tsetType: type\\n\\t\\t\\t\\tposition: cursorPoint\\n\\t\\t\\t\\twhich: 0\\n\\t\\t\\t\\tbuttons: buttons\\n\\t\\t\\t\\thand: sourceHand\\n\\t\\t\\t\\tstamp: nil].\\n\\t(type == #keystroke) | (type == #keyDown) | (type == #keyUp) ifTrue:[\\n\\t\\t^KeyboardEvent new\\n\\t\\t\\tsetType: type\\n\\t\\t\\tbuttons: buttons\\n\\t\\t\\tposition: cursorPoint\\n\\t\\t\\tkeyValue: keyValue\\n\\t\\t\\thand: sourceHand\\n\\t\\t\\tstamp: nil].\\n\\t^nil! !\\n\\n!MorphicEvent class methodsFor: 'instance creation' stamp: 'ar 10/26/2000 00:49'!\\nreadFrom: aStream\\n\\t\\\"Read a MorphicEvent from the given stream.\\\"\\n\\t| typeString c |\\n\\ttypeString _ String streamContents:\\n\\t\\t[:s | [(c _ aStream next) isLetter] whileTrue: [s nextPut: c]].\\n\\ttypeString = 'mouseMove' ifTrue:[^MouseMoveEvent type: #mouseMove readFrom: aStream].\\n\\ttypeString = 'mouseDown' ifTrue:[^MouseButtonEvent type: #mouseDown readFrom: aStream].\\n\\ttypeString = 'mouseUp' ifTrue:[^MouseButtonEvent type: #mouseUp readFrom: aStream].\\n\\n\\ttypeString = 'keystroke' ifTrue:[^KeyboardEvent type: #keystroke readFrom: aStream].\\n\\ttypeString = 'keyDown' ifTrue:[^KeyboardEvent type: #keyDown readFrom: aStream].\\n\\ttypeString = 'keyUp' ifTrue:[^KeyboardEvent type: #keyUp readFrom: aStream].\\n\\n\\ttypeString = 'mouseOver' ifTrue:[^MouseEvent type: #mouseOver readFrom: aStream].\\n\\ttypeString = 'mouseEnter' ifTrue:[^MouseEvent type: #mouseEnter readFrom: aStream].\\n\\ttypeString = 'mouseLeave' ifTrue:[^MouseEvent type: #mouseLeave readFrom: aStream].\\n\\n\\ttypeString = 'unknown' ifTrue:[^MorphicUnknownEvent type: #unknown readFrom: aStream].\\n\\n\\t^nil\\n! !\\n\\n!MorphicEvent class methodsFor: 'instance creation' stamp: 'ar 10/25/2000 21:58'!\\nreadFromObsolete: aStream\\n\\t\\\"Read one of those old and now obsolete events from the stream\\\"\\n\\t| type x y buttons keyValue typeString c |\\n\\ttypeString _ String streamContents:\\n\\t\\t[:s | [(c _ aStream next) isLetter] whileTrue: [s nextPut: c]].\\n\\ttypeString = 'mouseMove'\\n\\t\\tifTrue: [type _ #mouseMove \\\"fast treatment of common case\\\"]\\n\\t\\tifFalse: [type _ typeString asSymbol].\\n\\n\\tx _ Integer readFrom: aStream.\\n\\taStream skip: 1.\\n\\ty _ Integer readFrom: aStream.\\n\\taStream skip: 1.\\n\\n\\tbuttons _ Integer readFrom: aStream.\\n\\taStream skip: 1.\\n\\n\\tkeyValue _ Integer readFrom: aStream.\\n\\n\\ttypeString = 'mouseMove' ifTrue:[\\n\\t\\t^MouseMoveEvent new\\n\\t\\t\\tsetType: #mouseMove \\n\\t\\t\\tstartPoint: x@y \\n\\t\\t\\tendPoint: x@y \\n\\t\\t\\ttrail: #() \\n\\t\\t\\tbuttons: buttons \\n\\t\\t\\thand: nil \\n\\t\\t\\tstamp: nil].\\n\\t(typeString = 'mouseDown') | (typeString = 'mouseUp') ifTrue:[\\n\\t\\t\\t^MouseButtonEvent new\\n\\t\\t\\t\\tsetType: type\\n\\t\\t\\t\\tposition: x@y\\n\\t\\t\\t\\twhich: 0\\n\\t\\t\\t\\tbuttons: buttons\\n\\t\\t\\t\\thand: nil\\n\\t\\t\\t\\tstamp: nil].\\n\\t(typeString = 'keystroke') | (typeString = 'keyDown') | (typeString = 'keyUp') ifTrue:[\\n\\t\\t^KeyboardEvent new\\n\\t\\t\\tsetType: type\\n\\t\\t\\tbuttons: buttons\\n\\t\\t\\tposition: x@y\\n\\t\\t\\tkeyValue: keyValue\\n\\t\\t\\thand: nil\\n\\t\\t\\tstamp: nil].\\n\\n\\t^nil! !\\n\\n!MorphicEvent class methodsFor: 'instance creation' stamp: 'ar 10/24/2000 16:32'!\\ntype: eventType readFrom: aStream\\n\\t^self new type: eventType readFrom: aStream! !\\n\\n\\n!MorphicEvent class methodsFor: '*nebraska-*nebraska-Morphic-Remote' stamp: 'ar 10/25/2000 23:32'!\\nfromStringArray: array\\n\\t\\\"decode an event that was encoded with encodedAsStringArray\\\"\\n\\t| type |\\n\\ttype := (array at: 1).\\n\\t(type = 'mouseMove')\\n\\t\\tifTrue:[^MouseMoveEvent new decodeFromStringArray: array].\\n\\t(type = 'mouseDown' or:[type = 'mouseUp']) \\n\\t\\tifTrue:[^MouseButtonEvent new decodeFromStringArray: array].\\n\\t(type = 'keystroke' or:[type = 'keyDown' or:[type = 'keyUp']]) \\n\\t\\tifTrue:[^KeyboardEvent new decodeFromStringArray: array].\\n\\t^nil! !\\nObject subclass: #MorphicEventDecoder\\n\\tinstanceVariableNames: 'connection'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n!MorphicEventDecoder commentStamp: '<historical>' prior: 0!\\ndecode messages sent via a MorphicEventEncoder.!\\n\\n\\n!MorphicEventDecoder methodsFor: 'handling messages' stamp: 'RAA 11/8/2000 15:15'!\\napply: aStringArray to: aHand\\n\\t\\\"decode aStringArray, and apply the encoded command to aHand\\\"\\n\\n\\taStringArray first = 'event' ifTrue: [\\n\\t\\t^self applyEventMessage: aStringArray to: aHand\\n\\t].\\n\\taStringArray first = 'viewExtent' ifTrue: [\\n\\t\\t^self applyViewExtentMessage: aStringArray to: aHand\\n\\t].\\n\\taStringArray first = 'beginBuffering' ifTrue: [\\n\\t\\t^aHand convertRemoteClientToBuffered\\n\\t].\\n\\n\\t^self error: 'unknown message type: ', aStringArray first! !\\n\\n!MorphicEventDecoder methodsFor: 'handling messages' stamp: 'ar 10/26/2000 01:55'!\\napplyEventMessage: aStringArray to: aHand\\n\\t| event |\\n\\tevent := MorphicEvent fromStringArray: (aStringArray copyFrom: 2 to: aStringArray size).\\n\\tevent ifNotNil:[aHand queueEvent: event].! !\\n\\n!MorphicEventDecoder methodsFor: 'handling messages' stamp: 'ls 3/25/2000 16:56'!\\napplyMessagesTo: aHand\\n\\t| msg |\\n\\t\\\"apply all queued events to the given hand\\\"\\n\\t\\\"currently, there is no way to extract the rawmessages. This is simply because I didn't feel like implementing individual classes for each message -lex\\\"\\n\\t[ msg := connection nextOrNil. msg notNil ] whileTrue: [\\n\\t\\tself apply: msg to: aHand ].\\n! !\\n\\n!MorphicEventDecoder methodsFor: 'handling messages' stamp: 'ls 4/11/2000 19:00'!\\napplyViewExtentMessage: aStringArray to: aHand\\n\\t| newViewExtent |\\n\\tnewViewExtent := CanvasDecoder decodePoint: aStringArray second.\\n\\n\\taHand setViewExtent: newViewExtent! !\\n\\n!MorphicEventDecoder methodsFor: 'handling messages' stamp: 'ls 3/24/2000 22:54'!\\nprocessIO\\n\\tconnection processIO! !\\n\\n\\n!MorphicEventDecoder methodsFor: 'initialization' stamp: 'ls 3/24/2000 21:42'!\\nconnection: aConnection\\n\\tconnection := aConnection! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphicEventDecoder class\\n\\tinstanceVariableNames: ''!\\n\\n!MorphicEventDecoder class methodsFor: 'instance creation' stamp: 'ls 3/24/2000 21:43'!\\non: aStringArray\\n\\t^self basicNew connection: aStringArray! !\\nObject subclass: #MorphicEventDispatcher\\n\\tinstanceVariableNames: 'lastType lastDispatch'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Events'!\\n!MorphicEventDispatcher commentStamp: '<historical>' prior: 0!\\nThe class represents a strategy for dispatching events to some immediate child of a morph. It is used by morphs to delegate the somewhat complex action of dispatching events accurately. !\\n\\n\\n!MorphicEventDispatcher methodsFor: 'dispatching' stamp: 'ar 10/10/2000 01:20'!\\ndispatchDefault: anEvent with: aMorph\\n\\t\\\"Dispatch the given event. The event will be passed to the front-most visible submorph that contains the position wrt. to the event.\\\"\\n\\t| localEvt index child morphs inside |\\n\\t\\\"See if we're fully outside aMorphs bounds\\\"\\n\\t(aMorph fullBounds containsPoint: anEvent position) ifFalse:[^#rejected]. \\\"outside\\\"\\n\\t\\\"Traverse children\\\"\\n\\tindex _ 1.\\n\\tmorphs _ aMorph submorphs.\\n\\tinside _ false.\\n\\t[index <= morphs size] whileTrue:[\\n\\t\\tchild _ morphs at: index.\\n\\t\\tlocalEvt _ anEvent transformedBy: (child transformedFrom: aMorph).\\n\\t\\t(child processEvent: localEvt using: self) == #rejected ifFalse:[\\n\\t\\t\\t\\\"Not rejected. The event was in some submorph of the receiver\\\"\\n\\t\\t\\tinside _ true.\\n\\t\\t\\tlocalEvt wasHandled ifTrue:[anEvent copyHandlerState: localEvt].\\n\\t\\t\\tindex _ morphs size. \\\"break\\\"\\n\\t\\t].\\n\\t\\tindex _ index + 1.\\n\\t].\\n\\n\\t\\\"Check for being inside the receiver\\\"\\n\\tinside ifFalse:[inside _ aMorph containsPoint: anEvent position event: anEvent].\\n\\tinside ifTrue:[^aMorph handleEvent: anEvent].\\n\\t^#rejected\\n! !\\n\\n!MorphicEventDispatcher methodsFor: 'dispatching' stamp: 'ar 10/10/2000 21:13'!\\ndispatchDropEvent: anEvent with: aMorph\\n\\t\\\"Find the appropriate receiver for the event and let it handle it. The dispatch is similar to the default dispatch with one difference: Morphs are given the chance to reject an entire drop operation. If the operation is rejected, no drop will be executed.\\\"\\n\\t| inside index morphs child localEvt |\\n\\t\\\"Try to get out quickly\\\"\\n\\t(aMorph fullBounds containsPoint: anEvent cursorPoint)\\n\\t\\tifFalse:[^#rejected].\\n\\t\\\"Give aMorph a chance to repel the dropping morph\\\"\\n\\taMorph rejectDropEvent: anEvent.\\n\\tanEvent wasHandled ifTrue:[^self].\\n\\n\\t\\\"Go looking if any of our submorphs wants it\\\"\\n\\tindex _ 1.\\n\\tinside _ false.\\n\\tmorphs _ aMorph submorphs.\\n\\t[index <= morphs size] whileTrue:[\\n\\t\\tchild _ morphs at: index.\\n\\t\\tlocalEvt _ anEvent transformedBy: (child transformedFrom: aMorph).\\n\\t\\t(child processEvent: localEvt using: self) == #rejected ifFalse:[\\n\\t\\t\\tlocalEvt wasHandled ifTrue:[^anEvent wasHandled: true]. \\\"done\\\"\\n\\t\\t\\tinside _ true.\\n\\t\\t\\tindex _ morphs size]. \\\"break\\\"\\n\\t\\tindex _ index + 1.\\n\\t].\\n\\n\\tinside ifFalse:[inside _ aMorph containsPoint: anEvent cursorPoint event: anEvent].\\n\\tinside ifTrue:[^aMorph handleEvent: anEvent].\\n\\t^#rejected! !\\n\\n!MorphicEventDispatcher methodsFor: 'dispatching' stamp: 'ar 1/10/2001 21:43'!\\ndispatchEvent: anEvent with: aMorph\\n\\t\\\"Dispatch the given event for a morph that has chosen the receiver to dispatch its events. The method implements a shortcut for repeated dispatches of events using the same dispatcher.\\\"\\n\\tanEvent type == lastType ifTrue:[^self perform: lastDispatch with: anEvent with: aMorph].\\n\\t\\\"Otherwise classify\\\"\\n\\tlastType _ anEvent type.\\n\\tanEvent isMouse ifTrue:[\\n\\t\\tanEvent isMouseDown ifTrue:[\\n\\t\\t\\tlastDispatch _ #dispatchMouseDown:with:.\\n\\t\\t\\t^self dispatchMouseDown: anEvent with: aMorph]].\\n\\tanEvent type == #dropEvent ifTrue:[\\n\\t\\tlastDispatch _ #dispatchDropEvent:with:.\\n\\t\\t^self dispatchDropEvent: anEvent with: aMorph].\\n\\tlastDispatch _ #dispatchDefault:with:.\\n\\t^self dispatchDefault: anEvent with: aMorph! !\\n\\n!MorphicEventDispatcher methodsFor: 'dispatching' stamp: 'ar 10/10/2000 21:14'!\\ndispatchMouseDown: anEvent with: aMorph\\n\\t\\\"Find the appropriate receiver for the event and let it handle it. Default rules:\\n\\t* The top-most chain of visible, unlocked morphs containing the event position will get a chance to handle the event.\\n\\t* When travelling down the hierarchy a prospective handler for the event is installed. This prospective handler can be used by submorphs wishing to handle the mouse down for negotiating who the receiver is.\\n\\t* When travelling up, the prospective handler is always executed. The handler needs to check if the event was handled before as well as checking if somebody else's handler has been installed.\\n\\t* If another handler has been installed but the event was not handled it means that somebody up in the hierarchy wants to handle the event.\\n\\\"\\n\\t| globalPt localEvt index child morphs handler inside lastHandler |\\n\\t\\\"Try to get out quickly\\\"\\n\\tglobalPt _ anEvent cursorPoint.\\n\\t(aMorph fullBounds containsPoint: globalPt) ifFalse:[^#rejected].\\n\\n\\t\\\"Install the prospective handler for the receiver\\\"\\n\\tlastHandler _ anEvent handler. \\\"in case the mouse wasn't even in the receiver\\\"\\n\\thandler _ aMorph handlerForMouseDown: anEvent.\\n\\thandler ifNotNil:[anEvent handler: handler].\\n\\n\\t\\\"Now give our submorphs a chance to handle the event\\\"\\n\\tindex _ 1.\\n\\tmorphs _ aMorph submorphs.\\n\\t[index <= morphs size] whileTrue:[\\n\\t\\tchild _ morphs at: index.\\n\\t\\tlocalEvt _ anEvent transformedBy: (child transformedFrom: aMorph).\\n\\t\\t(child processEvent: localEvt using: self) == #rejected ifFalse:[\\n\\t\\t\\t\\\"Some child did contain the point so we're part of the top-most chain.\\\"\\n\\t\\t\\tinside _ false.\\n\\t\\t\\tlocalEvt wasHandled ifTrue:[anEvent copyHandlerState: localEvt].\\n\\t\\t\\tindex _ morphs size].\\n\\t\\tindex _ index + 1.\\n\\t].\\n\\n\\t(inside == false or:[aMorph containsPoint: anEvent cursorPoint event: anEvent]) ifTrue:[\\n\\t\\t\\\"Receiver is in the top-most unlocked, visible chain.\\\"\\n\\t\\thandler ifNotNil:[handler handleEvent: anEvent].\\n\\t\\t\\\"Note: Re-installing the handler is not really necessary but good style.\\\"\\n\\t\\tanEvent handler: lastHandler.\\n\\t\\t^self\\n\\t].\\n\\t\\\"Mouse was not on receiver nor any of its children\\\"\\n\\tanEvent handler: lastHandler.\\n\\t^#rejected! !\\nObject subclass: #MorphicEventEncoder\\n\\tinstanceVariableNames: 'connection lastEventSent'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n!MorphicEventEncoder commentStamp: '<historical>' prior: 0!\\nA filter which translates MorphEvent's into StringArray's.!\\n\\n\\n!MorphicEventEncoder methodsFor: 'initialization' stamp: 'ls 3/24/2000 21:38'!\\nconnection: aConnection\\n\\tconnection := aConnection! !\\n\\n\\n!MorphicEventEncoder methodsFor: 'network I/O' stamp: 'ls 3/24/2000 21:42'!\\nflush\\n\\tconnection flush! !\\n\\n!MorphicEventEncoder methodsFor: 'network I/O' stamp: 'ls 3/24/2000 21:38'!\\nprocessIO\\n\\tconnection processIO! !\\n\\n!MorphicEventEncoder methodsFor: 'network I/O' stamp: 'RAA 12/13/2000 08:19'!\\nrequestBufferedConnection\\n\\t\\\"request the opposite side to send complete screen updates rather than discrete drawing commands\\\"\\n\\t\\n\\tconnection nextPut: { 'beginBuffering' }\\n! !\\n\\n!MorphicEventEncoder methodsFor: 'network I/O' stamp: 'ls 3/26/2000 01:08'!\\nsendEvent: anEvent\\n\\t(anEvent isMouseMove and: [ anEvent = lastEventSent ]) ifTrue: [\\n\\t\\t\\\"save on network traffic--don't send duplicate mouse moves\\\"\\n\\t\\t^self ].\\n\\tlastEventSent := anEvent.\\n\\tconnection nextPut: #('event'), anEvent encodedAsStringArray! !\\n\\n!MorphicEventEncoder methodsFor: 'network I/O' stamp: 'ls 4/11/2000 18:59'!\\nsendViewExtent: newExtent\\n\\t\\\"inform the opposite side that our view extent has changed\\\"\\n\\t\\n\\tconnection nextPut: { 'viewExtent'. CanvasEncoder encodePoint: newExtent }\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphicEventEncoder class\\n\\tinstanceVariableNames: ''!\\n\\n!MorphicEventEncoder class methodsFor: 'instance creation' stamp: 'ls 3/24/2000 21:43'!\\non: aStringArray\\n\\t^self basicNew connection: aStringArray! !\\nBorderedMorph subclass: #MorphicModel\\n\\tinstanceVariableNames: 'model slotName open'\\n\\tclassVariableNames: 'TimeOfError'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Kernel'!\\n!MorphicModel commentStamp: '<historical>' prior: 0!\\nMorphicModels are used to represent structures with state and behavior as well as graphical structure. A morphicModel is usually the root of a morphic tree depicting its appearance. The tree is constructed concretely by adding its consituent morphs to a world.\\n\\nWhen a part is named in a world, it is given a new slot in the model. When a part is sensitized, it is named, and a set of mouse-driven methods is also generated in the model. These may be edited to induce particular behavior. When a variable is added through the morphic world, it is given a slot in the model, along with a set of access methods.\\n\\nIn addition for public variables (and this is the default for now), methods are generated and called in any outer model in which this model gets embedded, thus propagating variable changes outward.!\\n\\n\\n!MorphicModel methodsFor: 'access'!\\nmodel \\n\\t^ model! !\\n\\n!MorphicModel methodsFor: 'access'!\\nslotName\\n\\t^ slotName! !\\n\\n!MorphicModel methodsFor: 'access' stamp: '6/7/97 10:40 di'!\\nwantsSlot\\n\\t\\\"Override this default for models that want to be installed in theri model\\\"\\n\\t^ false! !\\n\\n\\n!MorphicModel methodsFor: 'accessing' stamp: 'sw 10/23/1999 22:36'!\\nmodelOrNil\\n\\t^ model! !\\n\\n\\n!MorphicModel methodsFor: 'caching' stamp: 'sw 3/6/2001 11:22'!\\nreleaseCachedState\\n\\t\\\"Release cached state of the receiver\\\"\\n\\n\\t(model ~~ self and: [model respondsTo: #releaseCachedState]) ifTrue:\\n\\t\\t[model releaseCachedState].\\n\\tsuper releaseCachedState! !\\n\\n\\n!MorphicModel methodsFor: 'classification' stamp: 'ar 10/5/2000 16:40'!\\nisMorphicModel\\n\\t^true! !\\n\\n\\n!MorphicModel methodsFor: 'compilation'!\\naddPartNameLike: className withValue: aMorph\\n\\t| otherNames i default partName stem |\\n\\tstem _ className first asLowercase asString , className allButFirst.\\n\\totherNames _ self class allInstVarNames.\\n\\ti _ 1.\\n\\t[otherNames includes: (default _ stem, i printString)]\\n\\t\\twhileTrue: [i _ i + 1].\\n\\tpartName _ FillInTheBlank\\n\\t\\trequest: 'Please give this part a name'\\n\\t\\tinitialAnswer: default.\\n\\t(otherNames includes: partName)\\n\\t\\tifTrue: [self inform: 'Sorry, that name is already used'. ^ nil].\\n\\tself class addInstVarName: partName.\\n\\tself instVarAt: self class instSize put: aMorph. \\\"Assumes added as last field\\\"\\n\\t^ partName! !\\n\\n!MorphicModel methodsFor: 'compilation' stamp: 'tk 4/18/97'!\\ncompileAccessForSlot: aSlotName\\n\\t\\\"Write the method to get at this inst var. \\\"\\n\\t\\\"Instead call the right thing to make this happen?\\\"\\n\\n\\t| s |\\n\\ts _ WriteStream on: (String new: 2000).\\n\\ts nextPutAll: aSlotName; cr; tab; nextPutAll: '^', aSlotName.\\n\\tself class\\n\\t\\tcompile: s contents\\n\\t\\tclassified: 'public access'\\n\\t\\tnotifying: nil.\\n! !\\n\\n!MorphicModel methodsFor: 'compilation'!\\ncompilePropagationMethods\\n\\t| varName |\\n\\t(self class organization listAtCategoryNamed: 'private - propagation' asSymbol)\\n\\t\\tdo: [:sel | varName _ sel allButLast.\\n\\t\\t\\tmodel class compilePropagationForVarName: varName slotName: slotName]! !\\n\\n!MorphicModel methodsFor: 'compilation'!\\nnameFor: aMorph\\n\\t\\\"Return the name of the slot containing the given morph or nil if that morph has not been named.\\\"\\n\\n\\t| allNames start |\\n\\tallNames _ self class allInstVarNames.\\n\\tstart _ MorphicModel allInstVarNames size + 1.\\n\\tstart to: allNames size do: [:i |\\n\\t\\t(self instVarAt: i) == aMorph ifTrue: [^ allNames at: i]].\\n\\t^ nil\\n! !\\n\\n!MorphicModel methodsFor: 'compilation'!\\npropagate: value as: partStoreSelector\\n\\tmodel ifNil: [^ self].\\n\\\"\\n\\tLater we can cache this for more speed as follows...\\n\\t(partName == cachedPartName and: [slotName == cachedSlotName])\\n\\t\\tifFalse: [cachedPartName _ partName.\\n\\t\\t\\t\\tcachedSlotName _ slotName.\\n\\t\\t\\t\\tcachedStoreSelector _ (slotName , partStoreSelector) asSymbol].\\n\\tmodel perform: cachedStoreSelector with: value].\\n\\\"\\n\\tmodel perform: (self slotSelectorFor: partStoreSelector) with: value! !\\n\\n!MorphicModel methodsFor: 'compilation' stamp: 'tk 10/31/97 12:33'!\\nremoveAll\\n\\t\\\"Clear out all script methods and subpart instance variables in me. Start over.\\\"\\n\\t\\\"self removeAll\\\"\\n\\t\\\"MorphicModel2 removeAll\\\"\\n\\nself class == MorphicModel ifTrue: [^ self].\\t\\\"Must be a subclass!!\\\"\\nself class removeCategory: 'scripts'.\\nself class instVarNames do: [:nn | self class removeInstVarName: nn].! !\\n\\n!MorphicModel methodsFor: 'compilation'!\\nslotSelectorFor: selectorBody\\n\\t| selector |\\n\\tmodel ifNil: [^ nil].\\n\\t\\\"Make up selector from slotname if any\\\"\\n\\tselector _ (slotName ifNil: [selectorBody]\\n\\t\\t\\t\\t\\tifNotNil: [slotName , selectorBody]) asSymbol.\\n\\t(model canUnderstand: selector) ifFalse:\\n\\t\\t[self halt: 'Compiling a null response for ' , model class name , '>>' , selector].\\n\\t^ selector! !\\n\\n!MorphicModel methodsFor: 'compilation'!\\nuse: cachedSelector orMakeModelSelectorFor: selectorBody in: selectorBlock\\n\\t| selector |\\n\\tmodel ifNil: [^ nil].\\n\\tcachedSelector ifNil:\\n\\t\\t\\t[\\\"Make up selector from slotname if any\\\"\\n\\t\\t\\tselector _ (slotName ifNil: [selectorBody]\\n\\t\\t\\t\\t\\t\\t\\t\\tifNotNil: [slotName , selectorBody]) asSymbol.\\n\\t\\t\\t(model class canUnderstand: selector) ifFalse:\\n\\t\\t\\t\\t[(self confirm: 'Shall I compile a null response for'\\n\\t\\t\\t\\t\\t\\t\\t, Character cr asString\\n\\t\\t\\t\\t\\t\\t\\t, model class name , '>>' , selector)\\n\\t\\t\\t\\t\\t\\tifFalse: [self halt].\\n\\t\\t\\t\\tmodel class compile: (String streamContents:\\n\\t\\t\\t\\t\\t\\t\\t\\t[:s | selector keywords doWithIndex:\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[:k :i | s nextPutAll: k , ' arg' , i printString].\\n\\t\\t\\t\\t\\t\\t\\t\\ts cr; nextPutAll: '\\\"Automatically generated null response.\\\"'.\\n\\t\\t\\t\\t\\t\\t\\t\\ts cr; nextPutAll: '\\\"Add code below for appropriate behavior...\\\"'.])\\n\\t\\t\\t\\t\\t\\t\\tclassified: 'input events'\\n\\t\\t\\t\\t\\t\\t\\tnotifying: nil]]\\n\\t\\tifNotNil:\\n\\t\\t\\t[selector _ cachedSelector].\\n\\t^ selectorBlock value: selector! !\\n\\n\\n!MorphicModel methodsFor: 'debug and other' stamp: '6/7/97 10:43 di'!\\ninstallModelIn: aWorld\\n\\n\\tself wantsSlot ifFalse: [^ self]. \\\"No real need to install\\\"\\n\\tslotName _ aWorld model addPartNameLike: self class name withValue: self.\\n\\tslotName ifNil: [^ self]. \\\"user chose bad slot name\\\"\\n\\tself model: aWorld model slotName: slotName.\\n\\tself compilePropagationMethods.\\n\\taWorld model compileAccessForSlot: slotName.\\n! !\\n\\n\\n!MorphicModel methodsFor: 'drag and drop' stamp: 'di 6/22/97 23:17'!\\nallowSubmorphExtraction\\n\\t^ self isOpen\\n! !\\n\\n!MorphicModel methodsFor: 'drag and drop' stamp: 'di 6/22/97 23:16'!\\nisOpen\\n\\t\\\"Support drag/drop and other edits.\\\"\\n\\t^ open! !\\n\\n\\n!MorphicModel methodsFor: 'geometry'!\\nnewBounds: newBounds\\n\\tself bounds: newBounds! !\\n\\n!MorphicModel methodsFor: 'geometry'!\\nrecomputeBounds\\n\\n\\t| bnds |\\n\\tbnds _ submorphs first bounds.\\n\\tbounds _ bnds origin corner: bnds corner. \\\"copy it!!\\\"\\n\\tfullBounds _ nil.\\n\\tbounds _ self fullBounds.\\n! !\\n\\n\\n!MorphicModel methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:35'!\\ndefaultBorderColor\\n\\t\\\"answer the default border color/fill style for the receiver\\\"\\n\\t^ Color yellow! !\\n\\n!MorphicModel methodsFor: 'initialization' stamp: 'dgd 3/7/2003 15:07'!\\ndefaultBounds\\n\\\"answer the default bounds for the receiver\\\"\\n\\t^ 0 @ 0 corner: 200 @ 100! !\\n\\n!MorphicModel methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:28'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color transparent! !\\n\\n!MorphicModel methodsFor: 'initialization' stamp: 'tk 4/15/97'!\\nduplicate: newGuy from: oldGuy\\n\\t\\\"oldGuy has just been duplicated and will stay in this world. Make sure all the MorphicModel requirements are carried out for the copy. Ask user to rename it. \\\"\\n\\n\\tnewGuy installModelIn: oldGuy world.\\n\\tnewGuy copySlotMethodsFrom: oldGuy slotName.! !\\n\\n!MorphicModel methodsFor: 'initialization' stamp: 'dgd 2/14/2003 20:47'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\\"\\\"\\n\\topen _ false! !\\n\\n!MorphicModel methodsFor: 'initialization' stamp: 'jm\\n 8/20/1998 09:08'!\\nmodel: anObject\\n\\t\\\"Set my model and make me me a dependent of the given object.\\\"\\n\\n\\tmodel ifNotNil: [model removeDependent: self].\\n\\tanObject ifNotNil: [anObject addDependent: self].\\n\\tmodel _ anObject.\\n! !\\n\\n!MorphicModel methodsFor: 'initialization' stamp: 'di 6/21/97 13:25'!\\nmodel: thang slotName: nameOfThisPart\\n\\tmodel _ thang.\\n\\tslotName _ nameOfThisPart.\\n\\topen _ false.! !\\n\\n\\n!MorphicModel methodsFor: 'menu' stamp: 'dgd 8/30/2003 21:53'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\n\\tsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.\\n\\tmodel ifNotNil: [model addModelMenuItemsTo: aCustomMenu forMorph: self hand: aHandMorph].\\n\\tself isOpen ifTrue: [aCustomMenu add: 'close editing' translated action: #closeToEdits]\\n\\t\\t\\tifFalse: [aCustomMenu add: 'open editing' translated action: #openToEdits].\\n! !\\n\\n!MorphicModel methodsFor: 'menu' stamp: 'di 6/20/97 15:36'!\\ncloseToEdits\\n\\t\\\"Disable this morph's ability to add and remove morphs via drag-n-drop.\\\"\\n\\n\\topen _ false\\n! !\\n\\n!MorphicModel methodsFor: 'menu' stamp: 'di 6/20/97 15:36'!\\nopenToEdits\\n\\t\\\"Enable this morph's ability to add and remove morphs via drag-n-drop.\\\"\\n\\n\\topen _ true\\n! !\\n\\n\\n!MorphicModel methodsFor: 'naming' stamp: 'dgd 2/21/2003 23:00'!\\nchoosePartName\\n\\t\\\"When I am renamed, get a slot, make default methods, move any existing methods. ** Does not clean up old inst var name or methods** \\\"\\n\\n\\t| old |\\n\\told := slotName.\\n\\tsuper choosePartName.\\n\\tslotName ifNil: [^self].\\t\\\"user chose bad slot name\\\"\\n\\tself model: self world model slotName: slotName.\\n\\told isNil\\n\\t\\tifTrue: [self compilePropagationMethods]\\n\\t\\tifFalse: [self copySlotMethodsFrom: old]\\n\\t\\\"old ones not erased!!\\\"! !\\n\\n\\n!MorphicModel methodsFor: 'printing'!\\ninitString\\n\\n\\t^ String streamContents:\\n\\t\\t[:s | s nextPutAll: self class name;\\n\\t\\t\\tnextPutAll: ' newBounds: (';\\n\\t\\t\\tprint: bounds;\\n\\t\\t\\tnextPutAll: ') model: self slotName: ';\\n\\t\\t\\tprint: slotName]! !\\n\\n\\n!MorphicModel methodsFor: 'submorphs-accessing' stamp: 'dgd 2/22/2003 18:51'!\\nallKnownNames\\n\\t\\\"Return a list of all known names based on the scope of the receiver. If the receiver is a member of a uniclass, incorporate the original 1997 logic that queries the known names of the values of all the instance variables.\\\"\\n\\n\\t| superNames |\\n\\tsuperNames := super allKnownNames.\\t\\\"gather them from submorph tree\\\"\\n\\t^self belongsToUniClass \\n\\t\\tifTrue: \\n\\t\\t\\t[superNames , (self instanceVariableValues \\n\\t\\t\\t\\t\\t\\tselect: [:e | e notNil and: [e knownName notNil]]\\n\\t\\t\\t\\t\\t\\tthenCollect: [:e | e knownName])]\\n\\t\\tifFalse: [superNames]! !\\n\\n\\n!MorphicModel methodsFor: 'submorphs-add/remove' stamp: 'gm 2/22/2003 12:51'!\\ndelete\\n\\t(model isMorphicModel) ifFalse: [^super delete].\\n\\tslotName ifNotNil: \\n\\t\\t\\t[(PopUpMenu confirm: 'Shall I remove the slot ' , slotName \\n\\t\\t\\t\\t\\t\\t, '\\nalong with all associated methods?') \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[(model class selectors select: [:s | s beginsWith: slotName]) \\n\\t\\t\\t\\t\\t\\tdo: [:s | model class removeSelector: s].\\n\\t\\t\\t\\t\\t(model class instVarNames includes: slotName) \\n\\t\\t\\t\\t\\t\\tifTrue: [model class removeInstVarName: slotName]]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[(PopUpMenu \\n\\t\\t\\t\\t\\t\\tconfirm: '...but should I at least dismiss this morph?\\n[choose no to leave everything unchanged]') \\n\\t\\t\\t\\t\\t\\t\\tifFalse: [^self]]].\\n\\tsuper delete! !\\n\\n\\n!MorphicModel methodsFor: '*MorphicExtras-compilation'!\\ncompileInitMethods\\n\\t| s nodeDict varNames |\\n\\tnodeDict _ IdentityDictionary new.\\n\\ts _ WriteStream on: (String new: 2000).\\n\\tvarNames _ self class allInstVarNames.\\n\\ts nextPutAll: 'initMorph'.\\n\\t3 to: self class instSize do:\\n\\t\\t[:i | (self instVarAt: i) isMorph ifTrue:\\n\\t\\t\\t[s cr; tab; nextPutAll: (varNames at: i) , ' _ '.\\n\\t\\t\\ts nextPutAll: (self instVarAt: i) initString; nextPutAll: '.'.\\n\\t\\t\\tnodeDict at: (self instVarAt: i) put: (varNames at: i)]].\\n\\tsubmorphs do: \\n\\t\\t[:m | s cr; tab; nextPutAll: 'self addMorph: '.\\n\\t\\tm printConstructorOn: s indent: 1 nodeDict: nodeDict.\\n\\t\\ts nextPutAll: '.'].\\n\\tself class\\n\\t\\tcompile: s contents\\n\\t\\tclassified: 'initialization'\\n\\t\\tnotifying: nil.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphicModel class\\n\\tinstanceVariableNames: 'prototype'!\\n\\n!MorphicModel class methodsFor: 'compilation' stamp: 'tk 3/10/98 18:03'!\\ncategoryForSubclasses\\n\\t^ 'Morphic-Models'! !\\n\\n!MorphicModel class methodsFor: 'compilation' stamp: 'sw 5/23/2001 13:51'!\\nchooseNewName\\n\\t\\\"Choose a new name for the receiver, persisting until an acceptable name is provided or until the existing name is resubmitted\\\"\\n\\n\\t| oldName newName |\\n\\toldName _ self name.\\n\\t\\t[newName _ (FillInTheBlank request: 'Please give this Model a name'\\n\\t\\t\\t\\t\\tinitialAnswer: oldName) asSymbol.\\n\\t\\tnewName = oldName ifTrue: [^ self].\\n\\t\\tSmalltalk includesKey: newName]\\n\\t\\twhileTrue:\\n\\t\\t[self inform: 'Sorry, that name is already in use.'].\\n\\tself rename: newName.! !\\n\\n!MorphicModel class methodsFor: 'compilation'!\\ncompileAccessorsFor: varName\\n\\tself compile: (\\n'&var\\n\\t\\\"Return the value of &var\\\"\\n\\t^ &var'\\n\\t\\t\\tcopyReplaceAll: '&var' with: varName)\\n\\t\\tclassified: 'public access' notifying: nil.\\n\\tself compile: (\\n'&varPut: newValue\\n\\t\\\"Assign newValue to &var.\\n\\tAdd code below to update related graphics appropriately...\\\"\\n\\n\\t&var _ newValue.'\\n\\t\\t\\tcopyReplaceAll: '&var' with: varName)\\n\\t\\tclassified: 'public access' notifying: nil.\\n\\tself compile: (\\n'&var: newValue\\n\\t\\\"Assigns newValue to &var and updates owner\\\"\\n\\t&var _ newValue.\\n\\tself propagate: &var as: ''&var:'''\\n\\t\\t\\tcopyReplaceAll: '&var' with: varName)\\n\\t\\tclassified: 'private - propagation' notifying: nil.\\n! !\\n\\n!MorphicModel class methodsFor: 'compilation'!\\ncompilePropagationForVarName: varName slotName: slotName\\n\\tself compile: ((\\n'&slot&var: newValue\\n\\t\\\"The value of &var in &slot has changed to newValue.\\n\\tThis value can be read elsewhere in code with\\n\\t\\t&slot &var\\n\\tand it can be stored into with\\n\\t\\t&slot &varPut: someValue\\\"\\n\\n\\t\\\"Add code for appropriate response here...\\\"'\\n\\t\\t\\tcopyReplaceAll: '&var' with: varName)\\n\\t\\t\\tcopyReplaceAll: '&slot' with: slotName)\\n\\t\\tclassified: 'input events' notifying: nil.\\n! !\\n\\n\\n!MorphicModel class methodsFor: 'compiling' stamp: 'sw 5/13/1998 14:33'!\\nacceptsLoggingOfCompilation\\n\\t\\\"Dont log sources for my automatically-generated subclasses. Can easily switch this back when it comes to deal with Versions, etc.\\\"\\n\\n\\t^ self == MorphicModel or: [(name last isDigit) not]! !\\n\\n!MorphicModel class methodsFor: 'compiling' stamp: 'sw 8/4/97 17:16'!\\nwantsChangeSetLogging\\n\\t\\\"Log changes for MorphicModel itself and for things like PlayWithMe2, but not for automatically-created subclasses like MorphicModel1, MorphicModel2, etc.\\\"\\n\\n\\t^ self == MorphicModel or:\\n\\t\\t[(self class name beginsWith: 'Morphic') not]! !\\n\\n\\n!MorphicModel class methodsFor: 'housekeeping' stamp: 'jm 7/30/97 16:40'!\\nremoveUninstantiatedModels\\n\\t\\\"With the user's permission, remove the classes of any models that have neither instances nor subclasses.\\\"\\n\\t\\\"MorphicModel removeUninstantiatedModels\\\"\\n\\n\\t| candidatesForRemoval ok |\\n\\tSmalltalk garbageCollect.\\n\\tcandidatesForRemoval _\\n\\t\\tMorphicModel subclasses select: [:c |\\n\\t\\t\\t(c instanceCount = 0) and: [c subclasses size = 0]].\\n\\tcandidatesForRemoval do: [:c |\\n\\t\\tok _ self confirm: 'Are you certain that you\\nwant to delete the class ', c name, '?'.\\n\\t\\tok ifTrue: [c removeFromSystem]].\\n! !\\n\\n\\n!MorphicModel class methodsFor: 'instance creation' stamp: 'tk 8/13/1998 12:58'!\\nnew\\n\\t\\\"Return a copy of the prototype, if there is one.\\n\\tOtherwise create a new instance normally.\\\"\\n\\n\\tself hasPrototype ifTrue: [^ prototype veryDeepCopy].\\n\\t^ super new\\n! !\\n\\n!MorphicModel class methodsFor: 'instance creation' stamp: 'di 6/22/97 09:27'!\\nnewBounds: bounds model: thang slotName: nameOfThisPart\\n\\t^ (super new model: thang slotName: nameOfThisPart)\\n\\t\\tnewBounds: bounds! !\\n\\n\\n!MorphicModel class methodsFor: 'new-morph participation' stamp: 'di 2/21/98 11:01'!\\nincludeInNewMorphMenu\\n\\t\\\"Only include Models that are appropriate\\\"\\n\\t^ false! !\\n\\n\\n!MorphicModel class methodsFor: 'prototype access'!\\nprototype\\n\\t\\\"Return the prototype for this morph.\\\"\\n\\n\\t^ prototype\\n! !\\n\\n!MorphicModel class methodsFor: 'prototype access' stamp: 'gm 2/22/2003 19:13'!\\nprototype: aMorph\\n\\t\\\"Store a copy of the given morph as a prototype to be copied to make new instances.\\\"\\n\\n\\taMorph ifNil: [prototype _ nil. ^ self].\\n\\n\\tprototype _ aMorph veryDeepCopy.\\n\\t(prototype isMorphicModel) ifTrue: \\n\\t\\t[prototype model: nil slotName: nil].\\n! !\\n\\n\\n!MorphicModel class methodsFor: 'queries'!\\nhasPrototype\\n\\t\\\"Return true if there is a prototype for this morph.\\\"\\n\\n\\t^ prototype ~~ nil\\n! !\\n\\n\\n!MorphicModel class methodsFor: 'subclass creation'!\\nnewSubclass\\n\\t| i className |\\n\\ti _ 1.\\n\\t[className _ (self name , i printString) asSymbol.\\n\\t Smalltalk includesKey: className]\\n\\t\\twhileTrue: [i _ i + 1].\\n\\n\\t^ self subclass: className\\n\\t\\tinstanceVariableNames: ''\\n\\t\\tclassVariableNames: ''\\n\\t\\tpoolDictionaries: ''\\n\\t\\tcategory: 'Morphic-Models'! !\\n\\n\\n!MorphicModel class methodsFor: 'testing' stamp: 'tk 3/15/98 20:13'!\\nofficialClass\\n\\t\\\"We want to make a new instance of the receiver, which is a subclass of MorphicModel. Answer who to make a new subclass of. Also used to tell if a given class is a UniClass, existing only for its single instance.\\\"\\n\\n\\t^ self name last isDigit ifTrue: [MorphicModel] ifFalse: [self]\\n\\t\\t\\\"MorphicModel7 can not have subclasses, but Slider and SystemWindow may\\\"! !\\n\\n\\n!MorphicModel class methodsFor: '*eToys-queries' stamp: 'sw 2/27/2002 14:58'!\\nbaseUniclass\\n\\t\\\"Answer the uniclass that new instances should be instances of. This protocol is primarily intended for the Player lineage, but can get sent to a MorphicModel subclass when the project-loading mechanism is scrambling to fix up projects that have naming conflicts with the project being loaded.\\\"\\n\\n\\t| curr |\\n\\tcurr _ self.\\n\\t[curr theNonMetaClass superclass name endsWithDigit]\\n\\t\\twhileTrue:\\n\\t\\t\\t[curr _ curr superclass].\\n\\t^ curr\\n\\n\\\"PlayWithMe1 baseUniclass\\\"! !\\nAppRegistry subclass: #MorphicTextEditor\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Applications'!\\nToolBuilder subclass: #MorphicToolBuilder\\n\\tinstanceVariableNames: 'widgets panes parentMenu'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ToolBuilder-Morphic'!\\n!MorphicToolBuilder commentStamp: 'ar 2/11/2005 15:02' prior: 0!\\nThe Morphic tool builder.!\\n\\n\\n!MorphicToolBuilder methodsFor: 'opening' stamp: 'ar 6/5/2005 12:40'!\\nclose: aWidget\\n\\t\\\"Close a previously opened widget\\\"\\n\\taWidget delete! !\\n\\n!MorphicToolBuilder methodsFor: 'opening' stamp: 'ar 2/28/2006 17:39'!\\nopen: anObject\\n\\t\\\"Build and open the object. Answer the widget opened.\\\"\\n\\t| morph |\\n\\tmorph := self build: anObject.\\n\\t(morph isKindOf: MenuMorph)\\n\\t\\tifTrue:[morph popUpInWorld: World].\\n\\t(morph isKindOf: SystemWindow)\\n\\t\\tifTrue:[morph openInWorldExtent: morph extent]\\n\\t\\tifFalse:[morph openInWorld].\\n\\t^morph! !\\n\\n!MorphicToolBuilder methodsFor: 'opening' stamp: 'ar 6/5/2005 12:40'!\\nopen: anObject label: aString\\n\\t\\\"Build an open the object, labeling it appropriately. Answer the widget opened.\\\"\\n\\t| window |\\n\\twindow := self open: anObject.\\n\\twindow setLabel: aString.\\n\\t^window! !\\n\\n!MorphicToolBuilder methodsFor: 'opening' stamp: 'ar 6/5/2005 12:41'!\\nrunModal: aWidget\\n\\t\\\"Run the (previously opened) widget modally, e.g., \\n\\tdo not return control to the sender before the user has responded.\\\"\\n\\t[aWidget world notNil] whileTrue: [\\n\\t\\taWidget outermostWorldMorph doOneCycle.\\n\\t].\\n! !\\n\\n\\n!MorphicToolBuilder methodsFor: 'pluggable widgets' stamp: 'ar 2/12/2005 14:22'!\\nbuildPluggableActionButton: aSpec\\n\\t| button |\\n\\tbutton := self buildPluggableButton: aSpec.\\n\\tbutton beActionButton.\\n\\t^button! !\\n\\n!MorphicToolBuilder methodsFor: 'pluggable widgets' stamp: 'ar 7/14/2005 22:27'!\\nbuildPluggableButton: aSpec\\n\\t| widget label state action enabled |\\n\\tlabel := aSpec label.\\n\\tstate := aSpec state.\\n\\taction := aSpec action.\\n\\twidget := PluggableButtonMorphPlus on: aSpec model\\n\\t\\t\\t\\tgetState: (state isSymbol ifTrue:[state])\\n\\t\\t\\t\\taction: nil\\n\\t\\t\\t\\tlabel: (label isSymbol ifTrue:[label]).\\n\\tself register: widget id: aSpec name.\\n\\tenabled := aSpec enabled.\\n\\tenabled isSymbol\\n\\t\\tifTrue:[widget getEnabledSelector: enabled]\\n\\t\\tifFalse:[widget enabled:enabled].\\n\\twidget action: action.\\n\\twidget getColorSelector: aSpec color.\\n\\twidget offColor: Color transparent.\\n\\taSpec help ifNotNil:[widget setBalloonText: aSpec help].\\n\\t(label isSymbol or:[label == nil]) ifFalse:[widget label: label].\\n\\tself setFrame: aSpec frame in: widget.\\n\\tparent ifNotNil:[self add: widget to: parent].\\n\\t^widget! !\\n\\n!MorphicToolBuilder methodsFor: 'pluggable widgets' stamp: 'md 8/15/2005 17:55'!\\nbuildPluggableInputField: aSpec\\n\\t| widget |\\n\\twidget := self buildPluggableText: aSpec.\\n\\twidget acceptOnCR: true.\\n\\twidget hideScrollBarsIndefinitely.\\n\\t^widget! !\\n\\n!MorphicToolBuilder methodsFor: 'pluggable widgets' stamp: 'ar 7/15/2005 12:07'!\\nbuildPluggableList: aSpec\\n\\t| widget listClass getIndex setIndex |\\n\\taSpec getSelected ifNil:[\\n\\t\\tlistClass := PluggableListMorphPlus.\\n\\t\\tgetIndex := aSpec getIndex.\\n\\t\\tsetIndex := aSpec setIndex.\\n\\t] ifNotNil:[\\n\\t\\tlistClass := PluggableListMorphByItemPlus.\\n\\t\\tgetIndex := aSpec getSelected.\\n\\t\\tsetIndex := aSpec setSelected.\\n\\t].\\n\\twidget := listClass on: aSpec model\\n\\t\\t\\t\\tlist: aSpec list\\n\\t\\t\\t\\tselected: getIndex\\n\\t\\t\\t\\tchangeSelected: setIndex\\n\\t\\t\\t\\tmenu: aSpec menu\\n\\t\\t\\t\\tkeystroke: aSpec keyPress.\\n\\tself register: widget id: aSpec name.\\n\\twidget dragItemSelector: aSpec dragItem.\\n\\twidget dropItemSelector: aSpec dropItem.\\n\\twidget wantsDropSelector: aSpec dropAccept.\\n\\twidget autoDeselect: aSpec autoDeselect.\\n\\tself setFrame: aSpec frame in: widget.\\n\\tparent ifNotNil:[self add: widget to: parent].\\n\\tpanes ifNotNil:[\\n\\t\\taSpec list ifNotNil:[panes add: aSpec list].\\n\\t].\\n\\t^widget! !\\n\\n!MorphicToolBuilder methodsFor: 'pluggable widgets' stamp: 'ar 7/14/2005 22:27'!\\nbuildPluggableMultiSelectionList: aSpec\\n\\t| widget listClass |\\n\\taSpec getSelected ifNotNil:[^self error:'There is no PluggableListMorphOfManyByItem'].\\n\\tlistClass := PluggableListMorphOfMany.\\n\\twidget := listClass on: aSpec model\\n\\t\\tlist: aSpec list\\n\\t\\tprimarySelection: aSpec getIndex\\n\\t\\tchangePrimarySelection: aSpec setIndex\\n\\t\\tlistSelection: aSpec getSelectionList\\n\\t\\tchangeListSelection: aSpec setSelectionList\\n\\t\\tmenu: aSpec menu.\\n\\tself register: widget id: aSpec name.\\n\\twidget keystrokeActionSelector: aSpec keyPress.\\n\\tself setFrame: aSpec frame in: widget.\\n\\tparent ifNotNil:[self add: widget to: parent].\\n\\tpanes ifNotNil:[\\n\\t\\taSpec list ifNotNil:[panes add: aSpec list].\\n\\t].\\n\\t^widget! !\\n\\n!MorphicToolBuilder methodsFor: 'pluggable widgets' stamp: 'ar 7/14/2005 22:28'!\\nbuildPluggablePanel: aSpec\\n\\t| widget children |\\n\\twidget := PluggablePanelMorph new.\\n\\tself register: widget id: aSpec name.\\n\\twidget model: aSpec model.\\n\\twidget color: Color transparent.\\n\\twidget clipSubmorphs: true.\\n\\tchildren := aSpec children.\\n\\tchildren isSymbol ifTrue:[\\n\\t\\twidget getChildrenSelector: children.\\n\\t\\twidget update: children.\\n\\t\\tchildren := #().\\n\\t].\\n\\tself buildAll: children in: widget.\\n\\tself setFrame: aSpec frame in: widget.\\n\\tparent ifNotNil:[self add: widget to: parent].\\n\\tself setLayout: aSpec layout in: widget.\\n\\t^widget! !\\n\\n!MorphicToolBuilder methodsFor: 'pluggable widgets' stamp: 'ar 7/14/2005 22:28'!\\nbuildPluggableText: aSpec\\n\\t| widget |\\n\\twidget := PluggableTextMorphPlus on: aSpec model\\n\\t\\t\\t\\ttext: aSpec getText \\n\\t\\t\\t\\taccept: aSpec setText\\n\\t\\t\\t\\treadSelection: aSpec selection \\n\\t\\t\\t\\tmenu: aSpec menu.\\n\\tself register: widget id: aSpec name.\\n\\twidget getColorSelector: aSpec color.\\n\\tself setFrame: aSpec frame in: widget.\\n\\tparent ifNotNil:[self add: widget to: parent].\\n\\tpanes ifNotNil:[\\n\\t\\taSpec getText ifNotNil:[panes add: aSpec getText].\\n\\t].\\n\\t^widget! !\\n\\n!MorphicToolBuilder methodsFor: 'pluggable widgets' stamp: 'ar 7/15/2005 12:10'!\\nbuildPluggableTree: aSpec\\n\\t| widget |\\n\\twidget := PluggableTreeMorph new.\\n\\tself register: widget id: aSpec name.\\n\\twidget model: aSpec model.\\n\\twidget getSelectedPathSelector: aSpec getSelectedPath.\\n\\twidget setSelectedSelector: aSpec setSelected.\\n\\twidget getChildrenSelector: aSpec getChildren.\\n\\twidget hasChildrenSelector: aSpec hasChildren.\\n\\twidget getLabelSelector: aSpec label.\\n\\twidget getIconSelector: aSpec icon.\\n\\twidget getHelpSelector: aSpec help.\\n\\twidget getMenuSelector: aSpec menu.\\n\\twidget keystrokeActionSelector: aSpec keyPress.\\n\\twidget getRootsSelector: aSpec roots.\\n\\twidget autoDeselect: aSpec autoDeselect.\\n\\twidget dropItemSelector: aSpec dropItem.\\n\\twidget wantsDropSelector: aSpec dropAccept.\\n\\tself setFrame: aSpec frame in: widget.\\n\\tparent ifNotNil:[self add: widget to: parent].\\n\\tpanes ifNotNil:[\\n\\t\\taSpec roots ifNotNil:[panes add: aSpec roots].\\n\\t].\\n\\t^widget! !\\n\\n!MorphicToolBuilder methodsFor: 'pluggable widgets' stamp: 'ar 9/17/2005 21:07'!\\nbuildPluggableWindow: aSpec\\n\\t| widget children label |\\n\\taSpec layout == #proportional ifFalse:[\\n\\t\\t\\\"This needs to be implemented - probably by adding a single pane and then the rest\\\"\\n\\t\\t^self error: 'Not implemented'.\\n\\t].\\n\\twidget := PluggableSystemWindow new.\\n\\tself register: widget id: aSpec name.\\n\\twidget model: aSpec model.\\n\\t(label := aSpec label) ifNotNil:[\\n\\t\\tlabel isSymbol \\n\\t\\t\\tifTrue:[widget getLabelSelector: label]\\n\\t\\t\\tifFalse:[widget setLabel: label]].\\n\\tchildren := aSpec children.\\n\\tchildren isSymbol ifTrue:[\\n\\t\\twidget getChildrenSelector: children.\\n\\t\\twidget update: children.\\n\\t\\tchildren := #().\\n\\t].\\n\\twidget closeWindowSelector: aSpec closeAction.\\n\\tpanes := OrderedCollection new.\\n\\tself buildAll: children in: widget.\\n\\taSpec extent ifNotNil:[widget extent: aSpec extent].\\n\\twidget setUpdatablePanesFrom: panes.\\n\\t^widget! !\\n\\n\\n!MorphicToolBuilder methodsFor: 'private' stamp: 'ar 7/17/2005 00:00'!\\nadd: aMorph to: aParent\\n\\taParent addMorphBack: aMorph.\\n\\taParent isSystemWindow ifTrue:[\\n\\t\\taParent addPaneMorph: aMorph.\\n\\t].! !\\n\\n!MorphicToolBuilder methodsFor: 'private' stamp: 'stephaneducasse 2/3/2006 22:35'!\\nasFrame: aRectangle\\n\\t| frame |\\n\\taRectangle ifNil:[^nil].\\n\\tframe := LayoutFrame new.\\n\\tframe \\n\\t\\tleftFraction: aRectangle left; \\n\\t\\trightFraction: aRectangle right; \\n\\t\\ttopFraction: aRectangle top; \\n\\t\\tbottomFraction: aRectangle bottom.\\n\\t^frame! !\\n\\n!MorphicToolBuilder methodsFor: 'private' stamp: 'ar 7/14/2005 22:28'!\\nregister: widget id: id\\n\\tid ifNil:[^self].\\n\\twidgets ifNil:[widgets := Dictionary new].\\n\\twidgets at: id put: widget.! !\\n\\n!MorphicToolBuilder methodsFor: 'private' stamp: 'ar 2/12/2005 19:20'!\\nsetFrame: aRectangle in: widget\\n\\t| frame |\\n\\taRectangle ifNil:[^nil].\\n\\tframe := self asFrame: aRectangle.\\n\\twidget layoutFrame: frame.\\n\\twidget hResizing: #spaceFill; vResizing: #spaceFill.\\n\\t(parent isSystemWindow) ifTrue:[\\n\\t\\twidget borderWidth: 2; borderColor: #inset.\\n\\t].! !\\n\\n!MorphicToolBuilder methodsFor: 'private' stamp: 'ar 2/10/2005 22:28'!\\nsetLayout: layout in: widget\\n\\tlayout == #proportional ifTrue:[\\n\\t\\twidget layoutPolicy: ProportionalLayout new.\\n\\t\\t^self].\\n\\tlayout == #horizontal ifTrue:[\\n\\t\\twidget layoutPolicy: TableLayout new.\\n\\t\\twidget listDirection: #leftToRight.\\n\\t\\twidget submorphsDo:[:m| m hResizing: #spaceFill; vResizing: #spaceFill].\\n\\t\\t\\\"and then some...\\\"\\n\\t\\t^self].\\n\\tlayout == #vertical ifTrue:[\\n\\t\\twidget layoutPolicy: TableLayout new.\\n\\t\\twidget listDirection: #topToBottom.\\n\\t\\twidget submorphsDo:[:m| m hResizing: #spaceFill; vResizing: #spaceFill].\\n\\t\\t\\\"and then some...\\\"\\n\\t\\t^self].\\n\\t^self error: 'Unknown layout: ', layout.! !\\n\\n!MorphicToolBuilder methodsFor: 'private' stamp: 'ar 7/14/2005 22:30'!\\nwidgetAt: id ifAbsent: aBlock\\n\\twidgets ifNil:[^aBlock value].\\n\\t^widgets at: id ifAbsent: aBlock! !\\n\\n\\n!MorphicToolBuilder methodsFor: 'building' stamp: 'ar 2/28/2006 17:30'!\\nbuildPluggableMenu: menuSpec \\n\\t| prior menu |\\n\\tprior := parentMenu.\\n\\tparentMenu := menu := MenuMorph new.\\n\\tmenuSpec label ifNotNil:[parentMenu addTitle: menuSpec label].\\n\\tmenuSpec items do:[:each| each buildWith: self].\\n\\tparentMenu := prior.\\n\\t^menu! !\\n\\n!MorphicToolBuilder methodsFor: 'building' stamp: 'ar 2/28/2006 17:37'!\\nbuildPluggableMenuItem: itemSpec\\n\\t| item action label menu |\\n\\titem _ MenuItemMorph new.\\n\\tlabel := itemSpec label.\\n\\titemSpec checked ifTrue:[label := '<on>', label] ifFalse:[label := '<off>', label].\\n\\titem contents: label.\\n\\titem isEnabled: itemSpec enabled.\\n\\t(action := itemSpec action) ifNotNil:[\\n\\t\\titem \\n\\t\\t\\ttarget: action receiver;\\n\\t\\t\\tselector: action selector;\\n\\t\\t\\targuments: action arguments.\\n\\t].\\n\\t(menu := itemSpec subMenu) ifNotNil:[\\n\\t\\titem subMenu: (menu buildWith: self).\\n\\t].\\n\\tparentMenu ifNotNil:[parentMenu addMorphBack: item].\\n\\t^item! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphicToolBuilder class\\n\\tinstanceVariableNames: ''!\\n\\n!MorphicToolBuilder class methodsFor: 'accessing' stamp: 'ar 2/11/2005 15:24'!\\nisActiveBuilder\\n\\t\\\"Answer whether I am the currently active builder\\\"\\n\\t^Smalltalk isMorphic! !\\nToolBuilderTests subclass: #MorphicToolBuilderTests\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ToolBuilder-Morphic'!\\n!MorphicToolBuilderTests commentStamp: 'ar 2/11/2005 15:02' prior: 0!\\nTests for the Morphic tool builder.!\\n\\n\\n!MorphicToolBuilderTests methodsFor: 'support' stamp: 'ar 2/11/2005 19:26'!\\nacceptWidgetText\\n\\twidget hasUnacceptedEdits: true.\\n\\twidget accept.! !\\n\\n!MorphicToolBuilderTests methodsFor: 'support' stamp: 'ar 6/21/2005 10:35'!\\nbuttonWidgetEnabled\\n\\t\\\"Answer whether the current widget (a button) is currently enabled\\\"\\n\\t^widget enabled! !\\n\\n!MorphicToolBuilderTests methodsFor: 'support' stamp: 'ar 2/11/2005 19:22'!\\nchangeListWidget\\n\\twidget changeModelSelection: widget getCurrentSelectionIndex + 1.! !\\n\\n!MorphicToolBuilderTests methodsFor: 'support' stamp: 'ar 2/11/2005 19:15'!\\nfireButtonWidget\\n\\twidget performAction.! !\\n\\n!MorphicToolBuilderTests methodsFor: 'support' stamp: 'cwp 6/9/2005 00:11'!\\nfireMenuItemWidget\\n\\t(widget itemWithWording: 'Menu Item')\\n\\t\\tifNotNilDo: [:item | item doButtonAction]! !\\n\\n!MorphicToolBuilderTests methodsFor: 'support' stamp: 'ar 2/11/2005 14:46'!\\nsetUp\\n\\tsuper setUp.\\n\\tbuilder := MorphicToolBuilder new.! !\\n\\n!MorphicToolBuilderTests methodsFor: 'support' stamp: 'ar 2/11/2005 21:43'!\\nwidgetColor\\n\\t\\\"Answer color from widget\\\"\\n\\t^widget color! !\\n\\n\\n!MorphicToolBuilderTests methodsFor: 'tests-window' stamp: 'ar 2/13/2005 13:52'!\\ntestWindowDynamicLabel\\n\\tself makeWindow.\\n\\tself assert: (widget label = 'TestLabel').! !\\n\\n!MorphicToolBuilderTests methodsFor: 'tests-window' stamp: 'ar 2/13/2005 13:52'!\\ntestWindowStaticLabel\\n\\t| spec |\\n\\tspec := builder pluggableWindowSpec new.\\n\\tspec model: self.\\n\\tspec children: #().\\n\\tspec label: 'TestLabel'.\\n\\twidget := builder build: spec.\\n\\tself assert: (widget label = 'TestLabel').! !\\nDisplayTransform subclass: #MorphicTransform\\n\\tinstanceVariableNames: 'offset angle scale'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Graphics-Transformations'!\\n!MorphicTransform commentStamp: '<historical>' prior: 0!\\nThis class implements simple translation, scaling and rotation for points, as well as inverse transformations. These transformations are used in TransformMorphs (clipping scrollers) and TransformationMorphs (general flex-morph wrappers) to map, eg, global mouse coords into local coords, and to invert, eg, local damage rectangles into global damage rectangles.!\\n\\n\\n!MorphicTransform methodsFor: 'accessing'!\\nangle\\n\\t^ angle! !\\n\\n!MorphicTransform methodsFor: 'accessing' stamp: 'ar 11/9/1998 14:33'!\\ninverseTransformation\\n\\t\\\"Return the inverse transformation of the receiver\\\"\\n\\t^MorphicTransform\\n\\t\\toffset: (self transform: 0@0) - (self transform: offset)\\n\\t\\tangle: angle negated\\n\\t\\tscale: scale reciprocal! !\\n\\n!MorphicTransform methodsFor: 'accessing'!\\noffset\\n\\t^ offset\\n! !\\n\\n!MorphicTransform methodsFor: 'accessing'!\\nscale\\n\\t^ scale! !\\n\\n!MorphicTransform methodsFor: 'accessing'!\\nwithAngle: a\\n\\t\\\"Return a copy of me with a different Angle\\\"\\n\\t^ self copy setAngle: a! !\\n\\n!MorphicTransform methodsFor: 'accessing'!\\nwithOffset: a\\n\\t\\\"Return a copy of me with a different Offset\\\"\\n\\t^ self copy setOffset: a! !\\n\\n!MorphicTransform methodsFor: 'accessing'!\\nwithScale: a\\n\\t\\\"Return a copy of me with a different Scale\\\"\\n\\t^ self copy setScale: a! !\\n\\n\\n!MorphicTransform methodsFor: 'composing' stamp: 'nk 3/9/2001 13:55'!\\ncomposedWithLocal: aTransform\\n\\taTransform isIdentity ifTrue:[^self].\\n\\tself isIdentity ifTrue:[^aTransform].\\n\\taTransform isMorphicTransform ifFalse:[^super composedWithLocal: aTransform].\\n\\tself isPureTranslation ifTrue:[\\n\\t\\t^aTransform withOffset: aTransform offset + self offset].\\n\\taTransform isPureTranslation ifTrue:[\\n\\t\\t^self withOffset: (self localPointToGlobal: aTransform offset negated) negated].\\n\\t^super composedWithLocal: aTransform.! !\\n\\n\\n!MorphicTransform methodsFor: 'converting' stamp: 'ar 11/2/1998 20:14'!\\nasMatrixTransform2x3\\n\\t^((MatrixTransform2x3 withRotation: angle radiansToDegrees negated) composedWithLocal:\\n\\t\\t(MatrixTransform2x3 withScale: scale))\\n\\t\\t\\toffset: offset negated! !\\n\\n!MorphicTransform methodsFor: 'converting' stamp: 'di 10/26/1999 17:03'!\\nasMorphicTransform\\n\\n\\t^ self! !\\n\\n\\n!MorphicTransform methodsFor: 'initialize' stamp: 'ar 11/2/1998 20:58'!\\nsetIdentiy\\n\\tscale _ 1.0.\\n\\toffset _ 0@0.\\n\\tangle _ 0.0.! !\\n\\n\\n!MorphicTransform methodsFor: 'printing' stamp: 'ar 5/19/1999 18:21'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream nextPut:$(;\\n\\t\\tnextPutAll:'angle = '; print: angle;\\n\\t\\tnextPutAll:'; scale = '; print: scale;\\n\\t\\tnextPutAll:'; offset = '; print: offset;\\n\\t\\tnextPut:$).! !\\n\\n\\n!MorphicTransform methodsFor: 'testing' stamp: 'ar 11/2/1998 20:57'!\\nisIdentity\\n\\t\\\"Return true if the receiver is the identity transform; that is, if applying to a point returns the point itself.\\\"\\n\\n\\t^ self isPureTranslation and: [offset = (0@0)]\\n! !\\n\\n!MorphicTransform methodsFor: 'testing' stamp: 'ar 11/2/1998 19:51'!\\nisMorphicTransform\\n\\t^true! !\\n\\n!MorphicTransform methodsFor: 'testing' stamp: 'ar 11/2/1998 20:57'!\\nisPureTranslation\\n\\t\\\"Return true if the receiver specifies no rotation or scaling.\\\"\\n\\n\\t^ angle = 0.0 and: [scale = 1.0]\\n! !\\n\\n\\n!MorphicTransform methodsFor: 'transformations' stamp: 'di 3/4/98 19:10'!\\ncomposedWith: aTransform\\n\\t\\\"Return a new transform that has the effect of transforming points first by the receiver and then by the argument.\\\"\\n\\n\\tself isIdentity ifTrue: [^ aTransform].\\n\\taTransform isIdentity ifTrue: [^ self].\\n\\t^ CompositeTransform new globalTransform: self\\n\\t\\t\\t\\t\\t\\t\\tlocalTransform: aTransform! !\\n\\n!MorphicTransform methodsFor: 'transformations' stamp: 'di 10/28/1999 09:10'!\\ninvert: aPoint\\n\\t\\\"Transform the given point from local to global coordinates.\\\"\\n\\t| p3 p2 |\\n\\tself isPureTranslation ifTrue: [^ aPoint - offset].\\n\\tp3 _ aPoint * scale.\\n\\tp2 _ ((p3 x * angle cos) + (p3 y * angle sin))\\n\\t\\t@ ((p3 y * angle cos) - (p3 x * angle sin)).\\n\\t^ (p2 - offset)\\n! !\\n\\n!MorphicTransform methodsFor: 'transformations' stamp: 'di 10/3/1998 00:18'!\\ninvertBoundsRect: aRectangle\\n\\t\\\"Return a rectangle whose coordinates have been transformed\\n\\tfrom local back to global coordinates. NOTE: if the transformation\\n\\tis not just a translation, then it will compute the bounding box\\n\\tin global coordinates.\\\"\\n\\t| outerRect |\\n\\tself isPureTranslation\\n\\tifTrue:\\n\\t\\t[^ (self invert: aRectangle topLeft)\\n\\t\\t\\tcorner: (self invert: aRectangle bottomRight)]\\n\\tifFalse:\\n\\t\\t[outerRect _ Rectangle encompassing:\\n\\t\\t\\t(aRectangle innerCorners collect: [:p | self invert: p]).\\n\\t\\t\\\"Following asymmetry due to likely subsequent truncation\\\"\\n\\t\\t^ outerRect topLeft - (1@1) corner: outerRect bottomRight + (2@2)]! !\\n\\n!MorphicTransform methodsFor: 'transformations' stamp: 'di 10/2/1998 08:54'!\\ninvertRect: aRectangle\\n\\n\\tself error: 'method name changed to emphasize enclosing bounds'.\\n\\t^ self invertBoundsRect: aRectangle! !\\n\\n!MorphicTransform methodsFor: 'transformations' stamp: 'di 10/28/1999 09:05'!\\ntransform: aPoint\\n\\t\\\"Transform the given point from global to local coordinates.\\\"\\n\\t| p2 p3 |\\n\\tself isPureTranslation ifTrue: [^ aPoint + offset].\\n\\tp2 _ aPoint + offset.\\n\\tp3 _ (((p2 x * angle cos) - (p2 y * angle sin))\\n\\t\\t@ ((p2 y * angle cos) + (p2 x * angle sin)))\\n\\t\\t\\t/ scale.\\n\\t^ p3! !\\n\\n!MorphicTransform methodsFor: 'transformations' stamp: 'di 10/3/1998 00:18'!\\ntransformBoundsRect: aRectangle\\n\\t\\\"Return a rectangle whose coordinates have been transformed\\n\\tfrom global to local coordinates. NOTE: if the transformation\\n\\tis not just a translation, then it will compute the bounding box\\n\\tin global coordinates.\\\"\\n\\t| outerRect |\\n\\tself isPureTranslation\\n\\tifTrue:\\n\\t\\t[^ (self transform: aRectangle topLeft)\\n\\t\\t\\tcorner: (self transform: aRectangle bottomRight)]\\n\\tifFalse:\\n\\t\\t[outerRect _ Rectangle encompassing:\\n\\t\\t\\t(aRectangle innerCorners collect: [:p | self transform: p]).\\n\\t\\t\\\"Following asymmetry due to likely subsequent truncation\\\"\\n\\t\\t^ outerRect topLeft - (1@1) corner: outerRect bottomRight + (2@2)]! !\\n\\n\\n!MorphicTransform methodsFor: 'transforming points' stamp: 'ar 11/2/1998 16:13'!\\nglobalPointToLocal: aPoint\\n\\t\\\"Transform aPoint from global coordinates into local coordinates\\\"\\n\\t^self transform: aPoint! !\\n\\n!MorphicTransform methodsFor: 'transforming points' stamp: 'ar 11/2/1998 16:32'!\\nlocalPointToGlobal: aPoint\\n\\t\\\"Transform aPoint from global coordinates into local coordinates\\\"\\n\\t^self invert: aPoint! !\\n\\n\\n!MorphicTransform methodsFor: '*nebraska-*nebraska-Morphic-Remote' stamp: 'ls 10/9/1999 19:06'!\\nencodeForRemoteCanvas\\n\\t\\\"encode this transform into a string for use by a RemoteCanvas\\\"\\n\\t^String streamContents: [ :str |\\n\\t\\tstr nextPutAll: 'Morphic,';\\n\\t\\t\\tprint: offset x truncated;\\n\\t\\t\\tnextPut: $,;\\n\\t\\t\\tprint: offset y truncated;\\n\\t\\t\\tnextPut: $,;\\n\\t\\t\\tprint: scale;\\n\\t\\t\\tnextPut: $,;\\n\\t\\t\\tprint: angle\\n\\t]! !\\n\\n\\n!MorphicTransform methodsFor: 'private'!\\nsetAngle: aFloat\\n\\n\\tangle _ aFloat.\\n! !\\n\\n!MorphicTransform methodsFor: 'private'!\\nsetOffset: aPoint\\n\\n\\toffset _ aPoint.\\n! !\\n\\n!MorphicTransform methodsFor: 'private'!\\nsetOffset: aPoint angle: a scale: s\\n\\n\\toffset _ aPoint.\\n\\tangle _ a.\\n\\tscale _ s! !\\n\\n!MorphicTransform methodsFor: 'private'!\\nsetScale: aFloat\\n\\n\\tscale _ aFloat.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphicTransform class\\n\\tinstanceVariableNames: ''!\\n\\n!MorphicTransform class methodsFor: 'instance creation'!\\nidentity\\n\\n\\t^ self offset: 0@0 angle: 0.0 scale: 1.0! !\\n\\n!MorphicTransform class methodsFor: 'instance creation'!\\nnew\\n\\n\\t^ self offset: 0@0\\n! !\\n\\n!MorphicTransform class methodsFor: 'instance creation'!\\noffset: aPoint\\n\\n\\t^ self offset: aPoint angle: 0.0 scale: 1.0! !\\n\\n!MorphicTransform class methodsFor: 'instance creation'!\\noffset: aPoint angle: a scale: s\\n\\n\\t^ self basicNew setOffset: aPoint angle: a scale: s! !\\n\\n\\n!MorphicTransform class methodsFor: '*nebraska-instance creation' stamp: 'sd 11/20/2005 21:25'!\\nfromRemoteCanvasEncoding: encoded\\n\\t\\\"DisplayTransform fromRemoteCanvasEncoding: 'Morphic,-88,-128,1.345165663873898,0.1352584843149221'\\\"\\n\\t| type offsetXEnc offsetYEnc scaleEnc angleEnc offsetX offsetY angle scale rs |\\n\\n\\t\\\"separate the numbers\\\"\\n\\trs := ReadStream on: encoded.\\n\\ttype := rs upTo: $,.\\n\\toffsetXEnc := rs upTo: $,.\\n\\toffsetYEnc := rs upTo: $,.\\n\\tscaleEnc := rs upTo: $,.\\n\\tangleEnc := rs upToEnd.\\n\\n\\t\\\"decode the numbers\\\"\\n\\toffsetX := Integer readFromString: offsetXEnc.\\n\\toffsetY := Integer readFromString: offsetYEnc.\\n\\n\\tscale := Number readFromString: scaleEnc.\\n\\tangle := Number readFromString: angleEnc.\\n\\n\\t\\\"create an instance\\\"\\n\\t^self offset: offsetX@offsetY angle: angle scale: scale! !\\nUIManager subclass: #MorphicUIManager\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ToolBuilder-Morphic'!\\n!MorphicUIManager commentStamp: 'ar 2/11/2005 21:52' prior: 0!\\nThe Morphic ui manager.!\\n\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 7/16/2005 19:37'!\\nchooseDirectory: label from: dir\\n\\t\\\"Let the user choose a directory\\\"\\n\\t^FileList2 modalFolderSelector: dir! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 7/17/2005 00:28'!\\nchooseFileMatching: patterns label: aString\\n\\t\\\"Let the user choose a file matching the given patterns\\\"\\n\\t| result |\\n\\tresult := FileList2 modalFileSelectorForSuffixes: patterns.\\n\\t^result ifNotNil:[result fullName]! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 12/27/2004 10:47'!\\nchooseFrom: aList lines: linesArray title: aString\\n\\t\\\"Choose an item from the given list. Answer the index of the selected item.\\\"\\n\\t| menu |\\n\\tmenu := PopUpMenu labelArray: aList lines: linesArray.\\n\\t^aString isEmpty ifTrue:[menu startUp] ifFalse:[menu startUpWithCaption: aString]! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 7/15/2005 23:44'!\\nchooseFrom: labelList values: valueList lines: linesArray title: aString\\n\\t\\\"Choose an item from the given list. Answer the selected item.\\\"\\n\\t| menu |\\n\\tmenu := SelectionMenu labels: labelList lines: linesArray selections: valueList.\\n\\t^aString isEmpty ifTrue:[menu startUp] ifFalse:[menu startUpWithCaption: aString]! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 12/27/2004 08:45'!\\nconfirm: queryString\\n\\t\\\"Put up a yes/no menu with caption queryString. Answer true if the \\n\\tresponse is yes, false if no. This is a modal question--the user must \\n\\trespond yes or no.\\\"\\n\\t^PopUpMenu confirm: queryString! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 12/27/2004 09:49'!\\nconfirm: aString orCancel: cancelBlock\\n\\t\\\"Put up a yes/no/cancel menu with caption aString. Answer true if \\n\\tthe response is yes, false if no. If cancel is chosen, evaluate \\n\\tcancelBlock. This is a modal question--the user must respond yes or no.\\\"\\n\\t^PopUpMenu confirm: aString orCancel: cancelBlock! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 2/28/2005 17:13'!\\ndisplayProgress: titleString at: aPoint from: minVal to: maxVal during: workBlock\\n\\t\\\"Display titleString as a caption over a progress bar while workBlock is evaluated.\\\"\\n\\t^ProgressInitiationException \\n\\t\\tdisplay: titleString\\n\\t\\tat: aPoint \\n\\t\\tfrom: minVal \\n\\t\\tto: maxVal \\n\\t\\tduring: workBlock! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 7/17/2005 00:27'!\\nedit: aText label: labelString accept: anAction\\n\\t\\\"Open an editor on the given string/text\\\"\\n\\t| window holder text |\\n\\tholder := StringHolder new.\\n\\tholder contents: aText.\\n\\ttext := PluggableTextMorphPlus \\n\\t\\ton: holder \\n\\t\\ttext: #contents \\n\\t\\taccept: #acceptContents: \\n\\t\\treadSelection: nil \\n\\t\\tmenu: nil.\\n\\ttext acceptAction: anAction.\\n\\twindow := SystemWindow new.\\n\\tlabelString ifNotNil:[window setLabel: labelString].\\n\\twindow addMorph: text frame: (0@0 extent: 1@1).\\n\\twindow paneColor: Color gray.\\n\\twindow openInWorld.\\n! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 2/28/2005 17:07'!\\ninformUserDuring: aBlock\\n\\t\\\"Display a message above (or below if insufficient room) the cursor \\n\\tduring execution of the given block.\\n\\t\\tUIManager default informUserDuring:[:bar|\\n\\t\\t\\t#(one two three) do:[:info|\\n\\t\\t\\t\\tbar value: info.\\n\\t\\t\\t\\t(Delay forSeconds: 1) wait]]\\\"\\n\\t(MVCMenuMorph from: (SelectionMenu labels: '') title: '\\t\\t\\t\\t\\t\\t')\\n\\t\\tinformUserAt: Sensor cursorPoint during: aBlock.! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 12/27/2004 08:46'!\\ninform: aString\\n\\t\\\"Display a message for the user to read and then dismiss\\\"\\n\\t^PopUpMenu inform: aString! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 2/28/2005 17:05'!\\nmultiLineRequest: queryString centerAt: aPoint initialAnswer: defaultAnswer answerHeight: answerHeight\\n\\t\\\"Create a multi-line instance of me whose question is queryString with\\n\\tthe given initial answer. Invoke it centered at the given point, and\\n\\tanswer the string the user accepts. Answer nil if the user cancels. An\\n\\tempty string returned means that the ussr cleared the editing area and\\n\\tthen hit 'accept'. Because multiple lines are invited, we ask that the user\\n\\tuse the ENTER key, or (in morphic anyway) hit the 'accept' button, to \\n\\tsubmit; that way, the return key can be typed to move to the next line.\\\"\\n\\t^FillInTheBlank multiLineRequest: queryString centerAt: aPoint initialAnswer: defaultAnswer answerHeight: answerHeight! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 12/27/2004 08:47'!\\nrequestPassword: queryString\\n\\t\\\"Create an instance of me whose question is queryString. Invoke it centered\\n\\tat the cursor, and answer the string the user accepts. Answer the empty \\n\\tstring if the user cancels.\\\"\\n\\t^FillInTheBlank requestPassword: queryString! !\\n\\n!MorphicUIManager methodsFor: 'ui requests' stamp: 'ar 12/27/2004 08:46'!\\nrequest: queryString initialAnswer: defaultAnswer \\n\\t\\\"Create an instance of me whose question is queryString with the given \\n\\tinitial answer. Invoke it centered at the given point, and answer the \\n\\tstring the user accepts. Answer the empty string if the user cancels.\\\"\\n\\t^FillInTheBlank request: queryString initialAnswer: defaultAnswer ! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMorphicUIManager class\\n\\tinstanceVariableNames: ''!\\n\\n!MorphicUIManager class methodsFor: 'accessing' stamp: 'ar 2/11/2005 15:41'!\\nisActiveManager\\n\\t\\\"Answer whether I should act as the active ui manager\\\"\\n\\t^Smalltalk isMorphic! !\\nMorphicEvent subclass: #MorphicUnknownEvent\\n\\tinstanceVariableNames: 'type argument'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: 'EventSensorConstants'\\n\\tcategory: 'Morphic-Events'!\\n\\n!MorphicUnknownEvent methodsFor: 'accessing' stamp: 'ar 10/25/2000 20:04'!\\nargument\\n\\t^argument! !\\n\\n!MorphicUnknownEvent methodsFor: 'accessing' stamp: 'ar 10/25/2000 20:04'!\\nargument: arg\\n\\targument _ arg! !\\n\\n!MorphicUnknownEvent methodsFor: 'accessing' stamp: 'ar 10/25/2000 19:55'!\\nposition\\n\\t^0@0! !\\n\\n!MorphicUnknownEvent methodsFor: 'accessing' stamp: 'ar 10/25/2000 19:55'!\\ntype\\n\\t^type! !\\n\\n\\n!MorphicUnknownEvent methodsFor: 'initialize' stamp: 'ar 10/26/2000 01:20'!\\ntype: eventType readFrom: aStream\\n\\t| typeAndArg |\\n\\ttimeStamp _ Integer readFrom: aStream.\\n\\taStream skip: 1.\\n\\ttypeAndArg _ Object readFrom: aStream.\\n\\ttype _ typeAndArg first.\\n\\targument _ typeAndArg last.! !\\n\\n\\n!MorphicUnknownEvent methodsFor: 'objects from disk' stamp: 'RAA 12/20/2000 17:48'!\\nconvertToCurrentVersion: varDict refStream: smartRefStrm\\n\\t\\n\\ttype ifNil: [type _ #startSound].\\n\\tsource ifNil: [source _ varDict at: 'sourceHand'].\\n\\targument ifNil: [argument _ varDict at: 'sound' ifAbsent: [nil]].\\t\\\"???\\\"\\n\\t^super convertToCurrentVersion: varDict refStream: smartRefStrm.\\n\\n! !\\n\\n\\n!MorphicUnknownEvent methodsFor: 'printing' stamp: 'ar 10/26/2000 01:19'!\\nstoreOn: aStream\\n\\taStream nextPutAll: 'unknown'.\\n\\taStream space.\\n\\tself timeStamp storeOn: aStream.\\n\\taStream space.\\n\\t{type. argument} storeOn: aStream.! !\\n\\n\\n!MorphicUnknownEvent methodsFor: 'private' stamp: 'ar 10/25/2000 19:59'!\\nsetType: evtType argument: arg\\n\\ttype _ evtType.\\n\\targument _ arg.! !\\n\\n!MorphicUnknownEvent methodsFor: 'private' stamp: 'ar 10/25/2000 19:58'!\\nsetType: evtType argument: arg hand: evtHand stamp: stamp\\n\\ttype _ evtType.\\n\\targument _ arg.\\n\\tsource _ evtHand.\\n\\ttimeStamp _ stamp.! !\\nMorph subclass: #MouseActionIndicatorMorph\\n\\tinstanceVariableNames: 'siblings'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Widgets'!\\n!MouseActionIndicatorMorph commentStamp: '<historical>' prior: 0!\\nI am used to highlight morphs which have a special mouseup action!\\n\\n\\n!MouseActionIndicatorMorph methodsFor: 'as yet unclassified' stamp: 'RAA 7/12/2000 10:49'!\\ndeleteWithSiblings\\n\\n\\tsiblings do: [ :each | each delete]\\n! !\\n\\n!MouseActionIndicatorMorph methodsFor: 'as yet unclassified' stamp: 'RAA 7/12/2000 10:49'!\\nsiblings: aCollection\\n\\n\\tsiblings _ aCollection.\\n! !\\n\\n\\n!MouseActionIndicatorMorph methodsFor: 'event handling' stamp: 'RAA 7/12/2000 10:48'!\\nhandlesMouseOver: evt\\n\\n\\t^true! !\\n\\n!MouseActionIndicatorMorph methodsFor: 'event handling' stamp: 'RAA 7/17/2000 09:52'!\\nhandlesMouseOverDragging: evt\\n\\n\\t^true! !\\n\\n!MouseActionIndicatorMorph methodsFor: 'event handling' stamp: 'RAA 7/12/2000 10:50'!\\nmouseEnter: evt\\n\\n\\tself deleteWithSiblings\\n! !\\n\\n!MouseActionIndicatorMorph methodsFor: 'event handling' stamp: 'RAA 7/17/2000 09:52'!\\nmouseEnterDragging: evt\\n\\n\\tself deleteWithSiblings\\n! !\\n\\n\\n!MouseActionIndicatorMorph methodsFor: 'initialization' stamp: 'RAA 7/12/2000 10:48'!\\ninitialize\\n\\n\\tsuper initialize.\\n\\tsiblings _ #().! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMouseActionIndicatorMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!MouseActionIndicatorMorph class methodsFor: 'as yet unclassified' stamp: 'RAA 7/12/2000 11:08'!\\nworld: aWorld inner: innerRectangle outer: outerRectangle color: aColor\\n\\n\\t| allRects allMorphs |\\n\\n\\tallRects _ outerRectangle areasOutside: innerRectangle.\\n\\tallMorphs _ allRects collect: [ :each |\\n\\t\\tself new bounds: each; color: aColor\\n\\t].\\n\\tallMorphs do: [ :each |\\n\\t\\teach siblings: allMorphs; openInWorld: aWorld\\n\\t].\\n\\t^allMorphs\\n\\n\\n! !\\nMouseEvent subclass: #MouseButtonEvent\\n\\tinstanceVariableNames: 'whichButton'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Events'!\\n\\n!MouseButtonEvent methodsFor: 'accessing' stamp: 'ar 9/15/2000 19:58'!\\nblueButtonChanged\\n\\t\\\"Answer true if the blue mouse button has changed. This is the third mouse button or cmd+click on the Mac.\\\"\\n\\n\\t^ whichButton anyMask: 1! !\\n\\n!MouseButtonEvent methodsFor: 'accessing' stamp: 'ar 9/15/2000 19:58'!\\nredButtonChanged\\n\\t\\\"Answer true if the red mouse button has changed. This is the first mouse button.\\\"\\n\\n\\t^ whichButton anyMask: 4! !\\n\\n!MouseButtonEvent methodsFor: 'accessing' stamp: 'nk 3/11/2004 17:44'!\\nwhichButton\\n\\t^whichButton! !\\n\\n!MouseButtonEvent methodsFor: 'accessing' stamp: 'ar 9/15/2000 19:59'!\\nyellowButtonChanged\\n\\t\\\"Answer true if the yellow mouse button has changed. This is the second mouse button or option+click on the Mac.\\\"\\n\\n\\t^ whichButton anyMask: 2! !\\n\\n\\n!MouseButtonEvent methodsFor: 'dispatching' stamp: 'ar 9/16/2000 13:05'!\\nsentTo: anObject\\n\\t\\\"Dispatch the receiver into anObject\\\"\\n\\ttype == #mouseDown ifTrue:[^anObject handleMouseDown: self].\\n\\ttype == #mouseUp ifTrue:[^anObject handleMouseUp: self].\\n\\t^super sentTo: anObject! !\\n\\n\\n!MouseButtonEvent methodsFor: 'initialize' stamp: 'ar 10/24/2000 16:29'!\\ntype: eventType readFrom: aStream\\n\\tsuper type: eventType readFrom: aStream.\\n\\taStream skip: 1.\\n\\twhichButton _ Integer readFrom: aStream.! !\\n\\n\\n!MouseButtonEvent methodsFor: 'printing' stamp: 'ar 10/24/2000 16:29'!\\nstoreOn: aStream\\n\\tsuper storeOn: aStream.\\n\\taStream space.\\n\\twhichButton storeOn: aStream.! !\\n\\n\\n!MouseButtonEvent methodsFor: '*nebraska-*nebraska-Morphic-Remote' stamp: 'dgd 2/22/2003 19:00'!\\ndecodeFromStringArray: array \\n\\t\\\"decode the receiver from an array of strings\\\"\\n\\n\\ttype := array first asSymbol.\\n\\tposition := CanvasDecoder decodePoint: (array second).\\n\\tbuttons := CanvasDecoder decodeInteger: (array third).\\n\\twhichButton := CanvasDecoder decodeInteger: (array fourth)! !\\n\\n!MouseButtonEvent methodsFor: '*nebraska-*nebraska-Morphic-Remote' stamp: 'ar 10/25/2000 23:24'!\\nencodedAsStringArray\\n\\t\\\"encode the receiver into an array of strings, such that it can be retrieved via the fromStringArray: class method\\\"\\n\\t^{\\n\\t\\ttype.\\n\\t\\tCanvasEncoder encodePoint: position.\\n\\t\\tCanvasEncoder encodeInteger: buttons.\\n\\t\\tCanvasEncoder encodeInteger: whichButton.\\n\\t}! !\\n\\n\\n!MouseButtonEvent methodsFor: 'private' stamp: 'ar 10/5/2000 23:55'!\\nsetType: evtType position: evtPos which: button buttons: evtButtons hand: evtHand stamp: stamp\\n\\ttype _ evtType.\\n\\tposition _ evtPos.\\n\\tbuttons _ evtButtons.\\n\\tsource _ evtHand.\\n\\twasHandled _ false.\\n\\twhichButton _ button.\\n\\ttimeStamp _ stamp.! !\\nObject subclass: #MouseClickState\\n\\tinstanceVariableNames: 'clickClient clickState firstClickDown firstClickUp firstClickTime clickSelector dblClickSelector dblClickTime dblClickTimeoutSelector dragSelector dragThreshold'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Kernel'!\\n!MouseClickState commentStamp: '<historical>' prior: 0!\\nMouseClickState is a simple class managing the distinction between clicks, double clicks, and drag operations. It has been factored out of HandMorph due to the many instVars.\\n\\nInstance variables:\\n\\tclickClient \\t<Morph>\\t\\tThe client wishing to receive #click:, #dblClick:, or #drag messages\\n\\tclickState \\t<Symbol>\\tThe internal state of handling the last event (#firstClickDown, #firstClickUp, #firstClickTimedOut)\\n\\tfirstClickDown \\t<MorphicEvent>\\tThe #mouseDown event after which the client wished to receive #click: or similar messages\\n\\tfirstClickUp \\t<MorphicEvent>\\tThe first mouse up event which came in before the double click time out was exceeded (it is sent if there is a timout after the first mouse up event occured)\\n\\tfirstClickTime \\t<Integer>\\tThe millisecond clock value of the first event\\n\\tclickSelector \\t<Symbol>\\tThe selector to use for sending #click: messages\\n\\tdblClickSelector \\t<Symbol>\\tThe selector to use for sending #doubleClick: messages\\n\\tdblClickTime \\t<Integer>\\tTimout in milliseconds for a double click operation\\n\\tdragSelector \\t<Symbol>\\tThe selector to use for sending #drag: messages\\n\\tdragThreshold \\t<Integer>\\tThreshold used for determining if a #drag: message is sent (pixels!!)\\n!\\n\\n\\n!MouseClickState methodsFor: 'as yet unclassified' stamp: 'nk 7/26/2004 09:13'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream nextPut: $[; print: clickState; nextPut: $]\\n! !\\n\\n\\n!MouseClickState methodsFor: 'event handling' stamp: 'jcg 9/21/2001 11:23'!\\nclick\\n\\n\\tclickSelector ifNotNil: [clickClient perform: clickSelector with: firstClickDown]! !\\n\\n!MouseClickState methodsFor: 'event handling' stamp: 'jcg 9/21/2001 11:24'!\\ndoubleClick\\n\\n\\tdblClickSelector ifNotNil: [clickClient perform: dblClickSelector with: firstClickDown]! !\\n\\n!MouseClickState methodsFor: 'event handling' stamp: 'jcg 9/21/2001 13:09'!\\ndoubleClickTimeout\\n\\n\\tdblClickTimeoutSelector ifNotNil: [\\n\\t\\tclickClient perform: dblClickTimeoutSelector with: firstClickDown]! !\\n\\n!MouseClickState methodsFor: 'event handling' stamp: 'jcg 9/21/2001 11:27'!\\ndrag: event\\n\\n\\tdragSelector ifNotNil: [clickClient perform: dragSelector with: event]! !\\n\\n!MouseClickState methodsFor: 'event handling' stamp: 'nk 7/26/2004 10:21'!\\nhandleEvent: evt from: aHand\\n\\t\\\"Process the given mouse event to detect a click, double-click, or drag.\\n\\tReturn true if the event should be processed by the sender, false if it shouldn't.\\n\\tNOTE: This method heavily relies on getting *all* mouse button events.\\\"\\n\\t| localEvt timedOut isDrag |\\n\\ttimedOut _ (evt timeStamp - firstClickTime) > dblClickTime.\\n\\tlocalEvt _ evt transformedBy: (clickClient transformedFrom: aHand owner).\\n\\tisDrag _ (localEvt position - firstClickDown position) r > dragThreshold.\\n\\tclickState == #firstClickDown ifTrue: [\\n\\t\\t\\\"Careful here - if we had a slow cycle we may have a timedOut mouseUp event\\\"\\n\\t\\t(timedOut and:[localEvt isMouseUp not]) ifTrue:[\\n\\t\\t\\t\\\"timeout before #mouseUp -> keep waiting for drag if requested\\\"\\n\\t\\t\\tclickState _ #firstClickTimedOut.\\n\\t\\t\\tdragSelector ifNil:[\\n\\t\\t\\t\\taHand resetClickState.\\n\\t\\t\\t\\tself doubleClickTimeout; click \\\"***\\\"].\\n\\t\\t\\t^true].\\n\\t\\tlocalEvt isMouseUp ifTrue:[\\n\\n\\t\\t\\t(timedOut or:[dblClickSelector isNil]) ifTrue:[\\n\\t\\t\\t\\tself click.\\n\\t\\t\\t\\taHand resetClickState.\\n\\t\\t\\t\\t^true].\\n\\t\\t\\t\\\"Otherwise transfer to #firstClickUp\\\"\\n\\t\\t\\tfirstClickUp _ evt copy.\\n\\t\\t\\tclickState _ #firstClickUp.\\n\\t\\t\\t\\\"If timedOut or the client's not interested in dbl clicks get outta here\\\"\\n\\t\\t\\tself click.\\n\\t\\t\\taHand handleEvent: firstClickUp.\\n\\t\\t\\t^false].\\n\\t\\tisDrag ifTrue:[\\\"drag start\\\"\\n\\t\\t\\tself doubleClickTimeout. \\\"***\\\"\\n\\t\\t\\taHand resetClickState.\\n\\t\\t\\tdragSelector \\\"If no drag selector send #click instead\\\"\\n\\t\\t\\t\\tifNil: [self click]\\n\\t\\t\\t\\tifNotNil: [self drag: firstClickDown].\\n\\t\\t\\t^true].\\n\\t\\t^false].\\n\\n\\tclickState == #firstClickTimedOut ifTrue:[\\n\\t\\tlocalEvt isMouseUp ifTrue:[\\\"neither drag nor double click\\\"\\n\\t\\t\\taHand resetClickState.\\n\\t\\t\\tself doubleClickTimeout; click. \\\"***\\\"\\n\\t\\t\\t^true].\\n\\t\\tisDrag ifTrue:[\\\"drag start\\\"\\n\\t\\t\\taHand resetClickState.\\n\\t\\t\\tself doubleClickTimeout; drag: firstClickDown. \\\"***\\\"\\n\\t\\t\\t^true].\\n\\t\\t^false].\\n\\n\\tclickState = #firstClickUp ifTrue:[\\n\\t\\t(timedOut) ifTrue:[\\n\\t\\t\\t\\\"timed out after mouseUp - signal timeout and pass the event\\\"\\n\\t\\t\\taHand resetClickState.\\n\\t\\t\\tself doubleClickTimeout. \\\"***\\\"\\n\\t\\t\\t^true].\\n\\t\\tlocalEvt isMouseDown ifTrue:[\\\"double click\\\"\\n\\t\\t\\tclickState _ #secondClickDown.\\n\\t\\t\\t^false]].\\n\\n\\tclickState == #secondClickDown ifTrue: [\\n\\t\\ttimedOut ifTrue:[\\n\\t\\t\\t\\\"timed out after second mouseDown - pass event after signaling timeout\\\"\\n\\t\\t\\taHand resetClickState.\\n\\t\\t\\tself doubleClickTimeout. \\\"***\\\"\\n\\t\\t\\t^true].\\n\\t\\tisDrag ifTrue: [\\\"drag start\\\"\\n\\t\\t\\tself doubleClickTimeout. \\\"***\\\"\\n\\t\\t\\taHand resetClickState.\\n\\t\\t\\tdragSelector \\\"If no drag selector send #click instead\\\"\\n\\t\\t\\t\\tifNil: [self click]\\n\\t\\t\\t\\tifNotNil: [self drag: firstClickDown].\\n\\t\\t\\t^true].\\n\\t\\tlocalEvt isMouseUp ifTrue: [\\\"double click\\\"\\n\\t\\t\\taHand resetClickState.\\n\\t\\t\\tself doubleClick.\\n\\t\\t\\t^false]\\n\\t].\\n\\n\\t^true\\n! !\\n\\n\\n!MouseClickState methodsFor: 'initialize' stamp: 'jcg 9/21/2001 13:08'!\\nclient: aMorph click: aClickSelector dblClick: aDblClickSelector dblClickTime: timeOut dblClickTimeout: aDblClickTimeoutSelector drag: aDragSelector threshold: aNumber event: firstClickEvent\\n\\tclickClient _ aMorph.\\n\\tclickSelector _ aClickSelector.\\n\\tdblClickSelector _ aDblClickSelector.\\n\\tdblClickTime _ timeOut.\\n\\tdblClickTimeoutSelector _ aDblClickTimeoutSelector.\\n\\tdragSelector _ aDragSelector.\\n\\tdragThreshold _ aNumber.\\n\\tfirstClickDown _ firstClickEvent.\\n\\tfirstClickTime _ firstClickEvent timeStamp.\\n\\tclickState _ #firstClickDown.! !\\nUserInputEvent subclass: #MouseEvent\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Events'!\\n\\n!MouseEvent methodsFor: 'accessing' stamp: 'ar 9/15/2000 22:51'!\\ncursorPoint\\n\\t\\\"Answer the location of the cursor's hotspot when this event occured.\\\"\\n\\n\\t^ position! !\\n\\n\\n!MouseEvent methodsFor: 'button state' stamp: 'NS 5/19/2003 15:17'!\\nanyButtonPressed\\n\\t\\\"Answer true if any mouse button is being pressed.\\\"\\n\\n\\t^ buttons anyMask: self class anyButton! !\\n\\n!MouseEvent methodsFor: 'button state' stamp: 'NS 5/19/2003 15:17'!\\nblueButtonPressed\\n\\t\\\"Answer true if the blue mouse button is being pressed. This is the third mouse button or cmd+click on the Mac.\\\"\\n\\n\\t^ buttons anyMask: self class blueButton! !\\n\\n!MouseEvent methodsFor: 'button state' stamp: 'NS 5/19/2003 15:17'!\\nredButtonPressed\\n\\t\\\"Answer true if the red mouse button is being pressed. This is the first mouse button.\\\"\\n\\n\\t^ buttons anyMask: self class redButton! !\\n\\n!MouseEvent methodsFor: 'button state' stamp: 'ar 9/15/2000 22:51'!\\ntargetPoint\\n\\t\\\"Answer the location of the cursor's hotspot, adjusted by the offset\\n\\tof the last mouseDown relative to the recipient morph.\\\"\\n\\n\\t^ position - source targetOffset! !\\n\\n!MouseEvent methodsFor: 'button state' stamp: 'NS 5/19/2003 15:17'!\\nyellowButtonPressed\\n\\t\\\"Answer true if the yellow mouse button is being pressed. This is the second mouse button or option+click on the Mac.\\\"\\n\\n\\t^ buttons anyMask: self class yellowButton! !\\n\\n\\n!MouseEvent methodsFor: 'comparing' stamp: 'ar 9/15/2000 22:50'!\\n= aMorphicEvent\\n\\tsuper = aMorphicEvent ifFalse:[^false].\\n\\tposition = aMorphicEvent position ifFalse: [^ false].\\n\\tbuttons = aMorphicEvent buttons ifFalse: [^ false].\\n\\t^ true\\n! !\\n\\n!MouseEvent methodsFor: 'comparing' stamp: 'ar 9/15/2000 22:47'!\\nhash\\n\\t^ position hash + buttons hash! !\\n\\n\\n!MouseEvent methodsFor: 'converting' stamp: 'ar 10/10/2000 21:17'!\\nasMouseEnter\\n\\t^self clone setType: #mouseEnter! !\\n\\n!MouseEvent methodsFor: 'converting' stamp: 'ar 10/10/2000 21:17'!\\nasMouseLeave\\n\\t^self clone setType: #mouseLeave! !\\n\\n!MouseEvent methodsFor: 'converting' stamp: 'ar 10/6/2000 18:59'!\\nasMouseMove\\n\\t\\\"Convert the receiver into a mouse move\\\"\\n\\t^MouseMoveEvent new setType: #mouseMove startPoint: position endPoint: position trail: {position. position} buttons: buttons hand: source stamp: Time millisecondClockValue.! !\\n\\n!MouseEvent methodsFor: 'converting' stamp: 'ar 9/25/2000 14:29'!\\nasMouseOver\\n\\t\\\"Convert the receiver into a mouse over event\\\"\\n\\t^MouseEvent new setType: #mouseOver position: position buttons: buttons hand: source! !\\n\\n\\n!MouseEvent methodsFor: 'dispatching' stamp: 'ar 10/10/2000 21:15'!\\nsentTo: anObject\\n\\t\\\"Dispatch the receiver into anObject\\\"\\n\\ttype == #mouseOver ifTrue:[^anObject handleMouseOver: self].\\n\\ttype == #mouseEnter ifTrue:[^anObject handleMouseEnter: self].\\n\\ttype == #mouseLeave ifTrue:[^anObject handleMouseLeave: self].\\n\\t^super sentTo: anObject.! !\\n\\n\\n!MouseEvent methodsFor: 'initialize' stamp: 'ar 10/25/2000 22:08'!\\ntype: eventType readFrom: aStream\\n\\t| x y |\\n\\ttype _ eventType.\\n\\ttimeStamp _ Integer readFrom: aStream.\\n\\taStream skip: 1.\\n\\tx _ Integer readFrom: aStream.\\n\\taStream skip: 1.\\n\\ty _ Integer readFrom: aStream.\\n\\taStream skip: 1.\\n\\tbuttons _ Integer readFrom: aStream.\\n\\tposition _ x@y.\\n! !\\n\\n\\n!MouseEvent methodsFor: 'printing' stamp: 'ar 10/7/2000 22:01'!\\nprintOn: aStream\\n\\n\\taStream nextPut: $[.\\n\\taStream nextPutAll: self cursorPoint printString; space.\\n\\taStream nextPutAll: type; space.\\n\\taStream nextPutAll: self modifierString.\\n\\taStream nextPutAll: self buttonString.\\n\\taStream nextPutAll: timeStamp printString.\\n\\taStream nextPut: $].! !\\n\\n!MouseEvent methodsFor: 'printing' stamp: 'ar 10/25/2000 22:09'!\\nstoreOn: aStream\\n\\n\\taStream nextPutAll: type.\\n\\taStream space.\\n\\tself timeStamp storeOn: aStream.\\n\\taStream space.\\n\\tposition x storeOn: aStream.\\n\\taStream space.\\n\\tposition y storeOn: aStream.\\n\\taStream space.\\n\\tbuttons storeOn: aStream.! !\\n\\n\\n!MouseEvent methodsFor: 'testing' stamp: 'ar 10/5/2000 19:43'!\\nisDraggingEvent\\n\\tsource ifNil:[^false].\\n\\tsource hasSubmorphs ifTrue:[^true].\\n\\tself anyButtonPressed ifTrue:[^true].\\n\\t^false! !\\n\\n!MouseEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 15:30'!\\nisMouse\\n\\t^true! !\\n\\n!MouseEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 15:32'!\\nisMouseDown\\n\\t^self type == #mouseDown! !\\n\\n!MouseEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 15:32'!\\nisMouseEnter\\n\\t^self type == #mouseEnter! !\\n\\n!MouseEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 15:32'!\\nisMouseLeave\\n\\t^self type == #mouseLeave! !\\n\\n!MouseEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 15:32'!\\nisMouseMove\\n\\t^self type == #mouseMove! !\\n\\n!MouseEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 15:32'!\\nisMouseUp\\n\\t^self type == #mouseUp! !\\n\\n!MouseEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 19:29'!\\nisMove\\n\\t^false! !\\n\\n\\n!MouseEvent methodsFor: 'private' stamp: 'ar 10/10/2000 21:15'!\\nsetType: aSymbol\\n\\t\\\"For quick conversion between event types\\\"\\n\\ttype _ aSymbol.! !\\n\\n!MouseEvent methodsFor: 'private' stamp: 'ar 9/15/2000 22:53'!\\nsetType: evtType position: evtPos buttons: evtButtons hand: evtHand\\n\\ttype _ evtType.\\n\\tposition _ evtPos.\\n\\tbuttons _ evtButtons.\\n\\tsource _ evtHand.\\n\\twasHandled _ false.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMouseEvent class\\n\\tinstanceVariableNames: ''!\\n\\n!MouseEvent class methodsFor: 'constants' stamp: 'NS 5/19/2003 15:16'!\\nanyButton\\n\\t^ 7! !\\n\\n!MouseEvent class methodsFor: 'constants' stamp: 'NS 5/19/2003 15:16'!\\nblueButton\\n\\t^ 1! !\\n\\n!MouseEvent class methodsFor: 'constants' stamp: 'NS 5/19/2003 15:16'!\\nredButton\\n\\t^ 4! !\\n\\n!MouseEvent class methodsFor: 'constants' stamp: 'NS 5/19/2003 15:16'!\\nyellowButton\\n\\t^ 2! !\\nController subclass: #MouseMenuController\\n\\tinstanceVariableNames: 'redButtonMenu redButtonMessages'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Kernel-Remnants'!\\n!MouseMenuController commentStamp: '<historical>' prior: 0!\\nI am a Controller that modifies the scheduling of user activities so that the three mouse buttons can be used to make selections or display menus. The menu items are unary messages to the value of sending my instance the message menuMessageReceiver.!\\n\\n\\n!MouseMenuController methodsFor: 'control defaults' stamp: 'sma 3/11/2000 15:28'!\\ncontrolActivity\\n\\t\\\"Refer to the comment in Controller|controlActivity.\\\"\\n\\t| cursorPoint |\\n\\tcursorPoint _ sensor cursorPoint.\\n\\tsuper controlActivity.\\n\\t(cursorPoint = sensor cursorPoint and: [self viewHasCursor])\\n\\t\\tifTrue: \\n\\t\\t\\t[sensor redButtonPressed ifTrue: [^ self redButtonActivity].\\n\\t\\t\\tsensor yellowButtonPressed ifTrue: [^ self yellowButtonActivity].\\n\\t\\t\\tsensor blueButtonPressed ifTrue: [^ self blueButtonActivity]]! !\\n\\n!MouseMenuController methodsFor: 'control defaults' stamp: 'sma 3/11/2000 11:24'!\\nisControlActive \\n\\t\\\"In contrast to class Controller, only blue button but not yellow button\\n\\tevents will end the receiver's control loop.\\\"\\n\\n\\t^ self viewHasCursor and: [sensor blueButtonPressed not]! !\\n\\n\\n!MouseMenuController methodsFor: 'initialize-release' stamp: 'sma 3/11/2000 15:54'!\\nrelease\\n\\tsuper release.\\n\\tredButtonMenu release! !\\n\\n!MouseMenuController methodsFor: 'initialize-release' stamp: 'sma 3/11/2000 15:54'!\\nreset\\n\\t\\\"Eliminate references to all mouse button menus.\\\"\\n\\n\\tredButtonMenu _ nil.\\n\\tredButtonMessages _ nil! !\\n\\n\\n!MouseMenuController methodsFor: 'menu messages' stamp: 'sma 3/11/2000 15:01'!\\nblueButtonActivity\\n\\t\\\"This normally opens the window menu. It is a no-op here\\n\\tas only the StandardSystemController deals with that kind\\n\\tof menus.\\\"! !\\n\\n!MouseMenuController methodsFor: 'menu messages'!\\nperformMenuMessage: aSelector\\n\\t\\\"Perform a menu command by sending self the message aSelector.\\n\\t Default does nothing special.\\\"\\n\\n\\t^self perform: aSelector! !\\n\\n!MouseMenuController methodsFor: 'menu messages' stamp: 'sma 3/11/2000 14:56'!\\nredButtonActivity\\n\\t\\\"Determine which item in the red button pop-up menu is selected. If one \\n\\tis selected, then send the corresponding message to the object designated \\n\\tas the menu message receiver.\\\"\\n\\n\\t| index |\\n\\tredButtonMenu ~~ nil\\n\\t\\tifTrue: \\n\\t\\t\\t[index _ redButtonMenu startUp.\\n\\t\\t\\tindex ~= 0 \\n\\t\\t\\t\\tifTrue: [self perform: (redButtonMessages at: index)]]\\n\\t\\tifFalse: [super controlActivity]! !\\n\\n!MouseMenuController methodsFor: 'menu messages' stamp: 'sma 3/11/2000 14:59'!\\nyellowButtonActivity\\n\\t\\\"This normally opens a popup menu. Determine the selected\\n\\titem and, if one is selected, then send the corresponding message\\n\\tto either the model or the receiver.\\\"\\n\\n\\t^ self pluggableYellowButtonActivity: sensor leftShiftDown! !\\n\\n\\n!MouseMenuController methodsFor: 'menu setup'!\\nredButtonMenu: aSystemMenu redButtonMessages: anArray \\n\\t\\\"Initialize the pop-up menu that should appear when the user presses the \\n\\tred mouse button to be aSystemMenu. The corresponding messages that \\n\\tshould be sent are listed in the array, anArray.\\\"\\n\\n\\tredButtonMenu release.\\n\\tredButtonMenu _ aSystemMenu.\\n\\tredButtonMessages _ anArray! !\\n\\n\\n!MouseMenuController methodsFor: 'pluggable menus' stamp: 'sma 3/11/2000 12:36'!\\ngetPluggableYellowButtonMenu: shiftKeyState\\n\\t^ view getMenu: shiftKeyState! !\\n\\n!MouseMenuController methodsFor: 'pluggable menus' stamp: 'sw 2/17/2002 04:35'!\\npluggableYellowButtonActivity: shiftKeyState\\n\\t\\\"Invoke the model's popup menu.\\\"\\n\\n\\t| menu |\\n\\t(menu _ self getPluggableYellowButtonMenu: shiftKeyState)\\n\\t\\tifNil:\\n\\t\\t\\t[sensor waitNoButton]\\n\\t\\tifNotNil:\\n\\t\\t\\t[self terminateAndInitializeAround:\\n\\t\\t\\t\\t[menu invokeOn: model orSendTo: self]]! !\\n\\n!MouseMenuController methodsFor: 'pluggable menus' stamp: 'sw 3/22/2001 12:03'!\\nshiftedTextPaneMenuRequest\\n\\t\\\"The user chose the more... branch from the text-pane menu.\\\"\\n\\n\\t^ self pluggableYellowButtonActivity: true! !\\n\\n!MouseMenuController methodsFor: 'pluggable menus' stamp: 'sma 3/11/2000 12:37'!\\nshiftedYellowButtonActivity\\n\\t\\\"Invoke the model's special popup menu.\\\"\\n\\n\\t^ self pluggableYellowButtonActivity: true! !\\n\\n!MouseMenuController methodsFor: 'pluggable menus' stamp: 'sma 3/11/2000 12:37'!\\nunshiftedYellowButtonActivity\\n\\t\\\"Invoke the model's normal popup menu.\\\"\\n\\n\\t^ self pluggableYellowButtonActivity: false! !\\nMouseEvent subclass: #MouseMoveEvent\\n\\tinstanceVariableNames: 'startPoint trail'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Events'!\\n\\n!MouseMoveEvent methodsFor: 'accessing' stamp: 'ar 9/15/2000 22:51'!\\nendPoint\\n\\t\\\"Return the point where the movement ended.\\\"\\n\\t^position! !\\n\\n!MouseMoveEvent methodsFor: 'accessing' stamp: 'ar 9/13/2000 16:25'!\\nstartPoint\\n\\t\\\"Return the point where the movement started.\\\"\\n\\t^startPoint! !\\n\\n!MouseMoveEvent methodsFor: 'accessing' stamp: 'ar 10/24/2000 16:33'!\\ntrail\\n\\t\\\"Return any immediate points that have been assembled along the move\\\"\\n\\t^trail ifNil:[#()]! !\\n\\n\\n!MouseMoveEvent methodsFor: 'comparing' stamp: 'ar 9/15/2000 22:49'!\\n= aMorphicEvent\\n\\tsuper = aMorphicEvent ifFalse:[^false].\\n\\tposition = aMorphicEvent position ifFalse: [^ false].\\n\\tstartPoint = aMorphicEvent startPoint ifFalse: [^ false].\\n\\tbuttons = aMorphicEvent buttons ifFalse: [^ false].\\n\\t^ true\\n! !\\n\\n!MouseMoveEvent methodsFor: 'comparing' stamp: 'ar 9/15/2000 22:49'!\\nhash\\n\\t^ position hash + startPoint hash + buttons hash! !\\n\\n\\n!MouseMoveEvent methodsFor: 'dispatching' stamp: 'ar 10/10/2000 21:15'!\\nsentTo: anObject\\n\\t\\\"Dispatch the receiver into anObject\\\"\\n\\ttype == #mouseMove ifTrue:[^anObject handleMouseMove: self].\\n\\t^super sentTo: anObject.\\n! !\\n\\n\\n!MouseMoveEvent methodsFor: 'initialize' stamp: 'ar 10/24/2000 16:31'!\\ntype: eventType readFrom: aStream\\n\\t| x y |\\n\\tsuper type: eventType readFrom: aStream.\\n\\taStream skip: 1.\\n\\tx _ Integer readFrom: aStream.\\n\\taStream skip: 1.\\n\\ty _ Integer readFrom: aStream.\\n\\tstartPoint _ x@y.! !\\n\\n\\n!MouseMoveEvent methodsFor: 'printing' stamp: 'ar 10/7/2000 22:00'!\\nprintOn: aStream\\n\\n\\taStream nextPut: $[.\\n\\taStream nextPutAll: self startPoint printString; space.\\n\\taStream nextPutAll: self endPoint printString; space.\\n\\taStream nextPutAll: self type; space.\\n\\taStream nextPutAll: self modifierString.\\n\\taStream nextPutAll: self buttonString.\\n\\taStream nextPutAll: timeStamp printString.\\n\\taStream nextPut: $].! !\\n\\n!MouseMoveEvent methodsFor: 'printing' stamp: 'ar 10/24/2000 16:30'!\\nstoreOn: aStream\\n\\tsuper storeOn: aStream.\\n\\taStream space.\\n\\tself startPoint x storeOn: aStream.\\n\\taStream space.\\n\\tself startPoint y storeOn: aStream.\\n\\taStream space.\\n\\t\\\"trail storeOn: aStream.\\\"! !\\n\\n\\n!MouseMoveEvent methodsFor: 'testing' stamp: 'ar 9/13/2000 19:29'!\\nisMove\\n\\t^true! !\\n\\n\\n!MouseMoveEvent methodsFor: 'transforming' stamp: 'ar 9/15/2000 22:52'!\\ntransformBy: aMorphicTransform\\n\\t\\\"Transform the receiver into a local coordinate system.\\\"\\n\\tposition _ aMorphicTransform globalPointToLocal: position.\\n\\tstartPoint _ aMorphicTransform globalPointToLocal: startPoint.! !\\n\\n!MouseMoveEvent methodsFor: 'transforming' stamp: 'ar 9/15/2000 22:52'!\\ntranslateBy: delta\\n\\t\\\"add delta to cursorPoint, and return the new event\\\"\\n\\tposition _ position + delta.\\n\\tstartPoint _ startPoint + delta.! !\\n\\n\\n!MouseMoveEvent methodsFor: '*nebraska-*nebraska-Morphic-Remote' stamp: 'dgd 2/22/2003 19:01'!\\ndecodeFromStringArray: array \\n\\t\\\"decode the receiver from an array of strings\\\"\\n\\n\\ttype := array first asSymbol.\\n\\tposition := CanvasDecoder decodePoint: (array second).\\n\\tbuttons := CanvasDecoder decodeInteger: (array third).\\n\\tstartPoint := CanvasDecoder decodePoint: (array fourth)! !\\n\\n!MouseMoveEvent methodsFor: '*nebraska-*nebraska-Morphic-Remote' stamp: 'ar 10/25/2000 23:25'!\\nencodedAsStringArray\\n\\t\\\"encode the receiver into an array of strings, such that it can be retrieved via the fromStringArray: class method\\\"\\n\\t^{\\n\\t\\ttype.\\n\\t\\tCanvasEncoder encodePoint: position.\\n\\t\\tCanvasEncoder encodeInteger: buttons.\\n\\t\\tCanvasEncoder encodePoint: startPoint.\\n\\t}! !\\n\\n\\n!MouseMoveEvent methodsFor: 'private' stamp: 'ar 10/5/2000 23:55'!\\nsetType: evtType startPoint: evtStart endPoint: evtEnd trail: evtTrail buttons: evtButtons hand: evtHand stamp: stamp\\n\\ttype _ evtType.\\n\\tstartPoint _ evtStart.\\n\\tposition _ evtEnd.\\n\\ttrail _ evtTrail.\\n\\tbuttons _ evtButtons.\\n\\tsource _ evtHand.\\n\\twasHandled _ false.\\n\\ttimeStamp _ stamp.! !\\nObject subclass: #MouseOverHandler\\n\\tinstanceVariableNames: 'mouseOverMorphs enteredMorphs overMorphs leftMorphs'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Events'!\\n\\n!MouseOverHandler methodsFor: 'event handling' stamp: 'ar 9/28/2000 18:52'!\\nnoticeMouseOver: aMorph event: anEvent\\n\\t\\\"Remember that the mouse is currently over some morph\\\"\\n\\t(leftMorphs includes: aMorph) \\n\\t\\tifTrue:[leftMorphs remove: aMorph]\\n\\t\\tifFalse:[enteredMorphs nextPut: aMorph].\\n\\toverMorphs nextPut: aMorph.\\n! !\\n\\n!MouseOverHandler methodsFor: 'event handling' stamp: 'dgd 2/21/2003 23:00'!\\nprocessMouseOver: anEvent \\n\\t\\\"Re-establish the z-order for all morphs wrt the given event\\\"\\n\\n\\t| hand localEvt focus evt |\\n\\thand := anEvent hand.\\n\\tleftMorphs := mouseOverMorphs asIdentitySet.\\n\\t\\\"Assume some coherence for the number of objects in over list\\\"\\n\\toverMorphs := WriteStream on: (Array new: leftMorphs size).\\n\\tenteredMorphs := WriteStream on: #().\\n\\t\\\"Now go looking for eventual mouse overs\\\"\\n\\thand handleEvent: anEvent asMouseOver.\\n\\t\\\"Get out early if there's no change\\\"\\n\\t(leftMorphs isEmpty and: [enteredMorphs position = 0]) \\n\\t\\tifTrue: [^leftMorphs := enteredMorphs := overMorphs := nil].\\n\\tfocus := hand mouseFocus.\\n\\t\\\"Send #mouseLeave as appropriate\\\"\\n\\tevt := anEvent asMouseLeave.\\n\\t\\\"Keep the order of the left morphs by recreating it from the mouseOverMorphs\\\"\\n\\tleftMorphs size > 1 \\n\\t\\tifTrue: [leftMorphs := mouseOverMorphs select: [:m | leftMorphs includes: m]].\\n\\tleftMorphs do: \\n\\t\\t\\t[:m | \\n\\t\\t\\t(m == focus or: [m hasOwner: focus]) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[localEvt := evt transformedBy: (m transformedFrom: hand).\\n\\t\\t\\t\\t\\tm handleEvent: localEvt]\\n\\t\\t\\t\\tifFalse: [overMorphs nextPut: m]].\\n\\t\\\"Send #mouseEnter as appropriate\\\"\\n\\tevt := anEvent asMouseEnter.\\n\\tenteredMorphs ifNil: \\n\\t\\t\\t[\\\"inform: was called in handleEvent:\\\"\\n\\n\\t\\t\\t^leftMorphs := enteredMorphs := overMorphs := nil].\\n\\tenteredMorphs := enteredMorphs contents.\\n\\tenteredMorphs reverseDo: \\n\\t\\t\\t[:m | \\n\\t\\t\\t(m == focus or: [m hasOwner: focus]) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[localEvt := evt transformedBy: (m transformedFrom: hand).\\n\\t\\t\\t\\t\\tm handleEvent: localEvt]].\\n\\t\\\"And remember the over list\\\"\\n\\toverMorphs ifNil: \\n\\t\\t\\t[\\\"inform: was called in handleEvent:\\\"\\n\\n\\t\\t\\t^leftMorphs := enteredMorphs := overMorphs := nil].\\n\\tmouseOverMorphs := overMorphs contents.\\n\\tleftMorphs := enteredMorphs := overMorphs := nil! !\\n\\n\\n!MouseOverHandler methodsFor: 'initialize-release' stamp: 'ar 9/28/2000 17:08'!\\ninitialize\\n\\tmouseOverMorphs _ #().! !\\nMovieClipStartMorph subclass: #MovieClipEndMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Movies-Player'!\\n!MovieClipEndMorph commentStamp: '<historical>' prior: 0!\\nThe idea is that soon we will show the soundtrack extending between the start cue and the end morph.!\\n\\n\\n!MovieClipEndMorph methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nmovieFileName: movieFileName image: aForm player: aMoviePlayer frameNumber: n\\n\\n\\tmovieClipFileName := movieFileName.\\n\\tself image: aForm frameNumber: n.\\n\\tmoviePlayerMorph := movieClipPlayer := aMoviePlayer.\\n\\tscoreEvent := AmbientEvent new morph: self.\\n! !\\n\\n\\n!MovieClipEndMorph methodsFor: 'drawing' stamp: 'di 10/23/2000 10:42'!\\nthumbnailHeight\\n\\n\\t^ 30! !\\n\\n\\n!MovieClipEndMorph methodsFor: 'piano rolls' stamp: 'di 10/26/2000 00:25'!\\naddMorphsTo: morphList pianoRoll: pianoRoll eventTime: t betweenTime: leftTime and: rightTime\\n\\n\\t\\\"Ignored -- all display is done by the starting morph -- see superclass\\\"! !\\n\\n!MovieClipEndMorph methodsFor: 'piano rolls' stamp: 'di 10/11/2000 23:06'!\\nencounteredAtTime: ticks inScorePlayer: scorePlayer atIndex: index inEventTrack: track secsPerTick: secsPerTick\\n\\n\\tmovieClipPlayer ifNotNil:\\n\\t\\t[\\\"If being shown as a clip, then tell the clipPlayer to stop showing this clip\\\"\\n\\t\\tmovieClipPlayer stopRunning]! !\\n\\n!MovieClipEndMorph methodsFor: 'piano rolls' stamp: 'di 10/22/2000 12:43'!\\npauseFrom: scorePlayer\\n\\n\\t\\\"Ignored\\\"! !\\n\\n!MovieClipEndMorph methodsFor: 'piano rolls' stamp: 'di 10/22/2000 12:43'!\\nresetFrom: scorePlayer\\n\\n\\t\\\"Ignored\\\"! !\\n\\n!MovieClipEndMorph methodsFor: 'piano rolls' stamp: 'di 10/22/2000 12:43'!\\nresumeFrom: scorePlayer\\n\\n\\t\\\"Ignored\\\"! !\\nMovieFrameSyncMorph subclass: #MovieClipStartMorph\\n\\tinstanceVariableNames: 'movieClipPlayer movieClipFileName soundTrackFileName soundTrackPlayerReady soundTrackMorph soundTrackTimeScale scoreEvent endMorph clipColor colorMorph'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Movies-Player'!\\n!MovieClipStartMorph commentStamp: '<historical>' prior: 0!\\nThis class and its subclasses act to syncronize movie players with the progress of a MIDI score and further background can be found in the comment for MoviePlayerMorph.\\n\\nMovieClipStartMorphs are used where you have a movie clip player plex. You can create such a plex by opening a midi score, spawning a piano roll (by the button of that name), and then choosing 'add movie clip player' from the piano roll menu. Much simpler, you can open a MoviePlayerMorph as a new morph, and then choose 'make a new movie' from its menu. This plex then serves as a central editable score for composing movie clips.\\n\\nTo add a new movie clip to the score, open a movie from the fileList (or as a new morph followed by 'open a movie'). Play or otherwise position the clip to the desired starting position, and then tear off a thumbnail and drop it into the score at the desired time. The starting thumbnail (MovieClipStartMorph) will appear in the score, tied to an endMorph by a colored stripe. The ending time will be chosen based on the total length of the clip, a default starting clip length (200 frames), and possible interference with other clips that follow it.\\n\\nTo reposition a clip, you can pick up its clipStart with halo black handle, and drop it elsewhere. The rest of the clip will follow as best it can. To delete a clip, delete its clipStart. To change the duration of a clip, play the composition up to some point in that clip, and pause it. Then use the controls on the central movie player to move forward or backward to the desired ending frame, and choose 'end clip here' from the player menu.!\\n\\n\\n!MovieClipStartMorph methodsFor: 'access' stamp: 'di 10/19/2000 14:27'!\\nendMorph\\n\\n\\t^ endMorph! !\\n\\n!MovieClipStartMorph methodsFor: 'access' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nframeNumber: newFrame\\n\\n\\tframeNumber := newFrame! !\\n\\n!MovieClipStartMorph methodsFor: 'access' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nmovieClipPlayer: aMoviePlayerMorph\\n\\t\\\"For now, these morphs work both as a sync point in a long movie, and\\n\\tas a cue point for a short clip in a longer score.\\n\\tTo a cue point, this method provides a reference to the clip player.\\\"\\n\\n\\tmovieClipPlayer := aMoviePlayerMorph! !\\n\\n!MovieClipStartMorph methodsFor: 'access' stamp: 'di 10/25/2000 22:02'!\\nrelatedPlayer\\n \\n\\t^ movieClipPlayer! !\\n\\n!MovieClipStartMorph methodsFor: 'access' stamp: 'di 10/19/2000 12:24'!\\nscoreEvent\\n\\t^ scoreEvent! !\\n\\n\\n!MovieClipStartMorph methodsFor: 'drawing' stamp: 'di 10/23/2000 10:46'!\\ncolorMargin\\n\\t\\\"How far the clip span color highlight extends outside the starting clip\\\"\\n\\n\\t^ 5! !\\n\\n!MovieClipStartMorph methodsFor: 'drawing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\ncolorMorph\\n\\tcolorMorph ifNotNil: [^ colorMorph].\\n\\n\\t\\\"Make up a morph to highlight the span of this clip.\\\"\\n\\tColorIndex := (ColorIndex ifNil: [0]) + 2 \\\\\\\\ 8 + 1.\\n\\t^ colorMorph := Morph newBounds: (0@0 extent: 9@9) color: ((Color wheel: 8) at: ColorIndex)\\n! !\\n\\n!MovieClipStartMorph methodsFor: 'drawing' stamp: 'di 10/23/2000 10:23'!\\nsoundTrackHeight\\n\\n\\t^ 40! !\\n\\n!MovieClipStartMorph methodsFor: 'drawing' stamp: 'di 10/23/2000 10:58'!\\nsoundTrackOnBottom \\\"a local preference during test\\\"\\n\\n\\t^ false! !\\n\\n!MovieClipStartMorph methodsFor: 'drawing' stamp: 'di 10/23/2000 12:32'!\\nthumbnailHeight\\n\\n\\t^ 60! !\\n\\n\\n!MovieClipStartMorph methodsFor: 'dropping/grabbing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\njustDroppedInto: newOwner event: evt\\n\\t| pianoRoll syncMorph |\\n\\t\\\"When dropping this morph into a pianoRoll, add a corresponding\\n\\tevent to the score so that it will always appear when played,\\n\\tin addition to possibly triggering other actions\\\"\\n\\n\\t(newOwner isKindOf: PianoRollScoreMorph)\\n\\tifTrue:\\n\\t\\t[pianoRoll := newOwner.\\n\\t\\tpianoRoll movieClipPlayer ifNil:\\n\\t\\t\\t[\\\"This PianoRoll is not a clip player -- replace me by a SyncMorph\\\"\\n\\t\\t\\tsyncMorph := MovieFrameSyncMorph new\\n\\t\\t\\t\\t\\t\\timage: image\\n\\t\\t\\t\\t\\t\\tplayer: moviePlayerMorph\\n\\t\\t\\t\\t\\t\\tframeNumber: frameNumber.\\n\\t\\t\\tpianoRoll replaceSubmorph: self by: syncMorph.\\n\\t\\t\\t\\\"rewrite to use justDroppedInto:...\\\"\\n\\t\\t\\tpianoRoll score removeAmbientEventWithMorph: self;\\n\\t\\t\\t\\t\\taddAmbientEvent: (scoreEvent\\n\\t\\t\\t\\t\\t\\tmorph: syncMorph;\\n\\t\\t\\t\\t\\t\\ttime: (pianoRoll timeForX: self left)).\\n\\t\\t\\t^ self].\\n\\n\\t\\tself movieClipPlayer: pianoRoll movieClipPlayer.\\n\\t\\tself setTimeInScore: pianoRoll score\\n\\t\\t\\t\\t\\tnear: (pianoRoll timeForX: self left).\\n\\t\\tself endTime > newOwner scorePlayer durationInTicks ifTrue:\\n\\t\\t\\t[newOwner scorePlayer updateDuration]]\\n\\tifFalse:\\n\\t\\t[\\\"Dropped it somewhere else -- delete related morphs\\\"\\n\\t\\tendMorph ifNotNil: [endMorph delete].\\n\\t\\tsoundTrackMorph ifNotNil: [soundTrackMorph delete]].\\n\\n\\tsuper justDroppedInto: newOwner event: evt\\n! !\\n\\n\\n!MovieClipStartMorph methodsFor: 'events' stamp: 'di 10/22/2000 20:24'!\\nendTime\\n\\n\\t^ endMorph scoreEvent time! !\\n\\n!MovieClipStartMorph methodsFor: 'events' stamp: 'di 10/22/2000 20:27'!\\nframeAtTick: time\\n\\t\\\"Return the frame number corresponding to the given tick time\\\"\\n\\n\\t^ frameNumber +\\n\\t\\t((time - self startTime) asFloat\\n\\t\\t\\t/ (self endTime - self startTime)\\n\\t\\t\\t* (endMorph frameNumber - frameNumber)) asInteger! !\\n\\n!MovieClipStartMorph methodsFor: 'events' stamp: 'di 10/22/2000 20:24'!\\nstartTime\\n\\n\\t^ scoreEvent time! !\\n\\n\\n!MovieClipStartMorph methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nimage: aForm frameNumber: n\\n\\n\\tself image: (aForm magnifyBy: self thumbnailHeight asFloat / aForm height).\\n\\tframeNumber := n.! !\\n\\n!MovieClipStartMorph methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nmovieFileName: movieFileName soundTrackFileName: soundFileName\\n\\t\\t\\timage: aForm player: aMoviePlayer frameNumber: n\\n\\tmovieClipFileName := movieFileName.\\n\\tsoundTrackFileName := soundFileName.\\n\\tself image: aForm frameNumber: n.\\n\\tmoviePlayerMorph := aMoviePlayer.\\n\\tsoundTrackPlayerReady := moviePlayerMorph scorePlayer copy.\\n\\tscoreEvent := AmbientEvent new morph: self.\\n! !\\n\\n\\n!MovieClipStartMorph methodsFor: 'piano rolls' stamp: 'dgd 2/22/2003 14:09'!\\naddMorphsTo: morphList pianoRoll: pianoRoll eventTime: t betweenTime: leftTime and: rightTime \\n\\t\\\"This code handles both the start and end morphs.\\\"\\n\\n\\t| startX endX h delta |\\n\\tself startTime > rightTime \\n\\t\\tifTrue: [^self\\t\\\"Start time has not come into view.\\\"].\\n\\tself endTime < leftTime ifTrue: [^self\\t\\\"End time has passed out of view.\\\"].\\n\\tstartX := pianoRoll xForTime: self startTime.\\n\\tendX := pianoRoll xForTime: self endTime.\\n\\th := self colorMargin.\\t\\\"Height of highlight bar over thumbnails.\\\"\\n\\tmorphList add: (self align: self bottomLeft\\n\\t\\t\\t\\twith: startX @ (pianoRoll bottom - pianoRoll borderWidth - h)).\\n\\tmorphList \\n\\t\\tadd: (endMorph align: endMorph bounds rightCenter with: endX @ self center y).\\n\\tmorphList add: (self colorMorph \\n\\t\\t\\t\\tbounds: (self topLeft - (0 @ h) corner: endMorph right @ (self bottom + h))).\\n\\t(soundTrackMorph isNil and: [moviePlayerMorph scorePlayer isNil]) \\n\\t\\tifFalse: \\n\\t\\t\\t[\\\"Wants a sound track\\\"\\n\\n\\t\\t\\t(soundTrackMorph isNil or: [pianoRoll timeScale ~= soundTrackTimeScale]) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[\\\"Needs a new sound track\\\"\\n\\n\\t\\t\\t\\t\\tself buildSoundTrackMorphFor: pianoRoll].\\n\\t\\t\\tmorphList add: (soundTrackMorph align: soundTrackMorph bottomLeft\\n\\t\\t\\t\\t\\t\\twith: colorMorph topLeft).\\n\\t\\t\\tself soundTrackOnBottom \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[soundTrackMorph align: soundTrackMorph bottomLeft with: self bottomLeft.\\n\\t\\t\\t\\t\\tdelta := 0 @ self soundTrackHeight.\\n\\t\\t\\t\\t\\tself position: self position - delta.\\n\\t\\t\\t\\t\\tendMorph position: endMorph position - delta.\\n\\t\\t\\t\\t\\tcolorMorph position: colorMorph position - delta]]! !\\n\\n!MovieClipStartMorph methodsFor: 'piano rolls' stamp: 'di 10/26/2000 00:09'!\\nencounteredAtTime: ticks inScorePlayer: scorePlayer atIndex: index inEventTrack: track secsPerTick: secsPerTick\\n\\n\\t\\\"If being shown as a clip, then tell the clipPlayer to start showing this clip\\\"\\n\\tmovieClipPlayer setCueMorph: self.\\n\\tmovieClipPlayer openFileNamed: movieClipFileName\\n\\t\\t\\twithScorePlayer: soundTrackPlayerReady copy\\n\\t\\t\\tandPlayFrom: frameNumber.\\n! !\\n\\n!MovieClipStartMorph methodsFor: 'piano rolls' stamp: 'dgd 2/22/2003 14:09'!\\nresetFrom: scorePlayer \\n\\t(movieClipPlayer cueMorph isNil \\n\\t\\tor: [self startTime < movieClipPlayer cueMorph startTime]) \\n\\t\\t\\tifTrue: \\n\\t\\t\\t\\t[movieClipPlayer\\n\\t\\t\\t\\t\\topenFileNamed: movieClipFileName\\n\\t\\t\\t\\t\\t\\twithScorePlayer: soundTrackPlayerReady copy\\n\\t\\t\\t\\t\\t\\tandPlayFrom: frameNumber;\\n\\t\\t\\t\\t\\tsetCueMorph: self;\\n\\t\\t\\t\\t\\tstep;\\n\\t\\t\\t\\t\\tpauseFrom: scorePlayer]! !\\n\\n!MovieClipStartMorph methodsFor: 'piano rolls' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nresumeFrom: scorePlayer\\n\\n\\t| time |\\n\\t\\\"New movie clip style of use.\\\"\\n\\ttime := scorePlayer ticksSinceStart.\\n\\ttime < self startTime ifTrue: [^ self]. \\\"It's not my time yet\\\"\\n\\ttime > self endTime ifTrue: [^ self]. \\\"It's past my time\\\"\\n\\n\\t\\\"The player is starting in the midst of this clip.\\\"\\n\\tmovieClipPlayer openFileNamed: movieClipFileName\\n\\t\\t\\t\\twithScorePlayer: soundTrackPlayerReady copy\\n\\t\\t\\t\\tandPlayFrom: (self frameAtTick: time);\\n\\t\\tsetCueMorph: self.\\n! !\\n\\n\\n!MovieClipStartMorph methodsFor: 'submorphs-add/remove' stamp: 'di 10/23/2000 10:24'!\\ndelete\\n\\t(owner isKindOf: PianoRollScoreMorph) ifTrue:\\n\\t\\t[owner score removeAmbientEventWithMorph: self.\\n\\t\\tendMorph ifNotNil: [owner score removeAmbientEventWithMorph: endMorph]].\\n\\tendMorph ifNotNil: [endMorph delete].\\n\\tsoundTrackMorph ifNotNil: [soundTrackMorph delete].\\n\\tcolorMorph ifNotNil: [colorMorph delete].\\n\\tsuper delete.\\n! !\\n\\n\\n!MovieClipStartMorph methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nbuildSoundTrackMorphFor: pianoRoll\\n\\t| stopTime soundTrackForm startTime samplesPerTick samplesPerMs |\\n\\tsoundTrackTimeScale := pianoRoll timeScale. \\\"pixels per tick\\\"\\n\\tsamplesPerTick := moviePlayerMorph scorePlayer originalSamplingRate \\\"Samples per sec\\\"\\n\\t\\t\\t\\t\\t\\t* pianoRoll scorePlayer secsPerTick. \\\"secs per tick\\\"\\n\\tsamplesPerMs := moviePlayerMorph scorePlayer originalSamplingRate / 1000.0.\\n\\tstartTime := frameNumber * moviePlayerMorph msPerFrame. \\\"ms\\\"\\n\\tstopTime := endMorph frameNumber * moviePlayerMorph msPerFrame.\\n\\tsoundTrackForm := moviePlayerMorph scorePlayer\\n\\t\\tvolumeForm: self soundTrackHeight\\n\\t\\tfrom: (startTime * samplesPerMs) rounded\\n\\t\\tto: (stopTime * samplesPerMs) rounded\\n\\t\\tnSamplesPerPixel: samplesPerTick / soundTrackTimeScale.\\n\\t^ soundTrackMorph := ImageMorph new image: soundTrackForm! !\\n\\n!MovieClipStartMorph methodsFor: 'private' stamp: 'di 10/29/2000 08:02'!\\nsetEndFrameNumber: frame\\n\\n\\tself setEndFrameNumber: frame tickTime: nil! !\\n\\n!MovieClipStartMorph methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nsetEndFrameNumber: frameOrNil tickTime: timeOrNil\\n\\t\\\"May be called with either time or frame being nil,\\n\\tin which case the other will br computed.\\\"\\n\\n\\t| pianoRoll frame time |\\n\\tpianoRoll := movieClipPlayer pianoRoll.\\n\\tframe := frameOrNil ifNil:\\n\\t\\t[frameNumber + \\n\\t\\t\\t((timeOrNil - self startTime)\\n\\t\\t\\t* (pianoRoll scorePlayer secsPerTick*1000.0)\\n\\t\\t\\t/ moviePlayerMorph msPerFrame) asInteger - 1].\\n\\ttime := timeOrNil ifNil:\\n\\t\\t[self startTime + \\\"in ticks\\\"\\n\\t\\t\\t(pianoRoll scorePlayer ticksForMSecs:\\n\\t\\t\\t(frameOrNil - frameNumber) * moviePlayerMorph msPerFrame)].\\n\\tendMorph ifNil:\\n\\t\\t[endMorph := MovieClipEndMorph new\\n\\t\\t\\tmovieFileName: movieClipFileName\\n\\t\\t\\timage: (moviePlayerMorph pageFormForFrame: frame)\\n\\t\\t\\tplayer: movieClipPlayer\\n\\t\\t\\tframeNumber: frame]\\n\\t\\tifNotNil:\\n\\t\\t[endMorph image: (moviePlayerMorph pageFormForFrame: frame)\\n\\t\\t\\tframeNumber: frame].\\n\\n\\tendMorph scoreEvent time: time.\\n\\tpianoRoll score removeAmbientEventWithMorph: endMorph;\\n\\t\\taddAmbientEvent: endMorph scoreEvent.\\n\\tsoundTrackMorph := nil. \\\"Force it to be recomputed.\\\"\\n\\tpianoRoll rebuildFromScore\\n! !\\n\\n!MovieClipStartMorph methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nsetTimeInScore: score near: dropTime\\n\\t\\\"Find a time to place this clip that does not overlap other clips.\\n\\tSo, if I start in the middle of another clip, move me to the end of it,\\n\\tand if I start very soon after another clip, put me right at the end.\\n\\tThen, if my end goes beyond the start of another clip, shorten me\\n\\tso I end right before that clip.\\\"\\n\\n\\t| startTime endTime delta endFrame |\\n\\tstartTime := dropTime.\\n\\tendMorph ifNil: [endFrame := moviePlayerMorph frameCount]\\n\\t\\t\\tifNotNil: [endFrame := endMorph frameNumber].\\n\\tendTime := startTime \\\"in ticks\\\"\\n\\t\\t+ (movieClipPlayer pianoRoll scorePlayer ticksForMSecs:\\n\\t\\t\\t(endFrame - frameNumber)\\n\\t\\t\\t* moviePlayerMorph msPerFrame).\\n\\tscore eventMorphsDo:\\n\\t\\t[:m | (m ~~ self and: [m isMemberOf: self class]) ifTrue:\\n\\t\\t\\t\\t[((startTime between: m startTime and: m endTime)\\n\\t\\t\\t\\t\\tor: [startTime between: m endTime and: m endTime+50])\\n\\t\\t\\t\\t\\tifTrue: [\\\"If I start in the middle of another clip, or a little\\n\\t\\t\\t\\t\\t\\t\\tpast its end, move me exactly to the end of it\\\"\\n\\t\\t\\t\\t\\t\\t\\tdelta := (m endTime + 1) - startTime.\\n\\t\\t\\t\\t\\t\\t\\tstartTime := startTime + delta.\\n\\t\\t\\t\\t\\t\\t\\tendTime := endTime + delta].\\n\\t\\t\\t\\t(endTime between: m startTime and: m endTime)\\n\\t\\t\\t\\t\\tifTrue: [\\\"If my end goes overlaps another clip, shorten me so I fit.\\\"\\n\\t\\t\\t\\t\\t\\t\\tendTime := m startTime - 1].\\n\\t\\t\\t\\t]].\\n\\tscoreEvent time: startTime.\\n\\tscore removeAmbientEventWithMorph: self;\\n\\t\\t\\taddAmbientEvent: scoreEvent.\\n\\tself setEndFrameNumber: endFrame tickTime: endTime.\\n! !\\nImageMorph subclass: #MovieFrameSyncMorph\\n\\tinstanceVariableNames: 'moviePlayerMorph frameNumber'\\n\\tclassVariableNames: 'ColorIndex'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Movies-Player'!\\n!MovieFrameSyncMorph commentStamp: '<historical>' prior: 0!\\nThis class and its subclasses act to syncronize movie players with the progress of a MIDI score and further background can be found in the comment for MoviePlayerMorph.\\n\\nThere are two main forms of synchroniztion.\\n\\nMovieFrameSyncMorphs are used where you have a MIDI score open with a piano roll, and a separate MoviePlayer Morph. A MovieFrameSyncMorph can be torn off from the MoviePlayer with a shift-drag gesture or menu command, and can then be dropped into a MIDI score. They are used to start a movie player at a given place in the score, and then to stretch or compress the movie frame rate so that certain frames are synchronized with the corresponding points in the score.\\n\\nMovieClipStartMorphs (q.v.) and MovieClipEndMorphs are used for the other kind of synchronization, namely where you wish to assemble a number of movie clips in a sequence.!\\n\\n\\n!MovieFrameSyncMorph methodsFor: 'access' stamp: 'di 8/6/1998 14:13'!\\nframeNumber\\n\\t^ frameNumber! !\\n\\n!MovieFrameSyncMorph methodsFor: 'access' stamp: 'di 10/11/2000 21:39'!\\nmoviePlayerMorph\\n \\n\\t^ moviePlayerMorph! !\\n\\n!MovieFrameSyncMorph methodsFor: 'access' stamp: 'di 10/25/2000 22:02'!\\nrelatedPlayer\\n \\n\\t^ moviePlayerMorph! !\\n\\n\\n!MovieFrameSyncMorph methodsFor: 'dropping/grabbing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\njustDroppedInto: newOwner event: evt \\n\\t| pianoRoll |\\n\\t\\\"When dropping this morph into a pianoRoll, add a corresponding\\n\\tevent to the score so that it will always appear when played,\\n\\tin addition to possibly triggering other actions\\\"\\n\\n\\t(self isMemberOf: MovieFrameSyncMorph) ifFalse:\\n\\t\\t[^ super justDroppedInto: newOwner event: evt].\\n\\n\\t(newOwner isKindOf: PianoRollScoreMorph)\\n\\tifTrue:\\n\\t\\t[\\\"Legacy code for existing sync morphs\\\"\\n\\t\\tpianoRoll := newOwner.\\n\\t\\tpianoRoll score\\n\\t\\t\\tremoveAmbientEventWithMorph: self;\\n\\t\\t\\taddAmbientEvent: (AmbientEvent new\\n\\t\\t\\t\\t\\t\\tmorph: self;\\n\\t\\t\\t\\t\\t\\ttime: (pianoRoll timeForX: self left))].\\n\\n\\tsuper justDroppedInto: newOwner event: evt\\n! !\\n\\n\\n!MovieFrameSyncMorph methodsFor: 'events' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nnextSyncEventAfter: index inTrack: track\\n\\t| evt |\\n\\tindex to: track size do:\\n\\t\\t[:i | evt := track at: i.\\n\\t\\t((evt morph isMemberOf: self class)\\n\\t\\t\\tand: [evt morph moviePlayerMorph == moviePlayerMorph])\\n\\t\\t\\tifTrue: [^ evt]].\\n\\t^ nil! !\\n\\n\\n!MovieFrameSyncMorph methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nimage: aForm player: aMoviePlayer frameNumber: n\\n\\tself image: aForm.\\n\\tmoviePlayerMorph := aMoviePlayer.\\n\\tframeNumber := n! !\\n\\n\\n!MovieFrameSyncMorph methodsFor: 'piano rolls' stamp: 'stephaneducasse 2/4/2006 20:48'!\\naddMorphsTo: morphList pianoRoll: pianoRoll eventTime: t betweenTime: leftTime and: rightTime\\n\\n\\t| leftX |\\n\\tt > rightTime ifTrue: [^ self \\\"Start time has not come into view.\\\"]. \\n\\tleftX := pianoRoll xForTime: t.\\n\\t(leftX + self width) < pianoRoll left ifTrue: [^ self \\\"End time has passed out of view.\\\"].\\n\\tmorphList add: \\n\\t\\t(self align: self bottomLeft\\n\\t\\t\\twith: leftX @ (pianoRoll bottom - pianoRoll borderWidth)).\\n! !\\n\\n!MovieFrameSyncMorph methodsFor: 'piano rolls' stamp: 'dgd 2/21/2003 22:58'!\\nencounteredAtTime: ticks inScorePlayer: scorePlayer atIndex: index inEventTrack: track secsPerTick: secsPerTick \\n\\t\\\"Set frame number and milliseconds since start in case of drift\\\"\\n\\n\\t| next |\\n\\tmoviePlayerMorph frameNumber: frameNumber\\n\\t\\tmsSinceStart: scorePlayer millisecondsSinceStart.\\n\\n\\t\\\"If there is a later sync point, set the appropriate frame rate until then.\\\"\\n\\t(next := self nextSyncEventAfter: index inTrack: track) isNil \\n\\t\\tifFalse: \\n\\t\\t\\t[moviePlayerMorph msPerFrame: (next time - ticks) * secsPerTick * 1000.0 \\n\\t\\t\\t\\t\\t\\t/ (next morph frameNumber - self frameNumber)]! !\\n\\n!MovieFrameSyncMorph methodsFor: 'piano rolls' stamp: 'RAA 12/11/2000 22:58'!\\njustDroppedIntoPianoRoll: pianoRoll event: evt\\n\\n\\t\\\"since these morphs handle their own dropping, ignore\\\"! !\\n\\n!MovieFrameSyncMorph methodsFor: 'piano rolls' stamp: 'di 10/25/2000 22:03'!\\npauseFrom: scorePlayer\\n\\n\\tself relatedPlayer pauseFrom: scorePlayer! !\\n\\n!MovieFrameSyncMorph methodsFor: 'piano rolls' stamp: 'di 10/25/2000 22:02'!\\nresetFrom: scorePlayer\\n\\n\\tself relatedPlayer resetFrom: scorePlayer! !\\n\\n!MovieFrameSyncMorph methodsFor: 'piano rolls' stamp: 'di 10/25/2000 22:03'!\\nresumeFrom: scorePlayer\\n\\n\\tself relatedPlayer resumeFrom: scorePlayer! !\\nMorph subclass: #MovieMorph\\n\\tinstanceVariableNames: 'playMode msecsPerFrame rotationDegrees scalePoint frameList currentFrameIndex dwellCount'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Basic'!\\n\\n!MovieMorph methodsFor: 'accessing'!\\nform\\n\\n\\t^ self currentFrame form\\n! !\\n\\n!MovieMorph methodsFor: 'accessing' stamp: 'jm 7/24/97 15:05'!\\nscalePoint\\n\\n\\t^ scalePoint\\n! !\\n\\n!MovieMorph methodsFor: 'accessing' stamp: 'jm 7/24/97 15:05'!\\nscalePoint: newScalePoint\\n\\n\\t| frame |\\n\\tnewScalePoint ~= scalePoint ifTrue: [\\n\\t\\tself changed.\\n\\t\\tscalePoint _ newScalePoint.\\n\\t\\tframe _ self currentFrame.\\n\\t\\tframe ifNotNil: [frame scalePoint: newScalePoint].\\n\\t\\tself layoutChanged.\\n\\t\\tself changed].\\n! !\\n\\n\\n!MovieMorph methodsFor: 'drawing' stamp: 'dgd 2/22/2003 18:47'!\\ndrawOn: aCanvas \\n\\t| frame |\\n\\tframe := self currentFrame.\\n\\tframe notNil \\n\\t\\tifTrue: [^frame drawOn: aCanvas]\\n\\t\\tifFalse: [^super drawOn: aCanvas]! !\\n\\n\\n!MovieMorph methodsFor: 'geometry testing' stamp: 'dgd 2/22/2003 18:48'!\\ncontainsPoint: p \\n\\t| frame |\\n\\tframe := self currentFrame.\\n\\t^ (frame notNil and: [playMode = #stop]) \\n\\t\\tifTrue: [frame containsPoint: p]\\n\\t\\tifFalse: [super containsPoint: p]! !\\n\\n\\n!MovieMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:28'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color\\n\\t\\tr: 1\\n\\t\\tg: 0\\n\\t\\tb: 1! !\\n\\n!MovieMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 21:47'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\t\\n\\tplayMode _ #stop.\\n\\t\\\"#stop, #playOnce, or #loop\\\"\\n\\tmsecsPerFrame _ 200.\\n\\trotationDegrees _ 0.\\n\\tscalePoint _ 1.0 @ 1.0.\\n\\tframeList _ EmptyArray.\\n\\tcurrentFrameIndex _ 1.\\n\\tdwellCount _ 0! !\\n\\n\\n!MovieMorph methodsFor: 'menu' stamp: 'nk 6/12/2004 09:59'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\n\\t| movies subMenu |\\n\\tsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.\\n\\taCustomMenu addLine.\\n\\tsubMenu _ MenuMorph new defaultTarget: self.\\n\\tframeList size > 1 ifTrue: [\\n\\t\\tsubMenu add: 'repaint' translated action: #editDrawing.\\n\\t\\tsubMenu add: 'set rotation center' translated action: #setRotationCenter.\\n\\t\\tsubMenu add: 'play once' translated action: #playOnce.\\n\\t\\tsubMenu add: 'play loop' translated action: #playLoop.\\n\\t\\tsubMenu add: 'stop playing' translated action: #stopPlaying.\\n\\t\\tcurrentFrameIndex > 1 ifTrue: [\\n\\t\\t\\tsubMenu add: 'previous frame' translated action: #previousFrame].\\n\\t\\tcurrentFrameIndex < frameList size ifTrue: [\\n\\t\\t\\tsubMenu add: 'next frame' translated action: #nextFrame]].\\n\\tsubMenu add: 'extract this frame' translated action: #extractFrame:.\\n\\tmovies _\\n\\t\\t(self world rootMorphsAt: aHandMorph targetOffset)\\n\\t\\t\\tselect: [:m | (m isKindOf: MovieMorph) or:\\n\\t\\t\\t\\t\\t\\t[m isSketchMorph]].\\n\\t(movies size > 1) ifTrue:\\n\\t\\t[subMenu add: 'insert into movie' translated action: #insertIntoMovie:].\\n\\taCustomMenu add: 'movie...' translated subMenu: subMenu\\n! !\\n\\n!MovieMorph methodsFor: 'menu'!\\nadvanceFrame\\n\\n\\tcurrentFrameIndex < frameList size\\n\\t\\tifTrue: [self setFrame: currentFrameIndex + 1]\\n\\t\\tifFalse: [self setFrame: 1].\\n! !\\n\\n!MovieMorph methodsFor: 'menu' stamp: 'dgd 2/22/2003 18:47'!\\neditDrawing\\n\\t| frame |\\n\\tframe := self currentFrame.\\n\\tframe notNil \\n\\t\\tifTrue: [frame editDrawingIn: self pasteUpMorph forBackground: false]! !\\n\\n!MovieMorph methodsFor: 'menu'!\\nextractFrame: evt\\n\\n\\t| f |\\n\\tf _ self currentFrame.\\n\\tf ifNil: [^ self].\\n\\tframeList _ frameList copyWithout: f.\\n\\tframeList isEmpty\\n\\t\\tifTrue: [self position: f position]\\n\\t\\tifFalse: [self setFrame: currentFrameIndex].\\n\\tevt hand attachMorph: f.\\n! !\\n\\n!MovieMorph methodsFor: 'menu' stamp: 'nk 6/12/2004 09:59'!\\ninsertIntoMovie: evt\\n\\n\\t| movies aTarget |\\n\\tmovies _\\n\\t\\t(self world rootMorphsAt: evt hand targetOffset)\\n\\t\\t\\tselect: [:m | ((m isKindOf: MovieMorph) or:\\n\\t\\t\\t\\t\\t\\t [m isSketchMorph]) and: [m ~= self]].\\n\\tmovies isEmpty ifTrue: [^ self].\\n\\taTarget _ movies first.\\n\\t(aTarget isSketchMorph) ifTrue:\\n\\t\\t[aTarget _ aTarget replaceSelfWithMovie].\\n\\tmovies first insertFrames: frameList.\\n\\tself delete.\\n! !\\n\\n!MovieMorph methodsFor: 'menu'!\\nnextFrame\\n\\n\\tcurrentFrameIndex < frameList size\\n\\t\\tifTrue: [self setFrame: currentFrameIndex + 1].\\n! !\\n\\n!MovieMorph methodsFor: 'menu'!\\nplayLoop\\n\\n\\tplayMode _ #loop.\\n! !\\n\\n!MovieMorph methodsFor: 'menu'!\\nplayOnce\\n\\n\\tself setFrame: 1.\\n\\tplayMode _ #playOnce.\\n! !\\n\\n!MovieMorph methodsFor: 'menu'!\\npreviousFrame\\n\\n\\tcurrentFrameIndex > 1\\n\\t\\tifTrue: [self setFrame: currentFrameIndex - 1].\\n! !\\n\\n!MovieMorph methodsFor: 'menu'!\\nstopPlaying\\n\\n\\tplayMode _ #stop.\\n\\tself setFrame: 1.\\n! !\\n\\n\\n!MovieMorph methodsFor: 'rotate scale and flex'!\\nrotationDegrees\\n\\n\\t^ rotationDegrees\\n! !\\n\\n\\n!MovieMorph methodsFor: 'stepping and presenter'!\\nstep\\n\\n\\tplayMode = #stop ifTrue: [^ self].\\n\\n\\tdwellCount > 0 ifTrue: [\\n\\t\\tdwellCount _ dwellCount - 1.\\n\\t\\t^ self].\\n\\n\\tcurrentFrameIndex < frameList size\\n\\t\\tifTrue: [^ self setFrame: currentFrameIndex + 1].\\n\\n\\tplayMode = #loop\\n\\t\\tifTrue: [self setFrame: 1]\\n\\t\\tifFalse: [playMode _ #stop].\\n! !\\n\\n\\n!MovieMorph methodsFor: 'testing'!\\nstepTime\\n\\n\\t^ msecsPerFrame\\n! !\\n\\n\\n!MovieMorph methodsFor: 'private' stamp: 'jdl 3/28/2003 08:03'!\\ncurrentFrame\\n\\tframeList isEmpty ifTrue: [^nil].\\n currentFrameIndex := currentFrameIndex min: (frameList size).\\n currentFrameIndex := currentFrameIndex max: 1.\\n\\t^frameList at: currentFrameIndex! !\\n\\n!MovieMorph methodsFor: 'private'!\\ninsertFrames: newFrames\\n\\t\\\"Insert the given collection of frames into this movie just after the currentrame.\\\"\\n\\n\\tframeList isEmpty ifTrue: [\\n\\t\\tframeList _ newFrames asArray copy.\\n\\t\\tself setFrame: 1.\\n\\t\\t^ self].\\n\\n\\tframeList _\\n\\t\\tframeList\\n\\t\\t\\tcopyReplaceFrom: currentFrameIndex + 1 \\\"insert before\\\"\\n\\t\\t\\tto: currentFrameIndex\\n\\t\\t\\twith: newFrames.\\n! !\\n\\n!MovieMorph methodsFor: 'private' stamp: 'jdl 3/28/2003 08:08'!\\nsetFrame: newFrameIndex \\n\\t| oldFrame p newFrame |\\n\\toldFrame := self currentFrame.\\n\\toldFrame ifNil: [^self].\\n\\tself changed.\\n\\tp := oldFrame referencePosition.\\n\\tcurrentFrameIndex := newFrameIndex.\\n currentFrameIndex := currentFrameIndex min: (frameList size). \\n\\tcurrentFrameIndex := currentFrameIndex max: 1.\\n\\tnewFrame := frameList at: currentFrameIndex.\\n\\tnewFrame referencePosition: p.\\n\\toldFrame delete.\\n\\tself addMorph: newFrame.\\n\\tdwellCount := newFrame framesToDwell.\\n\\tself layoutChanged.\\n\\tself changed! !\\nBookMorph subclass: #MoviePlayerMorph\\n\\tinstanceVariableNames: 'movieFileName movieFile frameSize frameDepth frameNumber frameCount playDirection msSinceStart msAtStart msAtLastSync frameAtLastSync msPerFrame frameBufferIfScaled soundTrackFileName scorePlayer soundTrackForm soundTrackMorph pianoRoll cueMorph'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Movies-Player'!\\n!MoviePlayerMorph commentStamp: '<historical>' prior: 0!\\nMoviePlayerMorph plays images from a file using async io. The file format is simple but non-standard (see below).\\n\\nThe heart of the play logic is in the step method. Note that play is driven by a simulated time since start. For a movie with a sound score, this is the millisecondsSinceStart of the score player, whereas a movie by itself gets this from the millisecondClock minus msAtStart.\\n\\nMovie players are designed to be used in three ways\\n\\t1. Select a movie in the file list, 'open as movie', and play it.\\n\\t2. As in (1), but drop thumbnails for various frames into a\\n\\t\\tMIDI piano roll to synchronize video with music.\\n\\t3. Open a MoviePlayerMorph as a 'new morph', and choose\\n\\t\\t'make a new movie' from the menu.\\n\\nIn (1) and (2), a shift-drag is used to 'tear off' a thumbnail reference morph to the currently visible frame of this clips. The thumbnail can then be dropped in a MIDI score player to either syncronize that frame with what point in the music, or to cause that clip to being playing in the shared player of a SqueakMovie plex.\\n\\nWhen making a new movie, an empty score and piano roll are linked to the movie player, as a SqueakMovie plex. You can then open another movie as a clip, and drop a thumbnail morph into the score to start that clip playing at that frame in the shared player. If you pause while playing that clip, you can manually play the clip forward and backward in the current clip. if you stop at a given frame, you can choose 'end clip here' from the shared player menu to shorten or lengthen the clip.\\n\\nClips can be moved by picking up the starting thumbnail (use halo black handle), and dropping them elsewhere. If you try to place one clip in the middle of another, it will slide to the end. If you position one clip close to the end of another, it will sidle up to make them contiguous.\\n\\nIf you wish a soundtrack to be included with a clip, make sure it has been opened in the source clip player before tearing off the starting thumbnail.\\n\\nAbout the .movie file format...\\nThe following code was used to convert 27 files into a movie. They were named\\n\\t'BalloonDrop10fps003.bmp' through 'BalloonDrop10fps081.bmp'\\nincrementing by 003. Each was known to be a 320x240 image in 32-bit BMP format.\\nNote the 27 in the 5th line is the number of frames, = (3 to: 81 by: 3) size.\\n\\n\\t| ps zps f32 out ff |\\n\\tout _ FileStream newFileNamed: 'BalloonDrop10fps.movie'.\\n\\tout binary.\\n\\tff _ Form extent: 320@240 depth: 16.\\n\\t#(22 320 240 16 27 100000) , (7 to: 32)\\n\\t\\tdo: [:i | out nextInt32Put: i].\\n\\t\\t\\n\\t3 to: 81 by: 3 do:\\n\\t\\t[:i | ps _ i printString. zps _ ps padded: #left to: 3 with: $0.\\n\\t\\tf32 _ Form fromFileNamed:\\n\\t\\t\\t'BalloonDrop10fps' , zps , '.bmp'.\\n\\t\\tf32 displayOn: ff at: 0@0. \\\"Convert down to 16 bits\\\"\\n\\t\\tff display; writeOnMovie: out].\\n\\tout close.\\n!\\n\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'di 10/26/2000 00:18'!\\ncueMorph\\n\\t^ cueMorph! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'di 10/4/2000 17:19'!\\nfileName\\n\\t^ movieFileName! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'di 10/22/2000 10:54'!\\nframeCount\\n\\n\\t^ frameCount! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nframeNumber: n\\n\\n\\tframeNumber := n! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nframeNumber: n msSinceStart: ms\\n\\t\\\"Set the current frame number, and save the scorePlayer's simulated time for synchronization.\\\"\\n\\n\\tframeAtLastSync := n.\\n\\tmsAtLastSync := ms.\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'di 10/19/2000 16:31'!\\nmsPerFrame\\n\\t^ msPerFrame! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nmsPerFrame: n\\n\\t\\\"Set a new frame rate, base on, eg, score synchronization info.\\\"\\n\\n\\tmsPerFrame := n.\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'stephaneducasse 2/4/2006 20:48'!\\npageFormForFrame: frameNo\\n\\n\\t| f form oldFrame |\\noldFrame := frameNumber.\\nself goToPage: frameNo.\\nform := currentPage image deepCopy.\\nself goToPage: oldFrame.\\ntrue ifTrue: [^ form].\\n\\n\\tf := FileStream readOnlyFileNamed: movieFileName.\\n\\tform := Form extent: frameSize depth: frameDepth.\\n\\n\\t\\\"For some weird reason, the next line does not work...\\\"\\n\\tf position: (self filePosForFrameNo: frameNo).\\n\\t\\\"... but this line was found empirically to work instead.\\\"\\n\\tf position: (128 + ((frameNo-1)*(form bits size*4+4)) + 4).\\n\\n\\tf nextInto: form bits.\\n\\tf close.\\n\\t^ form! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'di 10/15/2000 19:15'!\\nrelativePosition\\n\\n\\t^ frameNumber asFloat / frameCount! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'di 10/11/2000 12:13'!\\nscorePlayer\\n\\n\\t^ scorePlayer! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nscorePlayer: aScorePlayer\\n\\n\\tscorePlayer := aScorePlayer! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nsetCueMorph: aMorph\\n\\tcueMorph := aMorph\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'access' stamp: 'di 10/13/2000 11:51'!\\nsoundTrackFileName\\n\\t^ soundTrackFileName! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'controls and layout' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nshowHideSoundTrack\\n\\n\\tsoundTrackForm ifNotNil:\\n\\t\\t[soundTrackMorph delete.\\n\\t\\t^ soundTrackForm := soundTrackMorph := nil].\\n\\n\\tsoundTrackForm := scorePlayer volumeForm: 20 from: 1 to: scorePlayer samples size nSamplesPerPixel: 250.\\n\\tsoundTrackMorph := ImageMorph new image: (Form extent: 140 @ soundTrackForm height).\\n\\tsoundTrackMorph addMorph:\\n\\t\\t(Morph newBounds: (soundTrackMorph bounds topCenter extent: 1@soundTrackMorph height)\\n\\t\\t\\t\\t\\tcolor: Color red).\\n\\tself addMorph: soundTrackMorph after: currentPage.\\n\\tself layoutChanged.\\n\\tself stepSoundTrack.\\n! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'copying' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nduplicate\\n\\t| dup |\\n\\tplayDirection ~= 0 ifTrue: [self stopPlay].\\n\\tdup := super duplicate.\\n\\tdup scorePlayer: scorePlayer copy. \\\"Share sound track if any.\\\"\\n\\t^ dup duplicateMore startStepping! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'event handling' stamp: 'di 10/16/2000 13:27'!\\nhandlesMouseDown: evt\\n\\t\\\"We use shift drag to 'tear off' a thumbnail\\\"\\n\\n\\tevt shiftPressed ifTrue: [^ true].\\n\\t^ super handlesMouseDown: evt! !\\n\\n!MoviePlayerMorph methodsFor: 'event handling' stamp: 'di 10/16/2000 13:32'!\\nmouseDown: evt\\n\\t\\\"We use shift drag to 'tear off' a thumbnail\\\"\\n\\n\\tevt shiftPressed ifTrue: [^ self makeThumbnailInHand: evt hand].\\n\\t^ super mouseDown: evt\\n\\t\\t! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'geometry' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nextent: newExtent\\n\\n\\t| tlMargin brMargin pageExtent scale fullSizeImage |\\n\\tfullSizeImage := frameBufferIfScaled ifNil: [currentPage image].\\n\\tframeCount ifNil: [^ self]. \\\"Not yet open\\\"\\n\\ttlMargin := currentPage topLeft - self topLeft.\\n\\tbrMargin := self bottomRight - currentPage bottomRight.\\n\\tpageExtent := newExtent - brMargin - tlMargin.\\n\\tscale := pageExtent x asFloat / frameSize x min: pageExtent y asFloat / frameSize y.\\n\\t(scale := scale max: 0.25) > 0.9 ifTrue: [scale := 1.0].\\n\\n\\tpageExtent := (frameSize * scale) rounded.\\n\\tpageExtent = frameSize\\n\\t\\tifTrue: [currentPage image: fullSizeImage.\\n\\t\\t\\t\\tframeBufferIfScaled := nil]\\n\\t\\tifFalse: [currentPage image: (Form extent: pageExtent depth: frameDepth).\\n\\t\\t\\t\\tframeBufferIfScaled := fullSizeImage.\\n\\t\\t\\t\\t(WarpBlt current toForm: currentPage image) sourceForm: fullSizeImage;\\n\\t\\t\\t\\t\\tcombinationRule: 3;\\n\\t\\t\\t\\t\\tcopyQuad: fullSizeImage boundingBox innerCorners\\n\\t\\t\\t\\t\\t\\ttoRect: currentPage image boundingBox].\\n\\t^ self layoutChanged\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'geometry' stamp: 'dgd 2/22/2003 19:01'!\\nposition: newPos \\n\\tsuper position: newPos.\\n\\t(currentPage notNil and: [currentPage left odd]) \\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"crude word alignment for depth = 16\\\"\\n\\n\\t\\t\\tsuper position: newPos + (1 @ 0)]! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:38'!\\ndefaultBorderWidth\\n\\t\\\"answer the default border width for the receiver\\\"\\n\\t^ 2! !\\n\\n!MoviePlayerMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:29'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color veryLightGray! !\\n\\n!MoviePlayerMorph methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nduplicateMore\\n\\t\\\"Duplicate dies not replicate Forms, but MoviePlayers need this.\\\"\\n\\n\\tframeBufferIfScaled := frameBufferIfScaled deepCopy.\\n\\tcurrentPage image: currentPage image deepCopy.\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'initialization' stamp: 'di 10/8/2000 21:43'!\\nopenFileNamed: fName \\n\\tself pvtOpenFileNamed: fName.\\n\\tself goToPage: 1! !\\n\\n!MoviePlayerMorph methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nopenFileNamed: fName withScorePlayer: playerReady andPlayFrom: frameNo\\n\\t\\\"Note: The plan is that the score player (a SampledSound) is already spaced\\n\\tforward to this frame number so it does not need to be reset as would normally\\n\\thappen in startRunning.\\\"\\n\\n\\tself pvtOpenFileNamed: fName.\\n\\tscorePlayer := playerReady.\\n\\tframeNumber := frameNo.\\n\\tframeAtLastSync := frameNo.\\n\\tmsAtLastSync := frameAtLastSync * msPerFrame.\\n\\tself playForward.! !\\n\\n!MoviePlayerMorph methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nsetInitialState\\n\\tsuper setInitialState.\\n\\\"\\\"\\n\\tself layoutInset: 3.\\n\\tpageSize := frameSize := 200 @ 200.\\n\\tframeDepth := 8.\\n\\tself disableDragNDrop! !\\n\\n!MoviePlayerMorph methodsFor: 'initialization' stamp: 'dgd 2/22/2003 13:22'!\\nstopSoundTrackIfAny\\n\\tscorePlayer isNil ifTrue: [^self].\\n\\t(scorePlayer isKindOf: SampledSound) \\n\\t\\tifTrue: [scorePlayer endGracefully]\\n\\t\\tifFalse: [scorePlayer := nil]! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'menu' stamp: 'dgd 2/22/2003 13:21'!\\naddSoundTrack\\n\\t| fileName |\\n\\tfileName := Utilities chooseFileWithSuffixFromList: #('.aif' '.wav')\\n\\t\\t\\t\\twithCaption: 'Choose a sound track file'.\\n\\tfileName isNil ifTrue: [^self].\\n\\tsoundTrackFileName := fileName.\\n\\tself tryToShareScoreFor: soundTrackFileName.\\n\\tscorePlayer ifNil: \\n\\t\\t\\t[('*aif' match: fileName) \\n\\t\\t\\t\\tifTrue: [scorePlayer := SampledSound fromAIFFfileNamed: fileName].\\n\\t\\t\\t('*wav' match: fileName) \\n\\t\\t\\t\\tifTrue: [scorePlayer := SampledSound fromWaveFileNamed: fileName]].\\n\\tsoundTrackForm ifNotNil: \\n\\t\\t\\t[\\\"Compute new soundTrack if we're showing it.\\\"\\n\\n\\t\\t\\tself\\n\\t\\t\\t\\tshowHideSoundTrack;\\n\\t\\t\\t\\tshowHideSoundTrack]! !\\n\\n!MoviePlayerMorph methodsFor: 'menu' stamp: 'di 10/19/2000 17:07'!\\nendClipHere\\n\\t\\\"Change set the termination time for this clip via the endMorph\\\"\\n\\n\\tcueMorph ifNil: [^ self].\\n\\tcueMorph setEndFrameNumber: frameNumber\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'menu' stamp: 'stephaneducasse 2/4/2006 20:48'!\\ninvokeBookMenu\\n\\t\\\"Invoke the book's control panel menu.\\\"\\n\\t| aMenu |\\n\\taMenu := MVCMenuMorph new defaultTarget: self.\\n\\taMenu add:\\t'make a new movie' translated action: #makeAMovie.\\n\\taMenu add:\\t'open movie file' translated action: #openMovieFile.\\n\\taMenu add:\\t'add sound track' translated action: #addSoundTrack.\\n\\taMenu addLine.\\n\\tscorePlayer ifNotNil:\\n\\t\\t[soundTrackForm isNil\\n\\t\\t\\tifTrue: [aMenu add:\\t'show sound track' translated action: #showHideSoundTrack]\\n\\t\\t\\tifFalse: [aMenu add:\\t'hide sound track' translated action: #showHideSoundTrack]].\\n\\taMenu add:\\t'make thumbnail' translated action: #thumbnailForThisPage.\\n\\tcueMorph ifNotNil:\\n\\t\\t[\\\"Should check if piano roll and score already have a start event\\n\\t\\tprior to this time.\\\"\\n\\t\\taMenu add:\\t'end clip here' translated action: #endClipHere].\\n\\n\\taMenu popUpEvent: self world activeHand lastEvent in: self world\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'menu' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nmakeAMovie\\n\\t| scoreController score |\\n\\tframeSize := 640@480. frameDepth := 16. self makeMyPage; changed.\\n\\n\\t(score := MIDIScore new initialize) \\\"addAmbientEvent: (AmbientEvent new time: 200*60)\\\".\\n\\tscoreController := ScorePlayerMorph new\\n\\t\\t\\tonScorePlayer: (ScorePlayer onScore: score) title: 'sMovie'.\\n\\tpianoRoll := PianoRollScoreMorph new on: scoreController scorePlayer.\\n\\tself pianoRoll: pianoRoll. \\\"back link\\\"\\n\\tpianoRoll enableDragNDrop;\\n\\t\\tuseRoundedCorners;\\n\\t\\tmovieClipPlayer: self;\\n\\t\\tborderWidth: 2;\\n\\t\\textent: self width @ 120;\\n\\t\\talign: pianoRoll topLeft with: self bottomLeft - (0@2);\\n\\t\\topenInWorld.\\n\\tscoreController extent: self width @ scoreController height;\\n\\t\\talign: scoreController topLeft with: pianoRoll bottomLeft - (0@2);\\n\\t\\topenInWorld.\\n\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'menu' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nopenMovieFile\\n\\t| fileName |\\n\\tfileName := Utilities chooseFileWithSuffixFromList: #('.movie')\\n\\t\\t\\t\\t\\twithCaption: 'Choose a movie file to open'.\\n\\tfileName ifNotNil:\\n\\t\\t[self openFileNamed: fileName.\\n\\t\\tself showMoreControls]! !\\n\\n!MoviePlayerMorph methodsFor: 'menu' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nscanBySlider\\n\\t| scrollSlider handle |\\n\\tscrollSlider := SimpleSliderMorph new extent: 150@10;\\n\\t\\tcolor: color; sliderColor: Color gray;\\n\\t\\ttarget: self; actionSelector: #goToRelativePosition:;\\n\\t\\tadjustToValue: self relativePosition.\\n\\t(handle := scrollSlider firstSubmorph) on: #mouseUp send: #delete to: scrollSlider.\\n\\tscrollSlider align: handle center with: self activeHand position.\\n\\tself world addMorph: scrollSlider.\\n\\tself activeHand targetOffset: (handle width // 2) @ 0.\\n\\tself activeHand newMouseFocus: handle! !\\n\\n!MoviePlayerMorph methodsFor: 'menu' stamp: 'di 10/16/2000 13:31'!\\nthumbnailForThisPage\\n\\t\\\"Overridden to make a MovieFrameSyncMorph\\\"\\n\\n\\t^ self makeThumbnailInHand: self activeHand\\n! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'menu commands' stamp: 'di 7/6/1998 19:32'!\\nfirstPage\\n\\tplayDirection = 0 ifFalse: [^ self]. \\\"No-op during play\\\"\\n\\tself goToPage: 1\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'menu commands' stamp: 'di 7/6/1998 14:05'!\\ninsertPage\\n\\t^ self makeMyPage! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'movie clip player' stamp: 'di 10/19/2000 22:02'!\\npianoRoll\\n\\t^ pianoRoll! !\\n\\n!MoviePlayerMorph methodsFor: 'movie clip player' stamp: 'stephaneducasse 2/4/2006 20:48'!\\npianoRoll: aPianoRollScoreMorph\\n\\t\\\"Provides access also to the score and scorePlayer\\\"\\n\\n\\tpianoRoll := aPianoRollScoreMorph\\n! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'navigation' stamp: 'stephaneducasse 2/4/2006 20:48'!\\ngoToPage: i\\n\\tcurrentPage ifNil: [self makeMyPage].\\n\\tframeNumber := i.\\n\\tplayDirection := 0.\\n\\tself startRunning; step. \\\"will stop after first step\\\"\\n\\tsoundTrackMorph ifNotNilDo: [:m | m image fillWhite].\\n\\tself stepSoundTrack.\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'navigation' stamp: 'di 7/6/1998 19:29'!\\nlastPage\\n\\tplayDirection = 0 ifFalse: [^ self]. \\\"No-op during play\\\"\\n\\tself goToPage: frameCount\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'navigation' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nnextPage\\n\\tplayDirection = 0 ifFalse: [^ self]. \\\"No-op during play\\\"\\n\\tself goToPage: (frameNumber := frameNumber + 1 min: frameCount).\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'navigation' stamp: 'stephaneducasse 2/4/2006 20:48'!\\npreviousPage\\n\\tplayDirection = 0 ifFalse: [^ self]. \\\"No-op during play\\\"\\n\\tself goToPage: (frameNumber := frameNumber - 1 max: 1).\\n! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'page controls' stamp: 'di 10/16/2000 13:20'!\\nfullControlSpecs\\n\\t^ #(\\t\\n\\t\\t\\t( '\\U00b7'\\t\\tinvokeBookMenu 'Invoke menu')\\n\\t\\t\\t( '<--'\\t\\tfirstPage\\t\\t'Go to first page')\\n\\t\\t\\t( '<<'\\t\\tplayReverse\\t\\t'Play backward')\\n\\t\\t\\t( '<-' \\t\\tpreviousPage\\t'Back one frame')\\n\\t\\t\\t( '| |' \\t\\tstopPlay\\t\\t'Stop playback')\\n\\t\\t\\t( '->'\\t\\tnextPage\\t\\t'Forward one frame')\\n\\t\\t\\t( '>>'\\t\\tplayForward\\t'Play forward')\\n\\t\\t\\t( '-->'\\t\\tlastPage\\t\\t\\t'Go to final page')\\n\\t\\t\\t( '<->'\\t\\tscanBySlider\\t'Scan by slider' 'menu')\\n\\t\\t\\\"Note extra spec 'menu' causes mousedown activation -- see makePageControlsFrom:\\\"\\n\\t)! !\\n\\n!MoviePlayerMorph methodsFor: 'page controls' stamp: 'di 10/24/2000 16:55'!\\nshowPageControls\\n\\tself showPageControls: self fullControlSpecs.\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'page controls' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nshowPageControls: controlSpecs \\n\\t| pageControls |\\n\\tself hidePageControls.\\n\\n\\tpageControls := self makePageControlsFrom: controlSpecs.\\n\\tpageControls borderWidth: 0; layoutInset: 0; extent: pageControls width@14.\\n\\tpageControls setProperty: #pageControl toValue: true.\\n\\tpageControls setNameTo: 'Page Controls'.\\n\\tpageControls eventHandler: (EventHandler new on: #mouseDown send: #move to: self).\\n\\tself addMorphBack: pageControls beSticky! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'piano rolls' stamp: 'stephaneducasse 2/4/2006 20:48'!\\npauseFrom: player\\n\\n\\tplayDirection := 0.\\n\\tself step.! !\\n\\n!MoviePlayerMorph methodsFor: 'piano rolls' stamp: 'di 10/25/2000 22:06'!\\nresetFrom: player\\n\\tself pauseFrom: player.\\n\\tself firstPage! !\\n\\n!MoviePlayerMorph methodsFor: 'piano rolls' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nresumeFrom: player\\n\\tplayDirection ~= 0 ifTrue: [^ self]. \\\"Already running\\\"\\n\\tplayDirection := 1.\\n\\tpianoRoll ifNil:\\n\\t\\t[\\\"Sync movie to score player if not a clip player\\\"\\n\\t\\tscorePlayer := player].\\n\\tself startRunning! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'player control' stamp: 'di 10/16/2000 11:02'!\\ngoToRelativePosition: newPos\\n\\n\\tmovieFile ifNotNil: [^ self].\\n\\tself goToPage: ((newPos*frameCount) asInteger min: frameCount max: 1).\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'player control' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nplayForward\\n\\t(playDirection ~= 0 or: [frameNumber >= frameCount]) ifTrue:\\n\\t\\t[^ self]. \\\"No-op during play or at end\\\"\\n\\tplayDirection := 1.\\n\\tself startRunning! !\\n\\n!MoviePlayerMorph methodsFor: 'player control' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nplayReverse\\n\\t(playDirection ~= 0 or: [frameNumber <= 1]) ifTrue:\\n\\t\\t[^ self]. \\\"No-op during play or at end\\\"\\n\\tplayDirection := -1.\\n\\tself startRunning! !\\n\\n!MoviePlayerMorph methodsFor: 'player control' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nstopPlay\\n\\n\\tplayDirection := 0.\\n\\tself step! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'rounding' stamp: 'di 10/22/2000 23:41'!\\nwantsRoundedCorners\\n\\t^ Preferences roundedWindowCorners or: [super wantsRoundedCorners]! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'stepping' stamp: 'di 9/5/2000 23:09'!\\nfileByteCountPerFrame\\n\\t\\n\\t^ (frameBufferIfScaled ifNil: [currentPage image]) bits size * 4\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'stepping' stamp: 'di 5/27/1999 22:40'!\\nfilePosForFrameNo: frameNo\\n\\t\\n\\t^ 128 + ((frameNo-1)*(4+self fileByteCountPerFrame)) + 4\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'stepping' stamp: 'dgd 2/22/2003 13:22'!\\nstartRunning\\n\\t| ms |\\n\\t(frameBufferIfScaled ifNil: [currentPage image]) unhibernate.\\n\\tmovieFile := AsyncFile new \\n\\t\\t\\t\\topen: (FileDirectory default fullNameFor: movieFileName)\\n\\t\\t\\t\\tforWrite: false.\\n\\tmovieFile \\n\\t\\tprimReadStart: movieFile fileHandle\\n\\t\\tfPosition: (self filePosForFrameNo: frameNumber)\\n\\t\\tcount: self fileByteCountPerFrame.\\n\\tscorePlayer isNil \\n\\t\\tifTrue: \\n\\t\\t\\t[ms := Time millisecondClockValue.\\n\\t\\t\\tmsAtStart := ms - ((frameNumber - 1) * msPerFrame).\\n\\t\\t\\tmsAtLastSync := ms - msAtStart]\\n\\t\\tifFalse: \\n\\t\\t\\t[(playDirection > 0 and: [scorePlayer isKindOf: SampledSound]) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[scorePlayer\\n\\t\\t\\t\\t\\t\\treset;\\n\\t\\t\\t\\t\\t\\tplaySilentlyUntil: (frameNumber - 1) * msPerFrame / 1000.0;\\n\\t\\t\\t\\t\\t\\tinitialVolume: 1.0.\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t[scorePlayer resumePlaying.\\n\\t\\t\\t\\t\\tmsAtLastSync := scorePlayer millisecondsSinceStart] \\n\\t\\t\\t\\t\\t\\t\\tforkAt: Processor userInterruptPriority].\\n\\t\\t\\tmsAtLastSync := scorePlayer millisecondsSinceStart].\\n\\tframeAtLastSync := frameNumber! !\\n\\n!MoviePlayerMorph methodsFor: 'stepping' stamp: 'dgd 2/22/2003 13:22'!\\nstep\\n\\t\\\"NOTE: The movie player has two modes of play, depending on whether scorePlayer is nil or not. If scorePlayer is nil, then play runs according to the millisecond clock. If scorePlayer is not nil, then the scorePlayer is consulted for synchronization. If the movie is running ahead, then some calls on step will skip their action until the right time. If the movie is running behind, then the frame may advance by more than one to maintain synchronization.\\\"\\n\\n\\t\\\"ALSO: This player operates with overlapped disk i/o. This means that while one frame is being displayed, the next frame in sequence is being read into a disk buffer. The value of frameNumber corresponds to the frame currently visible.\\\"\\n\\n\\t\\\"This code may not work right for playing backwards right now.\\n\\tSingle-step and backwards (dir <= 0) should just run open-loop.\\\"\\n\\n\\t| byteCount simTime ms nextFrameNumber |\\n\\tmovieFile isNil ifTrue: [^self].\\n\\tscorePlayer isNil \\n\\t\\tifTrue: \\n\\t\\t\\t[(ms := Time millisecondClockValue) < msAtStart \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[\\\"clock rollover\\\"\\n\\n\\t\\t\\t\\t\\tmsAtStart := ms - (frameNumber * msPerFrame)].\\n\\t\\t\\tsimTime := ms - msAtStart]\\n\\t\\tifFalse: [simTime := scorePlayer millisecondsSinceStart].\\n\\tplayDirection > 0 \\n\\t\\tifTrue: \\n\\t\\t\\t[nextFrameNumber := frameAtLastSync \\n\\t\\t\\t\\t\\t\\t+ ((simTime - msAtLastSync) // msPerFrame).\\n\\t\\t\\tnextFrameNumber = frameNumber \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[((scorePlayer isKindOf: AbstractSound) and: [scorePlayer isPlaying not]) \\n\\t\\t\\t\\t\\t\\tifTrue: [^self stopRunning].\\n\\t\\t\\t\\t\\t^self]]\\n\\t\\tifFalse: \\n\\t\\t\\t[nextFrameNumber := playDirection < 0 \\n\\t\\t\\t\\t\\t\\tifTrue: [frameNumber - 1]\\n\\t\\t\\t\\t\\t\\tifFalse: [frameNumber]].\\n\\tbyteCount := self fileByteCountPerFrame.\\n\\tself stepSoundTrack.\\n\\tmovieFile waitForCompletion.\\n\\tmovieFile \\n\\t\\tprimReadResult: movieFile fileHandle\\n\\t\\tintoBuffer: (frameBufferIfScaled ifNil: [currentPage image]) bits\\n\\t\\tat: 1\\n\\t\\tcount: byteCount // 4.\\n\\tframeBufferIfScaled ifNotNil: \\n\\t\\t\\t[\\\"If this player has been shrunk, then we have to warp to the current page.\\\"\\n\\n\\t\\t\\t(WarpBlt current toForm: currentPage image)\\n\\t\\t\\t\\tsourceForm: frameBufferIfScaled;\\n\\t\\t\\t\\tcombinationRule: 3;\\n\\t\\t\\t\\tcellSize: (playDirection = 0 \\n\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t[\\\"Use smoothing if just stepping\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t2]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [1]);\\n\\t\\t\\t\\tcopyQuad: frameBufferIfScaled boundingBox innerCorners\\n\\t\\t\\t\\t\\ttoRect: currentPage image boundingBox].\\n\\tcurrentPage changed.\\n\\tframeNumber := nextFrameNumber.\\n\\t(playDirection = 0 or: \\n\\t\\t\\t[(playDirection > 0 and: [frameNumber >= frameCount]) \\n\\t\\t\\t\\tor: [playDirection < 0 and: [frameNumber <= 1]]]) \\n\\t\\tifTrue: [^self stopRunning].\\n\\n\\t\\\"Start the read operation for the next frame...\\\"\\n\\tmovieFile \\n\\t\\tprimReadStart: movieFile fileHandle\\n\\t\\tfPosition: (self filePosForFrameNo: frameNumber)\\n\\t\\tcount: byteCount! !\\n\\n!MoviePlayerMorph methodsFor: 'stepping' stamp: 'aoy 2/15/2003 21:45'!\\nstepSoundTrack\\n\\t| x image timeInMillisecs |\\n\\tscorePlayer ifNil: [^self].\\n\\tsoundTrackForm ifNil: [^self].\\n\\ttimeInMillisecs := playDirection = 0 \\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"Stepping forward or back\\\"\\n\\n\\t\\t\\t (frameNumber - 1) * msPerFrame]\\n\\t\\tifFalse: \\n\\t\\t\\t[\\\"Driven by sound track\\\"\\n\\n\\t\\t\\t scorePlayer millisecondsSinceStart].\\n\\tx := timeInMillisecs / 1000.0 * scorePlayer originalSamplingRate // 250.\\n\\timage := soundTrackMorph image.\\n\\timage \\n\\t\\tcopy: (image boundingBox translateBy: (x - (image width // 2)) @ 0)\\n\\t\\tfrom: soundTrackForm\\n\\t\\tto: 0 @ 0\\n\\t\\trule: Form over.\\n\\tsoundTrackMorph changed! !\\n\\n!MoviePlayerMorph methodsFor: 'stepping' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nstopRunning\\n\\t\\\"Must only be called with no outstanding file read requests...\\\"\\n\\tmovieFile ifNotNil: [movieFile close. movieFile := nil].\\n\\tplayDirection := 0.\\n\\tself stopSoundTrackIfAny\\n! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'testing' stamp: 'di 8/8/1998 11:57'!\\nstepTime\\n\\t^ 0 \\\"step as fast as possible\\\"! !\\n\\n\\n!MoviePlayerMorph methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nmakeMyPage\\n\\n\\tcurrentPage ifNotNil:\\n\\t\\t[(currentPage isMemberOf: ImageMorph)\\n\\t\\t\\tifTrue: [\\\"currentPage is already an ImageMorph.\\\"\\n\\t\\t\\t\\t\\t(currentPage image extent = frameSize\\n\\t\\t\\t\\t\\t\\tand: [currentPage image depth = frameDepth])\\n\\t\\t\\t\\t\\t\\tifTrue: [^ self \\\"page is already properly dimensioned.\\\"].\\n\\t\\t\\t\\t\\t^ currentPage image: (Form extent: frameSize depth: frameDepth)]\\n\\t\\t\\tifFalse: [currentPage releaseCachedState; delete]].\\n\\tcurrentPage := ImageMorph new image: (Form extent: frameSize depth: frameDepth).\\n\\tcurrentPage lock.\\n\\tpages := OrderedCollection with: currentPage.\\n\\tself addMorphFront: currentPage! !\\n\\n!MoviePlayerMorph methodsFor: 'private' stamp: 'di 10/25/2000 23:01'!\\nmakeThumbnailInHand: aHand\\n\\n\\tscorePlayer ifNotNil:\\n\\t\\t[\\\"Position the soundTrack for this frameNumber\\\"\\n\\t\\tscorePlayer reset; playSilentlyUntil: frameNumber - 1 * msPerFrame / 1000.0].\\n\\n\\taHand attachMorph:\\n\\t\\t(MovieClipStartMorph new\\n\\t\\t\\tmovieFileName: movieFileName\\n\\t\\t\\tsoundTrackFileName: soundTrackFileName\\n\\t\\t\\timage: currentPage image\\n\\t\\t\\tplayer: self\\n\\t\\t\\tframeNumber: frameNumber)\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:48'!\\npvtOpenFileNamed: fName\\n\\t\\\"Private - open on the movie file iof the given name\\\"\\n\\n\\t| f w h d n m |\\n\\tself stopRunning.\\n\\tfName = movieFileName ifTrue: [^ self]. \\\"No reopen necessary on same file\\\"\\n\\n\\tmovieFileName := fName.\\n\\t\\\"Read movie file parameters from 128-byte header...\\n\\t\\t(records follow as {N=int32, N words}*)\\\"\\n\\tf := (FileStream oldFileNamed: movieFileName) binary.\\n\\t\\tf nextInt32.\\n\\t\\tw := f nextInt32.\\n\\t\\th := f nextInt32.\\n\\t\\td := f nextInt32.\\n\\t\\tn := f nextInt32.\\n\\t\\tm := f nextInt32.\\n\\t\\tf close.\\n\\tpageSize := frameSize := w@h.\\n\\tframeDepth := d.\\n\\tframeCount := n.\\n\\tframeNumber := 1.\\n\\tplayDirection := 0.\\n\\tmsAtLastSync := 0.\\n\\tmsPerFrame := m/1000.0.\\n\\tself makeMyPage.\\n\\t(SmalltalkImage current platformName = 'Mac OS') ifTrue:[\\n\\t\\t(SmalltalkImage current extraVMMemory < self fileByteCountPerFrame) ifTrue:\\n\\t\\t\\t[^ self inform:\\n'Playing movies in Squeak requires that extra memory be allocated\\nfor asynchronous file IO. This particular movie requires a buffer of\\n' ,\\n(self fileByteCountPerFrame printString) , ' bytes, but you only have ' , (SmalltalkImage current extraVMMemory printString) , ' allocated.\\nYou can evaluate ''SmalltalkImage current extraVMMemory'' to check your allocation,\\nand ''SmalltalkImage current extraVMMemory: 485000'' or the like to increase your allocation.\\nNote that raising your allocation in this way only marks your image as\\nneeding this much, so you must then save, quit, and start over again\\nbefore you can run this movie. Good luck.']].\\n! !\\n\\n!MoviePlayerMorph methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:48'!\\ntryToShareScoreFor: fileName\\n\\n\\tscorePlayer := nil.\\n\\tself class allInstancesDo:\\n\\t\\t[:mp | mp == self ifFalse:\\n\\t\\t\\t[mp soundTrackFileName = fileName ifTrue:\\n\\t\\t\\t\\t[\\\"Found this score already open in another player\\n\\t\\t\\t\\t\\t-- return a copy that shares the same sound buffer.\\\"\\n\\t\\t\\t\\tmp scorePlayer ifNotNil: [^ scorePlayer := mp scorePlayer copy reset]]]]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMoviePlayerMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!MoviePlayerMorph class methodsFor: 'class initialization' stamp: 'hg 8/3/2000 16:59'!\\ninitialize\\n\\n\\tFileList registerFileReader: self! !\\n\\n\\n!MoviePlayerMorph class methodsFor: 'fileIn/Out' stamp: 'sd 2/6/2002 21:36'!\\nfileReaderServicesForFile: fullName suffix: suffix\\n\\n\\t^(suffix = 'movie') | (suffix = '*')\\n\\t\\tifTrue: [ self services]\\n\\t\\tifFalse: [#()]! !\\n\\n!MoviePlayerMorph class methodsFor: 'fileIn/Out' stamp: 'hg 8/3/2000 17:01'!\\nopenAsMovie: fullFileName\\n\\t\\\"Open a MoviePlayerMorph on the given file (must be in .movie format).\\\"\\n \\n\\t(self new openFileNamed: fullFileName) openInWorld! !\\n\\n!MoviePlayerMorph class methodsFor: 'fileIn/Out' stamp: 'sw 2/17/2002 01:23'!\\nserviceOpenAsMovie\\n\\t\\\"Answer a service for opening a file as a movie\\\"\\n\\n\\t^ SimpleServiceEntry \\n\\t\\tprovider: self \\n\\t\\tlabel: 'open as movie'\\n\\t\\tselector: #openAsMovie:\\n\\t\\tdescription: 'open file as movie'\\n\\t\\tbuttonLabel: 'open'! !\\n\\n!MoviePlayerMorph class methodsFor: 'fileIn/Out' stamp: 'sw 9/7/2004 18:21'!\\nservices\\n\\t\\\"Formerly: answer a service for opening as a movie. Nowadays... no services\\\"\\n\\n\\t^ #().\\n\\\"\\n\\t^ Array with: self serviceOpenAsMovie\\\"\\n\\n\\t! !\\n\\n\\n!MoviePlayerMorph class methodsFor: 'initialize-release' stamp: 'SD 11/15/2001 22:22'!\\nunload\\n\\n\\tFileList unregisterFileReader: self ! !\\nEllipseMorph subclass: #MovingEyeMorph\\n\\tinstanceVariableNames: 'inner iris'\\n\\tclassVariableNames: 'IrisSize'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Demo'!\\n\\n!MovingEyeMorph methodsFor: 'as yet unclassified' stamp: 'yo 2/15/2001 15:24'!\\nirisPos: cp\\n\\n\\t| a b theta x y |\\n\\ttheta _ (cp - self center) theta.\\n\\ta _ inner width // 2.\\n\\tb _ inner height // 2.\\n\\tx _ a * (theta cos).\\n\\ty _ b * (theta sin).\\n\\tiris position: ((x@y) asIntegerPoint) + self center - (iris extent // 2).! !\\n\\n\\n!MovingEyeMorph methodsFor: 'geometry' stamp: 'yo 2/15/2001 15:59'!\\nextent: aPoint\\n\\n\\tsuper extent: aPoint.\\n\\tinner extent: (self extent * ((1.0@1.0)-IrisSize)) asIntegerPoint.\\n\\tiris extent: (self extent * IrisSize) asIntegerPoint.\\n\\tinner position: (self center - (inner extent // 2)) asIntegerPoint.\\n! !\\n\\n\\n!MovingEyeMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:42'!\\ndefaultColor\\n\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color black! !\\n\\n!MovingEyeMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:42'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\tinner _ EllipseMorph new.\\n\\tinner color: self color.\\n\\tinner extent: (self extent * (1.0 @ 1.0 - IrisSize)) asIntegerPoint.\\n\\tinner borderColor: self color.\\n\\tinner borderWidth: 0.\\n\\\"\\\"\\n\\tiris _ EllipseMorph new.\\n\\tiris color: Color white.\\n\\tiris extent: (self extent * IrisSize) asIntegerPoint.\\n\\\"\\\"\\n\\tself addMorphCentered: inner.\\n\\tinner addMorphCentered: iris.\\n\\\"\\\"\\n\\tself extent: 26 @ 33! !\\n\\n\\n!MovingEyeMorph methodsFor: 'stepping and presenter' stamp: 'di 2/18/2001 00:10'!\\nstep\\n\\t| cp |\\n\\tcp _ self globalPointToLocal: World primaryHand position.\\n\\t(inner containsPoint: cp)\\n\\t\\tifTrue: [iris position: (cp - (iris extent // 2))]\\n\\t\\tifFalse: [self irisPos: cp].\\n\\tself changed \\\"cover up gribblies if embedded in Flash\\\"! !\\n\\n\\n!MovingEyeMorph methodsFor: 'testing' stamp: 'yo 2/15/2001 15:38'!\\nstepTime\\n\\n\\t^ 100.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMovingEyeMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!MovingEyeMorph class methodsFor: 'class initialization' stamp: 'yo 2/15/2001 16:04'!\\ninitialize\\n\\\"\\n\\tMovingEyeMorph initialize\\n\\\"\\n\\tIrisSize _ (0.42@0.50).! !\\n\\n\\n!MovingEyeMorph class methodsFor: 'parts bin' stamp: 'sw 8/2/2001 12:51'!\\ndescriptionForPartsBin\\n\\t^ self partName:\\t'MovingEye'\\n\\t\\tcategories:\\t\\t#('Demo')\\n\\t\\tdocumentation:\\t'An eye which follows the cursor'! !\\nSoundCodec subclass: #MuLawCodec\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'DecodingTable'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n!MuLawCodec commentStamp: '<historical>' prior: 0!\\nI represent a mu-law (u-law) codec. I compress sound data by a factor of 2:1 by encoding the most significant 12 bits of each 16-bit sample as a signed, exponentially encoded byte. The idea is to use more resolution for smaller lower sample values. This encoding was developed for the North American phone system and a variant of it, a-law, is a European phone standard. It is a popular sound encoding on Unix platforms (.au files).\\n!\\n\\n\\n!MuLawCodec methodsFor: 'external access' stamp: 'di 2/8/1999 22:28'!\\nuLawDecodeSample: byte\\n\\t\\\"Decode a 16-bit signed sample from 8 bits using uLaw decoding\\\"\\n\\n\\t^ DecodingTable at: byte + 1! !\\n\\n!MuLawCodec methodsFor: 'external access' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nuLawEncodeSample: sample\\n\\t\\\"Encode a 16-bit signed sample into 8 bits using uLaw encoding\\\"\\n\\n\\t| s |\\n\\ts := sample // 8. \\\"drop 3 least significant bits\\\"\\n\\ts < 0 ifTrue: [^ (self uLawEncode12Bits: 0-s) + 16r80]\\n\\t\\tifFalse: [^ (self uLawEncode12Bits: s)].\\n! !\\n\\n\\n!MuLawCodec methodsFor: 'subclass responsibility' stamp: 'jm 2/2/1999 09:15'!\\nbytesPerEncodedFrame\\n\\t\\\"Answer the number of bytes required to hold one frame of compressed sound data. Answer zero if this codec produces encoded frames of variable size.\\\"\\n\\n\\t^ 1\\n! !\\n\\n!MuLawCodec methodsFor: 'subclass responsibility' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ndecodeFrames: frameCount from: srcByteArray at: srcIndex into: dstSoundBuffer at: dstIndex\\n\\t\\\"Decode the given number of monophonic frames starting at the given index in the given ByteArray of compressed sound data and storing the decoded samples into the given SoundBuffer starting at the given destination index. Answer a pair containing the number of bytes of compressed data consumed and the number of decompressed samples produced.\\\"\\n\\t\\\"Note: Assume that the sender has ensured that the given number of frames will not exhaust either the source or destination buffers.\\\"\\n\\n\\t| dst |\\n\\tdst := dstIndex.\\n\\tsrcIndex to: srcIndex + frameCount - 1 do: [:src |\\n\\t\\tdstSoundBuffer at: dst put: (DecodingTable at: (srcByteArray at: src) + 1).\\n\\t\\tdst := dst + 1].\\n\\t^ Array with: frameCount with: frameCount\\n! !\\n\\n!MuLawCodec methodsFor: 'subclass responsibility' stamp: 'di 2/8/1999 22:25'!\\nencodeFrames: frameCount from: srcSoundBuffer at: srcIndex into: dstByteArray at: dstIndex\\n\\t\\\"Encode the given number of frames starting at the given index in the given monophonic SoundBuffer and storing the encoded sound data into the given ByteArray starting at the given destination index. Encode only as many complete frames as will fit into the destination. Answer a pair containing the number of samples consumed and the number of bytes of compressed data produced.\\\"\\n\\t\\\"Note: Assume that the sender has ensured that the given number of frames will not exhaust either the source or destination buffers.\\\"\\n\\n\\tsrcIndex to: srcIndex + frameCount - 1 do: [:i |\\n\\t\\tdstByteArray at: i put: (self uLawEncodeSample: (srcSoundBuffer at: i))].\\n\\t^ Array with: frameCount with: frameCount\\n! !\\n\\n!MuLawCodec methodsFor: 'subclass responsibility' stamp: 'jm 2/2/1999 09:11'!\\nsamplesPerFrame\\n\\t\\\"Answer the number of sound samples per compression frame.\\\"\\n\\n\\t^ 1\\n! !\\n\\n\\n!MuLawCodec methodsFor: 'private' stamp: 'di 2/9/1999 13:25'!\\nuLawEncode12Bits: s\\n\\t\\\"Encode a 12-bit unsigned sample (0-4095) into 7 bits using uLaw encoding.\\n\\tThis gets called by a method that scales 16-bit signed integers down to a\\n\\t\\t12-bit magnitude, and then ORs in 16r80 if they were negative.\\n\\tDetail: May get called with s >= 4096, and this works fine.\\\"\\n\\n\\ts < 496 ifTrue: [\\n\\t\\ts < 112 ifTrue: [\\n\\t\\t\\ts < 48 ifTrue: [\\n\\t\\t\\t\\ts < 16\\n\\t\\t\\t\\t\\tifTrue: [^ 16r70 bitOr: (15 - s)]\\n\\t\\t\\t\\t\\tifFalse: [^ 16r60 bitOr: (15 - ((s - 16) bitShift: -1))]].\\n\\t\\t\\t^ 16r50 bitOr: (15 - ((s - 48) bitShift: -2))].\\n\\t\\ts < 240\\n\\t\\t\\tifTrue: [^ 16r40 bitOr: (15 - ((s - 112) bitShift: -3))]\\n\\t\\t\\tifFalse: [^ 16r30 bitOr: (15 - ((s - 240) bitShift: -4))]].\\n\\n\\ts < 2032 ifTrue: [\\n\\t\\ts < 1008\\n\\t\\t\\tifTrue: [^ 16r20 bitOr: (15 - ((s - 496) bitShift: -5))]\\n\\t\\t\\tifFalse: [^ 16r10 bitOr: (15 - ((s - 1008) bitShift: -6))]].\\n\\n\\ts < 4080\\n\\t\\tifTrue: [^ 15 - ((s - 2032) bitShift: -7)]\\n\\t\\tifFalse: [^ 0].\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMuLawCodec class\\n\\tinstanceVariableNames: ''!\\n\\n!MuLawCodec class methodsFor: 'class initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitialize\\n\\t\\\"Build the 256 entry table to be used to decode 8-bit uLaw-encoded samples.\\\"\\n\\t\\\"MuLawCodec initialize\\\"\\n\\n\\t| encoded codec lastEncodedPos lastEncodedNeg |\\n\\tDecodingTable := Array new: 256.\\n\\tcodec := self new.\\n\\tlastEncodedPos := nil.\\n\\tlastEncodedNeg := nil.\\n\\t4095 to: 0 by: -1 do: [:s |\\n\\t\\tencoded := codec uLawEncode12Bits: s.\\n\\t\\tlastEncodedPos = encoded\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tDecodingTable at: (encoded + 1) put: (s bitShift: 3).\\n\\t\\t\\t\\tlastEncodedPos := encoded].\\n\\t\\tencoded := encoded bitOr: 16r80.\\n\\t\\tlastEncodedNeg = encoded\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tDecodingTable at: (encoded + 1) put: (s bitShift: 3) negated.\\n\\t\\t\\t\\tlastEncodedNeg := encoded]].\\n! !\\nReadWriteStream subclass: #MultiByteBinaryOrTextStream\\n\\tinstanceVariableNames: 'isBinary converter'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-TextConversion'!\\n!MultiByteBinaryOrTextStream commentStamp: '<historical>' prior: 0!\\nIt is similar to MultiByteFileStream, but works on in memory stream.!\\n\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'accessing' stamp: 'yo 11/11/2002 13:16'!\\nascii\\n\\tisBinary _ false\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'accessing' stamp: 'yo 11/11/2002 13:16'!\\nbinary\\n\\tisBinary _ true\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'accessing' stamp: 'nk 8/2/2004 17:02'!\\nconverter\\n\\n\\tconverter ifNil: [converter _ self class defaultConverter].\\n\\t^ converter\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'accessing' stamp: 'yo 8/7/2003 09:12'!\\nconverter: aConverter\\n\\n\\tconverter _ aConverter.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'accessing' stamp: 'yo 11/11/2002 13:25'!\\nisBinary\\n\\t^ isBinary! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'accessing' stamp: 'yo 11/11/2002 16:33'!\\ntext\\n\\tisBinary _ false\\n! !\\n\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'as yet unclassified' stamp: 'yo 3/1/2005 06:10'!\\nfileInObjectAndCodeForProject\\n\\t\\\"This file may contain:\\n1) a fileIn of code \\n2) just an object in SmartReferenceStream format \\n3) both code and an object.\\n\\tFile it in and return the object. Note that self must be a FileStream or RWBinaryOrTextStream. Maybe ReadWriteStream incorporate RWBinaryOrTextStream?\\\"\\n\\t| refStream object |\\n\\tself text.\\n\\tself peek asciiValue = 4\\n\\t\\tifTrue: [ \\\"pure object file\\\"\\n\\t\\t\\tself binary.\\n\\t\\t\\trefStream _ SmartRefStream on: self.\\n\\t\\t\\tobject _ refStream nextAndClose]\\n\\t\\tifFalse: [ \\\"objects mixed with a fileIn\\\"\\n\\t\\t\\tself fileInProject. \\\"reads code and objects, then closes the file\\\"\\n\\t\\t\\tself binary.\\n\\t\\t\\tobject _ SmartRefStream scannedObject].\\t\\\"set by side effect of one of the chunks\\\"\\n\\tSmartRefStream scannedObject: nil. \\\"clear scannedObject\\\"\\n\\t^ object! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'as yet unclassified' stamp: 'yo 3/1/2005 06:46'!\\nfileInProject\\n\\n\\tself setConverterForCodeForProject.\\n\\tsuper fileIn.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'as yet unclassified' stamp: 'yo 3/1/2005 06:46'!\\nsetConverterForCodeForProject\\n\\n\\tself converter: UTF8TextConverter new.\\n! !\\n\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'converting' stamp: 'yo 11/11/2002 13:16'!\\nasBinaryOrTextStream\\n\\n\\t^ self\\n! !\\n\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'fileIn/Out' stamp: 'yo 8/17/2004 10:02'!\\nfileIn\\n\\n\\tself setConverterForCode.\\n\\tsuper fileIn.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'fileIn/Out' stamp: 'yo 11/11/2002 16:31'!\\nfileInObjectAndCode\\n\\t\\\"This file may contain:\\n1) a fileIn of code \\n2) just an object in SmartReferenceStream format \\n3) both code and an object.\\n\\tFile it in and return the object. Note that self must be a FileStream or RWBinaryOrTextStream. Maybe ReadWriteStream incorporate RWBinaryOrTextStream?\\\"\\n\\t| refStream object |\\n\\tself text.\\n\\tself peek asciiValue = 4\\n\\t\\tifTrue: [ \\\"pure object file\\\"\\n\\t\\t\\tself binary.\\n\\t\\t\\trefStream _ SmartRefStream on: self.\\n\\t\\t\\tobject _ refStream nextAndClose]\\n\\t\\tifFalse: [ \\\"objects mixed with a fileIn\\\"\\n\\t\\t\\tself fileIn. \\\"reads code and objects, then closes the file\\\"\\n\\t\\t\\tself binary.\\n\\t\\t\\tobject _ SmartRefStream scannedObject].\\t\\\"set by side effect of one of the chunks\\\"\\n\\tSmartRefStream scannedObject: nil. \\\"clear scannedObject\\\"\\n\\t^ object! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'fileIn/Out' stamp: 'tak 1/12/2005 13:47'!\\nfileOutClass: extraClass andObject: theObject \\n\\tUTF8TextConverter writeBOMOn: self.\\n\\t^ super fileOutClass: extraClass andObject: theObject! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'fileIn/Out' stamp: 'yo 8/18/2004 09:36'!\\nsetConverterForCode\\n\\n\\t| current |\\n\\tcurrent _ converter saveStateOf: self.\\n\\tself position: 0.\\n\\tself binary.\\n\\t((self next: 3) = (ByteArray with: 16rEF with: 16rBB with: 16rBF)) ifTrue: [\\n\\t\\tself converter: UTF8TextConverter new\\n\\t] ifFalse: [\\n\\t\\tself converter: MacRomanTextConverter new.\\n\\t].\\n\\tconverter restoreStateOf: self with: current.\\n\\tself text.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'fileIn/Out' stamp: 'yo 7/7/2004 09:43'!\\nsetEncoderForSourceCodeNamed: streamName\\n\\n\\t| l |\\n\\tl _ streamName asLowercase.\\n\\\"\\t((l endsWith: FileStream multiCs) or: [\\n\\t\\t(l endsWith: FileStream multiSt) or: [\\n\\t\\t\\t(l endsWith: (FileStream multiSt, '.gz')) or: [\\n\\t\\t\\t\\t(l endsWith: (FileStream multiCs, '.gz'))]]]) ifTrue: [\\n\\t\\t\\t\\t\\tself converter: UTF8TextConverter new.\\n\\t\\t\\t\\t\\t^ self.\\n\\t].\\n\\\"\\n\\t((l endsWith: FileStream cs) or: [\\n\\t\\t(l endsWith: FileStream st) or: [\\n\\t\\t\\t(l endsWith: (FileStream st, '.gz')) or: [\\n\\t\\t\\t\\t(l endsWith: (FileStream cs, '.gz'))]]]) ifTrue: [\\n\\t\\t\\t\\t\\tself converter: MacRomanTextConverter new.\\n\\t\\t\\t\\t\\t^ self.\\n\\t].\\n\\n\\tself converter: UTF8TextConverter new.\\n! !\\n\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'properties-setting' stamp: 'yo 11/14/2002 13:49'!\\nsetFileTypeToObject\\n\\t\\\"do nothing. We don't have a file type\\\"! !\\n\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 7/30/2004 06:59'!\\ncontents\\n\\n\\t| ret state |\\n\\tstate _ converter saveStateOf: self.\\n\\tret _ self upToEnd.\\n\\tconverter restoreStateOf: self with: state.\\n\\t^ ret.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 11/11/2002 16:39'!\\nnext\\n\\n\\t| n |\\n\\tn _ self converter nextFromStream: self.\\n\\tn ifNil: [^ nil].\\n\\tisBinary and: [n isCharacter ifTrue: [^ n asciiValue]].\\n\\t^ n.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'ar 4/12/2005 17:34'!\\nnext: anInteger \\n\\n\\t| multiString |\\n\\t\\\"self halt.\\\"\\n\\tself isBinary ifTrue: [^ (super next: anInteger) asByteArray].\\n\\tmultiString _ WideString new: anInteger.\\n\\t1 to: anInteger do: [:index |\\n\\t\\t| character |\\n\\t\\t(character _ self next) ifNotNil: [\\n\\t\\t\\tmultiString at: index put: character\\n\\t\\t] ifNil: [\\n\\t\\t\\tmultiString _ multiString copyFrom: 1 to: index - 1.\\n\\t\\t\\t^ multiString\\n\\t\\t]\\n\\t].\\n\\t^ multiString.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 12/25/2003 16:05'!\\nnextDelimited: terminator\\n\\n\\t| out ch pos |\\n\\tout _ WriteStream on: (String new: 1000).\\n\\tself atEnd ifTrue: [^ ''].\\n\\tpos _ self position.\\n\\tself next = terminator ifFalse: [\\n\\t\\t\\\"absorb initial terminator\\\"\\n\\t\\tself position: pos.\\n\\t].\\n\\t[(ch _ self next) == nil] whileFalse: [\\n\\t\\t(ch = terminator) ifTrue: [\\n\\t\\t\\tself peek = terminator ifTrue: [\\n\\t\\t\\t\\tself next. \\\"skip doubled terminator\\\"\\n\\t\\t\\t] ifFalse: [\\n\\t\\t\\t\\t^ out contents \\\"terminator is not doubled; we're done!!\\\"\\n\\t\\t\\t].\\n\\t\\t].\\n\\t\\tout nextPut: ch.\\n\\t].\\n\\t^ out contents.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 11/11/2002 13:24'!\\nnextMatchAll: aColl\\n\\n | save |\\n save _ converter saveStateOf: self.\\n aColl do: [:each |\\n (self next) = each ifFalse: [\\n converter restoreStateOf: self with: save.\\n ^ false.\\n\\t\\t].\\n\\t].\\n ^ true.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 11/14/2002 13:54'!\\nnextPut: aCharacter\\n\\n\\taCharacter isInteger ifTrue: [^ super nextPut: aCharacter asCharacter].\\n\\t^ self converter nextPut: aCharacter toStream: self\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 11/11/2002 13:24'!\\nnextPutAll: aCollection\\n\\n\\tself isBinary ifTrue: [\\n\\t\\t^ super nextPutAll: aCollection.\\n\\t].\\n\\taCollection do: [:e | self nextPut: e].\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 11/14/2002 13:54'!\\npadToEndWith: aChar\\n\\t\\\"We don't have pages, so we are at the end, and don't need to pad.\\\"! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 12/25/2003 16:04'!\\npeek\\n\\t\\\"Answer what would be returned if the message next were sent to the receiver. If the receiver is at the end, answer nil. \\\"\\n\\n\\t| next pos |\\n\\tself atEnd ifTrue: [^ nil].\\n\\tpos _ self position.\\n\\tnext _ self next.\\n\\tself position: pos.\\n\\t^ next.\\n\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 11/11/2002 13:25'!\\npeekFor: item \\n\\n\\t| next state |\\n\\t\\\"self atEnd ifTrue: [^ false]. -- SFStream will give nil\\\"\\n\\tstate _ converter saveStateOf: self.\\n\\t(next _ self next) == nil ifTrue: [^ false].\\n\\titem = next ifTrue: [^ true].\\n\\tconverter restoreStateOf: self with: state.\\n\\t^ false.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'nk 7/29/2004 12:02'!\\nreset\\n\\n\\tsuper reset.\\n\\tisBinary ifNil: [isBinary _ false].\\n\\tcollection class == ByteArray ifTrue: [\\\"Store as String and convert as needed.\\\"\\n\\t\\tcollection _ collection asString.\\n\\t\\tisBinary _ true].\\n\\n\\tself converter. \\\"ensure that we have a converter.\\\"! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 11/11/2002 16:17'!\\nskipSeparators\\n\\n\\t[self atEnd] whileFalse: [\\n\\t\\tself basicNext isSeparator ifFalse: [\\n\\t\\t\\t^ self position: self position - 1]]\\n\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 12/25/2003 16:04'!\\nskipSeparatorsAndPeekNext\\n\\n\\t\\\"A special function to make nextChunk fast\\\"\\n\\t| peek pos |\\n\\t[self atEnd] whileFalse: [\\n\\t\\tpos _ self position.\\n\\t\\t(peek _ self next) isSeparator ifFalse: [\\n\\t\\t\\tself position: pos.\\n\\t\\t\\t^ peek.\\n\\t\\t].\\n\\t].\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 11/11/2002 13:24'!\\nupTo: delim \\n\\n\\t| out ch |\\n\\tout _ WriteStream on: (String new: 1000).\\n\\tself atEnd ifTrue: [^ ''].\\n\\t[(ch _ self next) isNil] whileFalse: [\\n\\t\\t(ch = delim) ifTrue: [\\n\\t\\t\\t^ out contents \\\"terminator is not doubled; we're done!!\\\"\\n\\t\\t].\\n\\t\\tout nextPut: ch.\\n\\t].\\n\\t^ out contents.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'public' stamp: 'yo 11/11/2002 16:17'!\\nupToEnd\\n\\n\\t| newStream element newCollection |\\n\\tnewCollection _ self isBinary\\n\\t\\t\\t\\tifTrue: [ByteArray new: 100]\\n\\t\\t\\t\\tifFalse: [String new: 100].\\n\\tnewStream _ WriteStream on: newCollection.\\n\\t[(element _ self next) notNil]\\n\\t\\twhileTrue: [newStream nextPut: element].\\n\\t^ newStream contents\\n! !\\n\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private' stamp: 'nk 8/2/2004 17:01'!\\nguessConverter\\n\\t^ (self originalContents includesSubString: (ByteArray withAll: {27. 36}) asString)\\n\\t\\tifTrue: [CompoundTextConverter new]\\n\\t\\tifFalse: [self class defaultConverter ]! !\\n\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private basic' stamp: 'yo 11/11/2002 16:01'!\\nbasicNext\\n\\n\\t^ super next \\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private basic' stamp: 'md 10/20/2004 15:32'!\\nbasicNext: anInteger\\n\\n\\t^ super next: anInteger.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private basic' stamp: 'yo 11/11/2002 13:21'!\\nbasicNext: n into: aString\\n\\n\\t^ super next: n into: aString.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private basic' stamp: 'yo 11/11/2002 13:21'!\\nbasicNextInto: aString\\n\\n\\t^ super nextInto: aString.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private basic' stamp: 'yo 11/11/2002 13:21'!\\nbasicNextPut: char\\n\\n\\t^ super nextPut: char.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private basic' stamp: 'yo 11/11/2002 13:21'!\\nbasicNextPutAll: aString\\n\\n\\t^ super nextPutAll: aString.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private basic' stamp: 'yo 11/11/2002 13:21'!\\nbasicPeek\\n\\n\\t^ super peek\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private basic' stamp: 'yo 11/11/2002 13:21'!\\nbasicPosition\\n\\n\\t^ super position.\\n! !\\n\\n!MultiByteBinaryOrTextStream methodsFor: 'private basic' stamp: 'yo 11/11/2002 13:21'!\\nbasicPosition: pos\\n\\n\\t^ super position: pos.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMultiByteBinaryOrTextStream class\\n\\tinstanceVariableNames: ''!\\n\\n!MultiByteBinaryOrTextStream class methodsFor: 'defaults' stamp: 'yo 2/25/2005 20:04'!\\ndefaultConverter\\n\\t^ Latin1TextConverter new.\\n! !\\n\\n\\n!MultiByteBinaryOrTextStream class methodsFor: 'instance creation' stamp: 'ykoubo 9/28/2003 19:59'!\\non: aCollection encoding: encodingName \\n\\t| aTextConverter |\\n\\tencodingName isNil\\n\\t\\tifTrue: [aTextConverter _ TextConverter default]\\n\\t\\tifFalse: [aTextConverter _ TextConverter newForEncoding: encodingName].\\n\\t^ (self on: aCollection)\\n\\t\\tconverter: aTextConverter! !\\n\\n!MultiByteBinaryOrTextStream class methodsFor: 'instance creation' stamp: 'yo 11/23/2003 20:32'!\\nwith: aCollection encoding: encodingName \\n\\t| aTextConverter |\\n\\tencodingName isNil\\n\\t\\tifTrue: [aTextConverter _ TextConverter default]\\n\\t\\tifFalse: [aTextConverter _ TextConverter newForEncoding: encodingName].\\n\\t^ (self with: aCollection)\\n\\t\\tconverter: aTextConverter! !\\nStandardFileStream subclass: #MultiByteFileStream\\n\\tinstanceVariableNames: 'converter lineEndConvention wantsLineEndConversion'\\n\\tclassVariableNames: 'Cr CrLf Lf LineEndDefault LineEndStrings LookAheadCount'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-TextConversion'!\\n!MultiByteFileStream commentStamp: '<historical>' prior: 0!\\nThe central class to access the external file. The interface of this object is similar to good old StandardFileStream, but internally it asks the converter, which is a sub-instance of TextConverter, and do the text conversion.\\n\\n It also combined the good old CrLfFileStream. CrLfFileStream class>>new now returns an instance of MultiByteFileStream.\\n\\n There are several pitfalls:\\n\\n * You always have to be careful about the binary/text distinction. In #text mode, it usually interpret the bytes.\\n * A few file pointer operations treat the file as uninterpreted byte no matter what. This means that if you use 'fileStream skip: -1', 'fileStream position: x', etc. in #text mode, the file position can be in the middle of multi byte character. If you want to implement some function similar to #peek for example, call the saveStateOf: and restoreStateOf: methods to be able to get back to the original state.\\n * #lineEndConvention: and #wantsLineEndConversion: (and #binary) can cause some puzzling situation because the inst var lineEndConvention and wantsLineEndConversion are mutated. If you have any suggestions to clean up the protocol, please let me know.!\\n\\n\\n!MultiByteFileStream methodsFor: 'accessing' stamp: 'yo 2/21/2004 02:57'!\\nascii\\n\\n\\tsuper ascii.\\n\\tself detectLineEndConvention.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'accessing' stamp: 'yo 2/21/2004 02:57'!\\nbinary\\n\\n\\tsuper binary.\\n\\tlineEndConvention _ nil.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'accessing' stamp: 'yo 8/18/2003 15:11'!\\nconverter\\n\\n\\tconverter ifNil: [converter _ TextConverter defaultSystemConverter].\\n\\t^ converter\\n! !\\n\\n!MultiByteFileStream methodsFor: 'accessing' stamp: 'yo 8/28/2002 11:09'!\\nconverter: aConverter\\n\\n\\tconverter _ aConverter.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'accessing' stamp: 'yo 8/6/2003 11:56'!\\nfileInEncodingName: aString\\n\\n\\tself converter: (TextConverter newForEncoding: aString).\\n\\tsuper fileIn.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'accessing' stamp: 'nk 9/5/2004 12:57'!\\nlineEndConvention\\n\\n\\t^lineEndConvention! !\\n\\n!MultiByteFileStream methodsFor: 'accessing' stamp: 'yo 2/21/2004 02:59'!\\nlineEndConvention: aSymbol\\n\\n\\tlineEndConvention _ aSymbol.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'accessing' stamp: 'yo 2/21/2004 04:24'!\\nwantsLineEndConversion: aBoolean\\n\\n\\twantsLineEndConversion _ aBoolean.\\n\\tself detectLineEndConvention.! !\\n\\n\\n!MultiByteFileStream methodsFor: 'crlf private' stamp: 'yo 2/24/2004 13:38'!\\nbareNext\\n\\n\\t ^ self converter nextFromStream: self.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'crlf private' stamp: 'yo 2/21/2004 02:56'!\\nconvertStringFromCr: aString \\n\\t| inStream outStream |\\n\\tlineEndConvention ifNil: [^ aString].\\n\\tlineEndConvention == #cr ifTrue: [^ aString].\\n\\tlineEndConvention == #lf ifTrue: [^ aString copy replaceAll: Cr with: Lf].\\n\\t\\\"lineEndConvention == #crlf\\\"\\n\\tinStream _ ReadStream on: aString.\\n\\toutStream _ WriteStream on: (String new: aString size).\\n\\t[inStream atEnd]\\n\\t\\twhileFalse: \\n\\t\\t\\t[outStream nextPutAll: (inStream upTo: Cr).\\n\\t\\t\\t(inStream atEnd not or: [aString last = Cr])\\n\\t\\t\\t\\tifTrue: [outStream nextPutAll: CrLf]].\\n\\t^ outStream contents! !\\n\\n!MultiByteFileStream methodsFor: 'crlf private' stamp: 'yo 2/21/2004 02:56'!\\nconvertStringToCr: aString \\n\\t| inStream outStream |\\n\\tlineEndConvention ifNil: [^ aString].\\n\\tlineEndConvention == #cr ifTrue: [^ aString].\\n\\tlineEndConvention == #lf ifTrue: [^ aString copy replaceAll: Lf with: Cr].\\n\\t\\\"lineEndConvention == #crlf\\\"\\n\\tinStream _ ReadStream on: aString.\\n\\toutStream _ WriteStream on: (String new: aString size).\\n\\t[inStream atEnd]\\n\\t\\twhileFalse: \\n\\t\\t\\t[outStream nextPutAll: (inStream upTo: Cr).\\n\\t\\t\\t(inStream atEnd not or: [aString last = Cr])\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[outStream nextPut: Cr.\\n\\t\\t\\t\\t\\tinStream peek = Lf ifTrue: [inStream next]]].\\n\\t^ outStream contents! !\\n\\n!MultiByteFileStream methodsFor: 'crlf private' stamp: 'nk 9/5/2004 12:50'!\\ndetectLineEndConvention\\n\\t\\\"Detect the line end convention used in this stream. The result may be either #cr, #lf or #crlf.\\\"\\n\\t| char numRead state |\\n\\tself isBinary ifTrue: [^ self error: 'Line end conventions are not used on binary streams'].\\n\\tself wantsLineEndConversion ifFalse: [^ lineEndConvention _ nil.].\\n\\tself closed ifTrue: [^ lineEndConvention _ LineEndDefault.].\\n\\n\\t\\\"Default if nothing else found\\\"\\n\\tnumRead _ 0.\\n\\tstate _ converter saveStateOf: self.\\n\\tlineEndConvention _ nil.\\n\\t[super atEnd not and: [numRead < LookAheadCount]]\\n\\t\\twhileTrue: \\n\\t\\t\\t[char _ self next.\\n\\t\\t\\tchar = Lf\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[converter restoreStateOf: self with: state.\\n\\t\\t\\t\\t\\t^ lineEndConvention _ #lf].\\n\\t\\t\\tchar = Cr\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[self peek = Lf\\n\\t\\t\\t\\t\\t\\tifTrue: [lineEndConvention _ #crlf]\\n\\t\\t\\t\\t\\t\\tifFalse: [lineEndConvention _ #cr].\\n\\t\\t\\t\\t\\tconverter restoreStateOf: self with: state.\\n\\t\\t\\t\\t\\t^ lineEndConvention].\\n\\t\\t\\tnumRead _ numRead + 1].\\n\\tconverter restoreStateOf: self with: state.\\n\\t^ lineEndConvention _ LineEndDefault.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'crlf private' stamp: 'nk 9/5/2004 12:51'!\\ndoConversion\\n\\n\\t^self wantsLineEndConversion and: [ lineEndConvention notNil ]! !\\n\\n!MultiByteFileStream methodsFor: 'crlf private' stamp: 'yo 2/24/2004 13:44'!\\nnext: n innerFor: aString\\n\\n\\t| peekChar state |\\n\\t\\\"if we just read a CR, and the next character is an LF, then skip the LF\\\"\\n\\taString size = 0 ifTrue: [^ aString].\\n\\t(aString last = Character cr) ifTrue: [\\n\\t\\tstate _ converter saveStateOf: self.\\n\\t\\tpeekChar _ self bareNext.\\t\\t\\\"super peek doesn't work because it relies on #next\\\"\\n\\t\\t(peekChar notNil and: [peekChar ~= Character lf]) ifTrue: [\\n\\t\\t\\tconverter restoreStateOf: self with: state.\\n\\t\\t].\\n\\t].\\n \\n\\t^ aString withSqueakLineEndings.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'crlf private' stamp: 'yo 2/21/2004 03:51'!\\nwantsLineEndConversion\\n\\n\\t^ wantsLineEndConversion ifNil: [false].\\n! !\\n\\n\\n!MultiByteFileStream methodsFor: 'fileIn/Out' stamp: 'yo 8/17/2004 10:03'!\\nfileIn\\n\\n\\tself setConverterForCode.\\n\\tsuper fileIn.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'fileIn/Out' stamp: 'ar 7/29/2005 22:33'!\\nfileInObjectAndCodeForProject\\n\\t\\\"This file may contain:\\n1) a fileIn of code \\n2) just an object in SmartReferenceStream format \\n3) both code and an object.\\n\\tFile it in and return the object. Note that self must be a FileStream or RWBinaryOrTextStream. Maybe ReadWriteStream incorporate RWBinaryOrTextStream?\\\"\\n\\t| refStream object |\\n\\tself text.\\n\\tself peek asciiValue = 4\\n\\t\\tifTrue: [ \\\"pure object file\\\"\\n\\t\\t\\tself binary.\\n\\t\\t\\trefStream _ SmartRefStream on: self.\\n\\t\\t\\tobject _ refStream nextAndClose]\\n\\t\\tifFalse: [ \\\"objects mixed with a fileIn\\\"\\n\\t\\t\\tself fileInProject. \\\"reads code and objects, then closes the file\\\"\\n\\t\\t\\tself binary.\\n\\t\\t\\tobject _ SmartRefStream scannedObject].\\t\\\"set by side effect of one of the chunks\\\"\\n\\tSmartRefStream scannedObject: nil. \\\"clear scannedObject\\\"\\n\\t^ object! !\\n\\n!MultiByteFileStream methodsFor: 'fileIn/Out' stamp: 'ar 7/29/2005 22:33'!\\nfileInProject\\n\\n\\tself setConverterForCodeForProject.\\n\\tsuper fileIn.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'fileIn/Out' stamp: 'tak 1/12/2005 14:48'!\\nfileOutClass: extraClass andObject: theObject \\n\\tself binary.\\n\\tUTF8TextConverter writeBOMOn: self.\\n\\tself text.\\n\\t^ super fileOutClass: extraClass andObject: theObject! !\\n\\n\\n!MultiByteFileStream methodsFor: 'open/close' stamp: 'md 7/20/2006 11:05'!\\nopen: fileName forWrite: writeMode \\n\\t| result |\\n\\tresult := super open: fileName forWrite: writeMode.\\n\\tresult ifNotNil: [\\n\\t\\t\\tconverter ifNil: [converter := UTF8TextConverter new].\\n\\t\\t\\tself detectLineEndConvention].\\n\\t^result! !\\n\\n!MultiByteFileStream methodsFor: 'open/close' stamp: 'yo 8/13/2003 13:51'!\\nreset\\n\\n\\tsuper reset.\\n\\tconverter ifNil: [\\n\\t\\tconverter _ UTF8TextConverter new.\\n\\t].\\n! !\\n\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 2/24/2004 13:49'!\\nnext\\n\\n\\t| char secondChar state |\\n\\tchar _ self converter nextFromStream: self.\\n\\tself doConversion ifTrue: [\\n\\t\\tchar == Cr ifTrue: [\\n\\t\\t\\tstate _ converter saveStateOf: self.\\n\\t\\t\\tsecondChar _ self bareNext.\\n\\t\\t\\tsecondChar ifNotNil: [secondChar == Lf ifFalse: [converter restoreStateOf: self with: state]].\\n\\t\\t^Cr].\\n\\t\\tchar == Lf ifTrue: [^Cr].\\n\\t].\\n\\t^ char.\\n\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 7/31/2004 18:03'!\\nnext: anInteger \\n\\n\\t| multiString |\\n\\tself isBinary ifTrue: [^ super next: anInteger].\\n\\tmultiString _ String new: anInteger.\\n\\t1 to: anInteger do: [:index |\\n\\t\\t| character |\\n\\t\\t(character _ self next) ifNotNil: [\\n\\t\\t\\tmultiString at: index put: character\\n\\t\\t] ifNil: [\\n\\t\\t\\tmultiString _ multiString copyFrom: 1 to: index - 1.\\n\\t\\t\\tself doConversion ifFalse: [\\n\\t\\t\\t\\t^ multiString\\n\\t\\t\\t].\\n\\t\\t\\t^ self next: anInteger innerFor: multiString.\\n\\t\\t]\\n\\t].\\n\\tself doConversion ifFalse: [\\n\\t\\t^ multiString\\n\\t].\\n\\n\\tmultiString _ self next: anInteger innerFor: multiString.\\n\\t(multiString size = anInteger or: [self atEnd]) ifTrue: [ ^ multiString].\\n\\t^ multiString, (self next: anInteger - multiString size).\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 2/21/2004 03:26'!\\nnextDelimited: terminator\\n\\n\\t| out ch save |\\n\\tout _ WriteStream on: (String new: 1000).\\n\\tself atEnd ifTrue: [^ ''].\\n\\tsave _ converter saveStateOf: self.\\n\\n\\tself next = terminator ifFalse: [\\n\\t\\t\\\"absorb initial terminator\\\"\\n\\t\\tconverter restoreStateOf: self with: save.\\n\\t].\\n\\t[(ch _ self next) == nil] whileFalse: [\\n\\t\\t(ch = terminator) ifTrue: [\\n\\t\\t\\tself peek = terminator ifTrue: [\\n\\t\\t\\t\\tself next. \\\"skip doubled terminator\\\"\\n\\t\\t\\t] ifFalse: [\\n\\t\\t\\t\\t^ out contents \\\"terminator is not doubled; we're done!!\\\"\\n\\t\\t\\t].\\n\\t\\t].\\n\\t\\tout nextPut: ch.\\n\\t].\\n\\t^ out contents.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 8/28/2002 11:13'!\\nnextMatchAll: aColl\\n\\n | save |\\n save _ converter saveStateOf: self.\\n aColl do: [:each |\\n (self next) = each ifFalse: [\\n converter restoreStateOf: self with: save.\\n ^ false.\\n\\t\\t].\\n\\t].\\n ^ true.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 2/21/2004 03:42'!\\nnextPut: aCharacter\\n\\n\\taCharacter isInteger ifTrue: [^ super nextPut: aCharacter].\\n\\tself doConversion ifTrue: [\\n\\t\\taCharacter = Cr ifTrue: [\\n\\t\\t\\t(LineEndStrings at: lineEndConvention) do: [:e | converter nextPut: e toStream: self].\\n\\t\\t] ifFalse: [\\n\\t\\t\\tconverter nextPut: aCharacter toStream: self\\n\\t\\t].\\n\\t\\t^ aCharacter\\n\\t].\\n\\t^ self converter nextPut: aCharacter toStream: self\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 5/23/2003 09:40'!\\nnextPutAll: aCollection\\n\\n\\t(self isBinary or: [aCollection class == ByteArray]) ifTrue: [\\n\\t\\t^ super nextPutAll: aCollection.\\n\\t].\\n\\taCollection do: [:e | self nextPut: e].\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 2/21/2004 04:00'!\\npeek\\n\\t\\\"Answer what would be returned if the message next were sent to the receiver. If the receiver is at the end, answer nil. \\\"\\n\\n\\t| next save |\\n\\tself atEnd ifTrue: [^ nil].\\n\\tsave _ converter saveStateOf: self.\\n\\tnext _ self next.\\n\\tconverter restoreStateOf: self with: save.\\n\\t^ next.\\n\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 8/28/2002 11:15'!\\npeekFor: item \\n\\n\\t| next state |\\n\\t\\\"self atEnd ifTrue: [^ false]. -- SFStream will give nil\\\"\\n\\tstate _ converter saveStateOf: self.\\n\\t(next _ self next) == nil ifTrue: [^ false].\\n\\titem = next ifTrue: [^ true].\\n\\tconverter restoreStateOf: self with: state.\\n\\t^ false.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 2/24/2004 13:35'!\\nskipSeparators\\n\\n\\t| state |\\n\\t[self atEnd] whileFalse: [\\n\\t\\tstate _ converter saveStateOf: self.\\n\\t\\tself next isSeparator ifFalse: [\\n\\t\\t\\t^ converter restoreStateOf: self with: state]]\\n\\n\\n\\\"\\t[self atEnd] whileFalse: [\\n\\t\\tself next isSeparator ifFalse: [\\n\\t\\t\\t^ self position: self position - converter currentCharSize.\\n\\t\\t].\\n\\t].\\n\\\"\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 2/21/2004 04:01'!\\nskipSeparatorsAndPeekNext\\n\\n\\t\\\"A special function to make nextChunk fast\\\"\\n\\t| peek save |\\n\\t[self atEnd] whileFalse: [\\n\\t\\tsave _ converter saveStateOf: self.\\n\\t\\t(peek _ self next) isSeparator ifFalse: [\\n\\t\\t\\tconverter restoreStateOf: self with: save.\\n\\t\\t\\t^ peek.\\n\\t\\t].\\n\\t].\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 8/28/2002 11:17'!\\nupTo: delim \\n\\n\\t| out ch |\\n\\tout _ WriteStream on: (String new: 1000).\\n\\tself atEnd ifTrue: [^ ''].\\n\\t[(ch _ self next) isNil] whileFalse: [\\n\\t\\t(ch = delim) ifTrue: [\\n\\t\\t\\t^ out contents \\\"terminator is not doubled; we're done!!\\\"\\n\\t\\t].\\n\\t\\tout nextPut: ch.\\n\\t].\\n\\t^ out contents.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'public' stamp: 'yo 8/30/2002 16:39'!\\nupToEnd\\n\\n\\t| newStream element |\\n\\tcollection _ self isBinary\\n\\t\\t\\t\\tifTrue: [ByteArray new: 100]\\n\\t\\t\\t\\tifFalse: [String new: 100].\\n\\tnewStream _ WriteStream on: collection.\\n\\t[(element _ self next) notNil]\\n\\t\\twhileTrue: [newStream nextPut: element].\\n\\t^ newStream contents\\n! !\\n\\n\\n!MultiByteFileStream methodsFor: 'remnant' stamp: 'yo 8/28/2002 11:06'!\\naccepts: aSymbol\\n\\n \\t^ converter accepts: aSymbol.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'remnant' stamp: 'yo 8/28/2002 11:09'!\\nfilterFor: aFileStream\\n\\n\\t| rw |\\n\\tname _ aFileStream name.\\n\\trw _ aFileStream isReadOnly not.\\n\\taFileStream close.\\n\\tself open: name forWrite: rw.\\n\\t^self.\\n! !\\n\\n\\n!MultiByteFileStream methodsFor: 'private' stamp: 'mir 8/25/2004 17:27'!\\nsetConverterForCode\\n\\n\\t| current |\\n\\t(SourceFiles at: 2)\\n\\t\\tifNotNil: [self fullName = (SourceFiles at: 2) fullName ifTrue: [^ self]].\\n\\tcurrent _ self converter saveStateOf: self.\\n\\tself position: 0.\\n\\tself binary.\\n\\t((self next: 3) = (ByteArray with: 16rEF with: 16rBB with: 16rBF)) ifTrue: [\\n\\t\\tself converter: UTF8TextConverter new\\n\\t] ifFalse: [\\n\\t\\tself converter: MacRomanTextConverter new.\\n\\t].\\n\\tconverter restoreStateOf: self with: current.\\n\\tself text.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private' stamp: 'ar 7/29/2005 22:33'!\\nsetConverterForCodeForProject\\n\\n\\tself converter: UTF8TextConverter new.\\n! !\\n\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'md 10/17/2004 16:09'!\\nbasicNext: anInteger\\n\\n\\t^ super next: anInteger.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:07'!\\nbasicNext: n into: aString\\n\\n\\t^ super next: n into: aString.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:07'!\\nbasicNextInto: aString\\n\\n\\t^ super nextInto: aString.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:07'!\\nbasicNextPut: char\\n\\n\\t^ super nextPut: char.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:07'!\\nbasicNextPutAll: aString\\n\\n\\t^ super nextPutAll: aString.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:07'!\\nbasicPeek\\n\\n\\t^ super peek\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:08'!\\nbasicPosition\\n\\n\\t^ super position.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:08'!\\nbasicPosition: pos\\n\\n\\t^ super position: pos.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:08'!\\nbasicReadInto: byteArray startingAt: startIndex count: count\\n\\n\\t^ super readInto: byteArray startingAt: startIndex count: count.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:08'!\\nbasicSetToEnd\\n\\n\\t^ super setToEnd.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:08'!\\nbasicSkip: n\\n\\n\\t^ super skip: n.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:08'!\\nbasicUpTo: delim\\n\\n\\t^ super upTo: delim.\\n! !\\n\\n!MultiByteFileStream methodsFor: 'private basic' stamp: 'yo 8/28/2002 11:09'!\\nbasicVerbatim: aString\\n\\n\\t^ super verbatim: aString.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMultiByteFileStream class\\n\\tinstanceVariableNames: ''!\\n\\n!MultiByteFileStream class methodsFor: 'class initialization' stamp: 'yo 2/21/2004 02:45'!\\ndefaultToCR\\n\\n\\t\\\"MultiByteFileStream defaultToCR\\\"\\n\\tLineEndDefault := #cr.\\n! !\\n\\n!MultiByteFileStream class methodsFor: 'class initialization' stamp: 'yo 2/21/2004 02:45'!\\ndefaultToCRLF\\n\\n\\t\\\"MultiByteFileStream defaultToCRLF\\\"\\n\\tLineEndDefault := #crlf.! !\\n\\n!MultiByteFileStream class methodsFor: 'class initialization' stamp: 'yo 2/21/2004 02:46'!\\ndefaultToLF\\n\\n\\t\\\"MultiByteFileStream defaultToLF\\\"\\n\\tLineEndDefault := #lf.\\n! !\\n\\n!MultiByteFileStream class methodsFor: 'class initialization' stamp: 'yo 2/21/2004 02:44'!\\nguessDefaultLineEndConvention\\n\\n\\t\\\"Lets try to guess the line end convention from what we know about the path name delimiter from FileDirectory.\\\"\\n\\tFileDirectory pathNameDelimiter = $: ifTrue:[^self defaultToCR].\\n\\tFileDirectory pathNameDelimiter = $/ ifTrue:[^self defaultToLF].\\n\\tFileDirectory pathNameDelimiter = $\\\\ ifTrue:[^self defaultToCRLF].\\n\\t\\\"in case we don't know\\\"\\n\\t^self defaultToCR.\\n! !\\n\\n!MultiByteFileStream class methodsFor: 'class initialization' stamp: 'yo 2/21/2004 02:44'!\\ninitialize\\n\\n\\t\\\"MultiByteFileStream initialize\\\"\\n\\tCr := Character cr.\\n\\tLf := Character lf.\\n\\tCrLf := String with: Cr with: Lf.\\n\\tLineEndStrings := Dictionary new.\\n\\tLineEndStrings at: #cr put: (String with: Character cr).\\n\\tLineEndStrings at: #lf put: (String with: Character lf).\\n\\tLineEndStrings at: #crlf put: (String with: Character cr with: Character lf).\\n\\tLookAheadCount := 2048.\\n\\tSmalltalk addToStartUpList: self.\\n\\tself startUp.\\n! !\\n\\n!MultiByteFileStream class methodsFor: 'class initialization' stamp: 'yo 2/21/2004 02:44'!\\nstartUp\\n\\n\\tself guessDefaultLineEndConvention.\\n! !\\n\\n\\n!MultiByteFileStream class methodsFor: 'instance creation' stamp: 'yo 8/28/2002 11:43'!\\nnewFrom: aFileStream\\n\\n\\t| rw n |\\n\\tn _ aFileStream name.\\n\\trw _ aFileStream isReadOnly not.\\n\\taFileStream close.\\n\\t^self new open: n forWrite: rw.\\n! !\\nPluggableCanvas subclass: #MultiCanvas\\n\\tinstanceVariableNames: 'canvases extent depth'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Support'!\\n!MultiCanvas commentStamp: '<historical>' prior: 0!\\nA canvas which forwards drawing commands to sub-canvases.!\\n\\n\\n!MultiCanvas methodsFor: 'accessing' stamp: 'ls 3/20/2000 20:48'!\\naddCanvas: aCanvas\\n\\tcanvases add: aCanvas! !\\n\\n!MultiCanvas methodsFor: 'accessing' stamp: 'RAA 11/7/2000 17:46'!\\nclipRect\\n\\t\\n\\t^super clipRect ifNil: [\\n\\t\\t0@0 extent: 5000@5000\\n\\t].! !\\n\\n!MultiCanvas methodsFor: 'accessing' stamp: 'RAA 8/14/2000 10:27'!\\ncontentsOfArea: aRectangle into: aForm\\n\\n\\tself apply: [ :c |\\n\\t\\t(c isKindOf: FormCanvas) ifTrue: [\\n\\t\\t\\tc contentsOfArea: aRectangle into: aForm.\\n\\t\\t\\t^aForm\\n\\t\\t].\\n\\t].\\n\\tself apply: [ :c |\\n\\t\\tc contentsOfArea: aRectangle into: aForm.\\n\\t\\t^aForm.\\n\\t].\\n\\t^aForm! !\\n\\n!MultiCanvas methodsFor: 'accessing' stamp: 'ls 4/8/2000 22:35'!\\ndepth\\n\\t^depth! !\\n\\n!MultiCanvas methodsFor: 'accessing' stamp: 'ls 4/8/2000 22:35'!\\nextent\\n\\t^extent! !\\n\\n!MultiCanvas methodsFor: 'accessing' stamp: 'ls 3/20/2000 20:48'!\\nremoveCanvas: aCanvas\\n\\tcanvases remove: aCanvas ifAbsent: []! !\\n\\n\\n!MultiCanvas methodsFor: 'initialization' stamp: 'RAA 8/1/2000 13:50'!\\nallocateForm: extentPoint\\n\\t\\\"Allocate a new form which is similar to the receiver and can be used for accelerated blts\\\"\\n\\t^Form extent: extentPoint depth: self depth! !\\n\\n!MultiCanvas methodsFor: 'initialization' stamp: 'ls 4/8/2000 22:35'!\\ndepth: newDepth\\n\\t\\\"set the extent to be used with this canvas\\\"\\n\\tdepth := newDepth.! !\\n\\n!MultiCanvas methodsFor: 'initialization' stamp: 'ls 4/8/2000 22:34'!\\nextent: newExtent\\n\\t\\\"set the extent to be used with this canvas\\\"\\n\\textent := newExtent.! !\\n\\n!MultiCanvas methodsFor: 'initialization' stamp: 'ls 4/8/2000 22:34'!\\ninitialize\\n\\tcanvases := Set new.\\n\\textent := 600@400.\\n\\tdepth := 32. ! !\\n\\n\\n!MultiCanvas methodsFor: 'private' stamp: 'RAA 11/6/2000 14:17'!\\napply: aCommand\\n\\n\\tself flag: #roundedRudeness.\\t\\n\\t\\\"This rudeness is to help get rounded corners to work right on RemoteCanvases. Since the RemoteCanvas has no other way to read its bits, we are grabbing them from Display for now. To support this, we need to see that the Display is written before any RemoteCanvases\\\"\\n\\n\\tcanvases do: [ :canvas | \\n\\t\\t(canvas isKindOf: FormCanvas) ifTrue: [aCommand value: canvas]\\n\\t].\\n\\tcanvases do: [ :canvas | \\n\\t\\t(canvas isKindOf: FormCanvas) ifFalse: [aCommand value: canvas]\\n\\t].\\n! !\\nMultiCharacterScanner subclass: #MultiCanvasCharacterScanner\\n\\tinstanceVariableNames: 'canvas fillBlt foregroundColor runX lineY'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-Scanning'!\\n\\n!MultiCanvasCharacterScanner methodsFor: 'accessing' stamp: 'yo 12/18/2002 13:55'!\\ncanvas: aCanvas\\n\\t\\\"set the canvas to draw on\\\"\\n\\tcanvas ifNotNil: [ self inform: 'initializing twice!!' ].\\n\\tcanvas _ aCanvas! !\\n\\n\\n!MultiCanvasCharacterScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:55'!\\ndisplayLine: textLine offset: offset leftInRun: leftInRun\\n\\t| nowLeftInRun done startLoc startIndex stopCondition |\\n\\t\\\"largely copied from DisplayScanner's routine\\\"\\n\\n\\tline _ textLine.\\n\\tforegroundColor ifNil: [ foregroundColor _ Color black ].\\n\\tleftMargin _ (line leftMarginForAlignment: alignment) + offset x.\\n\\n\\trightMargin _ line rightMargin + offset x.\\n\\tlineY _ line top + offset y.\\n\\tlastIndex _ textLine first.\\n\\tleftInRun <= 0\\n\\t\\tifTrue: [self setStopConditions. \\\"also sets the font\\\"\\n\\t\\t\\t\\tnowLeftInRun _ text runLengthFor: lastIndex]\\n\\t\\tifFalse: [nowLeftInRun _ leftInRun].\\n\\trunX _ destX _ leftMargin.\\n\\n\\trunStopIndex _ lastIndex + (nowLeftInRun - 1) min: line last.\\n\\tspaceCount _ 0.\\n\\tdone _ false.\\n\\n\\t[done] whileFalse: [\\n\\t\\t\\\"remember where this portion of the line starts\\\"\\n\\t\\tstartLoc _ destX@destY.\\n\\t\\tstartIndex _ lastIndex.\\n\\n\\t\\t\\\"find the end of this portion of the line\\\"\\n\\t\\tstopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex\\n\\t\\t\\t\\t\\t\\tin: text string rightX: rightMargin stopConditions: stopConditions\\n\\t\\t\\t\\t\\t\\tkern: kern \\\"displaying: false\\\".\\n\\n\\t\\t\\\"display that portion of the line\\\"\\n\\t\\tcanvas drawString: text string\\n\\t\\t\\tfrom: startIndex to: lastIndex\\n\\t\\t\\tat: startLoc\\n\\t\\t\\tfont: font\\n\\t\\t\\tcolor: foregroundColor.\\n\\n\\t\\t\\\"handle the stop condition\\\"\\n\\t\\tdone _ self perform: stopCondition\\n\\t].\\n\\n\\t^runStopIndex - lastIndex! !\\n\\n\\n!MultiCanvasCharacterScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:55'!\\ncr\\n\\t\\\"When a carriage return is encountered, simply increment the pointer \\n\\tinto the paragraph.\\\"\\n\\n\\tlastIndex_ lastIndex + 1.\\n\\t^false! !\\n\\n!MultiCanvasCharacterScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:55'!\\ncrossedX\\n\\t\\\"This condition will sometimes be reached 'legally' during display, when, \\n\\tfor instance the space that caused the line to wrap actually extends over \\n\\tthe right boundary. This character is allowed to display, even though it \\n\\tis technically outside or straddling the clipping ectangle since it is in \\n\\tthe normal case not visible and is in any case appropriately clipped by \\n\\tthe scanner.\\\"\\n\\n\\t\\\"self fillLeading.\\\"\\n\\t^ true ! !\\n\\n!MultiCanvasCharacterScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:55'!\\nendOfRun\\n\\t\\\"The end of a run in the display case either means that there is actually \\n\\ta change in the style (run code) to be associated with the string or the \\n\\tend of this line has been reached.\\\"\\n\\t| runLength |\\n\\n\\tlastIndex = line last ifTrue: [^true].\\n\\trunX _ destX.\\n\\trunLength _ text runLengthFor: (lastIndex _ lastIndex + 1).\\n\\trunStopIndex _ lastIndex + (runLength - 1) min: line last.\\n\\tself setStopConditions.\\n\\t^ false! !\\n\\n!MultiCanvasCharacterScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:55'!\\npaddedSpace\\n\\t\\\"Each space is a stop condition when the alignment is right justified. \\n\\tPadding must be added to the base width of the space according to \\n\\twhich space in the line this space is and according to the amount of \\n\\tspace that remained at the end of the line when it was composed.\\\"\\n\\n\\tdestX _ destX + spaceWidth + (line justifiedPadFor: spaceCount).\\n\\n\\tlastIndex _ lastIndex + 1.\\n\\t^ false! !\\n\\n!MultiCanvasCharacterScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:55'!\\nsetStopConditions\\n\\t\\\"Set the font and the stop conditions for the current run.\\\"\\n\\t\\n\\tself setFont.\\n\\tself setConditionArray: (textStyle alignment = Justified ifTrue: [#paddedSpace]).\\n! !\\n\\n!MultiCanvasCharacterScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:55'!\\ntab\\n\\n\\tdestX _ (alignment == Justified and: [self leadingTab not])\\n\\t\\tifTrue:\\t\\t\\\"imbedded tabs in justified text are weird\\\"\\n\\t\\t\\t[destX + (textStyle tabWidth - (line justifiedTabDeltaFor: spaceCount)) max: destX]\\n\\t\\tifFalse: \\n\\t\\t\\t[textStyle nextTabXFrom: destX\\n\\t\\t\\t\\tleftMargin: leftMargin\\n\\t\\t\\t\\trightMargin: rightMargin].\\n\\n\\tlastIndex _ lastIndex + 1.\\n\\t^ false! !\\n\\n\\n!MultiCanvasCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:55'!\\ndoesDisplaying\\n\\t^false \\\"it doesn't do displaying using copyBits\\\"! !\\n\\n!MultiCanvasCharacterScanner methodsFor: 'private' stamp: 'yo 1/6/2005 23:00'!\\nsetFont\\n\\tforegroundColor ifNil: [foregroundColor _ Color black].\\n\\tsuper setFont.\\n\\tbaselineY _ lineY + line baseline.\\n\\tdestY _ baselineY - font ascent.! !\\n\\n!MultiCanvasCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:55'!\\ntextColor: color\\n\\tforegroundColor _ color! !\\nMultiCharacterScanner subclass: #MultiCharacterBlockScanner\\n\\tinstanceVariableNames: 'characterPoint characterIndex lastCharacter lastCharacterExtent lastSpaceOrTabExtent nextLeftMargin specialWidth'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-Scanning'!\\n\\n!MultiCharacterBlockScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:56'!\\ncharacterBlockAtPoint: aPoint in: aParagraph\\n\\t\\\"Answer a CharacterBlock for character in aParagraph at point aPoint. It \\n\\tis assumed that aPoint has been transformed into coordinates appropriate \\n\\tto the text's destination form rectangle and the composition rectangle.\\\"\\n\\n\\tself initializeFromParagraph: aParagraph clippedBy: aParagraph clippingRectangle.\\n\\tcharacterPoint _ aPoint.\\n\\t^self buildCharacterBlockIn: aParagraph! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'scanning' stamp: 'nk 11/22/2004 14:36'!\\ncharacterBlockAtPoint: aPoint index: index in: textLine\\n\\t\\\"This method is the Morphic characterBlock finder. It combines\\n\\tMVC's characterBlockAtPoint:, -ForIndex:, and buildCharcterBlock:in:\\\"\\n\\t| runLength lineStop done stopCondition |\\n\\tline := textLine.\\n\\trightMargin := line rightMargin.\\n\\tlastIndex := line first.\\n\\tself setStopConditions.\\t\\t\\\"also sets font\\\"\\n\\tcharacterIndex := index. \\\" == nil means scanning for point\\\"\\n\\tcharacterPoint := aPoint.\\n\\t(characterPoint isNil or: [characterPoint y > line bottom])\\n\\t\\tifTrue: [characterPoint := line bottomRight].\\n\\t(text isEmpty or: [(characterPoint y < line top or: [characterPoint x < line left])\\n\\t\\t\\t\\tor: [characterIndex notNil and: [characterIndex < line first]]])\\n\\t\\tifTrue:\\t[^ (CharacterBlock new stringIndex: line first text: text\\n\\t\\t\\t\\t\\ttopLeft: line leftMargin@line top extent: 0 @ textStyle lineGrid)\\n\\t\\t\\t\\t\\ttextLine: line].\\n\\tdestX := leftMargin := line leftMarginForAlignment: alignment.\\n\\tdestY := line top.\\n\\trunLength := text runLengthFor: line first.\\n\\tcharacterIndex\\n\\t\\tifNotNil:\\t[lineStop := characterIndex \\\"scanning for index\\\"]\\n\\t\\tifNil:\\t[lineStop := line last \\\"scanning for point\\\"].\\n\\trunStopIndex := lastIndex + (runLength - 1) min: lineStop.\\n\\tlastCharacterExtent := 0 @ line lineHeight.\\n\\tspaceCount := 0.\\n\\n\\tdone := false.\\n\\t[done] whileFalse:\\n\\t\\t[stopCondition := self scanCharactersFrom: lastIndex to: runStopIndex\\n\\t\\t\\tin: text string rightX: characterPoint x\\n\\t\\t\\tstopConditions: stopConditions kern: kern.\\n\\t\\t\\\"see setStopConditions for stopping conditions for character block \\toperations.\\\"\\n\\t\\tself lastCharacterExtentSetX: (specialWidth\\n\\t\\t\\tifNil: [font widthOf: (text at: lastIndex)]\\n\\t\\t\\tifNotNil: [specialWidth]).\\n\\t\\t(self perform: stopCondition) ifTrue:\\n\\t\\t\\t[characterIndex\\n\\t\\t\\t\\tifNil: [\\n\\t\\t\\t\\t\\t\\\"Result for characterBlockAtPoint: \\\"\\n\\t\\t\\t\\t\\t(stopCondition ~~ #cr and: [ lastIndex == line last\\n\\t\\t\\t\\t\\t\\tand: [ aPoint x > ((characterPoint x) + (lastCharacterExtent x / 2)) ]])\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [ \\\"Correct for right half of last character in line\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\t^ (CharacterBlock new stringIndex: lastIndex + 1\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\ttext: text\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\ttopLeft: characterPoint + (lastCharacterExtent x @ 0) + (font descentKern @ 0)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\textent: 0 @ lastCharacterExtent y)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\ttextLine: line ].\\n\\t\\t\\t\\t\\t\\t^ (CharacterBlock new stringIndex: lastIndex\\n\\t\\t\\t\\t\\t\\t\\ttext: text topLeft: characterPoint + (font descentKern @ 0)\\n\\t\\t\\t\\t\\t\\t\\textent: lastCharacterExtent - (font baseKern @ 0))\\n\\t\\t\\t\\t\\t\\t\\t\\t\\ttextLine: line]\\n\\t\\t\\t\\tifNotNil: [\\\"Result for characterBlockForIndex: \\\"\\n\\t\\t\\t\\t\\t\\t^ (CharacterBlock new stringIndex: characterIndex\\n\\t\\t\\t\\t\\t\\t\\ttext: text topLeft: characterPoint + ((font descentKern) - kern @ 0)\\n\\t\\t\\t\\t\\t\\t\\textent: lastCharacterExtent)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\ttextLine: line]]]! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:56'!\\ncharacterBlockForIndex: targetIndex in: aParagraph \\n\\t\\\"Answer a CharacterBlock for character in aParagraph at targetIndex. The \\n\\tcoordinates in the CharacterBlock will be appropriate to the intersection \\n\\tof the destination form rectangle and the composition rectangle.\\\"\\n\\n\\tself \\n\\t\\tinitializeFromParagraph: aParagraph \\n\\t\\tclippedBy: aParagraph clippingRectangle.\\n\\tcharacterIndex _ targetIndex.\\n\\tcharacterPoint _ \\n\\t\\taParagraph rightMarginForDisplay @ \\n\\t\\t\\t(aParagraph topAtLineIndex: \\n\\t\\t\\t\\t(aParagraph lineIndexOfCharacterIndex: characterIndex)).\\n\\t^self buildCharacterBlockIn: aParagraph! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:56'!\\nindentationLevel: anInteger\\n\\tsuper indentationLevel: anInteger.\\n\\tnextLeftMargin _ leftMargin.\\n\\tindentationLevel timesRepeat: [\\n\\t\\tnextLeftMargin _ textStyle nextTabXFrom: nextLeftMargin\\n\\t\\t\\t\\t\\tleftMargin: leftMargin\\n\\t\\t\\t\\t\\trightMargin: rightMargin]! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:56'!\\nplaceEmbeddedObject: anchoredMorph\\n\\t\\\"Workaround: The following should really use #textAnchorType\\\"\\n\\tanchoredMorph relativeTextAnchorPosition ifNotNil:[^true].\\n\\t(super placeEmbeddedObject: anchoredMorph) ifFalse: [^ false].\\n\\tspecialWidth _ anchoredMorph width.\\n\\t^ true! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'scanning' stamp: 'yo 8/6/2003 05:55'!\\nscanMultiCharactersCombiningFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta\\n\\n\\t| encoding f nextDestX maxAscii startEncoding char charValue |\\n\\tlastIndex _ startIndex.\\n\\tlastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun].\\n\\tstartEncoding _ (sourceString at: startIndex) leadingChar.\\n\\tfont ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1].\\n\\t((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [\\n\\t\\t[f _ font fontArray at: startEncoding + 1]\\n\\t\\t\\ton: Exception do: [:ex | f _ font fontArray at: 1].\\n\\t\\tf ifNil: [ f _ font fontArray at: 1].\\n\\t\\tmaxAscii _ f maxAscii.\\n\\t\\tspaceWidth _ f widthOf: Space.\\n\\t] ifFalse: [\\n\\t\\tmaxAscii _ font maxAscii.\\n\\t].\\n\\n\\t[lastIndex <= stopIndex] whileTrue: [\\n\\t\\tencoding _ (sourceString at: lastIndex) leadingChar.\\n\\t\\tencoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1. ^ stops at: EndOfRun].\\n\\t\\tchar _ (sourceString at: lastIndex).\\n\\t\\tcharValue _ char charCode.\\n\\t\\tcharValue > maxAscii ifTrue: [charValue _ maxAscii].\\n\\t\\t(encoding = 0 and: [(stopConditions at: charValue + 1) ~~ nil]) ifTrue: [\\n\\t\\t\\t^ stops at: charValue + 1\\n\\t\\t].\\n\\t\\tnextDestX _ destX + (self widthOf: char inFont: font).\\n\\t\\tnextDestX > rightX ifTrue: [^ stops at: CrossedX].\\n\\t\\tdestX _ nextDestX + kernDelta.\\n\\t\\tlastIndex _ lastIndex + 1.\\n\\t].\\n\\tlastIndex _ stopIndex.\\n\\t^ stops at: EndOfRun! !\\n\\n\\n!MultiCharacterBlockScanner methodsFor: 'stop conditions' stamp: 'yo 1/6/2005 22:55'!\\ncr \\n\\t\\\"Answer a CharacterBlock that specifies the current location of the mouse \\n\\trelative to a carriage return stop condition that has just been \\n\\tencountered. The ParagraphEditor convention is to denote selections by \\n\\tCharacterBlocks, sometimes including the carriage return (cursor is at \\n\\tthe end) and sometimes not (cursor is in the middle of the text).\\\"\\n\\n\\t((characterIndex ~= nil\\n\\t\\tand: [characterIndex > text size])\\n\\t\\t\\tor: [(line last = text size)\\n\\t\\t\\t\\tand: [(destY + line lineHeight) < characterPoint y]])\\n\\t\\tifTrue:\\t[\\\"When off end of string, give data for next character\\\"\\n\\t\\t\\t\\tdestY _ destY + line lineHeight.\\n\\t\\t\\t\\tbaselineY _ line lineHeight.\\n\\t\\t\\t\\tlastCharacter _ nil.\\n\\t\\t\\t\\tcharacterPoint _ (nextLeftMargin ifNil: [leftMargin]) @ destY.\\n\\t\\t\\t\\tlastIndex _ lastIndex + 1.\\n\\t\\t\\t\\tself lastCharacterExtentSetX: 0.\\n\\t\\t\\t\\t^ true].\\n\\t\\tlastCharacter _ CR.\\n\\t\\tcharacterPoint _ destX @ destY.\\n\\t\\tself lastCharacterExtentSetX: rightMargin - destX.\\n\\t\\t^true! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:56'!\\ncrossedX\\n\\t\\\"Text display has wrapping. The scanner just found a character past the x \\n\\tlocation of the cursor. We know that the cursor is pointing at a character \\n\\tor before one.\\\"\\n\\n\\t| leadingTab currentX |\\n\\tcharacterIndex == nil ifFalse: [\\n\\t\\t\\\"If the last character of the last line is a space,\\n\\t\\tand it crosses the right margin, then locating\\n\\t\\tthe character block after it is impossible without this hack.\\\"\\n\\t\\tcharacterIndex > text size ifTrue: [\\n\\t\\t\\tlastIndex _ characterIndex.\\n\\t\\t\\tcharacterPoint _ (nextLeftMargin ifNil: [leftMargin]) @ (destY + line lineHeight).\\n\\t\\t\\t^true]].\\n\\tcharacterPoint x <= (destX + (lastCharacterExtent x // 2))\\n\\t\\tifTrue:\\t[lastCharacter _ (text at: lastIndex).\\n\\t\\t\\t\\tcharacterPoint _ destX @ destY.\\n\\t\\t\\t\\t^true].\\n\\tlastIndex >= line last \\n\\t\\tifTrue:\\t[lastCharacter _ (text at: line last).\\n\\t\\t\\t\\tcharacterPoint _ destX @ destY.\\n\\t\\t\\t\\t^true].\\n\\n\\t\\\"Pointing past middle of a character, return the next character.\\\"\\n\\tlastIndex _ lastIndex + 1.\\n\\tlastCharacter _ text at: lastIndex.\\n\\tcurrentX _ destX + lastCharacterExtent x + kern.\\n\\tself lastCharacterExtentSetX: (font widthOf: lastCharacter).\\n\\tcharacterPoint _ currentX @ destY.\\n\\tlastCharacter = Space ifFalse: [^ true].\\n\\n\\t\\\"Yukky if next character is space or tab.\\\"\\n\\talignment = Justified ifTrue:\\n\\t\\t[self lastCharacterExtentSetX:\\n\\t\\t\\t(lastCharacterExtent x + \\t(line justifiedPadFor: (spaceCount + 1))).\\n\\t\\t^ true].\\n\\n\\ttrue ifTrue: [^ true].\\n\\t\\\"NOTE: I find no value to the following code, and so have defeated it - DI\\\"\\n\\n\\t\\\"See tabForDisplay for illumination on the following awfulness.\\\"\\n\\tleadingTab _ true.\\n\\tline first to: lastIndex - 1 do:\\n\\t\\t[:index | (text at: index) ~= Tab ifTrue: [leadingTab _ false]].\\n\\t(alignment ~= Justified or: [leadingTab])\\n\\t\\tifTrue:\\t[self lastCharacterExtentSetX: (textStyle nextTabXFrom: currentX\\n\\t\\t\\t\\t\\tleftMargin: leftMargin rightMargin: rightMargin) -\\n\\t\\t\\t\\t\\t\\tcurrentX]\\n\\t\\tifFalse:\\t[self lastCharacterExtentSetX: (((currentX + (textStyle tabWidth -\\n\\t\\t\\t\\t\\t\\t(line justifiedTabDeltaFor: spaceCount))) -\\n\\t\\t\\t\\t\\t\\t\\tcurrentX) max: 0)].\\n\\t^ true! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:56'!\\nendOfRun\\n\\t\\\"Before arriving at the cursor location, the selection has encountered an \\n\\tend of run. Answer false if the selection continues, true otherwise. Set \\n\\tup indexes for building the appropriate CharacterBlock.\\\"\\n\\n\\t| runLength lineStop |\\n\\t(((characterIndex ~~ nil and:\\n\\t\\t[runStopIndex < characterIndex and: [runStopIndex < text size]])\\n\\t\\t\\tor:\\t[characterIndex == nil and: [lastIndex < line last]]) or: [\\n\\t\\t\\t\\t((lastIndex < line last)\\n\\t\\t\\t\\tand: [((text at: lastIndex) leadingChar ~= (text at: lastIndex+1) leadingChar)\\n\\t\\t\\t\\t\\tand: [lastIndex ~= characterIndex]])])\\n\\t\\tifTrue:\\t[\\\"We're really at the end of a real run.\\\"\\n\\t\\t\\t\\trunLength _ (text runLengthFor: (lastIndex _ lastIndex + 1)).\\n\\t\\t\\t\\tcharacterIndex ~~ nil\\n\\t\\t\\t\\t\\tifTrue:\\t[lineStop _ characterIndex\\t\\\"scanning for index\\\"]\\n\\t\\t\\t\\t\\tifFalse:\\t[lineStop _ line last\\t\\t\\t\\\"scanning for point\\\"].\\n\\t\\t\\t\\t(runStopIndex _ lastIndex + (runLength - 1)) > lineStop\\n\\t\\t\\t\\t\\tifTrue: \\t[runStopIndex _ lineStop].\\n\\t\\t\\t\\tself setStopConditions.\\n\\t\\t\\t\\t^false].\\n\\n\\tlastCharacter _ text at: lastIndex.\\n\\tcharacterPoint _ destX @ destY.\\n\\t((lastCharacter = Space and: [alignment = Justified])\\n\\t\\tor: [lastCharacter = Tab and: [lastSpaceOrTabExtent notNil]])\\n\\t\\tifTrue: [lastCharacterExtent _ lastSpaceOrTabExtent].\\n\\tcharacterIndex ~~ nil\\n\\t\\tifTrue:\\t[\\\"If scanning for an index and we've stopped on that index,\\n\\t\\t\\t\\tthen we back destX off by the width of the character stopped on\\n\\t\\t\\t\\t(it will be pointing at the right side of the character) and return\\\"\\n\\t\\t\\t\\trunStopIndex = characterIndex\\n\\t\\t\\t\\t\\tifTrue:\\t[self characterPointSetX: destX - lastCharacterExtent x.\\n\\t\\t\\t\\t\\t\\t\\t^true].\\n\\t\\t\\t\\t\\\"Otherwise the requested index was greater than the length of the\\n\\t\\t\\t\\tstring. Return string size + 1 as index, indicate further that off the\\n\\t\\t\\t\\tstring by setting character to nil and the extent to 0.\\\"\\n\\t\\t\\t\\tlastIndex _ lastIndex + 1.\\n\\t\\t\\t\\tlastCharacter _ nil.\\n\\t\\t\\t\\tself lastCharacterExtentSetX: 0.\\n\\t\\t\\t\\t^true].\\n\\n\\t\\\"Scanning for a point and either off the end of the line or off the end of the string.\\\"\\n\\trunStopIndex = text size\\n\\t\\tifTrue:\\t[\\\"off end of string\\\"\\n\\t\\t\\t\\tlastIndex _ lastIndex + 1.\\n\\t\\t\\t\\tlastCharacter _ nil.\\n\\t\\t\\t\\tself lastCharacterExtentSetX: 0.\\n\\t\\t\\t\\t^true].\\n\\t\\\"just off end of line without crossing x\\\"\\n\\tlastIndex _ lastIndex + 1.\\n\\t^true! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:56'!\\npaddedSpace\\n\\t\\\"When the line is justified, the spaces will not be the same as the font's \\n\\tspace character. A padding of extra space must be considered in trying \\n\\tto find which character the cursor is pointing at. Answer whether the \\n\\tscanning has crossed the cursor.\\\"\\n\\n\\t| pad |\\n\\tpad _ 0.\\n\\tspaceCount _ spaceCount + 1.\\n\\tpad _ line justifiedPadFor: spaceCount.\\n\\tlastSpaceOrTabExtent _ lastCharacterExtent copy.\\n\\tself lastSpaceOrTabExtentSetX: spaceWidth + pad.\\n\\t(destX + lastSpaceOrTabExtent x) >= characterPoint x\\n\\t\\tifTrue: [lastCharacterExtent _ lastSpaceOrTabExtent copy.\\n\\t\\t\\t\\t^self crossedX].\\n\\tlastIndex _ lastIndex + 1.\\n\\tdestX _ destX + lastSpaceOrTabExtent x.\\n\\t^ false\\n! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:56'!\\nsetFont\\n\\tspecialWidth _ nil.\\n\\tsuper setFont! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'stop conditions' stamp: 'ar 10/18/2004 14:31'!\\nsetStopConditions\\n\\t\\\"Set the font and the stop conditions for the current run.\\\"\\n\\t\\n\\tself setFont.\\n\\tself setConditionArray: (alignment = Justified ifTrue: [#paddedSpace]).\\n! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:56'!\\ntab\\n\\t| currentX |\\n\\tcurrentX _ (alignment == Justified and: [self leadingTab not])\\n\\t\\tifTrue:\\t\\t\\\"imbedded tabs in justified text are weird\\\"\\n\\t\\t\\t[destX + (textStyle tabWidth - (line justifiedTabDeltaFor: spaceCount)) max: destX]\\n\\t\\tifFalse:\\n\\t\\t\\t[textStyle\\n\\t\\t\\t\\tnextTabXFrom: destX\\n\\t\\t\\t\\tleftMargin: leftMargin\\n\\t\\t\\t\\trightMargin: rightMargin].\\n\\tlastSpaceOrTabExtent _ lastCharacterExtent copy.\\n\\tself lastSpaceOrTabExtentSetX: (currentX - destX max: 0).\\n\\tcurrentX >= characterPoint x\\n\\t\\tifTrue: \\n\\t\\t\\t[lastCharacterExtent _ lastSpaceOrTabExtent copy.\\n\\t\\t\\t^ self crossedX].\\n\\tdestX _ currentX.\\n\\tlastIndex _ lastIndex + 1.\\n\\t^false! !\\n\\n\\n!MultiCharacterBlockScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:56'!\\nbuildCharacterBlockIn: para\\n\\t| lineIndex runLength lineStop done stopCondition |\\n\\t\\\"handle nullText\\\"\\n\\t(para numberOfLines = 0 or: [text size = 0])\\n\\t\\tifTrue:\\t[^ CharacterBlock new stringIndex: 1 \\\"like being off end of string\\\"\\n\\t\\t\\t\\t\\ttext: para text\\n\\t\\t\\t\\t\\ttopLeft: (para leftMarginForDisplayForLine: 1 alignment: (alignment ifNil:[textStyle alignment]))\\n\\t\\t\\t\\t\\t\\t\\t\\t@ para compositionRectangle top\\n\\t\\t\\t\\t\\textent: 0 @ textStyle lineGrid].\\n\\t\\\"find the line\\\"\\n\\tlineIndex _ para lineIndexOfTop: characterPoint y.\\n\\tdestY _ para topAtLineIndex: lineIndex.\\n\\tline _ para lines at: lineIndex.\\n\\trightMargin _ para rightMarginForDisplay.\\n\\n\\t(lineIndex = para numberOfLines and:\\n\\t\\t[(destY + line lineHeight) < characterPoint y])\\n\\t\\t\\tifTrue:\\t[\\\"if beyond lastLine, force search to last character\\\"\\n\\t\\t\\t\\t\\tself characterPointSetX: rightMargin]\\n\\t\\t\\tifFalse:\\t[characterPoint y < (para compositionRectangle) top\\n\\t\\t\\t\\t\\t\\tifTrue: [\\\"force search to first line\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\tcharacterPoint _ (para compositionRectangle) topLeft].\\n\\t\\t\\t\\t\\tcharacterPoint x > rightMargin\\n\\t\\t\\t\\t\\t\\tifTrue:\\t[self characterPointSetX: rightMargin]].\\n\\tdestX _ (leftMargin _ para leftMarginForDisplayForLine: lineIndex alignment: (alignment ifNil:[textStyle alignment])).\\n\\tnextLeftMargin_ para leftMarginForDisplayForLine: lineIndex+1 alignment: (alignment ifNil:[textStyle alignment]).\\n\\tlastIndex _ line first.\\n\\n\\tself setStopConditions.\\t\\t\\\"also sets font\\\"\\n\\trunLength _ (text runLengthFor: line first).\\n\\tcharacterIndex == nil\\n\\t\\tifTrue:\\t[lineStop _ line last \\\"characterBlockAtPoint\\\"]\\n\\t\\tifFalse:\\t[lineStop _ characterIndex \\\"characterBlockForIndex\\\"].\\n\\t(runStopIndex _ lastIndex + (runLength - 1)) > lineStop\\n\\t\\tifTrue:\\t[runStopIndex _ lineStop].\\n\\tlastCharacterExtent _ 0 @ line lineHeight.\\n\\tspaceCount _ 0. done _ false.\\n\\tself handleIndentation.\\n\\n\\t[done]\\n\\twhileFalse:\\n\\t[stopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex\\n\\t\\t\\tin: text string rightX: characterPoint x\\n\\t\\t\\tstopConditions: stopConditions kern: kern.\\n\\n\\t\\\"see setStopConditions for stopping conditions for character block \\toperations.\\\"\\n\\tself lastCharacterExtentSetX: (font widthOf: (text at: lastIndex)).\\n\\t(self perform: stopCondition) ifTrue:\\n\\t\\t[characterIndex == nil\\n\\t\\t\\tifTrue: [\\\"characterBlockAtPoint\\\"\\n\\t\\t\\t\\t\\t^ CharacterBlock new stringIndex: lastIndex text: text\\n\\t\\t\\t\\t\\t\\ttopLeft: characterPoint + (font descentKern @ 0)\\n\\t\\t\\t\\t\\t\\textent: lastCharacterExtent]\\n\\t\\t\\tifFalse: [\\\"characterBlockForIndex\\\"\\n\\t\\t\\t\\t\\t^ CharacterBlock new stringIndex: lastIndex text: text\\n\\t\\t\\t\\t\\t\\ttopLeft: characterPoint + ((font descentKern) - kern @ 0)\\n\\t\\t\\t\\t\\t\\textent: lastCharacterExtent]]]! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:56'!\\ncharacterPointSetX: xVal\\n\\tcharacterPoint _ xVal @ characterPoint y! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:56'!\\nlastCharacterExtentSetX: xVal\\n\\tlastCharacterExtent _ xVal @ lastCharacterExtent y! !\\n\\n!MultiCharacterBlockScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:56'!\\nlastSpaceOrTabExtentSetX: xVal\\n\\tlastSpaceOrTabExtent _ xVal @ lastSpaceOrTabExtent y! !\\nObject subclass: #MultiCharacterScanner\\n\\tinstanceVariableNames: 'destX lastIndex xTable destY stopConditions text textStyle alignment leftMargin rightMargin font line runStopIndex spaceCount spaceWidth emphasisCode kern indentationLevel wantsColumnBreaks presentation presentationLine numOfComposition baselineY firstDestX'\\n\\tclassVariableNames: 'DefaultStopConditions NilCondition PaddedSpaceCondition SpaceCondition'\\n\\tpoolDictionaries: 'TextConstants'\\n\\tcategory: 'Multilingual-Scanning'!\\n\\n!MultiCharacterScanner methodsFor: 'initialize' stamp: 'yo 12/18/2002 13:53'!\\ninitialize\\n\\tdestX _ destY _ leftMargin _ 0.! !\\n\\n!MultiCharacterScanner methodsFor: 'initialize' stamp: 'yo 12/18/2002 13:53'!\\ninitializeStringMeasurer\\n\\tstopConditions _ Array new: 258.\\n\\tstopConditions at: CrossedX put: #crossedX.\\n\\tstopConditions at: EndOfRun put: #endOfRun.\\n! !\\n\\n!MultiCharacterScanner methodsFor: 'initialize' stamp: 'yo 12/18/2002 13:53'!\\nwantsColumnBreaks: aBoolean\\n\\n\\twantsColumnBreaks _ aBoolean! !\\n\\n\\n!MultiCharacterScanner methodsFor: 'multilingual scanning' stamp: 'yo 1/3/2003 12:09'!\\naddCharToPresentation: char\\n\\n! !\\n\\n!MultiCharacterScanner methodsFor: 'multilingual scanning' stamp: 'yo 12/20/2002 16:15'!\\nregisterBreakableIndex\\n\\n\\t\\\"Record left x and character index of the line-wrappable point. \\n\\tThe default implementation here does nothing.\\\"\\n\\n\\t^ false.\\n! !\\n\\n!MultiCharacterScanner methodsFor: 'multilingual scanning' stamp: 'yo 1/23/2003 14:25'!\\nremoveLastCharFromPresentation\\n! !\\n\\n!MultiCharacterScanner methodsFor: 'multilingual scanning' stamp: 'yo 1/1/2003 10:43'!\\nwidthOf: char inFont: aFont\\n\\n\\t(char isMemberOf: CombinedChar) ifTrue: [\\n\\t\\t^ aFont widthOf: char base.\\n\\t] ifFalse: [\\n\\t\\t^ aFont widthOf: char.\\n\\t].\\n\\n\\n! !\\n\\n\\n!MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 12/18/2002 13:53'!\\nbasicScanCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta\\n\\t\\\"Primitive. This is the inner loop of text display--but see \\n\\tscanCharactersFrom: to:rightX: which would get the string, \\n\\tstopConditions and displaying from the instance. March through source \\n\\tString from startIndex to stopIndex. If any character is flagged with a \\n\\tnon-nil entry in stops, then return the corresponding value. Determine \\n\\twidth of each character from xTable, indexed by map. \\n\\tIf dextX would exceed rightX, then return stops at: 258. \\n\\tAdvance destX by the width of the character. If stopIndex has been\\n\\treached, then return stops at: 257. Optional. \\n\\tSee Object documentation whatIsAPrimitive.\\\"\\n\\t| ascii nextDestX char |\\n\\t<primitive: 103>\\n\\tlastIndex _ startIndex.\\n\\t[lastIndex <= stopIndex]\\n\\t\\twhileTrue: \\n\\t\\t\\t[char _ (sourceString at: lastIndex).\\n\\t\\t\\tascii _ char asciiValue + 1.\\n\\t\\t\\t(stops at: ascii) == nil ifFalse: [^stops at: ascii].\\n\\t\\t\\t\\\"Note: The following is querying the font about the width\\n\\t\\t\\tsince the primitive may have failed due to a non-trivial\\n\\t\\t\\tmapping of characters to glyphs or a non-existing xTable.\\\"\\n\\t\\t\\tnextDestX _ destX + (font widthOf: char).\\n\\t\\t\\tnextDestX > rightX ifTrue: [^stops at: CrossedX].\\n\\t\\t\\tdestX _ nextDestX + kernDelta.\\n\\t\\t\\tlastIndex _ lastIndex + 1].\\n\\tlastIndex _ stopIndex.\\n\\t^stops at: EndOfRun! !\\n\\n!MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 12/30/2002 22:59'!\\ncombinableChar: char for: prevEntity\\n\\n! !\\n\\n!MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 12/20/2002 11:46'!\\nisBreakableAt: index in: sourceString in: encodingClass\\n\\n\\t^ encodingClass isBreakableAt: index in: sourceString.\\n! !\\n\\n!MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 3/16/2005 19:03'!\\nscanJapaneseCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta\\n\\n\\t| ascii encoding f nextDestX maxAscii startEncoding |\\n\\tlastIndex _ startIndex.\\n\\tlastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun].\\n\\tstartEncoding _ (sourceString at: startIndex) leadingChar.\\n\\tfont ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1].\\n\\t((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [\\n\\t\\t[f _ font fontArray at: startEncoding + 1]\\n\\t\\t\\ton: Exception do: [:ex | f _ font fontArray at: 1].\\n\\t\\tf ifNil: [ f _ font fontArray at: 1].\\n\\t\\tmaxAscii _ f maxAscii.\\n\\t\\t\\\"xTable _ f xTable.\\n\\t\\tmaxAscii _ xTable size - 2.\\\"\\n\\t\\tspaceWidth _ f widthOf: Space.\\n\\t] ifFalse: [\\n\\t\\t(font isMemberOf: HostFont) ifTrue: [\\n\\t\\t\\tf _ font.\\n\\t\\t\\tmaxAscii _ f maxAscii.\\n\\t\\t\\tspaceWidth _ f widthOf: Space.\\n\\t\\t] ifFalse: [\\n\\t\\t\\tmaxAscii _ font maxAscii.\\n\\t\\t].\\n\\t].\\n\\t[lastIndex <= stopIndex] whileTrue: [\\n\\t\\t\\\"self halt.\\\"\\n\\t\\tencoding _ (sourceString at: lastIndex) leadingChar.\\n\\t\\tencoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1. ^ stops at: EndOfRun].\\n\\t\\tascii _ (sourceString at: lastIndex) charCode.\\n\\t\\tascii > maxAscii ifTrue: [ascii _ maxAscii].\\n\\t\\t(encoding = 0 and: [(stopConditions at: ascii + 1) ~~ nil]) ifTrue: [^ stops at: ascii + 1].\\n\\t\\t(self isBreakableAt: lastIndex in: sourceString in: (EncodedCharSet charsetAt: encoding)) ifTrue: [\\n\\t\\t\\tself registerBreakableIndex.\\n\\t\\t].\\n\\t\\tnextDestX _ destX + (font widthOf: (sourceString at: lastIndex)).\\n\\t\\tnextDestX > rightX ifTrue: [firstDestX ~= destX ifTrue: [^ stops at: CrossedX]].\\n\\t\\tdestX _ nextDestX + kernDelta.\\n\\t\\tlastIndex _ lastIndex + 1.\\n\\t].\\n\\tlastIndex _ stopIndex.\\n\\t^ stops at: EndOfRun! !\\n\\n!MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 3/16/2005 19:09'!\\nscanMultiCharactersCombiningFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta\\n\\n\\t| charCode encoding f maxAscii startEncoding combining combined combiningIndex c |\\n\\tlastIndex _ startIndex.\\n\\tlastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun].\\n\\tstartEncoding _ (sourceString at: startIndex) leadingChar.\\n\\tfont ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1].\\n\\t((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [\\n\\t\\t[f _ font fontArray at: startEncoding + 1]\\n\\t\\t\\ton: Exception do: [:ex | f _ font fontArray at: 1].\\n\\t\\tf ifNil: [ f _ font fontArray at: 1].\\n\\t\\tmaxAscii _ f maxAscii.\\n\\t\\tspaceWidth _ font widthOf: Space.\\n\\t] ifFalse: [\\n\\t\\tmaxAscii _ font maxAscii.\\n\\t\\tspaceWidth _ font widthOf: Space.\\n\\t].\\n\\n\\tcombining _ nil.\\n\\t[lastIndex <= stopIndex] whileTrue: [\\n\\t\\tcharCode _ (sourceString at: lastIndex) charCode.\\n\\t\\tc _ (sourceString at: lastIndex).\\n\\t\\tcombining ifNil: [\\n\\t\\t\\tcombining _ CombinedChar new.\\n\\t\\t\\tcombining add: c.\\n\\t\\t\\tcombiningIndex _ lastIndex.\\n\\t\\t\\tlastIndex _ lastIndex + 1.\\n\\t\\t] ifNotNil: [\\n\\t\\t\\t(combining add: c) ifFalse: [\\n\\t\\t\\t\\tself addCharToPresentation: (combined _ combining combined).\\n\\t\\t\\t\\tcombining _ CombinedChar new.\\n\\t\\t\\t\\tcombining add: c.\\n\\t\\t\\t\\tcharCode _ combined charCode.\\n\\t\\t\\t\\tencoding _ combined leadingChar.\\n\\t\\t\\t\\tencoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1.\\n\\t\\t\\t\\t\\t(encoding = 0 and: [(stopConditions at: charCode + 1) ~~ nil]) ifTrue: [\\n\\t\\t\\t\\t\\t\\t^ stops at: charCode + 1\\n\\t\\t\\t\\t\\t] ifFalse: [\\n\\t\\t\\t\\t\\t\\t ^ stops at: EndOfRun\\n\\t\\t\\t\\t\\t].\\n\\t\\t\\t\\t].\\n\\t\\t\\t\\tcharCode > maxAscii ifTrue: [charCode _ maxAscii].\\n\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t\\t(encoding = 0 and: [(stopConditions at: charCode + 1) ~~ nil]) ifTrue: [\\n\\t\\t\\t\\t\\tcombining ifNotNil: [\\n\\t\\t\\t\\t\\t\\tself addCharToPresentation: (combining combined).\\n\\t\\t\\t\\t\\t].\\n\\t\\t\\t\\t\\t^ stops at: charCode + 1\\n\\t\\t\\t\\t].\\n\\t\\t\\t\\t(self isBreakableAt: lastIndex in: sourceString in: Latin1Environment) ifTrue: [\\n\\t\\t\\t\\t\\tself registerBreakableIndex.\\n\\t\\t\\t\\t].\\t\\t\\n\\t\\t\\t\\tdestX > rightX ifTrue: [\\n\\t\\t\\t\\t\\tdestX ~= firstDestX ifTrue: [\\n\\t\\t\\t\\t\\t\\tlastIndex _ combiningIndex.\\n\\t\\t\\t\\t\\t\\tself removeLastCharFromPresentation.\\n\\t\\t\\t\\t\\t\\t^ stops at: CrossedX]].\\n\\t\\t\\t\\tcombiningIndex _ lastIndex.\\n\\t\\t\\t\\tlastIndex _ lastIndex + 1.\\n\\t\\t\\t] ifTrue: [\\n\\t\\t\\t\\tlastIndex _ lastIndex + 1.\\n\\t\\t\\t\\tnumOfComposition _ numOfComposition + 1.\\n\\t\\t\\t].\\n\\t\\t].\\n\\t].\\n\\tlastIndex _ stopIndex.\\n\\tcombining ifNotNil: [\\n\\t\\tcombined _ combining combined.\\n\\t\\tself addCharToPresentation: combined.\\n\\t\\t\\\"assuming that there is always enough space for at least one character\\\".\\n\\t\\tdestX _ destX + (self widthOf: combined inFont: font).\\n\\t].\\n\\t^ stops at: EndOfRun! !\\n\\n!MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 3/16/2005 19:08'!\\nscanMultiCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta\\n\\n\\t| ascii encoding f nextDestX maxAscii startEncoding |\\n\\tlastIndex _ startIndex.\\n\\tlastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun].\\n\\tstartEncoding _ (sourceString at: startIndex) leadingChar.\\n\\tfont ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1].\\n\\t((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [\\n\\t\\t[f _ font fontArray at: startEncoding + 1]\\n\\t\\t\\ton: Exception do: [:ex | f _ font fontArray at: 1].\\n\\t\\tf ifNil: [ f _ font fontArray at: 1].\\n\\t\\tmaxAscii _ f maxAscii.\\n\\t\\tspaceWidth _ f widthOf: Space.\\n\\t] ifFalse: [\\n\\t\\tmaxAscii _ font maxAscii.\\n\\t].\\n\\n\\t[lastIndex <= stopIndex] whileTrue: [\\n\\t\\tencoding _ (sourceString at: lastIndex) leadingChar.\\n\\t\\tencoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1. ^ stops at: EndOfRun].\\n\\t\\tascii _ (sourceString at: lastIndex) charCode.\\n\\t\\tascii > maxAscii ifTrue: [ascii _ maxAscii].\\n\\t\\t(encoding = 0 and: [ascii < stopConditions size and: [(stopConditions at: ascii + 1) ~~ nil]]) ifTrue: [^ stops at: ascii + 1].\\n\\t\\t(self isBreakableAt: lastIndex in: sourceString in: Latin1Environment) ifTrue: [\\n\\t\\t\\tself registerBreakableIndex.\\n\\t\\t].\\n\\t\\tnextDestX _ destX + (font widthOf: (sourceString at: lastIndex)).\\n\\t\\tnextDestX > rightX ifTrue: [destX ~= firstDestX ifTrue: [^ stops at: CrossedX]].\\n\\t\\tdestX _ nextDestX + kernDelta.\\n\\t\\tlastIndex _ lastIndex + 1.\\n\\t].\\n\\tlastIndex _ stopIndex.\\n\\t^ stops at: EndOfRun! !\\n\\n!MultiCharacterScanner methodsFor: 'scanner methods' stamp: 'yo 3/16/2005 19:08'!\\nscanMultiCharactersR2LFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta\\n\\n\\t\\\"Note that 'rightX' really means 'endX' in R2L context. Ie. rightX is usually smaller than destX.\\\"\\n\\t| ascii encoding f nextDestX maxAscii startEncoding |\\n\\tlastIndex _ startIndex.\\n\\tlastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun].\\n\\tstartEncoding _ (sourceString at: startIndex) leadingChar.\\n\\tfont ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1].\\n\\t((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [\\n\\t\\t[f _ font fontArray at: startEncoding + 1]\\n\\t\\t\\ton: Exception do: [:ex | f _ font fontArray at: 1].\\n\\t\\tf ifNil: [ f _ font fontArray at: 1].\\n\\t\\tmaxAscii _ f maxAscii.\\n\\t\\tspaceWidth _ f widthOf: Space.\\n\\t] ifFalse: [\\n\\t\\tmaxAscii _ font maxAscii.\\n\\t].\\n\\n\\t[lastIndex <= stopIndex] whileTrue: [\\n\\t\\tencoding _ (sourceString at: lastIndex) leadingChar.\\n\\t\\tencoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1. ^ stops at: EndOfRun].\\n\\t\\tascii _ (sourceString at: lastIndex) charCode.\\n\\t\\tascii > maxAscii ifTrue: [ascii _ maxAscii].\\n\\t\\t(encoding = 0 and: [(stopConditions at: ascii + 1) ~~ nil]) ifTrue: [^ stops at: ascii + 1].\\n\\t\\t(self isBreakableAt: lastIndex in: sourceString in: Latin1Environment) ifTrue: [\\n\\t\\t\\tself registerBreakableIndex.\\n\\t\\t].\\n\\t\\tnextDestX _ destX - (font widthOf: (sourceString at: lastIndex)).\\n\\t\\tnextDestX < rightX ifTrue: [^ stops at: CrossedX].\\n\\t\\tdestX _ nextDestX - kernDelta.\\n\\t\\tlastIndex _ lastIndex + 1.\\n\\t].\\n\\tlastIndex _ stopIndex.\\n\\t^ stops at: EndOfRun! !\\n\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:53'!\\ncolumnBreak\\n\\n\\t^true! !\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:53'!\\nembeddedObject\\n\\t| savedIndex |\\n\\tsavedIndex _ lastIndex.\\n\\ttext attributesAt: lastIndex do:[:attr| \\n\\t\\tattr anchoredMorph ifNotNil:[\\n\\t\\t\\t\\\"Following may look strange but logic gets reversed.\\n\\t\\t\\tIf the morph fits on this line we're not done (return false for true) \\n\\t\\t\\tand if the morph won't fit we're done (return true for false)\\\"\\n\\t\\t\\t(self placeEmbeddedObject: attr anchoredMorph) ifFalse:[^true]]].\\n\\tlastIndex _ savedIndex + 1. \\\"for multiple(!!) embedded morphs\\\"\\n\\t^false! !\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:53'!\\nhandleIndentation\\n\\tself indentationLevel timesRepeat: [\\n\\t\\tself plainTab]! !\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:53'!\\nindentationLevel\\n\\t\\\"return the number of tabs that are currently being placed at the beginning of each line\\\"\\n\\t^indentationLevel ifNil:[0]! !\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:53'!\\nindentationLevel: anInteger\\n\\t\\\"set the number of tabs to put at the beginning of each line\\\"\\n\\tindentationLevel _ anInteger! !\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:53'!\\nleadingTab\\n\\t\\\"return true if only tabs lie to the left\\\"\\n\\tline first to: lastIndex do:\\n\\t\\t[:i | (text at: i) == Tab ifFalse: [^ false]].\\n\\t^ true! !\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'yo 1/18/2005 08:08'!\\nmeasureString: aString inFont: aFont from: startIndex to: stopIndex\\n\\t\\\"WARNING: In order to use this method the receiver has to be set up using #initializeStringMeasurer\\\"\\n\\tdestX _ destY _ lastIndex _ 0.\\n\\tbaselineY _ aFont ascent.\\n\\txTable _ aFont xTable.\\n\\tfont := aFont. \\\" added Dec 03, 2004 \\\"\\n\\\"\\tmap _ aFont characterToGlyphMap.\\\"\\n\\tself scanCharactersFrom: startIndex to: stopIndex in: aString rightX: 999999 stopConditions: stopConditions kern: 0.\\n\\t^destX! !\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:53'!\\nplaceEmbeddedObject: anchoredMorph\\n\\t\\\"Place the anchoredMorph or return false if it cannot be placed.\\n\\tIn any event, advance destX by its width.\\\"\\n\\t| w |\\n\\t\\\"Workaround: The following should really use #textAnchorType\\\"\\n\\tanchoredMorph relativeTextAnchorPosition ifNotNil:[^true].\\n\\tdestX _ destX + (w _ anchoredMorph width).\\n\\t(destX > rightMargin and: [(leftMargin + w) <= rightMargin])\\n\\t\\tifTrue: [\\\"Won't fit, but would on next line\\\"\\n\\t\\t\\t\\t^ false].\\n\\tlastIndex _ lastIndex + 1.\\n\\tself setFont. \\\"Force recalculation of emphasis for next run\\\"\\n\\t^ true! !\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'yo 12/18/2002 13:53'!\\nplainTab\\n\\t\\\"This is the basic method of adjusting destX for a tab.\\\"\\n\\tdestX _ (alignment == Justified and: [self leadingTab not])\\n\\t\\tifTrue:\\t\\t\\\"embedded tabs in justified text are weird\\\"\\n\\t\\t\\t[destX + (textStyle tabWidth - (line justifiedTabDeltaFor: spaceCount)) max: destX]\\n\\t\\tifFalse: \\n\\t\\t\\t[textStyle nextTabXFrom: destX\\n\\t\\t\\t\\tleftMargin: leftMargin\\n\\t\\t\\t\\trightMargin: rightMargin]! !\\n\\n!MultiCharacterScanner methodsFor: 'scanning' stamp: 'ar 4/12/2005 19:53'!\\nscanCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta\\n\\n\\t| startEncoding selector |\\n\\t(sourceString isByteString) ifTrue: [^ self basicScanCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta.].\\n\\n\\t(sourceString isWideString) ifTrue: [\\n\\t\\tstartIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun].\\n\\t\\tstartEncoding _ (sourceString at: startIndex) leadingChar.\\n\\t\\tselector _ (EncodedCharSet charsetAt: startEncoding) scanSelector.\\n\\t\\t^ self perform: selector withArguments: (Array with: startIndex with: stopIndex with: sourceString with: rightX with: stopConditions with: kernDelta).\\n\\t].\\n\\t\\n\\t^ stops at: EndOfRun\\n! !\\n\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:53'!\\naddEmphasis: code\\n\\t\\\"Set the bold-ital-under-strike emphasis.\\\"\\n\\temphasisCode _ emphasisCode bitOr: code! !\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:53'!\\naddKern: kernDelta\\n\\t\\\"Set the current kern amount.\\\"\\n\\tkern _ kern + kernDelta! !\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:53'!\\ninitializeFromParagraph: aParagraph clippedBy: clippingRectangle\\n\\n\\ttext _ aParagraph text.\\n\\ttextStyle _ aParagraph textStyle. \\n! !\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:53'!\\nsetActualFont: aFont\\n\\t\\\"Set the basal font to an isolated font reference.\\\"\\n\\n\\tfont _ aFont! !\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:53'!\\nsetAlignment: style\\n\\talignment _ style.\\n\\t! !\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'yo 12/19/2002 02:05'!\\nsetConditionArray: aSymbol\\n\\n\\taSymbol == #paddedSpace ifTrue: [^stopConditions _ PaddedSpaceCondition \\\"copy\\\"].\\n\\t\\\"aSymbol == #space ifTrue: [^stopConditions _ SpaceCondition copy].\\\"\\n\\taSymbol == nil ifTrue: [^stopConditions _ NilCondition \\\"copy\\\"].\\n\\tself error: 'undefined stopcondition for space character'.\\n! !\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'tak 12/19/2004 15:45'!\\nsetFont\\n\\t| priorFont |\\n\\t\\\"Set the font and other emphasis.\\\"\\n\\tpriorFont _ font.\\n\\ttext == nil ifFalse:[\\n\\t\\temphasisCode _ 0.\\n\\t\\tkern _ 0.\\n\\t\\tindentationLevel _ 0.\\n\\t\\talignment _ textStyle alignment.\\n\\t\\tfont _ nil.\\n\\t\\t(text attributesAt: lastIndex forStyle: textStyle)\\n\\t\\t\\tdo: [:att | att emphasizeScanner: self]].\\n\\tfont == nil ifTrue:\\n\\t\\t[self setFont: textStyle defaultFontIndex].\\n\\tfont _ font emphasized: emphasisCode.\\n\\tpriorFont ifNotNil: [destX _ destX + priorFont descentKern].\\n\\tdestX _ destX - font descentKern.\\n\\t\\\"NOTE: next statement should be removed when clipping works\\\"\\n\\tleftMargin ifNotNil: [destX _ destX max: leftMargin].\\n\\tkern _ kern - font baseKern.\\n\\n\\t\\\"Install various parameters from the font.\\\"\\n\\tspaceWidth _ font widthOf: Space.\\n\\txTable _ font xTable.\\n\\\"\\tmap _ font characterToGlyphMap.\\\"\\n\\tstopConditions _ DefaultStopConditions.! !\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:53'!\\nsetFont: fontNumber\\n\\t\\\"Set the font by number from the textStyle.\\\"\\n\\n\\tself setActualFont: (textStyle fontAt: fontNumber)! !\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:53'!\\ntext: t textStyle: ts\\n\\ttext _ t.\\n\\ttextStyle _ ts! !\\n\\n!MultiCharacterScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:53'!\\ntextColor: ignored\\n\\t\\\"Overridden in DisplayScanner\\\"! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMultiCharacterScanner class\\n\\tinstanceVariableNames: ''!\\n\\n!MultiCharacterScanner class methodsFor: 'class initialization' stamp: 'yo 12/18/2002 14:09'!\\ninitialize\\n\\\"\\n\\tMultiCharacterScanner initialize\\n\\\"\\n\\t| a |\\n\\ta _ Array new: 258.\\n\\ta at: 1 + 1 put: #embeddedObject.\\n\\ta at: Tab asciiValue + 1 put: #tab.\\n\\ta at: CR asciiValue + 1 put: #cr.\\n\\ta at: EndOfRun put: #endOfRun.\\n\\ta at: CrossedX put: #crossedX.\\n\\tNilCondition _ a copy.\\n\\tDefaultStopConditions _ a copy.\\n\\n\\tPaddedSpaceCondition _ a copy.\\n\\tPaddedSpaceCondition at: Space asciiValue + 1 put: #paddedSpace.\\n\\t\\n\\tSpaceCondition _ a copy.\\n\\tSpaceCondition at: Space asciiValue + 1 put: #space.\\n! !\\nMultiCharacterScanner subclass: #MultiCompositionScanner\\n\\tinstanceVariableNames: 'spaceX lineHeight baseline breakableIndex lineHeightAtBreak baselineAtBreak breakAtSpace lastWidth'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-Scanning'!\\n\\n!MultiCompositionScanner methodsFor: 'accessing' stamp: 'yo 1/3/2003 02:33'!\\npresentation\\n\\n\\t^ presentation.\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'accessing' stamp: 'yo 1/3/2003 02:33'!\\npresentationLine\\n\\n\\t^ presentationLine.\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'accessing' stamp: 'yo 12/18/2002 14:56'!\\nrightX\\n\\t\\\"Meaningful only when a line has just been composed -- refers to the \\n\\tline most recently composed. This is a subtrefuge to allow for easy \\n\\tresizing of a composition rectangle to the width of the maximum line. \\n\\tUseful only when there is only one line in the form or when each line \\n\\tis terminated by a carriage return. Handy for sizing menus and lists.\\\"\\n\\n\\tbreakAtSpace ifTrue: [^ spaceX].\\n\\n\\t^ destX.\\n! !\\n\\n\\n!MultiCompositionScanner methodsFor: 'intialize-release' stamp: 'yo 12/18/2002 13:57'!\\nforParagraph: aParagraph\\n\\t\\\"Initialize the receiver for scanning the given paragraph.\\\"\\n\\n\\tself\\n\\t\\tinitializeFromParagraph: aParagraph\\n\\t\\tclippedBy: aParagraph clippingRectangle.\\n! !\\n\\n\\n!MultiCompositionScanner methodsFor: 'multilingual scanning' stamp: 'yo 2/10/2004 23:00'!\\naddCharToPresentation: char\\n\\n\\tpresentation nextPut: char.\\n\\tlastWidth _ self widthOf: char inFont: font.\\n\\tdestX _ destX + lastWidth.\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'multilingual scanning' stamp: 'yo 1/16/2003 17:38'!\\ngetPresentation\\n\\n\\t^ presentation contents.\\n\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'multilingual scanning' stamp: 'yo 1/16/2003 17:28'!\\ngetPresentationLine\\n\\n\\t^ presentationLine.\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'multilingual scanning' stamp: 'yo 12/20/2002 11:51'!\\nisBreakableAt: index in: sourceString in: encodingClass\\n\\n\\t^ encodingClass isBreakableAt: index in: sourceString.\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'multilingual scanning' stamp: 'yo 12/20/2002 16:28'!\\nregisterBreakableIndex\\n\\n\\t\\\"Record left x and character index of the line-wrappable point. \\n\\tUsed for wrap-around. Answer whether the character has crossed the \\n\\tright edge of the composition rectangle of the paragraph.\\\"\\n\\n\\t(text at: lastIndex) = Character space ifTrue: [\\n\\t\\tbreakAtSpace _ true.\\n\\t\\tspaceX _ destX.\\n\\t\\tspaceCount _ spaceCount + 1.\\n\\t\\tlineHeightAtBreak _ lineHeight.\\n\\t\\tbaselineAtBreak _ baseline.\\n\\t\\tbreakableIndex _ lastIndex.\\n\\t\\tdestX > rightMargin ifTrue: \\t[^self crossedX].\\n\\t] ifFalse: [\\n\\t\\tbreakAtSpace _ false.\\n\\t\\tlineHeightAtBreak _ lineHeight.\\n\\t\\tbaselineAtBreak _ baseline.\\n\\t\\tbreakableIndex _ lastIndex - 1.\\n\\t].\\n\\t^ false.\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'multilingual scanning' stamp: 'yo 2/10/2004 22:59'!\\nremoveLastCharFromPresentation\\n\\n\\tpresentation ifNotNil: [\\n\\t\\tpresentation position: presentation position - 1.\\n\\t].\\n\\tdestX _ destX - lastWidth.\\n! !\\n\\n\\n!MultiCompositionScanner methodsFor: 'scanning' stamp: 'ar 4/12/2005 17:34'!\\ncomposeFrom: startIndex inRectangle: lineRectangle\\n\\tfirstLine: firstLine leftSide: leftSide rightSide: rightSide\\n\\t\\\"Answer an instance of TextLineInterval that represents the next line in the paragraph.\\\"\\n\\t| runLength done stopCondition |\\n\\t\\\"Set up margins\\\"\\n\\tleftMargin _ lineRectangle left.\\n\\tleftSide ifTrue: [leftMargin _ leftMargin +\\n\\t\\t\\t\\t\\t\\t(firstLine ifTrue: [textStyle firstIndent]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [textStyle restIndent])].\\n\\tdestX _ spaceX _ leftMargin.\\n\\tfirstDestX _ destX.\\n\\trightMargin _ lineRectangle right.\\n\\trightSide ifTrue: [rightMargin _ rightMargin - textStyle rightIndent].\\n\\tlastIndex _ startIndex.\\t\\\"scanning sets last index\\\"\\n\\tdestY _ lineRectangle top.\\n\\tlineHeight _ baseline _ 0. \\\"Will be increased by setFont\\\"\\n\\tself setStopConditions.\\t\\\"also sets font\\\"\\n\\trunLength _ text runLengthFor: startIndex.\\n\\trunStopIndex _ (lastIndex _ startIndex) + (runLength - 1).\\n\\tline _ (TextLine start: lastIndex stop: 0 internalSpaces: 0 paddingWidth: 0)\\n\\t\\t\\t\\trectangle: lineRectangle.\\n\\tpresentationLine _ (TextLine start: lastIndex stop: 0 internalSpaces: 0 paddingWidth: 0)\\n\\t\\t\\t\\trectangle: lineRectangle.\\n\\tnumOfComposition _ 0.\\n\\tspaceCount _ 0.\\n\\tself handleIndentation.\\n\\tleftMargin _ destX.\\n\\tline leftMargin: leftMargin.\\n\\tpresentationLine leftMargin: leftMargin.\\n\\n\\tpresentation _ TextStream on: (Text fromString: (WideString new: text size)).\\n\\n\\tdone _ false.\\n\\t[done]\\n\\t\\twhileFalse: \\n\\t\\t\\t[stopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex\\n\\t\\t\\t\\tin: text string rightX: rightMargin stopConditions: stopConditions\\n\\t\\t\\t\\tkern: kern.\\n\\t\\t\\t\\\"See setStopConditions for stopping conditions for composing.\\\"\\n\\t\\t\\t(self perform: stopCondition)\\n\\t\\t\\t\\tifTrue: [presentationLine lineHeight: lineHeight + textStyle leading\\n\\t\\t\\t\\t\\t\\t\\tbaseline: baseline + textStyle leading.\\n\\t\\t\\t\\t\\t\\t^ line lineHeight: lineHeight + textStyle leading\\n\\t\\t\\t\\t\\t\\t\\tbaseline: baseline + textStyle leading]]! !\\n\\n!MultiCompositionScanner methodsFor: 'scanning' stamp: 'ar 4/12/2005 17:34'!\\ncomposeLine: lineIndex fromCharacterIndex: startIndex inParagraph: aParagraph \\n\\t\\\"Answer an instance of TextLineInterval that represents the next line in the paragraph.\\\"\\n\\t| runLength done stopCondition |\\n\\tdestX _ spaceX _ leftMargin _ aParagraph leftMarginForCompositionForLine: lineIndex.\\n\\tdestY _ 0.\\n\\trightMargin _ aParagraph rightMarginForComposition.\\n\\tleftMargin >= rightMargin ifTrue: [self error: 'No room between margins to compose'].\\n\\tlastIndex _ startIndex.\\t\\\"scanning sets last index\\\"\\n\\tlineHeight _ textStyle lineGrid. \\\"may be increased by setFont:...\\\"\\n\\tbaseline _ textStyle baseline.\\n\\tbaselineY _ destY + baseline.\\n\\tself setStopConditions.\\t\\\"also sets font\\\"\\n\\tself handleIndentation.\\n\\trunLength _ text runLengthFor: startIndex.\\n\\trunStopIndex _ (lastIndex _ startIndex) + (runLength - 1).\\n\\tline _ TextLineInterval\\n\\t\\tstart: lastIndex\\n\\t\\tstop: 0\\n\\t\\tinternalSpaces: 0\\n\\t\\tpaddingWidth: 0.\\n\\tpresentationLine _ TextLineInterval\\n\\t\\tstart: lastIndex\\n\\t\\tstop: 0\\n\\t\\tinternalSpaces: 0\\n\\t\\tpaddingWidth: 0.\\n\\tnumOfComposition _ 0.\\n\\tpresentation _ TextStream on: (Text fromString: (WideString new: text size)).\\n\\tspaceCount _ 0.\\n\\tdone _ false.\\n\\t[done]\\n\\t\\twhileFalse: \\n\\t\\t\\t[stopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex\\n\\t\\t\\t\\tin: text string rightX: rightMargin stopConditions: stopConditions\\n\\t\\t\\t\\tkern: kern.\\n\\t\\t\\t\\\"See setStopConditions for stopping conditions for composing.\\\"\\n\\t\\t\\t(self perform: stopCondition)\\n\\t\\t\\t\\tifTrue: [presentationLine lineHeight: lineHeight + textStyle leading\\n\\t\\t\\t\\t\\t\\t\\tbaseline: baseline + textStyle leading.\\n\\t\\t\\t\\t\\t\\t^line lineHeight: lineHeight + textStyle leading\\n\\t\\t\\t\\t\\t\\t\\tbaseline: baseline + textStyle leading]]! !\\n\\n!MultiCompositionScanner methodsFor: 'scanning' stamp: 'yo 1/3/2003 11:54'!\\ncrossedX\\n\\t\\\"There is a word that has fallen across the right edge of the composition \\n\\trectangle. This signals the need for wrapping which is done to the last \\n\\tspace that was encountered, as recorded by the space stop condition.\\\"\\n\\n\\t(breakAtSpace) ifTrue: [\\n\\t\\tspaceCount >= 1 ifTrue:\\n\\t\\t\\t[\\\"The common case. First back off to the space at which we wrap.\\\"\\n\\t\\t\\tline stop: breakableIndex.\\n\\t\\t\\tpresentationLine stop: breakableIndex - numOfComposition.\\n\\t\\t\\tlineHeight _ lineHeightAtBreak.\\n\\t\\t\\tbaseline _ baselineAtBreak.\\n\\t\\t\\tspaceCount _ spaceCount - 1.\\n\\t\\t\\tbreakableIndex _ breakableIndex - 1.\\n\\n\\t\\t\\t\\\"Check to see if any spaces preceding the one at which we wrap.\\n\\t\\t\\t\\tDouble space after punctuation, most likely.\\\"\\n\\t\\t\\t[(spaceCount > 1 and: [(text at: breakableIndex) = Space])]\\n\\t\\t\\t\\twhileTrue:\\n\\t\\t\\t\\t\\t[spaceCount _ spaceCount - 1.\\n\\t\\t\\t\\t\\t\\\"Account for backing over a run which might\\n\\t\\t\\t\\t\\t\\tchange width of space.\\\"\\n\\t\\t\\t\\t\\tfont _ text fontAt: breakableIndex withStyle: textStyle.\\n\\t\\t\\t\\t\\tbreakableIndex _ breakableIndex - 1.\\n\\t\\t\\t\\t\\tspaceX _ spaceX - (font widthOf: Space)].\\n\\t\\t\\tline paddingWidth: rightMargin - spaceX.\\n\\t\\t\\tpresentationLine paddingWidth: rightMargin - spaceX.\\n\\t\\t\\tpresentationLine internalSpaces: spaceCount.\\n\\t\\t\\tline internalSpaces: spaceCount]\\n\\t\\tifFalse:\\n\\t\\t\\t[\\\"Neither internal nor trailing spaces -- almost never happens.\\\"\\n\\t\\t\\tlastIndex _ lastIndex - 1.\\n\\t\\t\\t[destX <= rightMargin]\\n\\t\\t\\t\\twhileFalse:\\n\\t\\t\\t\\t\\t[destX _ destX - (font widthOf: (text at: lastIndex)).\\n\\t\\t\\t\\t\\tlastIndex _ lastIndex - 1].\\n\\t\\t\\tspaceX _ destX.\\n\\t\\t\\tline paddingWidth: rightMargin - destX.\\n\\t\\t\\tpresentationLine paddingWidth: rightMargin - destX.\\n\\t\\t\\tpresentationLine stop: (lastIndex max: line first).\\n\\t\\t\\tline stop: (lastIndex max: line first)].\\n\\t\\t^true\\n\\t].\\n\\n\\t(breakableIndex isNil or: [breakableIndex < line first]) ifTrue: [\\n\\t\\t\\\"Any breakable point in this line. Just wrap last character.\\\"\\n\\t\\tbreakableIndex _ lastIndex - 1.\\n\\t\\tlineHeightAtBreak _ lineHeight.\\n\\t\\tbaselineAtBreak _ baseline.\\n\\t].\\n\\n\\t\\\"It wasn't a space, but anyway this is where we break the line.\\\"\\n\\tline stop: breakableIndex.\\n\\tpresentationLine stop: breakableIndex.\\n\\tlineHeight _ lineHeightAtBreak.\\n\\tbaseline _ baselineAtBreak.\\n\\t^ true.\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'scanning' stamp: 'tak 12/22/2004 00:59'!\\nsetActualFont: aFont\\n\\t\\\"Keep track of max height and ascent for auto lineheight\\\"\\n\\t| descent |\\n\\tsuper setActualFont: aFont.\\n\\t\\\"' ', lastIndex printString, ' ' displayAt: (lastIndex * 15)@0.\\\"\\n\\tlineHeight == nil\\n\\t\\tifTrue: [descent _ font descent.\\n\\t\\t\\t\\tbaseline _ font ascent.\\n\\t\\t\\t\\tlineHeight _ baseline + descent]\\n\\t\\tifFalse: [descent _ lineHeight - baseline max: font descent.\\n\\t\\t\\t\\tbaseline _ baseline max: font ascent.\\n\\t\\t\\t\\tlineHeight _ lineHeight max: baseline + descent]! !\\n\\n\\n!MultiCompositionScanner methodsFor: 'stop conditions' stamp: 'yo 1/3/2003 11:56'!\\ncolumnBreak\\n\\n\\t\\\"Answer true. Set up values for the text line interval currently being \\n\\tcomposed.\\\"\\n\\n\\tline stop: lastIndex.\\n\\tpresentationLine stop: lastIndex - numOfComposition.\\n\\tspaceX _ destX.\\n\\tline paddingWidth: rightMargin - spaceX.\\n\\tpresentationLine paddingWidth: rightMargin - spaceX.\\n\\t^true! !\\n\\n!MultiCompositionScanner methodsFor: 'stop conditions' stamp: 'yo 1/3/2003 11:56'!\\ncr\\n\\t\\\"Answer true. Set up values for the text line interval currently being \\n\\tcomposed.\\\"\\n\\n\\tline stop: lastIndex.\\n\\tpresentationLine stop: lastIndex - numOfComposition.\\n\\tspaceX _ destX.\\n\\tline paddingWidth: rightMargin - spaceX.\\n\\tpresentationLine paddingWidth: rightMargin - spaceX.\\n\\t^true! !\\n\\n!MultiCompositionScanner methodsFor: 'stop conditions' stamp: 'yo 2/10/2004 23:03'!\\nendOfRun\\n\\t\\\"Answer true if scanning has reached the end of the paragraph. \\n\\tOtherwise step conditions (mostly install potential new font) and answer \\n\\tfalse.\\\"\\n\\n\\t| runLength |\\n\\tlastIndex = text size\\n\\tifTrue:\\t[line stop: lastIndex.\\n\\t\\t\\tpresentationLine stop: lastIndex - numOfComposition.\\n\\t\\t\\tspaceX _ destX.\\n\\t\\t\\tline paddingWidth: rightMargin - destX.\\n\\t\\t\\tpresentationLine paddingWidth: rightMargin - destX.\\n\\t\\t\\t^true]\\n\\tifFalse:\\t[\\n\\t\\t\\t\\\"(text at: lastIndex) charCode = 32 ifTrue: [destX _ destX + spaceWidth].\\\"\\n\\t\\t\\trunLength _ (text runLengthFor: (lastIndex _ lastIndex + 1)).\\n\\t\\t\\trunStopIndex _ lastIndex + (runLength - 1).\\n\\t\\t\\tself setStopConditions.\\n\\t\\t\\t^false]\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'stop conditions' stamp: 'yo 1/3/2003 11:56'!\\nplaceEmbeddedObject: anchoredMorph\\n\\t| descent |\\n\\t\\\"Workaround: The following should really use #textAnchorType\\\"\\n\\tanchoredMorph relativeTextAnchorPosition ifNotNil:[^true].\\n\\t(super placeEmbeddedObject: anchoredMorph) ifFalse: [\\\"It doesn't fit\\\"\\n\\t\\t\\\"But if it's the first character then leave it here\\\"\\n\\t\\tlastIndex < line first ifFalse:[\\n\\t\\t\\tline stop: lastIndex-1.\\n\\t\\t\\t^ false]].\\n\\tdescent _ lineHeight - baseline.\\n\\tlineHeight _ lineHeight max: anchoredMorph height.\\n\\tbaseline _ lineHeight - descent.\\n\\tline stop: lastIndex.\\n\\tpresentationLine stop: lastIndex - numOfComposition.\\n\\t^ true! !\\n\\n!MultiCompositionScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 21:47'!\\nsetFont\\n\\tsuper setFont.\\n\\tbreakAtSpace _ false.\\n\\twantsColumnBreaks == true ifTrue: [\\n\\t\\tstopConditions _ stopConditions copy.\\n\\t\\tstopConditions at: TextComposer characterForColumnBreak asciiValue + 1 put: #columnBreak.\\n\\t].\\n! !\\n\\n!MultiCompositionScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:57'!\\nsetStopConditions\\n\\t\\\"Set the font and the stop conditions for the current run.\\\"\\n\\t\\n\\tself setFont! !\\n\\n!MultiCompositionScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:57'!\\ntab\\n\\t\\\"Advance destination x according to tab settings in the paragraph's \\n\\ttextStyle. Answer whether the character has crossed the right edge of \\n\\tthe composition rectangle of the paragraph.\\\"\\n\\n\\tdestX _ textStyle\\n\\t\\t\\t\\tnextTabXFrom: destX leftMargin: leftMargin rightMargin: rightMargin.\\n\\tdestX > rightMargin ifTrue:\\t[^self crossedX].\\n\\tlastIndex _ lastIndex + 1.\\n\\t^false\\n! !\\nMultiCharacterScanner subclass: #MultiDisplayScanner\\n\\tinstanceVariableNames: 'bitBlt lineY runX foregroundColor backgroundColor fillBlt lineHeight paragraph paragraphColor morphicOffset ignoreColorChanges'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-Scanning'!\\n\\n!MultiDisplayScanner methodsFor: 'MVC-compatibility' stamp: 'yo 1/7/2005 12:15'!\\ndisplayLines: linesInterval in: aParagraph clippedBy: visibleRectangle\\n\\t\\\"The central display routine. The call on the primitive \\n\\t(scanCharactersFrom:to:in:rightX:) will be interrupted according to an \\n\\tarray of stop conditions passed to the scanner at which time the code to \\n\\thandle the stop condition is run and the call on the primitive continued \\n\\tuntil a stop condition returns true (which means the line has \\n\\tterminated).\\\"\\n\\t| runLength done stopCondition leftInRun startIndex string lastPos |\\n\\t\\\"leftInRun is the # of characters left to scan in the current run;\\n\\t\\twhen 0, it is time to call 'self setStopConditions'\\\"\\n\\tmorphicOffset _ 0@0.\\n\\tleftInRun _ 0.\\n\\tself initializeFromParagraph: aParagraph clippedBy: visibleRectangle.\\n\\tignoreColorChanges _ false.\\n\\tparagraph _ aParagraph.\\n\\tforegroundColor _ paragraphColor _ aParagraph foregroundColor.\\n\\tbackgroundColor _ aParagraph backgroundColor.\\n\\taParagraph backgroundColor isTransparent\\n\\t\\tifTrue: [fillBlt _ nil]\\n\\t\\tifFalse: [fillBlt _ bitBlt copy. \\\"Blt to fill spaces, tabs, margins\\\"\\n\\t\\t\\t\\tfillBlt sourceForm: nil; sourceOrigin: 0@0.\\n\\t\\t\\t\\tfillBlt fillColor: aParagraph backgroundColor].\\n\\trightMargin _ aParagraph rightMarginForDisplay.\\n\\tlineY _ aParagraph topAtLineIndex: linesInterval first.\\n\\tbitBlt destForm deferUpdatesIn: visibleRectangle while: [\\n\\t\\tlinesInterval do: \\n\\t\\t\\t[:lineIndex | \\n\\t\\t\\tleftMargin _ aParagraph leftMarginForDisplayForLine: lineIndex alignment: (alignment ifNil:[textStyle alignment]).\\n\\t\\t\\tdestX _ (runX _ leftMargin).\\n\\t\\t\\tline _ aParagraph lines at: lineIndex.\\n\\t\\t\\tlineHeight _ line lineHeight.\\n\\t\\t\\tfillBlt == nil ifFalse:\\n\\t\\t\\t\\t[fillBlt destX: visibleRectangle left destY: lineY\\n\\t\\t\\t\\t\\twidth: visibleRectangle width height: lineHeight; copyBits].\\n\\t\\t\\tlastIndex _ line first.\\n\\t\\t\\tleftInRun <= 0\\n\\t\\t\\t\\tifTrue: [self setStopConditions. \\\"also sets the font\\\"\\n\\t\\t\\t\\t\\t\\tleftInRun _ text runLengthFor: line first].\\n\\t\\t\\tbaselineY _ lineY + line baseline.\\n\\t\\t\\tdestY _ baselineY - font ascent. \\\"Should have happened in setFont\\\"\\n\\t\\t\\trunLength _ leftInRun.\\n\\t\\t\\trunStopIndex _ lastIndex + (runLength - 1) min: line last.\\n\\t\\t\\tleftInRun _ leftInRun - (runStopIndex - lastIndex + 1).\\n\\t\\t\\tspaceCount _ 0.\\n\\t\\t\\tdone _ false.\\n\\t\\t\\tstring _ text string.\\n\\t\\t\\tself handleIndentation.\\n\\t\\t\\t[done] whileFalse:[\\n\\t\\t\\t\\tstartIndex _ lastIndex.\\n\\t\\t\\t\\tlastPos _ destX@destY.\\n\\t\\t\\t\\tstopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex\\n\\t\\t\\t\\t\\t\\t\\tin: string rightX: rightMargin stopConditions: stopConditions\\n\\t\\t\\t\\t\\t\\t\\tkern: kern.\\n\\t\\t\\t\\tlastIndex >= startIndex ifTrue:[\\n\\t\\t\\t\\t\\tfont displayString: string on: bitBlt \\n\\t\\t\\t\\t\\t\\tfrom: startIndex to: lastIndex at: lastPos kern: kern baselineY: baselineY].\\n\\t\\t\\t\\t\\\"see setStopConditions for stopping conditions for displaying.\\\"\\n\\t\\t\\t\\tdone _ self perform: stopCondition].\\n\\t\\t\\tfillBlt == nil ifFalse:\\n\\t\\t\\t\\t[fillBlt destX: destX destY: lineY width: visibleRectangle right-destX height: lineHeight; copyBits].\\n\\t\\t\\tlineY _ lineY + lineHeight]]! !\\n\\n!MultiDisplayScanner methodsFor: 'MVC-compatibility' stamp: 'yo 3/14/2005 06:48'!\\ninitializeFromParagraph: aParagraph clippedBy: clippingRectangle\\n\\n\\tsuper initializeFromParagraph: aParagraph clippedBy: clippingRectangle.\\n\\tbitBlt _ BitBlt asGrafPort toForm: aParagraph destinationForm.\\n\\tbitBlt sourceX: 0; width: 0.\\t\\\"Init BitBlt so that the first call to a primitive will not fail\\\"\\n\\tbitBlt combinationRule: Form paint.\\n\\tbitBlt colorMap:\\n\\t\\t(Bitmap with: 0 \\\"Assumes 1-bit deep fonts\\\"\\n\\t\\t\\t\\twith: (bitBlt destForm pixelValueFor: aParagraph foregroundColor)).\\n\\tbitBlt clipRect: clippingRectangle.\\n! !\\n\\n\\n!MultiDisplayScanner methodsFor: 'multilingual scanning' stamp: 'yo 12/20/2002 11:52'!\\nisBreakableAt: index in: sourceString in: encodingClass\\n\\n\\t^ false.\\n! !\\n\\n!MultiDisplayScanner methodsFor: 'multilingual scanning' stamp: 'yo 8/6/2003 05:57'!\\nscanMultiCharactersCombiningFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta\\n\\n\\t| encoding f nextDestX maxAscii startEncoding char charValue |\\n\\tlastIndex _ startIndex.\\n\\tlastIndex > stopIndex ifTrue: [lastIndex _ stopIndex. ^ stops at: EndOfRun].\\n\\tstartEncoding _ (sourceString at: startIndex) leadingChar.\\n\\tfont ifNil: [font _ (TextConstants at: #DefaultMultiStyle) fontArray at: 1].\\n\\t((font isMemberOf: StrikeFontSet) or: [font isKindOf: TTCFontSet]) ifTrue: [\\n\\t\\t[f _ font fontArray at: startEncoding + 1]\\n\\t\\t\\ton: Exception do: [:ex | f _ font fontArray at: 1].\\n\\t\\tf ifNil: [ f _ font fontArray at: 1].\\n\\t\\tmaxAscii _ f maxAscii.\\n\\t\\tspaceWidth _ f widthOf: Space.\\n\\t] ifFalse: [\\n\\t\\tmaxAscii _ font maxAscii.\\n\\t].\\n\\n\\t[lastIndex <= stopIndex] whileTrue: [\\n\\t\\tencoding _ (sourceString at: lastIndex) leadingChar.\\n\\t\\tencoding ~= startEncoding ifTrue: [lastIndex _ lastIndex - 1. ^ stops at: EndOfRun].\\n\\t\\tchar _ (sourceString at: lastIndex).\\n\\t\\tcharValue _ char charCode.\\n\\t\\tcharValue > maxAscii ifTrue: [charValue _ maxAscii].\\n\\t\\t(encoding = 0 and: [(stopConditions at: charValue + 1) ~~ nil]) ifTrue: [\\n\\t\\t\\t^ stops at: charValue + 1\\n\\t\\t].\\n\\t\\tnextDestX _ destX + (self widthOf: char inFont: font).\\n\\t\\tnextDestX > rightX ifTrue: [^ stops at: CrossedX].\\n\\t\\tdestX _ nextDestX + kernDelta.\\n\\t\\tlastIndex _ lastIndex + 1.\\n\\t].\\n\\tlastIndex _ stopIndex.\\n\\t^ stops at: EndOfRun! !\\n\\n\\n!MultiDisplayScanner methodsFor: 'scanning' stamp: 'yo 1/7/2005 12:15'!\\ndisplayLine: textLine offset: offset leftInRun: leftInRun\\n\\t\\\"The call on the primitive (scanCharactersFrom:to:in:rightX:) will be interrupted according to an array of stop conditions passed to the scanner at which time the code to handle the stop condition is run and the call on the primitive continued until a stop condition returns true (which means the line has terminated). leftInRun is the # of characters left to scan in the current run; when 0, it is time to call setStopConditions.\\\"\\n\\t| done stopCondition nowLeftInRun startIndex string lastPos |\\n\\tline _ textLine.\\n\\tmorphicOffset _ offset.\\n\\tlineY _ line top + offset y.\\n\\tlineHeight _ line lineHeight.\\n\\trightMargin _ line rightMargin + offset x.\\n\\tlastIndex _ line first.\\n\\tleftInRun <= 0 ifTrue: [self setStopConditions].\\n\\tleftMargin _ (line leftMarginForAlignment: alignment) + offset x.\\n\\tdestX _ runX _ leftMargin.\\n\\tfillBlt == nil ifFalse:\\n\\t\\t[\\\"Not right\\\"\\n\\t\\tfillBlt destX: line left destY: lineY\\n\\t\\t\\twidth: line width left height: lineHeight; copyBits].\\n\\tlastIndex _ line first.\\n\\tleftInRun <= 0\\n\\t\\tifTrue: [nowLeftInRun _ text runLengthFor: lastIndex]\\n\\t\\tifFalse: [nowLeftInRun _ leftInRun].\\n\\tbaselineY _ lineY + line baseline.\\n\\tdestY _ baselineY - font ascent.\\n\\trunStopIndex _ lastIndex + (nowLeftInRun - 1) min: line last.\\n\\tspaceCount _ 0.\\n\\tdone _ false.\\n\\tstring _ text string.\\n\\t[done] whileFalse:[\\n\\t\\tstartIndex _ lastIndex.\\n\\t\\tlastPos _ destX@destY.\\n\\t\\tstopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex\\n\\t\\t\\t\\t\\t\\tin: string rightX: rightMargin stopConditions: stopConditions\\n\\t\\t\\t\\t\\t\\tkern: kern.\\n\\t\\tlastIndex >= startIndex ifTrue:[\\n\\t\\t\\tfont displayString: string on: bitBlt \\n\\t\\t\\t\\tfrom: startIndex to: lastIndex at: lastPos kern: kern baselineY: baselineY].\\n\\t\\t\\\"see setStopConditions for stopping conditions for displaying.\\\"\\n\\t\\tdone _ self perform: stopCondition.\\n\\t\\t\\\"lastIndex > runStopIndex ifTrue: [done _ true].\\\"\\n\\t].\\n\\t^ runStopIndex - lastIndex \\\"Number of characters remaining in the current run\\\"! !\\n\\n!MultiDisplayScanner methodsFor: 'scanning' stamp: 'lr 1/21/2006 16:01'!\\nplaceEmbeddedObject: anchoredMorph\\n\\tanchoredMorph relativeTextAnchorPosition ifNotNil:[\\n\\t\\tanchoredMorph position: \\n\\t\\t\\tanchoredMorph relativeTextAnchorPosition +\\n\\t\\t\\t(anchoredMorph owner textBounds origin x @ 0)\\n\\t\\t\\t- (0@morphicOffset y) + (0@lineY).\\n\\t\\t^true\\n\\t].\\n\\t(super placeEmbeddedObject: anchoredMorph) ifFalse: [^ false].\\n\\tanchoredMorph isMorph ifTrue: [\\n\\t\\tanchoredMorph position: ((destX - anchoredMorph width)@lineY) - morphicOffset\\n\\t] ifFalse: [\\n\\t\\tdestY _ lineY.\\n\\t\\tbaselineY _ lineY + anchoredMorph height..\\n\\t\\trunX _ destX.\\n\\t\\tanchoredMorph \\n\\t\\t\\tdisplayOn: bitBlt destForm \\n\\t\\t\\tat: destX - anchoredMorph width @ destY\\n\\t\\t\\tclippingBox: bitBlt clipRect\\n\\t\\t\\trule: Form blend\\n\\t\\t\\tfillColor: Color white \\n\\t].\\n\\t^ true! !\\n\\n\\n!MultiDisplayScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:58'!\\ncr\\n\\t\\\"When a carriage return is encountered, simply increment the pointer \\n\\tinto the paragraph.\\\"\\n\\n\\tlastIndex_ lastIndex + 1.\\n\\t^false! !\\n\\n!MultiDisplayScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:58'!\\ncrossedX\\n\\t\\\"This condition will sometimes be reached 'legally' during display, when, \\n\\tfor instance the space that caused the line to wrap actually extends over \\n\\tthe right boundary. This character is allowed to display, even though it \\n\\tis technically outside or straddling the clipping ectangle since it is in \\n\\tthe normal case not visible and is in any case appropriately clipped by \\n\\tthe scanner.\\\"\\n\\n\\t^ true ! !\\n\\n!MultiDisplayScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:58'!\\nendOfRun\\n\\t\\\"The end of a run in the display case either means that there is actually \\n\\ta change in the style (run code) to be associated with the string or the \\n\\tend of this line has been reached.\\\"\\n\\t| runLength |\\n\\tlastIndex = line last ifTrue: [^true].\\n\\trunX _ destX.\\n\\trunLength _ text runLengthFor: (lastIndex _ lastIndex + 1).\\n\\trunStopIndex _ lastIndex + (runLength - 1) min: line last.\\n\\tself setStopConditions.\\n\\t^ false! !\\n\\n!MultiDisplayScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:58'!\\npaddedSpace\\n\\t\\\"Each space is a stop condition when the alignment is right justified. \\n\\tPadding must be added to the base width of the space according to \\n\\twhich space in the line this space is and according to the amount of \\n\\tspace that remained at the end of the line when it was composed.\\\"\\n\\n\\tspaceCount _ spaceCount + 1.\\n\\tdestX _ destX + spaceWidth + (line justifiedPadFor: spaceCount).\\n\\tlastIndex _ lastIndex + 1.\\n\\t^ false! !\\n\\n!MultiDisplayScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:58'!\\nplainTab\\n\\t| oldX |\\n\\toldX _ destX.\\n\\tsuper plainTab.\\n\\tfillBlt == nil ifFalse:\\n\\t\\t[fillBlt destX: oldX destY: destY width: destX - oldX height: font height; copyBits]! !\\n\\n!MultiDisplayScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:58'!\\nsetStopConditions\\n\\t\\\"Set the font and the stop conditions for the current run.\\\"\\n\\t\\n\\tself setFont.\\n\\tself setConditionArray: (alignment = Justified ifTrue: [#paddedSpace]).\\n\\n\\\"\\n\\talignment = Justified ifTrue: [\\n\\t\\tstopConditions == DefaultStopConditions \\n\\t\\t\\tifTrue:[stopConditions _ stopConditions copy].\\n\\t\\tstopConditions at: Space asciiValue + 1 put: #paddedSpace]\\n\\\"! !\\n\\n!MultiDisplayScanner methodsFor: 'stop conditions' stamp: 'yo 12/18/2002 13:58'!\\ntab\\n\\tself plainTab.\\n\\tlastIndex _ lastIndex + 1.\\n\\t^ false! !\\n\\n\\n!MultiDisplayScanner methodsFor: 'private' stamp: 'yo 1/23/2003 14:40'!\\npresentationText: t\\n\\n\\ttext _ t.\\n! !\\n\\n!MultiDisplayScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:58'!\\nsetDestForm: df\\n\\tbitBlt setDestForm: df.! !\\n\\n!MultiDisplayScanner methodsFor: 'private' stamp: 'yo 1/6/2005 23:06'!\\nsetFont \\n\\tforegroundColor _ paragraphColor.\\n\\tsuper setFont. \\\"Sets font and emphasis bits, and maybe foregroundColor\\\"\\n\\tfont installOn: bitBlt foregroundColor: foregroundColor backgroundColor: Color transparent.\\n\\ttext ifNotNil:[\\n\\t\\tbaselineY _ lineY + line baseline.\\n\\t\\tdestY _ baselineY - font ascent].\\n! !\\n\\n!MultiDisplayScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:58'!\\nsetPort: aBitBlt\\n\\t\\\"Install the BitBlt to use\\\"\\n\\tbitBlt _ aBitBlt.\\n\\tbitBlt sourceX: 0; width: 0.\\t\\\"Init BitBlt so that the first call to a primitive will not fail\\\"\\n\\tbitBlt sourceForm: nil. \\\"Make sure font installation won't be confused\\\"\\n! !\\n\\n!MultiDisplayScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:58'!\\ntext: t textStyle: ts foreground: foreColor background: backColor fillBlt: blt ignoreColorChanges: shadowMode\\n\\ttext _ t.\\n\\ttextStyle _ ts. \\n\\tforegroundColor _ paragraphColor _ foreColor.\\n\\t(backgroundColor _ backColor) isTransparent ifFalse:\\n\\t\\t[fillBlt _ blt.\\n\\t\\tfillBlt fillColor: backgroundColor].\\n\\tignoreColorChanges _ shadowMode! !\\n\\n!MultiDisplayScanner methodsFor: 'private' stamp: 'yo 12/18/2002 13:58'!\\ntextColor: textColor\\n\\tignoreColorChanges ifTrue: [^ self].\\n\\tforegroundColor _ textColor! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMultiDisplayScanner class\\n\\tinstanceVariableNames: ''!\\n\\n!MultiDisplayScanner class methodsFor: 'queries' stamp: 'yo 12/18/2002 13:58'!\\ndefaultFont\\n\\t^ TextStyle defaultFont! !\\nNewParagraph subclass: #MultiNewParagraph\\n\\tinstanceVariableNames: 'presentationText presentationLines'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: 'TextConstants'\\n\\tcategory: 'Multilingual-Scanning'!\\n\\n!MultiNewParagraph methodsFor: 'as yet unclassified' stamp: 'yo 1/23/2003 16:09'!\\ndisplayOn: aCanvas using: displayScanner at: somePosition\\n\\t\\\"Send all visible lines to the displayScanner for display\\\"\\n\\n\\t| visibleRectangle offset leftInRun line |\\n\\tvisibleRectangle _ aCanvas clipRect.\\n\\toffset _ somePosition - positionWhenComposed.\\n\\tleftInRun _ 0.\\n\\t(self lineIndexForPoint: visibleRectangle topLeft)\\n\\t\\tto: (self lineIndexForPoint: visibleRectangle bottomRight)\\n\\t\\tdo: [:i | line _ lines at: i.\\n\\t\\t\\tself displaySelectionInLine: line on: aCanvas.\\n\\t\\t\\tline first <= line last ifTrue:\\n\\t\\t\\t\\t[leftInRun _ displayScanner displayLine: line\\n\\t\\t\\t\\t\\t\\t\\t\\toffset: offset leftInRun: leftInRun]].\\n! !\\n\\n!MultiNewParagraph methodsFor: 'as yet unclassified' stamp: 'yo 1/23/2003 22:33'!\\ndisplayOnTest: aCanvas using: displayScanner at: somePosition\\n\\t\\\"Send all visible lines to the displayScanner for display\\\"\\n\\n\\t| visibleRectangle offset leftInRun line |\\n\\t(presentationText isNil or: [presentationLines isNil]) ifTrue: [\\n\\t\\t^ self displayOn: aCanvas using: displayScanner at: somePosition.\\n\\t].\\n\\tvisibleRectangle _ aCanvas clipRect.\\n\\toffset _ somePosition - positionWhenComposed.\\n\\tleftInRun _ 0.\\n\\t(self lineIndexForPoint: visibleRectangle topLeft)\\n\\t\\tto: (self lineIndexForPoint: visibleRectangle bottomRight)\\n\\t\\tdo: [:i | line _ presentationLines at: i.\\n\\t\\t\\tself displaySelectionInLine: line on: aCanvas.\\n\\t\\t\\tline first <= line last ifTrue:\\n\\t\\t\\t\\t[leftInRun _ displayScanner displayLine: line\\n\\t\\t\\t\\t\\t\\t\\t\\toffset: offset leftInRun: leftInRun]].\\n! !\\n\\n!MultiNewParagraph methodsFor: 'as yet unclassified' stamp: 'yo 1/23/2003 12:53'!\\nmultiComposeLinesFrom: start to: stop delta: delta into: lineColl priorLines: priorLines\\n\\tatY: startingY\\n\\t\\\"While the section from start to stop has changed, composition may ripple all the way to the end of the text. However in a rectangular container, if we ever find a line beginning with the same character as before (ie corresponding to delta in the old lines), then we can just copy the old lines from there to the end of the container, with adjusted indices and y-values\\\"\\n\\n\\t| newResult composer presentationInfo |\\n\\n\\tcomposer _ MultiTextComposer new.\\n\\tpresentationLines _ nil.\\n\\tpresentationText _ nil.\\n\\tnewResult _ composer\\n\\t\\tmultiComposeLinesFrom: start \\n\\t\\tto: stop \\n\\t\\tdelta: delta \\n\\t\\tinto: lineColl \\n\\t\\tpriorLines: priorLines\\n\\t\\tatY: startingY\\n\\t\\ttextStyle: textStyle \\n\\t\\ttext: text \\n\\t\\tcontainer: container\\n\\t\\twantsColumnBreaks: wantsColumnBreaks == true.\\n\\tlines _ newResult first asArray.\\n\\tmaxRightX _ newResult second.\\n\\tpresentationInfo _ composer getPresentationInfo.\\n\\tpresentationLines _ presentationInfo first asArray.\\n\\tpresentationText _ presentationInfo second.\\n\\t\\\"maxRightX printString displayAt: 0@0.\\\"\\n\\t^maxRightX\\n! !\\n\\n!MultiNewParagraph methodsFor: 'as yet unclassified' stamp: 'yo 1/23/2003 17:31'!\\npresentationLines\\n\\n\\t^ presentationLines.\\n! !\\n\\n!MultiNewParagraph methodsFor: 'as yet unclassified' stamp: 'yo 1/23/2003 17:31'!\\npresentationText\\n\\n\\t^ presentationText.\\n! !\\nFormCanvas subclass: #MultiResolutionCanvas\\n\\tinstanceVariableNames: 'deferredMorphs'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Support'!\\n\\n!MultiResolutionCanvas methodsFor: 'as yet unclassified' stamp: 'RAA 12/4/2000 12:00'!\\ndeferredMorphs\\n\\n\\t^deferredMorphs! !\\n\\n!MultiResolutionCanvas methodsFor: 'as yet unclassified' stamp: 'RAA 12/4/2000 11:58'!\\ndeferredMorphs: aCollection\\n\\n\\tdeferredMorphs _ aCollection! !\\n\\n!MultiResolutionCanvas methodsFor: 'as yet unclassified' stamp: 'RAA 12/17/2000 13:25'!\\ninitializeFrom: aFormCanvas\\n\\n\\torigin _ aFormCanvas origin.\\n\\tclipRect _ aFormCanvas privateClipRect.\\n\\tform _ aFormCanvas form.\\n\\tport _ aFormCanvas privatePort.\\n\\tshadowColor _ aFormCanvas shadowColor.\\n! !\\n\\n\\n!MultiResolutionCanvas methodsFor: 'drawing-general' stamp: 'RAA 12/4/2000 12:00'!\\nfullDraw: aMorph\\n\\n\\taMorph canDrawAtHigherResolution ifTrue: [\\n\\t\\tdeferredMorphs ifNil: [deferredMorphs _ OrderedCollection new].\\n\\t\\tdeferredMorphs add: aMorph.\\n\\t] ifFalse: [\\n\\t\\tsuper fullDraw: aMorph\\n\\t].! !\\nTTCFont subclass: #MultiTTCFont\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-Display'!\\n\\n!MultiTTCFont methodsFor: 'as yet unclassified' stamp: 'yo 12/10/2002 18:08'!\\naccess: char at: index\\n\\n\\t| wcache entry |\\n\\twcache _ self cache.\\n\\tentry _ wcache at: index.\\n\\twcache replaceFrom: index to: wcache size - 1 with: wcache startingAt: index + 1.\\n\\twcache at: wcache size put: entry.\\n! !\\n\\n!MultiTTCFont methodsFor: 'as yet unclassified' stamp: 'yo 12/10/2002 18:09'!\\nat: char put: form\\n\\n\\t| wcache |\\n\\twcache _ self cache.\\n\\twcache replaceFrom: 1 to: wcache size - 1 with: wcache startingAt: 2.\\n\\twcache at: wcache size\\n\\t\\tput: (Array with: char asciiValue with: foregroundColor with: form).\\n! !\\n\\n!MultiTTCFont methodsFor: 'as yet unclassified' stamp: 'yo 12/10/2002 18:27'!\\nflushCache\\n\\n\\tcache at: 1 put: ((1 to: 128) collect: [:i | Array with: -1 with: nil with: nil]).\\n! !\\n\\n!MultiTTCFont methodsFor: 'as yet unclassified' stamp: 'yo 12/10/2002 21:04'!\\nformOf: char\\n\\n\\t| newForm |\\n\\tself hasCached: char ifTrue: [:form :index |\\n\\t\\tself access: char at: index.\\n\\t\\t^ form.\\n\\t].\\n\\n\\tnewForm _ self computeForm: char.\\n\\tself at: char put: newForm.\\n\\t^ newForm.\\n! !\\n\\n!MultiTTCFont methodsFor: 'as yet unclassified' stamp: 'yo 1/7/2005 11:09'!\\nglyphInfoOf: char into: glyphInfoArray\\n\\n\\t| newForm |\\n\\tself hasCached: char ifTrue: [:form :index |\\n\\t\\tself access: char at: index.\\n\\t\\tglyphInfoArray at: 1 put: form;\\n\\t\\t\\tat: 2 put: 0;\\n\\t\\t\\tat: 3 put: form width;\\n\\t\\t\\tat: 4 put: (self ascentOf: char);\\n\\t\\t\\tat: 5 put: self.\\n\\t\\t^ glyphInfoArray.\\n\\t].\\n\\n\\tnewForm _ self computeForm: char.\\n\\tself at: char put: newForm.\\n\\n\\tglyphInfoArray at: 1 put: newForm;\\n\\t\\tat: 2 put: 0;\\n\\t\\tat: 3 put: newForm width;\\n\\t\\tat: 4 put: (self ascentOf: char);\\n\\t\\tat: 5 put: self.\\n\\t^ glyphInfoArray.\\n! !\\n\\n!MultiTTCFont methodsFor: 'as yet unclassified' stamp: 'yo 12/10/2002 18:39'!\\nhasCached: char ifTrue: twoArgBlock\\n\\n\\t| value elem |\\n\\tvalue _ char asciiValue.\\n\\n\\tself cache size to: 1 by: -1 do: [:i |\\n\\t\\telem _ self cache at: i.\\n\\t\\t(elem first = value and: [elem second = foregroundColor]) ifTrue: [\\n\\t\\t\\t^ twoArgBlock value: elem third value: i.\\n\\t\\t].\\n\\t].\\n\\t^ false.\\n! !\\n\\n!MultiTTCFont methodsFor: 'as yet unclassified' stamp: 'yo 12/29/2003 15:01'!\\nisTTCFont\\n\\t^true! !\\n\\n!MultiTTCFont methodsFor: 'as yet unclassified' stamp: 'yo 12/10/2002 18:30'!\\nwidthOf: char\\n\\n\\t\\\"This method cannot use #formOf: because formOf: discriminates the color and causes unnecessary bitmap creation.\\\"\\n\\n\\t| newForm |\\n\\tself hasCached: char ifTrue: [:form :index |\\n\\t\\tself access: char at: index.\\n\\t\\t^ form width.\\n\\t].\\n\\n\\tnewForm _ self computeForm: char.\\n\\tself at: char put: newForm.\\n\\t^ newForm width.\\n\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMultiTTCFont class\\n\\tinstanceVariableNames: ''!\\n\\n!MultiTTCFont class methodsFor: 'as yet unclassified' stamp: 'yo 12/10/2002 18:34'!\\ncacheAllNil\\n\\\"\\n\\tself cacheAllNil\\n\\\"\\n\\tself allInstances do: [:inst |\\n\\t\\tinst cache do: [:e |\\n\\t\\t\\te third ifNotNil: [^ false].\\n\\t\\t].\\n\\t].\\n\\n\\t^ true.\\n! !\\nTextComposer subclass: #MultiTextComposer\\n\\tinstanceVariableNames: 'presentation presentationLines'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: 'TextConstants'\\n\\tcategory: 'Multilingual-Scanning'!\\n\\n!MultiTextComposer methodsFor: 'as yet unclassified' stamp: 'yo 1/23/2003 12:53'!\\ncomposeEachRectangleIn: rectangles\\n\\n\\t| myLine lastChar |\\n\\n\\t1 to: rectangles size do: [:i | \\n\\t\\tcurrCharIndex <= theText size ifFalse: [^false].\\n\\t\\tmyLine _ scanner \\n\\t\\t\\tcomposeFrom: currCharIndex \\n\\t\\t\\tinRectangle: (rectangles at: i)\\t\\t\\t\\t\\n\\t\\t\\tfirstLine: isFirstLine \\n\\t\\t\\tleftSide: i=1 \\n\\t\\t\\trightSide: i=rectangles size.\\n\\t\\tlines addLast: myLine.\\n\\t\\tpresentationLines addLast: scanner getPresentationLine.\\n\\t\\tpresentation ifNil: [presentation _ scanner getPresentation]\\n\\t\\t\\tifNotNil: [presentation _ presentation, scanner getPresentation].\\n\\t\\tactualHeight _ actualHeight max: myLine lineHeight. \\\"includes font changes\\\"\\n\\t\\tcurrCharIndex _ myLine last + 1.\\n\\t\\tlastChar _ theText at: myLine last.\\n\\t\\tlastChar = Character cr ifTrue: [^#cr].\\n\\t\\twantsColumnBreaks ifTrue: [\\n\\t\\t\\tlastChar = TextComposer characterForColumnBreak ifTrue: [^#columnBreak].\\n\\t\\t].\\n\\t].\\n\\t^false! !\\n\\n!MultiTextComposer methodsFor: 'as yet unclassified' stamp: 'yo 1/23/2003 12:53'!\\ngetPresentationInfo\\n\\n\\t^ Array with: presentationLines with: presentation.\\n! !\\n\\n!MultiTextComposer methodsFor: 'as yet unclassified' stamp: 'yo 1/16/2003 17:30'!\\nmultiComposeLinesFrom: argStart to: argStop delta: argDelta into: argLinesCollection priorLines: argPriorLines atY: argStartY textStyle: argTextStyle text: argText container: argContainer wantsColumnBreaks: argWantsColumnBreaks\\n\\n\\twantsColumnBreaks _ argWantsColumnBreaks.\\n\\tlines _ argLinesCollection.\\n\\tpresentationLines _ argLinesCollection copy.\\n\\ttheTextStyle _ argTextStyle.\\n\\ttheText _ argText.\\n\\ttheContainer _ argContainer.\\n\\tdeltaCharIndex _ argDelta.\\n\\tcurrCharIndex _ startCharIndex _ argStart.\\n\\tstopCharIndex _ argStop.\\n\\tprevLines _ argPriorLines.\\n\\tcurrentY _ argStartY.\\n\\tdefaultLineHeight _ theTextStyle lineGrid.\\n\\tmaxRightX _ theContainer left.\\n\\tpossibleSlide _ stopCharIndex < theText size and: [theContainer isMemberOf: Rectangle].\\n\\tnowSliding _ false.\\n\\tprevIndex _ 1.\\n\\tscanner _ MultiCompositionScanner new text: theText textStyle: theTextStyle.\\n\\tscanner wantsColumnBreaks: wantsColumnBreaks.\\n\\tisFirstLine _ true.\\n\\tself composeAllLines.\\n\\tisFirstLine ifTrue: [\\\"No space in container or empty text\\\"\\n\\t\\tself \\n\\t\\t\\taddNullLineWithIndex: startCharIndex\\n\\t\\t\\tandRectangle: (theContainer topLeft extent: 0@defaultLineHeight)\\n\\t] ifFalse: [\\n\\t\\tself fixupLastLineIfCR\\n\\t].\\n\\t^{lines asArray. maxRightX}\\n\\n! !\\nLazyListMorph subclass: #MulticolumnLazyListMorph\\n\\tinstanceVariableNames: 'columnWidths'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Widgets'!\\n!MulticolumnLazyListMorph commentStamp: '<historical>' prior: 0!\\nA variant of LazyListMorph that can display multi-column lists.!\\n\\n\\n!MulticolumnLazyListMorph methodsFor: 'as yet unclassified' stamp: 'ls 5/17/2001 21:23'!\\ngetListItem: index\\n\\t^listSource getListRow: index! !\\n\\n!MulticolumnLazyListMorph methodsFor: 'as yet unclassified' stamp: 'ls 5/18/2001 16:43'!\\nlistChanged\\n\\tcolumnWidths := nil.\\n\\tsuper listChanged! !\\n\\n\\n!MulticolumnLazyListMorph methodsFor: 'drawing' stamp: 'nk 1/10/2004 16:19'!\\ndisplay: items atRow: row on: canvas \\n\\t\\\"display the specified item, which is on the specified row; for Multicolumn \\n\\tlists, items will be a list of strings\\\"\\n\\t| drawBounds |\\n\\tdrawBounds := self drawBoundsForRow: row.\\n\\tdrawBounds := drawBounds intersect: self bounds.\\n\\titems\\n\\t\\twith: (1 to: items size)\\n\\t\\tdo: [:item :index | \\n\\t\\t\\t\\\"move the bounds to the right at each step\\\"\\n\\t\\t\\tindex > 1\\n\\t\\t\\t\\tifTrue: [drawBounds := drawBounds left: drawBounds left + 6\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t+ (columnWidths at: index - 1)].\\n\\t\\t\\titem isText\\n\\t\\t\\t\\tifTrue: [canvas\\n\\t\\t\\t\\t\\t\\tdrawString: item\\n\\t\\t\\t\\t\\t\\tin: drawBounds\\n\\t\\t\\t\\t\\t\\tfont: (font\\n\\t\\t\\t\\t\\t\\t\\t\\temphasized: (item emphasisAt: 1))\\n\\t\\t\\t\\t\\t\\tcolor: (self colorForRow: row)]\\n\\t\\t\\t\\tifFalse: [canvas\\n\\t\\t\\t\\t\\t\\tdrawString: item\\n\\t\\t\\t\\t\\t\\tin: drawBounds\\n\\t\\t\\t\\t\\t\\tfont: font\\n\\t\\t\\t\\t\\t\\tcolor: (self colorForRow: row)]]! !\\n\\n!MulticolumnLazyListMorph methodsFor: 'drawing' stamp: 'ls 5/17/2001 21:58'!\\ndrawOn: aCanvas\\n self getListSize = 0 ifTrue:[ ^self ].\\n\\n self setColumnWidthsFor: aCanvas.\\n\\n super drawOn: aCanvas! !\\n\\n!MulticolumnLazyListMorph methodsFor: 'drawing' stamp: 'sps 3/23/2004 15:51'!\\nsetColumnWidthsFor: aCanvas\\n | row topRow bottomRow |\\n \\\"set columnWidths for drawing on the specified canvas\\\"\\n\\t\\tcolumnWidths ifNil: [\\n\\t\\tcolumnWidths := (self item: 1) collect: [ :ignored | 0 ]. ].\\n\\ttopRow := (self topVisibleRowForCanvas: aCanvas) max: 1.\\n\\tbottomRow := (self bottomVisibleRowForCanvas: aCanvas) max: 1.\\n\\ttopRow > bottomRow ifTrue: [ ^ self ].\\n\\ttopRow to: bottomRow do: [ :rowIndex |\\n row := self item: rowIndex.\\n columnWidths := columnWidths with: row collect: [ :currentWidth :item |\\n\\t\\t\\t\\t| widthOfItem |\\n\\t\\t\\t\\twidthOfItem := (font widthOfStringOrText: item).\\n\\t\\t\\t\\twidthOfItem > currentWidth\\n\\t\\t\\t\\t\\tifTrue: [ self changed. widthOfItem ]\\n\\t\\t\\t\\t\\tifFalse: [ currentWidth ] ] ]! !\\n\\n\\n!MulticolumnLazyListMorph methodsFor: 'scroll range' stamp: 'sps 4/2/2004 12:16'!\\nhUnadjustedScrollRange\\n\\\"multi column list morphs don't use hScrollbars\\\"\\n\\n\\t^0\\n\\n! !\\n\\n!MulticolumnLazyListMorph methodsFor: 'scroll range' stamp: 'ls 4/17/2004 12:21'!\\nwidthToDisplayItem: item\\n\\t| widths |\\n\\twidths := item collect: [ :each | super widthToDisplayItem: each ].\\n\\t^widths sum + (10 * (widths size - 1)) \\\"add in space between the columns\\\"\\n! !\\nSketchMorph subclass: #MultiuserTinyPaint\\n\\tinstanceVariableNames: 'drawState'\\n\\tclassVariableNames: 'LastMouseIndex PenColorIndex PenIndex PenSizeIndex'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-AdditionalWidgets'!\\n!MultiuserTinyPaint commentStamp: '<historical>' prior: 0!\\nA very simple paint program that handles multiple users (hands).\\nEach user has their own brush size and color.\\n!\\n\\n\\n!MultiuserTinyPaint methodsFor: 'event handling' stamp: 'jm 11/4/97 07:15'!\\nhandlesMouseDown: evt\\n\\n\\t^ true\\n! !\\n\\n!MultiuserTinyPaint methodsFor: 'event handling' stamp: 'jm 11/4/97 07:15'!\\nmouseDown: evt\\n\\n\\t| state |\\n\\t(drawState includesKey: evt hand) ifFalse: [self createDrawStateFor: evt hand].\\n\\tstate _ drawState at: evt hand.\\n\\tstate at: LastMouseIndex put: evt cursorPoint.\\n! !\\n\\n!MultiuserTinyPaint methodsFor: 'event handling' stamp: 'jm 11/4/97 07:15'!\\nmouseMove: evt\\n\\n\\t| state lastP p pen |\\n\\tstate _ drawState at: evt hand ifAbsent: [^ self].\\n\\tlastP _ state at: LastMouseIndex.\\n\\tp _ evt cursorPoint.\\n\\tp = lastP ifTrue: [^ self].\\n\\n\\tpen _ state at: PenIndex.\\n\\tpen drawFrom: lastP - bounds origin to: p - bounds origin.\\n\\tself invalidRect: (\\n\\t\\t((lastP min: p) - pen sourceForm extent) corner:\\n\\t\\t((lastP max: p) + pen sourceForm extent)).\\n\\tstate at: LastMouseIndex put: p.\\n! !\\n\\n\\n!MultiuserTinyPaint methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:29'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color veryVeryLightGray! !\\n\\n!MultiuserTinyPaint methodsFor: 'initialization' stamp: 'dgd 2/14/2003 21:52'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\t\\n\\tdrawState _ IdentityDictionary new.\\n\\tself clear! !\\n\\n\\n!MultiuserTinyPaint methodsFor: 'menu' stamp: 'dgd 8/30/2003 21:55'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\n\\tsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.\\n\\taCustomMenu add: 'clear' translated action: #clear.\\n\\taCustomMenu add: 'pen color' translated action: #setPenColor:.\\n\\taCustomMenu add: 'pen size' translated action: #setPenSize:.\\n\\\"\\taCustomMenu add: 'fill' translated action: #fill:.\\\"\\n! !\\n\\n!MultiuserTinyPaint methodsFor: 'menu' stamp: 'jm 11/4/97 07:15'!\\nbrushColor: aColor hand: hand\\n\\n\\t| state |\\n\\t(drawState includesKey: hand) ifFalse: [self createDrawStateFor: hand].\\n\\tstate _ drawState at: hand.\\n\\t(state at: PenIndex) color: aColor.\\n\\tstate at: PenColorIndex put: aColor.\\n! !\\n\\n!MultiuserTinyPaint methodsFor: 'menu' stamp: 'jm 11/4/97 07:15'!\\nclear\\n\\n\\t| newPen |\\n\\tself form: ((Form extent: 400@300 depth: 8) fillColor: color).\\n\\tdrawState do: [:state |\\n\\t\\tnewPen _ Pen newOnForm: originalForm.\\n\\t\\tnewPen roundNib: (state at: PenSizeIndex).\\n\\t\\tnewPen color: (state at: PenColorIndex).\\n\\t\\tstate at: PenIndex put: newPen].\\n! !\\n\\n!MultiuserTinyPaint methodsFor: 'menu' stamp: 'bf 1/5/2000 19:12'!\\nfill: evt\\n\\n\\t| state fillPt |\\n\\t(drawState includesKey: evt hand) ifFalse: [self createDrawStateFor: evt hand].\\n\\tstate _ drawState at: evt hand.\\n\\n\\tCursor blank show.\\n\\tCursor crossHair showWhile:\\n\\t\\t[fillPt _ Sensor waitButton - self position].\\n\\toriginalForm shapeFill: (state at: PenColorIndex) interiorPoint: fillPt.\\n\\tself changed.\\n! !\\n\\n!MultiuserTinyPaint methodsFor: 'menu' stamp: 'jm 9/26/97 14:47'!\\npenSize: anInteger hand: hand\\n\\n\\t| state |\\n\\t(drawState includesKey: hand) ifFalse: [self createDrawStateFor: hand].\\n\\tstate _ drawState at: hand.\\n\\tstate at: PenSizeIndex put: anInteger.\\n\\t(state at: PenIndex) roundNib: anInteger.\\n! !\\n\\n!MultiuserTinyPaint methodsFor: 'menu' stamp: 'ar 10/5/2000 18:52'!\\nsetPenColor: evt\\n\\t| state |\\n\\t(drawState includesKey: evt hand) ifFalse: [self createDrawStateFor: evt hand].\\n\\tstate _ drawState at: evt hand.\\n\\tself changeColorTarget: self selector: #brushColor:hand: originalColor: (state at: PenColorIndex) hand: evt hand! !\\n\\n!MultiuserTinyPaint methodsFor: 'menu' stamp: 'RAA 6/12/2000 09:07'!\\nsetPenSize: evt\\n\\n\\t| menu sizes |\\n\\tmenu _ MenuMorph new.\\n\\tsizes _ (0 to: 5), (6 to: 12 by: 2), (15 to: 40 by: 5).\\n\\tsizes do: [:w |\\n\\t\\tmenu add: w printString\\n\\t\\t\\ttarget: self\\n\\t\\t\\tselector: #penSize:hand:\\n\\t\\t\\targumentList: (Array with: w with: evt hand)].\\n\\n\\tmenu popUpEvent: evt in: self world! !\\n\\n\\n!MultiuserTinyPaint methodsFor: 'private' stamp: 'jm 11/4/97 07:15'!\\ncreateDrawStateFor: aHand\\n\\n\\t| pen state |\\n\\tpen _ Pen newOnForm: originalForm.\\n\\tstate _ Array new: 4.\\n\\tstate at: PenIndex put: pen.\\n\\tstate at: PenSizeIndex put: 3.\\n\\tstate at: PenColorIndex put: Color red.\\n\\tstate at: LastMouseIndex put: nil.\\n\\tdrawState at: aHand put: state.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMultiuserTinyPaint class\\n\\tinstanceVariableNames: ''!\\n\\n!MultiuserTinyPaint class methodsFor: 'class initialization' stamp: 'jm 11/4/97 07:15'!\\ninitialize\\n\\t\\\"MultiuserTinyPaint initialize\\\"\\n\\n\\t\\\"indices into the state array for a given hand\\\"\\n\\tPenIndex _ 1.\\n\\tPenSizeIndex _ 2.\\n\\tPenColorIndex _ 3.\\n\\tLastMouseIndex _ 4.\\n! !\\nObject subclass: #Mutex\\n\\tinstanceVariableNames: 'semaphore owner'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Processes'!\\n!Mutex commentStamp: '<historical>' prior: 0!\\nA Mutex is a light-weight MUTual EXclusion object being used when two or more processes need to access a shared resource concurrently. A Mutex grants ownership to a single process and will suspend any other process trying to aquire the mutex while in use. Waiting processes are granted access to the mutex in the order the access was requested.\\n\\nInstance variables:\\n\\tsemaphore\\t<Semaphore>\\t\\tThe (primitive) semaphore used for synchronization.\\n\\towner\\t\\t<Process>\\t\\tThe process owning the mutex.!\\n\\n\\n!Mutex methodsFor: 'initialize' stamp: 'das 11/3/2005 22:53'!\\ninitialize\\n\\tsemaphore := Semaphore forMutualExclusion.! !\\n\\n\\n!Mutex methodsFor: 'mutual exclusion' stamp: 'das 11/3/2005 22:53'!\\ncritical: aBlock\\n\\t\\\"Evaluate aBlock protected by the receiver.\\\"\\n\\t| activeProcess |\\n\\tactiveProcess := Processor activeProcess.\\n\\tactiveProcess == owner ifTrue:[^aBlock value].\\n\\t^semaphore critical:[\\n\\t\\towner := activeProcess.\\n\\t\\taBlock ensure:[owner := nil]].! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMutex class\\n\\tinstanceVariableNames: ''!\\nObject subclass: #MutexSet\\n\\tinstanceVariableNames: 'array'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Processes'!\\n!MutexSet commentStamp: '<historical>' prior: 0!\\nA MutexSet helps with aquiring a set of mutexes.!\\n\\n\\n!MutexSet methodsFor: 'initialize' stamp: 'das 11/3/2005 22:54'!\\nwithAll: mutexList\\n\\tarray := mutexList.! !\\n\\n\\n!MutexSet methodsFor: 'mutual exclusion' stamp: 'das 11/3/2005 22:54'!\\ncritical: aBlock\\n\\t\\\"Evaluate aBlock aquiring all mutexes\\\"\\n\\t^self pvtCritical: aBlock startingAt: 1! !\\n\\n\\n!MutexSet methodsFor: 'private' stamp: 'das 11/3/2005 22:54'!\\npvtCritical: aBlock startingAt: index\\n\\t| mutex |\\n\\tindex > array size ifTrue:[^aBlock value].\\n\\tmutex := array at: index.\\n\\t^mutex critical:[self pvtCritical: aBlock startingAt: index+1].! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nMutexSet class\\n\\tinstanceVariableNames: ''!\\n\\n!MutexSet class methodsFor: 'instance creation' stamp: 'das 11/3/2005 22:54'!\\nwithAll: mutexList\\n\\t^self new withAll: mutexList! !\\nAppRegistry subclass: #MvcTextEditor\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Applications'!\\n!MvcTextEditor commentStamp: 'tween 8/27/2004 12:24' prior: 0!\\nA subclass of AppRegistry which allows the user, or Browser add-ons, to control which class is used when creating the code editing view in mvc Browsers!\\n\\nError subclass: #MyResumableTestError\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Exceptions-Tests'!\\n\\n!MyResumableTestError methodsFor: 'exceptionDescription' stamp: 'tfei 6/13/1999 00:46'!\\nisResumable\\n\\n\\t^true! !\\nError subclass: #MyTestError\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Exceptions-Tests'!\\nNotification subclass: #MyTestNotification\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Exceptions-Tests'!\\nNetworkError subclass: #NameLookupFailure\\n\\tinstanceVariableNames: 'hostName'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Kernel'!\\n!NameLookupFailure commentStamp: 'mir 5/12/2003 18:16' prior: 0!\\nSignals that a name lookup operation failed.\\n\\n\\thostName\\thostName for which the name loopup failed\\n!\\n\\n\\n!NameLookupFailure methodsFor: 'accessing' stamp: 'rbb 2/18/2005 14:27'!\\ndefaultAction\\n\\t\\\"Backward compatibility\\\"\\n\\t| response |\\n\\tresponse _ (UIManager default chooseFrom: #( 'Retry' 'Give Up')\\n\\t\\t\\ttitle: self messageText).\\n\\t^ response = 2\\n\\t\\tifFalse: [self retry]! !\\n\\n!NameLookupFailure methodsFor: 'accessing' stamp: 'len 12/14/2002 11:57'!\\nhostName\\n\\t^ hostName! !\\n\\n!NameLookupFailure methodsFor: 'accessing' stamp: 'len 12/14/2002 11:57'!\\nhostName: aString\\n\\thostName _ aString! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNameLookupFailure class\\n\\tinstanceVariableNames: ''!\\n\\n!NameLookupFailure class methodsFor: 'instance creation' stamp: 'len 12/14/2002 11:57'!\\nhostName: aString\\n\\t^ self new hostName: aString! !\\nObject subclass: #NameOfSubclass\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tests-Bugs'!\\nUpdatingStringMorph subclass: #NameStringInHalo\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Widgets'!\\n!NameStringInHalo commentStamp: 'kfr 10/27/2003 16:29' prior: 0!\\nShows the name of the morph in the halo. !\\n\\n\\n!NameStringInHalo methodsFor: 'accessing' stamp: 'sw 9/17/1999 13:17'!\\ninterimContents: aString\\n\\tself contents: aString.\\n\\tself placeContents! !\\n\\n\\n!NameStringInHalo methodsFor: 'as yet unclassified' stamp: 'di 11/25/1999 23:40'!\\nplaceContents\\n\\t| namePosition |\\n\\t(owner notNil and: [owner isInWorld]) ifTrue:\\n\\t\\t[namePosition _ owner basicBox bottomCenter -\\n\\t\\t\\t((self width // 2) @ (owner handleSize negated // 2 - 1)).\\n\\t\\tnamePosition _ namePosition min: self world viewBox bottomRight - self extent y + 2.\\n\\t\\tself bounds: (namePosition extent: self extent)]! !\\n\\n\\n!NameStringInHalo methodsFor: 'drawing' stamp: 'sw 9/7/1999 21:27'!\\ndrawOn: aCanvas\\n\\taCanvas fillRectangle: self bounds color: Color white.\\n\\tsuper drawOn: aCanvas.! !\\n\\n\\n!NameStringInHalo methodsFor: 'editing' stamp: 'sw 9/17/1999 13:41'!\\ncancelEdits\\n\\tself interimContents: target externalName.\\n\\tsuper cancelEdits! !\\nObject subclass: #NaturalLanguageFormTranslator\\n\\tinstanceVariableNames: 'id generics'\\n\\tclassVariableNames: 'CachedTranslations'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Localization'!\\n\\n!NaturalLanguageFormTranslator methodsFor: 'accessing' stamp: 'yo 1/13/2005 11:15'!\\ngenerics\\n\\t^generics ifNil: [generics := Dictionary new]! !\\n\\n!NaturalLanguageFormTranslator methodsFor: 'accessing' stamp: 'yo 1/13/2005 11:27'!\\nlocaleID\\n\\t^id! !\\n\\n!NaturalLanguageFormTranslator methodsFor: 'accessing' stamp: 'yo 1/13/2005 11:26'!\\nlocaleID: anID\\n\\tid := anID! !\\n\\n!NaturalLanguageFormTranslator methodsFor: 'accessing' stamp: 'yo 1/13/2005 11:17'!\\nname: formName form: translatedForm \\n\\tself generics at: formName put: translatedForm.\\n! !\\n\\n\\n!NaturalLanguageFormTranslator methodsFor: 'i/o' stamp: 'yo 1/13/2005 14:02'!\\nsaveFormsOn: aStream\\n\\n\\t| rr |\\n\\trr _ ReferenceStream on: aStream.\\n\\trr nextPut: {id isoString. generics}.\\n\\trr close.\\n! !\\n\\n\\n!NaturalLanguageFormTranslator methodsFor: 'utilities' stamp: 'yo 1/13/2005 11:35'!\\ntranslate: aString\\n\\n\\t^ (self generics\\n\\t\\tat: aString ifAbsent: [nil]) deepCopy.\\n\\n\\t\\\"Do you like to write 'form ifNotNil: [form deepCopy]'?\\\"\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNaturalLanguageFormTranslator class\\n\\tinstanceVariableNames: ''!\\n\\n!NaturalLanguageFormTranslator class methodsFor: 'accessing' stamp: 'yo 1/13/2005 11:13'!\\ncachedTranslations\\n\\t\\\"CachedTranslations := nil\\\" \\n\\t^CachedTranslations ifNil: [CachedTranslations := Dictionary new]! !\\n\\n!NaturalLanguageFormTranslator class methodsFor: 'accessing' stamp: 'yo 1/13/2005 11:13'!\\nisoLanguage: isoLanguage\\n\\t\\\"Return the generic language translator as there is no information about the country code\\\"\\n\\n\\t^self isoLanguage: isoLanguage isoCountry: nil! !\\n\\n!NaturalLanguageFormTranslator class methodsFor: 'accessing' stamp: 'yo 1/13/2005 11:13'!\\nisoLanguage: isoLanguage isoCountry: isoCountry\\n\\t^self localeID: (LocaleID isoLanguage: isoLanguage isoCountry: isoCountry)! !\\n\\n!NaturalLanguageFormTranslator class methodsFor: 'accessing' stamp: 'yo 1/13/2005 11:13'!\\nlocaleID: localeID \\n\\t^ self cachedTranslations\\n\\t\\tat: localeID\\n\\t\\tifAbsentPut: [self new localeID: localeID]! !\\n\\n\\n!NaturalLanguageFormTranslator class methodsFor: 'i/o' stamp: 'yo 1/13/2005 14:02'!\\nloadFormsFrom: aStream\\n\\n\\t| rr pair inst |\\n\\trr _ ReferenceStream on: aStream.\\n\\tpair _ rr next.\\n\\tinst _ self localeID: (LocaleID isoString: pair first).\\n\\tpair second associationsDo: [:assoc |\\n\\t\\tinst name: assoc key form: assoc value.\\n\\t].\\n\\t^ inst.\\n! !\\nObject subclass: #NaturalLanguageTranslator\\n\\tinstanceVariableNames: 'id generics contexts'\\n\\tclassVariableNames: 'AllKnownPhrases CachedTranslations'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Localization'!\\n\\n!NaturalLanguageTranslator methodsFor: 'accessing' stamp: 'dgd 8/13/2004 21:12'!\\ndisplayLanguage\\n\\t^ id displayLanguage! !\\n\\n!NaturalLanguageTranslator methodsFor: 'accessing' stamp: 'dgd 10/7/2004 20:50'!\\ndisplayName\\n\\t^ id displayName! !\\n\\n!NaturalLanguageTranslator methodsFor: 'accessing' stamp: 'mir 7/15/2004 14:41'!\\nisoCountry\\n\\t^self localeID isoCountry! !\\n\\n!NaturalLanguageTranslator methodsFor: 'accessing' stamp: 'mir 7/15/2004 14:42'!\\nisoLanguage\\n\\t^self localeID isoLanguage! !\\n\\n!NaturalLanguageTranslator methodsFor: 'accessing' stamp: 'mir 7/15/2004 14:42'!\\nlocaleID\\n\\t^id! !\\n\\n!NaturalLanguageTranslator methodsFor: 'accessing' stamp: 'mir 7/21/2004 17:00'!\\ntranslations\\n\\t^self generics! !\\n\\n!NaturalLanguageTranslator methodsFor: 'accessing' stamp: 'mir 7/21/2004 17:03'!\\nuntranslated\\n\\t| translations |\\n\\ttranslations := self translations.\\n\\t^self class allKnownPhrases reject: [:each | translations includesKey: each]! !\\n\\n\\n!NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'tak 11/16/2004 11:04'!\\nfileOutHeader\\n\\t^ '''Translation dictionary'''! !\\n\\n!NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'tak 11/28/2004 14:50'!\\nfileOutHeaderOn: aStream \\n\\taStream nextChunkPut: self fileOutHeader;\\n\\t\\t cr.\\n\\taStream timeStamp; cr.\\n\\taStream nextPut: $!!.\\n\\taStream nextChunkPut: '(' , self class name , ' localeID: ' , id storeString , ')'.\\n\\taStream cr! !\\n\\n!NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'yo 11/29/2005 11:19'!\\nfileOutOn: aStream \\n\\t\\\"self current fileOutOn: Transcript. Transcript endEntry\\\"\\n\\tself fileOutHeaderOn: aStream.\\n\\tself fileOutOn: aStream keys: nil! !\\n\\n!NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'yo 11/29/2005 11:19'!\\nfileOutOn: aStream keys: keys \\n\\t\\\"self current fileOutOn: Transcript. Transcript endEntry\\\"\\n\\t(keys\\n\\t\\tifNil: [generics keys asSortedCollection])\\n\\t\\tdo: [:key | self\\n\\t\\t\\t\\tnextChunkPut: (generics associationAt: key)\\n\\t\\t\\t\\ton: aStream].\\n\\tkeys\\n\\t\\tifNil: [self untranslated\\n\\t\\t\\t\\tdo: [:each | self nextChunkPut: each -> '' on: aStream]].\\n\\taStream nextPut: $!!;\\n\\t\\t cr! !\\n\\n!NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'tak 11/16/2004 09:26'!\\nnextChunkPut: anObject on: aStream \\n\\t| i remainder terminator |\\n\\tterminator := $!!.\\n\\tremainder := anObject storeString.\\n\\t[(i := remainder indexOf: terminator) = 0]\\n\\t\\twhileFalse: [aStream\\n\\t\\t\\t\\tnextPutAll: (remainder copyFrom: 1 to: i).\\n\\t\\t\\taStream nextPut: terminator.\\n\\t\\t\\t\\\"double imbedded terminators\\\"\\n\\t\\t\\tremainder := remainder copyFrom: i + 1 to: remainder size].\\n\\taStream nextPutAll: remainder.\\n\\taStream nextPut: terminator; cr.! !\\n\\n!NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'tak 12/15/2004 16:07'!\\nscanFrom: aStream \\n\\t\\\"Read a definition of dictionary. \\n\\tMake sure current locale corresponds my locale id\\\"\\n\\t| aString newTranslations assoc currentPlatform |\\n\\tnewTranslations := Dictionary new.\\n\\tcurrentPlatform := Locale currentPlatform.\\n\\t[Locale\\n\\t\\tcurrentPlatform: (Locale localeID: id).\\n\\t[aString := aStream nextChunk withSqueakLineEndings.\\n\\taString size > 0]\\n\\t\\twhileTrue: [assoc := Compiler evaluate: aString.\\n\\t\\t\\tassoc value = ''\\n\\t\\t\\t\\tifTrue: [self class registerPhrase: assoc key]\\n\\t\\t\\t\\tifFalse: [newTranslations add: assoc]]]\\n\\t\\tensure: [Locale currentPlatform: currentPlatform].\\n\\tself mergeTranslations: newTranslations! !\\n\\n!NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'yo 2/25/2005 09:37'!\\nwriteAsMimeString\\n\\n\\t| fileName fileStream tmpStream s2 gzs |\\n\\ttmpStream _ MultiByteBinaryOrTextStream on: ''.\\n\\ttmpStream converter: UTF8TextConverter new.\\n\\tself fileOutOn: tmpStream.\\n\\ts2 _ RWBinaryOrTextStream on: ''.\\n\\tgzs := GZipWriteStream on: s2.\\n\\ttmpStream reset.\\n\\tgzs nextPutAll: (tmpStream binary contentsOfEntireFile asString) contents.\\n\\tgzs close.\\n\\ts2 reset.\\n\\n\\tfileName _ id isoString, '.translation.gz.mime'.\\n\\tfileStream _ FileStream newFileNamed: fileName.\\n\\tfileStream nextPutAll: (Base64MimeConverter mimeEncode: s2) contents.\\n\\tfileStream close.\\n! !\\n\\n\\n!NaturalLanguageTranslator methodsFor: 'initialize-release' stamp: 'mir 7/15/2004 14:41'!\\nlocaleID: anID\\n\\tid := anID! !\\n\\n\\n!NaturalLanguageTranslator methodsFor: 'printing' stamp: 'nk 8/29/2004 10:51'!\\nprintOn: aStream\\n\\taStream nextPutAll: self class name; nextPut: $(; print: self localeID; nextPut: $)! !\\n\\n\\n!NaturalLanguageTranslator methodsFor: 'translation' stamp: 'mir 7/21/2004 18:02'!\\ncheckPhrase: phrase translation: translation! !\\n\\n!NaturalLanguageTranslator methodsFor: 'translation' stamp: 'yo 7/30/2004 13:03'!\\nphrase: phraseString translation: translationString \\n\\tself generics at: phraseString put: translationString asString.\\n\\tself changed: #translations.\\n\\tself changed: #untranslated.! !\\n\\n!NaturalLanguageTranslator methodsFor: 'translation' stamp: 'yo 8/2/2004 12:27'!\\nrawPhrase: phraseString translation: translationString \\n\\tself generics at: phraseString put: translationString asString.\\n! !\\n\\n!NaturalLanguageTranslator methodsFor: 'translation' stamp: 'yo 1/14/2005 16:25'!\\nrawRemoveUntranslated: untranslated\\n\\n\\tself class allKnownPhrases removeKey: untranslated ifAbsent: [].\\n\\tself changed: #untranslated.! !\\n\\n!NaturalLanguageTranslator methodsFor: 'translation' stamp: 'yo 8/1/2004 01:07'!\\nremoveTranslationFor: phraseString\\n\\tself generics removeKey: phraseString ifAbsent: [].\\n\\tself changed: #translations.\\n\\tself changed: #untranslated.! !\\n\\n!NaturalLanguageTranslator methodsFor: 'translation' stamp: 'yo 1/14/2005 16:25'!\\nremoveUntranslated: untranslated\\n\\n\\tself class allKnownPhrases removeKey: untranslated ifAbsent: [].\\n! !\\n\\n!NaturalLanguageTranslator methodsFor: 'translation' stamp: 'em 3/23/2005 12:08'!\\ntranslate: aString\\n\\t^self generics\\n\\t\\tat: aString\\n\\t\\tifAbsent: [self class registeredPhraseFor: aString. \\n\\t\\t\\t\\t\\tself changed: #untranslated. \\n\\t\\t\\t\\t\\tself localeID hasParent\\n\\t\\t\\tifTrue: [(self class localeID: self localeID parent) translate: aString]\\n\\t\\t\\tifFalse: [aString]]! !\\n\\n!NaturalLanguageTranslator methodsFor: 'translation' stamp: 'mir 6/30/2004 20:22'!\\ntranslate: aString in: aContext! !\\n\\n!NaturalLanguageTranslator methodsFor: 'translation' stamp: 'mir 7/15/2004 14:58'!\\ntranslationFor: aString\\n\\t^self translate: aString! !\\n\\n\\n!NaturalLanguageTranslator methodsFor: 'user interface' stamp: 'dgd 8/13/2004 21:54'!\\ndefaultBackgroundColor\\n\\t\\\"answer the receiver's defaultBackgroundColor for views\\\"\\n\\t^ Color cyan! !\\n\\n\\n!NaturalLanguageTranslator methodsFor: 'private' stamp: 'mir 6/30/2004 20:23'!\\ngenerics\\n\\t^generics ifNil: [generics := Dictionary new]! !\\n\\n\\n!NaturalLanguageTranslator methodsFor: 'private store-retrieve' stamp: 'yo 7/30/2004 13:00'!\\nloadFromFileNamed: fileNameString \\n\\t\\\"Load translations from an external file\\\"\\n\\n\\t| stream |\\n\\t[stream := FileStream readOnlyFileNamed: fileNameString.\\n\\tself loadFromStream: stream]\\n\\t\\tensure: [stream close].\\n\\tself changed: #translations.\\n\\tself changed: #untranslated.\\n! !\\n\\n!NaturalLanguageTranslator methodsFor: 'private store-retrieve' stamp: 'tak 11/16/2004 12:37'!\\nloadFromRefStream: stream \\n\\t\\\"Load translations from an external file\\\"\\n\\t| loadedArray refStream |\\n\\trefStream := ReferenceStream on: stream.\\n\\t[loadedArray := refStream next]\\n\\t\\tensure: [refStream close].\\n\\tself processExternalObject: loadedArray ! !\\n\\n!NaturalLanguageTranslator methodsFor: 'private store-retrieve' stamp: 'em 3/30/2005 14:32'!\\nloadFromStream: stream \\n\\t\\\"Load translations from an external file\\\"\\n\\t| header isFileIn |\\n\\theader := '''Translation dictionary'''.\\n\\tisFileIn := (stream next: header size)\\n\\t\\t\\t\\t= header.\\n\\tstream reset.\\n\\tisFileIn\\n\\t\\tifTrue: [stream fileInAnnouncing: 'Loading ' translated, stream localName]\\n\\t\\tifFalse: [self loadFromRefStream: stream]! !\\n\\n!NaturalLanguageTranslator methodsFor: 'private store-retrieve' stamp: 'yo 8/2/2004 12:27'!\\nmergeTranslations: newTranslations\\n\\t\\\"Merge a new set of translations into the exiting table.\\n\\tOverwrites existing entries.\\\"\\n\\n\\tnewTranslations keysAndValuesDo: [:key :value |\\n\\t\\tself rawPhrase: (self class registeredPhraseFor: key) translation: value].\\n\\tself changed: #translations.\\n\\tself changed: #untranslated.! !\\n\\n!NaturalLanguageTranslator methodsFor: 'private store-retrieve' stamp: 'mir 7/15/2004 20:04'!\\nprocessExternalObject: anArray \\n\\t\\\"pivate - process the external object\\\"\\n\\n\\t\\\"new format -> {translations. untranslated}\\\"\\n\\n\\tanArray second do: [:each | self class registerPhrase: each].\\n\\n\\tself mergeTranslations: anArray first! !\\n\\n!NaturalLanguageTranslator methodsFor: 'private store-retrieve' stamp: 'yo 2/17/2005 15:45'!\\nsaveToFileNamed: fileNameString \\n\\t\\\"save the receiver's translations to a file named fileNameString\\\"\\n\\t| stream |\\n\\t\\\"Set true if you need to save as binary\\\"\\n\\tfalse\\n\\t\\tifTrue: [stream := ReferenceStream fileNamed: fileNameString.\\n\\t\\t\\tstream nextPut: {self translations. self untranslated}.\\n\\t\\t\\tstream close.\\n\\t\\t\\t^ self].\\n\\tstream := FileStream fileNamed: fileNameString.\\n\\t[self fileOutOn: stream]\\n\\t\\tensure: [stream close]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNaturalLanguageTranslator class\\n\\tinstanceVariableNames: ''!\\n\\n!NaturalLanguageTranslator class methodsFor: 'accessing' stamp: 'dgd 8/24/2004 20:20'!\\navailableLanguageLocaleIDs\\n\\t\\\"Return the locale ids for the currently available languages. \\n\\tMeaning those which either internally or externally have \\n\\ttranslations available.\\\"\\n\\t\\\"NaturalLanguageTranslator availableLanguageLocaleIDs\\\"\\n\\t^ CachedTranslations values collect:[:each | each localeID]! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'accessing' stamp: 'dgd 8/24/2004 19:39'!\\ncurrent\\n\\t^ LocaleID current translator\\n\\n! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'accessing' stamp: 'nk 8/29/2004 14:23'!\\ndefault\\n\\t^self localeID: (LocaleID default)\\n! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'accessing' stamp: 'mir 7/15/2004 14:36'!\\nisoLanguage: isoLanguage\\n\\t\\\"Return the generic language translator as there is no information about the country code\\\"\\n\\n\\t^self isoLanguage: isoLanguage isoCountry: nil! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'accessing' stamp: 'mir 7/15/2004 14:36'!\\nisoLanguage: isoLanguage isoCountry: isoCountry\\n\\t^self localeID: (LocaleID isoLanguage: isoLanguage isoCountry: isoCountry)! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'accessing' stamp: 'dgd 8/24/2004 19:18'!\\nlocaleID: localeID \\n\\t^ self cachedTranslations\\n\\t\\tat: localeID\\n\\t\\tifAbsentPut: [self new localeID: localeID]! !\\n\\n\\n!NaturalLanguageTranslator class methodsFor: 'class initialization' stamp: 'mir 8/11/2004 13:38'!\\ninitialize\\n\\t\\\"NaturalLanguageTranslator initialize\\\"\\n\\n\\tFileList registerFileReader: self.\\n\\tSmalltalk addToStartUpList: NaturalLanguageTranslator after: FileDirectory.\\n! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'class initialization' stamp: 'mir 7/15/2004 19:48'!\\nresetCaches\\n\\t\\\"NaturalLanguageTranslator resetCaches\\\"\\n\\n\\tCachedTranslations := nil.\\n! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'class initialization' stamp: 'mir 8/31/2005 23:37'!\\nstartUp: resuming \\n\\t| defaultID |\\n\\tresuming\\n\\t\\tifFalse: [^ self].\\n\\t\\\"\\\"\\n\\tdefaultID := LocaleID current.\\n\\tself cachedTranslations\\n\\t\\tat: defaultID\\n\\t\\tifAbsent: [self localeID: defaultID].\\n\\t\\\"\\\"\\n\\tself loadAvailableExternalLocales! !\\n\\n\\n!NaturalLanguageTranslator class methodsFor: 'file-services' stamp: 'mir 8/11/2004 10:52'!\\nfileReaderServicesForFile: fullName suffix: suffix \\n\\t\\\"Answer the file services associated with given file\\\"\\n\\t^ (suffix = self translationSuffix) | (suffix = '*')\\n\\t\\tifTrue: [{self serviceMergeLanguageTranslations}]\\n\\t\\tifFalse: [#()]! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'file-services' stamp: 'tak 3/14/2005 15:51'!\\nloadForLocaleIsoString: localeString fromGzippedMimeLiteral: mimeString \\n\\t\\\"merge the translation from the mime literal.\\\"\\n\\t| stream localeID translator gs rbStream s currentPlatform |\\n\\ts := Base64MimeConverter mimeDecodeToBytes: mimeString readStream.\\n\\ts reset.\\n\\tgs := GZipReadStream on: s.\\n\\trbStream := MultiByteBinaryOrTextStream with: gs contents asString.\\n\\trbStream converter: UTF8TextConverter new.\\n\\trbStream reset.\\n\\tlocaleID := LocaleID isoString: localeString.\\n\\tcurrentPlatform := Locale currentPlatform.\\n\\t[Locale\\n\\t\\tcurrentPlatform: (Locale localeID: localeID).\\n\\tstream := ReadStream on: rbStream contents]\\n\\t\\tensure: [Locale currentPlatform: currentPlatform].\\n\\ttranslator := self localeID: localeID.\\n\\ttranslator loadFromStream: stream.\\n\\tLanguageEnvironment resetKnownEnvironments! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'file-services' stamp: 'yo 2/24/2005 21:04'!\\nmergeTranslationFileNamed: fileFullNameString \\n\\t\\\"merge the translation in the file named fileFullNameString\\\"\\n\\n\\t| stream localeID translator |\\n\\tstream := FileStream readOnlyFileNamed: fileFullNameString.\\n\\t[localeID := LocaleID isoString: stream localName sansPeriodSuffix.\\n\\ttranslator := self localeID: localeID.\\n\\ttranslator loadFromStream: stream]\\n\\t\\tensure: [stream close].\\n\\tLanguageEnvironment resetKnownEnvironments.\\n\\n! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'file-services' stamp: 'mir 7/21/2004 13:45'!\\nserviceMergeLanguageTranslations\\n\\t\\\"Answer a service for merging of translation files\\\"\\n\\t^ SimpleServiceEntry\\n\\t\\tprovider: self\\n\\t\\tlabel: 'merge the translation file'\\n\\t\\tselector: #mergeTranslationFileNamed:\\n\\t\\tdescription: 'merge the translation file into the language named like the file'\\n\\t\\tbuttonLabel: 'merge'! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'file-services' stamp: 'mir 7/21/2004 13:45'!\\nservices\\n\\t\\\"Answer potential file services associated with this class\\\"\\n\\t^ {self serviceMergeLanguageTranslations}! !\\n\\n\\n!NaturalLanguageTranslator class methodsFor: 'private' stamp: 'mir 7/15/2004 19:58'!\\nallKnownPhrases\\n\\t^AllKnownPhrases ifNil: [AllKnownPhrases := Dictionary new: 2051]! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private' stamp: 'mir 7/13/2004 00:06'!\\ncachedTranslations\\n\\t\\\"CachedTranslations := nil\\\" \\n\\t^CachedTranslations ifNil: [CachedTranslations := Dictionary new]! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private' stamp: 'mir 8/31/2005 16:55'!\\ncleanUpCache\\n\\t\\\"NaturalLanguageTranslator cleanUpCache\\\"\\n\\n\\tself cachedTranslations keys do: [:key |\\n\\t\\tkey isoLanguage size > 2 ifTrue: [self cachedTranslations removeKey: key]]! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private' stamp: 'mir 7/15/2004 20:02'!\\nregisterPhrase: phrase\\n\\t\\\"Using a Dictionary so we can lookup existing string instead of creating needless copies when loading a translation.\\\"\\n\\tself allKnownPhrases at: phrase put: phrase! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private' stamp: 'mir 7/21/2004 14:18'!\\nregisteredPhraseFor: phrase\\n\\t\\\"Using a Dictionary so we can lookup existing string instead of creating needless copies when loading a translation.\\\"\\n\\t^self allKnownPhrases at: phrase ifAbsentPut: [phrase]! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private' stamp: 'mir 8/11/2004 10:52'!\\ntranslationSuffix\\n\\t^'translation'! !\\n\\n\\n!NaturalLanguageTranslator class methodsFor: 'private loading' stamp: 'nk 8/21/2004 13:03'!\\ndirectoryForLanguage: isoLanguage country: isoCountry create: createDir\\n\\t\\\"Try to locate the <prefs>/locale/<language>{/<country>} folder.\\n\\tIf createDir is set, create the path down to country or language, depending on wether it's specified..\\n\\tReturn the directory for country or language depending on specification.\\n\\tIf neither exists, nil\\\"\\n\\n\\t\\\"NaturalLanguageTranslator directoryForLanguage: 'es' country: nil create: true\\\"\\n\\t\\\"NaturalLanguageTranslator directoryForLanguage: 'de' country: 'DE' create: true\\\"\\n\\t\\\"NaturalLanguageTranslator directoryForLanguage: 'en' country: 'US' create: false\\\"\\n\\t\\\"NaturalLanguageTranslator directoryForLanguage: 'en' country: nil create: true\\\"\\n\\n\\t\\\"If this fails, there is nothing we can do about it here\\\"\\n\\t| localeDir countryDir languageDir |\\n\\tlocaleDir := self localeDirCreate: createDir.\\n\\tlocaleDir ifNil: [^nil].\\n\\n\\tisoCountry ifNil: [\\n\\t\\tlanguageDir := localeDir directoryNamed: isoLanguage.\\n\\t\\tcreateDir\\n\\t\\t\\tifTrue: [languageDir assureExistence].\\n\\t\\t^languageDir exists\\n\\t\\t\\tifTrue: [languageDir]\\n\\t\\t\\tifFalse: [nil]].\\n\\n\\tcountryDir := languageDir directoryNamed: isoCountry.\\n\\tcreateDir\\n\\t\\tifTrue: [countryDir assureExistence].\\n\\n\\t^countryDir exists\\n\\t\\tifTrue: [countryDir]\\n\\t\\tifFalse: [nil]! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private loading' stamp: 'mir 8/11/2004 10:44'!\\ndirectoryForLocaleID: localeID create: createDir\\n\\t\\\"Try to locate the <prefs>/locale/<language>{/<country>} folder.\\n\\tIf createDir is set, create the path down to country or language, depending on locale.\\n\\tReturn the directory for country or language depending on locale.\\n\\tIf neither exists, nil\\\"\\n\\n\\t\\\"NaturalLanguageTranslator directoryForLanguage: 'de' country: nil readOnly: true\\\"\\n\\t\\\"NaturalLanguageTranslator directoryForLanguage: 'de' country: 'DE' readOnly: true\\\"\\n\\t\\\"NaturalLanguageTranslator directoryForLanguage: 'en' country: 'US' readOnly: false\\\"\\n\\t\\\"NaturalLanguageTranslator directoryForLanguage: 'en' country: nil readOnly: true\\\"\\n\\n\\t^self directoryForLanguage: localeID isoLanguage country: localeID isoCountry create: createDir! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private loading' stamp: 'mir 8/25/2004 11:57'!\\nloadAvailableExternalLocales\\n\\t\\\"private - register locales IDs based on the content of the <prefs>/locale/ directory\\\"\\n\\t| localeDir |\\n\\tlocaleDir := self localeDirCreate: false.\\n\\tlocaleDir ifNil: [^ #()].\\n\\n\\tlocaleDir directoryNames\\n\\t\\tdo: [:langDirName | \\n\\t\\t\\t| langDir | \\n\\t\\t\\tlangDir := localeDir directoryNamed: langDirName.\\n\\n\\t\\t\\t(langDir fileNamesMatching: '*.' , self translationSuffix)\\n\\t\\t\\t\\tifNotEmpty: [self loadTranslatorForIsoLanguage: langDirName isoCountry: nil].\\n\\n\\t\\t\\tlangDir directoryNames\\n\\t\\t\\t\\tdo: [:countryDirName | \\n\\t\\t\\t\\t\\t| countryDir | \\n\\t\\t\\t\\t\\tcountryDir := langDirName directoryNamed: countryDirName.\\n\\t\\t\\t\\t\\t(countryDir fileNamesMatching: '*.' , self translationSuffix)\\n\\t\\t\\t\\t\\t\\tifNotEmpty: [self loadTranslatorForIsoLanguage: langDirName isoCountry: countryDirName]\\n\\t\\t\\t]\\n\\t\\t].\\n! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private loading' stamp: 'nk 8/21/2004 13:00'!\\nloadExternalTranslationsFor: translator\\n\\t\\\"Try to load translations from external external files.\\n\\tThe files are located in the <prefs>/locale/<language>{/<country>} folder.\\n\\tThere can be more than one file for each location, so applications can install their own partial translation tables. All files in the specific folder are loaded.\\\"\\n\\n\\t| translationDir |\\n\\ttranslationDir := self directoryForLocaleID: translator localeID create: false.\\n\\ttranslationDir ifNil: [ ^nil ]. \\n\\t(translationDir fileNamesMatching: '*.' , self translationSuffix)\\n\\t\\tdo: [:fileName | translator loadFromFileNamed: (translationDir fullNameFor: fileName)]! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private loading' stamp: 'mir 8/25/2004 11:59'!\\nloadTranslatorForIsoLanguage: isoLanguage isoCountry: isoCountry \\n\\t\\\"private - load the translations from <prefs>/locale/ directory \\n\\tthe procedure is to assure the existence of a translator for the \\n\\tgiven language/country and then load the external translations for this translator\\\"\\n\\n\\t| translator |\\n\\ttranslator := self localeID: (LocaleID isoLanguage: isoLanguage isoCountry: isoCountry).\\n\\n\\tself loadExternalTranslationsFor: translator! !\\n\\n!NaturalLanguageTranslator class methodsFor: 'private loading' stamp: 'mir 8/25/2004 12:03'!\\nlocaleDirCreate: createDir\\n\\t\\\"Try to locate the <prefs>/locale/ folder.\\n\\tIf createDir is set, try to create the path.\\n\\tIf it doesn't exist, return nil\\\"\\n\\n\\t\\\"If this fails, there is nothing we can do about it here\\\"\\n\\t| prefDir localeDir |\\n\\t(createDir not\\n\\t\\t\\tand: [ExternalSettings preferenceDirectory isNil])\\n\\t\\tifTrue: [^ nil].\\n\\n\\tprefDir := ExternalSettings assuredPreferenceDirectory.\\n\\tprefDir exists\\n\\t\\tifFalse: [^nil].\\n\\n\\n\\tlocaleDir := prefDir directoryNamed: 'locale'.\\n\\tcreateDir\\n\\t\\tifTrue: [localeDir assureExistence].\\n\\t^localeDir exists\\n\\t\\tifTrue: [localeDir]\\n\\t\\tifFalse: [nil]! !\\nObject subclass: #NebraskaClient\\n\\tinstanceVariableNames: 'connection encoder hand canvas'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n!NebraskaClient commentStamp: '<historical>' prior: 0!\\nA client that has connected to a Nebraska server, seen from the server's point of view.!\\n\\n\\n!NebraskaClient methodsFor: 'as yet unclassified' stamp: 'RAA 7/31/2000 23:59'!\\nbacklog\\n\\n\\t^connection backlog! !\\n\\n!NebraskaClient methodsFor: 'as yet unclassified' stamp: 'RAA 12/13/2000 08:30'!\\ncurrentStatusString\\n\\n\\t(connection isNil or: [connection isConnected not]) ifTrue: [^'nada'].\\n\\t^(NetNameResolver stringFromAddress: connection remoteAddress),\\n\\t\\t' - ',\\n\\t\\t(self backlog // 1024) printString,'k'! !\\n\\n\\n!NebraskaClient methodsFor: 'attributes' stamp: 'ls 3/25/2000 22:27'!\\ncanvas\\n\\t\\\"return the hand this canvas that should be drawn on for this client\\\"\\n\\t^canvas! !\\n\\n!NebraskaClient methodsFor: 'attributes' stamp: 'ls 3/25/2000 22:27'!\\nhand\\n\\t\\\"return the hand this client is controlling\\\"\\n\\t^hand! !\\n\\n\\n!NebraskaClient methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:25'!\\nconvertToBuffered\\n\\n\\tcanvas purgeOutputQueue.\\n\\tcanvas := canvas asBufferedCanvas.! !\\n\\n!NebraskaClient methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:25'!\\ndestroy\\n\\thand ifNotNil:[hand world ifNotNil:[hand world removeHand: hand]].\\n\\tconnection ifNotNil:[connection destroy].\\n\\tencoder := canvas := hand := connection := nil.! !\\n\\n!NebraskaClient methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:25'!\\ninitialize: aConnection\\n\\n\\t| remoteAddress userPicture |\\n\\n\\tconnection := aConnection.\\n\\thand := RemoteControlledHandMorph on: (MorphicEventDecoder on: aConnection).\\n\\thand nebraskaClient: self.\\n\\tremoteAddress := connection remoteAddress.\\n\\tremoteAddress ifNotNil: [remoteAddress := NetNameResolver stringFromAddress: remoteAddress].\\n\\tuserPicture := EToySenderMorph pictureForIPAddress: remoteAddress.\\n\\thand\\n\\t\\tuserInitials: ((EToySenderMorph nameForIPAddress: remoteAddress) ifNil: ['???'])\\n\\t\\tandPicture: (userPicture ifNotNil: [userPicture scaledToSize: 16@20]).\\n\\tencoder := CanvasEncoder on: aConnection.\\n\\tcanvas := RemoteCanvas\\n\\t\\tconnection: encoder\\n\\t\\tclipRect: NebraskaServer extremelyBigRectangle\\n\\t\\ttransform: MorphicTransform identity! !\\n\\n\\n!NebraskaClient methodsFor: 'network' stamp: 'ls 4/9/2000 14:43'!\\nextent: newExtent depth: newDepth\\n\\tencoder extent: newExtent depth: newDepth! !\\n\\n!NebraskaClient methodsFor: 'network' stamp: 'ls 3/25/2000 22:25'!\\nisConnected\\n\\t^connection isConnected! !\\n\\n!NebraskaClient methodsFor: 'network' stamp: 'ls 3/25/2000 22:25'!\\nprocessIO\\n\\tconnection processIO.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNebraskaClient class\\n\\tinstanceVariableNames: ''!\\n\\n!NebraskaClient class methodsFor: 'instance creation' stamp: 'ls 3/25/2000 22:28'!\\nonConnection: aStringSocket\\n\\t^self new initialize: aStringSocket! !\\nObject subclass: #NebraskaDebug\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'DEBUG Details'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n!NebraskaDebug commentStamp: '<historical>' prior: 0!\\nBufferedCanvas enabled: false.\\nBufferedCanvas enabled: true.\\n\\nNebraskaDebug beginStats\\nNebraskaDebug showStats\\nNebraskaDebug stopAndShowAll\\nNebraskaDebug killStats\\nStringSocket showRatesSeen\\nStringSocket clearRatesSeen\\nNebraskaDebug showAndClearStats: #allStats\\nNebraskaDebug showAndClearStats: #queuedbufferSizes\\n\\n\\nCanvasEncoder beginStats\\nCanvasEncoder showStats\\nCanvasEncoder killStats\\nNebraskaDebug showStats: #peerBytesSent\\nNebraskaDebug showStats: #soundReductionTime\\nNebraskaDebug showStats: #FormEncodeTimes\\nNebraskaDebug showStats: #SendReceiveStats\\nNebraskaDebug showStats: #sendDeltas\\nNebraskaDebug showStats: #bigImage\\nNebraskaDebug showStats: #sketch\\nNebraskaDebug showStats: #addToOutBuf:\\n----\\nbuffered off, painting 125kb/s, dragging 400kb/s\\nbuffered on, painting 100kb/s, dragging 170kb/s!\\n]style[(62 142 14 78 17 3 73 415)f1cblue;,f1cblack;,f1,f1cblack;,f1cred;,f1cblack;,f1cblue;,f1cblack;!\\n\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNebraskaDebug class\\n\\tinstanceVariableNames: ''!\\n\\n!NebraskaDebug class methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\nat: queueName add: anArray\\n\\n\\t| now |\\n\\n\\tDEBUG ifNil: [\\n\\t\\tqueueName == #sketchZZZ ifFalse: [^self].\\n\\t\\t\\\"Details := OrderedCollection new.\\\"\\n\\t\\tself beginStats.\\n\\t].\\n\\t(Details notNil and: [Details size < 20]) ifTrue: [\\n\\t\\tDetails add: thisContext longStack\\n\\t].\\n\\tnow := Time millisecondClockValue.\\n\\tDEBUG add: {now},anArray,{queueName}.\\n! !\\n\\n!NebraskaDebug class methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\nbeginStats\\n\\n\\tDEBUG := OrderedCollection new! !\\n\\n!NebraskaDebug class methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\nkillStats\\n\\n\\tDEBUG := nil.\\n! !\\n\\n!NebraskaDebug class methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\nshowAndClearStats: queueName\\n\\n\\tDEBUG ifNil: [^Beeper beep].\\n\\tself \\n\\t\\tshowStats: queueName \\n\\t\\tfrom: DEBUG.\\n\\tDEBUG := nil.! !\\n\\n!NebraskaDebug class methodsFor: 'as yet unclassified' stamp: 'nb 6/17/2003 12:25'!\\nshowStats\\n\\n\\tDEBUG ifNil: [^Beeper beep].\\n\\tDEBUG explore.! !\\n\\n!NebraskaDebug class methodsFor: 'as yet unclassified' stamp: 'nb 6/17/2003 12:25'!\\nshowStats: queueName\\n\\n\\tDEBUG ifNil: [^Beeper beep].\\n\\tself \\n\\t\\tshowStats: queueName \\n\\t\\tfrom: DEBUG.\\n! !\\n\\n!NebraskaDebug class methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\nshowStats: queueName from: aCollection\\n\\n\\t| xx answer prevTime currTime |\\n\\n\\tprevTime := nil.\\n\\tanswer := String streamContents: [ :s | \\n\\t\\ts nextPutAll: (aCollection last first - aCollection first first) asStringWithCommas,' ms';cr;cr.\\n\\t\\taCollection withIndexDo: [ :each :index | \\n\\t\\t\\t(queueName == #allStats or: [queueName == each last]) ifTrue: [\\n\\t\\t\\t\\tcurrTime := each first.\\n\\t\\t\\t\\txx := currTime printString.\\n\\t\\t\\t\\tprevTime ifNil: [prevTime := currTime].\\n\\t\\t\\t\\ts nextPutAll: index printString,'. ',\\n\\t\\t\\t\\t\\t(xx allButLast: 3),'.',(xx last: 3),' ',(currTime - prevTime) printString,' '.\\n\\t\\t\\t\\ts nextPutAll: each allButFirst printString; cr.\\n\\t\\t\\t\\tprevTime := currTime.\\n\\t\\t\\t].\\n\\t\\t]\\n\\t].\\n\\tStringHolder new \\n\\t\\tcontents: answer;\\n\\t\\topenLabel: queueName! !\\n\\n!NebraskaDebug class methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\nstopAndShowAll\\n\\n\\t| prev |\\n\\nself halt.\\t\\\"not updated to new format\\\"\\n\\n\\tprev := DEBUG.\\n\\tDEBUG := nil.\\n\\tprev ifNil: [^Beeper beep].\\n\\tprev keysAndValuesDo: [ :k :v |\\n\\t\\tself showStats: k from: v\\n\\t].! !\\nProjectNavigationMorph subclass: #NebraskaNavigationMorph\\n\\tinstanceVariableNames: 'nebraskaBorder nebraskaTerminal'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 12/13/2000 08:49'!\\naddButtons\\n\\n\\tself addARow: {\\n\\t\\tself inAColumn: {self buttonScale}.\\n\\t\\tself inAColumn: {self buttonQuit}.\\n\\t\\tself inAColumn: {self buttonBuffered}.\\n\\t}.\\n! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 12/13/2000 08:26'!\\nbufferNebraska\\n\\n\\tnebraskaTerminal requestBufferedConnection\\n! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 12/13/2000 08:23'!\\nbuttonBuffered\\n\\n\\t^self makeButton: 'B' balloonText: 'Request buffered Nebraska session' for: #bufferNebraska\\n! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/8/2000 11:34'!\\nbuttonScale\\n\\n\\t^self makeButton: '1x1' balloonText: 'Switch between 1x1 and scaled view' for: #toggleFullView\\n! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/8/2000 11:47'!\\ncurrentNavigatorVersion\\n\\n\\t^1\\t\\t\\\"not particularly relevant here\\\"! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'yo 11/4/2002 21:06'!\\nfontForButtons\\n\\n\\t^ TextStyle defaultFont.\\n\\t\\\"^Preferences standardButtonFont\\\"! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:25'!\\nnebraskaBorder: aNebraskaBorder\\n\\n\\tnebraskaBorder := aNebraskaBorder! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:25'!\\nnebraskaTerminal: aNebraskaTerminal\\n\\n\\tnebraskaTerminal := aNebraskaTerminal! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:25'!\\npositionVertically\\n\\n\\t| w |\\n\\tw := self world ifNil: [^self].\\n\\tself top < w top ifTrue: [self top: w top].\\n\\tself bottom > w bottom ifTrue: [self bottom: w bottom].! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/8/2000 11:47'!\\nquitNebraska\\n\\n\\tnebraskaBorder ifNotNil: [nebraskaBorder delete].\\n\\tself delete.! !\\n\\n!NebraskaNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/8/2000 11:48'!\\ntoggleFullView\\n\\n\\tnebraskaBorder ifNotNil: [nebraskaBorder toggleFullView]! !\\n\\n\\n!NebraskaNavigationMorph methodsFor: 'dropping/grabbing' stamp: 'RAA 11/8/2000 11:42'!\\nwantsToBeDroppedInto: aMorph\\n\\n\\t\\\"avoid difficulties in placement\\\"\\n\\t^(aMorph isKindOf: NetworkTerminalMorph) not! !\\n\\n\\n!NebraskaNavigationMorph methodsFor: 'initialization' stamp: 'dgd 2/16/2003 14:11'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color yellow ! !\\n\\n\\n!NebraskaNavigationMorph methodsFor: 'stepping and presenter' stamp: 'RAA 11/8/2000 11:37'!\\nstep\\n\\n\\tsuper step.\\n\\t(nebraskaBorder isNil or: [nebraskaBorder world isNil]) ifTrue: [self delete].! !\\n\\n\\n!NebraskaNavigationMorph methodsFor: 'the buttons' stamp: 'RAA 11/8/2000 11:36'!\\nbuttonQuit\\n\\n\\t^self makeButton: 'Quit' balloonText: 'Quit this Nebraska session' for: #quitNebraska\\n! !\\nModel subclass: #NebraskaServer\\n\\tinstanceVariableNames: 'worldDepth world clients listenQueue'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n!NebraskaServer commentStamp: '<historical>' prior: 0!\\nA Nebraska server has a private world and some collection of clients. It associates a RemoteControlledHand for each client. Redraw events in the world are broadcasted to all connected clients. A Nebraska server can listen on a TCP/IP port and accept new clients. Current version has been modified so that the server serves the world in which it was launched. Other variations are certainly possible.\\n\\nTo start a server, execute the following code:\\n\\tNebraskaServerMorph serveWorld: World\\n\\nTo start a client, run the following in another image:\\n\\tNetworkTerminalMorph openAndConnectTo: 'servername'\\n\\nFill in your server's hostname for 'servername'. At this point, everything should be working!!\\n\\nBefore starting a server, you can tweak these:\\nBufferedCanvas enabled: false.\\nBufferedCanvas enabled: true.\\n\\nAt any time you can do these:\\nNebraskaDebug beginStats\\nNebraskaDebug showStats\\nNebraskaDebug showStats: #delays\\nNebraskaDebug showStats: #bigImage\\nNebraskaDebug showStats: #FormEncodeTimes\\nNebraskaDebug killStats\\n\\nNOTE: if you want to have a local view of the server, you shouldn't use the TCP connections. The problem is that the server will occasionally do a #flush, and it won't work due to single threading. The better solution is to use a LoopBackStringSocket instead of a regular StringSocket, but there is no handy method for that right now....\\n\\n\\n!\\n]style[(266 136 49 39 56 53 96 46 1 62 29 525)f1,f1cred;,f1,f1cblue;,f1,f1cblue;,f1,f1cblue;,f1,f1cred;,f1cblue;,f1!\\n\\n\\n!NebraskaServer methodsFor: 'accessing' stamp: 'ar 10/26/2000 14:23'!\\nclients\\n\\t^clients ifNil:[#()].! !\\n\\n\\n!NebraskaServer methodsFor: 'attributes' stamp: 'ls 4/11/2000 19:48'!\\nextent: newExtent depth: newDepth\\n\\t\\\"modify the extent and/or depth of the shared world\\\"\\n\\tclients do: [ :client |\\n\\t\\tclient extent: newExtent depth: newDepth ].\\n\\tworld extent: newExtent.\\n\\n\\tworldDepth := newDepth.! !\\n\\n!NebraskaServer methodsFor: 'attributes' stamp: 'ls 4/11/2000 18:41'!\\nnumClients\\n\\t\\\"return the number of connected clients\\\"\\n\\t^clients size! !\\n\\n!NebraskaServer methodsFor: 'attributes' stamp: 'ls 3/25/2000 23:13'!\\nsharedWorld\\n\\t^world! !\\n\\n\\n!NebraskaServer methodsFor: 'initialization' stamp: 'ar 10/26/2000 14:02'!\\ndestroy\\n\\tself stopListening.\\n\\tclients do:[:each| each destroy].\\n\\tself breakDependents.! !\\n\\n!NebraskaServer methodsFor: 'initialization' stamp: 'ar 10/26/2000 14:20'!\\ninitialize\\n\\tclients := IdentitySet new.\\n\\tself extent: 800@600 depth: 16.! !\\n\\n!NebraskaServer methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:25'!\\ninitializeForWorld: aWorld\\n\\n\\tworld := aWorld.\\n\\tclients := IdentitySet new.\\n\\tself extent: world extent depth: Display depth.\\n\\taWorld remoteServer: self.! !\\n\\n\\n!NebraskaServer methodsFor: 'menus' stamp: 'RAA 7/31/2000 22:28'!\\nstep\\n\\n\\tself processIO.\\n\\n\\t\\\"savedWorld := Processor activeProcess world.\\n\\tProcessor activeProcess setWorld: world.\\\"\\n\\n\\tself flag: #bob.\\t\\t\\\"in this version, world is THE WORLD, so it steps itself\\\"\\n\\t\\\"world doOneCycle.\\\"\\n\\n\\t\\\"Processor activeProcess setWorld: savedWorld.\\\"\\n\\n\\tclients do: [ :each | each canvas apply: [ :ignore | ]].\\t\\\"for modes that need a little push\\\"\\n! !\\n\\n\\n!NebraskaServer methodsFor: 'networking' stamp: 'ls 3/25/2000 22:35'!\\nacceptNewConnections\\n\\t| connection |\\n\\tlistenQueue ifNil: [ ^self ].\\n\\t[ clients size > 20 ifTrue: [ \\\"too many connections!!\\\" ^self ].\\n\\t connection := listenQueue getConnectionOrNil. \\n\\t connection isNil ] \\n\\twhileFalse: [\\n\\t self addClientFromConnection: (StringSocket on: connection) ].! !\\n\\n!NebraskaServer methodsFor: 'networking' stamp: 'sd 11/20/2005 21:25'!\\nacceptNullConnection\\n\\n\\t| twins |\\n\\n\\ttwins := LoopbackStringSocket newPair.\\n\\tself addClientFromConnection: twins first.\\n\\t(NullTerminalMorph new connection: twins second) openInWorld.\\n! !\\n\\n!NebraskaServer methodsFor: 'networking' stamp: 'sd 11/20/2005 21:25'!\\nacceptPhonyConnection\\n\\n\\t| twins |\\n\\n\\ttwins := LoopbackStringSocket newPair.\\n\\tself addClientFromConnection: twins first.\\n\\t(NetworkTerminalMorph new connection: twins second) inspect \\\"openInWorld\\\".\\n! !\\n\\n!NebraskaServer methodsFor: 'networking' stamp: 'RAA 7/20/2000 10:03'!\\naddClientFromConnection: connection\\n\\t| client |\\n\\n\\tclient := NebraskaClient onConnection: connection.\\n\\tclients add: client.\\n\\tclient extent: world extent depth: worldDepth.\\n\\tworld addRemoteClient: client.\\n\\tself changed: #numClients.! !\\n\\n!NebraskaServer methodsFor: 'networking' stamp: 'RAA 8/1/2000 00:01'!\\nbacklog\\n\\n\\t^clients inject: 0 into: [ :max :each | max max: each backlog]! !\\n\\n!NebraskaServer methodsFor: 'networking' stamp: 'ls 3/25/2000 22:36'!\\nprocessIO\\n\\tself pruneDeadConnections.\\n\\tself acceptNewConnections.! !\\n\\n!NebraskaServer methodsFor: 'networking' stamp: 'ar 10/26/2000 14:20'!\\npruneDeadConnections\\n\\t| deadConnections |\\n\\tdeadConnections := clients select: [ :client | client isConnected not ].\\n\\tdeadConnections do: [ :client |\\n\\t\\tworld removeRemoteClient: client].\\n\\n\\tdeadConnections isEmpty ifTrue:[ ^self ].\\n\\n\\tclients removeAll: deadConnections.\\n\\tself changed: #numClients.! !\\n\\n!NebraskaServer methodsFor: 'networking' stamp: 'ls 3/25/2000 22:31'!\\nstartListeningOnPort: portNumber\\n\\tSocket initializeNetwork.\\n\\tself stopListening.\\n\\tlistenQueue := ConnectionQueue portNumber: portNumber queueLength: 5.! !\\n\\n!NebraskaServer methodsFor: 'networking' stamp: 'ls 3/25/2000 22:32'!\\nstopListening\\n\\tlistenQueue ifNil: [ ^self ].\\n\\tlistenQueue destroy.\\n\\tlistenQueue := nil.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNebraskaServer class\\n\\tinstanceVariableNames: ''!\\n\\n!NebraskaServer class methodsFor: 'as yet unclassified' stamp: 'RAA 7/24/2000 12:06'!\\ndefaultPort\\n\\n\\t^9091! !\\n\\n!NebraskaServer class methodsFor: 'as yet unclassified' stamp: 'RAA 11/8/2000 14:59'!\\nextremelyBigRectangle\\n\\n\\t^(0@0 extent: 5000@5000)! !\\n\\n\\n!NebraskaServer class methodsFor: 'instance creation' stamp: 'mu 11/28/2003 19:38'!\\nnewForWorld: aWorld\\n\\n\\t^self basicNew initializeForWorld: aWorld! !\\n\\n!NebraskaServer class methodsFor: 'instance creation' stamp: 'ar 10/26/2000 14:00'!\\nserveWorld: aWorld\\n\\n\\t^self serveWorld: aWorld onPort: self defaultPort! !\\n\\n!NebraskaServer class methodsFor: 'instance creation' stamp: 'sd 11/20/2005 21:26'!\\nserveWorld: aWorld onPort: aPortNumber\\n\\n\\t| server |\\n\\n\\tUtilities authorName.\\t\\\"since we will need it later\\\"\\n\\n\\tserver := self newForWorld: aWorld.\\n\\tserver startListeningOnPort: aPortNumber.\\n\\t^server\\n\\t\\\"server acceptNullConnection\\\"\\t\\t\\\"server acceptPhonyConnection.\\\"\\n! !\\nAlignmentMorphBob1 subclass: #NebraskaServerMorph\\n\\tinstanceVariableNames: 'server slowCounter previousBacklog lastFullUpdateTime currentStatusString fullDisplay previousClients currentBacklogString'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n!NebraskaServerMorph commentStamp: '<historical>' prior: 0!\\nA cheezy morph that simply steps a Nebraska server instance over and over.!\\n\\n\\n!NebraskaServerMorph methodsFor: 'accessing' stamp: 'RAA 5/31/2001 15:03'!\\ncurrentBacklogString\\n\\n\\t^currentBacklogString! !\\n\\n!NebraskaServerMorph methodsFor: 'accessing' stamp: 'RAA 11/8/2000 16:07'!\\ncurrentStatusString\\n\\n\\t^currentStatusString! !\\n\\n!NebraskaServerMorph methodsFor: 'accessing' stamp: 'ar 10/26/2000 14:05'!\\nserver\\n\\t^self world remoteServer! !\\n\\n\\n!NebraskaServerMorph methodsFor: 'drawing' stamp: 'sd 11/20/2005 21:25'!\\nupdateCurrentStatusString\\n\\n\\tself server ifNil:[\\n\\t\\tcurrentStatusString := '<Nebraska not active>' translated.\\n\\t\\tcurrentBacklogString := ''.\\n\\t] ifNotNil:[\\n\\t\\tcurrentStatusString := \\n\\t\\t\\t' Nebraska: ' translated, \\n\\t\\t\\tself server numClients printString, \\n\\t\\t\\t' clients' translated.\\n\\t\\tcurrentBacklogString := 'backlog: ' translated,\\n\\t\\t\\t\\t((previousBacklog := self server backlog) // 1024) printString,'k'\\n\\t].\\n! !\\n\\n\\n!NebraskaServerMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:29'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color white! !\\n\\n!NebraskaServerMorph methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:25'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\tfullDisplay := false.\\n\\t\\n\\tlastFullUpdateTime := 0.\\n\\tself listDirection: #topToBottom;\\n\\t\\t hResizing: #shrinkWrap;\\n\\t\\t vResizing: #shrinkWrap! !\\n\\n!NebraskaServerMorph methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:25'!\\nrebuild\\n\\n\\t| myServer toggle closeBox font |\\n\\n\\tfont := StrikeFont familyName: #Palatino size: 14.\\n\\tself removeAllMorphs.\\n\\tself setColorsAndBorder.\\n\\tself updateCurrentStatusString.\\n\\ttoggle := SimpleHierarchicalListMorph new perform: (\\n\\t\\tfullDisplay ifTrue: [#expandedForm] ifFalse: [#notExpandedForm]\\n\\t).\\n\\tcloseBox := SimpleButtonMorph new borderWidth: 0;\\n\\t\\t\\tlabel: 'X' font: Preferences standardButtonFont; color: Color transparent;\\n\\t\\t\\tactionSelector: #delete; target: self; extent: 14@14;\\n\\t\\t\\tsetBalloonText: 'End Nebrasks session'.\\n\\n\\tself addARow: {\\n\\t\\tself inAColumn: {closeBox}.\\n\\t\\tself inAColumn: {\\n\\t\\t\\tUpdatingStringMorph new\\n\\t\\t\\t\\tuseStringFormat;\\n\\t\\t\\t\\ttarget: self;\\n\\t\\t\\t\\tfont: font;\\n\\t\\t\\t\\tgetSelector: #currentStatusString;\\n\\t\\t\\t\\tcontents: self currentStatusString;\\n\\t\\t\\t\\tstepTime: 2000;\\n\\t\\t\\t\\tlock.\\n\\t\\t}.\\n\\t\\tself inAColumn: {\\n\\t\\t\\ttoggle asMorph\\n\\t\\t\\t\\ton: #mouseUp send: #toggleFull to: self;\\n\\t\\t\\t\\tsetBalloonText: 'Show more or less of Nebraska Status'\\n\\t\\t}.\\n\\t}.\\n\\tmyServer := self server.\\n\\t(myServer isNil or: [fullDisplay not]) ifTrue: [\\n\\t\\t^World startSteppingSubmorphsOf: self\\n\\t].\\n\\t\\\"--- the expanded display ---\\\"\\n\\tself addARow: {\\n\\t\\tself inAColumn: {\\n\\t\\t\\tUpdatingStringMorph new\\n\\t\\t\\t\\tuseStringFormat;\\n\\t\\t\\t\\ttarget: self;\\n\\t\\t\\t\\tfont: font;\\n\\t\\t\\t\\tgetSelector: #currentBacklogString;\\n\\t\\t\\t\\tcontents: self currentBacklogString;\\n\\t\\t\\t\\tstepTime: 2000;\\n\\t\\t\\t\\tlock.\\n\\t\\t}.\\n\\t}.\\n\\n\\tself addARow: {\\n\\t\\tself inAColumn: {\\n\\t\\t\\t(StringMorph contents: '--clients--' translated) lock; font: font.\\n\\t\\t}.\\n\\t}.\\n\\n\\tmyServer clients do: [ :each |\\n\\t\\tself addARow: {\\n\\t\\t\\tUpdatingStringMorph new\\n\\t\\t\\t\\tuseStringFormat;\\n\\t\\t\\t\\ttarget: each;\\n\\t\\t\\t\\tfont: font;\\n\\t\\t\\t\\tgetSelector: #currentStatusString;\\n\\t\\t\\t\\tcontents: each currentStatusString;\\n\\t\\t\\t\\tstepTime: 2000;\\n\\t\\t\\t\\tlock.\\n\\t\\t}\\n\\t].\\n\\tWorld startSteppingSubmorphsOf: self.! !\\n\\n!NebraskaServerMorph methodsFor: 'initialization' stamp: 'aoy 2/15/2003 21:35'!\\nsetColorsAndBorder\\n\\t| worldColor c |\\n\\tc := ((Preferences menuColorFromWorld and: [Display depth > 4]) \\n\\t\\t\\t\\tand: [(worldColor := self currentWorld color) isColor]) \\n\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t[worldColor luminance > 0.7 \\n\\t\\t\\t\\t\\t\\t\\tifTrue: [worldColor mixed: 0.8 with: Color black]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [worldColor mixed: 0.4 with: Color white]]\\n\\t\\t\\t\\t\\tifFalse: [Preferences menuColor]. \\n\\tself color: c.\\n\\tself borderColor: #raised.\\n\\tself borderWidth: Preferences menuBorderWidth.\\n\\tself useRoundedCorners! !\\n\\n!NebraskaServerMorph methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:25'!\\ntoggleFull\\n\\n\\tfullDisplay := fullDisplay not.\\n\\tself rebuild.\\n! !\\n\\n\\n!NebraskaServerMorph methodsFor: 'stepping and presenter' stamp: 'sd 11/20/2005 21:25'!\\nstep\\n\\n\\t| now |\\n\\n\\tself server ifNil: [ ^self ].\\n\\tself server step.\\n\\tnow := Time millisecondClockValue.\\n\\t(now - lastFullUpdateTime) abs > 5000 ifTrue: [\\n\\t\\tlastFullUpdateTime := now.\\n\\t\\t(previousBacklog = self server backlog and: [self server clients = previousClients]) ifFalse: [\\n\\t\\t\\tpreviousClients := self server clients copy.\\n\\t\\t\\tself rebuild\\n\\t\\t]\\n\\t].\\n! !\\n\\n\\n!NebraskaServerMorph methodsFor: 'submorphs-add/remove' stamp: 'ar 10/26/2000 14:07'!\\ndelete\\n\\tself server ifNotNil:[\\n\\t\\t(self confirm:'Shutdown the server?') \\n\\t\\t\\tifTrue:[self world remoteServer: nil]].\\n\\tsuper delete.! !\\n\\n\\n!NebraskaServerMorph methodsFor: 'testing' stamp: 'RAA 11/8/2000 15:57'!\\nstepTime\\n\\n\\t^10! !\\n\\n\\n!NebraskaServerMorph methodsFor: 'updating' stamp: 'RAA 11/8/2000 16:03'!\\nupdate: aSymbol\\n\\n\\tself rebuild.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNebraskaServerMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!NebraskaServerMorph class methodsFor: 'as yet unclassified' stamp: 'RAA 8/15/2000 14:49'!\\nkillOldServers\\n\\n\\tNebraskaServerMorph allInstances do: [ :each |\\n\\t\\teach delete.\\n\\t].\\n\\tNebraskaServer allInstances do: [ :each |\\n\\t\\teach stopListening.\\n\\t\\tDependentsFields removeKey: each ifAbsent: [].\\n\\t].\\n! !\\n\\n!NebraskaServerMorph class methodsFor: 'as yet unclassified' stamp: 'yo 12/17/2005 23:06'!\\nserveWorld\\n\\n\\t^ self serveWorld: ActiveWorld.\\n! !\\n\\n!NebraskaServerMorph class methodsFor: 'as yet unclassified' stamp: 'yo 12/17/2005 23:07'!\\nserveWorldButton\\n\\n\\t| button |\\n\\tbutton _ ScriptableButton new.\\n\\tbutton target: NebraskaServerMorph.\\n\\tbutton actionSelector: #serveWorld.\\n\\tbutton arguments: #().\\n\\tbutton label: 'Share'.\\n\\tbutton color: Color yellow.\\n\\t^ button.\\n! !\\n\\n!NebraskaServerMorph class methodsFor: 'as yet unclassified' stamp: 'wiz 1/9/2005 15:12'!\\nserveWorld: aWorld\\n\\t\\\"Check to make sure things won't crash. See Mantis #0000519\\\"\\n\\taWorld isSafeToServe ifTrue:[\\n\\t\\t^self serveWorld: aWorld onPort: NebraskaServer defaultPort]\\n\\t! !\\n\\n!NebraskaServerMorph class methodsFor: 'as yet unclassified' stamp: 'ar 10/26/2000 14:05'!\\nserveWorld: aWorld onPort: aPortNumber\\n\\n\\t| server |\\n\\tserver := NebraskaServer serveWorld: aWorld onPort: aPortNumber.\\n\\t(self new) openInWorld: aWorld.\\n\\n\\t\\\"server acceptNullConnection\\\"\\t\\t\\\"server acceptPhonyConnection.\\\"\\n! !\\n\\n!NebraskaServerMorph class methodsFor: 'as yet unclassified' stamp: 'yo 12/17/2005 23:08'!\\nsupplementaryPartsDescriptions\\n\\t^ {DescriptionForPartsBin\\n\\t\\tformalName: 'NebraskaServer'\\n\\t\\tcategoryList: #('Collaborative')\\n\\t\\tdocumentation: 'A button to start the Nebraska desktop sharing server' translated\\n\\t\\tglobalReceiverSymbol: #NebraskaServerMorph\\n\\t\\tnativitySelector: #serveWorldButton\\n\\t}! !\\nObject subclass: #NetNameResolver\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'DefaultHostName HaveNetwork ResolverBusy ResolverError ResolverMutex ResolverReady ResolverSemaphore ResolverUninitialized'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Kernel'!\\n!NetNameResolver commentStamp: '<historical>' prior: 0!\\nThis class implements TCP/IP style network name lookup and translation facilities.\\n\\nAttempt to keep track of whether there is a network available.\\nHaveNetwork\\ttrue if last attempt to contact the network was successful.\\nLastContact\\t\\tTime of that contact (totalSeconds).\\nhaveNetwork\\treturns true, false, or #expired. True means there was contact in the last 30 minutes. False means contact failed or was false last time we asked. Get out of false state by making contact with a server in some way (FileList or updates).!\\n\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNetNameResolver class\\n\\tinstanceVariableNames: ''!\\n\\n!NetNameResolver class methodsFor: 'address string utils' stamp: 'jm 9/15/97 06:19'!\\naddressFromString: addressString\\n\\t\\\"Return the internet address represented by the given string. The string should contain four positive decimal integers delimited by periods, commas, or spaces, where each integer represents one address byte. Return nil if the string is not a host address in an acceptable format.\\\"\\n\\t\\\"NetNameResolver addressFromString: '1.2.3.4'\\\"\\n\\t\\\"NetNameResolver addressFromString: '1,2,3,4'\\\"\\n\\t\\\"NetNameResolver addressFromString: '1 2 3 4'\\\"\\n\\n\\t| newAddr s byte delimiter |\\n\\tnewAddr _ ByteArray new: 4.\\n\\ts _ ReadStream on: addressString.\\n\\ts skipSeparators.\\n\\t1 to: 4 do: [:i |\\n\\t\\tbyte _ self readDecimalByteFrom: s.\\n\\t\\tbyte = nil ifTrue: [^ nil].\\n\\t\\tnewAddr at: i put: byte.\\n\\t\\ti < 4 ifTrue: [\\n\\t\\t\\tdelimiter _ s next.\\n\\t\\t\\t((delimiter = $.) or: [(delimiter = $,) or: [delimiter = $ ]])\\n\\t\\t\\t\\tifFalse: [^ nil]]].\\n\\t^ newAddr\\n! !\\n\\n!NetNameResolver class methodsFor: 'address string utils' stamp: 'jm 9/15/97 16:52'!\\nstringFromAddress: addr\\n\\t\\\"Return a string representing the given host address as four decimal bytes delimited with decimal points.\\\"\\n\\t\\\"NetNameResolver stringFromAddress: NetNameResolver localHostAddress\\\"\\n\\n\\t| s |\\n\\ts _ WriteStream on: ''.\\n\\t1 to: 3 do: [ :i | (addr at: i) printOn: s. s nextPut: $.].\\n\\t(addr at: 4) printOn: s.\\n\\t^ s contents\\n! !\\n\\n\\n!NetNameResolver class methodsFor: 'class initialization' stamp: 'jm 9/17/97 16:18'!\\ninitialize\\n\\t\\\"NetNameResolver initialize\\\"\\n\\t\\\"Note: On the Mac, the name resolver is asynchronous (i.e., Squeak can do other things while it is working), but can only handle one request at a time. On other platforms, such as Unix, the resolver is synchronous; a call to, say, the name lookup primitive will block all Squeak processes until it returns.\\\"\\n\\n\\t\\\"Resolver Status Values\\\"\\n\\tResolverUninitialized _ 0.\\t\\\"network is not initialized\\\"\\n\\tResolverReady _ 1.\\t\\t\\t\\\"resolver idle, last request succeeded\\\"\\n\\tResolverBusy _ 2.\\t\\t\\t\\\"lookup in progress\\\"\\n\\tResolverError _ 3.\\t\\t\\t\\\"resolver idle, last request failed\\\"\\n\\n\\tDefaultHostName _ ''.\\n! !\\n\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'ls 9/5/1998 01:14'!\\naddressForName: aString\\n\\t^self addressForName: aString timeout: 60! !\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'mu 9/7/2003 22:53'!\\naddressForName: hostName timeout: secs\\n\\t\\\"Look up the given host name and return its address. Return nil if the address is not found in the given number of seconds.\\\"\\n\\t\\\"NetNameResolver addressForName: 'create.ucsb.edu' timeout: 30\\\"\\n\\t\\\"NetNameResolver addressForName: '100000jobs.de' timeout: 30\\\"\\n\\t\\\"NetNameResolver addressForName: '1.7.6.4' timeout: 30\\\"\\n\\t\\\"NetNameResolver addressForName: '' timeout: 30 (This seems to return nil?)\\\"\\n\\n\\t| deadline result |\\n\\tself initializeNetwork.\\n\\t\\\"check if this is a valid numeric host address (e.g. 1.2.3.4)\\\"\\n\\tresult _ self addressFromString: hostName.\\n\\tresult isNil ifFalse: [^result].\\n\\n\\t\\\"Look up a host name, including ones that start with a digit (e.g. 100000jobs.de or squeak.org)\\\"\\n\\tdeadline _ Time millisecondClockValue + (secs * 1000).\\n\\t\\\"Protect the execution of this block, as the ResolverSemaphore is used for both parts of the transaction.\\\"\\n\\tself resolverMutex\\n\\t\\tcritical: [\\n\\t\\t\\t(self waitForResolverReadyUntil: deadline)\\n\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\tself primStartLookupOfName: hostName.\\n\\t\\t\\t\\t\\t(self waitForCompletionUntil: deadline)\\n\\t\\t\\t\\t\\t\\tifTrue: [result _ self primNameLookupResult]\\n\\t\\t\\t\\t\\t\\tifFalse: [(NameLookupFailure hostName: hostName) signal: 'Could not resolve the server named: ', hostName]]\\n\\t\\t\\t\\tifFalse: [(NameLookupFailure hostName: hostName) signal: 'Could not resolve the server named: ', hostName]].\\n\\t^result! !\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'jm 9/15/97 16:52'!\\nlocalAddressString\\n\\t\\\"Return a string representing the local host address as four decimal bytes delimited with decimal points.\\\"\\n\\t\\\"NetNameResolver localAddressString\\\"\\n\\n\\t^ NetNameResolver stringFromAddress: NetNameResolver localHostAddress\\n! !\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'mir 2/22/2002 15:50'!\\nlocalHostAddress\\n\\t\\\"Return the local address of this host.\\\"\\n\\t\\\"NetNameResolver localHostAddress\\\"\\n\\n\\tself initializeNetwork.\\n\\t^ self primLocalAddress\\n! !\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'mir 2/22/2002 15:12'!\\nlocalHostName\\n\\t\\\"Return the local name of this host.\\\"\\n\\t\\\"NetNameResolver localHostName\\\"\\n\\n\\t| hostName |\\n\\thostName _ NetNameResolver\\n\\t\\tnameForAddress: self localHostAddress\\n\\t\\ttimeout: 5.\\n\\t^hostName\\n\\t\\tifNil: [self localAddressString]\\n\\t\\tifNotNil: [hostName]! !\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'nk 6/27/2003 10:51'!\\nnameForAddress: hostAddress timeout: secs\\n\\t\\\"Look up the given host address and return its name. Return nil if the lookup fails or is not completed in the given number of seconds. Depends on the given host address being known to the gateway, which may not be the case for dynamically allocated addresses.\\\"\\n\\t\\\"NetNameResolver\\n\\t\\tnameForAddress: (NetNameResolver addressFromString: '128.111.92.2')\\n\\t\\ttimeout: 30\\\"\\n\\n\\t| deadline result |\\n\\tself initializeNetwork.\\n\\tdeadline _ Time millisecondClockValue + (secs * 1000).\\n\\t\\\"Protect the execution of this block, as the ResolverSemaphore is used for both parts of the transaction.\\\"\\n\\tself resolverMutex\\n\\t\\tcritical: [\\n\\t\\t\\tresult _ (self waitForResolverReadyUntil: deadline)\\n\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\tself primStartLookupOfAddress: hostAddress.\\n\\t\\t\\t\\t\\t(self waitForCompletionUntil: deadline)\\n\\t\\t\\t\\t\\t\\tifTrue: [self primAddressLookupResult]\\n\\t\\t\\t\\t\\t\\tifFalse: [nil]]\\n\\t\\t\\t\\tifFalse: [nil]].\\n\\t^result\\n! !\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'jm 9/17/97 16:26'!\\npromptUserForHostAddress\\n\\t\\\"Ask the user for a host name and return its address.\\\"\\n\\t\\\"NetNameResolver promptUserForHostAddress\\\"\\n\\n\\t^ NetNameResolver promptUserForHostAddressDefault: ''\\n! !\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'rbb 3/1/2005 11:01'!\\npromptUserForHostAddressDefault: defaultName\\n\\t\\\"Ask the user for a host name and return its address. If the default name is the empty string, use the last host name as the default.\\\"\\n\\t\\\"NetNameResolver promptUserForHostAddressDefault: ''\\\"\\n\\n\\t| default hostName serverAddr |\\n\\tdefaultName isEmpty\\n\\t\\tifTrue: [default := DefaultHostName]\\n\\t\\tifFalse: [default := defaultName].\\n\\thostName := UIManager default\\n\\t\\trequest: 'Host name or address?'\\n\\t\\tinitialAnswer: default.\\n\\thostName isEmpty ifTrue: [^ 0].\\n\\tserverAddr := NetNameResolver addressForName: hostName timeout: 15.\\n\\thostName size > 0 ifTrue: [DefaultHostName := hostName].\\n\\t^ serverAddr! !\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'JMM 5/3/2000 11:25'!\\nresolverError\\n\\t^self primNameResolverError\\n! !\\n\\n!NetNameResolver class methodsFor: 'lookups' stamp: 'JMM 5/3/2000 11:25'!\\nresolverStatus\\n\\t^self primNameResolverStatus\\n! !\\n\\n\\n!NetNameResolver class methodsFor: 'network initialization' stamp: 'mir 2/22/2002 15:03'!\\ninitializeNetwork\\n\\t\\\"Initialize the network drivers and record the semaphore to be used by the resolver. Do nothing if the network is already initialized. Evaluate the given block if network initialization fails.\\\"\\n\\t\\\"NetNameResolver initializeNetwork\\\"\\n\\n\\t| semaIndex |\\n\\tself resolverStatus = ResolverUninitialized\\n\\t\\tifFalse: [^HaveNetwork _ true]. \\\"network is already initialized\\\"\\n\\n\\tHaveNetwork _ false.\\t\\\"in case abort\\\"\\n\\tResolverSemaphore _ Semaphore new.\\n\\tsemaIndex _ Smalltalk registerExternalObject: ResolverSemaphore.\\n\\n\\t\\\"result is nil if network initialization failed, self if it succeeds\\\"\\n\\t(self primInitializeNetwork: semaIndex)\\n\\t\\tifNil: [NoNetworkError signal: 'failed network initialization']\\n\\t\\tifNotNil: [HaveNetwork _ true].\\n! !\\n\\n!NetNameResolver class methodsFor: 'network initialization' stamp: 'ar 2/2/2001 15:09'!\\nprimInitializeNetwork: resolverSemaIndex\\n\\t\\\"Initialize the network drivers on platforms that need it, such as the Macintosh, and return nil if network initialization failed or the reciever if it succeeds. Since mobile computers may not always be connected to a network, this method should NOT be called automatically at startup time; rather, it should be called when first starting a networking application. It is a noop if the network driver has already been initialized. If non-zero, resolverSemaIndex is the index of a VM semaphore to be associated with the network name resolver. This semaphore will be signalled when the resolver status changes, such as when a name lookup query is completed.\\\"\\n\\t\\\"Note: some platforms (e.g., Mac) only allow only one name lookup query at a time, so a manager process should be used to serialize resolver lookup requests.\\\"\\n\\n\\t<primitive: 'primitiveInitializeNetwork' module: 'SocketPlugin'>\\n\\t^ nil \\\"return nil if primitive fails\\\"\\n! !\\n\\n\\n!NetNameResolver class methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimAbortLookup\\n\\t\\\"Abort the current lookup operation, freeing the name resolver for the next query.\\\"\\n\\n\\t<primitive: 'primitiveResolverAbortLookup' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!NetNameResolver class methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimAddressLookupResult\\n\\t\\\"Return the host name found by the last host address lookup. Returns nil if the last lookup was unsuccessful.\\\"\\n\\n\\t<primitive: 'primitiveResolverAddressLookupResult' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!NetNameResolver class methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimLocalAddress\\n\\t\\\"Return the local address of this host.\\\"\\n\\n\\t<primitive: 'primitiveResolverLocalAddress' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!NetNameResolver class methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimNameLookupResult\\n\\t\\\"Return the host address found by the last host name lookup. Returns nil if the last lookup was unsuccessful.\\\"\\n\\n\\t<primitive: 'primitiveResolverNameLookupResult' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!NetNameResolver class methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimNameResolverError\\n\\t\\\"Return an integer reflecting the error status of the last network name resolver request. Zero means no error.\\\"\\n\\n\\t<primitive: 'primitiveResolverError' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!NetNameResolver class methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimNameResolverStatus\\n\\t\\\"Return an integer reflecting the status of the network name resolver. For a list of possible values, see the comment in the 'initialize' method of this class.\\\"\\n\\n\\t<primitive: 'primitiveResolverStatus' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!NetNameResolver class methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimStartLookupOfAddress: hostAddr\\n\\t\\\"Look up the given host address in the Domain Name Server to find its name. This call is asynchronous. To get the results, wait for it to complete or time out and then use primAddressLookupResult.\\\"\\n\\n\\t<primitive: 'primitiveResolverStartAddressLookup' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!NetNameResolver class methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimStartLookupOfName: hostName\\n\\t\\\"Look up the given host name in the Domain Name Server to find its address. This call is asynchronous. To get the results, wait for it to complete or time out and then use primNameLookupResult.\\\"\\n\\n\\t<primitive: 'primitiveResolverStartNameLookup' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n\\n!NetNameResolver class methodsFor: 'private' stamp: 'JMM 5/3/2000 13:57'!\\nreadDecimalByteFrom: aStream\\n\\t\\\"Read a positive, decimal integer from the given stream. Stop when a non-digit or end-of-stream is encountered. Return nil if stream is not positioned at a decimal digit or if the integer value read exceeds 255.\\nJMM - 000503 fixed didn't work correctly\\\"\\n\\n\\t| digitSeen value digit |\\n\\tdigitSeen _ false.\\n\\tvalue _ 0.\\n\\t[aStream atEnd] whileFalse: \\n\\t\\t[digit _ aStream next digitValue.\\n\\t\\t(digit < 0 or: [digit > 9]) ifTrue: [\\n\\t\\t\\taStream skip: -1.\\n\\t\\t\\t(digitSeen not or: [value > 255]) ifTrue: [^ nil].\\n\\t\\t\\t^ value].\\n\\t\\tdigitSeen _ true.\\n\\t\\tvalue _ (value * 10) + digit].\\n\\t(digitSeen not or: [value > 255]) ifTrue: [^ nil].\\n\\t^ value\\n! !\\n\\n!NetNameResolver class methodsFor: 'private' stamp: 'mir 6/18/2001 21:05'!\\nresolverMutex\\n\\tResolverMutex ifNil: [ResolverMutex _ Semaphore forMutualExclusion].\\n\\t^ResolverMutex! !\\n\\n!NetNameResolver class methodsFor: 'private' stamp: 'JMM 5/3/2000 11:35'!\\nwaitForCompletionUntil: deadline\\n\\t\\\"Wait up to the given number of seconds for the resolver to be ready to accept a new request. Return true if the resolver is ready, false if the network is not initialized or the resolver does not become free within the given time period.\\\"\\n\\n\\t| status |\\n\\tstatus _ self resolverStatus.\\n\\t[(status = ResolverBusy) and:\\n\\t [Time millisecondClockValue < deadline]]\\n\\t\\twhileTrue: [\\n\\t\\t\\t\\\"wait for resolver to be available\\\"\\n\\t\\t\\tResolverSemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue).\\n\\t\\t\\tstatus _ self resolverStatus].\\n\\n\\tstatus = ResolverReady\\n\\t\\tifTrue: [^ true]\\n\\t\\tifFalse: [\\n\\t\\t\\tstatus = ResolverBusy ifTrue: [self primAbortLookup].\\n\\t\\t\\t^ false].\\n! !\\n\\n!NetNameResolver class methodsFor: 'private' stamp: 'JMM 5/3/2000 11:36'!\\nwaitForResolverReadyUntil: deadline\\n\\t\\\"Wait up to the given number of seconds for the resolver to be ready to accept a new request. Return true if the resolver is not busy, false if the network is not initialized or the resolver does not become free within the given time period.\\\"\\n\\n\\t| status |\\n\\tstatus _ self resolverStatus.\\n\\tstatus = ResolverUninitialized ifTrue: [^ false].\\n\\n\\t[(status = ResolverBusy) and:\\n\\t [Time millisecondClockValue < deadline]]\\n\\t\\twhileTrue: [\\n\\t\\t\\t\\\"wait for resolver to be available\\\"\\n\\t\\t\\tResolverSemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue).\\n\\t\\t\\tstatus _ self resolverStatus].\\n\\n\\t^ status ~= ResolverBusy\\n! !\\nError subclass: #NetworkError\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Kernel'!\\n!NetworkError commentStamp: 'mir 5/12/2003 18:12' prior: 0!\\nAbstract super class for all network related exceptions.!\\n\\nEmbeddedWorldBorderMorph subclass: #NetworkTerminalBorderMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n\\n!NetworkTerminalBorderMorph methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:25'!\\ntoggleFullView\\n\\t\\\"Toggle the full view for network terminal\\\"\\n\\t| fullExtent priorExtent |\\n\\tfullExtent := self worldIEnclose extent + (2 * self borderWidth).\\n\\tpriorExtent := self valueOfProperty: #priorExtent.\\n\\tpriorExtent ifNil:[\\n\\t\\tself setProperty: #priorExtent toValue: self extent.\\n\\t\\tself extent: fullExtent.\\n\\t\\tself position: self position + self borderWidth asPoint negated.\\n\\t] ifNotNil:[\\n\\t\\tself removeProperty: #priorExtent.\\n\\t\\tself extent: priorExtent.\\n\\t\\tself position: (self position max: 0@0).\\n\\t].! !\\n\\n\\n!NetworkTerminalBorderMorph methodsFor: 'boxes' stamp: 'RAA 8/15/2000 12:21'!\\nboxesAndColorsAndSelectors\\n\\n\\t^#()! !\\n\\n\\n!NetworkTerminalBorderMorph methodsFor: 'initialization' stamp: 'RAA 12/14/2000 14:12'!\\ninitialize\\n\\n\\tsuper initialize.\\n\\tself setBalloonText: nil.\\t\\t\\\"'I am a view on another Squeak'.\\\"\\n\\tself layoutInset: 0.\\n! !\\nMorph subclass: #NetworkTerminalMorph\\n\\tinstanceVariableNames: 'connection decoder eventEncoder backgroundForm enteringHand'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n!NetworkTerminalMorph commentStamp: '<historical>' prior: 0!\\nA morph used to communicate with a remote image. It sends all mouse/keyboard events to the remote side, and it displays canvas commands that are sent back.!\\n\\n\\n!NetworkTerminalMorph methodsFor: 'as yet unclassified' stamp: 'RAA 8/29/2000 12:13'!\\naddScalingMenuItems: menu hand: aHandMorph\\n\\n\\t\\\"for comaptibility when in scaled frame\\\"! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'drawing' stamp: 'RAA 7/25/2000 13:00'!\\nareasRemainingToFill: aRectangle\\n\\t\\\"I assume that we are opaque\\\"\\n\\n\\t^ aRectangle areasOutside: self bounds! !\\n\\n!NetworkTerminalMorph methodsFor: 'drawing' stamp: 'RAA 7/24/2000 11:43'!\\ndrawOn: aCanvas\\n\\n\\tbackgroundForm ifNotNil: [\\n\\t\\taCanvas clipBy: bounds during: [ :c |\\n\\t\\t\\tc drawImage: backgroundForm at: bounds topLeft\\n\\t\\t].\\n\\t].\\n! !\\n\\n!NetworkTerminalMorph methodsFor: 'drawing' stamp: 'sd 11/20/2005 21:25'!\\nforceToFront: aRegion\\n\\t| highQuality |\\n\\t\\\"force the given region from the drawing form onto the background form\\\"\\n\\n\\thighQuality := false.\\t\\t\\\"highQuality is slower\\\"\\n\\n\\tself updateBackgroundForm.\\n\\tbackgroundForm\\n\\t\\tcopy: aRegion\\n\\t\\tfrom: aRegion topLeft\\n\\t\\tin: decoder drawingForm\\n\\t\\trule: Form over.\\n\\tself invalidRect: (\\n\\t\\thighQuality ifTrue: [\\n\\t\\t\\tbounds\\n\\t\\t] ifFalse: [\\n\\t\\t\\t(aRegion expandBy: 4) translateBy: bounds topLeft\\t\\\"try to remove gribblys\\\"\\n\\t\\t]\\n\\t)\\n! !\\n\\n!NetworkTerminalMorph methodsFor: 'drawing' stamp: 'sd 11/20/2005 21:26'!\\nupdateBackgroundForm\\n\\t\\\"make sure that our background form matches what the server has most recently requested\\\"\\n\\n\\t| drawingForm |\\n\\n\\tdrawingForm := decoder drawingForm.\\n\\t(drawingForm extent = backgroundForm extent and: [\\n\\t\\tdrawingForm depth = backgroundForm depth ]) ifTrue: [\\n\\t\\t\\t\\\"they match just fine\\\"\\n\\t\\t\\t^self ].\\n\\n\\tbackgroundForm := drawingForm deepCopy.\\t\\t\\\"need copy to capture the moment\\\"\\n\\tself extent: backgroundForm extent.! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'dropping/grabbing' stamp: 'RAA 11/5/2000 13:26'!\\nwantsDroppedMorph: aMorph event: evt\\n\\n\\t^true.! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'event handling' stamp: 'RAA 11/5/2000 13:23'!\\ncommResult: anArrayOfAssociations\\n\\n\\t\\\"ignore for now\\\"! !\\n\\n!NetworkTerminalMorph methodsFor: 'event handling' stamp: 'ar 10/26/2000 15:25'!\\nhandlesMouseOver: evt\\n\\t^true! !\\n\\n!NetworkTerminalMorph methodsFor: 'event handling' stamp: 'ar 10/26/2000 15:24'!\\nmouseEnter: evt\\n\\tevt hand newKeyboardFocus: self.\\n\\tevt hand needsToBeDrawn ifTrue:[Cursor blank show].! !\\n\\n!NetworkTerminalMorph methodsFor: 'event handling' stamp: 'ar 10/26/2000 15:25'!\\nmouseLeave: evt\\n\\n\\tevt hand needsToBeDrawn ifTrue:[Cursor normal show].! !\\n\\n!NetworkTerminalMorph methodsFor: 'event handling' stamp: 'RAA 8/15/2000 11:34'!\\nsendEvent: evt\\n\\n\\tself sendEventAsIs: (evt translatedBy: bounds topLeft negated).! !\\n\\n!NetworkTerminalMorph methodsFor: 'event handling' stamp: 'RAA 8/15/2000 11:33'!\\nsendEventAsIs: evt\\n\\n\\teventEncoder ifNil: [ ^self ].\\n\\teventEncoder sendEvent: evt.! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'events-processing' stamp: 'ar 10/24/2000 18:02'!\\nhandleKeyDown: anEvent\\n\\tanEvent wasHandled ifTrue:[^self].\\n\\t(self handlesKeyboard: anEvent) ifFalse:[^self].\\n\\tanEvent wasHandled: true.\\n\\tself sendEventAsIs: anEvent.! !\\n\\n!NetworkTerminalMorph methodsFor: 'events-processing' stamp: 'ar 10/24/2000 18:02'!\\nhandleKeyUp: anEvent\\n\\tanEvent wasHandled ifTrue:[^self].\\n\\t(self handlesKeyboard: anEvent) ifFalse:[^self].\\n\\tanEvent wasHandled: true.\\n\\tself sendEventAsIs: anEvent.! !\\n\\n!NetworkTerminalMorph methodsFor: 'events-processing' stamp: 'ar 10/24/2000 18:11'!\\nhandleKeystroke: anEvent\\n\\tanEvent wasHandled ifTrue:[^self].\\n\\tanEvent wasHandled: true.\\n\\tself sendEventAsIs: anEvent.! !\\n\\n!NetworkTerminalMorph methodsFor: 'events-processing' stamp: 'ar 10/24/2000 18:03'!\\nhandleMouseDown: anEvent\\n\\tanEvent wasHandled ifTrue:[^self].\\n\\tanEvent hand removePendingBalloonFor: self.\\n\\tanEvent hand removePendingHaloFor: self.\\n\\tanEvent wasHandled: true.\\n\\tanEvent hand newMouseFocus: self event: anEvent.\\n\\tanEvent hand removeHaloFromClick: anEvent on: self.\\n\\tself sendEventAsIs: anEvent.! !\\n\\n!NetworkTerminalMorph methodsFor: 'events-processing' stamp: 'ar 10/24/2000 18:04'!\\nhandleMouseMove: anEvent\\n\\tanEvent wasHandled ifTrue:[^self]. \\\"not interested\\\"\\n\\t(anEvent hand hasSubmorphs) ifTrue:[^self].\\n\\t(anEvent anyButtonPressed and:[anEvent hand mouseFocus ~~ self]) ifTrue:[^self].\\n\\tanEvent wasHandled: true.\\n\\tself sendEventAsIs: anEvent.! !\\n\\n!NetworkTerminalMorph methodsFor: 'events-processing' stamp: 'ar 10/24/2000 18:03'!\\nhandleMouseUp: anEvent\\n\\tanEvent wasHandled ifTrue:[^self]. \\\"not interested\\\"\\n\\tanEvent hand mouseFocus == self ifFalse:[^self]. \\\"Not interested in other parties\\\"\\n\\tanEvent hand releaseMouseFocus: self.\\n\\tanEvent wasHandled: true.\\n\\tself sendEventAsIs: anEvent.! !\\n\\n!NetworkTerminalMorph methodsFor: 'events-processing' stamp: 'ar 10/24/2000 18:06'!\\nhandlerForMouseDown: anEvent\\n\\t^self! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'geometry' stamp: 'RAA 7/24/2000 11:35'!\\nextent: newExtent\\n\\n\\tsuper extent: newExtent.\\n\\teventEncoder sendViewExtent: self extent! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'initialization' stamp: 'RAA 8/15/2000 12:06'!\\nconnection: aConnection\\n\\n\\tconnection := aConnection.\\n\\tdecoder := CanvasDecoder connection: aConnection.\\n\\teventEncoder := MorphicEventEncoder on: aConnection.! !\\n\\n!NetworkTerminalMorph methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitialize\\n\\tsuper initialize.\\n\\tbackgroundForm := (\\n\\t\\t(StringMorph contents: '......' font: (TextStyle default fontOfSize: 24))\\n\\t\\t\\tcolor: Color white\\n\\t) imageForm.\\n\\tbounds := backgroundForm boundingBox.\\n! !\\n\\n!NetworkTerminalMorph methodsFor: 'initialization' stamp: 'RAA 8/15/2000 10:45'!\\nopenInStyle: aSymbol\\n\\n\\taSymbol == #naked ifTrue: [\\n\\t\\tself openInWorld.\\n\\t].\\n\\taSymbol == #scaled ifTrue: [\\n\\t\\tself openScaled.\\n\\t].\\n\\taSymbol == #bordered ifTrue: [\\n\\t\\tAlignmentMorph newColumn\\n\\t\\t\\thResizing: \\t#shrinkWrap;\\n\\t\\t\\tvResizing: \\t#shrinkWrap;\\n\\t\\t\\tborderWidth: 8;\\n\\t\\t\\tborderColor: Color blue;\\n\\t\\t\\taddMorph: self;\\n\\t\\t\\topenInWorld.\\n\\t].\\n\\n\\t[\\n\\t\\t[self world isNil] whileFalse: [(Delay forSeconds: 2) wait].\\n\\t\\tself disconnect.\\n\\t] fork.\\n\\n! !\\n\\n!NetworkTerminalMorph methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:26'!\\nopenScaled\\n\\n\\t| window tm |\\n\\twindow := NetworkTerminalBorderMorph new\\n\\t\\tminWidth: 100;\\n\\t\\tminHeight: 100;\\n\\t\\tborderWidth: 8;\\n\\t\\tborderColor: Color orange;\\n\\t\\tbounds: (0@0 extent: Display extent * 3 // 4).\\n\\ttm := BOBTransformationMorph new.\\n\\ttm useRegularWarpBlt: true.\\t\\t\\\"try to reduce memory used\\\"\\n\\twindow addMorphBack: tm.\\n\\ttm addMorph: self.\\n\\twindow openInWorld.\\n\\tNebraskaNavigationMorph new \\n\\t\\tnebraskaBorder: window;\\n\\t\\tnebraskaTerminal: self;\\n\\t\\topenInWorld.! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'layout' stamp: 'sd 11/20/2005 21:25'!\\nacceptDroppingMorph: morphToDrop event: evt\\n\\n\\t| myCopy outData null |\\n\\n\\t(morphToDrop isKindOf: NewHandleMorph) ifTrue: [\\t\\t\\t\\\"don't send these\\\"\\n\\t\\t^morphToDrop rejectDropMorphEvent: evt.\\n\\t].\\n\\tself eToyRejectDropMorph: morphToDrop event: evt.\\t\\t\\\"we don't really want it\\\"\\n\\n\\t\\\"7 mar 2001 - remove #veryDeepCopy\\\"\\n\\tmyCopy := morphToDrop.\\t\\\"gradient fills require doing this second\\\"\\n\\tmyCopy setProperty: #positionInOriginatingWorld toValue: morphToDrop position.\\n\\n\\toutData := myCopy eToyStreamedRepresentationNotifying: nil.\\n\\tnull := String with: 0 asCharacter.\\n\\tEToyPeerToPeer new \\n\\t\\tsendSomeData: {\\n\\t\\t\\tEToyIncomingMessage typeMorph,null. \\n\\t\\t\\tPreferences defaultAuthorName,null.\\n\\t\\t\\toutData\\n\\t\\t}\\n\\t\\tto: (NetNameResolver stringFromAddress: connection remoteAddress)\\n\\t\\tfor: self.\\n! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'shutting down' stamp: 'ls 4/11/2000 18:36'!\\ndisconnect\\n\\tconnection ifNotNil: [ connection destroy ].\\n\\teventEncoder := connection := decoder := nil.! !\\n\\n!NetworkTerminalMorph methodsFor: 'shutting down' stamp: 'RAA 12/13/2000 08:21'!\\nrequestBufferedConnection\\n\\n\\teventEncoder ifNotNil: [eventEncoder requestBufferedConnection].\\n! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'stepping and presenter' stamp: 'ar 10/25/2000 23:19'!\\nstep\\n\\n\\tdecoder ifNil: [ ^self ].\\n\\tdecoder processIOOnForce: [ :rectangle | self forceToFront: rectangle ].! !\\n\\n\\n!NetworkTerminalMorph methodsFor: 'testing' stamp: 'ls 3/25/2000 16:58'!\\nstepTime\\n\\t^10! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNetworkTerminalMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!NetworkTerminalMorph class methodsFor: 'instance creation' stamp: 'RAA 8/4/2000 15:13'!\\nconnectTo: serverHost\\n\\n\\t^self connectTo: serverHost port: NebraskaServer defaultPort\\n\\n! !\\n\\n!NetworkTerminalMorph class methodsFor: 'instance creation' stamp: 'sd 11/20/2005 21:26'!\\nconnectTo: serverHost port: serverPort\\n\\n\\t| stringSock |\\n\\n\\tstringSock := self socketConnectedTo: serverHost port: serverPort.\\n\\t^self new connection: stringSock\\n! !\\n\\n!NetworkTerminalMorph class methodsFor: 'instance creation' stamp: 'RAA 7/24/2000 12:08'!\\nopenAndConnectTo: serverHost\\n\\n\\t^self openAndConnectTo: serverHost port: NebraskaServer defaultPort\\n\\n! !\\n\\n!NetworkTerminalMorph class methodsFor: 'instance creation' stamp: 'sd 11/20/2005 21:26'!\\nopenAndConnectTo: serverHost port: serverPort\\n\\n\\t| stringSock me |\\n\\n\\tstringSock := self socketConnectedTo: serverHost port: serverPort.\\n\\tme := self new connection: stringSock.\\n\\t^me openInStyle: #naked\\n! !\\n\\n!NetworkTerminalMorph class methodsFor: 'instance creation' stamp: 'sd 11/20/2005 21:26'!\\nsocketConnectedTo: serverHost port: serverPort\\n\\n\\t| sock |\\n\\n\\tSocket initializeNetwork.\\n\\tsock := Socket new.\\n\\t[sock connectTo: (NetNameResolver addressForName: serverHost) port: serverPort]\\n\\t\\ton: ConnectionTimedOut\\n\\t\\tdo: [:ex | self error: 'could not connect to server' ].\\n\\t^StringSocket on: sock\\n\\n! !\\nHandleMorph subclass: #NewHandleMorph\\n\\tinstanceVariableNames: 'hand offset waitingForClickInside'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Widgets'!\\n\\n!NewHandleMorph methodsFor: 'all' stamp: 'di 5/18/1998 15:27'!\\nfollowHand: aHand forEachPointDo: block1 lastPointDo: block2\\n\\thand _ aHand.\\n\\tpointBlock _ block1.\\n\\tlastPointBlock _ block2.\\n\\tself position: hand lastEvent cursorPoint - (self extent // 2)! !\\n\\n!NewHandleMorph methodsFor: 'all' stamp: 'ar 8/16/2001 15:48'!\\nfollowHand: aHand forEachPointDo: block1 lastPointDo: block2 withCursor: aCursor\\n\\thand _ aHand.\\n\\thand showTemporaryCursor: aCursor \\\"hotSpotOffset: aCursor offset negated\\\".\\n\\tborderWidth _ 0.\\n\\tcolor _ Color transparent.\\n\\tpointBlock _ block1.\\n\\tlastPointBlock _ block2.\\n\\tself position: hand lastEvent cursorPoint - (self extent // 2)! !\\n\\n!NewHandleMorph methodsFor: 'all' stamp: 'RAA 4/19/2001 11:36'!\\nsensorMode\\n\\n\\t\\\"If our client is still addressing the Sensor directly, we need to do so as well\\\"\\n\\t^self valueOfProperty: #sensorMode ifAbsent: [false].\\n! !\\n\\n!NewHandleMorph methodsFor: 'all' stamp: 'RAA 4/19/2001 11:36'!\\nsensorMode: aBoolean\\n\\n\\t\\\"If our client is still addressing the Sensor directly, we need to do so as well\\\"\\n\\tself setProperty: #sensorMode toValue: aBoolean.\\n! !\\n\\n\\n!NewHandleMorph methodsFor: 'dropping/grabbing' stamp: 'di 4/30/1999 14:06'!\\njustDroppedInto: aMorph event: anEvent\\n\\t\\\"No dropping behavior because stepping will delete me.\\n\\tMoreover it needs to be done that way to evaluate lastPointBlock\\\"\\n! !\\n\\n!NewHandleMorph methodsFor: 'dropping/grabbing' stamp: 'ar 10/5/2000 18:16'!\\nundoGrabCommand\\n\\t^nil! !\\n\\n\\n!NewHandleMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:29'!\\ninitialize\\n\\\"initialize the state of the receiver\\\"\\n\\n\\tsuper initialize.\\n\\\"\\\"\\n\\twaitingForClickInside _ true.\\n\\tPreferences noviceMode\\n\\t\\tifTrue: [self setBalloonText: 'stretch']! !\\n\\n\\n!NewHandleMorph methodsFor: 'stepping and presenter' stamp: 'RAA 4/19/2001 11:37'!\\nstep\\n\\t| eventSource |\\n\\n\\teventSource _ self sensorMode ifTrue: [\\n\\t\\tSensor\\n\\t] ifFalse: [\\n\\t\\thand lastEvent\\n\\t].\\n\\teventSource anyButtonPressed\\n\\t\\tifTrue: [waitingForClickInside _ false.\\n\\t\\t\\t\\tself position: eventSource cursorPoint - (self extent // 2).\\n\\t\\t\\t\\tpointBlock value: self center]\\n\\t\\tifFalse: [waitingForClickInside\\n\\t\\t\\t\\t\\tifTrue: [(self containsPoint: eventSource cursorPoint)\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [\\\"mouse wandered out before clicked\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t^ self delete]]\\n\\t\\t\\t\\t\\tifFalse: [lastPointBlock value: self center.\\n\\t\\t\\t\\t\\t\\t\\t^ self delete]]! !\\n\\n\\n!NewHandleMorph methodsFor: 'submorphs-add/remove' stamp: 'ar 8/16/2001 15:38'!\\ndelete\\n\\thand ifNotNil:[\\n\\t\\thand showTemporaryCursor: nil.\\n\\t].\\n\\tsuper delete.! !\\n\\n\\n!NewHandleMorph methodsFor: 'WiW support' stamp: 'RAA 1/10/2001 10:15'!\\nmorphicLayerNumber\\n\\n\\t^1\\t\\t\\\"handles are very front-like - e.g. the spawn reframe logic actually asks if the first submorph of the world is one of us before deciding to create one\\\"! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNewHandleMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!NewHandleMorph class methodsFor: 'new-morph participation' stamp: 'di 5/3/1998 10:08'!\\nincludeInNewMorphMenu\\n\\t^ false! !\\nObject subclass: #NewParagraph\\n\\tinstanceVariableNames: 'text textStyle firstCharacterIndex container lines positionWhenComposed offsetToEnd maxRightX selectionStart selectionStop wantsColumnBreaks focused'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Text Support'!\\n!NewParagraph commentStamp: '<historical>' prior: 0!\\nA Paragraph represents text that has been laid out, or composed, in some container.\\n\\ttext \\t\\tA Text with encoded per-character emphasis.\\n\\ttextStyle\\tA TextStyle with font set, line height and horizontal alignment.\\n\\tfirstCharacterIndex The starting index in text for this paragraph, allowing\\n\\t\\t\\t\\tcomposition of a long text into a number of containers.\\n\\tcontainer\\tA Rectangle or TextContainer that determines where text can go.\\n\\tlines\\t\\tAn Array of TextLines comprising the final layout of the text\\n\\t\\t\\t\\tafter it has been composed within its container.\\n\\tpositionWhenComposed As its name implies. Allows display at new locations\\n\\t\\t\\t\\twithout the need to recompose the text.\\nLines are ordered vertically. However, for a given y, there may be several lines in left to right order. Lines must never be empty, even if text is empty.\\n\\nNotes on yet another hack - 5 Feb 2001\\n\\nWe really need to clean up #composeLinesFrom:to:delta:into:priorLines:atY:!!!!!!\\n\\nI added one more habdful of code to correct:\\n\\nThis is an annoying bug that's been around for a couple of years, but I finally figured out how to duplicate the problem, so I figured I'd just report it now. (It doesn't necessarily have to be fixed for 3.0 if it looks messy, but if it's a simple fix, it would be worth it.)\\n\\nIn Morphic, if you have the following text in a workspace:\\n\\nThis is line 1\\nThis is line 2\\n\\n**and** you have a return character after line 2, you will normally be able to click the mouse two times below line 2 in order to select all the text. If you edit line 2 (e.g. so that it reads \\\"line number 2\\\"), you can still select all the text by clicking below the second line. However, if you edit line 1, you will not be able to select all the text from the bottom in the same way. Things get messed up such that the last return character seems to be gone. In this state, if you position the cursor immediately after the 2, and press the right arrow, the cursor jumps to the beginning of line 2... oof. (report by Doug Way)\\n\\nWhile I don't have a very deep understanding of the above mentioned method, I was able to determine that text ending in a CR worked better in the editor when the last entry in <lines> had a start of text size + 1 and a stop of text size. I have accordingly added code near the end to ensure this. It seems to have fixed the problem, but we do need to clean this baby up some day. - Bob\\n!\\n]style[(830 38 127 1000 388)f1,f2cblue;,f1,f1cred;,f1!\\n\\n\\n!NewParagraph methodsFor: 'access' stamp: 'di 11/16/97 09:02'!\\nadjustedFirstCharacterIndex\\n\\t\\\"Return the index in the text where this paragraph WOULD begin if nothing had changed, except the size of the text -- ie if there have only been an insertion of deletion in the preceding morphs\\\"\\n\\toffsetToEnd ifNil: [^ -1].\\n\\t^ text size - offsetToEnd! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'di 10/24/97 17:38'!\\nextent\\n\\t^ container width @ (lines last bottom - lines first top)! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'di 11/8/97 15:41'!\\nfirstCharacterIndex\\n\\t^ firstCharacterIndex! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'rr 3/22/2004 12:42'!\\nfocused\\n\\tfocused ifNil: [focused := false].\\n\\t^ focused! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'rr 3/22/2004 12:41'!\\nfocused: aBoolean\\n\\tfocused := aBoolean! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'di 10/23/97 21:01'!\\nlastCharacterIndex\\n\\t^ lines last last! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'sbw 10/13/1999 22:31'!\\nnumberOfLines\\n\\n\\t^lines size! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'sw 1/13/98 21:31'!\\nstring\\n\\t^ text string! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'di 10/21/97 14:39'!\\ntext\\n\\t^ text! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'jm 11/19/97 20:27'!\\ntextOwner: ignored \\\"See TextOnCurve\\\"! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'di 10/21/97 14:39'!\\ntextStyle\\n\\t^ textStyle! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'di 10/23/97 19:33'!\\ntextStyle: aTextStyle \\n\\t\\\"Set the style by which the receiver should display its text.\\\"\\n\\ttextStyle _ aTextStyle! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'RAA 5/6/2001 15:04'!\\nwantsColumnBreaks\\n\\n\\t^wantsColumnBreaks! !\\n\\n!NewParagraph methodsFor: 'access' stamp: 'RAA 5/6/2001 15:03'!\\nwantsColumnBreaks: aBoolean\\n\\n\\twantsColumnBreaks _ aBoolean! !\\n\\n\\n!NewParagraph methodsFor: 'alignment' stamp: 'di 10/25/97 19:26'!\\ncentered \\n\\ttextStyle centered! !\\n\\n!NewParagraph methodsFor: 'alignment' stamp: 'di 10/25/97 19:26'!\\njustified \\n\\ttextStyle justified! !\\n\\n!NewParagraph methodsFor: 'alignment' stamp: 'di 10/25/97 19:26'!\\nleftFlush \\n\\ttextStyle leftFlush! !\\n\\n!NewParagraph methodsFor: 'alignment' stamp: 'di 10/25/97 19:26'!\\nrightFlush \\n\\ttextStyle rightFlush! !\\n\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'jm 2/25/2003 16:20'!\\nOLDcomposeLinesFrom: start to: stop delta: delta into: lineColl priorLines: priorLines atY: startingY \\n\\t\\\"While the section from start to stop has changed, composition may ripple all the way to the end of the text. However in a rectangular container, if we ever find a line beginning with the same character as before (ie corresponding to delta in the old lines), then we can just copy the old lines from there to the end of the container, with adjusted indices and y-values\\\"\\n\\n\\t| charIndex lineY lineHeight scanner line row firstLine lineHeightGuess saveCharIndex hitCR maybeSlide sliding bottom priorIndex priorLine |\\n\\tcharIndex := start.\\n\\tlines := lineColl.\\n\\tlineY := startingY.\\n\\tlineHeightGuess := textStyle lineGrid.\\n\\tmaxRightX := container left.\\n\\tmaybeSlide := stop < text size and: [container isMemberOf: Rectangle].\\n\\tsliding := false.\\n\\tpriorIndex := 1.\\n\\tbottom := container bottom.\\n\\tscanner := CompositionScanner new text: text textStyle: textStyle.\\n\\tfirstLine := true.\\n\\t[charIndex <= text size and: [lineY + lineHeightGuess <= bottom]] \\n\\t\\twhileTrue: \\n\\t\\t\\t[sliding \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[\\\"Having detected the end of rippling recoposition, we are only sliding old lines\\\"\\n\\n\\t\\t\\t\\t\\tpriorIndex < priorLines size \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[\\\"Adjust and re-use previously composed line\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\tpriorIndex := priorIndex + 1.\\n\\t\\t\\t\\t\\t\\t\\tpriorLine := (priorLines at: priorIndex) slideIndexBy: delta\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tandMoveTopTo: lineY.\\n\\t\\t\\t\\t\\t\\t\\tlineColl addLast: priorLine.\\n\\t\\t\\t\\t\\t\\t\\tlineY := priorLine bottom.\\n\\t\\t\\t\\t\\t\\t\\tcharIndex := priorLine last + 1]\\n\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t[\\\"There are no more priorLines to slide.\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\tsliding := maybeSlide := false]]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[lineHeight := lineHeightGuess.\\n\\t\\t\\t\\t\\tsaveCharIndex := charIndex.\\n\\t\\t\\t\\t\\thitCR := false.\\n\\t\\t\\t\\t\\trow := container rectanglesAt: lineY height: lineHeight.\\n\\t\\t\\t\\t\\t1 to: row size\\n\\t\\t\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t\\t\\t[:i | \\n\\t\\t\\t\\t\\t\\t\\t(charIndex <= text size and: [hitCR not]) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[line := scanner \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcomposeFrom: charIndex\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tinRectangle: (row at: i)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tfirstLine: firstLine\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tleftSide: i = 1\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\trightSide: i = row size.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tlines addLast: line.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t(text at: line last) = Character cr ifTrue: [hitCR := true].\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tlineHeight := lineHeight max: line lineHeight.\\t\\\"includes font changes\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcharIndex := line last + 1]].\\n\\n\\t\\t\\t\\t\\tlineY := lineY + lineHeight.\\n\\t\\t\\t\\t\\trow notEmpty \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[lineY > bottom \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[\\\"Oops -- the line is really too high to fit -- back out\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcharIndex := saveCharIndex.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\trow do: [:r | lines removeLast]]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[\\\"It's OK -- the line still fits.\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tmaxRightX := maxRightX max: scanner rightX.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t1 to: row size - 1\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[:i | \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\\"Adjust heights across row if necess\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t(lines at: lines size - row size + i) lineHeight: lines last lineHeight\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tbaseline: lines last baseline].\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcharIndex > text size \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[\\\"end of text\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\thitCR \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[\\\"If text ends with CR, add a null line at the end\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tlineY + lineHeightGuess <= container bottom \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[row := container rectanglesAt: lineY height: lineHeightGuess.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\trow notEmpty \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[line := (TextLine \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tstart: charIndex\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tstop: charIndex - 1\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tinternalSpaces: 0\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tpaddingWidth: 0)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\trectangle: row first;\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tlineHeight: lineHeightGuess baseline: textStyle baseline.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tlines addLast: line]]].\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tlines := lines asArray.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t^maxRightX].\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tfirstLine := false]].\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t(maybeSlide and: [charIndex > stop]) \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[\\\"Check whether we are now in sync with previously composed lines\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\t[priorIndex < priorLines size \\n\\t\\t\\t\\t\\t\\t\\t\\tand: [(priorLines at: priorIndex) first < (charIndex - delta)]] \\n\\t\\t\\t\\t\\t\\t\\t\\t\\twhileTrue: [priorIndex := priorIndex + 1].\\n\\t\\t\\t\\t\\t\\t\\t(priorLines at: priorIndex) first = (charIndex - delta) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[\\\"Yes -- next line will have same start as prior line.\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tpriorIndex := priorIndex - 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tmaybeSlide := false.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tsliding := true]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[priorIndex = priorLines size \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[\\\"Weve reached the end of priorLines,\\n\\t\\t\\t\\t\\t\\t\\t\\tso no use to keep looking for lines to slide.\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tmaybeSlide := false]]]]].\\n\\tfirstLine \\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"No space in container or empty text\\\"\\n\\n\\t\\t\\tline := (TextLine \\n\\t\\t\\t\\t\\t\\tstart: start\\n\\t\\t\\t\\t\\t\\tstop: start - 1\\n\\t\\t\\t\\t\\t\\tinternalSpaces: 0\\n\\t\\t\\t\\t\\t\\tpaddingWidth: 0)\\n\\t\\t\\t\\t\\t\\trectangle: (container topLeft extent: 0 @ lineHeightGuess);\\n\\t\\t\\t\\t\\t\\tlineHeight: lineHeightGuess baseline: textStyle baseline.\\n\\t\\t\\tlines := Array with: line]\\n\\t\\tifFalse: [self fixLastWithHeight: lineHeightGuess].\\n\\t\\\"end of container\\\"\\n\\tlines := lines asArray.\\n\\t^maxRightX! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'di 11/8/97 15:31'!\\ncompose: t style: ts from: startingIndex in: textContainer\\n\\ttext _ t.\\n\\ttextStyle _ ts.\\n\\tfirstCharacterIndex _ startingIndex.\\n\\toffsetToEnd _ text size - firstCharacterIndex.\\n\\tcontainer _ textContainer.\\n\\tself composeAll! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'yo 12/20/2002 16:18'!\\ncomposeAll\\n\\ttext string isOctetString ifTrue: [\\n\\t\\t^ self composeLinesFrom: firstCharacterIndex to: text size delta: 0\\n\\t\\t\\tinto: OrderedCollection new priorLines: Array new atY: container top.\\n\\t].\\n\\n\\t^ self multiComposeLinesFrom: firstCharacterIndex to: text size delta: 0\\n\\t\\tinto: OrderedCollection new priorLines: Array new atY: container top.\\n! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'di 11/15/97 09:21'!\\ncomposeAllStartingAt: characterIndex\\n\\tfirstCharacterIndex _ characterIndex.\\n\\toffsetToEnd _ text size - firstCharacterIndex.\\n\\tself composeAll! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'RAA 5/7/2001 10:58'!\\ncomposeLinesFrom: start to: stop delta: delta into: lineColl priorLines: priorLines\\n\\tatY: startingY\\n\\t\\\"While the section from start to stop has changed, composition may ripple all the way to the end of the text. However in a rectangular container, if we ever find a line beginning with the same character as before (ie corresponding to delta in the old lines), then we can just copy the old lines from there to the end of the container, with adjusted indices and y-values\\\"\\n\\n\\t| newResult |\\n\\n\\tnewResult _ TextComposer new\\n\\t\\tcomposeLinesFrom: start \\n\\t\\tto: stop \\n\\t\\tdelta: delta \\n\\t\\tinto: lineColl \\n\\t\\tpriorLines: priorLines\\n\\t\\tatY: startingY\\n\\t\\ttextStyle: textStyle \\n\\t\\ttext: text \\n\\t\\tcontainer: container\\n\\t\\twantsColumnBreaks: wantsColumnBreaks == true.\\n\\tlines _ newResult first asArray.\\n\\tmaxRightX _ newResult second.\\n\\t^maxRightX\\n! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'di 10/22/97 11:13'!\\ncompositionRectangle\\n\\t^ container! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'RAA 2/25/2001 15:02'!\\nfixLastWithHeight: lineHeightGuess\\n\\\"This awful bit is to ensure that if we have scanned all the text and the last character is a CR that there is a null line at the end of lines. Sometimes this was not happening which caused anomalous selections when selecting all the text. This is implemented as a post-composition fixup because I coul;dn't figure out where to put it in the main logic.\\\"\\n\\n\\t| oldLastLine newRectangle line |\\n\\n\\t(text size > 1 and: [text last = Character cr]) ifFalse: [^self].\\n\\n\\toldLastLine _ lines last.\\n\\toldLastLine last - oldLastLine first >= 0 ifFalse: [^self].\\n\\toldLastLine last = text size ifFalse: [^self].\\n\\n\\tnewRectangle _ oldLastLine left @ oldLastLine bottom \\n\\t\\t\\t\\textent: 0@(oldLastLine bottom - oldLastLine top).\\n\\t\\\"Even though we may be below the bottom of the container,\\n\\tit is still necessary to compose the last line for consistency...\\\"\\n\\n\\tline _ TextLine start: text size+1 stop: text size internalSpaces: 0 paddingWidth: 0.\\n\\tline rectangle: newRectangle.\\n\\tline lineHeight: lineHeightGuess baseline: textStyle baseline.\\n\\tlines _ lines, (Array with: line).\\n! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'yo 1/3/2003 12:17'!\\nmultiComposeLinesFrom: start to: stop delta: delta into: lineColl priorLines: priorLines\\n\\tatY: startingY\\n\\t\\\"While the section from start to stop has changed, composition may ripple all the way to the end of the text. However in a rectangular container, if we ever find a line beginning with the same character as before (ie corresponding to delta in the old lines), then we can just copy the old lines from there to the end of the container, with adjusted indices and y-values\\\"\\n\\n\\t| newResult |\\n\\n\\tnewResult _ MultiTextComposer new\\n\\t\\tmultiComposeLinesFrom: start \\n\\t\\tto: stop \\n\\t\\tdelta: delta \\n\\t\\tinto: lineColl \\n\\t\\tpriorLines: priorLines\\n\\t\\tatY: startingY\\n\\t\\ttextStyle: textStyle \\n\\t\\ttext: text \\n\\t\\tcontainer: container\\n\\t\\twantsColumnBreaks: wantsColumnBreaks == true.\\n\\tlines _ newResult first asArray.\\n\\tmaxRightX _ newResult second.\\n\\t\\\"maxRightX printString displayAt: 0@0.\\\"\\n\\t^maxRightX\\n! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'yo 12/20/2002 16:18'!\\nrecomposeFrom: start to: stop delta: delta\\n\\t\\\"Recompose this paragraph. The altered portion is between start and stop.\\n\\tRecomposition may continue to the end of the text, due to a ripple effect.\\n\\tDelta is the amount by which the current text is longer than it was\\n\\twhen its current lines were composed.\\\"\\n\\t| startLine newLines |\\n\\t\\\"Have to recompose line above in case a word-break was affected.\\\"\\n\\tstartLine _ (self lineIndexForCharacter: start) - 1 max: 1.\\n\\t[startLine > 1 and: [(lines at: startLine-1) top = (lines at: startLine) top]]\\n\\t\\twhileTrue: [startLine _ startLine - 1]. \\\"Find leftmost of line pieces\\\"\\n\\tnewLines _ OrderedCollection new: lines size + 1.\\n\\t1 to: startLine-1 do: [:i | newLines addLast: (lines at: i)].\\n\\ttext string isOctetString ifTrue: [\\n\\t\\t^ self composeLinesFrom: (lines at: startLine) first to: stop delta: delta\\n\\t\\t\\tinto: newLines priorLines: lines\\n\\t\\t\\tatY: (lines at: startLine) top.\\n\\t].\\n\\tself multiComposeLinesFrom: (lines at: startLine) first to: stop delta: delta\\n\\t\\tinto: newLines priorLines: lines\\n\\t\\tatY: (lines at: startLine) top.\\n! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'RAA 5/6/2001 15:09'!\\ntestNewComposeAll\\n\\t| newResult |\\n\\tself \\n\\t\\tOLDcomposeLinesFrom: firstCharacterIndex \\n\\t\\tto: text size \\n\\t\\tdelta: 0\\n\\t\\tinto: OrderedCollection new \\n\\t\\tpriorLines: Array new \\n\\t\\tatY: container top.\\n\\tnewResult _ TextComposer new\\n\\t\\tcomposeLinesFrom: firstCharacterIndex \\n\\t\\tto: text size \\n\\t\\tdelta: 0\\n\\t\\tinto: OrderedCollection new \\n\\t\\tpriorLines: Array new \\n\\t\\tatY: container top\\n\\t\\ttextStyle: textStyle \\n\\t\\ttext: text \\n\\t\\tcontainer: container\\n\\t\\twantsColumnBreaks: false.\\n\\tnewResult first with: lines do: [ :e1 :e2 |\\n\\t\\te1 longPrintString = e2 longPrintString ifFalse: [self halt].\\n\\t].\\n\\tnewResult second = maxRightX ifFalse: [self halt].\\n\\t^{newResult. {lines. maxRightX}}\\n! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'yo 12/17/2002 14:48'!\\ntestNewComposeAll2\\n\\t| newResult |\\n\\tnewResult _ TextComposer new\\n\\t\\tcomposeLinesFrom: firstCharacterIndex \\n\\t\\tto: text size \\n\\t\\tdelta: 0\\n\\t\\tinto: OrderedCollection new \\n\\t\\tpriorLines: Array new \\n\\t\\tatY: container top\\n\\t\\ttextStyle: textStyle \\n\\t\\ttext: text \\n\\t\\tcontainer: container\\n\\t\\twantsColumnBreaks: false.\\n\\t^{newResult. {lines. maxRightX}}\\n! !\\n\\n!NewParagraph methodsFor: 'composition' stamp: 'yo 12/18/2002 15:00'!\\ntestNewComposeAll3\\n\\t| newResult |\\n\\tnewResult _ TextComposer new\\n\\t\\tmultiComposeLinesFrom: firstCharacterIndex \\n\\t\\tto: text size \\n\\t\\tdelta: 0\\n\\t\\tinto: OrderedCollection new \\n\\t\\tpriorLines: Array new \\n\\t\\tatY: container top\\n\\t\\ttextStyle: textStyle \\n\\t\\ttext: text \\n\\t\\tcontainer: (0@0 extent: 31@60)\\n\\t\\twantsColumnBreaks: false.\\n\\t^{newResult. {lines. maxRightX}}\\n! !\\n\\n\\n!NewParagraph methodsFor: 'copying' stamp: 'di 5/21/1998 21:45'!\\ndeepCopy\\n\\t\\\"Don't want to copy the container (etc) or fonts in the TextStyle.\\\"\\n\\t| new |\\n\\tnew _ self copy.\\n\\tnew textStyle: textStyle copy\\n\\t\\tlines: lines copy\\n\\t\\ttext: text deepCopy.\\n\\t^ new! !\\n\\n\\n!NewParagraph methodsFor: 'display' stamp: 'di 8/13/2000 12:27'!\\nasParagraphForPostscript\\n\\n\\t^ self! !\\n\\n!NewParagraph methodsFor: 'display' stamp: 'lr 7/12/2006 09:27'!\\ncaretWidth\\n\\t^ Preferences caretWidth! !\\n\\n!NewParagraph methodsFor: 'display' stamp: 'nk 8/31/2004 11:10'!\\ndisplaySelectionInLine: line on: aCanvas \\n\\t| leftX rightX w caretColor |\\n\\tselectionStart ifNil: [^self].\\t\\\"No selection\\\"\\n\\taCanvas isShadowDrawing ifTrue: [ ^self ].\\t\\\"don't draw selection with shadow\\\"\\n\\tselectionStart = selectionStop \\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"Only show caret on line where clicked\\\"\\n\\n\\t\\t\\tselectionStart textLine ~= line ifTrue: [^self]]\\n\\t\\tifFalse: \\n\\t\\t\\t[\\\"Test entire selection before or after here\\\"\\n\\n\\t\\t\\t(selectionStop stringIndex < line first \\n\\t\\t\\t\\tor: [selectionStart stringIndex > (line last + 1)]) ifTrue: [^self].\\t\\\"No selection on this line\\\"\\n\\t\\t\\t(selectionStop stringIndex = line first \\n\\t\\t\\t\\tand: [selectionStop textLine ~= line]) ifTrue: [^self].\\t\\\"Selection ends on line above\\\"\\n\\t\\t\\t(selectionStart stringIndex = (line last + 1) \\n\\t\\t\\t\\tand: [selectionStop textLine ~= line]) ifTrue: [^self]].\\t\\\"Selection begins on line below\\\"\\n\\tleftX := (selectionStart stringIndex < line first \\n\\t\\t\\t\\tifTrue: [line ]\\n\\t\\t\\t\\tifFalse: [selectionStart ])left.\\n\\trightX := (selectionStop stringIndex > (line last + 1) or: \\n\\t\\t\\t\\t\\t[selectionStop stringIndex = (line last + 1) \\n\\t\\t\\t\\t\\t\\tand: [selectionStop textLine ~= line]]) \\n\\t\\t\\t\\tifTrue: [line right]\\n\\t\\t\\t\\tifFalse: [selectionStop left].\\n\\tselectionStart = selectionStop \\n\\t\\tifTrue: \\n\\t\\t\\t[rightX := rightX + 1.\\n\\t\\t\\tw := self caretWidth.\\n\\t\\t\\tcaretColor := self insertionPointColor.\\n\\t\\t\\t1 to: w\\n\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t[:i | \\n\\t\\t\\t\\t\\t\\\"Draw caret triangles at top and bottom\\\"\\n\\n\\t\\t\\t\\t\\taCanvas fillRectangle: ((leftX - w + i - 1) @ (line top + i - 1) \\n\\t\\t\\t\\t\\t\\t\\t\\textent: ((w - i) * 2 + 3) @ 1)\\n\\t\\t\\t\\t\\t\\tcolor: caretColor.\\n\\t\\t\\t\\t\\taCanvas fillRectangle: ((leftX - w + i - 1) @ (line bottom - i) \\n\\t\\t\\t\\t\\t\\t\\t\\textent: ((w - i) * 2 + 3) @ 1)\\n\\t\\t\\t\\t\\t\\tcolor: caretColor].\\n\\t\\t\\taCanvas fillRectangle: (leftX @ line top corner: rightX @ line bottom)\\n\\t\\t\\t\\tcolor: caretColor]\\n\\t\\tifFalse: \\n\\t\\t\\t[aCanvas fillRectangle: (leftX @ line top corner: rightX @ line bottom)\\n\\t\\t\\t\\tcolor: self selectionColor]! !\\n\\n!NewParagraph methodsFor: 'display' stamp: 'rr 3/22/2004 19:56'!\\ninsertionPointColor\\n\\tself focused ifFalse: [^ Color transparent].\\n\\t^ Display depth <= 2\\n\\t\\tifTrue: [Color black]\\n\\t\\tifFalse: [Preferences insertionPointColor]! !\\n\\n!NewParagraph methodsFor: 'display' stamp: 'rr 3/23/2004 19:52'!\\nselectionColor\\n\\t| color |\\n\\tDisplay depth = 1 ifTrue: [^ Color veryLightGray].\\n\\tDisplay depth = 2 ifTrue: [^ Color gray].\\n\\tcolor := Preferences textHighlightColor.\\n\\tself focused ifFalse: [color := color alphaMixed: 0.2 with: Color veryVeryLightGray].\\n\\t^ color! !\\n\\n\\n!NewParagraph methodsFor: 'editing' stamp: 'mk 5/28/2005 11:15'!\\nclickAt: clickPoint for: model controller: editor\\n\\t\\\"Give sensitive text a chance to fire. Display flash: (100@100 extent: 100@100).\\\"\\n\\t| startBlock action target range boxes box |\\n\\taction _ false.\\n\\tstartBlock _ self characterBlockAtPoint: clickPoint.\\n\\t(text attributesAt: startBlock stringIndex forStyle: textStyle) \\n\\t\\tdo: [:att | att mayActOnClick ifTrue:\\n\\t\\t\\t\\t[(target _ model) ifNil: [target _ editor morph].\\n\\t\\t\\t\\trange _ text rangeOf: att startingAt: startBlock stringIndex.\\n\\t\\t\\t\\tboxes _ self selectionRectsFrom: (self characterBlockForIndex: range first) \\n\\t\\t\\t\\t\\t\\t\\tto: (self characterBlockForIndex: range last+1).\\n\\t\\t\\t\\tbox _ boxes detect: [:each | each containsPoint: clickPoint] ifNone: [nil].\\n\\t\\t\\t\\tbox ifNotNil:\\n\\t\\t\\t\\t\\t[ box _ (editor transformFrom: nil) invertBoundsRect: box.\\n\\t\\t\\t\\t\\teditor morph allOwnersDo: [ :m | box _ box intersect: (m boundsInWorld) ].\\n\\t\\t\\t\\t\\tUtilities awaitMouseUpIn: box\\n\\t\\t\\t\\t\\t\\trepeating: []\\n\\t\\t\\t\\t\\t\\tifSucceed: [(att actOnClickFor: target in: self at: clickPoint editor: editor) ifTrue: [action _ true]].\\n\\t\\t\\t\\t\\tCursor currentCursor == Cursor webLink ifTrue:[Cursor normal show].\\n\\t\\t\\t\\t]]].\\n\\t^ action! !\\n\\n!NewParagraph methodsFor: 'editing' stamp: 'di 4/28/1999 10:14'!\\nreplaceFrom: start to: stop with: aText displaying: displayBoolean \\n\\t\\\"Edit the text, and then recompose the lines.\\\" \\n\\ttext replaceFrom: start to: stop with: aText.\\n\\tself recomposeFrom: start to: start + aText size - 1 delta: aText size - (stop-start+1)! !\\n\\n\\n!NewParagraph methodsFor: 'fonts-display' stamp: 'nk 3/20/2004 11:13'!\\ndisplayOn: aCanvas using: displayScanner at: somePosition\\n\\t\\\"Send all visible lines to the displayScanner for display\\\"\\n\\t| visibleRectangle offset leftInRun line |\\n\\tvisibleRectangle _ aCanvas clipRect.\\n\\toffset _ (somePosition - positionWhenComposed) truncated.\\n\\tleftInRun _ 0.\\n\\t(self lineIndexForPoint: visibleRectangle topLeft)\\n\\t\\tto: (self lineIndexForPoint: visibleRectangle bottomRight)\\n\\t\\tdo: [:i | line _ lines at: i.\\n\\t\\t\\tself displaySelectionInLine: line on: aCanvas.\\n\\t\\t\\tline first <= line last ifTrue:\\n\\t\\t\\t\\t[leftInRun _ displayScanner displayLine: line\\n\\t\\t\\t\\t\\t\\t\\t\\toffset: offset leftInRun: leftInRun]].\\n! !\\n\\n\\n!NewParagraph methodsFor: 'initialize-release' stamp: 'tak 12/21/2004 13:29'!\\ninitialize\\n\\tself positionWhenComposed: 0 @ 0! !\\n\\n\\n!NewParagraph methodsFor: 'selection' stamp: 'ar 4/12/2005 19:53'!\\ncharacterBlockAtPoint: aPoint \\n\\t\\\"Answer a CharacterBlock for the character in the text at aPoint.\\\"\\n\\t| line |\\n\\tline _ lines at: (self lineIndexForPoint: aPoint).\\n\\t^ ((text string isWideString) ifTrue: [\\n\\t\\tMultiCharacterBlockScanner new text: text textStyle: textStyle\\n\\t] ifFalse: [CharacterBlockScanner new text: text textStyle: textStyle])\\n\\t\\tcharacterBlockAtPoint: aPoint index: nil\\n\\t\\tin: line! !\\n\\n!NewParagraph methodsFor: 'selection' stamp: 'ar 4/12/2005 19:53'!\\ncharacterBlockForIndex: index \\n\\t\\\"Answer a CharacterBlock for the character in text at index.\\\"\\n\\t| line |\\n\\tline _ lines at: (self lineIndexForCharacter: index).\\n\\t^ ((text string isWideString) ifTrue: [\\n\\t\\tMultiCharacterBlockScanner new text: text textStyle: textStyle\\n\\t] ifFalse: [\\n\\t\\tCharacterBlockScanner new text: text textStyle: textStyle\\n\\t])\\n\\t\\tcharacterBlockAtPoint: nil index: ((index max: line first) min: text size+1)\\n\\t\\tin: line! !\\n\\n!NewParagraph methodsFor: 'selection' stamp: 'jm 11/19/97 22:56'!\\ncontainsPoint: aPoint\\n\\t^ (lines at: (self lineIndexForPoint: aPoint)) rectangle\\n\\t\\tcontainsPoint: aPoint! !\\n\\n!NewParagraph methodsFor: 'selection' stamp: 'di 10/5/1998 12:59'!\\ndefaultCharacterBlock\\n\\t^ (CharacterBlock new stringIndex: firstCharacterIndex text: text\\n\\t\\t\\ttopLeft: lines first topLeft extent: 0 @ 0)\\n\\t\\ttextLine: lines first! !\\n\\n!NewParagraph methodsFor: 'selection' stamp: 'di 11/30/97 12:10'!\\nselectionRects\\n\\t\\\"Return an array of rectangles representing the selection region.\\\"\\n\\tselectionStart ifNil: [^ Array new].\\n\\t^ self selectionRectsFrom: selectionStart to: selectionStop! !\\n\\n!NewParagraph methodsFor: 'selection' stamp: 'ls 11/2/2001 23:10'!\\nselectionRectsFrom: characterBlock1 to: characterBlock2 \\n\\t\\\"Return an array of rectangles representing the area between the two character blocks given as arguments.\\\"\\n\\t| line1 line2 rects cb1 cb2 w |\\n\\tcharacterBlock1 <= characterBlock2\\n\\t\\tifTrue: [cb1 _ characterBlock1. cb2 _ characterBlock2]\\n\\t\\tifFalse: [cb2 _ characterBlock1. cb1 _ characterBlock2].\\n\\tcb1 = cb2 ifTrue:\\n\\t\\t[w _ self caretWidth.\\n\\t\\t^ Array with: (cb1 topLeft - (w@0) corner: cb1 bottomLeft + ((w+1)@0))].\\n\\tline1 _ self lineIndexForCharacter: cb1 stringIndex.\\n\\tline2 _ self lineIndexForCharacter: cb2 stringIndex.\\n\\tline1 = line2 ifTrue:\\n\\t\\t[^ Array with: (cb1 topLeft corner: cb2 bottomRight)].\\n\\trects _ OrderedCollection new.\\n\\trects addLast: (cb1 topLeft corner: (lines at: line1) bottomRight).\\n\\tline1+1 to: line2-1 do: [ :i |\\n\\t\\t| line |\\n\\t\\tline := lines at: i.\\n\\t\\t(line left = rects last left and: [ line right = rects last right ])\\n\\t\\t\\tifTrue: [ \\\"new line has same margins as old one -- merge them, so that the caller gets as few rectangles as possible\\\"\\n\\t\\t\\t\\t\\t| lastRect |\\n\\t\\t\\t\\t\\tlastRect := rects removeLast.\\n\\t\\t\\t\\t\\trects add: (lastRect bottom: line bottom) ]\\n\\t\\t\\tifFalse: [ \\\"differing margins; cannot merge\\\"\\n\\t\\t\\t\\t\\trects add: line rectangle ] ].\\n\\n\\trects addLast: ((lines at: line2) topLeft corner: cb2 bottomLeft).\\n\\t^ rects! !\\n\\n!NewParagraph methodsFor: 'selection' stamp: 'di 12/2/97 19:57'!\\nselectionStart: startBlock selectionStop: stopBlock\\n\\tselectionStart _ startBlock.\\n\\tselectionStop _ stopBlock.! !\\n\\n\\n!NewParagraph methodsFor: 'private' stamp: 'di 11/8/97 15:47'!\\nadjustLineIndicesBy: delta\\n\\tfirstCharacterIndex _ firstCharacterIndex + delta.\\n\\tlines do: [:line | line slide: delta].\\n! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'di 10/26/97 15:57'!\\nadjustRightX\\n\\t| shrink |\\n\\tshrink _ container right - maxRightX.\\n\\tlines do: [:line | line paddingWidth: (line paddingWidth - shrink)].\\n\\tcontainer _ container withRight: maxRightX! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'di 4/14/98 13:17'!\\nfastFindFirstLineSuchThat: lineBlock\\n\\t\\\"Perform a binary search of the lines array and return the index\\n\\tof the first element for which lineBlock evaluates as true.\\n\\tThis assumes the condition is one that goes from false to true for\\n\\tincreasing line numbers (as, eg, yval > somey or start char > somex).\\n\\tIf lineBlock is not true for any element, return size+1.\\\"\\n\\t| index low high |\\n\\tlow _ 1.\\n\\thigh _ lines size.\\n\\t[index _ high + low // 2.\\n\\tlow > high]\\n\\t\\twhileFalse: \\n\\t\\t\\t[(lineBlock value: (lines at: index))\\n\\t\\t\\t\\tifTrue: [high _ index - 1]\\n\\t\\t\\t\\tifFalse: [low _ index + 1]].\\n\\t^ low! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'RAA 8/30/1998 15:30'!\\nindentationOfLineIndex: lineIndex ifBlank: aBlock\\n\\t\\\"Answer the number of leading tabs in the line at lineIndex. If there are\\n\\t no visible characters, pass the number of tabs to aBlock and return its value.\\n\\t If the line is word-wrap overflow, back up a line and recur.\\\"\\n\\n\\t| arrayIndex first last cr |\\n\\tcr _ Character cr.\\n\\tarrayIndex _ lineIndex.\\n\\t[first _ (lines at: arrayIndex) first.\\n\\t first > 1 and: [(text string at: first - 1) ~~ cr]] whileTrue: \\\"word wrap\\\"\\n\\t\\t[arrayIndex _ arrayIndex - 1].\\n\\tlast _ (lines at: arrayIndex) last.\\n\\t\\n\\t^(text string copyFrom: first to: last) indentationIfBlank: aBlock.\\n! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'di 4/14/98 13:11'!\\nlineIndexForCharacter: index\\n\\t\\\"Answer the index of the line in which to select the character at index.\\\"\\n\\t^ (self fastFindFirstLineSuchThat: [:line | line first > index]) - 1 max: 1! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'di 4/14/98 13:13'!\\nlineIndexForPoint: aPoint\\n\\t\\\"Answer the index of the line in which to select the character nearest to aPoint.\\\"\\n\\t| i py |\\n\\tpy _ aPoint y truncated.\\n\\n\\t\\\"Find the first line at this y-value\\\"\\n\\ti _ (self fastFindFirstLineSuchThat: [:line | line bottom > py]) min: lines size.\\n\\n\\t\\\"Now find the first line at this x-value\\\"\\n\\t[i < lines size and: [(lines at: i+1) top = (lines at: i) top\\n\\t\\t\\t\\tand: [aPoint x >= (lines at: i+1) left]]]\\n\\t\\twhileTrue: [i _ i + 1].\\n\\t^ i! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'RAA 8/30/1998 15:04'!\\nlineIndexOfCharacterIndex: characterIndex \\n\\t\\\"Answer the line index for a given characterIndex.\\\"\\n\\t\\\"apparently the selector changed with NewParagraph\\\"\\n\\n\\t^self lineIndexForCharacter: characterIndex \\n! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'di 10/24/97 17:40'!\\nlines\\n\\t^ lines! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'edc 6/18/2004 09:10'!\\nmoveBy: delta\\n\\tlines do: [:line | line moveBy: delta].\\n\\tpositionWhenComposed ifNotNil:[\\n\\tpositionWhenComposed _ positionWhenComposed + delta].\\n\\tcontainer _ container translateBy: delta! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'di 10/21/97 21:36'!\\npositionWhenComposed: pos\\n\\tpositionWhenComposed _ pos! !\\n\\n!NewParagraph methodsFor: 'private' stamp: 'di 5/21/1998 21:47'!\\ntextStyle: ts lines: l text: t\\n\\t\\\"Private -- just a service for deepCopy\\\"\\n\\ttextStyle _ ts.\\n\\tlines _ l.\\n\\ttext _ t.! !\\nSystemWindow subclass: #NewWorldWindow\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-AdditionalWorlds'!\\n\\n!NewWorldWindow methodsFor: 'color' stamp: 'nb 6/17/2003 12:25'!\\nsetWindowColor: incomingColor\\n\\t| existingColor aColor |\\n\\n\\tincomingColor ifNil: [^ self]. \\\"it happens\\\"\\n\\taColor _ incomingColor asNontranslucentColor.\\n\\t(aColor = ColorPickerMorph perniciousBorderColor \\n\\t\\tor: [aColor = Color black]) ifTrue: [^ self].\\n\\texistingColor _ self paneColorToUse.\\n\\texistingColor ifNil: [^ Beeper beep].\\n\\tself setStripeColorsFrom: aColor\\n\\t\\t\\n! !\\n\\n\\n!NewWorldWindow methodsFor: 'initialization' stamp: 'ar 5/11/2001 23:48'!\\nopenInWorld: aWorld\\n\\t| xxx |\\n\\t\\\"This msg and its callees result in the window being activeOnlyOnTop\\\"\\n\\n\\txxx _ RealEstateAgent initialFrameFor: self world: aWorld.\\n\\n\\t\\\"Bob say: 'opening in ',xxx printString,' out of ',aWorld bounds printString.\\n\\t6 timesRepeat: [Display flash: xxx andWait: 300].\\\"\\n\\n\\tself bounds: xxx.\\n\\t^self openAsIsIn: aWorld.! !\\n\\n\\n!NewWorldWindow methodsFor: 'label' stamp: 'sw 5/19/2001 10:44'!\\nsetStripeColorsFrom: paneColor\\n\\t\\\"Since our world may be *any* color, try to avoid really dark colors so title will show\\\"\\n\\n\\t| revisedColor |\\n\\tstripes ifNil: [^ self].\\n\\trevisedColor _ paneColor atLeastAsLuminentAs: 0.1 .\\n\\tself isActive ifTrue:\\n\\t\\t[stripes second \\n\\t\\t\\tcolor: revisedColor; \\n\\t\\t\\tborderColor: stripes second color darker.\\n\\t\\tstripes first \\n\\t\\t\\tcolor: stripes second borderColor darker;\\n\\t\\t\\tborderColor: stripes first color darker.\\n\\t\\t^ self].\\n\\t\\\"This could be much faster\\\"\\n\\tstripes second \\n\\t\\tcolor: revisedColor; \\n\\t\\tborderColor: revisedColor.\\n\\tstripes first \\n\\t\\tcolor: revisedColor; \\n\\t\\tborderColor: revisedColor! !\\n\\n\\n!NewWorldWindow methodsFor: 'panes' stamp: 'ar 11/9/2000 01:31'!\\naddMorph: aMorph frame: relFrame\\n\\t| cc |\\n\\tcc _ aMorph color.\\n\\tsuper addMorph: aMorph frame: relFrame.\\n\\taMorph color: cc.! !\\n\\n!NewWorldWindow methodsFor: 'panes' stamp: 'RAA 6/1/2000 18:21'!\\nupdatePaneColors\\n\\t\\\"Useful when changing from monochrome to color display\\\"\\n\\n\\tself setStripeColorsFrom: self paneColorToUse.\\n\\n\\t\\\"paneMorphs do: [:p | p color: self paneColorToUse].\\\"\\t\\\"since pane is a world, skip this\\\"\\n! !\\n\\n\\n!NewWorldWindow methodsFor: 'stepping' stamp: 'RAA 6/1/2000 18:30'!\\namendSteppingStatus! !\\n\\n\\n!NewWorldWindow methodsFor: 'testing' stamp: 'RAA 6/1/2000 18:33'!\\nwantsSteps\\n\\t\\n\\t^true! !\\nController subclass: #NoController\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Framework'!\\n!NoController commentStamp: '<historical>' prior: 0!\\nI represent a controller that never wants control. I am the controller for views that are non-interactive.!\\n\\n\\n!NoController methodsFor: 'basic control sequence'!\\nstartUp\\n\\t\\\"I do nothing.\\\"\\n\\n\\t^self! !\\n\\n\\n!NoController methodsFor: 'control defaults'!\\nisControlActive \\n\\t\\\"Refer to the comment in Controller|isControlActive.\\\"\\n\\n\\t^false! !\\n\\n!NoController methodsFor: 'control defaults'!\\nisControlWanted \\n\\t\\\"Refer to the comment in Controller|isControlWanted.\\\"\\n\\n\\t^false! !\\nClipboardInterpreter subclass: #NoConversionClipboardInterpreter\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-TextConversion'!\\n\\n!NoConversionClipboardInterpreter methodsFor: 'as yet unclassified' stamp: 'yo 8/11/2003 19:03'!\\nfromSystemClipboard: aString\\n\\n\\t^ aString.\\n! !\\n\\n!NoConversionClipboardInterpreter methodsFor: 'as yet unclassified' stamp: 'yo 8/11/2003 21:06'!\\ntoSystemClipboard: aString\\n\\n\\t| result |\\n\\taString isOctetString ifTrue: [^ aString asOctetString].\\n\\n\\tresult _ WriteStream on: (String new: aString size).\\n\\taString do: [:each | each value < 256 ifTrue: [result nextPut: each]].\\n\\t^ result contents.\\n! !\\nKeyboardInputInterpreter subclass: #NoInputInterpreter\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-TextConversion'!\\n\\n!NoInputInterpreter methodsFor: 'as yet unclassified' stamp: 'yo 7/25/2003 14:59'!\\nnextCharFrom: sensor firstEvt: evtBuf\\n\\n\\n\\n\\t| keyValue |\\n\\n\\tkeyValue := evtBuf third.\\n\\n\\t^ keyValue asCharacter.\\n\\n! !\\nNetworkError subclass: #NoNetworkError\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Kernel'!\\n!NoNetworkError commentStamp: 'mir 5/12/2003 18:17' prior: 0!\\nSignals that no network was found. This could happen, e.g., on dial-up connection when no connection was established when Squeak tried to access it.\\n\\n!\\n\\nError subclass: #NonBooleanReceiver\\n\\tinstanceVariableNames: 'object'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Exceptions-Kernel'!\\n\\n!NonBooleanReceiver methodsFor: 'accessing' stamp: 'hmm 7/29/2001 21:30'!\\nobject\\n\\t^object! !\\n\\n!NonBooleanReceiver methodsFor: 'accessing' stamp: 'hmm 7/29/2001 21:30'!\\nobject: anObject\\n\\tobject _ anObject! !\\n\\n\\n!NonBooleanReceiver methodsFor: 'signaledException' stamp: 'hmm 7/29/2001 21:37'!\\nisResumable\\n\\n\\t^true! !\\nAbstractScoreEvent subclass: #NoteEvent\\n\\tinstanceVariableNames: 'duration midiKey velocity channel'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Scores'!\\n!NoteEvent commentStamp: '<historical>' prior: 0!\\nRepresents a note on or off event in a MIDI score.\\n!\\n\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'jm 12/30/97 22:02'!\\nchannel\\n\\n\\t^ channel\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nchannel: midiChannel\\n\\n\\tchannel := midiChannel.\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'jm 12/18/97 19:10'!\\nduration\\n\\n\\t^ duration\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nduration: aNumber\\n\\n\\tduration := aNumber.\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'jm 8/27/1998 16:38'!\\nendTime\\n\\n\\t^ time + duration\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nkey: midiKeyNum velocity: midiVelocity channel: midiChannel\\n\\n\\tmidiKey := midiKeyNum.\\n\\tvelocity := midiVelocity.\\n\\tchannel := midiChannel.\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'jm 12/18/97 20:58'!\\nmidiKey\\n\\n\\t^ midiKey\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nmidiKey: midiKeyNum\\n\\n\\tmidiKey := midiKeyNum.\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'jm 8/3/1998 17:06'!\\npitch\\n\\t\\\"Convert my MIDI key number to a pitch and return it.\\\"\\n\\n\\t^ AbstractSound pitchForMIDIKey: midiKey\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'jm 12/30/97 09:32'!\\nvelocity\\n\\n\\t^ velocity\\n! !\\n\\n!NoteEvent methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nvelocity: midiVelocity\\n\\n\\tvelocity := midiVelocity.\\n! !\\n\\n\\n!NoteEvent methodsFor: 'classification' stamp: 'jm 12/31/97 11:48'!\\nisNoteEvent\\n\\n\\t^ true\\n! !\\n\\n\\n!NoteEvent methodsFor: 'midi' stamp: 'jm 9/10/1998 15:58'!\\nendNoteOnMidiPort: aMidiPort\\n\\t\\\"Output a noteOff event to the given MIDI port. (Actually, output a noteOff event with zero velocity. This does the same thing, but allows running status to be used when sending a mixture of note on and off commands.)\\\"\\n\\n\\taMidiPort\\n\\t\\tmidiCmd: 16r90\\n\\t\\tchannel: channel\\n\\t\\tbyte: midiKey\\n\\t\\tbyte: 0.\\n! !\\n\\n!NoteEvent methodsFor: 'midi' stamp: 'jm 9/10/1998 15:56'!\\nstartNoteOnMidiPort: aMidiPort\\n\\t\\\"Output a noteOn event to the given MIDI port.\\\"\\n\\n\\taMidiPort\\n\\t\\tmidiCmd: 16r90\\n\\t\\tchannel: channel\\n\\t\\tbyte: midiKey\\n\\t\\tbyte: velocity.\\n! !\\n\\n\\n!NoteEvent methodsFor: 'printing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nkeyName\\n\\t\\\"Return a note name for my pitch.\\\"\\n\\n\\t| pitchName octave |\\n\\tpitchName := #(c cs d ef e f fs g af a bf b) at: (midiKey \\\\\\\\ 12) + 1.\\n\\toctave := (#(-1 0 1 2 3 4 5 6 7 8 9) at: (midiKey // 12) + 1) printString.\\n\\t^ pitchName, octave\\n! !\\n\\n!NoteEvent methodsFor: 'printing' stamp: 'jm 1/3/98 08:59'!\\nprintOn: aStream\\n\\n\\taStream nextPut: $(.\\n\\ttime printOn: aStream.\\n\\taStream nextPutAll: ': '.\\n\\taStream nextPutAll: self keyName.\\n\\taStream space.\\n\\tduration printOn: aStream.\\n\\taStream nextPut: $).\\n! !\\nException subclass: #Notification\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Exceptions-Kernel'!\\n!Notification commentStamp: '<historical>' prior: 0!\\nA Notification is an indication that something interesting has occurred. If it is not handled, it will pass by without effect.!\\n\\n\\n!Notification methodsFor: 'exceptionDescription' stamp: 'pnm 8/16/2000 15:04'!\\ndefaultAction\\n\\t\\\"No action is taken. The value nil is returned as the value of the message that signaled the exception.\\\"\\n\\n\\t^nil! !\\n\\n!Notification methodsFor: 'exceptionDescription' stamp: 'tfei 6/4/1999 18:17'!\\nisResumable\\n\\t\\\"Answer true. Notification exceptions by default are specified to be resumable.\\\"\\n\\n\\t^true! !\\nPluggableCanvas subclass: #NullCanvas\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Support'!\\n!NullCanvas commentStamp: '<historical>' prior: 0!\\nA canvas which ignores all drawing commands.!\\n\\n\\n!NullCanvas methodsFor: 'accessing' stamp: 'ls 3/20/2000 21:11'!\\nclipRect\\n\\t^1@1 extent: 99@99! !\\n\\n!NullCanvas methodsFor: 'accessing' stamp: 'ls 3/20/2000 21:11'!\\nextent\\n\\t^100@100! !\\n\\n!NullCanvas methodsFor: 'accessing' stamp: 'ls 3/20/2000 21:12'!\\nform\\n\\t^Form extent: self extent! !\\n\\n!NullCanvas methodsFor: 'accessing' stamp: 'ls 3/20/2000 21:13'!\\norigin\\n\\t^0@0! !\\n\\n\\n!NullCanvas methodsFor: 'copying' stamp: 'ls 3/20/2000 21:26'!\\ncopyClipRect: clipRect\\n\\t\\\"who cares what the clipping rectangle is?\\\"\\n\\t^self! !\\n\\n\\n!NullCanvas methodsFor: 'drawing-support' stamp: 'ls 3/27/2000 21:41'!\\nclipBy: region during: aBlock\\n\\t\\\"do this in order that timing runs work better\\\"\\n\\taBlock value: self! !\\n\\n!NullCanvas methodsFor: 'drawing-support' stamp: 'ls 3/27/2000 21:39'!\\ntransformBy: aDisplayTransform clippingTo: aClipRect during: aBlock smoothing: cellSize\\n\\t\\\"do this in order that timing runs work better\\\"\\n\\taBlock value: self! !\\n\\n!NullCanvas methodsFor: 'drawing-support' stamp: 'ls 3/27/2000 21:40'!\\ntranslateBy: delta during: aBlock\\n\\t\\\"do this in order that timing runs work better\\\"\\n\\taBlock value: self! !\\nObject subclass: #NullEncoder\\n\\tinstanceVariableNames: 'target filterSelector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Support'!\\n\\n!NullEncoder methodsFor: 'accessing' stamp: 'RAA 9/17/2000 11:53'!\\nclose\\n\\n\\t^target close.\\n! !\\n\\n!NullEncoder methodsFor: 'accessing' stamp: 'MPW 1/1/1901 00:56'!\\ncontents\\n\\t^target contents.\\n! !\\n\\n!NullEncoder methodsFor: 'accessing' stamp: 'MPW 1/1/1901 00:16'!\\ntarget\\n\\t^target.! !\\n\\n\\n!NullEncoder methodsFor: 'initialization' stamp: 'MPW 1/1/1901 00:04'!\\ninitWithTarget:aTarget\\n\\ttarget _ aTarget.\\n\\tfilterSelector _ self class filterSelector.\\n\\t^self.\\n! !\\n\\n\\n!NullEncoder methodsFor: 'processing' stamp: 'MPW 1/1/1901 01:19'!\\nprocess:anObject\\n\\tself write:anObject.\\n\\t^self contents.! !\\n\\n\\n!NullEncoder methodsFor: 'writing' stamp: 'MPW 1/1/1901 01:17'!\\nforward:anObject\\n\\tanObject ~= nil ifTrue:[target write:anObject].\\n! !\\n\\n!NullEncoder methodsFor: 'writing' stamp: 'mpw 8/13/1999 10:54'!\\nwrite:anObject\\n\\tfilterSelector ifNil:[filterSelector_self class filterSelector].\\n\\tanObject ifNotNil: [anObject perform:filterSelector with:self].\\n! !\\n\\n!NullEncoder methodsFor: 'writing' stamp: 'MPW 1/1/1901 01:16'!\\nwriteObject:anObject\\n\\t^self forward:anObject.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNullEncoder class\\n\\tinstanceVariableNames: ''!\\n\\n!NullEncoder class methodsFor: 'configuring' stamp: 'MPW 1/1/1901 00:02'!\\ndefaultTarget\\n\\t^OrderedCollection new.\\n! !\\n\\n!NullEncoder class methodsFor: 'configuring' stamp: 'MPW 1/1/1901 00:02'!\\nfilterSelector\\n\\t^#writeOnFilterStream:\\n! !\\n\\n\\n!NullEncoder class methodsFor: 'creation' stamp: 'MPW 1/1/1901 00:55'!\\nstream\\n\\t^self streamOn:self defaultTarget. \\n! !\\n\\n!NullEncoder class methodsFor: 'creation' stamp: 'MPW 1/1/1901 00:05'!\\nstream:newTarget\\n\\t^self new initWithTarget:newTarget.\\n! !\\n\\n!NullEncoder class methodsFor: 'creation' stamp: 'MPW 1/1/1901 01:15'!\\nstreamOn:newTargetCollection\\n\\t^self new initWithTarget:newTargetCollection.\\n! !\\n\\n!NullEncoder class methodsFor: 'creation' stamp: 'MPW 1/1/1901 02:20'!\\nstreamOnFile:fileName\\n\\t^self new initWithTarget:(FileStream newFileNamed: fileName).\\n! !\\n\\n\\n!NullEncoder class methodsFor: 'processing' stamp: 'MPW 1/1/1901 01:20'!\\nprocess:anObject\\n\\t^self stream process:anObject.\\n\\n! !\\nNetworkTerminalMorph subclass: #NullTerminalMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Morphic-Remote'!\\n\\n!NullTerminalMorph methodsFor: 'drawing' stamp: 'RAA 7/22/2000 07:20'!\\ndrawOn: aCanvas\\n\\n\\taCanvas fillRectangle: self bounds fillStyle: Color orange.\\n\\taCanvas frameRectangle: self bounds color: Color black! !\\n\\n!NullTerminalMorph methodsFor: 'drawing' stamp: 'RAA 7/22/2000 07:22'!\\nforceToFront: aRegion\\n\\t\\\"force the given region from the drawing form onto the background form\\\"\\n\\tself updateBackgroundForm.\\n\\n! !\\n\\n\\n!NullTerminalMorph methodsFor: 'geometry' stamp: 'sd 11/20/2005 21:26'!\\nextent: newExtent\\n\\n\\t| aPoint |\\n\\taPoint := 50@50.\\n\\tbounds extent = aPoint ifFalse: [\\n\\t\\tself changed.\\n\\t\\tbounds := bounds topLeft extent: aPoint.\\n\\t\\tself layoutChanged.\\n\\t\\tself changed\\n\\t].\\n\\teventEncoder sendViewExtent: newExtent! !\\nMagnitude subclass: #Number\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Numbers'!\\n!Number commentStamp: '<historical>' prior: 0!\\nClass Number holds the most general methods for dealing with numbers. Subclasses Float, Fraction, and Integer, and their subclasses, provide concrete representations of a numeric quantity.\\n\\nAll of Number's subclasses participate in a simple type coercion mechanism that supports mixed-mode arithmetic and comparisons. It works as follows: If\\n\\tself<typeA> op: arg<typeB>\\nfails because of incompatible types, then it is retried in the following guise:\\n\\t(arg adaptTypeA: self) op: arg adaptToTypeA.\\nThis gives the arg of typeB an opportunity to resolve the incompatibility, knowing exactly what two types are involved. If self is more general, then arg will be converted, and viceVersa. This mechanism is extensible to any new number classes that one might wish to add to Squeak. The only requirement is that every subclass of Number must support a pair of conversion methods specific to each of the other subclasses of Number.!\\n\\n\\n!Number methodsFor: 'arithmetic'!\\n* aNumber \\n\\t\\\"Answer the result of multiplying the receiver by aNumber.\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n!Number methodsFor: 'arithmetic'!\\n+ aNumber \\n\\t\\\"Answer the sum of the receiver and aNumber.\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n!Number methodsFor: 'arithmetic'!\\n- aNumber \\n\\t\\\"Answer the difference between the receiver and aNumber.\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n!Number methodsFor: 'arithmetic'!\\n/ aNumber \\n\\t\\\"Answer the result of dividing the receiver by aNumber.\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n!Number methodsFor: 'arithmetic'!\\n// aNumber \\n\\t\\\"Integer quotient defined by division with truncation toward negative \\n\\tinfinity. 9//4 = 2, -9//4 = -3. -0.9//0.4 = -3. \\\\\\\\ answers the remainder \\n\\tfrom this division.\\\"\\n\\n\\t^(self / aNumber) floor! !\\n\\n!Number methodsFor: 'arithmetic'!\\n\\\\\\\\ aNumber \\n\\t\\\"modulo. Remainder defined in terms of //. Answer a Number with the \\n\\tsame sign as aNumber. e.g. 9\\\\\\\\4 = 1, -9\\\\\\\\4 = 3, 9\\\\\\\\-4 = -3, 0.9\\\\\\\\0.4 = 0.1.\\\"\\n\\n\\t^self - (self // aNumber * aNumber)! !\\n\\n!Number methodsFor: 'arithmetic'!\\nabs\\n\\t\\\"Answer a Number that is the absolute value (positive magnitude) of the \\n\\treceiver.\\\"\\n\\n\\tself < 0\\n\\t\\tifTrue: [^self negated]\\n\\t\\tifFalse: [^self]! !\\n\\n!Number methodsFor: 'arithmetic' stamp: 'mk 10/27/2003 21:00'!\\narg\\n\\t\\\"Answer the argument of the receiver (see Complex | arg).\\\"\\n\\t\\n\\tself isZero ifTrue: [self error: 'Zero (0 + 0 i) does not have an argument.'].\\n\\t0 < self\\n\\t\\tifTrue: [^ 0]\\n\\t\\tifFalse: [^ Float pi]! !\\n\\n!Number methodsFor: 'arithmetic'!\\nnegated\\n\\t\\\"Answer a Number that is the negation of the receiver.\\\"\\n\\n\\t^0 - self! !\\n\\n!Number methodsFor: 'arithmetic'!\\nquo: aNumber \\n\\t\\\"Integer quotient defined by division with truncation toward zero. -9 quo: \\n\\t4 = -2, -0.9 quo: 0.4 = -2. rem: answers the remainder from this division.\\\"\\n\\n\\t^(self / aNumber) truncated! !\\n\\n!Number methodsFor: 'arithmetic' stamp: 'RAH 4/25/2000 19:49'!\\nreciprocal\\n\\t\\\"Answer 1 divided by the receiver. Create an error notification if the \\n\\treceiver is 0.\\\"\\n\\t#Numeric.\\n\\t\\\"Changed 200/01/19 For ANSI <number> support.\\\"\\n\\tself = 0 ifTrue: [^ (ZeroDivide dividend: self) signal\\\"<- Chg\\\"].\\n\\t^ 1 / self! !\\n\\n!Number methodsFor: 'arithmetic'!\\nrem: aNumber \\n\\t\\\"Remainder defined in terms of quo:. Answer a Number with the same \\n\\tsign as self. e.g. 9 rem: 4 = 1, -9 rem: 4 = -1. 0.9 rem: 0.4 = 0.1.\\\"\\n\\n\\t^self - ((self quo: aNumber) * aNumber)! !\\n\\n\\n!Number methodsFor: 'comparing' stamp: 'tk 4/16/1999 18:26'!\\ncloseTo: num\\n\\t\\\"are these two numbers close?\\\"\\n\\n\\t| ans |\\n\\tnum isFloat ifTrue: [^ num closeTo: self asFloat].\\n\\t[ans _ self = num] ifError: [:aString :aReceiver | ^ false].\\n\\t^ ans! !\\n\\n\\n!Number methodsFor: 'converting' stamp: 'avi 9/6/2005 22:07'!\\nprintShowingDecimalPlaces: placesDesired\\n\\t\\\"Print the receiver showing precisely the given number of places desired . If the placesDesired provided is positive, a decimal point and that many digits after the decimal point will always be shown. If the placesDesired is zero, a whole number will be shown, without a decimal point. This method could probably be greatly optimized -- improvements welcomed.\\\"\\n\\n\\t| precision rounded integerString fractionString |\\n\\tplacesDesired <= 0 ifTrue: [^ self rounded printString].\\n\\tprecision _ Utilities floatPrecisionForDecimalPlaces: placesDesired.\\n\\trounded _ self roundTo: precision.\\n\\tintegerString _ rounded integerPart asInteger asString.\\n\\tfractionString _ (rounded fractionPart abs / precision) asInteger asString.\\n\\t^ String streamContents:\\n\\t\\t[:s |\\n\\t\\ts nextPutAll: integerString.\\n\\t\\ts nextPut: $..\\n\\t\\t(placesDesired - fractionString size) timesRepeat: [s nextPut: $0].\\n\\t\\ts nextPutAll: fractionString]\\n\\\"\\n23 printShowingDecimalPlaces: 2\\n23.5698 printShowingDecimalPlaces: 2\\n-234.567 printShowingDecimalPlaces: 5\\n23.4567 printShowingDecimalPlaces: 0\\n100000000 printShowingDecimalPlaces: 1\\n\\\"! !\\n\\n!Number methodsFor: 'converting'!\\n@ y \\n\\t\\\"Primitive. Answer a Point whose x value is the receiver and whose y \\n\\tvalue is the argument. Optional. No Lookup. See Object documentation \\n\\twhatIsAPrimitive.\\\"\\n\\n\\t<primitive: 18>\\n\\t^Point x: self y: y! !\\n\\n!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:43'!\\nadaptToCollection: rcvr andSend: selector\\n\\t\\\"If I am involved in arithmetic with a Collection, return a Collection of\\n\\tthe results of each element combined with me in that expression.\\\"\\n\\n\\t^ rcvr collect: [:element | element perform: selector with: self]! !\\n\\n!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:21'!\\nadaptToFloat: rcvr andSend: selector \\n\\t\\\"If I am involved in arithmetic with a Float, convert me to a Float.\\\"\\n\\t^ rcvr perform: selector with: self asFloat! !\\n\\n!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:44'!\\nadaptToFraction: rcvr andSend: selector\\n\\t\\\"If I am involved in arithmetic with a Fraction, convert us and evaluate exprBlock.\\\"\\n\\t^ self subclassResponsibility! !\\n\\n!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:44'!\\nadaptToInteger: rcvr andSend: selector\\n\\t\\\"If I am involved in arithmetic with a Integer, convert us and evaluate exprBlock.\\\"\\n\\t^ self subclassResponsibility! !\\n\\n!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:44'!\\nadaptToPoint: rcvr andSend: selector\\n\\t\\\"If I am involved in arithmetic with a Point, convert me to a Point.\\\"\\n\\t^ rcvr perform: selector with: self@self! !\\n\\n!Number methodsFor: 'converting' stamp: 'RAH 4/25/2000 19:49'!\\nadaptToScaledDecimal: receiverScaledDecimal andSend: arithmeticOpSelector \\n\\t\\\"Do any required conversion and then the arithmetic. \\n\\treceiverScaledDecimal arithmeticOpSelector self.\\\"\\n\\t#Numeric.\\n\\t\\\"add 200/01/19 For ScaledDecimal support.\\\"\\n\\t^ self subclassResponsibility! !\\n\\n!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:45'!\\nadaptToString: rcvr andSend: selector\\n\\t\\\"If I am involved in arithmetic with a String, convert it to a Number.\\\"\\n\\t^ rcvr asNumber perform: selector with: self! !\\n\\n!Number methodsFor: 'converting' stamp: 'ar 5/20/2001 01:40'!\\nasB3DVector3\\n\\t^self@self@self! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 5/13/2003 10:13'!\\nasDuration\\n\\n\\n\\n\\t^ Duration nanoSeconds: self asInteger\\n\\n! !\\n\\n!Number methodsFor: 'converting' stamp: 'RAH 4/25/2000 19:49'!\\nasFloatD\\n\\t\\\"Answer a d precision floating-point number approximating the receiver.\\\"\\n\\t#Numeric.\\n\\t\\\"add 200/01/19 For ANSI <number> protocol.\\\"\\n\\t^ self asFloat! !\\n\\n!Number methodsFor: 'converting' stamp: 'RAH 4/25/2000 19:49'!\\nasFloatE\\n\\t\\\"Answer a floating-point number approximating the receiver.\\\"\\n\\t#Numeric.\\n\\t\\\"add 200/01/19 For ANSI <number> protocol.\\\"\\n\\t^ self asFloat! !\\n\\n!Number methodsFor: 'converting' stamp: 'RAH 4/25/2000 19:49'!\\nasFloatQ\\n\\t\\\"Answer a floating-point number approximating the receiver.\\\"\\n\\t#Numeric.\\n\\t\\\"add 200/01/19 For ANSI <number> protocol.\\\"\\n\\t^ self asFloat! !\\n\\n!Number methodsFor: 'converting'!\\nasInteger\\n\\t\\\"Answer an Integer nearest the receiver toward zero.\\\"\\n\\n\\t^self truncated! !\\n\\n!Number methodsFor: 'converting' stamp: 'sw 2/16/1999 18:15'!\\nasNumber\\n\\t^ self! !\\n\\n!Number methodsFor: 'converting'!\\nasPoint\\n\\t\\\"Answer a Point with the receiver as both coordinates; often used to \\n\\tsupply the same value in two dimensions, as with symmetrical gridding \\n\\tor scaling.\\\"\\n\\n\\t^self @ self! !\\n\\n!Number methodsFor: 'converting' stamp: 'dtl 9/25/2004 11:47'!\\nasScaledDecimal\\n\\t\\\"Answer a scaled decimal number approximating the receiver.\\\"\\n\\t#Numeric.\\n\\n\\t^ self asScaledDecimal: 8\\n! !\\n\\n!Number methodsFor: 'converting' stamp: 'RAH 4/25/2000 19:49'!\\nasScaledDecimal: scale \\n\\t\\\"Answer a scaled decimal number, with a fractional precision of scale, \\n\\tapproximating the receiver.\\\"\\n\\t#Numeric.\\n\\t\\\"add 200/01/19 For number protocol.\\\"\\n\\t^ ScaledDecimal newFromNumber: self scale: scale! !\\n\\n!Number methodsFor: 'converting' stamp: 'sw 9/8/97 16:30'!\\nasSmallAngleDegrees\\n\\t\\\"Return the receiver normalized to lie within the range (-180, 180)\\\"\\n\\n\\t| pos |\\n\\tpos _ self \\\\\\\\ 360.\\n\\tpos > 180 ifTrue: [pos _ pos - 360].\\n\\t^ pos\\n\\n\\\"#(-500 -300 -150 -5 0 5 150 300 500 1200) collect: [:n | n asSmallAngleDegrees]\\\"! !\\n\\n!Number methodsFor: 'converting' stamp: 'sw 10/7/1999 12:24'!\\nasSmallPositiveDegrees\\n\\t\\\"Return the receiver normalized to lie within the range (0, 360)\\\"\\n\\n\\t| result |\\n\\tresult _ self.\\n\\t[result < 0] whileTrue: [result _ result + 360].\\n\\t^ result \\\\\\\\ 360\\n\\n\\\"#(-500 -300 -150 -5 0 5 150 300 500 1200) collect: [:n | n asSmallPositiveDegrees]\\\"! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:12'!\\nday\\n\\n\\n\\n\\t^ self sign days! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:56'!\\ndays\\n\\n\\n\\n\\t^ Duration days: self! !\\n\\n!Number methodsFor: 'converting'!\\ndegreesToRadians\\n\\t\\\"The receiver is assumed to represent degrees. Answer the conversion to \\n\\tradians.\\\"\\n\\n\\t^self asFloat degreesToRadians! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:28'!\\nhour\\n\\n\\n\\n\\t^ self sign hours\\n\\n! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:56'!\\nhours\\n\\n\\n\\n\\t^ Duration hours: self! !\\n\\n!Number methodsFor: 'converting' stamp: 'mk 10/27/2003 18:17'!\\ni\\n\\t^ Complex real: 0 imaginary: self! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:26'!\\nmilliSecond\\n\\n\\n\\n\\t^ self sign milliSeconds\\n\\n! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 9/25/2003 13:16'!\\nmilliSeconds\\n\\n\\n\\n\\t^ Duration milliSeconds: self\\n\\n! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:16'!\\nminute\\n\\n\\n\\n\\t^ self sign minutes\\n\\n! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:56'!\\nminutes\\n\\n\\n\\n\\t^ Duration minutes: self! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:27'!\\nnanoSecond\\n\\n\\n\\n\\t^ self sign nanoSeconds\\n\\n! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 08:52'!\\nnanoSeconds\\n\\n\\n\\n\\t^ Duration nanoSeconds: self.! !\\n\\n!Number methodsFor: 'converting'!\\nradiansToDegrees\\n\\t\\\"The receiver is assumed to represent radians. Answer the conversion to \\n\\tdegrees.\\\"\\n\\n\\t^self asFloat radiansToDegrees! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:17'!\\nsecond\\n\\n\\n\\n\\t^ self sign seconds\\n\\n! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:57'!\\nseconds\\n\\n\\n\\n\\t^ Duration seconds: self! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 5/21/2003 08:20'!\\nsign: aNumber\\n\\n\\t\\\"Return a Number with the same sign as aNumber\\\"\\n\\n\\n\\n\\t^ aNumber positive ifTrue: [self abs] ifFalse: [self abs negated].! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:19'!\\nweek\\n\\n\\n\\n\\t^ self sign weeks\\n\\n! !\\n\\n!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:57'!\\nweeks\\n\\n\\n\\n\\t^ Duration weeks: self! !\\n\\n\\n!Number methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 00:07'!\\nbyteEncode:aStream\\n\\t^aStream writeNumber:self.\\n! !\\n\\n\\n!Number methodsFor: 'intervals'!\\nto: stop\\n\\t\\\"Answer an Interval from the receiver up to the argument, stop, \\n\\tincrementing by 1.\\\"\\n\\n\\t^Interval from: self to: stop by: 1! !\\n\\n!Number methodsFor: 'intervals'!\\nto: stop by: step\\n\\t\\\"Answer an Interval from the receiver up to the argument, stop, \\n\\tincrementing by step.\\\"\\n\\n\\t^Interval from: self to: stop by: step! !\\n\\n!Number methodsFor: 'intervals' stamp: 'tao 1/30/1999 08:58'!\\nto: stop by: step do: aBlock \\n\\t\\\"Normally compiled in-line, and therefore not overridable.\\n\\tEvaluate aBlock for each element of the interval (self to: stop by: \\nstep).\\\"\\n\\t| nextValue |\\n\\tnextValue _ self.\\n\\tstep = 0 ifTrue: [self error: 'step must be non-zero'].\\n\\tstep < 0\\n\\t\\tifTrue: [[stop <= nextValue]\\n\\t\\t\\t\\twhileTrue: \\n\\t\\t\\t\\t\\t[aBlock value: nextValue.\\n\\t\\t\\t\\t\\tnextValue _ nextValue + step]]\\n\\t\\tifFalse: [[stop >= nextValue]\\n\\t\\t\\t\\twhileTrue: \\n\\t\\t\\t\\t\\t[aBlock value: nextValue.\\n\\t\\t\\t\\t\\tnextValue _ nextValue + step]]! !\\n\\n!Number methodsFor: 'intervals'!\\nto: stop do: aBlock \\n\\t\\\"Normally compiled in-line, and therefore not overridable.\\n\\tEvaluate aBlock for each element of the interval (self to: stop by: 1).\\\"\\n\\t| nextValue |\\n\\tnextValue _ self.\\n\\t[nextValue <= stop]\\n\\t\\twhileTrue: \\n\\t\\t\\t[aBlock value: nextValue.\\n\\t\\t\\tnextValue _ nextValue + 1]! !\\n\\n\\n!Number methodsFor: 'mathematical functions'!\\narcCos \\n\\t\\\"The receiver is the cosine of an angle. Answer the angle measured in \\n\\tradians.\\\"\\n\\n\\t^self asFloat arcCos! !\\n\\n!Number methodsFor: 'mathematical functions'!\\narcSin\\n\\t\\\"The receiver is the sine of an angle. Answer the angle measured in \\n\\tradians.\\\"\\n\\n\\t^self asFloat arcSin! !\\n\\n!Number methodsFor: 'mathematical functions'!\\narcTan\\n\\t\\\"The receiver is the tangent of an angle. Answer the angle measured in \\n\\tradians.\\\"\\n\\n\\t^self asFloat arcTan! !\\n\\n!Number methodsFor: 'mathematical functions' stamp: 'jsp 2/24/1999 15:20'!\\narcTan: denominator\\n\\t\\\"The receiver is the tangent of an angle. Answer the angle measured in \\n\\tradians.\\\"\\n\\n\\t^(self asFloat) arcTan: denominator.! !\\n\\n!Number methodsFor: 'mathematical functions'!\\ncos\\n\\t\\\"The receiver represents an angle measured in radians. Answer its cosine.\\\"\\n\\n\\t^self asFloat cos! !\\n\\n!Number methodsFor: 'mathematical functions' stamp: 'sd 3/5/2004 10:04'!\\ndegreeCos\\n\\t\\\"Answer the cosine of the receiver taken as an angle in degrees.\\\"\\n\\t\\n\\t^ (90 + self) degreeSin! !\\n\\n!Number methodsFor: 'mathematical functions' stamp: 'sd 3/5/2004 10:04'!\\ndegreeSin\\n\\t\\\"Answer the sine of the receiver taken as an angle in degrees.\\\"\\n\\t\\n\\t^ self asFloat degreesToRadians sin! !\\n\\n!Number methodsFor: 'mathematical functions'!\\nexp\\n\\t\\\"Answer the exponential of the receiver as a floating point number.\\\"\\n\\n\\t^self asFloat exp! !\\n\\n!Number methodsFor: 'mathematical functions' stamp: 'jm 3/27/98 06:16'!\\nfloorLog: radix\\n\\t\\\"Answer the floor of the log base radix of the receiver.\\\"\\n\\n\\t^ self asFloat floorLog: radix\\n! !\\n\\n!Number methodsFor: 'mathematical functions' stamp: 'ar 8/31/2000 20:05'!\\ninterpolateTo: aNumber at: param\\n\\t^self + (aNumber - self * param)! !\\n\\n!Number methodsFor: 'mathematical functions'!\\nln\\n\\t\\\"Answer the natural log of the receiver.\\\"\\n\\n\\t^self asFloat ln! !\\n\\n!Number methodsFor: 'mathematical functions' stamp: 'di 9/8/1998 17:10'!\\nlog\\n\\t\\\"Answer the base-10 log of the receiver.\\\"\\n\\n\\t^self asFloat log! !\\n\\n!Number methodsFor: 'mathematical functions'!\\nlog: aNumber \\n\\t\\\"Answer the log base aNumber of the receiver.\\\"\\n\\n\\t^self ln / aNumber ln! !\\n\\n!Number methodsFor: 'mathematical functions' stamp: 'RJ 3/15/1999 19:35'!\\nraisedTo: aNumber \\n\\t\\\"Answer the receiver raised to aNumber.\\\"\\n\\n\\taNumber isInteger ifTrue:\\n\\t\\t[\\\"Do the special case of integer power\\\"\\n\\t\\t^ self raisedToInteger: aNumber].\\n\\tself < 0 ifTrue:\\n\\t\\t[ self error: self printString, ' raised to a non-integer power' ].\\n\\taNumber = 0 ifTrue: [^ 1].\\t\\t\\\"Special case of exponent=0\\\"\\n\\t(self = 0) | (aNumber = 1) ifTrue:\\n\\t\\t[^ self].\\t\\t\\t\\t\\t\\t\\\"Special case of exponent=1\\\"\\n\\t^ (aNumber * self ln) exp\\t\\t\\\"Otherwise use logarithms\\\"! !\\n\\n!Number methodsFor: 'mathematical functions' stamp: 'RAH 4/25/2000 19:49'!\\nraisedToInteger: operand \\n\\t\\\"Answer the receiver raised to the power operand, an Integer.\\\"\\n\\t| count result |\\n\\t#Numeric.\\n\\t\\\"Changed 200/01/19 For ANSI <number> support.\\\"\\n\\toperand isInteger ifFalse: [^ ArithmeticError signal: 'parameter is not an Integer'\\\"<- Chg\\\"].\\n\\toperand = 0 ifTrue: [^ self class one].\\n\\toperand = 1 ifTrue: [^ self].\\n\\toperand < 0 ifTrue: [^ (self raisedToInteger: operand negated) reciprocal].\\n\\tcount := 1.\\n\\t[(count := count + count) < operand] whileTrue.\\n\\tresult := self class one.\\n\\t[count > 0]\\n\\t\\twhileTrue: \\n\\t\\t\\t[result := result * result.\\n\\t\\t\\t(operand bitAnd: count)\\n\\t\\t\\t\\t= 0 ifFalse: [result := result * self].\\n\\t\\t\\tcount := count bitShift: -1].\\n\\t^ result! !\\n\\n!Number methodsFor: 'mathematical functions'!\\nsin\\n\\t\\\"The receiver represents an angle measured in radians. Answer its sine.\\\"\\n\\n\\t^self asFloat sin! !\\n\\n!Number methodsFor: 'mathematical functions'!\\nsqrt\\n\\t\\\"Answer the square root of the receiver.\\\"\\n\\n\\t^self asFloat sqrt! !\\n\\n!Number methodsFor: 'mathematical functions'!\\nsquared\\n\\t\\\"Answer the receiver multipled by itself.\\\"\\n\\n\\t^self * self! !\\n\\n!Number methodsFor: 'mathematical functions'!\\ntan\\n\\t\\\"The receiver represents an angle measured in radians. Answer its \\n\\ttangent.\\\"\\n\\n\\t^self asFloat tan! !\\n\\n\\n!Number methodsFor: 'printing'!\\ndefaultLabelForInspector\\n\\t\\\"Answer the default label to be used for an Inspector window on the receiver.\\\"\\n\\n\\t^ super defaultLabelForInspector, ': ', self printString! !\\n\\n!Number methodsFor: 'printing' stamp: 'sw 6/29/1999 21:10'!\\nisOrAreStringWith: aNoun\\n\\t| result |\\n\\tresult _ self = 1\\n\\t\\tifTrue:\\n\\t\\t\\t[' is one ']\\n\\t\\tifFalse:\\n\\t\\t\\t[self = 0\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[' are no ']\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[' are ', self printString, ' ']].\\n\\tresult _ result, aNoun.\\n\\tself = 1 ifFalse: [result _ result, 's'].\\n\\t^ result\\n\\n\\\"#(0 1 2 98.6) do:\\n\\t[:num | Transcript cr; show: 'There', (num isOrAreStringWith: 'way'), ' to skin a cat']\\\"! !\\n\\n!Number methodsFor: 'printing' stamp: 'laza 3/29/2004 12:53'!\\nprintOn: aStream\\n\\tself printOn: aStream base: 10! !\\n\\n!Number methodsFor: 'printing' stamp: 'laza 3/29/2004 12:55'!\\nprintOn: aStream base: base\\n\\t^self subclassResponsibility! !\\n\\n!Number methodsFor: 'printing' stamp: 'laza 3/30/2004 10:50'!\\nprintString\\n\\t^self printStringBase: 10! !\\n\\n!Number methodsFor: 'printing'!\\nprintStringBase: base\\n\\t^ String streamContents:\\n\\t\\t[:strm | self printOn: strm base: base]! !\\n\\n!Number methodsFor: 'printing' stamp: 'laza 3/29/2004 12:50'!\\nstoreOn: aStream \\n\\tself printOn: aStream! !\\n\\n!Number methodsFor: 'printing' stamp: 'laza 3/29/2004 12:59'!\\nstoreOn: aStream base: base\\n\\tself printOn: aStream base: base! !\\n\\n!Number methodsFor: 'printing'!\\nstoreStringBase: base\\n\\t^ String streamContents: [:strm | self storeOn: strm base: base]! !\\n\\n!Number methodsFor: 'printing' stamp: 'sw 7/1/1998 12:33'!\\nstringForReadout\\n\\t^ self rounded printString! !\\n\\n\\n!Number methodsFor: 'testing' stamp: 'sw 9/27/2001 17:26'!\\nbasicType\\n\\t\\\"Answer a symbol representing the inherent type of the receiver\\\"\\n\\n\\t^ #Number! !\\n\\n!Number methodsFor: 'testing'!\\neven\\n\\t\\\"Answer whether the receiver is an even number.\\\"\\n\\n\\t^self \\\\\\\\ 2 = 0! !\\n\\n!Number methodsFor: 'testing' stamp: 'sw 12/30/1998 13:21'!\\nisDivisibleBy: aNumber\\n\\taNumber = 0 ifTrue: [^ false].\\n\\taNumber isInteger ifFalse: [^ false].\\n\\t^ (self \\\\\\\\ aNumber) = 0! !\\n\\n!Number methodsFor: 'testing' stamp: 'tao 10/10/97 16:36'!\\nisInf\\n\\t^ false! !\\n\\n!Number methodsFor: 'testing' stamp: 'tao 4/19/98 23:33'!\\nisInfinite\\n\\n\\t^ false! !\\n\\n!Number methodsFor: 'testing' stamp: 'tao 10/10/97 16:36'!\\nisNaN\\n\\t^ false! !\\n\\n!Number methodsFor: 'testing'!\\nisNumber\\n\\t^ true! !\\n\\n!Number methodsFor: 'testing'!\\nisZero\\n\\t^self = 0! !\\n\\n!Number methodsFor: 'testing' stamp: 'di 4/23/1998 11:18'!\\nnegative\\n\\t\\\"Answer whether the receiver is mathematically negative.\\\"\\n\\n\\t^ self < 0! !\\n\\n!Number methodsFor: 'testing'!\\nodd\\n\\t\\\"Answer whether the receiver is an odd number.\\\"\\n\\n\\t^self even == false! !\\n\\n!Number methodsFor: 'testing' stamp: 'di 4/23/1998 11:17'!\\npositive\\n\\t\\\"Answer whether the receiver is positive or equal to 0. (ST-80 protocol).\\n\\tSee also strictlyPositive\\\"\\n\\n\\t^ self >= 0! !\\n\\n!Number methodsFor: 'testing'!\\nsign\\n\\t\\\"Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0.\\\"\\n\\n\\tself > 0 ifTrue: [^1].\\n\\tself < 0 ifTrue: [^-1].\\n\\t^0! !\\n\\n!Number methodsFor: 'testing' stamp: 'di 4/23/1998 11:02'!\\nstrictlyPositive\\n\\t\\\"Answer whether the receiver is mathematically positive.\\\"\\n\\n\\t^ self > 0! !\\n\\n\\n!Number methodsFor: 'truncation and round off'!\\nceiling\\n\\t\\\"Answer the integer nearest the receiver toward positive infinity.\\\"\\n\\n\\tself <= 0.0\\n\\t\\tifTrue: [^self truncated]\\n\\t\\tifFalse: [^self negated floor negated]! !\\n\\n!Number methodsFor: 'truncation and round off' stamp: 'di 2/19/98 21:58'!\\ndetentBy: detent atMultiplesOf: grid snap: snap\\n\\t\\\"Map all values that are within detent/2 of any multiple of grid to that multiple. Otherwise, if snap is true, return self, meaning that the values in the dead zone will never be returned. If snap is false, then expand the range between dead zones so that it covers the range between multiples of the grid, and scale the value by that factor.\\\"\\n\\t| r1 r2 |\\n\\tr1 _ self roundTo: grid. \\\"Nearest multiple of grid\\\"\\n\\t(self roundTo: detent) = r1 ifTrue: [^ r1]. \\\"Snap to that multiple...\\\"\\n\\tsnap ifTrue: [^ self]. \\\"...or return self\\\"\\n\\n\\tr2 _ self < r1 \\\"Nearest end of dead zone\\\"\\n\\t\\tifTrue: [r1 - (detent asFloat/2)]\\n\\t\\tifFalse: [r1 + (detent asFloat/2)].\\n\\t\\\"Scale values between dead zones to fill range between multiples\\\"\\n\\t^ r1 + ((self - r2) * grid asFloat / (grid - detent))\\n\\\"\\n\\t(170 to: 190 by: 2) collect: [:a | a detentBy: 10 atMultiplesOf: 90 snap: true] \\t(170 to: 190 by: 2) collect: [:a | a detentBy: 10 atMultiplesOf: 90 snap: false]\\n\\t(3.9 to: 4.1 by: 0.02) collect: [:a | a detentBy: 0.1 atMultiplesOf: 1.0 snap: true] \\t(-3.9 to: -4.1 by: -0.02) collect: [:a | a detentBy: 0.1 atMultiplesOf: 1.0 snap: false]\\n\\\"! !\\n\\n!Number methodsFor: 'truncation and round off'!\\nfloor\\n\\t\\\"Answer the integer nearest the receiver toward negative infinity.\\\"\\n\\n\\t| truncation |\\n\\ttruncation _ self truncated.\\n\\tself >= 0 ifTrue: [^truncation].\\n\\tself = truncation\\n\\t\\tifTrue: [^truncation]\\n\\t\\tifFalse: [^truncation - 1]! !\\n\\n!Number methodsFor: 'truncation and round off' stamp: 'RAH 4/25/2000 19:49'!\\nfractionPart\\n\\t\\\"Answer the fractional part of the receiver.\\\"\\n\\t#Numeric.\\n\\t\\\"2000/03/04 Harmon R. Added ANSI <number> protocol\\\"\\n\\t^ self - self truncated! !\\n\\n!Number methodsFor: 'truncation and round off' stamp: 'RAH 4/25/2000 19:49'!\\nintegerPart\\n\\t\\\"Answer the integer part of the receiver.\\\"\\n\\t#Numeric.\\n\\t\\\"2000/03/04 Harmon R. Added ANSI <number> protocol\\\"\\n\\t^ self truncated! !\\n\\n!Number methodsFor: 'truncation and round off'!\\nreduce\\n \\\"If self is close to an integer, return that integer\\\"\\n ^ self! !\\n\\n!Number methodsFor: 'truncation and round off' stamp: 'di 10/4/1999 08:08'!\\nroundTo: quantum \\n\\t\\\"Answer the nearest number that is a multiple of quantum.\\\"\\n\\n\\t^(self / quantum) rounded * quantum! !\\n\\n!Number methodsFor: 'truncation and round off'!\\nroundUpTo: aNumber \\n\\t\\\"Answer the next multiple of aNumber toward infinity that is nearest the \\n\\treceiver.\\\"\\n\\n\\t^(self/aNumber) ceiling * aNumber! !\\n\\n!Number methodsFor: 'truncation and round off'!\\nrounded\\n\\t\\\"Answer the integer nearest the receiver.\\\"\\n\\n\\t^(self + (self sign / 2)) truncated! !\\n\\n!Number methodsFor: 'truncation and round off'!\\ntruncateTo: aNumber \\n\\t\\\"Answer the next multiple of aNumber toward zero that is nearest the \\n\\treceiver.\\\"\\n\\n\\t^(self quo: aNumber)\\n\\t\\t* aNumber! !\\n\\n!Number methodsFor: 'truncation and round off'!\\ntruncated\\n\\t\\\"Answer an integer nearest the receiver toward zero.\\\"\\n\\n\\t^self quo: 1! !\\n\\n\\n!Number methodsFor: '*eToys-printing' stamp: 'sw 10/31/97 13:54'!\\nnewTileMorphRepresentative\\n\\t^ TileMorph new addArrows; setLiteral: self; addSuffixIfCan\\n! !\\n\\n\\n!Number methodsFor: '*eToys-vocabulary' stamp: 'sw 8/3/2001 13:43'!\\nvocabularyDemanded\\n\\t\\\"Answer the vocabulary normally preferred by this object\\\"\\n\\n\\t^ Vocabulary numberVocabulary! !\\n\\n\\n!Number methodsFor: '*Morphic-NewCurve-testing' stamp: 'jmv 2/21/2006 13:15'!\\nisNonZero\\n\\t\\\"Return true for numbers not zero and false for all other\\n\\tobjects \\\"\\n\\t^ self isZero not! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNumber class\\n\\tinstanceVariableNames: ''!\\n\\n!Number class methodsFor: 'instance creation' stamp: 'nice 5/1/2006 21:46'!\\nreadExactlyFrom: stringOrStream \\n\\t\\\"Answer a number as described on aStream. The number may\\n\\tinclude a leading radix specification, as in 16rFADE\\\"\\n\\t\\n\\t^(SqNumberParser on: stringOrStream) nextNumber! !\\n\\n!Number class methodsFor: 'instance creation' stamp: 'yo 8/28/2002 22:40'!\\nreadFrom: stringOrStream \\n\\t\\\"Answer a number as described on aStream. The number may\\n\\tinclude a leading radix specification, as in 16rFADE\\\"\\n\\t| value base aStream sign |\\n\\taStream _ (stringOrStream isString)\\n\\t\\tifTrue: [ReadStream on: stringOrStream]\\n\\t\\tifFalse: [stringOrStream].\\n\\t(aStream nextMatchAll: 'NaN') ifTrue: [^ Float nan].\\n\\tsign _ (aStream peekFor: $-) ifTrue: [-1] ifFalse: [1].\\n\\t(aStream nextMatchAll: 'Infinity') ifTrue: [^ Float infinity * sign].\\n\\tbase _ 10.\\n\\tvalue _ Integer readFrom: aStream base: base.\\n\\t(aStream peekFor: $r)\\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"<base>r<integer>\\\"\\n\\t\\t\\t(base _ value) < 2 ifTrue: [^self error: 'Invalid radix'].\\n\\t\\t\\t(aStream peekFor: $-) ifTrue: [sign _ sign negated].\\n\\t\\t\\tvalue _ Integer readFrom: aStream base: base].\\n\\t^ self readRemainderOf: value from: aStream base: base withSign: sign.! !\\n\\n!Number class methodsFor: 'instance creation' stamp: 'yo 8/28/2002 22:41'!\\nreadFrom: stringOrStream base: base\\n\\t\\\"Answer a number as described on aStream in the given number base.\\\"\\n\\n\\t| aStream sign |\\n\\taStream _ (stringOrStream isString)\\n\\t\\tifTrue: [ReadStream on: stringOrStream]\\n\\t\\tifFalse: [stringOrStream].\\n\\t(aStream nextMatchAll: 'NaN') ifTrue: [^ Float nan].\\n\\tsign _ (aStream peekFor: $-) ifTrue: [-1] ifFalse: [1].\\n\\t(aStream nextMatchAll: 'Infinity') ifTrue: [^ Float infinity * sign].\\n\\t^ self readRemainderOf: (Integer readFrom: aStream base: base)\\n\\t\\t\\tfrom: aStream base: base withSign: sign! !\\n\\n\\n!Number class methodsFor: 'private' stamp: 'dtl 7/3/2006 17:41'!\\nreadExponent: baseValue base: base from: aStream\\n\\t\\\"Complete creation of a number, reading exponent from aStream. Answer the\\n\\tnumber, or nil if parsing fails.\\n\\t<number>(e|d|q)<exponent>>\\\"\\n\\n\\t| sign exp value |\\n\\t('edq' includes: aStream next) ifFalse: [^ nil].\\n\\tsign := ((aStream peek) == $-)\\n\\t\\tifTrue: [aStream next. -1]\\n\\t\\tifFalse: [1].\\n\\t(aStream atEnd or: [(aStream peek digitValue between: 0 and: 9) not])\\n\\t\\tifTrue: [^ nil]. \\\"Avoid throwing an error\\\"\\n\\texp := (Integer readFrom: aStream base: 10) * sign.\\n\\tvalue := baseValue * (base raisedTo: exp).\\n\\t^ value\\n! !\\n\\n!Number class methodsFor: 'private' stamp: 'dtl 7/4/2006 08:32'!\\nreadRemainderOf: integerPart from: aStream base: base withSign: sign \\n\\t\\\"Read optional fractional part and exponent or decimal scale, and return the final result\\\"\\n\\t\\\"Changed 200/01/19 For ANSI Numeric Literals support.\\\"\\n\\t\\\"Number readFrom: '3r-22.2'\\\"\\n\\n\\t| value fractionDigits fracpos fractionPart fraction pos v foundDecimal |\\n\\t#Numeric.\\n\\tvalue := integerPart.\\n\\tfractionDigits := 0.\\n\\tfoundDecimal := false.\\n\\t(aStream peekFor: $.)\\n\\t\\tifTrue: [\\\"<integer>.<fraction>\\\"\\n\\t\\t\\tfoundDecimal := true.\\n\\t\\t\\t(aStream atEnd not\\n\\t\\t\\t\\t\\tand: [aStream peek digitValue between: 0 and: base - 1])\\n\\t\\t\\t\\tifTrue: [fracpos := aStream position.\\n\\t\\t\\t\\t\\tfractionPart := Integer readFrom: aStream base: base.\\n\\t\\t\\t\\t\\tfraction := fractionPart asFloat\\n\\t\\t\\t\\t\\t\\t\\t\\t/ (base raisedTo: aStream position - fracpos).\\n\\t\\t\\t\\t\\tfractionDigits := aStream position - fracpos.\\n\\t\\t\\t\\t\\tvalue := value asFloat + fraction]].\\n\\n\\tpos := aStream position.\\n\\t(v := self readScaledDecimal: integerPart\\n\\t\\t\\tfractionPart: fractionPart\\n\\t\\t\\tdigits: fractionDigits\\n\\t\\t\\tbase: base\\n\\t\\t\\tsign: sign\\n\\t\\t\\tfrom: aStream)\\n\\t\\tifNil: [aStream position: pos]\\n\\t\\tifNotNil: [^ v \\\"<number>s<scale>>\\\"].\\n\\n\\tpos := aStream position.\\n\\t(v := self readExponent: value base: base from: aStream)\\n\\t\\tifNil: [aStream position: pos.\\n\\t\\t\\t(foundDecimal and: [fractionDigits = 0])\\n\\t\\t\\t\\tifTrue: [\\\"oops - just <integer>.\\\"\\n\\t\\t\\t\\t\\t\\t\\taStream skip: -1.\\n\\t\\t\\t\\t\\t\\t\\t\\\"un-gobble the period\\\"\\n\\t\\t\\t\\t\\t\\t\\t^ value * sign]]\\n\\t\\tifNotNil: [value := v \\\"<number>(e|d|q)<exponent>>\\\"].\\n\\n\\t(value isFloat\\n\\t\\t\\tand: [value = 0.0\\n\\t\\t\\t\\t\\tand: [sign = -1]])\\n\\t\\tifTrue: [^ Float negativeZero]\\n\\t\\tifFalse: [^ value * sign]! !\\n\\n!Number class methodsFor: 'private' stamp: 'md 7/15/2006 18:00'!\\nreadScaledDecimal: integerPart fractionPart: fractionPart digits: fractionDigits base: base sign: sign from: aStream \\n\\t\\\"Complete creation of a ScaledDecimal, reading scale from aStream. Answer\\n\\ta ScaledDecimal, or nil if parsing fails.\\n\\t<number>s[<scale>]\\\"\\n\\n\\t| scale decimalMultiplier decimalFraction |\\n\\taStream atEnd ifTrue: [^ nil].\\n\\t(aStream next == $s) ifFalse: [^ nil].\\n\\t\\\"<number>s<scale>\\\"\\n\\t(aStream atEnd not and: [aStream peek digitValue between: 0 and: 9])\\n\\t\\tifTrue: [scale := Integer readFrom: aStream]\\n\\t\\tifFalse: [^ nil].\\n\\tscale isNil\\n\\t\\tifTrue: [\\\"<number>s\\\"\\n\\t\\t\\tfractionDigits = 0\\n\\t\\t\\t\\tifTrue: [\\\"<integer>s\\\"\\n\\t\\t\\t\\t\\tscale := 0]\\n\\t\\t\\t\\tifFalse: [\\\"<integer>.<fraction>s\\\"\\n\\t\\t\\t\\t\\tscale := fractionDigits]].\\n\\tfractionPart isNil\\n\\t\\tifTrue: [^ ScaledDecimal newFromNumber: integerPart * sign scale: scale]\\n\\t\\tifFalse: [decimalMultiplier := base raisedTo: fractionDigits.\\n\\t\\t\\tdecimalFraction := integerPart * decimalMultiplier + fractionPart * sign / decimalMultiplier.\\n\\t\\t\\t^ ScaledDecimal newFromNumber: decimalFraction scale: scale]! !\\nTestCase subclass: #NumberParsingTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'KernelTests-Numbers'!\\n!NumberParsingTest commentStamp: 'dtl 11/24/2004 15:35' prior: 0!\\nTests to verify parsing of numbers from streams and strings.\\n\\nNote: ScaledDecimalTest contains related tests for parsing ScaledDecimal.!\\n\\n\\n!NumberParsingTest methodsFor: 'tests - Float' stamp: 'dtl 11/24/2004 14:29'!\\ntestFloatFromStreamAsNumber\\n\\t\\\"This covers parsing in Number>>readFrom:\\\"\\n\\n\\t| rs aFloat |\\n\\trs _ '10r-12.3456' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: -12.3456 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs _ '10r-12.3456e2' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs _ '10r-12.3456e2e2' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs upToEnd = 'e2'.\\n\\n\\trs _ '10r-12.3456d2' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs _ '10r-12.3456q2' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs _ '-12.3456q2' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs _ '12.3456q2' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: 1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs _ '12.3456z2' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: 12.3456 = aFloat.\\n\\tself assert: rs upToEnd = 'z2'.\\n! !\\n\\n!NumberParsingTest methodsFor: 'tests - Float' stamp: 'nice 4/28/2006 01:20'!\\ntestFloatFromStreamWithExponent\\n\\t\\\"This covers parsing in Number>>readFrom:\\\"\\n\\n\\t| rs aFloat |\\n\\trs _ '1.0e-14' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: 1.0e-14 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs _ '1.0e-14 1' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: 1.0e-14 = aFloat.\\n\\tself assert: rs upToEnd = ' 1'.\\n\\n\\trs _ '1.0e-14eee' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: 1.0e-14 = aFloat.\\n\\tself assert: rs upToEnd = 'eee'.\\n\\n\\trs _ '1.0e14e10' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: 1.0e14 = aFloat.\\n\\tself assert: rs upToEnd = 'e10'.\\n\\n\\trs _ '1.0e+14e' readStream. \\\"Plus sign is not parseable\\\"\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: 1.0 = aFloat.\\n\\tself assert: rs upToEnd = 'e+14e'.\\n\\n\\trs _ '1.0e' readStream.\\n\\taFloat _ Number readFrom: rs.\\n\\tself assert: 1.0 = aFloat.\\n\\tself assert: rs upToEnd = 'e'.! !\\n\\n!NumberParsingTest methodsFor: 'tests - Float' stamp: 'dtl 11/24/2004 14:07'!\\ntestFloatFromStringAsNumber\\n\\t\\\"This covers parsing in Number>>readFrom:\\\"\\n\\n\\t| aFloat |\\n\\taFloat _ '10r-12.3456' asNumber.\\n\\tself assert: -12.3456 = aFloat.\\n\\taFloat _ '10r-12.3456e2' asNumber.\\n\\tself assert: -1234.56 = aFloat.\\n\\taFloat _ '10r-12.3456d2' asNumber.\\n\\tself assert: -1234.56 = aFloat.\\n\\taFloat _ '10r-12.3456q2' asNumber.\\n\\tself assert: -1234.56 = aFloat.\\n\\taFloat _ '-12.3456q2' asNumber.\\n\\tself assert: -1234.56 = aFloat.\\n\\taFloat _ '12.3456q2' asNumber.\\n\\tself assert: 1234.56 = aFloat.\\n! !\\n\\n!NumberParsingTest methodsFor: 'tests - Float' stamp: 'dtl 11/24/2004 14:12'!\\ntestFloatFromStringWithExponent\\n\\t\\\"This covers parsing in Number>>readFrom:\\\"\\n\\n\\t| aFloat |\\n\\taFloat _ '1.0e-14' asNumber.\\n\\tself assert: 1.0e-14 = aFloat.\\n\\taFloat _ '1.0e-14 1' asNumber.\\n\\tself assert: 1.0e-14 = aFloat.\\n\\taFloat _ '1.0e-14e' asNumber.\\n\\tself assert: 1.0e-14 = aFloat.\\n\\taFloat _ '1.0e14e' asNumber.\\n\\tself assert: 1.0e14 = aFloat.\\n\\taFloat _ '1.0e+14e' asNumber. \\\"Plus sign is not parseable\\\"\\n\\tself assert: 1.0 = aFloat.\\n! !\\n\\n!NumberParsingTest methodsFor: 'tests - Float' stamp: 'nice 4/28/2006 01:39'!\\ntestFloatReadError\\n\\t\\\"This covers parsing in Number>>readFrom:\\\"\\n\\n\\t| rs num |\\n\\trs := '1e' readStream.\\n\\tnum := Number readFrom: rs.\\n\\tself assert: 1 = num.\\n\\tself assert: rs upToEnd = 'e'.\\n\\t\\n\\trs := '1s' readStream.\\n\\tnum := Number readFrom: rs.\\n\\tself assert: 1 = num.\\n\\tself assert: rs upToEnd = 's'.\\n\\n\\trs := '1.' readStream.\\n\\tnum := Number readFrom: rs.\\n\\tself assert: 1 = num.\\n\\tself assert: num isInteger.\\n\\tself assert: rs upToEnd = '.'.\\n\\t\\n\\trs := '' readStream.\\n\\tself should: [Number readFrom: rs] raise: Error.\\n\\t\\n\\trs := 'foo' readStream.\\n\\tself should: [Number readFrom: rs] raise: Error.\\n\\n\\trs := 'radix' readStream.\\n\\tself should: [Number readFrom: rs] raise: Error.\\n\\t\\n\\trs := '.e0' readStream.\\n\\tself should: [Number readFrom: rs] raise: Error.\\n\\t\\n\\trs := '-.e0' readStream.\\n\\tself should: [Number readFrom: rs] raise: Error.\\n\\t\\n\\trs := '--1' readStream.\\n\\tself should: [Number readFrom: rs] raise: Error.! !\\n\\n!NumberParsingTest methodsFor: 'tests - Float' stamp: 'dtl 11/24/2004 18:16'!\\ntestFloatReadWithRadix\\n\\t\\\"This covers parsing in Number>>readFrom:\\n\\tNote: In most Smalltalk dialects, the radix notation is not used for numbers\\n\\twith exponents. In Squeak, a string with radix and exponent can be parsed,\\n\\tand the exponent is always treated as base 10 (not the base indicated in the\\n\\tradix prefix). I am not sure if this is a feature, a bug, or both, but the\\n\\tSqueak behavior is documented in this test. -dtl\\\"\\n\\n\\t| aNumber rs |\\n\\taNumber _ '2r1.0101e9' asNumber.\\n\\tself assert: 672.0 = aNumber.\\n\\tself assert: (Number readFrom: '2r1.0101e9') = (1.3125 * (2 raisedTo: 9)).\\n\\trs _ ReadStream on: '2r1.0101e9e9'.\\n\\tself assert: (Number readFrom: rs) = 672.0.\\n\\tself assert: rs upToEnd = 'e9'\\n! !\\n\\n\\n!NumberParsingTest methodsFor: 'tests - Integer' stamp: 'dtl 11/24/2004 14:05'!\\ntestIntegerFromString\\n\\t\\\"This covers parsing in Number>>readFrom:\\n\\tTrailing decimal points should be ignored.\\\"\\n\\n\\tself assert: ('123' asNumber == 123).\\n\\tself assert: ('-123' asNumber == -123).\\n\\tself assert: ('123.' asNumber == 123).\\n\\tself assert: ('-123.' asNumber == -123).\\n\\tself assert: ('123This is not to be read' asNumber == 123).\\n\\tself assert: ('123s could be confused with a ScaledDecimal' asNumber == 123).\\n\\tself assert: ('123e could be confused with a Float' asNumber == 123).\\n! !\\n\\n!NumberParsingTest methodsFor: 'tests - Integer' stamp: 'tween 7/8/2006 12:31'!\\ntestIntegerReadFrom\\n\\t\\\"Ensure remaining characters in a stream are not lost when parsing an integer.\\\"\\n\\n\\t| rs i s |\\n\\trs _ ReadStream on: '123s could be confused with a ScaledDecimal'.\\n\\ti _ Number readFrom: rs.\\n\\tself assert: i == 123.\\n\\ts _ rs upToEnd.\\n\\tself assert: 's could be confused with a ScaledDecimal' = s.\\n\\trs _ ReadStream on: '123.s could be confused with a ScaledDecimal'.\\n\\ti _ Number readFrom: rs.\\n\\tself assert: i == 123.\\n\\ts _ rs upToEnd.\\n\\tself assert: '.s could be confused with a ScaledDecimal' = s.\\n\\trs _ ReadStream on: '123sA has unary message sA'.\\n\\ti _ Number readFrom: rs.\\n\\tself assert: i == 123.\\n\\ts _ rs upToEnd.\\n\\tself assert: 'sA has unary message sA' = s.\\t\\n\\trs _ ReadStream on: '123sB has unary message sB'.\\n\\ti _ Number readFrom: rs.\\n\\tself assert: i == 123.\\n\\ts _ rs upToEnd.\\n\\tself assert: 'sB has unary message sB' = s.\\n! !\\n\\n!NumberParsingTest methodsFor: 'tests - Integer' stamp: 'dtl 11/24/2004 18:18'!\\ntestIntegerReadWithRadix\\n\\t\\\"This covers parsing in Number>>readFrom:\\n\\tNote: In most Smalltalk dialects, the radix notation is not used for numbers\\n\\twith exponents. In Squeak, a string with radix and exponent can be parsed,\\n\\tand the exponent is always treated as base 10 (not the base indicated in the\\n\\tradix prefix). I am not sure if this is a feature, a bug, or both, but the\\n\\tSqueak behavior is documented in this test. -dtl\\\"\\n\\n\\t| aNumber rs |\\n\\taNumber _ '2r1e26' asNumber.\\n\\tself assert: 67108864 = aNumber.\\n\\tself assert: (Number readFrom: '2r1e26') = (2 raisedTo: 26).\\n\\trs _ '2r1e26eee' readStream.\\n\\tself assert: (Number readFrom: rs) = 67108864.\\n\\tself assert: rs upToEnd = 'eee'\\n! !\\nClassTestCase subclass: #NumberTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'KernelTests-Numbers'!\\n\\n!NumberTest methodsFor: 'tests' stamp: 'fbs 3/8/2006 11:24'!\\ntestPrintShowingDecimalPlaces\\n\\n\\tself assert: (111.2 printShowingDecimalPlaces: 2) = '111.20'.\\n\\tself assert: (111.2 printShowingDecimalPlaces: 0) = '111'.\\n\\tself assert: (111 printShowingDecimalPlaces: 0) = '111'.\\n\\tself assert: (111111111111111 printShowingDecimalPlaces: 2) = '111111111111111.00'.\\n\\tself assert: (10 printShowingDecimalPlaces: 20) ='10.00000000000000000000'.\\n! !\\n\\n!NumberTest methodsFor: 'tests' stamp: 'sd 6/5/2005 08:56'!\\ntestReadFrom\\n\\t\\n\\tself assert: 1.0e-14\\t= (Number readFrom: '1.0e-14').\\n\\tself assert: 2r1e26\\t= (Number readFrom: '2r1e26').! !\\nDataType subclass: #NumberType\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Protocols-Type Vocabularies'!\\n!NumberType commentStamp: 'sw 10/3/2002 02:18' prior: 0!\\nNumberType is a data type representing a numeric value.!\\n\\n\\n!NumberType methodsFor: 'initial value' stamp: 'sw 9/27/2001 17:29'!\\ninitialValueForASlotFor: aPlayer\\n\\t\\\"Answer the value to give initially to a newly created slot of the given type in the given player\\\"\\n\\n\\t^ (1 to: 9) atRandom! !\\n\\n\\n!NumberType methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:39'!\\ninitialize\\n\\t\\\"Initialize the receiver (automatically called when instances are created via 'new')\\\"\\n\\n\\t| aMethodCategory aMethodInterface |\\n\\tsuper initialize.\\n\\t\\\"Vocabulary replaceNumberVocabulary\\\"\\n\\t\\\"Vocabulary addVocabulary: Vocabulary newNumberVocabulary\\\"\\n\\n\\tself vocabularyName: #Number.\\n\\tself documentation: 'Numbers are things that can do arithmetic, have their magnitudes compared, etc.'.\\n\\n#((comparing\\t\\t\\t\\t'Determining which of two numbers is larger'\\n\\t\\t(= < > <= >= ~= ~~))\\n(arithmetic \\t\\t\\t\\t'Basic numeric operation'\\n\\t\\t(* + - / // \\\\\\\\ abs negated quo: rem:))\\n(testing \\t\\t\\t\\t\\t'Testing a number'\\n\\t\\t(even isDivisibleBy: negative odd positive sign))\\n(#'mathematical functions'\\t'Trigonometric and exponential functions'\\n\\t\\t(cos exp ln log log: raisedTo: sin sqrt squared tan raisedToInteger:))\\n(converting \\t\\t\\t\\t'Converting a number to another form'\\n\\t\\t(@ asInteger asPoint degreesToRadians radiansToDegrees asSmallAngleDegrees asSmallPositiveDegrees))\\n(#'truncation and round off' 'Making a real number (with a decimal point) into an integer'\\n\\t\\t(ceiling floor roundTo: roundUpTo: rounded truncateTo: truncated))\\n) do:\\n\\n\\t\\t[:item | \\n\\t\\t\\taMethodCategory := ElementCategory new categoryName: item first.\\n\\t\\t\\taMethodCategory documentation: item second.\\n\\t\\t\\titem third do:\\n\\t\\t\\t\\t[:aSelector | \\n\\t\\t\\t\\t\\taMethodInterface := MethodInterface new conjuredUpFor: aSelector class: (Number whichClassIncludesSelector: aSelector).\\n\\t\\t\\t\\t\\taMethodInterface argumentVariables do:\\n\\t\\t\\t\\t\\t\\t\\t[:var | var variableType: #Number].\\n\\n\\t\\t\\t\\t\\t(#(* + - / // \\\\\\\\ abs negated quo: rem:\\n\\t\\t\\t\\t\\t\\tcos exp ln log log: raisedTo: sin sqrt squared tan raisedToInteger:\\n\\t\\t\\t\\t\\t\\tasInteger degreesToRadians radiansToDegrees asSmallAngleDegrees asSmallPositiveDegrees)\\n\\t\\t\\t\\t\\t\\t\\tincludes: aSelector) ifTrue:\\n\\t\\t\\t\\t\\t\\t\\t\\t[aMethodInterface resultType: #Number].\\n\\n\\t\\t\\t\\t\\t(#( @ asPoint ) includes: aSelector) ifTrue:\\n\\t\\t\\t\\t\\t\\t[aMethodInterface resultType: #Point].\\n\\n\\t\\t\\t\\t\\t(#(= < > <= >= ~= ~~ even isDivisibleBy: negative odd positive) includes: aSelector) ifTrue:\\n\\t\\t\\t\\t\\t\\t[aMethodInterface resultType: #Boolean].\\n\\n\\t\\t\\t\\t\\taMethodInterface setNotToRefresh. \\n\\t\\t\\t\\t\\tself atKey: aSelector putMethodInterface: aMethodInterface.\\n\\t\\t\\t\\t\\taMethodCategory elementAt: aSelector put: aMethodInterface].\\n\\t\\t\\tself addCategory: aMethodCategory].\\n\\n\\\"\\n(('truncation and round off' ceiling detentBy:atMultiplesOf:snap: floor roundTo: roundUpTo: rounded truncateTo: truncated)\\n('testing' basicType even isDivisibleBy: isInf isInfinite isNaN isNumber isZero negative odd positive sign strictlyPositive)\\n('converting' @ adaptToCollection:andSend: adaptToFloat:andSend: adaptToFraction:andSend: adaptToInteger:andSend: adaptToPoint:andSend: adaptToString:andSend: asInteger asNumber asPoint asSmallAngleDegrees asSmallPositiveDegrees degreesToRadians radiansToDegrees)\\n('intervals' to: to:by: to:by:do: to:do:)\\n('printing' defaultLabelForInspector isOrAreStringWith: newTileMorphRepresentative printOn: printStringBase: storeOn: storeOn:base: storeStringBase: stringForReadout)\\n('comparing' closeTo:)\\n('filter streaming' byteEncode:)\\n('as yet unclassified' reduce)\\\"\\n\\n\\n\\n! !\\n\\n\\n!NumberType methodsFor: '*eToys-color' stamp: 'sw 9/27/2001 17:21'!\\ntypeColor\\n\\t\\\"Answer the color for tiles to be associated with objects of this type\\\"\\n\\n\\t^ self subduedColorFromTriplet: #(0.8 0.4 0.2)! !\\n\\n\\n!NumberType methodsFor: '*eToys-tiles' stamp: 'dgd 9/6/2003 20:30'!\\naddExtraItemsToMenu: aMenu forSlotSymbol: slotSym\\n\\t\\\"If the receiver has extra menu items to add to the slot menu, here is its chance to do it. The defaultTarget of the menu is the player concerned.\\\"\\n\\n\\taMenu add: 'decimal places...' translated selector: #setPrecisionFor: argument: slotSym.\\n\\taMenu balloonTextForLastItem: 'Lets you choose how many decimal places should be shown in readouts for this variable' translated! !\\n\\n!NumberType methodsFor: '*eToys-tiles' stamp: 'sw 9/15/2002 16:50'!\\naddUserSlotItemsTo: aMenu slotSymbol: slotSym\\n\\t\\\"Optionally add items to the menu that pertain to a user-defined slot of the given symbol\\\"\\n\\n\\t\\\"aMenu add: 'decimal places...' selector: #setPrecisionFor: argument: slotSym\\n\\tNB: This item is now generically added for system as well as user slots, so the addition is now done in NubmerType.addExtraItemsToMenu:forSlotSymbol:\\\"! !\\n\\n!NumberType methodsFor: '*eToys-tiles' stamp: 'sw 9/27/2001 02:53'!\\ncomparatorForSampleBoolean\\n\\t\\\"Answer the comparator to use in tile coercions involving the receiver; normally, the equality comparator is used but NumberType overrides\\\"\\n\\n\\t^ #<! !\\n\\n!NumberType methodsFor: '*eToys-tiles' stamp: 'sw 9/27/2001 17:30'!\\ndefaultArgumentTile\\n\\t\\\"Answer a tile to represent the type\\\"\\n\\n\\t^ 5 newTileMorphRepresentative typeColor: self typeColor! !\\n\\n!NumberType methodsFor: '*eToys-tiles' stamp: 'sw 9/27/2001 17:37'!\\nnewReadoutTile\\n\\t\\\"Answer a tile that can serve as a readout for data of this type\\\"\\n\\n\\t^ NumericReadoutTile new typeColor: Color lightGray lighter! !\\n\\n!NumberType methodsFor: '*eToys-tiles' stamp: 'sw 9/26/2001 03:11'!\\nwantsAssignmentTileVariants\\n\\t\\\"Answer whether an assignment tile for a variable of this type should show variants to increase-by, decrease-by, multiply-by.\\\"\\n\\n\\t^ true! !\\n\\n!NumberType methodsFor: '*eToys-tiles' stamp: 'sw 9/26/2001 03:18'!\\nwantsSuffixArrow\\n\\t\\\"Answer whether a tile showing data of this type would like to have a suffix arrow\\\"\\n\\n\\t^ true! !\\nTileMorph subclass: #NumericReadoutTile\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting Tiles'!\\n\\n!NumericReadoutTile methodsFor: 'accessing' stamp: 'ar 9/15/2000 23:27'!\\nabandonLabelFocus\\n\\t| aLabel |\\n\\t\\\"If the receiver's label has editing focus, abandon it\\\"\\n\\tself flag: #arNote. \\\"Probably unnecessary\\\"\\n\\t(aLabel _ self labelMorph) ifNotNil:\\n\\t\\t[aLabel hasFocus ifTrue:\\n\\t\\t\\t[aLabel contents: aLabel readFromTarget.\\n\\t\\t\\taLabel handsWithMeForKeyboardFocus do:\\n\\t\\t\\t\\t[:aHand | aHand releaseKeyboardFocus]]]! !\\n\\n!NumericReadoutTile methodsFor: 'accessing' stamp: 'tak 12/6/2004 01:53'!\\nliteralFromContents\\n\\t| label |\\n\\tlabel _ self labelMorph\\n\\t\\t\\t\\tifNil: [^ super literal].\\n\\tlabel step.\\n\\t^ literal _ label valueFromContents! !\\n\\n!NumericReadoutTile methodsFor: 'accessing' stamp: 'tak 4/6/2005 14:10'!\\nliteral: anObject \\n\\tliteral := anObject.\\n\\tself updateLiteralLabel.\\n\\tself labelMorph\\n\\t\\tifNotNilDo: [:label | label informTarget]! !\\n\\n\\n!NumericReadoutTile methodsFor: 'literal' stamp: 'sw 9/15/1999 15:14'!\\nsetLiteralTo: anObject width: w\\n\\t\\\"like literal:width: but does not inform the target\\\"\\n\\tliteral _ anObject.\\n\\tself updateLiteralLabel.\\n\\tsubmorphs last setWidth: w.\\n\\tself updateLiteralLabel! !\\n\\n\\n!NumericReadoutTile methodsFor: 'misc' stamp: 'sw 9/17/1999 08:01'!\\nbasicWidth\\n\\t^ 26! !\\n\\n!NumericReadoutTile methodsFor: 'misc' stamp: 'sw 9/17/1999 08:18'!\\nminimumWidth\\n\\t^ 40! !\\n\\n\\n!NumericReadoutTile methodsFor: 'mouse' stamp: 'ar 10/25/2000 18:07'!\\nhandlesMouseMove: evt\\n\\t^true! !\\n\\n\\n!NumericReadoutTile methodsFor: 'parts bin' stamp: 'sw 11/15/2001 20:22'!\\ninitializeToStandAlone\\n\\t\\\"Enclose my prototype in a SyntaxMorph. For the ObjectTool\\\"\\n\\n\\t| aWatcher aTile aLine aColor ms slotMsg |\\n\\n\\tsuper initializeToStandAlone.\\n\\taColor _ Color r: 0.387 g: 0.581 b: 1.0.\\n\\taTile _ self typeColor: aColor.\\n\\taWatcher _ UpdatingStringMorph new.\\n\\taWatcher growable: true;\\n\\t\\tgetSelector: nil;\\n\\t\\tputSelector: nil;\\n\\t\\tsetToAllowTextEdit.\\n\\taWatcher target: nil.\\n\\taTile addMorphBack: aWatcher.\\n\\taTile addArrows.\\n\\taTile setLiteralTo: 5 width: 30.\\n\\n\\tms _ MessageSend receiver: nil selector: #aNumber arguments: #().\\n\\tslotMsg _ ms asTilesIn: Player globalNames: false.\\n\\t\\t\\\"For CardPlayers, use 'aPlayer'. For others, name it, and use its name.\\\"\\n\\tms _ MessageSend receiver: 3 selector: #= asSymbol arguments: #(5).\\n\\taLine _ ms asTilesIn: Player globalNames: false.\\n\\taLine firstSubmorph delete.\\t\\t\\\"A little over-complicated? Yes?\\\"\\n\\taLine addMorphFront: (slotMsg submorphs second) firstSubmorph.\\n\\taLine addMorphFront: (Morph new transparentSpacerOfSize: 3@3).\\n\\taLine lastSubmorph delete.\\n\\taLine lastSubmorph delete.\\n\\taLine color: aColor.\\n\\taLine addMorphBack: (Morph new transparentSpacerOfSize: 3@3).\\n\\taLine addMorphBack: aTile.\\n\\taLine cellPositioning: #leftCenter.\\n\\taWatcher step; fitContents.\\n\\t^ aLine markAsPartsDonor.! !\\n\\n\\n!NumericReadoutTile methodsFor: 'testing' stamp: 'tk 11/1/2001 12:41'!\\nbasicType\\n\\t\\\"Answer a symbol representing the inherent type I hold\\\"\\n\\n\\t\\\"Number String Boolean player collection sound color etc\\\"\\n\\t^ #Number! !\\n\\n\\n!NumericReadoutTile methodsFor: 'event handling' stamp: 'tak 8/2/2005 23:36'!\\nmouseStillDown: evt \\n\\t(self labelMorph notNil\\n\\t\\t\\tand: [self labelMorph containsPoint: evt cursorPoint])\\n\\t\\tifTrue: [^ self labelMorph mouseDown: evt].\\n\\t^ super mouseStillDown: evt! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nNumericReadoutTile class\\n\\tinstanceVariableNames: ''!\\n\\n!NumericReadoutTile class methodsFor: 'instance creation' stamp: 'tk 12/14/2001 19:32'!\\nborderedPrototype\\n\\t\\\"Just number and up/down arrows\\\"\\n\\n\\t| aWatcher aTile |\\n\\n\\taTile _ self new typeColor: (Color r: 0.387 g: 0.581 b: 1.0).\\n\\taWatcher _ UpdatingStringMorph new.\\n\\taWatcher growable: true; setNameTo: 'value'.\\n\\taTile addMorphBack: aWatcher.\\n\\taTile addArrows; setNameTo: 'Number (mid)'.\\n\\taTile setLiteralTo: 5 width: 30.\\n\\taWatcher step; fitContents; setToAllowTextEdit.\\n\\t^ aTile extent: 30@24; markAsPartsDonor! !\\n\\n!NumericReadoutTile class methodsFor: 'instance creation' stamp: 'tk 12/14/2001 19:29'!\\nsimplePrototype\\n\\t\\\"Bare number readout. Will keep up to data with a number once it has target, getterSelector, setterSelector.\\\"\\n\\n\\t^ (UpdatingStringMorph new) contents: '5'; growable: true; setToAllowTextEdit; \\n\\t\\tstep; fitContents; setNameTo: 'Number (bare)'; markAsPartsDonor! !\\n\\n!NumericReadoutTile class methodsFor: 'instance creation' stamp: 'nk 8/23/2004 18:11'!\\nsupplementaryPartsDescriptions\\n\\t\\\"Answer additional items for the parts bin\\\"\\n\\n\\tPreferences universalTiles ifFalse: [^ #()].\\n\\n\\t^ {DescriptionForPartsBin\\n\\t\\tformalName: 'Number (fancy)'\\n\\t\\tcategoryList: #('Basic')\\n\\t\\tdocumentation: 'A number readout for a Stack. Shows current value. Click and type the value. Shift-click on title to edit.'\\n\\t\\tglobalReceiverSymbol: #NumericReadoutTile\\n\\t\\tnativitySelector: #authoringPrototype.\\n\\n\\t DescriptionForPartsBin\\n\\t\\tformalName: 'Number (bare)'\\n\\t\\tcategoryList: #('Basic')\\n\\t\\tdocumentation: 'A number readout for a Stack. Shows current value. Click and type the value.'\\n\\t\\tglobalReceiverSymbol: #NumericReadoutTile\\n\\t\\tnativitySelector: #simplePrototype.\\n\\n\\t DescriptionForPartsBin\\n\\t\\tformalName: 'Number (mid)'\\n\\t\\tcategoryList: #('Basic')\\n\\t\\tdocumentation: 'A number readout for a Stack. Shows current value. Click and type the value.'\\n\\t\\tglobalReceiverSymbol: #NumericReadoutTile\\n\\t\\tnativitySelector: #borderedPrototype}! !\\n\\n\\n!NumericReadoutTile class methodsFor: 'scripting' stamp: 'tk 12/14/2001 19:30'!\\nauthoringPrototype\\n\\t\\\"Enclose my prototype in a SyntaxMorph.\\\"\\n\\n\\t| aWatcher aTile aLine aColor ms slotMsg |\\n\\n\\taColor _ Color r: 0.387 g: 0.581 b: 1.0.\\n\\taTile _ self new typeColor: aColor.\\n\\taWatcher _ UpdatingStringMorph new.\\n\\taWatcher growable: true;\\n\\t\\tsetToAllowTextEdit;\\n\\t\\tgetSelector: nil;\\n\\t\\tputSelector: nil.\\n\\taWatcher target: nil.\\n\\taTile addMorphBack: aWatcher.\\n\\taTile addArrows.\\n\\taTile setLiteralTo: 5 width: 30.\\n\\n\\t\\\"This is the long way around to do this...\\\"\\n\\tms _ MessageSend receiver: nil selector: #aNumber arguments: #().\\n\\tslotMsg _ ms asTilesIn: Player globalNames: false.\\n\\t\\t\\\"For CardPlayers, use 'aPlayer'. For others, name it, and use its name.\\\"\\n\\tms _ MessageSend receiver: 3 selector: #= asSymbol arguments: #(5).\\n\\taLine _ ms asTilesIn: Player globalNames: false.\\n\\taLine firstSubmorph delete.\\t\\n\\taLine addMorphFront: (slotMsg submorphs second) firstSubmorph.\\n\\taLine firstSubmorph setNameTo: 'label'.\\n\\taLine addMorphFront: (Morph new transparentSpacerOfSize: 3@3).\\n\\taLine lastSubmorph delete.\\n\\taLine lastSubmorph delete.\\n\\taLine color: aColor; setNameTo: 'Number (fancy)'.\\n\\taLine addMorphBack: (Morph new transparentSpacerOfSize: 3@3).\\n\\taLine addMorphBack: aTile.\\n\\taLine readOut setNameTo: 'value'.\\n\\taLine cellPositioning: #leftCenter.\\n\\taWatcher step; fitContents.\\n\\t^ aLine markAsPartsDonor.! !\\nOBAnnouncement subclass: #OBAboutToChange\\n\\tinstanceVariableNames: 'veto'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBAboutToChange methodsFor: 'vetos' stamp: 'cwp 4/17/2006 22:18'!\\nisVetoed\\n\\t^ veto notNil! !\\n\\n!OBAboutToChange methodsFor: 'vetos' stamp: 'cwp 4/17/2006 19:45'!\\nveto\\n\\tveto _ true! !\\nMessageSend subclass: #OBAction\\n\\tinstanceVariableNames: 'announcer dispatcher label buttonLabel keystroke icon'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Services'!\\n!OBAction commentStamp: 'cwp 3/4/2004 20:52' prior: 0!\\nActions represent commands for manipulating the graph domain. They can be made available through menus or buttons in the browser. They carry information on how they should be presented to the user, and are responsible for handling exceptions generated when they are triggered. Actions are created by Actors.\\n\\niVars: \\n\\nlabel \\t\\ta string which describes the action for the user.\\nmonitor \\twhen the action is triggered, any notifications raised \\n\\t\\t\\twill be passed to this object for processing!\\n\\n\\n!OBAction methodsFor: 'accessing' stamp: 'cwp 6/4/2006 00:25'!\\nannouncer\\n\\t^ announcer! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'cwp 6/4/2006 00:25'!\\nannouncer: anAnnouncer\\n\\tannouncer _ anAnnouncer! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'cwp 3/10/2004 23:35'!\\nbuttonLabel\\n\\t^ buttonLabel! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'cwp 3/10/2004 23:35'!\\nbuttonLabel: aString\\n\\tbuttonLabel _ aString\\n\\t! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'hpt 5/17/2004 16:42'!\\nicon\\n\\t^icon! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'hpt 5/17/2004 16:42'!\\nicon: anIcon\\n\\ticon _ anIcon! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'hpt 5/17/2004 14:16'!\\nkeystroke\\n\\t^keystroke! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'hpt 5/17/2004 14:16'!\\nkeystroke: aChar\\n\\tkeystroke _ aChar! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'cwp 1/7/2004 09:11'!\\nlabel\\n\\t^ label! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'cwp 1/7/2004 09:12'!\\nlabel: aString\\n\\tlabel _ aString! !\\n\\n!OBAction methodsFor: 'accessing' stamp: 'cwp 3/10/2004 23:40'!\\nwantsButton\\n\\t^ buttonLabel notNil! !\\n\\n\\n!OBAction methodsFor: 'evaluating' stamp: 'cwp 1/7/2004 18:22'!\\nperform: aSelector orSendTo: anObject\\n\\t^ self perform: aSelector! !\\n\\n!OBAction methodsFor: 'evaluating' stamp: 'cwp 6/4/2006 00:58'!\\ntrigger\\n\\t[self value]\\n\\t\\ton: OBAnnouncerRequest\\n\\t\\tdo: [:notification | notification resume: announcer].! !\\n\\n\\n!OBAction methodsFor: 'morphic' stamp: 'hpt 5/17/2004 17:00'!\\naddItemToMenu: aMenu\\n\\taMenu\\n\\t\\tadd: self labelWithKeystroke\\n\\t\\ttarget: self \\n\\t\\tselector: #trigger.\\n\\tPreferences menuWithIcons & self icon notNil\\n\\t\\tifTrue: [aMenu lastItem icon: self icon].\\n\\taMenu addBlankIconsIfNecessary: MenuIcons blankIcon.! !\\n\\n!OBAction methodsFor: 'morphic' stamp: 'cwp 7/8/2006 12:55'!\\nbuttonLabelMorph\\n\\t^ StringMorph \\n\\t\\tcontents: self buttonLabel \\n\\t\\tfont: Preferences standardButtonFont! !\\n\\n!OBAction methodsFor: 'morphic' stamp: 'cwp 7/8/2006 12:54'!\\nbuttonMorph\\n\\t^ (PluggableButtonMorph\\n\\t\\ton: self\\n\\t\\tgetState: nil\\n\\t\\taction: #trigger\\n\\t\\tlabel: #buttonLabelMorph)\\t\\n\\t\\t\\tonColor: Color lightGray lighter offColor: Color lightGray twiceLighter;\\n\\t\\t\\tborderWidth: 2;\\n\\t\\t\\tborderRaised;\\n\\t\\t\\thResizing: #spaceFill;\\n\\t\\t\\tvResizing: #spaceFill;\\n\\t\\t\\tsetBalloonText: label! !\\n\\n!OBAction methodsFor: 'morphic' stamp: 'hpt 5/17/2004 14:17'!\\nlabelWithKeystroke\\n\\t^keystroke\\n\\t\\tifNil: [label]\\n\\t\\tifNotNil: [label, ' (', keystroke asString, ')']! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBAction class\\n\\tinstanceVariableNames: ''!\\n\\n!OBAction class methodsFor: 'instance creation' stamp: 'cwp 3/10/2004 23:36'!\\nlabel: aString buttonLabel: aString2 receiver: anObject selector: aSelector arguments: anArray\\n\\t^ (self receiver: anObject selector: aSelector arguments: anArray) \\n\\t\\tlabel: aString;\\n\\t\\tbuttonLabel: aString2! !\\n\\n!OBAction class methodsFor: 'instance creation' stamp: 'cwp 12/5/2004 18:49'!\\nlabel: aString buttonLabel: aString2 receiver: anObject selector: aSelector \\narguments: anArray keystroke: aChar icon: anIcon\\n\\t^ (self receiver: anObject selector: aSelector arguments: anArray) \\n\\t\\tlabel: aString;\\n\\t\\tbuttonLabel: aString2;\\n\\t\\tkeystroke: aChar;\\n\\t\\ticon: anIcon! !\\n\\n!OBAction class methodsFor: 'instance creation' stamp: 'cwp 1/7/2004 09:20'!\\nlabel: aString receiver: anObject selector: aSelector arguments: anArray\\n\\t^ (self receiver: anObject selector: aSelector arguments: anArray) label: aString! !\\n\\n!OBAction class methodsFor: 'instance creation' stamp: 'hpt 5/17/2004 16:50'!\\nlabel: aString receiver: anObject selector: aSelector arguments: anArray icon: anIcon\\n\\t^ (self receiver: anObject selector: aSelector arguments: anArray) \\n\\t\\tlabel: aString;\\n\\t\\ticon: anIcon! !\\n\\n!OBAction class methodsFor: 'instance creation' stamp: 'hpt 5/17/2004 14:16'!\\nlabel: aString receiver: anObject selector: aSelector arguments: anArray keystroke: aChar\\n\\t^ (self receiver: anObject selector: aSelector arguments: anArray) \\n\\t\\tlabel: aString;\\n\\t\\tkeystroke: aChar! !\\n\\n!OBAction class methodsFor: 'instance creation' stamp: 'hpt 5/17/2004 16:50'!\\nlabel: aString receiver: anObject selector: aSelector arguments: anArray keystroke: aChar icon: anIcon\\n\\t^ (self receiver: anObject selector: aSelector arguments: anArray) \\n\\t\\tlabel: aString;\\n\\t\\tkeystroke: aChar;\\n\\t\\ticon: anIcon! !\\nObject subclass: #OBActor\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Services'!\\n!OBActor commentStamp: 'cwp 1/7/2005 23:14' prior: 0!\\nActors provide the basic units of domain-related functionality. They are attached to metanodes, and supply the Actions used to build context menus and buttons in the browser. Actors can be proxies for functionality supplied by other classes, as in OBFileRegistryActor, or they may supply the funtionality them selves. \\n\\nOBActor is an abstract class which defines the protocol Actors must implement. Actors need not be subclasses of OBActor, however.!\\n\\n\\n!OBActor methodsFor: 'accessing' stamp: 'cwp 9/16/2004 23:25'!\\nactionWithLabel: aString selector: aSymbol \\n\\tself shouldBeImplemented! !\\n\\n\\n!OBActor methodsFor: 'public' stamp: 'cwp 2/4/2004 15:25'!\\nactionsForNode: aNode\\n\\t^#()! !\\n\\n!OBActor methodsFor: 'public' stamp: 'cwp 2/5/2004 20:12'!\\nactionsForParent: aNode\\n\\t^#()! !\\n\\n\\n!OBActor methodsFor: 'icons' stamp: 'cwp 7/10/2006 22:30'!\\ndeleteIcon\\n\\t^ MenuIcons tryIcons: #(deleteIcon smallDeleteIcon)! !\\n\\n!OBActor methodsFor: 'icons' stamp: 'cwp 7/10/2006 22:31'!\\nfindIcon\\n\\t^ MenuIcons tryIcons: #(findIcon smallFindIcon)! !\\n\\n!OBActor methodsFor: 'icons' stamp: 'cwp 7/10/2006 22:31'!\\nnewIcon\\n\\t^ MenuIcons tryIcons: #(newIcon smallNewIcon)! !\\nOBMethodCategoryNode subclass: #OBAllMethodCategoryNode\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBAllMethodCategoryNode commentStamp: 'cwp 1/8/2005 12:31' prior: 0!\\nOBAllMethodCategory implements the synthetic '-- all --' category, which contains all the methods in a class.!\\n\\n\\n!OBAllMethodCategoryNode methodsFor: 'accessing'!\\ncategory\\n\\t^ 'as yet unclassified'! !\\n\\n!OBAllMethodCategoryNode methodsFor: 'accessing'!\\nmethodReferences\\n\\t^ self theClass selectors asSortedArray \\n\\t\\tcollect: [:ea | MethodReference new setStandardClass: self theClass methodSymbol: ea]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBAllMethodCategoryNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBAllMethodCategoryNode class methodsFor: 'as yet unclassified'!\\non: className\\n\\t^ self on: '-- all --' inClass: className! !\\nObject subclass: #OBAnnouncement\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\nObject subclass: #OBAnnouncer\\n\\tinstanceVariableNames: 'subscriptions'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBAnnouncer methodsFor: 'subscription' stamp: 'cwp 6/5/2006 00:39'!\\nannounce: anObject\\n\\n\\t| ann |\\n\\tann _ anObject asAnnouncement.\\n\\tsubscriptions keysAndValuesDo:\\n\\t\\t[:class :action |\\n\\t\\t(ann isKindOf: class) ifTrue: [action valueWithArguments: {ann}]].\\n\\t^ ann! !\\n\\n!OBAnnouncer methodsFor: 'subscription' stamp: 'cwp 6/3/2006 21:21'!\\nobserve: aClass do: aValuable \\n\\t| actions |\\n\\tactions _ subscriptions at: aClass ifAbsent: [ActionSequence new].\\n\\tsubscriptions at: aClass put: (actions copyWith: aValuable).! !\\n\\n!OBAnnouncer methodsFor: 'subscription' stamp: 'cwp 6/3/2006 23:31'!\\nobserve: aClass send: aSelector to: anObject\\n\\tself\\n\\t\\tobserve: aClass\\n\\t\\tdo: (MessageSend receiver: anObject selector: aSelector)! !\\n\\n!OBAnnouncer methodsFor: 'subscription' stamp: 'cwp 6/10/2006 00:40'!\\nunsubscribe: anObject\\n\\tsubscriptions keysAndValuesDo:\\n\\t\\t[:class :actions |\\n\\t\\tsubscriptions at: class put: (actions reject: [:ea | ea receiver == anObject])].\\n\\tsubscriptions keysAndValuesRemove: [:key :value | value isEmpty]! !\\n\\n\\n!OBAnnouncer methodsFor: 'initialize-release' stamp: 'cwp 4/17/2006 11:51'!\\ninitialize\\n\\tsubscriptions _ IdentityDictionary new.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBAnnouncer class\\n\\tinstanceVariableNames: ''!\\n\\n!OBAnnouncer class methodsFor: 'instance creation' stamp: 'cwp 6/4/2006 00:55'!\\ncurrent\\n\\t^ OBAnnouncerRequest signal! !\\n\\n!OBAnnouncer class methodsFor: 'instance creation' stamp: 'cwp 4/17/2006 11:50'!\\nnew\\n\\t^ self basicNew initialize! !\\nNotification subclass: #OBAnnouncerRequest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Notifications'!\\nOBInteractionRequest subclass: #OBBrowseRequest\\n\\tinstanceVariableNames: 'browser'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Notifications'!\\n!OBBrowseRequest commentStamp: 'cwp 12/7/2004 00:10' prior: 0!\\nThis notification is raised whenever a browser needs to be opened. The default action is to open a SystemWindow in Morphic, but it can be caught in situations where that's not appropriate. The OB test suite uses this extensively. !\\n\\n\\n!OBBrowseRequest methodsFor: 'accessing' stamp: 'cwp 10/17/2004 18:45'!\\nbrowser\\n\\t^ browser! !\\n\\n!OBBrowseRequest methodsFor: 'accessing' stamp: 'cwp 10/17/2004 18:45'!\\nbrowser: aBrowser\\n\\tbrowser _ aBrowser! !\\n\\n!OBBrowseRequest methodsFor: 'accessing' stamp: 'cwp 10/17/2004 21:27'!\\ndefaultAction\\n\\t^ browser openInMorphic! !\\n\\n\\n!OBBrowseRequest methodsFor: 'testing' stamp: 'cwp 10/17/2004 19:32'!\\nisBrowseRequest\\n\\t^ true! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBBrowseRequest class\\n\\tinstanceVariableNames: ''!\\n\\n!OBBrowseRequest class methodsFor: 'as yet unclassified' stamp: 'cwp 10/17/2004 18:45'!\\nsignal: aBrowser\\n\\t^ (self new browser: aBrowser) signal! !\\nObject subclass: #OBBrowser\\n\\tinstanceVariableNames: 'panels announcer'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Kernel'!\\n!OBBrowser commentStamp: 'cwp 1/7/2005 23:17' prior: 0!\\nOBBrowser is the core of OmniBrower. It's the root object for each browser and the model for the SystemWindows which display them. Its main responsibily is managing panels, particularly passing update messages between them.\\n\\nOn the class side, OBBrowser provides some default settings for creating and opening browsers. Subclasses can override these settings to acheive customized behavior.\\n\\niVars:\\n\\npanels\\t- A collection of objects which manage submorphs of the browser's SystemWindow.\\n\\ncVars:\\n\\nMetaGraphs - A dictionary matching names to metagraphs!\\n\\n\\n!OBBrowser methodsFor: 'accessing' stamp: 'cwp 6/4/2006 00:36'!\\naddPanel: aPanel\\n\\tpanels add: aPanel.\\n\\taPanel browser: self.\\n! !\\n\\n!OBBrowser methodsFor: 'accessing' stamp: 'cwp 4/17/2006 15:42'!\\nannouncer\\n\\t^ announcer! !\\n\\n!OBBrowser methodsFor: 'accessing' stamp: 'cwp 11/20/2004 21:00'!\\ncurrentNode\\n\\t^self navigationPanel currentNode! !\\n\\n!OBBrowser methodsFor: 'accessing' stamp: 'cwp 11/20/2004 21:00'!\\ncurrentOrRootNode\\n\\t^self navigationPanel currentOrRootNode! !\\n\\n!OBBrowser methodsFor: 'accessing' stamp: 'cwp 8/31/2004 13:04'!\\ndefaultLabel\\n\\t^ self class titleForRoot: self root! !\\n\\n!OBBrowser methodsFor: 'accessing' stamp: 'cwp 12/5/2004 16:25'!\\nnavigationPanel\\n\\t^ panels \\n\\t\\tdetect: [:ea | ea isNavigation] \\n\\t\\tifNone: [self error: 'No navigation panel configured']! !\\n\\n!OBBrowser methodsFor: 'accessing' stamp: 'cwp 9/17/2004 00:53'!\\npanels\\n\\t^ panels! !\\n\\n!OBBrowser methodsFor: 'accessing' stamp: 'cwp 6/28/2006 00:44'!\\nrequestor\\n\\t^ OBRequestor for: self! !\\n\\n!OBBrowser methodsFor: 'accessing' stamp: 'dvf 9/5/2005 17:30'!\\nselectionPath\\n\\t^self navigationPanel selectionPath! !\\n\\n\\n!OBBrowser methodsFor: 'callbacks' stamp: 'cwp 11/20/2004 21:05'!\\nlabelString\\n\\t| label |\\n\\tlabel := self navigationPanel labelString.\\n\\t^label \\n\\t\\tifNil: [self defaultLabel]\\n\\t\\tifNotNil: [self defaultLabel , ': ' , label]! !\\n\\n!OBBrowser methodsFor: 'callbacks' stamp: 'cwp 4/17/2006 19:52'!\\nokToChange\\n\\t^ (self announcer announce: OBAboutToChange) isVetoed not! !\\n\\n\\n!OBBrowser methodsFor: 'initializing' stamp: 'cwp 6/4/2006 14:09'!\\ninitialize\\n\\tpanels _ OrderedCollection new.\\n\\tannouncer _ OBAnnouncer new.\\n\\tself subscribe! !\\n\\n!OBBrowser methodsFor: 'initializing' stamp: 'cwp 12/5/2004 16:24'!\\nsetMetaNode: aMetaNode node: aNode \\n\\tself navigationPanel setMetaNode: aMetaNode node: aNode! !\\n\\n\\n!OBBrowser methodsFor: 'morphic' stamp: 'cwp 11/27/2004 22:21'!\\ndefaultBackgroundColor\\n\\t^ Color gray veryMuchLighter! !\\n\\n!OBBrowser methodsFor: 'morphic' stamp: 'cwp 12/5/2004 14:23'!\\nmorph\\n\\t| window |\\n\\twindow := SystemWindow labelled: self defaultLabel.\\n\\twindow model: self.\\n\\tpanels isEmpty ifFalse: [self morphicPanelLayout addMorphsTo: window].\\n\\t^window! !\\n\\n!OBBrowser methodsFor: 'morphic' stamp: 'cwp 11/21/2004 00:31'!\\nmorphicPanelLayout\\n\\t^ OBMorphicPanelLayout for: panels! !\\n\\n!OBBrowser methodsFor: 'morphic' stamp: 'cwp 11/21/2004 00:30'!\\nopenInMorphic\\n\\t^ self morph openInWorld! !\\n\\n\\n!OBBrowser methodsFor: 'navigating' stamp: 'cwp 11/20/2004 21:00'!\\njumpToRoot\\n\\t^self navigationPanel jumpToRoot! !\\n\\n!OBBrowser methodsFor: 'navigating' stamp: 'cwp 11/20/2004 21:00'!\\njumpTo: aNode \\n\\tself navigationPanel jumpTo: aNode! !\\n\\n!OBBrowser methodsFor: 'navigating' stamp: 'cwp 9/17/2005 17:48'!\\nroot\\n\\t^self navigationPanel root! !\\n\\n\\n!OBBrowser methodsFor: 'opening' stamp: 'cwp 10/17/2004 21:31'!\\nopen\\n\\t^ OBBrowseRequest signal: self! !\\n\\n\\n!OBBrowser methodsFor: 'updating' stamp: 'cwp 6/9/2006 23:29'!\\ndontTranscribe\\n\\tself announcer unsubscribe: self.\\n\\tself subscribe.! !\\n\\n!OBBrowser methodsFor: 'updating' stamp: 'cwp 4/24/2006 15:10'!\\nrelabel: ann\\n\\tself changed: #relabel.\\n! !\\n\\n!OBBrowser methodsFor: 'updating' stamp: 'cwp 6/4/2006 18:50'!\\nsignalRefresh\\n\\tself announcer announce: OBRefreshRequired! !\\n\\n!OBBrowser methodsFor: 'updating' stamp: 'cwp 6/6/2006 00:25'!\\nsubscribe\\n\\tself announcer \\n\\t\\tobserve: OBSelectionChanged send: #relabel: to: self! !\\n\\n!OBBrowser methodsFor: 'updating' stamp: 'cwp 6/6/2006 00:26'!\\ntranscribe\\n\\tself announcer observe: OBAnnouncement do: [:ann | Transcript cr; show: ann].! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBBrowser class methodsFor: 'auto opening' stamp: 'cwp 12/6/2004 23:22'!\\nopen\\n\\t^ self new open! !\\n\\n!OBBrowser class methodsFor: 'auto opening' stamp: 'cwp 12/5/2004 17:03'!\\nopenRoot: rootNode selection: selectedNode\\n\\t^ (self root: rootNode selection: selectedNode) open! !\\n\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'avi 9/17/2005 01:10'!\\ndefaultMetaNode\\n\\tself subclassResponsibility! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 12/6/2004 23:20'!\\ndefaultRootNode\\n\\tself subclassResponsibility! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 8/31/2004 11:10'!\\ndefinitionPanel\\n\\t^ OBDefinitionPanel new! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 8/31/2004 11:01'!\\nmaxPanes\\n\\t^ self paneCount! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 8/31/2004 11:00'!\\nminPanes\\n\\t^ self paneCount! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 12/5/2004 16:55'!\\nnavigationPanel\\n\\t^ OBColumnPanel minPanes: self minPanes maxPanes: self maxPanes! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 11/26/2004 22:27'!\\noptionalButtonPanel\\n\\t| labels panel |\\n\\tlabels _ self optionalButtons.\\n\\t(Preferences optionalButtons and: [labels isEmpty not]) ifTrue: \\n\\t\\t[panel _ OBFixedButtonPanel new.\\n\\t\\tlabels do: [:ea | panel addButtonWithLabel: ea]].\\n\\t^ panel! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 8/31/2004 11:07'!\\noptionalButtons\\n\\t^ #()! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 8/31/2004 11:01'!\\npaneCount\\n\\t^ 4! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 12/5/2004 15:06'!\\npanels\\n\\t^ {self navigationPanel. self optionalButtonPanel. self definitionPanel} \\n\\t\\treject: [:ea | ea isNil]! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 8/31/2004 11:32'!\\ntitle\\n\\t^ 'OmniBrowser'! !\\n\\n!OBBrowser class methodsFor: 'configuration' stamp: 'cwp 8/31/2004 13:02'!\\ntitleForRoot: aNode\\n\\t^ self title! !\\n\\n\\n!OBBrowser class methodsFor: 'instance creation' stamp: 'cwp 12/5/2004 18:12'!\\nmetaNode: metaNode node: rootNode \\n\\t^ self metaNode: metaNode root: rootNode selection: nil panels: self panels! !\\n\\n!OBBrowser class methodsFor: 'instance creation' stamp: 'avi 9/17/2005 01:16'!\\nmetaNode: metaNode root: rootNode selection: selectedNode\\n\\t^ self metaNode: metaNode root: rootNode selection: selectedNode panels: self panels! !\\n\\n!OBBrowser class methodsFor: 'instance creation' stamp: 'cwp 12/6/2004 21:59'!\\nmetaNode: metaNode root: rootNode selection: selectedNode panels: panels\\n\\t| browser |\\n\\tbrowser _ self basicNew initialize.\\n\\tpanels do: [:ea | browser addPanel: ea].\\n\\tbrowser setMetaNode: metaNode node: rootNode.\\n\\tselectedNode ifNotNil: [browser jumpTo: selectedNode].\\n\\t^ browser! !\\n\\n!OBBrowser class methodsFor: 'instance creation' stamp: 'avi 9/16/2005 23:25'!\\nnew\\n\\t^ self \\n\\t\\tmetaNode: self defaultMetaNode\\n\\t\\troot: self defaultRootNode\\n\\t\\tselection: nil\\n\\t\\tpanels: self panels! !\\n\\n!OBBrowser class methodsFor: 'instance creation' stamp: 'cwp 12/5/2004 15:26'!\\nroot: aNode \\n\\t^ self root: aNode selection: nil! !\\n\\n!OBBrowser class methodsFor: 'instance creation' stamp: 'avi 9/16/2005 23:25'!\\nroot: rootNode selection: selectedNode\\n\\t^ self metaNode: self defaultMetaNode root: rootNode selection: selectedNode panels: self panels! !\\n\\n!OBBrowser class methodsFor: 'instance creation' stamp: 'cwp 12/6/2004 22:04'!\\nselection: selectedNode\\n\\t^ self root: self defaultRootNode selection: selectedNode! !\\n\\nObject subclass: #OBButtonModel\\n\\tinstanceVariableNames: 'bar label'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Morphic'!\\n!OBButtonModel commentStamp: 'cwp 3/5/2004 12:15' prior: 0!\\nAn OBButtonModel serves as a model for PluggableButtonMorphs used OBRadioButtonBar. OBRadioButtonBar cannot be a direct model for its PBMs, since it can contain a variable number of buttons.\\n\\niVars:\\n\\nbar\\t\\t- the OBRadioButton bar to which this button belongs\\nlabel\\t- the label of the button!\\n\\n\\n!OBButtonModel methodsFor: 'accessing' stamp: 'cwp 2/24/2004 18:29'!\\nbar: aRadioButtonBar\\n\\tbar _ aRadioButtonBar! !\\n\\n!OBButtonModel methodsFor: 'accessing' stamp: 'cwp 3/2/2004 21:46'!\\nlabel\\n\\t^ label! !\\n\\n!OBButtonModel methodsFor: 'accessing' stamp: 'cwp 2/24/2004 18:29'!\\nlabel: aString\\n\\tlabel _ aString! !\\n\\n!OBButtonModel methodsFor: 'accessing' stamp: 'cwp 11/27/2004 00:50'!\\nselectionChanged\\n\\tself changed: #isSelected.\\n\\tself changed: #labelMorph! !\\n\\n\\n!OBButtonModel methodsFor: 'callbacks' stamp: 'cwp 2/24/2004 18:42'!\\nisSelected\\n\\t^ bar isSelected: self! !\\n\\n!OBButtonModel methodsFor: 'callbacks' stamp: 'cwp 2/28/2006 10:45'!\\nlabelMorph\\n\\t^ (StringMorph \\n\\t\\tcontents: self label \\n\\t\\tfont: TextStyle defaultFont)\\n\\t\\t\\tcolor: (self isEnabled ifTrue: [Color black] ifFalse: [Color gray]);\\n\\t\\t\\tyourself! !\\n\\n!OBButtonModel methodsFor: 'callbacks' stamp: 'cwp 2/24/2004 19:30'!\\npush\\n\\tbar push: self.! !\\n\\n\\n!OBButtonModel methodsFor: 'morphs' stamp: 'lr 3/23/2006 18:08'!\\nmorph\\n\\t| morph |\\n\\tmorph := PluggableButtonMorph\\n\\t\\ton: self\\n\\t\\tgetState: #isSelected\\n\\t\\taction: #push\\n\\t\\tlabel: #labelMorph.\\n\\tmorph \\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #spaceFill.\\n\\t^ morph! !\\n\\n\\n!OBButtonModel methodsFor: 'testing' stamp: 'cwp 11/27/2004 19:09'!\\nisEnabled\\n\\t^ bar isEnabled: self! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBButtonModel class\\n\\tinstanceVariableNames: ''!\\n\\n!OBButtonModel class methodsFor: 'as yet unclassified' stamp: 'cwp 8/29/2004 13:31'!\\noffColor\\n\\t^ Color lightGray twiceLighter! !\\n\\n!OBButtonModel class methodsFor: 'as yet unclassified' stamp: 'cwp 8/29/2004 13:30'!\\nonColor\\n\\t^ Color lightGray lighter! !\\n\\n!OBButtonModel class methodsFor: 'as yet unclassified' stamp: 'cwp 2/24/2004 18:35'!\\nwithLabel: aString inBar: aRadioButtonBar\\n\\t^ self new label: aString; bar: aRadioButtonBar! !\\nOBActor subclass: #OBCategoryActor\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Services'!\\n!OBCategoryActor commentStamp: 'cwp 1/7/2005 23:43' prior: 0!\\nOBCategory actor implements a number of actions useful for manipulating both class and method categories.!\\n\\n\\n!OBCategoryActor methodsFor: 'public' stamp: 'cwp 7/10/2006 21:33'!\\nactionsForNode: aNode\\n\\t^ Array\\n\\t\\twith: (OBAction\\n\\t\\t\\t\\tlabel: 'remove'\\n\\t\\t\\t\\treceiver: self\\n\\t\\t\\t\\tselector: #remove:\\n\\t\\t\\t\\targuments: {aNode}\\n\\t\\t\\t\\tkeystroke: $x\\n\\t\\t\\t\\ticon: self deleteIcon)\\n\\t\\twith: (OBAction\\n\\t\\t\\t\\tlabel: 'rename...'\\n\\t\\t\\t\\treceiver: self\\n\\t\\t\\t\\tselector: #rename:\\n\\t\\t\\t\\targuments: {aNode})! !\\n\\n!OBCategoryActor methodsFor: 'public' stamp: 'cwp 1/9/2005 11:30'!\\nactionsForParent: aNode\\n\\t| actions |\\n\\tactions _ self stdActionsForParent: aNode.\\n\\taNode organization \\n\\t\\t\\tisClassOrganizer ifTrue: [actions _ actions copyWith: (self categorizeActionFor: aNode)].\\n\\t^ actions! !\\n\\n\\n!OBCategoryActor methodsFor: 'actions' stamp: 'cwp 9/18/2005 19:20'!\\nalphabetizeCategoriesIn: aNode \\n\\taNode organization sortCategories.\\n\\taNode signalChildrenChanged! !\\n\\n!OBCategoryActor methodsFor: 'actions' stamp: 'cwp 9/18/2004 22:53'!\\ncategorizeIn: aClassOrganizer \\n\\t\\\"Categorize methods by looking in parent classes for a method category.\\\"\\n\\t| organizers |\\n\\torganizers := aClassOrganizer subject withAllSuperclasses collect: [:ea | ea organization].\\n\\t(aClassOrganizer listAtCategoryNamed: ClassOrganizer default) do: [:sel | | found |\\n\\t\\tfound := (organizers collect: [ :org | org categoryOfElement: sel])\\n\\t\\t\\tdetect: [:ea | ea ~= ClassOrganizer default and: [ ea ~= nil]]\\n\\t\\t\\tifNone: [].\\n\\t\\tfound ifNotNil: [aClassOrganizer classify: sel under: found]]! !\\n\\n!OBCategoryActor methodsFor: 'actions' stamp: 'cwp 9/20/2005 08:40'!\\ncreateIn: aNode\\n\\t| catName organization |\\n\\torganization := aNode organization.\\n\\tcatName := OBTextRequest \\n\\t\\t\\t\\t\\tprompt: 'Please type new category name' \\n\\t\\t\\t\\t\\ttemplate: (self categoryTemplateFor: organization).\\n\\tcatName ifNotNil:\\t[organization addCategory: catName.\\n\\t\\t\\t\\t\\t\\t(aNode categoryNodeNamed: catName) signalSelection].! !\\n\\n!OBCategoryActor methodsFor: 'actions' stamp: 'cwp 9/18/2004 21:55'!\\nremoveEmptyCategoriesIn: anOrganizer \\n\\tanOrganizer removeEmptyCategories! !\\n\\n!OBCategoryActor methodsFor: 'actions' stamp: 'cwp 9/19/2004 00:11'!\\nremove: aNode\\n\\t| list choice |\\n\\tlist := aNode container organization listAtCategoryNamed: aNode name.\\n\\tlist isEmpty ifTrue: [^ aNode remove].\\n\\tchoice := OBConfirmationRequest prompt: 'Are you sure you want to\\nremove this category \\nand all its elements?' confirm: 'Remove'.\\n\\tchoice ifTrue: [^ aNode remove]! !\\n\\n!OBCategoryActor methodsFor: 'actions' stamp: 'cwp 9/18/2005 18:51'!\\nrename: aNode\\n\\t| category |\\n\\tcategory := OBTextRequest\\n\\t\\t\\t\\tprompt: 'Please type new category name' \\n\\t\\t\\t\\ttemplate: aNode name.\\n\\tcategory ifNotNil:\\t\\n\\t\\t[aNode container organization renameCategory: aNode name toBe: category.\\n\\t\\taNode signalChanged]! !\\n\\n!OBCategoryActor methodsFor: 'actions' stamp: 'cwp 6/4/2006 18:56'!\\nreorganizeCategoriesIn: anOrganizer\\n\\t| definition |\\n\\tdefinition _ OBOrganizationDefinition on: anOrganizer.\\n\\tdefinition signalChange.! !\\n\\n\\n!OBCategoryActor methodsFor: 'private' stamp: 'cwp 9/18/2004 23:52'!\\ncategorizeActionFor: aNode\\n\\t^ OBAction\\n\\t\\tlabel: 'categorize automatically'\\n\\t\\treceiver: self\\n\\t\\tselector: #categorizeIn:\\n\\t\\targuments: (Array with: aNode organization)! !\\n\\n!OBCategoryActor methodsFor: 'private' stamp: 'cwp 6/25/2006 17:36'!\\ncategoryTemplateFor: anOrganization\\n\\t^ anOrganization isClassOrganizer\\n\\t\\tifTrue: ['category name']\\n\\t\\tifFalse: ['Category-Name']! !\\n\\n!OBCategoryActor methodsFor: 'private' stamp: 'cwp 7/10/2006 21:49'!\\nstdActionsForParent: aNode\\n\\t^ Array\\n\\t\\twith: (OBAction \\n\\t\\t\\t\\tlabel: 'create category...'\\n\\t\\t\\t\\treceiver: self\\n\\t\\t\\t\\tselector: #createIn:\\n\\t\\t\\t\\targuments: (Array with: aNode)\\n\\t\\t\\t\\ticon: self newIcon)\\n\\t\\twith: (OBAction\\n\\t\\t\\t\\tlabel: 'alphabetize categories'\\n\\t\\t\\t\\treceiver: self\\n\\t\\t\\t\\tselector: #alphabetizeCategoriesIn:\\n\\t\\t\\t\\targuments: (Array with: aNode))\\n\\t\\twith: (OBAction\\n\\t\\t\\t\\tlabel: 'remove empty categories'\\n\\t\\t\\t\\treceiver: self\\n\\t\\t\\t\\tselector: #removeEmptyCategoriesIn:\\n\\t\\t\\t\\targuments: (Array with: aNode organization))\\n\\t\\twith: (OBAction\\n\\t\\t\\t\\tlabel: 'reorganize categories'\\n\\t\\t\\t\\treceiver: self\\n\\t\\t\\t\\tselector: #reorganizeCategoriesIn:\\n\\t\\t\\t\\targuments: (Array with: aNode organization))\\n! !\\nObject subclass: #OBCategoryServant\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Services'!\\n\\n!OBCategoryServant methodsFor: 'private' stamp: 'cwp 6/25/2006 17:32'!\\ncategoryTemplateFor: anOrganization\\n\\t^ anOrganization isClassOrganizer\\n\\t\\tifTrue: ['category name']\\n\\t\\tifFalse: ['Category-Name']! !\\n\\n\\n!OBCategoryServant methodsFor: 'actions' stamp: 'cwp 6/29/2006 00:13'!\\ncreateCategory: aRequestor\\n\\t| catName organization node |\\n\\tnode _ aRequestor requestCurrentNode.\\n\\torganization _ node organization.\\n\\tcatName _ OBTextRequest \\n\\t\\t\\t\\t\\tprompt: 'Please type new category name' \\n\\t\\t\\t\\t\\ttemplate: (self categoryTemplateFor: organization).\\n\\tcatName ifNotNil:\\t[organization addCategory: catName.\\n\\t\\t\\t\\t\\t\\taRequestor select: (node categoryNodeNamed: catName)].! !\\n\\n\\n!OBCategoryServant methodsFor: 'accessing' stamp: 'cwp 6/25/2006 17:25'!\\nservices\\n\\t| selectors |\\n\\tselectors _ self class organization listAtCategoryNamed: 'services'.\\n\\t^ selectors collect: [:ea | self perform: ea].\\n\\t! !\\n\\n\\n!OBCategoryServant methodsFor: 'services' stamp: 'cwp 6/30/2006 00:51'!\\nsvcCreateCategory\\n\\t^ (OBService action: (MessageSend receiver: self selector: #createCategory:))\\n\\t\\tcondition: [:req | req requestNode hasOrganization];\\n\\t\\tlabel: 'create category...'! !\\nOBAnnouncement subclass: #OBChildrenChanged\\n\\tinstanceVariableNames: 'node'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBChildrenChanged methodsFor: 'as yet unclassified' stamp: 'cwp 6/5/2006 00:49'!\\nnode\\n\\t^ node! !\\n\\n!OBChildrenChanged methodsFor: 'as yet unclassified' stamp: 'cwp 6/5/2006 00:49'!\\nnode: aNode\\n\\tnode _ aNode! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBChildrenChanged class\\n\\tinstanceVariableNames: ''!\\n\\n!OBChildrenChanged class methodsFor: 'as yet unclassified' stamp: 'cwp 6/5/2006 00:49'!\\nnode: aNode\\n\\t^ self new node: aNode! !\\nOBInteractionRequest subclass: #OBChoiceRequest\\n\\tinstanceVariableNames: 'prompt labels values lines'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Notifications'!\\n!OBChoiceRequest commentStamp: 'cwp 3/5/2004 12:26' prior: 0!\\nThis notification is used to ask the user for to choose from a list of alternatives. Its defaultAction is to open a PopUpMenu. Test cases an intercept the notification and respond programmatically.\\n\\nprompt\\t- A string describing the choice the user is asked to make.\\nlabels\\t- A list of strings describing the alternatives.\\nvalues\\t- When the user chooses an alternative, the corresponding item from this list is returned!\\n\\n\\n!OBChoiceRequest methodsFor: 'initializing' stamp: 'cwp 7/9/2006 00:05'!\\nsetPrompt: aString labels: labelArray values: valueArray lines: lineArray\\n\\tprompt _ aString.\\n\\tlabels _ labelArray.\\n\\tvalues _ valueArray.\\n\\tlines _ lineArray.! !\\n\\n\\n!OBChoiceRequest methodsFor: 'signaling' stamp: 'cwp 7/9/2006 00:09'!\\ndefaultAction\\n\\t^ values \\n\\t\\tat: ((PopUpMenu labelArray: labels lines: lines) startUpWithCaption: prompt)\\n\\t\\tifAbsent: [nil]! !\\n\\n\\n!OBChoiceRequest methodsFor: 'accessing' stamp: 'cwp 7/8/2006 23:45'!\\nlabels\\n\\t^ labels! !\\n\\n!OBChoiceRequest methodsFor: 'accessing' stamp: 'cwp 7/9/2006 00:11'!\\nlines\\n\\t^ lines! !\\n\\n!OBChoiceRequest methodsFor: 'accessing' stamp: 'cwp 7/8/2006 23:45'!\\nprompt\\n\\t^ prompt! !\\n\\n!OBChoiceRequest methodsFor: 'accessing' stamp: 'cwp 7/8/2006 23:45'!\\nvalues\\n\\t^ values! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBChoiceRequest class\\n\\tinstanceVariableNames: ''!\\n\\n!OBChoiceRequest class methodsFor: 'signalling' stamp: 'cwp 7/9/2006 00:07'!\\nlabels: anArray\\n\\t^ self\\n\\t\\tprompt: nil\\n\\t\\tlabels: anArray\\n\\t\\tvalues: anArray\\n\\t\\tlines: #()! !\\n\\n!OBChoiceRequest class methodsFor: 'signalling' stamp: 'cwp 7/9/2006 00:08'!\\nlabels: labelArray lines: lineArray\\n\\t^ self\\n\\t\\tprompt: nil\\n\\t\\tlabels: labelArray\\n\\t\\tvalues: labelArray\\n\\t\\tlines: lineArray! !\\n\\n!OBChoiceRequest class methodsFor: 'signalling' stamp: 'cwp 7/9/2006 00:06'!\\nprompt: aString labels: labelArray values: valueArray\\n\\t^ self\\n\\t\\tprompt: aString\\n\\t\\tlabels: labelArray\\n\\t\\t values: valueArray\\n\\t\\tlines: #()! !\\n\\n!OBChoiceRequest class methodsFor: 'signalling' stamp: 'cwp 7/9/2006 00:05'!\\nprompt: aString labels: labelArray values: valueArray lines: lineArray\\n\\t^ (self new \\n\\t\\tsetPrompt: aString \\n\\t\\tlabels: labelArray \\n\\t\\tvalues: valueArray \\n\\t\\tlines: lineArray) \\n\\t\\t\\tsignal! !\\nOBActor subclass: #OBClassActor\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Services'!\\n!OBClassActor commentStamp: 'cwp 1/7/2005 23:44' prior: 0!\\nOBClassActor provides basic actions for manipulating classes.!\\n\\n\\n!OBClassActor methodsFor: 'querying' stamp: 'cwp 7/10/2006 22:35'!\\nactionsForNode: aClassNode\\n\\t^ {OBAction\\n\\t\\t\\tlabel: 'remove' \\n\\t\\t\\treceiver: self\\n\\t\\t\\tselector: #remove:\\n\\t\\t\\targuments: {aClassNode}\\n\\t\\t\\tkeystroke: $x \\n\\t\\t\\ticon: self deleteIcon.\\n\\t\\tOBAction\\n\\t\\t\\tlabel: 'rename...' \\n\\t\\t\\treceiver: self\\n\\t\\t\\tselector: #rename:\\n\\t\\t\\targuments: {aClassNode}.\\n\\t\\tOBAction\\n\\t\\t\\tlabel: 'copy...' \\n\\t\\t\\treceiver: self\\n\\t\\t\\tselector: #copy:\\n\\t\\t\\targuments: {aClassNode}.\\n\\t\\tOBAction\\n\\t\\t\\tlabel: 'subclass template'\\n\\t\\t\\treceiver: self\\n\\t\\t\\tselector: #subclassTemplate:\\n\\t\\t\\targuments: {aClassNode}.\\n\\t\\tOBAction\\n\\t\\t\\tlabel: 'browse references'\\n\\t\\t\\treceiver: self\\n\\t\\t\\tselector: #browseReferences:\\n\\t\\t\\targuments: {aClassNode}\\n\\t}! !\\n\\n\\n!OBClassActor methodsFor: 'private' stamp: 'lr 3/28/2006 12:05'!\\nbrowseObsoleteRefs: aClassNode as: oldName \\n\\t| binding |\\n\\tbinding := aClassNode theNonMetaClass environment \\n\\t\\t\\t\\tassociationAt: aClassNode theNonMetaClass name.\\n\\t(SystemNavigation default allCallsOn: binding) isEmpty \\n\\t\\tifFalse: [OBReferencesBrowser\\n\\t\\t\\t\\t\\tbrowseRoot: aClassNode\\n\\t\\t\\t\\t\\ttitle: 'Obsolete references to']! !\\n\\n!OBClassActor methodsFor: 'private' stamp: 'cwp 7/8/2006 13:59'!\\ncopyClass: oldClass as: newName\\n\\t| oldDefinition newDefinition newClass |\\n\\t(oldClass environment hasClassNamed: newName)\\n\\t\\tifTrue: [^self error: newName, ' already exists'].\\n\\toldDefinition := oldClass definition.\\n\\tnewDefinition := oldDefinition \\n\\t\\t\\t\\t\\t\\tcopyReplaceAll: '#' , oldClass name asString \\n\\t\\t\\t\\t\\t\\twith: '#' , newName asString.\\n\\tCursor wait \\n\\t\\tshowWhile: [newClass := Compiler evaluate: newDefinition logged: true.\\n\\t\\t\\t\\t\\tnewClass copyAllCategoriesFrom: oldClass.\\n\\t\\t\\t\\t\\tnewClass class copyAllCategoriesFrom: oldClass class].\\n\\t^ newClass! !\\n\\n\\n!OBClassActor methodsFor: 'actions' stamp: 'lr 3/28/2006 12:10'!\\nbrowseReferences: aClassNode \\n\\tOBReferencesBrowser browseRoot: aClassNode theNonMetaClass asNode! !\\n\\n!OBClassActor methodsFor: 'actions' stamp: 'dvf 8/31/2005 13:11'!\\ncopy: aClassNode\\n\\t| newName newClass |\\n\\tnewName := OBTextRequest\\n\\t\\t\\tprompt: 'Please type new class name'\\n\\t\\t\\ttemplate: aClassNode theNonMetaClassName asString.\\n\\tnewName ifNotNil:\\t[newClass := self\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcopyClass: aClassNode theNonMetaClass \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tas: newName asSymbol.\\n\\t\\t\\t\\t\\t\\t(newClass asNode) signalSelection].! !\\n\\n!OBClassActor methodsFor: 'actions' stamp: 'lr 3/28/2006 12:04'!\\nremove: aClassNode\\n\\t(OBConfirmationRequest\\n\\t\\tprompt: 'Are you certain that you \\nwant to REMOVE the class ', aClassNode theNonMetaClassName, ' from the system?'\\n\\t\\tconfirm: 'Remove')\\n\\t\\t\\tifTrue: [aClassNode theNonMetaClass removeFromSystem.\\n\\t\\t\\t\\t\\taClassNode signalDeletion]! !\\n\\n!OBClassActor methodsFor: 'actions' stamp: 'lr 3/28/2006 12:05'!\\nrename: aClassNode\\n\\t| newName |\\n\\tnewName := OBTextRequest\\n\\t\\t\\t\\t\\tprompt: 'Please type new class name' \\n\\t\\t\\t\\t\\ttemplate: aClassNode theNonMetaClassName asString.\\n\\tnewName ifNotNil:\\t[ | oldName |\\n\\t\\t\\t\\t\\t\\toldName := aClassNode theNonMetaClass name.\\n\\t\\t\\t\\t\\t\\taClassNode theNonMetaClass environment \\n\\t\\t\\t\\t\\t\\t\\trenameClassNamed: oldName\\n\\t\\t\\t\\t\\t\\t\\tas: newName asSymbol.\\n\\t\\t\\t\\t\\t\\tself browseObsoleteRefs: aClassNode as: oldName].\\n\\t! !\\n\\n!OBClassActor methodsFor: 'actions' stamp: 'cwp 6/4/2006 18:53'!\\nsubclassTemplate: aClassNode \\n\\t| class definition |\\n\\tclass _ aClassNode theNonMetaClass.\\n\\tdefinition _ (OBClassDefinition \\n\\t\\t\\t\\t\\tenvironment: class environment \\n\\t\\t\\t\\t\\ttemplate: (Class \\n\\t\\t\\t\\t\\t\\t\\t\\ttemplateForSubclassOf: class \\n\\t\\t\\t\\t\\t\\t\\t\\tcategory: class category)).\\n\\tdefinition signalChange.! !\\nOBCodeNode subclass: #OBClassAwareNode\\n\\tinstanceVariableNames: 'theClass superior'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBClassAwareNode commentStamp: 'cwp 1/8/2005 11:23' prior: 0!\\nOBClassAware node models program elements that are part of a class. It provides methods for manipulating the class, as well as methods relating to sorting according to class hierarchy.\\n\\niVars\\n\\ntheClass \\t- the class that this node is part of\\nsuperior \\t- during hierarchical sorting this refers to the nearest superclass\\n\\t\\t\\t that belongs to the group being sorted!\\n\\n\\n!OBClassAwareNode methodsFor: 'superiors' stamp: 'cwp 12/11/2004 22:04'!\\nadoptSuperior: other \\n\\t| descent |\\n\\tdescent := self theClass allSuperclasses reversed.\\n\\t(descent indexOf: other theClass) > (descent indexOf: self superiorClass) \\n\\t\\tifTrue: [superior := other]! !\\n\\n!OBClassAwareNode methodsFor: 'superiors' stamp: 'cwp 12/11/2004 22:04'!\\nsortsBefore: aClassNode\\n\\t| own other |\\n\\town := self withSuperiors.\\n\\tother := aClassNode withSuperiors.\\n\\t1 \\tto: (own size min: other size)\\n\\t\\tdo: [:i | (own at: i) == (other at: i) ifFalse: \\n\\t\\t\\t\\t[^ (own at: i) theClassName <= (other at: i) theClassName]].\\n\\t^ other includes: self\\n\\t! !\\n\\n!OBClassAwareNode methodsFor: 'superiors' stamp: 'cwp 12/11/2004 22:03'!\\nsuperior\\n\\t^ superior! !\\n\\n!OBClassAwareNode methodsFor: 'superiors' stamp: 'cwp 12/11/2004 22:03'!\\nsuperiorClass\\n\\t^superior ifNotNil: [superior theClass]! !\\n\\n!OBClassAwareNode methodsFor: 'superiors' stamp: 'cwp 12/11/2004 22:03'!\\nsuperiors\\n\\t| result |\\n\\tresult := OrderedCollection new.\\n\\tself superiorsDo: [:ea | result add: ea].\\n\\t^ result asArray reversed! !\\n\\n!OBClassAwareNode methodsFor: 'superiors' stamp: 'cwp 12/11/2004 22:03'!\\nsuperiorsDo: aBlock\\n\\t| cursor |\\n\\tcursor := superior.\\n\\t[cursor isNil] whileFalse:\\n\\t\\t[aBlock value: cursor.\\n\\t\\tcursor := cursor superior]! !\\n\\n!OBClassAwareNode methodsFor: 'superiors' stamp: 'dvf 8/16/2005 17:23'!\\nsuperior: other \\n\\tsuperior := other! !\\n\\n!OBClassAwareNode methodsFor: 'superiors' stamp: 'cwp 12/11/2004 22:03'!\\nwithSuperiors\\n\\t| result |\\n\\tresult := OrderedCollection new.\\n\\tresult add: self.\\n\\tself superiorsDo: [:ea | result add: ea].\\n\\t^ result asArray reversed! !\\n\\n\\n!OBClassAwareNode methodsFor: 'actions' stamp: 'lr 3/6/2006 19:24'!\\nbrowse\\n\\tOBSystemBrowser openOnClass: self theNonMetaClass! !\\n\\n!OBClassAwareNode methodsFor: 'actions' stamp: 'lr 3/6/2006 19:22'!\\nbrowseHierarchically\\n\\tOBHierarchyBrowser openOnClass: self theNonMetaClass! !\\n\\n!OBClassAwareNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 23:10'!\\nbrowseHierarchyAction\\n\\t^ self \\n\\t\\taction: #browseHierarchically \\n\\t\\tbuttonLabel: 'hierarchy' \\n\\t\\tmenuLabel: 'browse hierarchy'.\\n! !\\n\\n!OBClassAwareNode methodsFor: 'actions' stamp: 'avi 9/17/2005 01:34'!\\nchaseVars\\n\\tOBVariablesBrowser browseRoot: self classNode! !\\n\\n\\n!OBClassAwareNode methodsFor: 'nodes' stamp: 'dvf 8/31/2005 13:11'!\\nclassNode\\n\\t^self theClass asNode! !\\n\\n\\n!OBClassAwareNode methodsFor: 'displaying' stamp: 'dvf 8/17/2005 14:59'!\\nindent\\n\\t| size indent |\\n\\tsize := 0.\\n\\tself superiorsDo: [:ea | size := size + 1].\\n\\tindent := Text new: size * 2.\\n\\tindent atAllPut: $ .\\n\\t^ indent! !\\n\\n!OBClassAwareNode methodsFor: 'displaying' stamp: 'cwp 1/7/2005 22:21'!\\nindentedName\\n\\t^ self indent, self name! !\\n\\n\\n!OBClassAwareNode methodsFor: 'ancestry' stamp: 'cwp 12/5/2004 12:56'!\\nisDescendantOfClassCat: aClassCategoryNode\\n\\n\\t\\\"optimized version: sending #category to the class is slow\\\"\\n\\t^ (self theNonMetaClass environment organization \\n\\t\\tlistAtCategoryNamed: aClassCategoryNode name)\\n\\t\\t\\tincludes: self theNonMetaClassName\\n\\n! !\\n\\n!OBClassAwareNode methodsFor: 'ancestry'!\\nisDescendantOfClass: aClassNode\\n\\t^ self theClassName = aClassNode theClassName! !\\n\\n\\n!OBClassAwareNode methodsFor: 'accessing'!\\ntheClass\\n\\t^ theClass! !\\n\\n!OBClassAwareNode methodsFor: 'accessing'!\\ntheClassName\\n\\t^ self theClass name! !\\n\\n!OBClassAwareNode methodsFor: 'accessing'!\\ntheClass: aClass\\n\\ttheClass := aClass! !\\n\\n!OBClassAwareNode methodsFor: 'accessing'!\\ntheMetaClass\\n\\t^ self theClass theMetaClass! !\\n\\n!OBClassAwareNode methodsFor: 'accessing'!\\ntheNonMetaClass\\n\\t^ self theClass theNonMetaClass! !\\n\\n!OBClassAwareNode methodsFor: 'accessing'!\\ntheNonMetaClassName\\n\\t^ self theNonMetaClass name! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBClassAwareNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBClassAwareNode class methodsFor: 'sorting' stamp: 'cwp 12/12/2004 22:13'!\\nsortHierarchically: nodes\\n\\tnodes do: [:a | nodes do: [:b | a adoptSuperior: b]].\\n\\tnodes sort: [:a : b | a sortsBefore: b].\\n\\t^ nodes! !\\nOBCodeNode subclass: #OBClassCategoryNode\\n\\tinstanceVariableNames: 'environment name'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBClassCategoryNode commentStamp: 'cwp 1/8/2005 12:58' prior: 0!\\nOBClassCategory represents a system category in the image's SystemOrganization.!\\n\\n\\n!OBClassCategoryNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 22:40'!\\nactions\\n\\t^ {\\n\\t\\tself action: #fileOut withLabel: 'file out'.\\n\\t\\tself browseAction.\\n\\t}\\n! !\\n\\n!OBClassCategoryNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 21:44'!\\nbrowse\\n\\tOBSystemBrowser openOnEnvironment: environment category: name! !\\n\\n!OBClassCategoryNode methodsFor: 'actions'!\\nfileOut\\n\\tenvironment organization fileOutCategory: name.! !\\n\\n!OBClassCategoryNode methodsFor: 'actions'!\\nprintOut\\n\\tenvironment organization fileOutCategory: name asHtml: true! !\\n\\n!OBClassCategoryNode methodsFor: 'actions' stamp: 'cwp 9/19/2004 00:11'!\\nremove\\n\\tenvironment organization removeSystemCategory: name.\\n\\tself signalDeletion! !\\n\\n\\n!OBClassCategoryNode methodsFor: 'ancestry'!\\nancestrySelector\\n\\t^ #isDescendantOfClassCat:! !\\n\\n!OBClassCategoryNode methodsFor: 'ancestry'!\\nisDescendantOfClassCat: other\\n\\t^ other name = name! !\\n\\n\\n!OBClassCategoryNode methodsFor: 'navigating' stamp: 'dvf 8/15/2005 17:31'!\\nclasses\\n\\t^ self classNames collect: [:ea | (environment at: ea) asNode]! !\\n\\n!OBClassCategoryNode methodsFor: 'navigating' stamp: 'cwp 12/12/2004 22:12'!\\nclassesHierarchically\\n\\t^ OBClassAwareNode sortHierarchically: self classes! !\\n\\n!OBClassCategoryNode methodsFor: 'navigating' stamp: 'dvf 8/17/2005 17:25'!\\ncomments\\n\\t^ self classNames collect: [:ea | (environment at: ea) asCommentNode ]! !\\n\\n!OBClassCategoryNode methodsFor: 'navigating' stamp: 'cwp 12/12/2004 22:19'!\\ncommentsHierarchically\\n\\t^ OBClassAwareNode sortHierarchically: self comments! !\\n\\n!OBClassCategoryNode methodsFor: 'navigating' stamp: 'dvf 8/15/2005 17:52'!\\nmetaclasses\\n\\t^self classNames collect: [:ea | (environment at: ea) asClassSideNode]! !\\n\\n!OBClassCategoryNode methodsFor: 'navigating' stamp: 'cwp 12/12/2004 22:19'!\\nmetaclassesHierarchically\\n\\t^ OBClassAwareNode sortHierarchically: self metaclasses! !\\n\\n\\n!OBClassCategoryNode methodsFor: 'private'!\\nclassNames\\n\\t^ environment organization listAtCategoryNamed: name! !\\n\\n\\n!OBClassCategoryNode methodsFor: 'accessing' stamp: 'cwp 9/22/2004 22:13'!\\ncontainer\\n\\t^ environment! !\\n\\n\\n!OBClassCategoryNode methodsFor: 'displaying'!\\ndefinition\\n\\t^ OBClassDefinition \\n\\t\\tenvironment: environment \\n\\t\\ttemplate: ((environment at: #Class) template: name)! !\\n\\n!OBClassCategoryNode methodsFor: 'displaying'!\\nname\\n\\t^ name! !\\n\\n!OBClassCategoryNode methodsFor: 'displaying'!\\ntext\\n\\t^ 'Object subclass: #NameOfSubclass\\n\\tinstanceVariableNames: ''''\\n\\tclassVariableNames: ''''\\n\\tpoolDictionaries: ''''\\n\\tcategory: ''', self name, ''''! !\\n\\n\\n!OBClassCategoryNode methodsFor: 'drag and drop'!\\ndropSelector\\n\\t^ #dropOnClassCategory:! !\\n\\n\\n!OBClassCategoryNode methodsFor: 'class creation'!\\nisRedefinedBy: definition\\n\\t\\\"No class is selected, so the definition can't be a redefinition.\\\"\\n\\t\\n\\t^ false! !\\n\\n\\n!OBClassCategoryNode methodsFor: 'initializing'!\\nsetName: aString\\n\\tself setName: aString environment: self class environment! !\\n\\n!OBClassCategoryNode methodsFor: 'initializing'!\\nsetName: aString environment: anEnvironment\\n\\tname := aString asSymbol.\\n\\tenvironment := anEnvironment! !\\n\\n\\n!OBClassCategoryNode methodsFor: 'testing' stamp: 'cwp 6/30/2006 00:42'!\\nhasOrganization\\n\\t^ true! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBClassCategoryNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBClassCategoryNode class methodsFor: 'actions'!\\nactionsForParent: aNode\\n\\t^ Array with: (OBAction\\n\\t\\t\\t\\t\\t\\tlabel: 'find class...'\\n\\t\\t\\t\\t\\t\\treceiver: self\\n\\t\\t\\t\\t\\t\\tselector: #findClassIn:\\n\\t\\t\\t\\t\\t\\targuments: (Array with: aNode environment)\\n\\t\\t\\t\\t\\t\\tkeystroke: $f)\\n! !\\n\\n!OBClassCategoryNode class methodsFor: 'actions' stamp: 'dvf 8/31/2005 11:33'!\\nfindClassIn: anEnvironment\\n\\t| pattern class |\\n\\tpattern := OBTextRequest \\n\\t\\t\\t\\t\\tprompt: 'Please type the name or fragment to look for' \\n\\t\\t\\t\\t\\ttemplate: ''.\\n\\tpattern ifNil: [^self].\\n\\tclass := self findClassIn: anEnvironment pattern: pattern.\\n\\tclass ifNotNil: [(class asNode) signalSelection].! !\\n\\n!OBClassCategoryNode class methodsFor: 'actions' stamp: 'cwp 7/14/2006 14:37'!\\nfindClassIn: anEnvironment pattern: pattern\\n\\t| classNames className toMatch potentialClassNames |\\n\\ttoMatch := (pattern copyWithout: $.) asLowercase.\\n\\tpotentialClassNames := (anEnvironment classNames , anEnvironment traitNames) asArray.\\n\\tclassNames := (pattern endsWith: '.')\\n\\t\\t\\t\\t\\tifTrue: [potentialClassNames\\n\\t\\t\\t\\t\\t\\t\\tselect: [:nm | nm asLowercase = toMatch]]\\n\\t\\t\\t\\t\\tifFalse: [potentialClassNames\\n\\t\\t\\t\\t\\t\\t\\tselect: [:n | n includesSubstring: toMatch caseSensitive: false]].\\n\\tclassNames size = 0 ifTrue: [^ nil].\\n\\tclassNames size = 1 ifTrue: [^ anEnvironment at: classNames first asSymbol].\\n\\tclassName := self userSelectionOf: classNames for: toMatch.\\n\\t^ className ifNotNil: [anEnvironment at: className asSymbol]\\n! !\\n\\n!OBClassCategoryNode class methodsFor: 'actions' stamp: 'cwp 7/9/2006 00:10'!\\nuserSelectionOf: classNames for: toMatch \\n\\t| exactMatch labels lines |\\n\\texactMatch := classNames detect: [:ea | ea asLowercase = toMatch] ifNone: [nil].\\n\\texactMatch \\n\\t\\tifNil: [labels _ classNames. lines _ #()]\\n\\t\\tifNotNil: [labels _ classNames copyWithFirst: exactMatch. lines _ #(1)].\\n\\t^ OBChoiceRequest labels: labels lines: lines.! !\\n\\n\\n!OBClassCategoryNode class methodsFor: 'instance creation'!\\non: aString\\n\\t^ self new setName: aString! !\\n\\n!OBClassCategoryNode class methodsFor: 'instance creation'!\\non: aString inEnvironment: anEnvironment\\n\\t^ self new setName: aString environment: anEnvironment! !\\nOBClassAwareNode subclass: #OBClassCommentNode\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBClassCommentNode commentStamp: 'cwp 1/8/2005 11:24' prior: 0!\\nOBClassCommentNode represents the comment attached to a particular class. !\\n\\n\\n!OBClassCommentNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 23:03'!\\nactions\\n\\t^ {\\n\\t\\tself browseAction.\\n\\t\\tself browseHierarchyAction.\\n\\t\\tself action: #chaseVars buttonLabel: 'variables' menuLabel: 'chase variables'\\n\\t}! !\\n\\n\\n!OBClassCommentNode methodsFor: 'public' stamp: 'cwp 12/13/2004 00:51'!\\nname\\n\\t^ self theClass name! !\\n\\n\\n!OBClassCommentNode methodsFor: 'initializing'!\\nsetClass: aClass\\n\\tself theClass: aClass! !\\n\\n\\n!OBClassCommentNode methodsFor: 'definition'!\\ntext\\n\\t^ self theClass comment! !\\n\\n!OBClassCommentNode methodsFor: 'definition'!\\ntext: aText\\n\\tself theClass comment: aText stamp: Utilities changeStamp.\\n\\t^ true! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBClassCommentNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBClassCommentNode class methodsFor: 'as yet unclassified'!\\non: classRef\\n\\t^ self new setClass: classRef! !\\nOBDefinition subclass: #OBClassDefinition\\n\\tinstanceVariableNames: 'environment template'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Definitions'!\\n!OBClassDefinition commentStamp: 'cwp 1/8/2005 13:13' prior: 0!\\nOBClassDefinition presents a textual interface for examining, modifying and creating classes. Given a class, it knows how to display the definition expression that reflects it's current state, and knows how to create or modify a class given a definition expression.\\n\\nOBClassDefinition implements a number of safety checks when defining or redefining classes, to ensure that existing classes are not accidentally overwritten.!\\n\\n\\n!OBClassDefinition methodsFor: 'callbacks'!\\naccept: aText notifying: aController\\n\\t^ self defineClass: aText notifying: aController! !\\n\\n!OBClassDefinition methodsFor: 'callbacks'!\\nselection\\n\\t^ 1 to: 0! !\\n\\n!OBClassDefinition methodsFor: 'callbacks'!\\ntext\\n\\t^ template! !\\n\\n\\n!OBClassDefinition methodsFor: 'confirmation'!\\nconfirmDefinition: definition\\n\\t\\\"Check to make sure the user isn't accidentally over-writing an existing class.\\\"\\n\\t\\n\\t(((self isRedefinition: definition) not) and: [self definedClassExists: definition])\\n\\t\\tifTrue: [^ self confirmRedefinition: definition]\\n\\t\\tifFalse: [^ true]! !\\n\\n!OBClassDefinition methodsFor: 'confirmation'!\\nconfirmRedefinition: definition\\n\\t| newName prompt |\\n\\tnewName := self nameOfClassDefinedBy: definition.\\n\\tprompt := (newName, ' is an existing class in this system.\\nRedefining it might cause serious problems.\\nIs this really what you want to do?') asText.\\n\\t^ OBConfirmationRequest\\n\\t\\tprompt: prompt\\n\\t\\tconfirm: 'Redefine'! !\\n\\n!OBClassDefinition methodsFor: 'confirmation'!\\ndefinedClassExists: definition\\n\\t^ environment hasClassNamed: (self nameOfClassDefinedBy: definition)! !\\n\\n!OBClassDefinition methodsFor: 'confirmation'!\\nisRedefinition: aDefinition\\n\\t^ (self nameOfClassDefinedBy: aDefinition) = (self nameOfClassDefinedBy: template)! !\\n\\n!OBClassDefinition methodsFor: 'confirmation'!\\nnameOfClassDefinedBy: definition\\n\\t^ (Scanner new scanTokens: definition) third! !\\n\\n!OBClassDefinition methodsFor: 'confirmation' stamp: 'cwp 10/18/2004 00:13'!\\nselectedClass\\n\\t^ environment at: (self nameOfClassDefinedBy: template) ifAbsent: [nil]! !\\n\\n\\n!OBClassDefinition methodsFor: 'class definition'!\\ndefineClass: definition notifying: aController\\n\\t| evaluator newClass |\\n\\t(self confirmDefinition: definition) ifFalse: [^ false].\\n\\tevaluator := self evaluatorForDefinition: definition.\\n\\tnewClass := evaluator\\n\\t\\t\\t\\tevaluate: definition\\n\\t\\t\\t\\tnotifying: aController\\n\\t\\t\\t\\tlogged: true.\\n\\tnewClass ifNil: [^ false].\\n\\tself signalSelectionOf: newClass.\\n\\t^ true\\n! !\\n\\n!OBClassDefinition methodsFor: 'class definition'!\\nevaluatorForDefinition: definition\\n\\t| tokens |\\n\\ttokens := Scanner new scanTokens: definition.\\n\\t^ (environment at: tokens first ifAbsent: [nil]) subclassDefinerClass! !\\n\\n!OBClassDefinition methodsFor: 'class definition' stamp: 'cwp 10/23/2005 14:42'!\\nsignalSelectionOf: aClass\\n\\taClass asNode demandSelection! !\\n\\n\\n!OBClassDefinition methodsFor: 'initializing'!\\nsetEnvironment: anEnvironment template: aText\\n\\tenvironment := anEnvironment.\\n\\ttemplate := aText.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBClassDefinition class\\n\\tinstanceVariableNames: ''!\\n\\n!OBClassDefinition class methodsFor: 'instance creation'!\\nenvironment: anEnvironment template: aString \\n\\t^ self new setEnvironment: anEnvironment template: aString! !\\nOBClassAwareNode subclass: #OBClassNode\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBClassNode commentStamp: 'cwp 1/8/2005 11:27' prior: 0!\\nOBClassNode wraps a class for display in various types of code browsers. It provides many navigation methods for the different types of browsers where classes may appear.!\\n\\n\\n!OBClassNode methodsFor: 'actions' stamp: 'cwp 7/10/2006 22:33'!\\nactions\\n\\t^ {\\n\\t\\tself action: #findMethod \\n\\t\\t\\twithLabel: 'find method...' \\n\\t\\t\\twithKeystroke: $f \\n\\t\\t\\twithIcon: (MenuIcons tryIcons: #(findIcon smallFindIcon)).\\n\\t\\tself action: #fileOut withLabel: 'file out'.\\n\\t\\tself browseAction.\\n\\t\\tself browseHierarchyAction.\\n\\t\\tself action: #chaseVars buttonLabel: 'variables' menuLabel: 'chase variables'.\\n\\t\\tself action: #inspectInstances withLabel: 'inspect instances'.\\n\\t\\tself action: #inspectSubInstances withLabel: 'inspect subinstances'\\n\\t}! !\\n\\n!OBClassNode methodsFor: 'actions' stamp: 'cwp 10/26/2004 00:49'!\\nfileOut\\n\\tself theNonMetaClass fileOut! !\\n\\n!OBClassNode methodsFor: 'actions'!\\nfindMethod\\n\\t| selectors selection |\\n\\tselectors := self theClass selectors asSortedArray.\\n\\tselectors isEmpty ifTrue: [^nil].\\n\\tselection := OBChoiceRequest labels: selectors.\\n\\tselection ifNotNil: [(OBMethodNode \\n\\t\\t\\t\\t\\t\\t\\t\\t\\ton: selection\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tinClass: self theClass) signalSelection].! !\\n\\n!OBClassNode methodsFor: 'actions'!\\ninspectInstances\\n\\tself theNonMetaClass inspectAllInstances! !\\n\\n!OBClassNode methodsFor: 'actions'!\\ninspectSubInstances\\n\\tself theNonMetaClass inspectSubInstances! !\\n\\n\\n!OBClassNode methodsFor: 'navigating' stamp: 'cwp 1/7/2005 23:05'!\\nallCategory\\n\\t^ Array with: (OBAllMethodCategoryNode on: self theClass)! !\\n\\n!OBClassNode methodsFor: 'navigating' stamp: 'cwp 1/7/2005 23:06'!\\ncategories\\n\\t^ self theClass organization categories\\n\\t\\tcollect: [:cat | OBMethodCategoryNode on: cat inClass: self theClass]\\n\\t\\t\\t! !\\n\\n!OBClassNode methodsFor: 'navigating' stamp: 'cwp 12/12/2004 23:31'!\\nclassHierarchy\\n\\t^ self nodeHierarchyWithClass: OBClassNode! !\\n\\n!OBClassNode methodsFor: 'navigating'!\\nclassVariables\\n\\t^ self theClass allClassVarNames asArray sort\\n\\t\\tcollect: [:ea | OBClassVariableNode on: ea inClass: self theClass]! !\\n\\n!OBClassNode methodsFor: 'navigating' stamp: 'cwp 12/12/2004 23:31'!\\ncommentHierarchy\\n\\t^ self nodeHierarchyWithClass: OBClassCommentNode! !\\n\\n!OBClassNode methodsFor: 'navigating'!\\ninstanceVariables\\n\\t^ self theClass allInstVarNames asArray sort\\n\\t\\tcollect: [:ea | OBInstanceVariableNode on: ea inClass: self theClass]! !\\n\\n!OBClassNode methodsFor: 'navigating' stamp: 'cwp 12/12/2004 23:30'!\\nmetaclassHierarchy\\n\\t^ self nodeHierarchyWithClass: OBMetaclassNode! !\\n\\n!OBClassNode methodsFor: 'navigating' stamp: 'cwp 12/12/2004 23:30'!\\nnodeHierarchyWithClass: aClass\\n\\t^ OBClassAwareNode sortHierarchically: \\n\\t\\t(self surroundingHierarchy collect: [:ea | aClass on: ea])! !\\n\\n!OBClassNode methodsFor: 'navigating' stamp: 'cwp 12/8/2004 23:45'!\\nusers\\n\\t^ (SystemNavigation default allCallsOn: (theClass environment associationAt: theClass name))\\n\\t\\tcollect: [:ref | OBClassRefNode on: self name inMethod: ref]! !\\n\\n\\n!OBClassNode methodsFor: 'ancestry'!\\nancestrySelector\\n\\t^ #isDescendantOfClass:! !\\n\\n\\n!OBClassNode methodsFor: 'nodes' stamp: 'cwp 9/20/2005 08:42'!\\ncategoryNodeNamed: aString \\n\\t^ OBMethodCategoryNode on: aString inClass: theClass! !\\n\\n!OBClassNode methodsFor: 'nodes'!\\nclassCategoryNode\\n\\t^ OBClassCategoryNode \\n\\t\\ton: self theNonMetaClass category\\n\\t\\tinEnvironment: self theClass environment! !\\n\\n\\n!OBClassNode methodsFor: 'accessing'!\\ndefinition\\n\\t^ OBClassDefinition \\n\\t\\tenvironment: self theClass environment \\n\\t\\ttemplate: self theClass definition! !\\n\\n!OBClassNode methodsFor: 'accessing'!\\norganization\\n\\t^ self theClass organization! !\\n\\n!OBClassNode methodsFor: 'accessing' stamp: 'cwp 12/12/2004 23:27'!\\nsurroundingHierarchy\\n\\t ^ (self theClass withAllSuperclasses union: self theClass allSubclasses)\\n\\t\\tasArray! !\\n\\n!OBClassNode methodsFor: 'accessing' stamp: 'cwp 12/12/2004 22:45'!\\n= other\\n\\tself species = other species ifFalse: [^ false].\\n\\t^ self theClass = other theClass! !\\n\\n\\n!OBClassNode methodsFor: 'drag and drop' stamp: 'lr 3/28/2006 18:29'!\\ndropOnClassCategory: aNode\\n\\tself theNonMetaClass category: aNode name.\\n\\tself signalSelection.\\n\\t^ true! !\\n\\n!OBClassNode methodsFor: 'drag and drop' stamp: 'lr 4/6/2006 11:31'!\\ndropSelector\\n\\t^ #dropOnClass:! !\\n\\n\\n!OBClassNode methodsFor: 'displaying' stamp: 'cwp 12/13/2004 00:51'!\\nname\\n\\t^ self theClass name! !\\n\\n!OBClassNode methodsFor: 'displaying'!\\ntitle\\n\\t^ self name! !\\n\\n\\n!OBClassNode methodsFor: 'printing' stamp: 'cwp 12/10/2004 23:53'!\\nprintOn: aStream\\n\\taStream\\n\\t\\tprint: self class;\\n\\t\\tnextPut: $<;\\n\\t\\tprint: self theClass;\\n\\t\\tnextPut: $>! !\\n\\n\\n!OBClassNode methodsFor: 'initializing'!\\nsetClass: aClass\\n\\tself theClass: aClass! !\\n\\n\\n!OBClassNode methodsFor: 'testing' stamp: 'cwp 6/30/2006 00:57'!\\nhasOrganization\\n\\t^ true! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBClassNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBClassNode class methodsFor: 'instance creation' stamp: 'cwp 11/30/2004 21:06'!\\non: aClass \\n\\t^ self new setClass: aClass ! !\\nOBMethodNode subclass: #OBClassRefNode\\n\\tinstanceVariableNames: 'className'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBClassRefNode commentStamp: 'cwp 1/8/2005 12:38' prior: 0!\\nEach instance of OBClassRefNode refers to a reference to a particular class from the source code of a method. It's used in the OBListBrowser created by the 'browse references' class action.!\\n\\n\\n!OBClassRefNode methodsFor: 'accessing' stamp: 'cwp 12/8/2004 22:14'!\\nname\\n\\t^ className! !\\n\\n!OBClassRefNode methodsFor: 'accessing' stamp: 'cwp 12/1/2004 01:16'!\\nselection\\n\\t| start parser |\\n\\t(parser _ Compiler parserClass new) parseSelector: self source.\\n\\tstart := parser endOfLastToken.\\n\\tstart := (self source asString findString: className startingAt: start).\\n\\t^ start to: start + className size - 1! !\\n\\n\\n!OBClassRefNode methodsFor: 'initialize-release' stamp: 'cwp 12/1/2004 01:10'!\\nsetClassName: theName reference: aMethodRef\\n\\tself setReference: aMethodRef.\\n\\tclassName := theName.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBClassRefNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBClassRefNode class methodsFor: 'as yet unclassified' stamp: 'cwp 12/1/2004 00:50'!\\non: aClassName inMethod: aMethodRef\\n\\t^ self new setClassName: aClassName reference: aMethodRef! !\\nObject subclass: #OBClassReference\\n\\tinstanceVariableNames: 'name isMeta'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Utilities'!\\n!OBClassReference commentStamp: 'cwp 1/8/2005 13:15' prior: 0!\\nOBClassReference provides a way to refer to classes that may or may not be loaded into the image. It refers to the class indirectly, via name, rather than with a direct pointer to the class object. It also provides a number of convenience methods, which makes it more convenient than using the class name directly.!\\n\\n\\n!OBClassReference methodsFor: 'accessing'!\\nbeMeta\\n\\tisMeta := true! !\\n\\n!OBClassReference methodsFor: 'accessing'!\\nbeNonMeta\\n\\tisMeta := false! !\\n\\n!OBClassReference methodsFor: 'accessing'!\\nname\\n\\t^ isMeta\\n\\t\\tifTrue: [name, ' class']\\n\\t\\tifFalse: [name]! !\\n\\n!OBClassReference methodsFor: 'accessing'!\\ntheClass\\n\\t| theClass |\\n\\ttheClass := self theNonMetaClass ifNil: [^ nil].\\n\\t^ isMeta\\n\\t\\tifFalse: [theClass]\\n\\t\\tifTrue: [theClass class]! !\\n\\n!OBClassReference methodsFor: 'accessing'!\\ntheNonMetaClass\\n\\t^ Smalltalk at: name ifAbsent: [].! !\\n\\n!OBClassReference methodsFor: 'accessing'!\\ntheNonMetaName\\n\\t^ name! !\\n\\n!OBClassReference methodsFor: 'accessing'!\\ntheNonMetaName: aSymbol\\n\\tname := aSymbol! !\\n\\n\\n!OBClassReference methodsFor: 'comparing'!\\nhash\\n\\t^ isMeta\\n\\t\\tifTrue: [name hash bitInvert]\\n\\t\\tifFalse: [name hash]! !\\n\\n!OBClassReference methodsFor: 'comparing'!\\n<= other\\n\\t^ self name <= other name! !\\n\\n!OBClassReference methodsFor: 'comparing'!\\n= other\\n\\t^ (other isKindOf: self class) \\n\\t\\tand: [name = other theNonMetaName] \\n\\t\\tand: [isMeta = other isMeta]! !\\n\\n\\n!OBClassReference methodsFor: 'testing'!\\nisMeta\\n\\t^ isMeta! !\\n\\n\\n!OBClassReference methodsFor: 'printing'!\\nprintOn: aStream\\n\\taStream nextPutAll: 'OBClassReference'.\\n\\taStream nextPut: $<.\\n\\taStream nextPutAll: name.\\n\\tisMeta ifTrue: [aStream nextPutAll: ' class'].\\n\\taStream nextPut: $>.! !\\n\\n\\n!OBClassReference methodsFor: 'converting'!\\nreferenceToMethod: aSelector\\n\\t| ref |\\n\\tref := MethodReference new.\\n\\tref setClassSymbol: name classIsMeta: isMeta methodSymbol: aSelector stringVersion: ''.\\n\\t^ ref! !\\n\\n\\n!OBClassReference methodsFor: 'initializing'!\\nsetName: aSymbol\\n\\tname := (aSymbol copyUpTo: $ ) asSymbol.\\n\\tisMeta := aSymbol endsWith: ' class'.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBClassReference class\\n\\tinstanceVariableNames: ''!\\n\\n!OBClassReference class methodsFor: 'instance creation'!\\nmetaNamed: aSymbol\\n\\t^ (self named: aSymbol) beMeta! !\\n\\n!OBClassReference class methodsFor: 'instance creation'!\\nnamed: aSymbol\\n\\t^ self new setName: aSymbol! !\\n\\n!OBClassReference class methodsFor: 'instance creation'!\\nto: aClass\\n\\t^ self named: aClass name! !\\nOBVariableNode subclass: #OBClassVariableNode\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBClassVariableNode commentStamp: 'cwp 1/8/2005 12:51' prior: 0!\\nOBClassVariable provides a method for finding methods which refer to a shared variable, ie, by searching for an association in the literal frame rather than for bytecodes refering to an instance variable.!\\n\\n\\n!OBClassVariableNode methodsFor: 'navigating' stamp: 'cwp 12/8/2004 23:47'!\\naccessors\\n\\t| literal |\\n\\tliteral := (self theClass withAllSuperclasses \\n\\t\\t\\t\\tgather: [:ea | ea classPool associations])\\n\\t\\t\\t\\t\\tdetect: [:ea | ea key = name].\\n\\t^ ((self systemNavigation allCallsOn: literal) asArray sort)\\n\\t\\tcollect: [:ref | OBMethodNode on: ref]! !\\nOBBrowser subclass: #OBCodeBrowser\\n\\tinstanceVariableNames: 'hasChanges'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n!OBCodeBrowser commentStamp: 'cwp 1/7/2005 23:45' prior: 0!\\nOBCodeBrowser is a superclass for all browsers which active code in the image. It provides methods for registering with the SystemChangeNotifier and updating it's display when it receives notification of system changes.!\\n\\n\\n!OBCodeBrowser methodsFor: 'morphic' stamp: 'cwp 1/8/2005 21:55'!\\naddModelItemsToWindowMenu: aMenu\\n\\tSmalltalk \\n\\t\\tat: #SystemBrowser \\n\\t\\tifPresent: [:class | class \\n\\t\\t\\t\\t\\t\\t\\t\\taddRegistryMenuItemsTo: aMenu \\n\\t\\t\\t\\t\\t\\t\\t\\tinAccountOf: OBSystemBrowserAdaptor new].! !\\n\\n!OBCodeBrowser methodsFor: 'morphic'!\\ninitialExtent\\n\\thasChanges := false.\\n\\tself register.\\n\\t^ super initialExtent! !\\n\\n!OBCodeBrowser methodsFor: 'morphic' stamp: 'cwp 6/4/2006 18:51'!\\nstepAt: milliseconds in: aSystemWindow\\n\\thasChanges ifTrue: [self signalRefresh].\\n\\tself clearChanges! !\\n\\n!OBCodeBrowser methodsFor: 'morphic'!\\nwantsStepsIn: aSystemWindow\\n\\t^ true! !\\n\\n!OBCodeBrowser methodsFor: 'morphic'!\\nwindowIsClosing\\n\\tself unregister! !\\n\\n\\n!OBCodeBrowser methodsFor: 'updating' stamp: 'cwp 1/7/2005 23:47'!\\nclearChanges\\n\\thasChanges := false! !\\n\\n!OBCodeBrowser methodsFor: 'updating'!\\nevent: anEvent\\n\\thasChanges := true! !\\n\\n!OBCodeBrowser methodsFor: 'updating' stamp: 'cwp 3/1/2006 19:48'!\\nregister\\n\\tSystemChangeNotifier uniqueInstance notify: self ofAllSystemChangesUsing: #event:! !\\n\\n!OBCodeBrowser methodsFor: 'updating' stamp: 'cwp 3/1/2006 19:48'!\\nunregister\\n\\tSystemChangeNotifier uniqueInstance noMoreNotificationsFor: self! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBCodeBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBCodeBrowser class methodsFor: 'configuration' stamp: 'lr 3/28/2006 12:00'!\\naddTo: root class: classSel comment: commentSel metaclass: metaclassSel \\n\\t| class metaclass comment methodCategory method allMethodCategory |\\n\\tclass := OBMetaNode named: 'Class'.\\n\\tcomment := OBMetaNode named: 'ClassComment'.\\n\\tmetaclass := OBMetaNode named: 'Metaclass'.\\n\\tallMethodCategory := OBMetaNode named: 'AllMethodCategory'.\\n\\tmethodCategory := OBMetaNode named: 'MethodCategory'.\\n\\tmethod := OBMetaNode named: 'Method'.\\n\\troot\\n\\t\\tchildAt: classSel\\n\\t\\t\\tlabeled: 'instance'\\n\\t\\t\\tput: class;\\n\\t\\tchildAt: commentSel\\n\\t\\t\\tlabeled: '?'\\n\\t\\t\\tput: comment;\\n\\t\\tchildAt: metaclassSel\\n\\t\\t\\tlabeled: 'class'\\n\\t\\t\\tput: metaclass;\\n\\t\\taddActor: (OBNodeActor onNodeClass: OBClassCategoryNode);\\n\\t\\taddActor: OBCategoryActor new;\\n\\t\\tfilterClass: OBModalFilter.\\n\\tclass\\n\\t\\tdisplaySelector: #indentedName;\\n\\t\\tchildAt: #allCategory put: allMethodCategory;\\n\\t\\tchildAt: #categories put: methodCategory;\\n\\t\\taddActor: OBNodeActor new;\\n\\t\\taddActor: OBClassActor new.\\n\\tcomment \\n\\t\\tdisplaySelector: #indentedName;\\n\\t\\taddActor: OBNodeActor new.\\n\\tmetaclass\\n\\t\\tdisplaySelector: #indentedName;\\n\\t\\tchildAt: #allCategory put: allMethodCategory;\\n\\t\\tchildAt: #categories put: methodCategory;\\n\\t\\taddActor: OBNodeActor new;\\n\\t\\taddActor: OBClassActor new.\\n\\tallMethodCategory\\n\\t\\tchildAt: #methods put: method;\\n\\t\\taddActor: (OBNodeActor onNodeClass: OBMethodCategoryNode).\\n\\tmethodCategory\\n\\t\\tchildAt: #methods put: method;\\n\\t\\taddActor: OBCategoryActor new;\\n\\t\\taddActor: (OBNodeActor onNodeClass: OBMethodCategoryNode).\\n\\tmethod addActor: OBNodeActor new.\\n\\t^ root! !\\n\\n!OBCodeBrowser class methodsFor: 'configuration' stamp: 'cwp 12/15/2004 22:52'!\\noptionalButtons\\n\\t^ #('browse' 'variables' 'hierarchy' 'inheritance' 'senders' 'implementors' 'versions')! !\\nOBNode subclass: #OBCodeNode\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBCodeNode commentStamp: 'cwp 1/8/2005 11:12' prior: 0!\\nOBCodeNode is an abstract superclass for node classes that represent program elements active in the image. Though it provides little functionality, it exists for structural purposes.!\\n\\n\\n!OBCodeNode methodsFor: 'actions' stamp: 'cwp 7/14/2006 14:24'!\\nbrowseAction\\n\\t^ self \\n\\t\\taction: #browse\\n\\t\\twithMenuLabel: 'browse'\\n\\t\\twithButtonLabel: 'browse'\\n\\t\\twithKeystroke: $b\\n\\t\\twithIcon: (MenuIcons tryIcons: #(windowIcon smallWindowIcon)).\\n! !\\n\\n\\n!OBCodeNode methodsFor: 'testing' stamp: 'cwp 6/30/2006 00:37'!\\nhasOrganization\\n\\t^ false! !\\nOBNode subclass: #OBCollectionNode\\n\\tinstanceVariableNames: 'collection'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Nodes'!\\n!OBCollectionNode commentStamp: 'cwp 1/7/2005 23:31' prior: 0!\\nOBCollectionNode is a trivial wrapper for a collection of nodes. It is typically used as an artificial root node for metagraphs that have no natural root.!\\n\\n\\n!OBCollectionNode methodsFor: 'displaying' stamp: 'cwp 3/15/2004 23:19'!\\nname\\n\\t^ collection species name! !\\n\\n\\n!OBCollectionNode methodsFor: 'initalizing' stamp: 'cwp 3/15/2004 23:18'!\\nsetCollection: aCollection\\n\\tcollection _ aCollection! !\\n\\n\\n!OBCollectionNode methodsFor: 'navigating' stamp: 'cwp 3/15/2004 23:19'!\\nchildren\\n\\t^ collection! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBCollectionNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBCollectionNode class methodsFor: 'as yet unclassified' stamp: 'cwp 3/15/2004 23:17'!\\non: aCollection\\n\\t^ self new setCollection: aCollection! !\\nObject subclass: #OBColumn\\n\\tinstanceVariableNames: 'panel filter children selection'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Kernel'!\\n!OBColumn commentStamp: 'cwp 1/7/2005 23:19' prior: 0!\\nAn OBColumn manages a list of nodes, which it displays in a PluggableListMorph in the pane scroller at the top of the browser. All instances of OBColumn belong to an OBColumnPanel. It's main responsibility is keeping its list - and those of its neighbours - up to date. Each column has a MetaNode, which provides the list contents. It uses a filter to meditate between its self and the MetaNode.\\n\\niVars:\\n\\npanel\\t\\t- the panel which owns the column\\nfilter\\t\\t- the filter which manages the column's MetaNode.\\nparent\\t\\t- the node selected in the column to the left of this column\\nchildren \\t- the nodes which make up this column's list\\nselection \\t- the index of the node selected by the user!\\n\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 4/17/2006 15:52'!\\nannouncer\\n\\t^ panel announcer! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 11/16/2004 21:49'!\\nbasicNext\\n\\t^panel columnAfter: self! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 11/17/2004 00:18'!\\nbrowser\\n\\t^ panel browser! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 2/9/2004 20:58'!\\nfilter\\n\\t^ filter! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 2/12/2004 18:47'!\\nfilter: aFilter\\n\\tfilter _ aFilter monitor: self.\\n\\tself changed: #filter.! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 2/28/2006 08:27'!\\nisEmpty\\n\\t^ children isEmpty! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 2/9/2004 20:59'!\\nmetaNode\\n\\t^ self filter metaNode! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 2/12/2004 20:50'!\\nnext\\n\\t^ self basicNext\\n\\t\\tifNil: [(self hasSelection and: [self shouldBeLast not])\\n\\t\\t\\t\\tifTrue: [self createNext]]\\n\\t! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 9/24/2005 22:45'!\\nparent\\n\\t^ panel parentNodeForColumn: self! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 6/8/2006 01:32'!\\nparent: aNode\\n\\t\\n\\tself filter: aNode metaNode filter.\\n\\tself getChildren.\\n\\tself clearSelection.\\n\\tself changed: #list.\\n\\tpanel clearAfter: self! !\\n\\n!OBColumn methodsFor: 'accessing' stamp: 'cwp 6/28/2006 00:53'!\\nrequestor\\n\\t^ self browser requestor node: (self selectedNode ifNil: [self parent])! !\\n\\n\\n!OBColumn methodsFor: 'actions' stamp: 'cwp 9/24/2005 22:23'!\\nactionSetsForParentNode\\n\\t^ self filter children gather: [:child | child actionSetsForParent: self parent].\\t! !\\n\\n!OBColumn methodsFor: 'actions' stamp: 'cwp 9/14/2004 19:08'!\\nactionSetsForSelectedNode\\n\\t| node |\\n\\tnode _ self selectedNode ifNil: [^ #()].\\n\\t^ node metaNode actionSetsForNode: node\\t! !\\n\\n!OBColumn methodsFor: 'actions' stamp: 'hpt 5/17/2004 14:19'!\\nactionsForKeystroke: aChar\\n\\t^self actionsForParentNode, self actionsForSelectedNode\\n\\t\\tselect: [:anAction | anAction keystroke == aChar]! !\\n\\n!OBColumn methodsFor: 'actions' stamp: 'cwp 9/24/2005 22:23'!\\nactionsForParentNode\\n\\t^ self filter children gather: [:child | child actionsForParent: self parent].\\t! !\\n\\n!OBColumn methodsFor: 'actions' stamp: 'avi 3/6/2004 16:26'!\\nactionsForSelectedNode\\n\\t| node |\\n\\tnode _ self selectedNode ifNil: [^ #()].\\n\\t^ node metaNode actionsForNode: node\\t! !\\n\\n!OBColumn methodsFor: 'actions' stamp: 'cwp 6/25/2006 00:22'!\\naddActionsToMenu: aMenu\\n\\tself actionSetsForParentNode, self actionSetsForSelectedNode\\n\\t\\tdo: \\n\\t\\t\\t[:set \\n\\t\\t\\t|set do: \\n\\t\\t\\t\\t[:action | \\n\\t\\t\\t\\taction announcer: self announcer.\\n\\t\\t\\t\\taction addItemToMenu: aMenu]]\\n\\t\\tseparatedBy: [aMenu addLine]! !\\n\\n!OBColumn methodsFor: 'actions' stamp: 'cwp 6/28/2006 00:24'!\\naddServicesToMenu: aMenu\\n\\t| scan |\\n\\tscan _ self announcer announce: OBServiceScan.\\n\\taMenu \\n\\t\\taddServices: scan services\\n\\t\\tfor: self requestor\\n\\t\\textraLines: #().\\n\\t! !\\n\\n!OBColumn methodsFor: 'actions' stamp: 'cwp 6/25/2006 13:55'!\\nservicesForKeystroke: aChar\\n\\t| scan |\\n\\tscan _ self announcer announce: OBServiceScan.\\n\\t^ scan services select: [:ea | ea keystroke == aChar]! !\\n\\n\\n!OBColumn methodsFor: 'callbacks' stamp: 'cwp 6/28/2006 00:50'!\\nkeystroke: aChar from: aMorph\\n\\tself isEmpty ifTrue: [^ self].\\n\\t(self actionsForKeystroke: aChar)\\n\\t\\tdo: [:action | \\n\\t\\t\\taction announcer: self announcer.\\n\\t\\t\\taction trigger].\\n\\t(self servicesForKeystroke: aChar)\\n\\t\\tdo: [:service | service condExecuteFor: self requestor]! !\\n\\n!OBColumn methodsFor: 'callbacks' stamp: 'cwp 12/8/2004 21:21'!\\nlist\\n\\t^ children \\n\\t\\tifNil: [#()]\\n\\t\\tifNotNil: [children collect: [:ea | ea displayString]]! !\\n\\n!OBColumn methodsFor: 'callbacks' stamp: 'cwp 12/8/2004 21:22'!\\nlistAt: index\\n\\t^ (children at: index ifAbsent: [^ '']) displayString! !\\n\\n!OBColumn methodsFor: 'callbacks' stamp: 'cwp 2/29/2004 21:48'!\\nlistSize\\n\\t^ children\\n\\t\\tifNil: [0]\\n\\t\\tifNotNil: [children size]! !\\n\\n!OBColumn methodsFor: 'callbacks' stamp: 'cwp 6/25/2006 00:24'!\\nmenu: aMenu\\n\\tself isEmpty ifFalse:\\n\\t\\t[self addActionsToMenu: aMenu.\\n\\t\\tself addServicesToMenu: aMenu].\\n\\t^ aMenu! !\\n\\n!OBColumn methodsFor: 'callbacks' stamp: 'cwp 4/18/2006 00:25'!\\nokToChange\\n\\t^ (self announcer announce: OBAboutToChange) isVetoed not! !\\n\\n!OBColumn methodsFor: 'callbacks' stamp: 'cwp 11/5/2003 19:01'!\\nselection\\n\\t^ selection ifNil: [0]! !\\n\\n!OBColumn methodsFor: 'callbacks' stamp: 'cwp 6/5/2006 23:37'!\\nselection: anInteger\\n\\tselection _ anInteger.\\n\\tself signalSelectionChanged.\\n\\tself changed: #selection.\\n! !\\n\\n\\n!OBColumn methodsFor: 'drag and drop' stamp: 'cwp 6/4/2006 00:37'!\\nacceptDroppingMorph: transferMorph event: evt inMorph: listMorph\\n\\t^ [(self nodeForDroppedMorph: transferMorph event: evt inMorph: listMorph)\\n\\t\\tacceptDroppedNode: transferMorph passenger]\\n\\t\\t\\ton: OBAnnouncerRequest\\n\\t\\t\\tdo: [:notification | notification resume: self announcer]\\n! !\\n\\n!OBColumn methodsFor: 'drag and drop' stamp: 'avi 2/20/2004 13:45'!\\ndragEnabled\\n\\t^ true! !\\n\\n!OBColumn methodsFor: 'drag and drop' stamp: 'avi 2/20/2004 14:35'!\\ndragPassengerFor: item inMorph: listMorph\\n\\t^ self nodeForItem: item inMorph: listMorph! !\\n\\n!OBColumn methodsFor: 'drag and drop' stamp: 'avi 2/20/2004 14:37'!\\ndragTransferType\\n\\t^ #OmniBrowser! !\\n\\n!OBColumn methodsFor: 'drag and drop' stamp: 'avi 2/20/2004 14:36'!\\ndragTransferTypeForMorph: listMorph\\n\\t^ self dragTransferType! !\\n\\n!OBColumn methodsFor: 'drag and drop' stamp: 'avi 2/20/2004 14:30'!\\ndropEnabled\\n\\t^ true! !\\n\\n!OBColumn methodsFor: 'drag and drop' stamp: 'cwp 3/3/2004 02:23'!\\nnodeForDroppedMorph: transferMorph event: evt inMorph: pluggableListMorph\\n\\t| index item |\\n\\tindex _ pluggableListMorph rowAtLocation: evt position.\\n\\tindex = 0 ifTrue: [^ nil].\\n\\titem _ pluggableListMorph listMorph item: index.\\n\\t^ self nodeForItem: item inMorph: pluggableListMorph! !\\n\\n!OBColumn methodsFor: 'drag and drop' stamp: 'cwp 6/10/2006 21:59'!\\nnodeForItem: item inMorph: pluggableListMorph\\n\\t^ children \\n\\t\\tdetect: [:child | child displayString = item contents asString]\\n\\t\\tifNone: [item contents]! !\\n\\n!OBColumn methodsFor: 'drag and drop' stamp: 'cwp 2/25/2004 21:26'!\\nwantsDroppedMorph: transferMorph event: evt inMorph: listMorph\\n\\t| node |\\n\\t(transferMorph isKindOf: TransferMorph) ifFalse: [^ false].\\n\\ttransferMorph dragTransferType == self dragTransferType ifFalse: [^ false].\\n\\tnode _ self nodeForDroppedMorph: transferMorph event: evt inMorph: listMorph.\\n\\t^ node notNil and: [node wantsDroppedNode: transferMorph passenger]! !\\n\\n\\n!OBColumn methodsFor: 'initializing' stamp: 'cwp 6/3/2006 23:38'!\\nsetPanel: aPanel \\n\\tpanel := aPanel.\\n\\tself subscribe.\\n\\tchildren := #().\\n\\tself clearSelection! !\\n\\n!OBColumn methodsFor: 'initializing' stamp: 'cwp 6/3/2006 23:39'!\\nsetPanel: aPanel metaNode: aMetaNode node: aNode \\n\\tpanel := aPanel.\\n\\tself subscribe.\\n\\tfilter := aMetaNode filter monitor: self.\\n\\tchildren _ self filter nodesForParent: aNode.\\n\\tself clearSelection! !\\n\\n\\n!OBColumn methodsFor: 'morphic' stamp: 'cwp 12/14/2003 22:15'!\\nbuttonHeight\\n\\t^ 20! !\\n\\n!OBColumn methodsFor: 'morphic' stamp: 'cwp 2/9/2004 21:06'!\\ncolumnWithHeader\\n\\t| col bh |\\n\\tcol _ BorderedMorph new\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\tclipSubmorphs: true;\\n\\t\\tcolor: Color transparent;\\n\\t\\tcellInset: 0;\\n\\t\\tborderWidth: 0;\\n\\t\\tlayoutPolicy: ProportionalLayout new.\\n\\t\\n\\tbh _ self buttonHeight negated.\\n\\tcol\\n\\t\\taddMorph: self listMorph\\n\\t\\tfullFrame: (LayoutFrame fractions: (0@0 corner: 1@1) offsets: (0@0 corner: 0@bh)).\\n\\tcol\\n\\t\\taddMorph: self filter buttonMorph\\n\\t\\tfullFrame: (LayoutFrame fractions: (0@1 corner: 1@1) offsets: (0@bh corner: 0@0)).\\n\\t\\t\\n\\n\\t^ col! !\\n\\n!OBColumn methodsFor: 'morphic' stamp: 'cwp 2/28/2006 08:37'!\\nlistMorph\\n\\t^ (PluggableListMorph\\n\\t\\ton: self\\n\\t\\tlist: #list\\n\\t\\tselected: #selection\\n\\t\\tchangeSelected: #selection:\\n\\t\\tmenu: #menu:\\n\\t\\tkeystroke: #keystroke:from:)\\n\\t\\t\\tgetListElementSelector: #listAt:;\\n\\t\\t\\tgetListSizeSelector: #listSize;\\n\\t\\t\\tdragEnabled: self dragEnabled;\\n\\t\\t\\tdropEnabled: self dropEnabled;\\n\\t\\t\\tborderWidth: 0;\\n\\t\\t\\tautoDeselect: false;\\n\\t\\t\\tadoptPaneColor: panel defaultBackgroundColor;\\n\\t\\t\\tyourself! !\\n\\n!OBColumn methodsFor: 'morphic' stamp: 'cwp 2/12/2004 19:17'!\\nmorph\\n\\t^ self isEmpty \\n\\t\\tifTrue: [self simplePane]\\n\\t\\tifFalse: [self filter wantsButton\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [self paneWithHeader]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [self simplePane]]! !\\n\\n!OBColumn methodsFor: 'morphic' stamp: 'cwp 2/12/2004 18:11'!\\npaneWithHeader\\n\\t^ OBPane forColumn: self withFilter: self filter! !\\n\\n!OBColumn methodsFor: 'morphic' stamp: 'cwp 2/12/2004 18:10'!\\nsimplePane\\n\\t^ OBPane forColumn: self! !\\n\\n\\n!OBColumn methodsFor: 'nodes' stamp: 'cwp 9/24/2005 22:29'!\\ngetChildren\\n\\tchildren _ self filter nodesForParent: self parent.\\n\\t^ children! !\\n\\n!OBColumn methodsFor: 'nodes' stamp: 'cwp 3/3/2004 00:11'!\\nnextMetaNode\\n\\t^ self selectedNode metaNode! !\\n\\n!OBColumn methodsFor: 'nodes' stamp: 'cwp 9/26/2005 00:14'!\\nselectAncestorOf: aNode\\n\\t| ancestor |\\n\\tancestor _ self filter selectAncestorOf: aNode withParent: self parent.\\n\\tancestor ifNotNil:\\n\\t\\t[self \\n\\t\\t\\tgetChildren; \\n\\t\\t\\tchanged: #list;\\n\\t\\t\\tselect: ancestor.\\n\\t\\tpanel selected: self].\\n\\t^ ancestor! !\\n\\n\\n!OBColumn methodsFor: 'printing' stamp: 'avi 3/6/2004 16:23'!\\ndescriptor\\n\\tself isEmpty ifTrue: [^ 'empty'].\\n\\tself hasSelection ifTrue: [^ self selectedNode name].\\n\\t^ ''! !\\n\\n!OBColumn methodsFor: 'printing' stamp: 'cwp 2/11/2004 23:31'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream nextPut: $(.\\n\\taStream nextPutAll: self descriptor.\\n\\taStream nextPut: $)! !\\n\\n\\n!OBColumn methodsFor: 'selecting' stamp: 'avi 3/6/2004 18:05'!\\nclearSelection\\n\\tselection _ 0! !\\n\\n!OBColumn methodsFor: 'selecting' stamp: 'cwp 2/2/2004 21:54'!\\nselectedNode\\n\\t^ children at: self selection ifAbsent: [].! !\\n\\n!OBColumn methodsFor: 'selecting' stamp: 'cwp 7/14/2006 12:50'!\\nselectSilently: aNode\\n\\t| match |\\n\\taNode ifNil: [selection := 0. ^ self].\\n\\tmatch := children \\n\\t\\t\\t\\tdetect: [:ea | ea correspondsWith: aNode] \\n\\t\\t\\t\\tifNone: [selection := 0. ^ self].\\n\\tselection _ children indexOf: match.! !\\n\\n!OBColumn methodsFor: 'selecting' stamp: 'cwp 12/8/2004 22:10'!\\nselect: aNode\\n\\tself selection: (children indexOf: (children detect: [:ea | ea = aNode] ifNone: []))! !\\n\\n\\n!OBColumn methodsFor: 'testing' stamp: 'avi 3/6/2004 23:07'!\\nhasSelection\\n\\t^ self selection > 0! !\\n\\n!OBColumn methodsFor: 'testing' stamp: 'cwp 12/20/2004 22:09'!\\nincludesNode: aNode\\n\\t^ children includes: aNode! !\\n\\n!OBColumn methodsFor: 'testing' stamp: 'avi 3/6/2004 16:27'!\\nshouldBeLast\\n\\t^ self hasSelection not or: [self nextMetaNode hasChildren not]! !\\n\\n!OBColumn methodsFor: 'testing' stamp: 'cwp 2/12/2004 20:18'!\\nwantsButton\\n\\t^ self filter notNil and: [self filter wantsButton]! !\\n\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/9/2006 22:35'!\\nchildrenChanged: announcement\\n\\t(self parent = announcement node) ifTrue:\\n\\t\\t[self refresh]! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 9/25/2005 23:56'!\\nclear\\n\\tfilter _ nil.\\n\\tchildren _ #().\\n\\tself clearSelection.\\n\\tself changed: #list.\\n\\tself changed: #selection.\\n\\tself changed: #filter.! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 9/24/2005 22:56'!\\ncreateNext\\n\\t| nextMetaNode created |\\n\\tnextMetaNode := self nextMetaNode.\\n\\tcreated := nextMetaNode columnInPanel: panel node: self selectedNode.\\n\\tpanel pushColumn: created.\\n\\t^created! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/9/2006 23:17'!\\nlistChanged\\n\\tself refreshAndSignal: true! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/9/2006 23:19'!\\nnodeChanged: ann\\n\\t(children includes: ann node) ifTrue: [self changed: #list]! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/4/2006 12:03'!\\nnodeDeleted: announcement \\n\\t\\\"This gets called if an action causes the currently selected node to be deleted.\\\"\\n\\n\\tself selectedNode = announcement node\\n\\t\\tifTrue: \\n\\t\\t\\t[self getChildren.\\n\\t\\t\\tself changed: #list.\\n\\t\\t\\tself selection: 0]! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/9/2006 23:08'!\\nrefresh\\n\\tself refreshAndSignal: false! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/9/2006 23:08'!\\nrefresh: ann\\n\\tself refreshAndSignal: false! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/9/2006 23:08'!\\nrefreshAndSignal: aBoolean\\n\\t| node oldChildren shouldSignal |\\n\\tshouldSignal _ aBoolean.\\n\\tself isEmpty ifTrue: [^self].\\n\\tnode := self selectedNode.\\n\\toldChildren := children.\\n\\tself getChildren.\\n\\tchildren = oldChildren ifFalse: \\n\\t\\t[self selectSilently: node.\\n\\t\\tself hasSelection ifFalse: \\n\\t\\t\\t[shouldSignal _ true]].\\n\\tshouldSignal ifTrue: [self signalSelectionChanged].\\n\\tself changed: #list! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/8/2006 00:27'!\\nselectionChanged: ann\\n\\t! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/5/2006 23:31'!\\nsignalSelectionChanged\\n\\tself announcer announce: (OBSelectionChanged column: self)! !\\n\\n!OBColumn methodsFor: 'updating' stamp: 'cwp 6/10/2006 00:18'!\\nsubscribe\\n\\tself announcer \\n\\t\\tobserve: OBRefreshRequired send: #refresh: to: self;\\n\\t\\tobserve: OBNodeChanged send: #nodeChanged: to: self;\\n\\t\\tobserve: OBNodeDeleted send: #nodeDeleted: to: self;\\n\\t\\tobserve: OBChildrenChanged send: #childrenChanged: to: self;\\n\\t\\tobserve: OBSelectionChanged send: #selectionChanged: to: self.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBColumn class\\n\\tinstanceVariableNames: ''!\\n\\n!OBColumn class methodsFor: 'instance creation' stamp: 'cwp 9/18/2005 13:26'!\\ninPanel: aBrowser\\n\\t^ self new setPanel: aBrowser! !\\n\\n!OBColumn class methodsFor: 'instance creation' stamp: 'cwp 9/18/2005 13:25'!\\ninPanel: aPanel metaNode: aMetaNode node: aNode\\n\\t^ self new\\n\\t\\t\\tsetPanel: aPanel\\n\\t\\t\\tmetaNode: aMetaNode\\n\\t\\t\\tnode: aNode! !\\nOBPanel subclass: #OBColumnPanel\\n\\tinstanceVariableNames: 'root columns minPanes maxPanes'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Panels'!\\n!OBColumnPanel commentStamp: 'cwp 12/6/2004 23:50' prior: 0!\\nOBColumnPanel handles navigation around the nodes of the object graph. It maintains a list of columns, which track the user's path through the node tree. As nodes are selected, additional columns are added to the list, which appear as panes on the right of the panel. \\n\\niVars:\\n\\ncolumns\\t- A collection of OBColumns, each of which manages a single pane in the scroller.\\nminPanes - The minimum number of panes that should ever be visible.\\nmaxPanes - The maximum number of panes that should ever be visible.\\n!\\n\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'cwp 11/16/2004 21:46'!\\ncolumns\\n\\t^columns! !\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'cwp 11/16/2004 21:46'!\\ncolumns: anObject\\n\\tcolumns := anObject! !\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'cwp 11/16/2004 22:22'!\\ncurrentNode\\n\\t^ self currentColumn ifNotNilDo: [:column | column selectedNode]! !\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'cwp 11/16/2004 22:23'!\\ncurrentOrRootNode\\n\\t^(self columns reversed detect: [:ea | ea hasSelection]\\n\\t\\tifNone: [^self columns first parent]) selectedNode! !\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'cwp 6/5/2006 23:10'!\\nhasSelection\\n\\t^ false! !\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'cwp 11/16/2004 23:51'!\\nlabelString\\n\\t| label |\\n\\tself columns reversed do: \\n\\t\\t[:ea | \\n\\t\\tlabel := ea selectedNode ifNotNilDo: [:node | node title].\\n\\t\\tlabel ifNotNil: [^ label]].\\n\\t^ nil\\n! !\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'cwp 11/16/2004 23:29'!\\nmaxPanes\\n\\t^maxPanes! !\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'cwp 11/16/2004 22:54'!\\nminPanes\\n\\t^ minPanes! !\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'cwp 2/28/2006 09:59'!\\nparentNodeForColumn: aColumn\\n\\t^ [(columns before: aColumn) selectedNode]\\n\\t\\ton: Error\\n\\t\\tdo: [:err | ^ root]! !\\n\\n!OBColumnPanel methodsFor: 'accessing' stamp: 'dvf 9/5/2005 18:08'!\\nselectionPath\\n\\t^(self columns \\n\\t\\tcollect: [:e | e parent] \\n\\t\\tthenSelect: [:e | e notNil]) allButFirst! !\\n\\n\\n!OBColumnPanel methodsFor: 'accessing columns' stamp: 'cwp 9/25/2005 23:58'!\\nclearAfter: aColumn \\n\\t| start |\\n\\tstart _ (columns indexOf: aColumn) + 1.\\n\\tstart to: columns size do: [:i | (columns at: i) clear]! !\\n\\n!OBColumnPanel methodsFor: 'accessing columns' stamp: 'cwp 2/28/2006 18:12'!\\ncolumnAfter: aColumn \\n\\t^ [self columns after: aColumn]\\n\\t\\ton: Error\\n\\t\\tdo: [:err | nil]\\n! !\\n\\n!OBColumnPanel methodsFor: 'accessing columns' stamp: 'cwp 2/28/2006 19:07'!\\ncolumnBefore: aColumn \\n\\t^ self columnBefore: aColumn ifAbsent: [nil]\\n\\n! !\\n\\n!OBColumnPanel methodsFor: 'accessing columns' stamp: 'cwp 2/28/2006 19:07'!\\ncolumnBefore: aColumn ifAbsent: aBlock\\n\\t^ [self columns before: aColumn]\\n\\t\\ton: Error\\n\\t\\tdo: [:err | aBlock value]\\n\\n\\n! !\\n\\n!OBColumnPanel methodsFor: 'accessing columns' stamp: 'cwp 11/16/2004 22:22'!\\ncurrentColumn\\n\\t^self columns reversed detect: [:ea | ea hasSelection] ifNone: []! !\\n\\n!OBColumnPanel methodsFor: 'accessing columns' stamp: 'cwp 11/16/2004 23:01'!\\nemptyColumn\\n\\t^ OBColumn inPanel: self! !\\n\\n!OBColumnPanel methodsFor: 'accessing columns' stamp: 'cwp 6/4/2006 00:39'!\\npopColumn\\n\\tself announcer unsubscribe: self columns removeLast.\\n! !\\n\\n!OBColumnPanel methodsFor: 'accessing columns' stamp: 'cwp 6/4/2006 00:40'!\\npushColumn: aColumn \\n\\tself columns addLast: aColumn.\\n\\tself changed: #panes.\\n! !\\n\\n!OBColumnPanel methodsFor: 'accessing columns' stamp: 'cwp 6/8/2006 01:35'!\\nselected: aColumn \\n\\taColumn next ifNotNilDo: \\n\\t\\t[:next | \\n\\t\\tnext parent: aColumn selectedNode].! !\\n\\n\\n!OBColumnPanel methodsFor: 'callbacks' stamp: 'cwp 11/26/2004 21:55'!\\ndefaultBackgroundColor\\n\\t^ browser defaultBackgroundColor! !\\n\\n!OBColumnPanel methodsFor: 'callbacks' stamp: 'cwp 11/23/2004 00:52'!\\nokToReclaimPane\\n\\tcolumns size > minPanes ifFalse: [^ false].\\n\\t^ columns last isEmpty or: [(columns at: columns size - 1) shouldBeLast].\\n! !\\n\\n!OBColumnPanel methodsFor: 'callbacks' stamp: 'cwp 11/17/2004 22:48'!\\npanes\\n\\t^ columns collect: [:ea | ea morph]! !\\n\\n!OBColumnPanel methodsFor: 'callbacks' stamp: 'cwp 9/18/2005 11:49'!\\nreclaimPanes\\n\\t| old |\\n\\told := columns size.\\n\\t[self okToReclaimPane] whileTrue: [self popColumn].\\n\\t^ old - columns size! !\\n\\n!OBColumnPanel methodsFor: 'callbacks' stamp: 'cwp 11/18/2004 00:00'!\\nsizing\\n\\t^ (columns size max: minPanes) min: maxPanes! !\\n\\n\\n!OBColumnPanel methodsFor: 'constructing' stamp: 'cwp 11/17/2004 23:24'!\\nbuildScroller\\n\\t^ (OBPaneScroller withModel: self)\\n\\t\\tname: 'scroller';\\n\\t\\tyourself! !\\n\\n!OBColumnPanel methodsFor: 'constructing' stamp: 'cwp 11/20/2004 22:22'!\\nmorph\\n\\t^ (OBPaneScroller withModel: self)\\n\\t\\tname: 'scroller';\\n\\t\\tyourself! !\\n\\n!OBColumnPanel methodsFor: 'constructing' stamp: 'cwp 11/20/2004 22:26'!\\nmorphHeight\\n\\t^ 0! !\\n\\n\\n!OBColumnPanel methodsFor: 'initializing' stamp: 'cwp 9/24/2005 22:45'!\\nsetMetaNode: aMetaNode node: aNode \\n\\troot _ aNode.\\n\\troot metaNode: aMetaNode.\\n\\tself pushColumn: (aMetaNode columnInPanel: self node: root).\\n\\tminPanes - self columns size \\n\\t\\ttimesRepeat: [self pushColumn: self emptyColumn]! !\\n\\n!OBColumnPanel methodsFor: 'initializing' stamp: 'cwp 12/5/2004 16:54'!\\nsetMinPanes: min maxPanes: max\\n\\tcolumns _ OrderedCollection new.\\n\\tminPanes _ min.\\n\\tmaxPanes _ max! !\\n\\n\\n!OBColumnPanel methodsFor: 'navigating' stamp: 'cwp 6/9/2006 23:18'!\\nhopTo: aNode \\n\\t| column |\\n\\tcolumn := self columns last.\\n\\t[column refreshAndSignal: false; includesNode: aNode]\\n\\t\\twhileFalse: [column := self \\n\\t\\t\\t\\t\\t\\tcolumnBefore: column \\n\\t\\t\\t\\t\\t\\tifAbsent: [^ self jumpTo: aNode]].\\n\\tcolumn select: aNode! !\\n\\n!OBColumnPanel methodsFor: 'navigating' stamp: 'cwp 11/16/2004 23:34'!\\njumpToRoot\\n\\t^ self columns first selection: 0! !\\n\\n!OBColumnPanel methodsFor: 'navigating' stamp: 'cwp 6/10/2006 00:11'!\\njumpTo: aNode \\n\\t| column ancestor |\\n\\tcolumn := self columns first.\\n\\t\\n\\t[ancestor := column selectAncestorOf: aNode.\\n\\tancestor = aNode or: [ancestor isNil]] whileFalse:\\n\\t\\t[column := self columns after: column].\\n\\t\\n\\tself announcer announce: (OBSelectionChanged column: column)! !\\n\\n!OBColumnPanel methodsFor: 'navigating' stamp: 'cwp 9/24/2005 22:47'!\\nroot\\n\\t^ root! !\\n\\n\\n!OBColumnPanel methodsFor: 'testing' stamp: 'cwp 11/20/2004 21:10'!\\nisNavigation\\n\\t^ true! !\\n\\n\\n!OBColumnPanel methodsFor: 'updating' stamp: 'cwp 6/5/2006 23:52'!\\nnodeDeleted: ann\\n\\tann node = self root \\n\\t\\tifTrue: \\n\\t\\t\\t[self columns first clear.\\n\\t\\t\\tself announcer announce: (OBSelectionChanged column: self)]! !\\n\\n!OBColumnPanel methodsFor: 'updating' stamp: 'cwp 6/4/2006 01:03'!\\nselectNode: announcement\\n\\t^ self hopTo: announcement node! !\\n\\n!OBColumnPanel methodsFor: 'updating' stamp: 'cwp 6/5/2006 01:33'!\\nselectionChanged: ann\\n\\tann column hasSelection\\n\\t\\tifTrue: [self selected: ann column]\\n\\t\\tifFalse: [self clearAfter: ann column]\\n! !\\n\\n!OBColumnPanel methodsFor: 'updating' stamp: 'cwp 6/5/2006 01:32'!\\nsubscribe\\n\\tself announcer\\n\\t\\tobserve: OBSelectingNode send: #selectNode: to: self;\\n\\t\\tobserve: OBSelectionChanged send: #selectionChanged: to: self;\\n\\t\\tobserve: OBNodeCreated send: #selectNode: to: self;\\n\\t\\tobserve: OBNodeDeleted send: #nodeDeleted: to: self.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBColumnPanel class\\n\\tinstanceVariableNames: ''!\\n\\n!OBColumnPanel class methodsFor: 'instance creation' stamp: 'cwp 12/5/2004 16:56'!\\nminPanes: min maxPanes: max\\n\\t^ self basicNew setMinPanes: min maxPanes: max! !\\n\\n!OBColumnPanel class methodsFor: 'instance creation' stamp: 'cwp 12/5/2004 16:56'!\\nnew\\n\\t^ self minPanes: 1 maxPanes: 1! !\\nOBInteractionRequest subclass: #OBConfirmationRequest\\n\\tinstanceVariableNames: 'prompt confirm cancel'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Notifications'!\\n!OBConfirmationRequest commentStamp: 'cwp 3/5/2004 12:30' prior: 0!\\nThis notification is used to ask the user to confirm some kind potentially dangerous operation. Its default action is to open a PopUpMenu.\\n\\niVars:\\n\\nprompt\\t\\t- a string describing the situation the user is asked to confirm\\nconfirm\\t\\t- a string describing the action that will be taken if the user confirms\\ncancel\\t\\t- a string describing the action that will be taken if the user does not confirm!\\n\\n\\n!OBConfirmationRequest methodsFor: 'initalizing' stamp: 'cwp 2/28/2004 12:00'!\\nsetPrompt: promptString confirm: confirmString cancel: cancelString\\n\\tprompt _ promptString.\\n\\tconfirm _ confirmString.\\n\\tcancel _ cancelString! !\\n\\n\\n!OBConfirmationRequest methodsFor: 'responding' stamp: 'cwp 2/28/2004 12:11'!\\ncancel\\n\\tself resume: false! !\\n\\n!OBConfirmationRequest methodsFor: 'responding' stamp: 'cwp 2/28/2004 12:11'!\\nok\\n\\tself resume: true! !\\n\\n\\n!OBConfirmationRequest methodsFor: 'user interaction' stamp: 'cwp 6/4/2006 14:17'!\\ndefaultAction\\n\\t(prompt beginsWith: 'BogusD') ifTrue: [self halt].\\n\\t^ PopUpMenu confirm: prompt trueChoice: confirm falseChoice: cancel! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBConfirmationRequest class\\n\\tinstanceVariableNames: ''!\\n\\n!OBConfirmationRequest class methodsFor: 'as yet unclassified' stamp: 'cwp 2/28/2004 12:09'!\\nnewPrompt: prompt confirm: confirm cancel: cancel\\n\\t^ self new setPrompt: prompt confirm: confirm cancel: cancel! !\\n\\n!OBConfirmationRequest class methodsFor: 'as yet unclassified' stamp: 'cwp 2/28/2004 12:13'!\\nprompt: prompt\\n\\t^ self prompt: prompt confirm: 'Ok'! !\\n\\n!OBConfirmationRequest class methodsFor: 'as yet unclassified' stamp: 'cwp 2/28/2004 12:12'!\\nprompt: prompt confirm: confirm\\n\\t^ self prompt: prompt confirm: confirm cancel: 'Cancel'! !\\n\\n!OBConfirmationRequest class methodsFor: 'as yet unclassified' stamp: 'cwp 2/28/2004 12:02'!\\nprompt: prompt confirm: confirm cancel: cancel\\n\\t^ (self newPrompt: prompt confirm: confirm cancel: cancel) signal! !\\nObject subclass: #OBDefinition\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Utilities'!\\n!OBDefinition commentStamp: 'cwp 1/7/2005 23:38' prior: 0!\\nThe responsibility of a definition is to express a node's composition textually and respond to changes in the text by updating the node it represents. For example,a file browser might use a file definition to allow editing of a files contents.!\\n\\n\\n\\n!OBDefinition methodsFor: 'callbacks' stamp: 'cwp 3/22/2004 20:51'!\\naccept: aText notifying: aController\\n\\t^ self text: aText! !\\n\\n!OBDefinition methodsFor: 'callbacks' stamp: 'cwp 3/23/2004 00:08'!\\ndoItContext\\n\\t^ nil! !\\n\\n!OBDefinition methodsFor: 'callbacks' stamp: 'cwp 2/28/2005 23:23'!\\ndoItReceiver\\n\\t| class |\\n\\tclass _ self selectedClass.\\n\\t^ class\\n\\t\\tifNotNil: [class theNonMetaClass]\\n\\t\\tifNil: [FakeClassPool new]! !\\n\\n!OBDefinition methodsFor: 'callbacks' stamp: 'cwp 3/23/2004 22:16'!\\nselection\\n\\t^ 1 to: 0! !\\n\\n!OBDefinition methodsFor: 'callbacks' stamp: 'cwp 3/22/2004 20:52'!\\ntext\\n\\t^ ''! !\\n\\n!OBDefinition methodsFor: 'callbacks' stamp: 'cwp 3/23/2004 22:16'!\\ntextSelection\\n\\t^ self selection! !\\n\\n!OBDefinition methodsFor: 'callbacks' stamp: 'cwp 3/22/2004 20:52'!\\ntext: aText\\n\\t^ false! !\\n\\n\\n!OBDefinition methodsFor: 'updating' stamp: 'cwp 6/4/2006 18:53'!\\nsignalChange\\n\\tOBAnnouncer current announce: (OBDefinitionChanged definition: self)! !\\nOBAnnouncement subclass: #OBDefinitionChanged\\n\\tinstanceVariableNames: 'definition node'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBDefinitionChanged methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:25'!\\ndefinition\\n\\t^ definition! !\\n\\n!OBDefinitionChanged methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:26'!\\ndefinition: aDefinition\\n\\tdefinition _ aDefinition! !\\n\\n!OBDefinitionChanged methodsFor: 'as yet unclassified' stamp: 'cwp 6/5/2006 00:47'!\\nnode\\n\\t^ node! !\\n\\n!OBDefinitionChanged methodsFor: 'as yet unclassified' stamp: 'cwp 6/5/2006 00:47'!\\nnode: aNode\\n\\tnode _ aNode! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBDefinitionChanged class\\n\\tinstanceVariableNames: ''!\\n\\n!OBDefinitionChanged class methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:28'!\\ndefinition: aDefinition\\n\\t^ self new\\n\\t\\tdefinition: aDefinition;\\n\\t\\tyourself! !\\n\\n!OBDefinitionChanged class methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:27'!\\nnode: aNode definition: aDefinition\\n\\t^ self new\\n\\t\\tnode: aNode;\\n\\t\\tdefinition: aDefinition;\\n\\t\\tyourself! !\\nOBPanel subclass: #OBDefinitionPanel\\n\\tinstanceVariableNames: 'definition'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Panels'!\\n!OBDefinitionPanel commentStamp: 'cwp 1/7/2005 23:35' prior: 0!\\nOBDefinition serves as the model for the text pane of a typical browser. It's main responsibility is to act as a relay between a PluggableTextMorph and a Definition supplied by the currently selected node.\\n\\niVars:\\n\\nbrowser - The browser of which this panel is a part.\\n!\\n\\n\\n!OBDefinitionPanel methodsFor: 'accessing' stamp: 'cwp 9/17/2004 00:56'!\\ndefinition: aDefinition\\n\\tdefinition _ aDefinition.\\n\\tself changed: #text! !\\n\\n!OBDefinitionPanel methodsFor: 'accessing' stamp: 'cwp 3/22/2004 20:06'!\\ngetDefinition\\n\\t^ browser currentNode ifNotNilDo: [:node | node definition]! !\\n\\n!OBDefinitionPanel methodsFor: 'accessing' stamp: 'cwp 3/22/2004 20:41'!\\nwithDefinitionDo: workBlock ifNil: nilBlock\\n\\tdefinition ifNil: [ ^ nilBlock value].\\n\\t^ workBlock value: definition! !\\n\\n\\n!OBDefinitionPanel methodsFor: 'callbacks' stamp: 'cwp 6/4/2006 00:41'!\\naccept: aText notifying: aController\\n\\t^ self \\n\\t\\twithDefinitionDo: [:def | [def accept: aText notifying: aController]\\n\\t\\t\\t\\t\\t\\t\\t\\t\\ton: OBAnnouncerRequest\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tdo: [:notification | notification resume: self announcer]]\\n\\t\\tifNil: [true]! !\\n\\n!OBDefinitionPanel methodsFor: 'callbacks' stamp: 'cwp 3/23/2004 00:23'!\\ndoItContext\\n\\t^ self \\n\\t\\twithDefinitionDo: [:def | (def respondsTo: #doItContext) ifTrue: [def doItContext]]\\n\\t\\tifNil: [nil]! !\\n\\n!OBDefinitionPanel methodsFor: 'callbacks' stamp: 'cwp 3/23/2004 00:23'!\\ndoItReceiver\\n\\t^ self \\n\\t\\twithDefinitionDo: [:def | (def respondsTo: #doItReceiver) ifTrue: [def doItReceiver]]\\n\\t\\tifNil: [nil]! !\\n\\n!OBDefinitionPanel methodsFor: 'callbacks' stamp: 'cwp 10/24/2004 09:16'!\\nmenu: aMenu shifted: aBoolean\\n\\t| items |\\n\\titems _ aBoolean \\n\\t\\tifTrue: [self shiftedYellowButtonMenu] \\n\\t\\tifFalse: [self yellowButtonMenu].\\n\\titems do: [:ea |\\n\\t\\t\\t ea = #-\\n\\t\\t\\t\\tifFalse: [aMenu add: ea first action: ea second]\\n\\t\\t\\t\\tifTrue: [aMenu addLine]].\\n\\t^ aMenu ! !\\n\\n!OBDefinitionPanel methodsFor: 'callbacks' stamp: 'cwp 10/24/2004 09:27'!\\nperform: aSelector orSendTo: anObject\\n\\t| receiver |\\n\\treceiver _ (self respondsTo: aSelector) ifTrue: [self] ifFalse: [anObject].\\n\\treceiver perform: aSelector! !\\n\\n!OBDefinitionPanel methodsFor: 'callbacks' stamp: 'cwp 3/23/2004 00:22'!\\nselectedClass\\n\\t^ self \\n\\t\\twithDefinitionDo: [:def | (def respondsTo: #selectedClass) ifTrue: [def selectedClass]] \\n\\t\\tifNil: [nil]! !\\n\\n!OBDefinitionPanel methodsFor: 'callbacks' stamp: 'cwp 3/22/2004 21:15'!\\nselection\\n\\t^ self withDefinitionDo: [:def | def textSelection] ifNil: [1 to: 0]! !\\n\\n!OBDefinitionPanel methodsFor: 'callbacks' stamp: 'cwp 3/22/2004 20:42'!\\ntext\\n\\t^ self withDefinitionDo: [:def | def text] ifNil: ['']! !\\n\\n\\n!OBDefinitionPanel methodsFor: 'constructing' stamp: 'cwp 10/30/2004 22:03'!\\nmorph\\n\\t^ (OBPluggableTextMorph\\n\\t\\ton: self\\n\\t\\ttext: #text\\n\\t\\taccept: #accept:notifying:\\n\\t\\treadSelection: #selection\\n\\t\\tmenu: #menu:shifted:)\\n\\t\\t\\tfont: Preferences standardCodeFont;\\n\\t\\t\\tyourself\\n\\t\\t\\t\\n\\t\\\"see CodeHolder>>buildMorphicCodePaneWith:\\\"! !\\n\\n!OBDefinitionPanel methodsFor: 'constructing' stamp: 'cwp 3/9/2004 21:35'!\\nmorphHeight\\n\\t^ 0! !\\n\\n!OBDefinitionPanel methodsFor: 'constructing' stamp: 'cwp 7/14/2006 01:17'!\\nshiftedYellowButtonMenu\\n\\t^ {\\n\\t\\t{'explain' translated.\\t\\t\\t\\t\\t\\t#explain}.\\n\\t\\t#-.\\n\\t\\t{'selectors containing it (W)' translated.\\t\\t#methodNamesContainingIt}.\\n\\t\\t{'method strings with it (E)' translated.\\t\\t#methodStringsContainingit}.\\n\\t\\t{'method source with it' translated.\\t\\t\\t#methodSourceContainingIt}.\\n\\t\\t{'class names containing it' translated.\\t\\t#classNamesContainingIt}.\\n\\t\\t{'class comments with it' translated.\\t\\t\\t#classCommentsContainingIt}.\\n\\t\\t{'change sets with it' translated.\\t\\t\\t\\t#browseChangeSetsWithSelector}.\\n\\t\\t#-.\\n\\t\\t{'save contents to file...' translated.\\t\\t\\t#saveContentsInFile}.\\n\\t\\t#-.\\n\\t\\t{'more...' translated.\\t\\t\\t\\t\\t\\t\\t#yellowButtonActivity}.\\n\\t}\\n! !\\n\\n!OBDefinitionPanel methodsFor: 'constructing' stamp: 'cwp 10/24/2004 23:28'!\\nyellowButtonMenu\\n\\t^ {\\n\\t\\t{'find...(f)' translated.\\t\\t\\t\\t#find}.\\t\\t\\t \\n\\t\\t{'find again (g)' translated.\\t\\t\\t#findAgain}.\\t\\t \\n\\t\\t{'set search string (h)' translated.\\t#setSearchString}.\\n\\t\\t#-.\\t \\n\\t\\t{'do again (j)' translated.\\t\\t\\t#again}.\\t\\t \\n\\t\\t{'undo (z)' translated.\\t\\t\\t\\t#undo}.\\t\\t\\t \\n\\t\\t#-.\\t \\n\\t\\t{'copy (c)' translated.\\t\\t\\t\\t#copySelection}.\\t \\n\\t\\t{'cut (x)' translated.\\t\\t\\t\\t\\t#cut}.\\t\\t\\t \\n\\t\\t{'paste (v)' translated.\\t\\t\\t\\t#paste}.\\t\\t \\n\\t\\t{'paste...' translated.\\t\\t\\t\\t\\t#pasteRecent}.\\t\\t \\n\\t\\t#-.\\t \\n\\t\\t{'accept (s)' translated.\\t\\t\\t\\t#accept}.\\t\\t \\n\\t\\t{'cancel (l)' translated.\\t\\t\\t\\t#cancel}.\\t\\t \\n\\t\\t#-.\\t \\n\\t\\t{'do it (d)' translated.\\t\\t\\t\\t#doIt}.\\t\\t\\t \\n\\t\\t{'print it (p)' translated.\\t\\t\\t\\t#printIt}.\\t\\t \\n\\t\\t{'inspect it (i)' translated.\\t\\t\\t#inspectIt}.\\t\\t \\n\\t\\t{'explore it (I)' translated.\\t\\t\\t#exploreIt}.\\t\\t \\n\\t\\t{'debug it' translated.\\t\\t\\t\\t#debugIt}.\\t\\t \\n\\t\\t#-.\\t \\n\\t\\t{'browse it (b)' translated.\\t\\t\\t\\t\\t#browseIt}.\\n\\t\\t{'senders of it (n)' translated.\\t\\t\\t\\t#sendersOfIt}.\\n\\t\\t{'implementors of it (m)' translated.\\t\\t\\t#implementorsOfIt}.\\n\\t\\t{'references to it (N)' translated.\\t\\t\\t\\t#referencesToIt}.\\n\\t\\t#-.\\n\\t\\t{'more...' translated.\\t\\t\\t\\t\\t#shiftedTextPaneMenuRequest}.\\n\\t}\\n! !\\n\\n\\n\\n!OBDefinitionPanel methodsFor: 'updating' stamp: 'cwp 4/18/2006 21:31'!\\naboutToChange: ann\\n\\t| ok |\\n\\tself canDiscardEdits ifTrue: [^ true].\\n\\tok _ OBConfirmationRequest\\n\\t\\t\\tprompt: 'Changes have not been saved.\\nIs it OK to discard those changes?'\\n\\t\\t\\tconfirm: 'Discard changes'.\\n\\tok\\n\\t\\tifTrue: [self changed: #clearUserEdits]\\n\\t\\tifFalse: [ann veto]! !\\n\\n!OBDefinitionPanel methodsFor: 'updating' stamp: 'cwp 6/4/2006 11:31'!\\ndefinitionChanged: ann\\n\\tdefinition _ ann definition.\\n\\tself changed: #text! !\\n\\n!OBDefinitionPanel methodsFor: 'updating' stamp: 'cwp 6/3/2006 21:55'!\\nrefresh: announcement\\n\\t| oldDefinition |\\n\\tdefinition ifNil: [^ self].\\n\\toldDefinition _ definition.\\n\\tdefinition _ self getDefinition.\\n\\tdefinition text = oldDefinition text ifTrue: [^ self].\\n\\tself canDiscardEdits\\n\\t\\t\\tifTrue: [self changed: #text]\\n\\t\\t\\tifFalse: [self changed: #codeChangedElsewhere]! !\\n\\n!OBDefinitionPanel methodsFor: 'updating' stamp: 'cwp 4/24/2006 16:06'!\\nselectionChanged: ann\\n\\tself definition: self getDefinition! !\\n\\n!OBDefinitionPanel methodsFor: 'updating' stamp: 'cwp 6/4/2006 11:30'!\\nsubscribe\\n\\tself announcer \\n\\t\\tobserve: OBAboutToChange\\n\\t\\tsend: #aboutToChange:\\n\\t\\tto: self;\\n\\t\\t\\n\\t\\tobserve: OBSelectionChanged\\n\\t\\tsend: #selectionChanged:\\n\\t\\tto: self;\\n\\t\\t\\n\\t\\tobserve: OBRefreshRequired\\n\\t\\tsend: #refresh:\\n\\t\\tto: self;\\n\\t\\t\\t\\t\\n\\t\\tobserve: OBDefinitionChanged\\n\\t\\tsend: #definitionChanged: \\n\\t\\tto: self.! !\\n\\n\\n!OBDefinitionPanel methodsFor: '*ob-standard-cmds' stamp: 'pmm 7/6/2006 20:49'!\\nbrowseIt: aSymbol\\n\\t| entry |\\n\\tentry := self selectedClass environment at: aSymbol ifAbsent: [nil].\\n\\tentry ifNil: [^ self implementorsOfIt: aSymbol].\\n\\t(entry isBehavior or: [entry isTrait ])\\n\\t\\tifFalse: [entry := entry class].\\n\\tOBSystemBrowser openOnClass: entry.\\n\\t^ true\\n\\t! !\\n\\n!OBDefinitionPanel methodsFor: '*ob-standard-cmds' stamp: 'avi 9/17/2005 01:36'!\\nimplementorsOfIt: aSelector \\n\\tOBImplementorsBrowser browseRoot: (OBSelectorNode on: aSelector).\\n\\t^true! !\\n\\n!OBDefinitionPanel methodsFor: '*ob-standard-cmds' stamp: 'avi 9/17/2005 01:36'!\\nreferencesToIt: aClassName \\n\\t| class |\\n\\tclass := self selectedClass environment at: aClassName ifAbsent: [^false].\\n\\tclass isBehavior ifFalse: [^false].\\n\\tOBReferencesBrowser browseRoot: (OBClassNode on: class).\\n\\t^true! !\\n\\n!OBDefinitionPanel methodsFor: '*ob-standard-cmds' stamp: 'avi 9/17/2005 01:36'!\\nsendersOfIt: aSelector \\n\\tOBSendersBrowser browseRoot: (OBSelectorNode on: aSelector).\\n\\t^true! !\\nNotification subclass: #OBDispatcherRequest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Notifications'!\\nOBCodeNode subclass: #OBEnvironmentNode\\n\\tinstanceVariableNames: 'environment'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBEnvironmentNode commentStamp: 'cwp 1/8/2005 13:01' prior: 0!\\nOBEnvironmentNode wraps an instance of SystemDictionary. In current Squeak images, there is only one such instance, but OB-Standard is coded so as to use rely on this assumption as little as possible. Thus OBEnvironmentNode typically serves as the root of the standard browser, and passes its environment on to other nodes in the tree.!\\n\\n\\n!OBEnvironmentNode methodsFor: 'navigating'!\\ncategories\\n\\t^ environment organization categories collect: [:cat | OBClassCategoryNode \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\ton: cat\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tinEnvironment: environment]! !\\n\\n!OBEnvironmentNode methodsFor: 'navigating' stamp: 'cwp 9/20/2005 08:43'!\\ncategoryNodeNamed: aString \\n\\t^ OBClassCategoryNode on: aString! !\\n\\n\\n!OBEnvironmentNode methodsFor: 'accessing'!\\nenvironment\\n\\t^ environment! !\\n\\n!OBEnvironmentNode methodsFor: 'accessing'!\\norganization\\n\\t^ self environment organization! !\\n\\n\\n!OBEnvironmentNode methodsFor: 'displaying'!\\nname \\n\\t^ 'Squeak'! !\\n\\n\\n!OBEnvironmentNode methodsFor: 'initializing'!\\nsetEnvironment: anEnvironment\\n\\tenvironment := anEnvironment! !\\n\\n\\n!OBEnvironmentNode methodsFor: 'testing' stamp: 'cwp 6/30/2006 00:54'!\\nhasOrganization\\n\\t^ true! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBEnvironmentNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBEnvironmentNode class methodsFor: 'as yet unclassified'!\\nforImage\\n\\t^ self on: Smalltalk! !\\n\\n!OBEnvironmentNode class methodsFor: 'as yet unclassified'!\\non: anEnvironment\\n\\t^ self new setEnvironment: anEnvironment! !\\nObject subclass: #OBFilter\\n\\tinstanceVariableNames: 'metaNode monitor'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Kernel'!\\n!OBFilter commentStamp: 'cwp 3/4/2004 21:53' prior: 0!\\nA browser's metagraph defines the way in which the user may traverse the graph of objects which make up the browser's domain. But it's not always desirable to have all the nodes made available by the metagraph to be visible in the browser. An filter provides a strategy for filtering out some of the nodes from the display. \\n\\nOBFilter provides a \\\"null\\\" filter - one that does no filtering at all - and serves as a superclass for other filters. !\\n\\n\\n!OBFilter methodsFor: 'accessing' stamp: 'cwp 2/11/2004 23:48'!\\nmetaNode\\n\\t^ metaNode! !\\n\\n!OBFilter methodsFor: 'accessing' stamp: 'cwp 2/9/2004 20:56'!\\nmonitor: aMonitor\\n\\tmonitor _ aMonitor! !\\n\\n\\n!OBFilter methodsFor: 'initalizing' stamp: 'cwp 2/9/2004 20:54'!\\nsetMetaNode: aMetaNode\\n\\tmetaNode _ aMetaNode! !\\n\\n\\n!OBFilter methodsFor: 'public' stamp: 'cwp 2/9/2004 20:50'!\\nchildren\\n\\t^ metaNode children! !\\n\\n!OBFilter methodsFor: 'public' stamp: 'cwp 2/9/2004 20:52'!\\nnodesForParent: aNode\\n\\t^ metaNode nodesForParent: aNode! !\\n\\n!OBFilter methodsFor: 'public' stamp: 'cwp 2/29/2004 14:34'!\\nselectAncestorOf: aNode withParent: parentNode\\n\\t^ (metaNode nodesForParent: parentNode)\\n\\t\\tdetect: [:child | child isAncestorOf: aNode] \\n\\t\\tifNone: [nil]! !\\n\\n\\n!OBFilter methodsFor: 'queries' stamp: 'cwp 2/9/2004 21:06'!\\nwantsButton\\n\\t^ false! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBFilter class\\n\\tinstanceVariableNames: ''!\\n\\n!OBFilter class methodsFor: 'as yet unclassified' stamp: 'cwp 2/9/2004 20:54'!\\nforMetaNode: aMetaNode\\n\\t^ self new setMetaNode: aMetaNode! !\\nOBPanel subclass: #OBFixedButtonPanel\\n\\tinstanceVariableNames: 'models actions'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Panels'!\\n!OBFixedButtonPanel commentStamp: 'cwp 1/7/2005 23:35' prior: 0!\\nOBFixedButtonPanel displays a horizontal row of buttons. In contrast to OBVarButtonPanel, the buttons do not change as nodes are selected in the navigation panel; instead they are enabled and disabled according to whether the actions they represent are applicable to the selected node.!\\n\\n\\n!OBFixedButtonPanel methodsFor: 'accessing' stamp: 'cwp 11/26/2004 22:53'!\\nbuttonModels\\n\\t^ models! !\\n\\n\\n!OBFixedButtonPanel methodsFor: 'callbacks' stamp: 'cwp 11/27/2004 19:20'!\\nisEnabled: aModel\\n\\t^ (actions at: aModel) notNil! !\\n\\n!OBFixedButtonPanel methodsFor: 'callbacks' stamp: 'cwp 11/27/2004 19:20'!\\nisSelected: aModel\\n\\t^ true! !\\n\\n!OBFixedButtonPanel methodsFor: 'callbacks' stamp: 'cwp 8/29/2004 11:28'!\\npush: aModel\\n\\t(actions at: aModel) ifNotNilDo: [:action | action trigger]! !\\n\\n!OBFixedButtonPanel methodsFor: 'callbacks' stamp: 'cwp 6/3/2006 22:15'!\\nselectionChanged: ann\\n\\t| node nodeActions |\\n\\tnode _ browser currentNode ifNil: [^ self].\\n\\tnodeActions _ (node metaNode actionsForNode: node) select: [:ea | ea wantsButton].\\n\\tactions keys do: \\n\\t\\t[:model | \\n\\t\\tactions at: model put: nil.\\n\\t\\tnodeActions do: \\n\\t\\t\\t[:action | model label = action buttonLabel ifTrue: [actions at: model put: action]]].\\n\\tactions keys do: [:ea | ea selectionChanged].! !\\n\\n!OBFixedButtonPanel methodsFor: 'callbacks' stamp: 'cwp 6/3/2006 22:14'!\\nsubscribe\\n\\tself announcer\\n\\t\\tobserve: OBSelectionChanged\\n\\t\\tsend: #selectionChanged:\\n\\t\\tto: self! !\\n\\n\\n!OBFixedButtonPanel methodsFor: 'constructing' stamp: 'lr 3/23/2006 18:14'!\\ncreateMorph\\n\\t^(RectangleMorph new)\\n\\t\\tlayoutPolicy: TableLayout new;\\n\\t\\tlistDirection: #leftToRight;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\tborderWidth: 0;\\n\\t\\twrapCentering: #center;\\n\\t\\tcellPositioning: #leftCenter;\\n\\t\\trubberBandCells: true;\\n\\t\\tlayoutInset: 2;\\n\\t\\tcellInset: 2;\\n\\t\\tyourself! !\\n\\n!OBFixedButtonPanel methodsFor: 'constructing' stamp: 'cwp 11/27/2004 21:24'!\\nmorph\\n\\t| morph |\\n\\tmorph := self createMorph.\\n\\tself buttonModels do: [:ea | morph addMorphBack: (self morphForModel: ea)].\\n\\t^morph! !\\n\\n!OBFixedButtonPanel methodsFor: 'constructing' stamp: 'cwp 11/27/2004 21:25'!\\nmorphForModel: aModel\\n\\t| morph paneColor |\\n\\tmorph _ aModel morph.\\n\\tpaneColor _ browser defaultBackgroundColor.\\n\\tmorph onColor: paneColor darker offColor: paneColor lighter.\\n\\t^ morph! !\\n\\n!OBFixedButtonPanel methodsFor: 'constructing' stamp: 'lr 3/23/2006 18:15'!\\nmorphHeight\\n\\t^ 30! !\\n\\n\\n!OBFixedButtonPanel methodsFor: 'initializing' stamp: 'cwp 11/26/2004 22:53'!\\ninitialize\\n\\tmodels _ OrderedCollection new.\\n\\tactions _ Dictionary new.! !\\n\\n\\n!OBFixedButtonPanel methodsFor: 'public' stamp: 'cwp 11/26/2004 22:52'!\\naddButtonWithLabel: label\\n\\t| model |\\n\\tmodel _ OBButtonModel withLabel: label inBar: self.\\n\\tmodels add: model.\\n\\tactions at: model put: nil! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBFixedButtonPanel class\\n\\tinstanceVariableNames: ''!\\n\\n!OBFixedButtonPanel class methodsFor: 'as yet unclassified' stamp: 'cwp 2/28/2006 10:41'!\\nnew\\n\\t^ self basicNew initialize! !\\nOBCodeBrowser subclass: #OBHierarchyBrowser\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n!OBHierarchyBrowser commentStamp: 'cwp 1/7/2005 23:50' prior: 0!\\nOBHierarchyBrowser provides a three-pane browers that displays a class within it's surrounding hierarchy - both superclasses and subclasses!\\n\\n\\n!OBHierarchyBrowser methodsFor: 'as yet unclassified' stamp: 'cwp 12/13/2004 00:40'!\\ndefaultBackgroundColor\\n\\t^ Color lightGreen! !\\n\\n!OBHierarchyBrowser methodsFor: 'as yet unclassified' stamp: 'cwp 12/13/2004 01:00'!\\ndefaultLabel\\n\\t^ self root name, ' Hierarchy'! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBHierarchyBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBHierarchyBrowser class methodsFor: 'configuration' stamp: 'avi 9/17/2005 01:06'!\\ndefaultMetaNode\\n\\t^ self \\n\\t\\taddTo: (OBMetaNode named: 'RootClass')\\n\\t\\tclass: #classHierarchy \\n\\t\\tcomment: #commentHierarchy \\n\\t\\tmetaclass: #metaclassHierarchy.\\n! !\\n\\n!OBHierarchyBrowser class methodsFor: 'configuration' stamp: 'cwp 12/13/2004 00:37'!\\npaneCount\\n\\t^ 3! !\\n\\n!OBHierarchyBrowser class methodsFor: 'configuration' stamp: 'cwp 12/13/2004 01:00'!\\ntitleForRoot: aNode\\n\\t^ aNode name, ' Hierarchy'! !\\n\\n\\n!OBHierarchyBrowser class methodsFor: 'instance creation' stamp: 'lr 3/6/2006 19:28'!\\nonClass: aClass \\n\\t^self root: aClass asNode selection: aClass asNode! !\\n\\n\\n!OBHierarchyBrowser class methodsFor: 'opening' stamp: 'cwp 12/15/2004 22:49'!\\nopenOnClass: aClass\\n\\t^ (self onClass: aClass) open! !\\nOBListBrowser subclass: #OBImplementorsBrowser\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBImplementorsBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBImplementorsBrowser class methodsFor: 'as yet unclassified' stamp: 'cwp 3/2/2006 15:35'!\\nchaseImplementorsNav: navSelector\\n\\t| message implementor |\\n\\tmessage := OBMetaNode named: 'Message'.\\n\\timplementor := OBMetaNode named: 'Implementor'.\\n\\timplementor\\n\\t\\tdisplaySelector: #indentedFullName;\\n\\t\\tchildAt: #messages put: message;\\n\\t\\taddActor: OBNodeActor new.\\n\\tmessage\\n\\t\\tchildAt: navSelector labeled: 'implementors' put: implementor;\\n\\t\\taddActor: OBNodeActor new.\\n\\t^ implementor! !\\n\\n!OBImplementorsBrowser class methodsFor: 'as yet unclassified' stamp: 'avi 9/17/2005 01:24'!\\ndefaultMetaNode\\n\\t^ self hierarchicalImplementors! !\\n\\n!OBImplementorsBrowser class methodsFor: 'as yet unclassified' stamp: 'avi 9/17/2005 01:24'!\\nhierarchicalImplementors\\n\\t^ self implementorsNav: #implementorsHierarchically! !\\n\\n!OBImplementorsBrowser class methodsFor: 'as yet unclassified' stamp: 'avi 9/17/2005 01:24'!\\nimplementorsNav: navSelector\\n\\t| selector implementors |\\n\\tselector := OBMetaNode named: 'Selector'.\\n\\timplementors := OBMetaNode named: 'Implementors'.\\n\\t\\n\\tselector \\n\\t\\tchildAt: navSelector labeled: 'list' put: implementors;\\n\\t\\tchildAt: navSelector labeled: 'chase' put: (self chaseImplementorsNav: navSelector);\\n\\t\\tfilterClass: OBModalFilter.\\n\\timplementors \\n\\t\\tdisplaySelector: #indentedFullName;\\n\\t\\taddActor: OBNodeActor new.\\n\\n\\t^ selector! !\\n\\n!OBImplementorsBrowser class methodsFor: 'as yet unclassified' stamp: 'avi 9/17/2005 01:36'!\\ntitle\\n\\t^ 'Implementors of'! !\\nOBActor subclass: #OBImplementorsViewActor\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Services'!\\n\\n!OBImplementorsViewActor methodsFor: 'as yet unclassified' stamp: 'cwp 7/14/2006 14:28'!\\nactionsForParent: aNode\\n\\t^{OBAction\\n\\t\\t\\tlabel: 'add implementor' \\n\\t\\t\\treceiver: self\\n\\t\\t\\tselector: #addImplementor:\\n\\t\\t\\targuments: {aNode}\\n\\t\\t\\tkeystroke: $a\\n\\t\\t\\ticon: self newIcon}! !\\n\\n!OBImplementorsViewActor methodsFor: 'as yet unclassified' stamp: 'dvf 9/12/2005 16:34'!\\naddImplementor: aNode \\n\\t| class sel |\\n\\tsel := aNode selector.\\n\\tclass := self getClassForNewImplementationOf: sel.\\n\\tclass ifNil: [^self].\\n\\t(class selectors includes: sel) \\n\\t\\tifTrue: [^self inform: class name , ' already implements #' , sel].\\n\\tclass compile: aNode selector , '\\n\\tself shouldBeImplemented'.\\n\\t(OBMethodNode on: sel inClass: class) signalSelection! !\\n\\n!OBImplementorsViewActor methodsFor: 'as yet unclassified' stamp: 'dvf 9/12/2005 16:14'!\\ngetClassForNewImplementationOf: sel \\n\\t| className |\\n\\tclassName := (OBTextRequest \\n\\t\\t\\t\\tprompt: 'Please type class name in which to implement ' , sel\\n\\t\\t\\t\\ttemplate: '') ifNil: [''].\\n\\t^(Smalltalk classNamed: className withBlanksTrimmed) ifNil: \\n\\t\\t\\t[self inform: 'Class ' , className , ' not found'.\\n\\t\\t\\tnil]! !\\nOBCodeBrowser subclass: #OBInheritanceBrowser\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n!OBInheritanceBrowser commentStamp: 'cwp 1/7/2005 23:51' prior: 0!\\nOBInheritanceBrowser shows the inheritance hierarchy of a method, both superclass implementations which it overrides, and subclass implementations which override it.!\\n\\n\\n!OBInheritanceBrowser methodsFor: 'morphic' stamp: 'avi 11/29/2004 21:52'!\\ndefaultBackgroundColor\\n\\t^ Color lightGreen! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBInheritanceBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBInheritanceBrowser class methodsFor: 'configuration' stamp: 'avi 9/17/2005 01:08'!\\ndefaultMetaNode\\n\\t| method root |\\n\\tmethod := OBMetaNode named: 'Method'.\\n\\troot := OBMetaNode named: 'Root'.\\n\\troot\\n\\t\\tchildAt: #children put: method.\\n\\tmethod\\n\\t\\tdisplaySelector: #fullName;\\n\\t\\tchildAt: #overrides put: method;\\n\\t\\taddActor: OBNodeActor new.\\n\\t^ root! !\\n\\n!OBInheritanceBrowser class methodsFor: 'configuration'!\\ntitle\\n\\t^ 'Inheritance'! !\\n\\n!OBInheritanceBrowser class methodsFor: 'configuration' stamp: 'cwp 11/25/2004 22:05'!\\ntitleForRoot: aCollectionNode\\n\\t^ 'Inheritance of ', aCollectionNode children first selector printString! !\\nOBVariableNode subclass: #OBInstanceVariableNode\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBInstanceVariableNode commentStamp: 'cwp 1/8/2005 12:50' prior: 0!\\nOBClassVariable provides a method for finding methods which refer to an instance, ie, by searching for instance variable access bytecodes rather than for an association in the literal frame.!\\n\\n\\n!OBInstanceVariableNode methodsFor: 'navigating' stamp: 'cwp 12/8/2004 23:48'!\\naccessors\\n\\t| accessors |\\n\\taccessors := OrderedCollection new.\\n\\tself theClass withAllSubAndSuperclassesDo: [:class |\\n\\t\\t(class whichSelectorsAccess: name) asSortedCollection\\n\\t\\t\\tdo: [:ea | ea = #DoIt ifFalse: [accessors add: \\n\\t\\t\\t\\t\\t(self referenceForMethod: ea ofClass: class name)]]].\\n\\t^ accessors asArray\\tcollect: [:ref | OBMethodNode on: ref]! !\\nNotification subclass: #OBInteractionRequest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Notifications'!\\n!OBInteractionRequest commentStamp: 'cwp 12/7/2004 00:13' prior: 0!\\nOBInteractionRequest is an abstract superclass for notifications that request some interaction with the user. It's useful for catching such notifications in an exception handler, while allowing other notifications to operate normally.!\\n\\n\\n!OBInteractionRequest methodsFor: 'as yet unclassified' stamp: 'cwp 10/17/2004 19:31'!\\nisBrowseRequest\\n\\t^ false! !\\nOBCodeBrowser subclass: #OBListBrowser\\n\\tinstanceVariableNames: 'labelPrefix'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n!OBListBrowser commentStamp: 'cwp 1/7/2005 23:53' prior: 0!\\nOBListBrowsers are used to display simple lists of methods, such as senders or implementors.!\\n\\n\\n!OBListBrowser methodsFor: 'morphic' stamp: 'avi 11/29/2004 21:58'!\\ndefaultBackgroundColor\\n\\t^ Color lightBlue! !\\n\\n\\n!OBListBrowser methodsFor: 'accessing' stamp: 'cwp 11/25/2004 22:21'!\\ndefaultLabel\\n\\t^ self labelPrefix, ' ', self root name printString! !\\n\\n!OBListBrowser methodsFor: 'accessing' stamp: 'cwp 11/25/2004 22:18'!\\nlabelPrefix\\n\\t^ labelPrefix ifNil: [labelPrefix _ self root metaNode edges first label capitalized, ' of']! !\\n\\n!OBListBrowser methodsFor: 'accessing' stamp: 'cwp 10/17/2004 20:54'!\\nlabelPrefix: aString\\n\\tlabelPrefix _ aString! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBListBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBListBrowser class methodsFor: 'opening' stamp: 'avi 9/17/2005 01:34'!\\nbrowseRoot: aNode\\n\\tself browseRoot: aNode title: self title! !\\n\\n!OBListBrowser class methodsFor: 'opening' stamp: 'avi 9/17/2005 01:21'!\\nbrowseRoot: aNode title: aString \\n\\t(self metaNode: self defaultMetaNode root: aNode selection: nil)\\n\\t\\tlabelPrefix: aString;\\n\\t\\topen\\n\\t! !\\n\\n\\n!OBListBrowser class methodsFor: 'configuration' stamp: 'cwp 12/5/2004 17:54'!\\nmaxPanes\\n\\t^ 2! !\\n\\n!OBListBrowser class methodsFor: 'configuration' stamp: 'cwp 12/5/2004 17:54'!\\nminPanes\\n\\t^ 1! !\\nOBMethodNode subclass: #OBMessageNode\\n\\tinstanceVariableNames: 'message'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBMessageNode commentStamp: 'cwp 1/8/2005 12:40' prior: 0!\\nAn OBMessageNode refers to a message send in the source code of a method. They are typically used in the 'senders' browser.!\\n\\n\\n!OBMessageNode methodsFor: 'navigating'!\\nimplementors\\n\\t^ self implementorsOf: message! !\\n\\n!OBMessageNode methodsFor: 'navigating'!\\nsendersOfMessage\\n\\t^ self sendersOf: message! !\\n\\n\\n!OBMessageNode methodsFor: 'displaying' stamp: 'cwp 12/8/2004 21:26'!\\nname\\n\\t^ message! !\\n\\n\\n!OBMessageNode methodsFor: 'accessing'!\\nselection\\n\\t| methodNode assoc |\\n\\tmethodNode := Parser new \\n\\t\\t\\t\\t\\tparse: self source\\n\\t\\t\\t\\t\\tclass: self theClass.\\n\\tassoc := (methodNode encoder rawSourceRanges) \\n\\t\\t\\tassociations detect: [:ea | ea key isMessage: message receiver: nil arguments: nil]\\n\\t\\t\\t\\t\\t\\tifNone: [nil -> (1 to: 0)].\\n\\t\\t\\t\\t\\t\\t\\\"Some messages are generated by the compiler.\\\"\\n\\t^ assoc value! !\\n\\n\\n!OBMessageNode methodsFor: 'initializing'!\\nsetMessage: aSelector selector: aSelector2 class: aClass\\n\\tmessage := aSelector.\\n\\tselector := aSelector2.\\n\\tself theClass: aClass! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBMessageNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBMessageNode class methodsFor: 'instance creation'!\\nfromMethodNode: aMethodNode\\n\\t^ self new \\n\\t\\tsetMessage: aMethodNode selector\\n\\t\\tselector: aMethodNode selector\\n\\t\\tclass: aMethodNode theClass! !\\n\\n!OBMessageNode class methodsFor: 'instance creation'!\\non: aSelector inMethodNode: aNode\\n\\t^ self \\n\\t\\ton: aSelector \\n\\t\\tinMethod: aNode selector \\n\\t\\tinClass: aNode theClass! !\\n\\n!OBMessageNode class methodsFor: 'instance creation' stamp: 'cwp 12/8/2004 23:46'!\\non: aSelector inMethodReference: ref\\n\\t^ self \\n\\t\\ton: aSelector \\n\\t\\tinMethod: ref methodSymbol\\n\\t\\tinClass: ref actualClass! !\\n\\n!OBMessageNode class methodsFor: 'instance creation'!\\non: aSelector inMethod: aSelector2 inClass: classRef\\n\\t^ self new setMessage: aSelector selector: aSelector2 class: classRef! !\\nObject subclass: #OBMetaEdge\\n\\tinstanceVariableNames: 'label selector metaNode'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Kernel'!\\n!OBMetaEdge commentStamp: 'cwp 1/7/2005 23:20' prior: 0!\\nAn OBMetaEdge is an edge in the browser's metagraph. It represents a message sent to a node to obtain further nodes. It is refered to by the \\\"parent\\\" metanode, and refers to the \\\"child\\\" metanode.\\n\\niVars:\\n\\nlabel \\t\\t- a string describing the metaNode, for filters which allow the user \\n\\t\\t\\t to choose which edges to follow\\nselector\\t- when a node is selected by the user, this message will be \\n\\t\\t\\t sent to it to obtain its children\\nmetaNode \\t- a MetaNode corresponding to the nodes answered by the above message\\n\\t\\t!\\n\\n\\n!OBMetaEdge methodsFor: 'accessing' stamp: 'cwp 2/7/2004 22:40'!\\nlabel\\n\\t^ label! !\\n\\n!OBMetaEdge methodsFor: 'accessing' stamp: 'cwp 2/7/2004 22:40'!\\nmetaNode\\n\\t^ metaNode! !\\n\\n!OBMetaEdge methodsFor: 'accessing' stamp: 'cwp 3/3/2004 00:12'!\\nnodesForParent: aNode\\n\\t^ (aNode perform: selector) do: [:ea | ea metaNode: metaNode]\\n! !\\n\\n!OBMetaEdge methodsFor: 'accessing' stamp: 'cwp 2/7/2004 22:40'!\\nselector\\n\\t^ selector! !\\n\\n\\n!OBMetaEdge methodsFor: 'initializing' stamp: 'cwp 2/7/2004 22:36'!\\nsetLabel: aString selector: aSelector metaNode: aMetaNode\\n\\tlabel _ aString.\\n\\tselector _ aSelector.\\n\\tmetaNode _ aMetaNode! !\\n\\n\\n!OBMetaEdge methodsFor: 'printing' stamp: 'dvf 8/16/2005 10:03'!\\nprintOn: aStream\\n\\taStream nextPutAll: selector printString, '->'. \\n\\tmetaNode shortPrintOn: aStream.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBMetaEdge class\\n\\tinstanceVariableNames: ''!\\n\\n!OBMetaEdge class methodsFor: 'as yet unclassified' stamp: 'cwp 2/7/2004 22:35'!\\nlabel: aString selector: aSelector metaNode: aMetaNode\\n\\t^ self new setLabel: aString selector: aSelector metaNode: aMetaNode! !\\n\\n!OBMetaEdge class methodsFor: 'as yet unclassified' stamp: 'cwp 2/9/2004 22:32'!\\nselector: aSelector metaNode: aMetaNode\\n\\t^ self new setLabel: aSelector asString selector: aSelector metaNode: aMetaNode! !\\nObject subclass: #OBMetaNode\\n\\tinstanceVariableNames: 'name filterClass columnClass edges actors displaySelector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Kernel'!\\n!OBMetaNode commentStamp: 'cwp 1/7/2005 23:23' prior: 0!\\nA MetaNode represents a hypothetical node in the browser's domain graph.\\n\\niVars:\\n\\nfilterClass\\t\\t\\t- the class used to filter this hypothetical node's children\\ncolumnClass\\t\\t- the class of column used to display this node's children\\nedges\\t\\t\\t\\t- messages that could be sent to the node to obtain children\\nactors\\t\\t\\t\\t- providers of functionality for manipulating the node\\ndisplaySelector\\t\\t- the message used to retreive a nodes display name!\\n\\n\\n!OBMetaNode methodsFor: 'accessing' stamp: 'cwp 12/8/2004 21:41'!\\ndisplaySelector\\n\\t^ displaySelector ifNil: [displaySelector _ #name]! !\\n\\n!OBMetaNode methodsFor: 'accessing' stamp: 'cwp 12/8/2004 21:42'!\\ndisplaySelector: aSelector\\n\\tdisplaySelector _ aSelector! !\\n\\n!OBMetaNode methodsFor: 'accessing' stamp: 'cwp 3/6/2004 21:54'!\\nname\\n\\t^ name ifNil: ['MetaNode']! !\\n\\n!OBMetaNode methodsFor: 'accessing' stamp: 'cwp 3/6/2004 21:05'!\\nname: aString\\n\\tname _ aString! !\\n\\n\\n!OBMetaNode methodsFor: 'actors' stamp: 'cwp 9/14/2004 18:59'!\\nactionSetsForNode: aNode\\n\\t^ actors collect: [:actor | actor actionsForNode: aNode]! !\\n\\n!OBMetaNode methodsFor: 'actors' stamp: 'cwp 9/14/2004 19:01'!\\nactionSetsForParent: aNode\\n\\t^ actors collect: [:actor | actor actionsForParent: aNode]! !\\n\\n!OBMetaNode methodsFor: 'actors' stamp: 'cwp 9/14/2004 19:00'!\\nactionsForNode: aNode\\n\\t^ (self actionSetsForNode: aNode) gather: [:ea | ea]! !\\n\\n!OBMetaNode methodsFor: 'actors' stamp: 'cwp 9/14/2004 19:02'!\\nactionsForParent: aNode\\n\\t^ (self actionSetsForParent: aNode) gather: [:ea | ea]! !\\n\\n!OBMetaNode methodsFor: 'actors' stamp: 'cwp 3/3/2004 22:48'!\\naddActor: anActor\\n\\tactors add: anActor.! !\\n\\n\\n!OBMetaNode methodsFor: 'children' stamp: 'cwp 2/9/2004 20:28'!\\nchildAt: aSelector labeled: aString put: aMetaNode\\n\\tedges add: (OBMetaEdge label: aString selector: aSelector metaNode: aMetaNode)! !\\n\\n!OBMetaNode methodsFor: 'children' stamp: 'cwp 2/7/2004 22:35'!\\nchildAt: aSelector put: aMetaNode\\n\\tedges add: (OBMetaEdge selector: aSelector metaNode: aMetaNode)! !\\n\\n!OBMetaNode methodsFor: 'children' stamp: 'cwp 2/7/2004 22:44'!\\nchildren\\n\\t^ edges collect: [:edge | edge metaNode]! !\\n\\n!OBMetaNode methodsFor: 'children' stamp: 'cwp 2/7/2004 22:38'!\\nhasChildren\\n\\t^ edges isEmpty not! !\\n\\n\\n!OBMetaNode methodsFor: 'columns' stamp: 'avi 3/4/2004 03:11'!\\ncolumnClass: aClass\\n\\tcolumnClass _ aClass! !\\n\\n!OBMetaNode methodsFor: 'columns' stamp: 'cwp 11/16/2004 22:03'!\\ncolumnInPanel: aBrowser node: aNode\\n\\tcolumnClass ifNil: [columnClass _ OBColumn].\\n\\t^ columnClass\\n\\t\\tinPanel: aBrowser\\n\\t\\tmetaNode: self\\n\\t\\tnode: aNode! !\\n\\n\\n!OBMetaNode methodsFor: 'filtering' stamp: 'cwp 2/9/2004 21:26'!\\nfilter\\n\\tfilterClass ifNil: [filterClass _ OBFilter].\\n\\t^ filterClass forMetaNode: self! !\\n\\n!OBMetaNode methodsFor: 'filtering' stamp: 'cwp 2/9/2004 21:02'!\\nfilterClass: aClass\\n\\tfilterClass _ aClass! !\\n\\n!OBMetaNode methodsFor: 'filtering' stamp: 'cwp 2/9/2004 21:00'!\\nmetaNode\\n\\t^ self! !\\n\\n\\n!OBMetaNode methodsFor: 'initializing' stamp: 'cwp 12/8/2004 20:06'!\\ninitialize\\n\\tedges _ OrderedCollection new.\\n\\tactors _ OrderedCollection new.! !\\n\\n\\n!OBMetaNode methodsFor: 'metagraph' stamp: 'cwp 2/9/2004 21:12'!\\nedges\\n\\t^ edges! !\\n\\n\\n!OBMetaNode methodsFor: 'nodes' stamp: 'cwp 3/3/2004 00:22'!\\nnodesForParent: aNode\\n\\t^ edges gather: [:edge | edge nodesForParent: aNode]! !\\n\\n\\n!OBMetaNode methodsFor: 'printing' stamp: 'dvf 8/16/2005 10:01'!\\nprintOn: aStream\\n\\taStream nextPutAll: self name;cr.\\n\\tedges do: [:e | e printOn: aStream. aStream cr].! !\\n\\n!OBMetaNode methodsFor: 'printing' stamp: 'dvf 8/16/2005 10:01'!\\nshortPrintOn: aStream\\n\\taStream nextPutAll: self name.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBMetaNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBMetaNode class methodsFor: 'instance creation' stamp: 'cwp 3/6/2004 21:06'!\\nnamed: aString\\n\\t^ self new name: aString! !\\n\\n!OBMetaNode class methodsFor: 'instance creation' stamp: 'cwp 3/3/2004 23:08'!\\nnew\\n\\t^ self basicNew initialize! !\\nOBClassNode subclass: #OBMetaclassNode\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBMetaclassNode commentStamp: 'cwp 1/8/2005 11:29' prior: 0!\\nOBMetaclassNode is essentially the same as an OBClassNode, but overrides a few methods to work properly with metaclasses.!\\n\\n\\n!OBMetaclassNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 21:57'!\\nbrowse\\n\\t^ OBSystemBrowser openOnClass: self theNonMetaClass ! !\\n\\n\\n!OBMetaclassNode methodsFor: 'displaying' stamp: 'cwp 12/13/2004 00:56'!\\nname \\n\\t^ self nonMetaName! !\\n\\n!OBMetaclassNode methodsFor: 'displaying'!\\nnonMetaName\\n\\t^ self theNonMetaClass name! !\\n\\n\\n!OBMetaclassNode methodsFor: 'initializing'!\\nsetClass: aClass\\n\\tsuper setClass: aClass theMetaClass\\n\\t\\t! !\\nOBClassAwareNode subclass: #OBMethodCategoryNode\\n\\tinstanceVariableNames: 'name'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBMethodCategoryNode commentStamp: 'cwp 1/8/2005 12:29' prior: 0!\\nOBMethodCategory represents a category within a ClassOrganization. Instead of an organization definition, OBMethodCategory presents a MethodDefinition with the class' default method template.!\\n\\n\\n!OBMethodCategoryNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 23:04'!\\nactions\\n\\t^ {\\n\\t\\tself action: #fileOut withLabel: 'file out'.\\n\\t\\tself browseAction.\\n\\t\\tself browseHierarchyAction.\\n\\t\\tself action: #chaseVars buttonLabel: 'variables' menuLabel: 'chase variables'\\n\\t}\\n! !\\n\\n!OBMethodCategoryNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 21:50'!\\nbrowse\\n\\tOBSystemBrowser openOnClass: self theClass category: name! !\\n\\n!OBMethodCategoryNode methodsFor: 'actions'!\\nfileOut\\n\\tself theClass fileOutCategory: name! !\\n\\n!OBMethodCategoryNode methodsFor: 'actions' stamp: 'cwp 9/19/2004 00:11'!\\nremove\\n\\tself theClass removeCategory: name.\\n\\tself signalDeletion! !\\n\\n\\n!OBMethodCategoryNode methodsFor: 'ancestry'!\\nancestrySelector\\n\\t^ #isDescendantOfMethodCat:! !\\n\\n!OBMethodCategoryNode methodsFor: 'ancestry'!\\nisDescendantOfMethodCat: other\\n\\t^ (other theClassName = self theClassName) and: [other name = name]! !\\n\\n\\n!OBMethodCategoryNode methodsFor: 'accessing'!\\ncategory\\n\\t^ name! !\\n\\n!OBMethodCategoryNode methodsFor: 'accessing'!\\ncontainer\\n\\t^ self theClass! !\\n\\n!OBMethodCategoryNode methodsFor: 'accessing' stamp: 'cwp 9/14/2005 09:06'!\\nmethodReferences\\n\\t^ (self theClass organization listAtCategoryNamed: name)\\n\\t\\tcollect: [:ea | MethodReference new\\n\\t\\t\\t\\t\\t\\tsetClassSymbol: self theNonMetaClassName\\n\\t\\t\\t\\t\\t\\tclassIsMeta: self theClass isMeta\\n\\t\\t\\t\\t\\t\\tmethodSymbol: ea\\n\\t\\t\\t\\t\\t\\tstringVersion: '']\\n! !\\n\\n!OBMethodCategoryNode methodsFor: 'accessing' stamp: 'dvf 8/16/2005 17:47'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream nextPut: $<.\\n\\tself name printOn: aStream.\\n\\taStream nextPut: $>.! !\\n\\n\\n!OBMethodCategoryNode methodsFor: 'public'!\\ndefinition\\n\\t^ OBMethodDefinition inCategory: self category inClass: self theClass! !\\n\\n!OBMethodCategoryNode methodsFor: 'public'!\\nname\\n\\t^ name! !\\n\\n\\n!OBMethodCategoryNode methodsFor: 'drag and drop' stamp: 'lr 4/6/2006 11:46'!\\ndropOnClass: aNode\\n\\tself methods do: [ :each | each dropOnClass: aNode ].\\n\\taNode signalChildrenChanged.\\n\\t^ true! !\\n\\n!OBMethodCategoryNode methodsFor: 'drag and drop'!\\ndropSelector\\n\\t^ #dropOnMethodCategory:! !\\n\\n\\n!OBMethodCategoryNode methodsFor: 'comparing' stamp: 'cwp 12/20/2004 00:53'!\\nhash\\n\\t^ self name hash! !\\n\\n!OBMethodCategoryNode methodsFor: 'comparing' stamp: 'cwp 12/20/2004 00:50'!\\n= other\\n\\tself species = other species ifFalse: [^ false].\\t\\n\\tself theClass = other theClass ifFalse: [^ false].\\n\\t^ self name = other name! !\\n\\n\\n!OBMethodCategoryNode methodsFor: 'navigating' stamp: 'dvf 8/19/2005 17:16'!\\nmethods\\n\\t^ self methodReferences collect: [:ref | ref asNode]! !\\n\\n\\n!OBMethodCategoryNode methodsFor: 'initializing'!\\nsetName: aString class: aClass\\n\\tname := aString.\\n\\tself theClass: aClass! !\\n\\n\\n!OBMethodCategoryNode methodsFor: 'testing' stamp: 'cwp 6/30/2006 00:48'!\\nhasOrganization\\n\\t^ true! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBMethodCategoryNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBMethodCategoryNode class methodsFor: 'actions' stamp: 'cwp 9/18/2004 22:58'!\\nactionsForParent: aNode\\n\\t^ #()! !\\n\\n\\n!OBMethodCategoryNode class methodsFor: 'instance creation'!\\non: aString inClass: aClassReference\\n\\t^ self new setName: aString class: aClassReference! !\\nOBDefinition subclass: #OBMethodDefinition\\n\\tinstanceVariableNames: 'theClass category source selection callback'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Definitions'!\\n!OBMethodDefinition commentStamp: 'cwp 1/8/2005 13:20' prior: 0!\\nOBMethodDefinition knows how to present method source in the browser's text pane and compile a new CompiledMethod when the source changes. It implements several safety checks to ensure that methods are not accidentally overwritten.!\\n\\n\\n!OBMethodDefinition methodsFor: 'callbacks' stamp: 'cwp 9/18/2005 14:53'!\\naccept: aText notifying: aController\\n\\t| newSelector |\\n\\tnewSelector := self compileMethod: aText notifying: aController.\\n\\tnewSelector ifNil: [^ false].\\n\\t(self nodeFor: newSelector) demandSelection.\\n\\t^ true! !\\n\\n!OBMethodDefinition methodsFor: 'callbacks' stamp: 'cwp 10/17/2004 23:16'!\\nredefineSource: aText selector: newSelector\\n\\tnewSelector = self selector \\n\\t\\tifTrue: [source := aText]\\n\\t\\tifFalse: [(self methodNodeFor: newSelector) signalSelection].\\n! !\\n\\n!OBMethodDefinition methodsFor: 'callbacks'!\\nselectedClass\\n\\t^ self theClass! !\\n\\n!OBMethodDefinition methodsFor: 'callbacks'!\\nselection\\n\\t^ selection ifNil: [1 to: (source ifNil: [self text size] ifNotNil: [0])]! !\\n\\n!OBMethodDefinition methodsFor: 'callbacks' stamp: 'cwp 11/29/2004 21:21'!\\ntext\\n\\t^ source \\n\\t\\tifNotNil: [source asText makeSelectorBold]\\n\\t\\tifNil: [self theClass sourceCodeTemplate]! !\\n\\n\\n!OBMethodDefinition methodsFor: 'accessing' stamp: 'cwp 10/17/2004 23:36'!\\ncallback: aBlockContext \\n\\tcallback _ aBlockContext! !\\n\\n!OBMethodDefinition methodsFor: 'accessing'!\\ncategory\\n\\t^ category ifNil: [category := self theClass whichCategoryIncludesSelector: self selector]! !\\n\\n!OBMethodDefinition methodsFor: 'accessing'!\\nselector\\n\\t^ source ifNotNil: [Parser new parseSelector: source]! !\\n\\n!OBMethodDefinition methodsFor: 'accessing'!\\ntheClass\\n\\t^ theClass! !\\n\\n\\n!OBMethodDefinition methodsFor: 'compiling'!\\ncompileMethod: aText notifying: aController\\n\\t^ (self confirmMethod: aText)\\n\\t\\tifTrue: [self theClass \\n\\t\\t\\t\\t\\tcompile: aText \\n\\t\\t\\t\\t\\tclassified: self category \\n\\t\\t\\t\\t\\tnotifying: aController]\\n\\t\\tifFalse: [nil]! !\\n\\n!OBMethodDefinition methodsFor: 'compiling' stamp: 'cwp 10/17/2004 23:33'!\\nnodeFor: aSelector\\n\\t^ callback value: aSelector! !\\n\\n\\n!OBMethodDefinition methodsFor: 'confirming' stamp: 'cwp 10/17/2004 22:42'!\\nconfirmMethod: aText\\n\\t| sel |\\n\\tsel _ Parser new parseSelector: aText.\\n\\t^ (self theClass isMeta \\n\\t\\t\\tand: [(self selectorAlreadyDefined: sel) not] \\n\\t\\t\\tand: [Metaclass isScarySelector: sel])\\n\\t\\t\\t\\tifTrue: [self confirmScarySelector: sel]\\n\\t\\t\\t\\tifFalse: [^ true]! !\\n\\n!OBMethodDefinition methodsFor: 'confirming'!\\nconfirmScarySelector: aSelector\\n\\t| prompt |\\n\\tprompt := aSelector, ' is used in the existing class system.\\nOverriding it could cause serious problems.\\nIs this really what you want to do?'.\\n\\n\\t^ OBConfirmationRequest\\n\\t\\tprompt: prompt\\n\\t\\tconfirm: 'Override'! !\\n\\n!OBMethodDefinition methodsFor: 'confirming'!\\nselectorAlreadyDefined: aSelector\\n\\t^ self theClass selectors includes: aSelector! !\\n\\n\\n!OBMethodDefinition methodsFor: 'initializing' stamp: 'cwp 10/17/2004 23:33'!\\nsetClass: aClass category: aString source: aText selection: anInterval\\n\\ttheClass := aClass.\\n\\tcategory := aString.\\n\\tsource := aText.\\n\\tselection := anInterval.\\n\\tcallback := [:sel | OBMethodNode on: sel inClass: theClass]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBMethodDefinition class\\n\\tinstanceVariableNames: ''!\\n\\n!OBMethodDefinition class methodsFor: 'instance creation' stamp: 'cwp 10/17/2004 23:07'!\\ninCategory: aString inClass: aClass\\n\\t^ self \\n\\t\\tselection: nil\\n\\t\\tsource: nil\\n\\t\\tinCategory: aString\\n\\t\\tinClass: aClass! !\\n\\n!OBMethodDefinition class methodsFor: 'instance creation' stamp: 'cwp 10/17/2004 23:07'!\\nselection: anInterval source: aText inCategory: aCategory inClass: aClass\\n\\t^ self new\\n\\t\\tsetClass: aClass\\n\\t\\tcategory: aCategory\\n\\t\\tsource: aText\\n\\t\\tselection: anInterval! !\\n\\n!OBMethodDefinition class methodsFor: 'instance creation' stamp: 'cwp 10/17/2004 23:07'!\\nselection: anInterval source: aText inClass: aClass\\n\\t^ self \\n\\t\\tselection: anInterval\\n\\t\\tsource: aText\\n\\t\\tinCategory: nil\\n\\t\\tinClass: aClass\\t! !\\n\\n!OBMethodDefinition class methodsFor: 'instance creation' stamp: 'cwp 10/17/2004 23:03'!\\nsource: aText inClass: aClass\\n\\t^ self \\n\\t\\tselection: nil\\n\\t\\tsource: aText\\n\\t\\tinCategory: nil\\n\\t\\tinClass: aClass! !\\nOBClassAwareNode subclass: #OBMethodNode\\n\\tinstanceVariableNames: 'selector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBMethodNode commentStamp: 'cwp 1/8/2005 12:37' prior: 0!\\nOBMethodNode wraps a method in a particular class. It supplies an OBMethodDefinition for displaying and editing the source code of the method, and various actions for manipulating the method. It has two roles: first it appears in the right most pane of a standard system browser. Second, it often serves as the root node for an OBListBrowser, and has navigation methods for senders, implementors etc.\\n\\nOBMethodNode also serves as the superclass for nodes that represent *parts* of a method, such as sends of a particular message, references to a class, accesses to a instance variable, etc.!\\n\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'cwp 7/12/2006 15:36'!\\nactions\\n\\t^{ \\n\\t\\tself action: #fileOut withLabel: 'file out'.\\n\\t\\tself browseAction.\\n\\t\\tself browseHierarchyAction.\\n\\t\\tself \\n\\t\\t\\taction: #browseSenders\\n\\t\\t\\twithMenuLabel: 'senders'\\n\\t\\t\\twithButtonLabel: 'senders'\\n\\t\\t\\twithKeystroke: $n\\n\\t\\t\\twithIcon: (MenuIcons tryIcons: #(findIcon smallFindIcon)).\\n\\t\\tself \\n\\t\\t\\taction: #browseImplementors\\n\\t\\t\\twithMenuLabel: 'implementors'\\n\\t\\t\\twithButtonLabel: 'implementors'\\n\\t\\t\\twithKeystroke: $m\\n\\t\\t\\twithIcon: (MenuIcons tryIcons: #(findIcon smallFindIcon)).\\n\\t\\tself \\n\\t\\t\\taction: #browseVersions\\n\\t\\t\\tbuttonLabel: 'versions'\\n\\t\\t\\tmenuLabel: 'versions'.\\n\\t\\tself \\n\\t\\t\\taction: #browseInheritance\\n\\t\\t\\tbuttonLabel: 'inheritance'\\n\\t\\t\\tmenuLabel: 'inheritance'.\\n\\t\\tself \\n\\t\\t\\taction: #chaseVars\\n\\t\\t\\tbuttonLabel: 'variables'\\n\\t\\t\\tmenuLabel: 'chase variables'.\\n\\t\\tself \\n\\t\\t\\taction: #remove\\n\\t\\t\\twithLabel: 'remove'\\n\\t\\t\\twithKeystroke: $x\\n\\t\\t\\twithIcon: (MenuIcons tryIcons: #(deleteIcon smallDeleteIcon)).\\n\\t\\tself moveToPackageAction\\n\\t}\\n! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'cwp 12/5/2004 18:35'!\\nbrowse\\n\\tOBSystemBrowser openOnClass: self theClass selector: selector! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'avi 9/17/2005 01:29'!\\nbrowseClass: aClass\\n\\taClass browseRoot: self copy! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'avi 9/17/2005 01:28'!\\nbrowseImplementors\\n\\tself browseClass: OBImplementorsBrowser! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'cwp 12/5/2004 18:03'!\\nbrowseInheritance\\n\\tOBInheritanceBrowser openRoot: self inheritanceRoot selection: self! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'avi 9/17/2005 01:28'!\\nbrowseSenders\\n\\tself browseClass: OBSendersBrowser! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'cwp 12/5/2004 15:42'!\\nbrowseVersions\\n\\tOBVersionBrowser openOn: self copy! !\\n\\n!OBMethodNode methodsFor: 'actions'!\\nfileOut\\n\\tself theClass fileOutMethod: selector! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'cwp 7/11/2006 02:43'!\\nmoveToPackage\\n\\t| packagesNames selection packages |\\n\\tpackages := PackageOrganizer default packages \\n\\t\\t\\t\\t\\tasSortedCollection: [:a :b | a packageName <= b packageName].\\n\\tpackagesNames := packages collect: [:ea | ea packageName].\\n\\tselection := OBChoiceRequest prompt: nil labels: packagesNames values: packages.\\n\\tselection ifNotNil: [selection addMethod: self reference].! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'cwp 7/12/2006 15:37'!\\nmoveToPackageAction\\n\\t^ self \\n\\t\\taction: #moveToPackage\\n\\t\\twithMenuLabel: 'move to package...'\\n\\t\\twithButtonLabel: 'move method'\\n\\t\\twithKeystroke: $p\\n\\t\\twithIcon: (MenuIcons tryIcons: #(windowIcon smallWindowIcon)).\\n! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'cwp 10/18/2004 00:30'!\\nremove\\n\\t| senders choice |\\n\\tsenders _ SystemNavigation default allCallsOn: self selector.\\n\\tsenders isEmpty ifTrue: [^ self doRemove].\\n\\tchoice _ OBChoiceRequest\\n\\t\\t\\t\\tprompt: 'This message has ', senders size asString, ' senders.'\\n\\t\\t\\t\\tlabels: #('Remove it' \\n\\t\\t\\t\\t\\t\\t'Remove, then browse senders' \\n\\t\\t\\t\\t\\t\\t'Don''t remove, but show me those senders' \\n\\t\\t\\t\\t\\t\\t'Forget it -- do nothing -- sorry I asked')\\n\\t\\t\\t\\tvalues: #(doRemove removeAndBrowse simpleBrowseSenders nil).\\n\\tchoice ifNotNil: [^ self perform: choice]\\n! !\\n\\n!OBMethodNode methodsFor: 'actions'!\\nselectMessage\\n\\t| messages sel |\\n\\tmessages := self messageSelectors copyWithFirst: selector.\\n\\tsel := (OBChoiceRequest labels: messages).\\n\\t^ sel ifNotNil: [OBMessageNode on: sel inMethodNode: self]! !\\n\\n!OBMethodNode methodsFor: 'actions' stamp: 'cwp 12/1/2004 00:36'!\\nsource\\n\\t^ (self theClass sourceCodeAt: self selector ifAbsent: [^ '']) \\n\\t\\tasText makeSelectorBold! !\\n\\n\\n!OBMethodNode methodsFor: 'private'!\\naddOverridersOf: aSelector inClass: aClass to: aCollection\\n\\taClass subclasses do: \\n\\t\\t[:ea | (ea includesSelector: aSelector)\\n\\t\\t\\t\\t\\tifTrue: [aCollection add: ea]\\n\\t\\t\\t\\t\\tifFalse: [self addOverridersOf: aSelector inClass: ea to: aCollection]]! !\\n\\n!OBMethodNode methodsFor: 'private' stamp: 'cwp 10/18/2004 00:29'!\\ndoRemove\\n\\tself theClass removeSelector: self selector.\\n\\tself signalDeletion! !\\n\\n!OBMethodNode methodsFor: 'private' stamp: 'cwp 12/8/2004 23:48'!\\nimplementorsOf: aSelector\\n\\t^ (SystemNavigation default allImplementorsOf: aSelector) asSortedArray\\n\\t\\t\\tcollect: [:ref | OBMethodNode on: ref]! !\\n\\n!OBMethodNode methodsFor: 'private' stamp: 'cwp 12/8/2004 23:49'!\\ninheritanceRoot\\n\\t| rootClass |\\n\\trootClass := (self theClass withAllSuperclasses asArray\\n\\t\\t\\t\\t\\tselect: [:ea | ea includesSelector: self selector]) last.\\n\\t^ OBCollectionNode on: {OBMethodNode \\n\\t\\t\\t\\t\\t\\t\\t\\ton: self selector \\n\\t\\t\\t\\t\\t\\t\\t\\tinClass: rootClass}! !\\n\\n!OBMethodNode methodsFor: 'private'!\\nmessageSelectors\\n\\t^ ((self theClass compiledMethodAt: self selector ifAbsent: [^ #()]) messages) asSortedArray! !\\n\\n!OBMethodNode methodsFor: 'private'!\\nremoveAndBrowse\\n\\tself simpleBrowseSenders.\\n\\tself theClass removeSelector: self selector.\\n\\tself signalDeletion! !\\n\\n!OBMethodNode methodsFor: 'private'!\\nsendersOf: aSelector\\n\\t^ (SystemNavigation default allCallsOn: aSelector) asSortedArray\\n\\t\\t\\tcollect: [:ref | OBMessageNode on: aSelector inMethodReference: ref]! !\\n\\n!OBMethodNode methodsFor: 'private' stamp: 'avi 9/17/2005 01:29'!\\nsimpleBrowseSenders\\n\\tOBSendersBrowser browseRoot: self! !\\n\\n!OBMethodNode methodsFor: 'private'!\\nsourcePointer\\n\\t^ (self theClass compiledMethodAt: self selector) sourcePointer! !\\n\\n\\n!OBMethodNode methodsFor: 'ancestry'!\\nancestrySelector\\n\\t^ #isDescendantOfMethod: ! !\\n\\n!OBMethodNode methodsFor: 'ancestry' stamp: 'cwp 12/2/2004 23:28'!\\nisDescendantOfMethodCat: aMethodCatNode\\n\\t^ (self theClass organization categoryOfElement: self selector) = aMethodCatNode name! !\\n\\n!OBMethodNode methodsFor: 'ancestry' stamp: 'cwp 10/17/2004 23:55'!\\nisDescendantOfMethodVersion: anOBMethodVersionNode \\n\\t^ false! !\\n\\n!OBMethodNode methodsFor: 'ancestry' stamp: 'cwp 11/28/2004 10:37'!\\nisDescendantOfMethod: other\\n\\t^ other selector = selector\\n\\t\\tand: [self theClass withAllSuperclasses includes: other theClass].\\n\\t! !\\n\\n\\n!OBMethodNode methodsFor: 'accessing' stamp: 'cwp 12/1/2004 00:36'!\\ndefinition\\n\\t^ OBMethodDefinition\\n\\t\\tselection: self selection\\n\\t\\tsource: self source\\n\\t\\tinClass: self theClass! !\\n\\n!OBMethodNode methodsFor: 'accessing'!\\nreference\\n\\t^ self referenceForMethod: selector ofClass: self theClassName! !\\n\\n!OBMethodNode methodsFor: 'accessing' stamp: 'cwp 12/1/2004 00:37'!\\nselection\\n\\t^ 1 to: 0! !\\n\\n!OBMethodNode methodsFor: 'accessing'!\\nselector\\n\\t^ selector! !\\n\\n!OBMethodNode methodsFor: 'accessing'!\\nsourceFiles\\n\\t^ OBSourceFilesRequest signal! !\\n\\n\\n!OBMethodNode methodsFor: 'drag and drop' stamp: 'lr 4/18/2006 08:55'!\\ndropOnClass: aNode\\n\\taNode theClass \\n\\t\\tcompile: self source\\n\\t\\tclassified: (self theClass organization \\n\\t\\t\\tcategoryOfElement: self selector).\\n\\tInputSensor default shiftPressed\\n\\t\\tifFalse: [ self theClass removeSelector: self selector ].\\n\\taNode signalChildrenChanged.\\n\\t^ true! !\\n\\n!OBMethodNode methodsFor: 'drag and drop' stamp: 'cwp 9/18/2005 19:01'!\\ndropOnMethodCategory: aNode\\n\\n\\t\\\"We don't support dropping on another class yet.\\\"\\n\\taNode theClass = self theClass ifFalse: [^ false].\\n\\t\\n\\tself theClass organization classify: self selector under: aNode name.\\n\\taNode signalChildrenChanged.\\n\\t\\n\\t^ true! !\\n\\n\\n!OBMethodNode methodsFor: 'displaying' stamp: 'lr 3/29/2006 12:08'!\\ndisplayString\\n\\t^ (self theClass respondsTo: #includesLocalSelector:) \\n\\t\\tifFalse: [ super displayString ]\\n\\t\\tifTrue: [\\n\\t\\t\\t(self theClass includesLocalSelector: selector)\\n\\t\\t\\t\\tifTrue: [ super displayString ]\\n\\t\\t\\t\\tifFalse: [ \\n\\t\\t\\t\\t\\tsuper displayString asText \\n\\t\\t\\t\\t\\t\\taddAttribute: TextEmphasis italic ] ]! !\\n\\n!OBMethodNode methodsFor: 'displaying' stamp: 'cwp 12/8/2004 21:08'!\\nfullName\\n\\t^ self theClassName, '>>', selector! !\\n\\n!OBMethodNode methodsFor: 'displaying' stamp: 'cwp 12/20/2004 23:13'!\\nindentedFullName\\n\\t^ self indent, self fullName! !\\n\\n!OBMethodNode methodsFor: 'displaying' stamp: 'cwp 12/8/2004 21:08'!\\nname\\n\\t^ selector! !\\n\\n\\n!OBMethodNode methodsFor: 'comparing' stamp: 'cwp 12/8/2004 22:07'!\\nhash\\n\\t^ theClass hash bitXor: selector hash! !\\n\\n!OBMethodNode methodsFor: 'comparing' stamp: 'cwp 12/8/2004 22:07'!\\n= other\\n\\t^ (self species = other species)\\n\\t\\tand: [self theClass = other theClass] \\n\\t\\tand: [self selector = other selector]! !\\n\\n\\n!OBMethodNode methodsFor: 'navigating' stamp: 'cwp 1/2/2005 23:12'!\\nimplementors\\n\\t^ self implementorsOf: selector! !\\n\\n!OBMethodNode methodsFor: 'navigating' stamp: 'cwp 1/7/2005 22:35'!\\nimplementorsHierarchically\\n\\t^ OBClassAwareNode sortHierarchically: self implementors! !\\n\\n!OBMethodNode methodsFor: 'navigating'!\\nmessages\\n\\t^ (((self theClass\\n\\t\\t\\t\\tcompiledMethodAt: self selector \\n\\t\\t\\t\\tifAbsent: [^ #()]) messages) asSortedArray)\\n\\t\\t\\t\\t\\tcollect: [:sel | OBMessageNode \\n\\t\\t\\t\\t\\t\\t\\t\\t\\ton: sel \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tinMethod: selector \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tinClass: self theClass]! !\\n\\n!OBMethodNode methodsFor: 'navigating' stamp: 'cwp 12/8/2004 23:49'!\\noverrides\\n\\t| classes |\\n\\tclasses := OrderedCollection new.\\n\\tself addOverridersOf: self selector inClass: self theClass to: classes.\\n\\t^ classes collect: [:ea | OBMethodNode on: selector inClass: ea] ! !\\n\\n!OBMethodNode methodsFor: 'navigating'!\\nselectorAndMessages\\n\\t^ self messages copyWithFirst: self messageNode! !\\n\\n!OBMethodNode methodsFor: 'navigating'!\\nsenders\\n\\t^ self sendersOf: selector! !\\n\\n!OBMethodNode methodsFor: 'navigating'!\\nversions\\n\\t^ (OBMethodVersion scan: self sourceFiles from: self sourcePointer)\\n\\t\\tcollect: [:ea | OBMethodVersionNode on: ea]! !\\n\\n\\n!OBMethodNode methodsFor: 'nodes'!\\nmessageNode\\n\\t^ OBMessageNode fromMethodNode: self! !\\n\\n\\n!OBMethodNode methodsFor: 'printing' stamp: 'cwp 12/8/2004 21:59'!\\nprintOn: aStream\\n\\taStream\\n\\t\\tnextPutAll: self class name;\\n\\t\\tnextPut: $<;\\n\\t\\tnextPutAll: self theClass name;\\n\\t\\tnextPut: $#;\\n\\t\\tnextPutAll: self selector;\\n\\t\\tnextPut: $>! !\\n\\n\\n!OBMethodNode methodsFor: 'initializing'!\\nsetReference: aMethodReference\\n\\tself \\n\\t\\tsetSelector: aMethodReference methodSymbol\\n\\t\\tclass: (aMethodReference actualClass)! !\\n\\n!OBMethodNode methodsFor: 'initializing'!\\nsetSelector: aSelector class: aClass\\n\\tselector := aSelector.\\n\\tself theClass: aClass\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBMethodNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBMethodNode class methodsFor: 'instance creation'!\\non: aMethodReference\\n\\t^ self new setReference: aMethodReference! !\\n\\n!OBMethodNode class methodsFor: 'instance creation'!\\non: aSelector inClass: aClassReference\\n\\t^ self new setSelector: aSelector class: aClassReference! !\\nObject subclass: #OBMethodVersion\\n\\tinstanceVariableNames: 'sources pointer classRef className category stamp prior selector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Utilities'!\\n!OBMethodVersion commentStamp: 'cwp 1/8/2005 13:25' prior: 0!\\nOBMethodVerison represents a version of a method found in the .sources or .changes files. It provides methods for parsing the method definition referenced by a source pointer, and for filing in the source to replace the current version of the method.!\\n\\n\\n!OBMethodVersion methodsFor: 'accessing'!\\ncategory\\n\\t^ category! !\\n\\n!OBMethodVersion methodsFor: 'accessing'!\\nclassSymbol\\n\\t^ classRef name! !\\n\\n!OBMethodVersion methodsFor: 'accessing' stamp: 'cwp 10/17/2004 23:51'!\\nlatest\\n\\t^ self class \\n\\t\\t\\tfromSources: sources \\n\\t\\t\\tandPointer: (classRef theClass compiledMethodAt: selector) sourcePointer! !\\n\\n!OBMethodVersion methodsFor: 'accessing' stamp: 'cwp 10/17/2004 23:42'!\\npointer\\n\\t^ pointer! !\\n\\n!OBMethodVersion methodsFor: 'accessing'!\\nselector\\n\\t^ selector ifNil: [self setSelector]! !\\n\\n!OBMethodVersion methodsFor: 'accessing'!\\nsource\\n\\t| file |\\n\\tfile := sources at: (sources fileIndexFromSourcePointer: pointer).\\n\\tfile position: (sources filePositionFromSourcePointer: pointer).\\n\\t^ file nextChunk asText makeSelectorBold! !\\n\\n!OBMethodVersion methodsFor: 'accessing'!\\nstamp\\n\\t^ stamp! !\\n\\n!OBMethodVersion methodsFor: 'accessing'!\\ntheClass\\n\\t^ classRef theClass! !\\n\\n!OBMethodVersion methodsFor: 'accessing'!\\ntheClassName\\n\\t^ classRef name! !\\n\\n\\n!OBMethodVersion methodsFor: 'compiling'!\\nfileIn\\n\\t(self theClass) ifNotNilDo: [:class | class\\n\\t\\t\\t\\t\\t\\t \\t\\t\\t\\tcompile: self source \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tclassified: self category \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\twithStamp: self stamp \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tnotifying: nil]\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t! !\\n\\n\\n!OBMethodVersion methodsFor: 'comparing' stamp: 'cwp 10/17/2004 23:45'!\\nhash\\n\\t^ pointer hash! !\\n\\n!OBMethodVersion methodsFor: 'comparing' stamp: 'cwp 10/17/2004 23:45'!\\n= other\\n\\t^ self species = other species and: [self pointer = other pointer]! !\\n\\n\\n!OBMethodVersion methodsFor: 'initializing' stamp: 'cwp 11/6/2004 23:14'!\\nparseChunk: aString\\n\\t| tokens |\\n\\ttokens := Scanner new scanTokens: aString.\\n\\tclassRef := OBClassReference named: tokens first.\\n\\ttokens second = #class\\n\\t\\tifTrue: [classRef beMeta.\\n\\t\\t\\t\\tcategory := tokens fourth.\\n\\t\\t\\t\\tstamp := tokens sixth]\\n\\t\\tifFalse: [category := tokens third.\\n\\t\\t\\t\\ttokens size > 3 ifTrue: [stamp := tokens fifth]].\\n\\ttokens size > 6 ifTrue: [prior := tokens last].! !\\n\\n!OBMethodVersion methodsFor: 'initializing'!\\nparseSource\\n\\t| file position chunk |\\n\\tfile := sources at: (sources fileIndexFromSourcePointer: pointer).\\n\\tposition := sources filePositionFromSourcePointer: pointer.\\n\\tposition > file size ifTrue: [self error: 'Invalid source pointer'].\\n\\t\\n\\tfile position: (0 max: position-150). \\t\\\"Skip back to before the preamble\\\"\\n\\t\\t[file position < (position-1)] \\t\\\"then pick it up from the front\\\"\\n\\t\\t\\twhileTrue: [chunk := file nextChunk].\\n\\t\\n\\tself parseChunk: chunk.! !\\n\\n!OBMethodVersion methodsFor: 'initializing'!\\nprevious\\n\\t^ prior ifNotNil: [self class fromSources: sources andPointer: prior]! !\\n\\n!OBMethodVersion methodsFor: 'initializing'!\\nsetSelector\\n\\t| file |\\n\\tfile := sources at: (sources fileIndexFromSourcePointer: pointer).\\n\\tfile position: (sources filePositionFromSourcePointer: pointer).\\n\\t^ selector := Parser new parseSelector: file nextChunk.! !\\n\\n!OBMethodVersion methodsFor: 'initializing'!\\nsetSources: aSourceFileArray pointer: aSourcePointer\\n\\tsources := aSourceFileArray.\\n\\tpointer := aSourcePointer.\\n\\tself parseSource.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBMethodVersion class\\n\\tinstanceVariableNames: ''!\\n\\n!OBMethodVersion class methodsFor: 'instance creation'!\\nfromSources: sources andPointer: pointer\\n\\t^ self new setSources: sources pointer: pointer! !\\n\\n\\n!OBMethodVersion class methodsFor: 'scanning'!\\nscan: sources from: pointer \\n\\t| versions current |\\n\\t\\n\\tversions := OrderedCollection new.\\n\\tcurrent := OBMethodVersion fromSources: sources andPointer: pointer.\\n\\t[current notNil]\\n\\t\\twhileTrue: [versions add: current.\\n\\t\\t\\t\\t\\tcurrent := current previous].\\n\\t^ versions! !\\n\\n!OBMethodVersion class methodsFor: 'scanning'!\\nversionsOfMethod: methodReference \\n\\t| class selector |\\n\\tclass := methodReference actualClass.\\n\\tselector := methodReference methodSymbol.\\n\\t^ self scan: SourceFiles from: (class compiledMethodAt: selector) sourcePointer! !\\nOBClassAwareNode subclass: #OBMethodVersionNode\\n\\tinstanceVariableNames: 'version'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBMethodVersionNode commentStamp: 'cwp 1/8/2005 12:41' prior: 0!\\nOBMethodVersions refer to OBMethodVersions, and are used by the VersionBrowser.!\\n\\n\\n!OBMethodVersionNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 22:38'!\\nactions\\n\\t^ {\\n\\t\\tself browseAction.\\n\\t \\tself action: #revert buttonLabel: 'revert' menuLabel: 'revert to selected version'\\n\\t}! !\\n\\n!OBMethodVersionNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 21:51'!\\nbrowse\\n\\tOBSystemBrowser openOnClass: self theClass selector: version selector! !\\n\\n!OBMethodVersionNode methodsFor: 'actions'!\\nrevert\\n\\tversion fileIn! !\\n\\n\\n!OBMethodVersionNode methodsFor: 'ancestry' stamp: 'cwp 10/17/2004 23:41'!\\nancestrySelector\\n\\t^ #isDescendantOfMethodVersion:! !\\n\\n!OBMethodVersionNode methodsFor: 'ancestry' stamp: 'cwp 10/17/2004 23:43'!\\nisDescendantOfMethodVersion: aNode\\n\\t^ (version = aNode version)! !\\n\\n\\n!OBMethodVersionNode methodsFor: 'accessing' stamp: 'cwp 10/17/2004 23:57'!\\ncategory\\n\\t^ self theClass organization categoryOfElement: version selector! !\\n\\n!OBMethodVersionNode methodsFor: 'accessing'!\\nreference\\n\\t^ self referenceForMethod: version selector ofClass: self theClassName.! !\\n\\n!OBMethodVersionNode methodsFor: 'accessing' stamp: 'cwp 10/17/2004 23:44'!\\nversion\\n\\t^ version! !\\n\\n\\n!OBMethodVersionNode methodsFor: 'compiling' stamp: 'cwp 10/17/2004 23:53'!\\ndefinition\\n\\t^ (OBMethodDefinition source: version source inClass: self theClass)\\n\\t\\tcallback: [:sel | \\n\\t\\t\\t\\t\\tversion selector = sel\\n\\t\\t\\t\\t\\t\\tifTrue: [self class on: version latest]\\n\\t\\t\\t\\t\\t\\tifFalse: [OBMethodNode on: sel inClass: self theClass]]! !\\n\\n\\n!OBMethodVersionNode methodsFor: 'displaying' stamp: 'cwp 11/27/2004 21:38'!\\nname\\n\\t| stamp |\\n\\tstamp := version stamp ifNil: ['<timestamp missing>'].\\n\\t^ version theClassName, '>>', version selector, ' ', stamp! !\\n\\n\\n!OBMethodVersionNode methodsFor: 'initializing'!\\nsetVersion: aMethodVersion\\n\\tversion := aMethodVersion.\\n\\tself theClass: version theClass! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBMethodVersionNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBMethodVersionNode class methodsFor: 'instance creation'!\\non: aMethodVersion \\n\\t^ self new setVersion: aMethodVersion! !\\nOBFilter subclass: #OBModalFilter\\n\\tinstanceVariableNames: 'selection'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Utilities'!\\n!OBModalFilter commentStamp: 'cwp 1/7/2005 23:39' prior: 0!\\nOBModalFilter is used to implement the 'instance/?/class' buttons in a standard class browser. In functional terms it filters the nodes of a column according to the edge of the metagraph that they correspond to. OBModalFilter displays an OBRadioButtonBar in its column's pane, with one button per edge. Only nodes from the currently selected edge are allowed in the column.\\n\\niVars:\\n\\nselection\\t- the currently selected edge!\\n\\n\\n!OBModalFilter methodsFor: 'callbacks' stamp: 'cwp 2/25/2004 00:28'!\\nlist\\n\\t^ metaNode edges collect: [:edge | edge label]! !\\n\\n!OBModalFilter methodsFor: 'callbacks' stamp: 'cwp 2/9/2004 21:10'!\\nselection\\n\\t^ selection ifNil: [selection _ 1]! !\\n\\n!OBModalFilter methodsFor: 'callbacks' stamp: 'cwp 6/6/2006 00:20'!\\nselection: anInteger\\n\\tselection _ anInteger.\\n\\tself changed: #selection.\\n\\tmonitor listChanged.\\n! !\\n\\n\\n!OBModalFilter methodsFor: 'morphs' stamp: 'cwp 11/27/2004 18:01'!\\nbuttonMorph\\n\\t^ OBRadioButtonBar\\n\\t\\ton: self\\n\\t\\tlist: #list\\n\\t\\tselected: #selection\\n\\t\\tchangeSelected: #selection:! !\\n\\n\\n!OBModalFilter methodsFor: 'public' stamp: 'cwp 3/3/2004 00:23'!\\nnodesForParent: aNode\\n\\t^ self selectedEdge nodesForParent: aNode! !\\n\\n!OBModalFilter methodsFor: 'public' stamp: 'cwp 2/29/2004 14:35'!\\nselectAncestorOf: aNode withParent: parentNode\\n\\t| ancestor |\\n\\t1 \\tto: metaNode edges size \\n\\t \\tdo: [:i | selection _ i.\\n\\t\\t\\tancestor _ (self nodesForParent: parentNode)\\n\\t\\t\\t\\tdetect: [:child | child isAncestorOf: aNode] \\n\\t\\t\\t\\tifNone: [nil].\\n\\t\\t\\tancestor ifNotNil: [self changed: #selection. ^ ancestor]].\\n\\t^ nil! !\\n\\n\\n!OBModalFilter methodsFor: 'queries' stamp: 'cwp 2/9/2004 21:08'!\\nwantsButton\\n\\t^ true! !\\n\\n\\n!OBModalFilter methodsFor: 'selection' stamp: 'cwp 2/9/2004 21:11'!\\nincrementSelection\\n\\tselection _ selection + 1.\\n\\t(selection > metaNode edges size) ifTrue: [selection _ 1].! !\\n\\n!OBModalFilter methodsFor: 'selection' stamp: 'cwp 2/9/2004 21:11'!\\nselectedEdge\\n\\t^ metaNode edges at: self selection ! !\\nObject subclass: #OBMorphicPanelLayout\\n\\tinstanceVariableNames: 'panels'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Morphic'!\\n!OBMorphicPanelLayout commentStamp: 'cwp 1/7/2005 23:42' prior: 0!\\nOBMorphicPanelLayout implements a somewhat hairy algorithm for layoung out panels in a morphic SystemWindow. It is the default layout strategy used by OBBrowser. Subclasses of OBBrowser may use other layout strategies to customize their appearance.!\\n\\n\\n!OBMorphicPanelLayout methodsFor: 'initializing' stamp: 'cwp 11/21/2004 00:23'!\\nsetPanels: aCollection \\n\\tpanels := aCollection! !\\n\\n\\n!OBMorphicPanelLayout methodsFor: 'public' stamp: 'cwp 11/21/2004 00:26'!\\naddMorphsTo: aMorph\\n\\tself addNavMorphTo: aMorph.\\n\\t(panels size > 1) ifTrue: [self addOtherMorphsTo: aMorph].\\n\\t! !\\n\\n\\n!OBMorphicPanelLayout methodsFor: 'private' stamp: 'cwp 11/21/2004 00:25'!\\naddNavMorphTo: aMorph\\n\\taMorph \\n\\t\\taddMorph: self navigationPanel buildScroller\\n\\t\\tfullFrame: (LayoutFrame fractions: (0 @ 0 extent: 1 @ self columnProportion)).\\n! !\\n\\n!OBMorphicPanelLayout methodsFor: 'private' stamp: 'cwp 11/21/2004 00:37'!\\naddOtherMorphsTo: aMorph\\n\\t| heights variableCount fraction offset vExtent h nonNavPanels |\\n\\tnonNavPanels := panels reject: [:ea | ea isNavigation].\\n\\tnonNavPanels isEmpty ifTrue: [^ self].\\n\\theights _ nonNavPanels collect: [:ea | ea morphHeight].\\n\\tvariableCount _ heights \\n\\t\\t\\t\\t\\t\\tinject: 0 \\n\\t\\t\\t\\t\\t\\tinto: [:count :ea | ea = 0 ifTrue: [count + 1] ifFalse: [count]].\\n\\tfraction _ self columnProportion.\\n\\toffset _ 0.\\n\\tvExtent _ 1- fraction / variableCount.\\n\\tnonNavPanels with: heights do: [:panel :height | \\n\\t\\th _ height = 0 ifTrue: [vExtent] ifFalse: [0].\\n\\t\\taMorph \\n\\t\\t\\taddMorph: panel morph\\n\\t\\t\\tfullFrame: (LayoutFrame\\n\\t\\t\\t\\t\\t\\t\\tfractions: (0@fraction extent: 1@h)\\n\\t\\t\\t\\t\\t\\t\\toffsets: (0@offset corner: 0@height)).\\n\\t\\theight = 0 \\n\\t\\t\\tifTrue: \\t[offset _ 0.\\n\\t\\t\\t\\t\\tfraction _ fraction + vExtent]\\n\\t\\t\\tifFalse: \\t[offset _ offset + height]]\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\n\\t\\t\\t\\t\\t\\t! !\\n\\n!OBMorphicPanelLayout methodsFor: 'private' stamp: 'cwp 11/21/2004 00:26'!\\ncolumnProportion\\n\\t^ panels size = 1\\n\\t\\tifTrue: [1]\\n\\t\\tifFalse: [0.4]! !\\n\\n!OBMorphicPanelLayout methodsFor: 'private' stamp: 'cwp 11/21/2004 00:28'!\\nnavigationPanel\\n\\t^ panels detect: [:ea | ea isNavigation]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBMorphicPanelLayout class\\n\\tinstanceVariableNames: ''!\\n\\n!OBMorphicPanelLayout class methodsFor: 'intance creation' stamp: 'cwp 11/20/2004 23:32'!\\nfor: aCollection\\n\\t^ self new setPanels: aCollection! !\\nObject subclass: #OBNode\\n\\tinstanceVariableNames: 'metaNode'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Kernel'!\\n!OBNode commentStamp: 'cwp 3/4/2004 22:20' prior: 0!\\nA node is a wrapper for an object in the browser's domain graph. OBNode is an abstract superclass for concrete nodes which might appear in the browser.\\n\\niVars:\\n\\nmetaNode - the MetaNode which produced this node!\\n\\n\\n!OBNode methodsFor: 'accessing' stamp: 'cwp 3/3/2004 23:24'!\\nmetaNode\\n\\t^ metaNode! !\\n\\n!OBNode methodsFor: 'accessing' stamp: 'cwp 3/3/2004 23:24'!\\nmetaNode: aMetaNode\\n\\tmetaNode _ aMetaNode! !\\n\\n\\n!OBNode methodsFor: 'ancestry' stamp: 'cwp 3/3/2004 00:44'!\\nancestrySelector\\n\\t^ #isDescendantOf: ! !\\n\\n!OBNode methodsFor: 'ancestry' stamp: 'cwp 3/3/2004 01:47'!\\nisAncestorOf: aNode\\n\\t^ aNode perform: self ancestrySelector with: self! !\\n\\n!OBNode methodsFor: 'ancestry' stamp: 'cwp 3/3/2004 00:44'!\\nisDescendantOf: aNode\\n\\t^ false! !\\n\\n\\n!OBNode methodsFor: 'comparing' stamp: 'cwp 7/14/2006 12:37'!\\ncorrespondsWith: aNode\\n\\t^ self displayString = aNode displayString! !\\n\\n!OBNode methodsFor: 'comparing' stamp: 'cwp 1/31/2004 14:57'!\\nhash\\n\\t^ self name hash! !\\n\\n!OBNode methodsFor: 'comparing' stamp: 'cwp 1/31/2004 14:57'!\\n= other\\n\\t^ self class = other class and: [self name = other name]! !\\n\\n\\n!OBNode methodsFor: 'displaying' stamp: 'cwp 12/8/2004 21:36'!\\ndisplayString\\n\\t^ self perform: metaNode displaySelector! !\\n\\n!OBNode methodsFor: 'displaying' stamp: 'cwp 8/28/2004 00:14'!\\ntitle\\n\\t^ nil! !\\n\\n\\n!OBNode methodsFor: 'drag and drop' stamp: 'cwp 3/2/2004 21:28'!\\nacceptDroppedNode: aNode\\n \\t^ aNode perform: self dropSelector with: self\\n! !\\n\\n!OBNode methodsFor: 'drag and drop' stamp: 'avi 2/20/2004 14:00'!\\nasDraggableMorph\\n\\t^(StringMorph contents: self name)\\n\\t\\tcolor: Color white;\\n\\t\\tyourself! !\\n\\n!OBNode methodsFor: 'drag and drop' stamp: 'cwp 3/2/2004 21:29'!\\ndropSelector\\n\\t\\\"Override in subclasses\\\"\\n\\t\\n\\t^ #dropOnNode: ! !\\n\\n!OBNode methodsFor: 'drag and drop' stamp: 'cwp 3/2/2004 21:28'!\\nwantsDroppedNode: aNode\\n\\t^ aNode respondsTo: self dropSelector! !\\n\\n\\n\\n!OBNode methodsFor: 'public' stamp: 'cwp 2/29/2004 13:49'!\\naccept: aText notifying: aController\\n\\t^ self text: aText! !\\n\\n!OBNode methodsFor: 'public' stamp: 'cwp 1/7/2004 09:25'!\\nactions\\n\\t^ #()! !\\n\\n!OBNode methodsFor: 'public' stamp: 'cwp 3/22/2004 20:48'!\\ndefinition\\n\\t^ self! !\\n\\n!OBNode methodsFor: 'public' stamp: 'dvf 8/17/2005 13:57'!\\ndisplayName\\n\\t\\\"expected to return a decorated text (rather than string) version of name\\\"\\n\\t^self name asText! !\\n\\n!OBNode methodsFor: 'public' stamp: 'cwp 12/10/2003 22:27'!\\nname\\n\\tself subclassResponsibility! !\\n\\n!OBNode methodsFor: 'public' stamp: 'cwp 12/7/2003 19:27'!\\ntext\\n\\t^ ''! !\\n\\n!OBNode methodsFor: 'public' stamp: 'cwp 2/29/2004 18:30'!\\ntextSelection\\n\\t^ 1 to: 0! !\\n\\n!OBNode methodsFor: 'public' stamp: 'cwp 3/14/2004 14:09'!\\ntext: aText\\n\\t^ false! !\\n\\n\\n!OBNode methodsFor: 'utility' stamp: 'cwp 3/10/2004 00:29'!\\naction: aSelector buttonLabel: buttonString menuLabel: menuString\\n\\t^ OBAction\\n\\t\\tlabel: menuString\\n\\t\\tbuttonLabel: buttonString\\n\\t\\treceiver: self\\n\\t\\tselector: aSelector\\n\\t\\targuments: #()! !\\n\\n!OBNode methodsFor: 'utility' stamp: 'cwp 2/3/2004 22:29'!\\naction: aSelector withLabel: aString\\n\\t^ OBAction\\n\\t\\tlabel: aString\\n\\t\\treceiver: self\\n\\t\\tselector: aSelector\\n\\t\\targuments: #()! !\\n\\n!OBNode methodsFor: 'utility' stamp: 'hpt 5/17/2004 16:51'!\\naction: aSelector withLabel: aString withIcon: anIcon\\n\\t^ OBAction\\n\\t\\tlabel: aString\\n\\t\\treceiver: self\\n\\t\\tselector: aSelector\\n\\t\\targuments: #()\\n\\t\\ticon: anIcon! !\\n\\n!OBNode methodsFor: 'utility' stamp: 'hpt 5/17/2004 14:28'!\\naction: aSelector withLabel: aString withKeystroke: aChar\\n\\t^ OBAction\\n\\t\\tlabel: aString\\n\\t\\treceiver: self\\n\\t\\tselector: aSelector\\n\\t\\targuments: #()\\n\\t\\tkeystroke: aChar! !\\n\\n!OBNode methodsFor: 'utility' stamp: 'hpt 5/17/2004 16:51'!\\naction: aSelector withLabel: aString withKeystroke: aChar withIcon: anIcon\\n\\t^ OBAction\\n\\t\\tlabel: aString\\n\\t\\treceiver: self\\n\\t\\tselector: aSelector\\n\\t\\targuments: #()\\n\\t\\tkeystroke: aChar\\n\\t\\ticon: anIcon! !\\n\\n!OBNode methodsFor: 'utility' stamp: 'cwp 12/5/2004 20:11'!\\naction: aSelector withMenuLabel: aString withButtonLabel: aString2 withKeystroke: aChar withIcon: anIcon \\n\\t^OBAction \\n\\t\\tlabel: aString\\n\\t\\tbuttonLabel: aString2\\n\\t\\treceiver: self\\n\\t\\tselector: aSelector\\n\\t\\targuments: #()\\n\\t\\tkeystroke: aChar\\n\\t\\ticon: anIcon! !\\n\\n!OBNode methodsFor: 'utility' stamp: 'cwp 2/7/2004 21:29'!\\nreferenceForMethod: selector ofClass: className\\n\\t| classIsMeta symbol |\\n\\tclassIsMeta _ className endsWith: ' class'.\\n\\tsymbol _ classIsMeta ifTrue: [(className allButLast: 6) asSymbol] ifFalse: [className].\\n\\t^ MethodReference new \\n\\t\\tsetClassSymbol: symbol\\n\\t\\tclassIsMeta: classIsMeta\\n\\t\\tmethodSymbol: selector\\n\\t\\tstringVersion: symbol, '>>', selector! !\\n\\n\\n!OBNode methodsFor: 'updating' stamp: 'cwp 6/4/2006 12:18'!\\nannounce: anObject\\n\\t^ OBAnnouncer current ifNotNilDo: [:announcer | announcer announce: anObject]! !\\n\\n!OBNode methodsFor: 'updating' stamp: 'cwp 6/4/2006 01:06'!\\ndemandSelection\\n\\t^ OBAnnouncer current announce: (OBNodeCreated node: self)! !\\n\\n!OBNode methodsFor: 'updating' stamp: 'cwp 6/4/2006 12:15'!\\nsignalChanged\\n\\tself announce: (OBNodeChanged node: self)! !\\n\\n!OBNode methodsFor: 'updating' stamp: 'cwp 6/4/2006 12:15'!\\nsignalChildrenChanged\\n\\tself announce: (OBChildrenChanged node: self)! !\\n\\n!OBNode methodsFor: 'updating' stamp: 'cwp 6/4/2006 12:15'!\\nsignalDeletion\\n\\tself announce: (OBNodeDeleted node: self)\\n! !\\n\\n!OBNode methodsFor: 'updating' stamp: 'cwp 6/4/2006 13:59'!\\nsignalSelection\\n\\t(self announce: OBAboutToChange)\\n\\t\\tisVetoed ifFalse: [self announce: (OBSelectingNode node: self)]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBNode class methodsFor: 'as yet unclassified' stamp: 'cwp 2/5/2004 20:25'!\\nactionsForParent: aNode\\n\\t^ #()! !\\n\\n!OBNode class methodsFor: 'as yet unclassified' stamp: 'cwp 12/18/2003 22:11'!\\nfromAssociation: anAssociationNode\\n\\t^ self on: anAssociationNode value! !\\nOBActor subclass: #OBNodeActor\\n\\tinstanceVariableNames: 'nodeClass'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Actors'!\\n!OBNodeActor commentStamp: 'cwp 3/5/2004 12:23' prior: 0!\\nFor simplicity, many actions are implemented by the nodes themselves. When the contextual menu for a node is displayed, this Actor gathers those actions and makes them available in to the user.\\n\\nIf a node class is specified, the OBNodeActor will also make available any class side actions provided by the node class. This is convenient for the user, since it makes it possible to invoke an action without first selecting a node. Many 'create' actions are implemented in this way.\\n\\niVars:\\n\\nnodeClass - if not nil, this class's class-side actions will be available to the user as well.!\\n\\n\\n!OBNodeActor methodsFor: 'public' stamp: 'cwp 1/23/2004 23:24'!\\nactionsForNode: aNode\\n\\t^ aNode actions! !\\n\\n!OBNodeActor methodsFor: 'public' stamp: 'cwp 3/3/2004 22:46'!\\nactionsForParent: aNode\\n\\t^ nodeClass \\n\\t\\tifNotNil: [nodeClass actionsForParent: aNode]\\n\\t\\tifNil: [#()]! !\\n\\n!OBNodeActor methodsFor: 'public' stamp: 'cwp 3/3/2004 22:42'!\\nnodeClass: aClass\\n\\tnodeClass _ aClass! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBNodeActor class\\n\\tinstanceVariableNames: ''!\\n\\n!OBNodeActor class methodsFor: 'as yet unclassified' stamp: 'cwp 3/3/2004 22:51'!\\nonNodeClass: aClass\\n\\t^ self new nodeClass: aClass! !\\nOBAnnouncement subclass: #OBNodeChanged\\n\\tinstanceVariableNames: 'node'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBNodeChanged methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:17'!\\nnode\\n\\t^ node! !\\n\\n!OBNodeChanged methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:17'!\\nnode: aNode\\n\\tnode _ aNode! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBNodeChanged class\\n\\tinstanceVariableNames: ''!\\n\\n!OBNodeChanged class methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:17'!\\nnode: aNode\\n\\t^ self new node: aNode! !\\nOBAnnouncement subclass: #OBNodeCreated\\n\\tinstanceVariableNames: 'node'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBNodeCreated methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 00:53'!\\nnode\\n\\t^ node! !\\n\\n!OBNodeCreated methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 00:53'!\\nnode: aNode\\n\\tnode _ aNode! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBNodeCreated class\\n\\tinstanceVariableNames: ''!\\n\\n!OBNodeCreated class methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 01:09'!\\nnode: aNode\\n\\t^ self new node: aNode! !\\nOBAnnouncement subclass: #OBNodeDeleted\\n\\tinstanceVariableNames: 'node'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBNodeDeleted methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:56'!\\nnode\\n\\t^ node! !\\n\\n!OBNodeDeleted methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:56'!\\nnode: aNode\\n\\tnode _ aNode! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBNodeDeleted class\\n\\tinstanceVariableNames: ''!\\n\\n!OBNodeDeleted class methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 11:56'!\\nnode: aNode\\n\\t^ self new node: aNode! !\\nOBDefinition subclass: #OBOrganizationDefinition\\n\\tinstanceVariableNames: 'organizer'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Definitions'!\\n!OBOrganizationDefinition commentStamp: 'cwp 1/8/2005 13:31' prior: 0!\\nOBOrganizationDefinition knows how to display and edit the organization of classes or methods by a Categorizer.!\\n\\n\\n!OBOrganizationDefinition methodsFor: 'as yet unclassified' stamp: 'cwp 9/22/2004 21:21'!\\norganizer: anOrganizer\\n\\torganizer _ anOrganizer! !\\n\\n!OBOrganizationDefinition methodsFor: 'as yet unclassified' stamp: 'cwp 9/22/2004 21:18'!\\ntext\\n\\t^ organizer asString! !\\n\\n!OBOrganizationDefinition methodsFor: 'as yet unclassified' stamp: 'cwp 1/9/2005 11:45'!\\ntext: aText\\n\\torganizer changeFromString: aText asString.\\n\\t^ true! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBOrganizationDefinition class\\n\\tinstanceVariableNames: ''!\\n\\n!OBOrganizationDefinition class methodsFor: 'as yet unclassified' stamp: 'cwp 9/22/2004 21:20'!\\non: anOrganizer\\n\\t^ self new organizer: anOrganizer! !\\nRectangleMorph subclass: #OBPane\\n\\tinstanceVariableNames: 'model list button'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Morphic'!\\n!OBPane commentStamp: 'cwp 1/7/2005 23:24' prior: 0!\\nAn OBPane is the visual representation of a column in a browser. It contains a morph to display nodes (typically a PluggableListMorph) and (optionally) a morph for communicating with the column's filter. It's main responsibility is to lay out its submorphs as the filter controls are added and removed.\\n\\niVars:\\n\\nmodel\\t- the OBColumn that controls the node list displayed in this pane\\nlist\\t\\t- the morph which displays the node list, usually a PluggableListMorph\\nbutton\\t- the morph which controls the column's filter, usually an OBRadioButtonBar.!\\n\\n\\n!OBPane methodsFor: 'constructing' stamp: 'cwp 11/2/2004 00:57'!\\nbuttonHeight\\n\\t^ self hasButton\\n\\t\\tifTrue: [button height]\\n\\t\\tifFalse: [self defaultButtonHeight]\\n! !\\n\\n!OBPane methodsFor: 'constructing' stamp: 'cwp 11/2/2004 01:10'!\\ndefaultButtonHeight\\n\\t^ 23! !\\n\\n!OBPane methodsFor: 'constructing' stamp: 'cwp 11/27/2004 21:19'!\\nnoteNewOwner: aMorph\\n\\tself containingWindow ifNotNilDo: [:window | self adoptPaneColor: window paneColor]! !\\n\\n\\n!OBPane methodsFor: 'geometry' stamp: 'cwp 2/12/2004 18:32'!\\nbounds: aRectangle\\n\\tsuper bounds: aRectangle.\\n\\tself adjustList.\\n\\tself adjustButton.! !\\n\\n\\n!OBPane methodsFor: 'initialization' stamp: 'cwp 2/12/2004 18:26'!\\ninitGeometry\\n\\tself\\t\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\tclipSubmorphs: true;\\n\\t\\tcolor: Color transparent;\\n\\t\\tcellInset: 0;\\n\\t\\tborderWidth: 0;\\n\\t\\tlayoutPolicy: ProportionalLayout new.\\n\\t\\t\\n\\tself addMorph: list.\\n\\tlist bounds: self innerBounds.\\n\\t\\t! !\\n\\n!OBPane methodsFor: 'initialization' stamp: 'cwp 2/12/2004 18:44'!\\nmodel: anObject\\n\\t\\\"Set my model and make me me a dependent of the given object.\\\"\\n\\n\\tmodel ifNotNil: [model removeDependent: self].\\n\\tanObject ifNotNil: [anObject addDependent: self].\\n\\tmodel _ anObject.\\n! !\\n\\n!OBPane methodsFor: 'initialization' stamp: 'cwp 2/12/2004 19:17'!\\nsetColumn: aColumn filter: aFilter\\n\\tself model: aColumn.\\n\\tlist _ aColumn listMorph.\\n\\tself initGeometry.\\n\\taFilter ifNotNil: [self addButton: aFilter buttonMorph].! !\\n\\n\\n!OBPane methodsFor: 'testing' stamp: 'cwp 2/12/2004 18:35'!\\nhasButton\\n\\t^ button notNil! !\\n\\n\\n!OBPane methodsFor: 'updating' stamp: 'cwp 11/2/2004 00:53'!\\naddButton: aButton\\n\\tself hasButton ifTrue: [self removeMorph: button].\\n\\tbutton _ aButton.\\n\\tbutton height: self defaultButtonHeight.\\n\\tself \\n\\t\\taddMorph: button;\\n\\t\\tadjustList;\\n\\t\\tadjustButton! !\\n\\n!OBPane methodsFor: 'updating' stamp: 'cwp 11/2/2004 00:50'!\\nadjustButton\\n\\t| inner |\\n\\tself hasButton ifTrue: \\n\\t\\t[inner _ self innerBounds.\\n\\t\\tbutton bounds: (inner withTop: inner bottom - self buttonHeight)]! !\\n\\n!OBPane methodsFor: 'updating' stamp: 'cwp 2/12/2004 18:35'!\\nadjustList\\n\\tself hasButton\\n\\t\\t\\tifFalse: [list bounds: self innerBounds]\\n\\t\\t\\tifTrue: [list bounds: (self innerBounds withHeight: (self height - self buttonHeight))]! !\\n\\n!OBPane methodsFor: 'updating' stamp: 'cwp 2/12/2004 20:29'!\\nremoveButton\\n\\tself hasButton \\n\\t\\tifTrue: [self removeMorph: button.\\n\\t\\t\\t\\tbutton _ nil.\\n\\t\\t\\t\\tself adjustList]! !\\n\\n!OBPane methodsFor: 'updating' stamp: 'cwp 2/12/2004 20:23'!\\nupdate: aSelector\\n\\taSelector = #filter ifFalse: [^ self].\\n\\t(model wantsButton)\\n\\t\\t\\tifTrue: [self addButton: model filter buttonMorph]\\n\\t\\t\\tifFalse: [self removeButton]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBPane class\\n\\tinstanceVariableNames: ''!\\n\\n!OBPane class methodsFor: 'instance creation' stamp: 'cwp 2/12/2004 18:11'!\\nforColumn: aColumn\\n\\t^ self forColumn: aColumn withFilter: nil! !\\n\\n!OBPane class methodsFor: 'instance creation' stamp: 'cwp 2/12/2004 18:12'!\\nforColumn: aColumn withFilter: aFilter\\n\\t^ self new setColumn: aColumn filter: aFilter! !\\nRectangleMorph subclass: #OBPaneScroller\\n\\tinstanceVariableNames: 'model sizing panes transform scrollBar'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Morphic'!\\n!OBPaneScroller commentStamp: 'cwp 3/5/2004 12:13' prior: 0!\\nInstances of OBPaneScroller contain the panes which represent columns in a browser. Their primary responsibilities are laying out panes to fit the space available and scrolling them horizontally when there isn't sufficient space. \\n\\niVars:\\n\\nsizing\\t\\t- The number of panes which should exactly fit the available space.\\n\\t\\t \\t During layout, the width of the panes is determined accordingly.\\ntransform\\t- A TransformMorph used for scrolling\\nscrollBar\\t- An OBHorizontalScrollBar used for scrolling!\\n\\n\\n!OBPaneScroller methodsFor: 'accessing' stamp: 'cwp 11/17/2004 22:03'!\\nmodel\\n\\t^model! !\\n\\n!OBPaneScroller methodsFor: 'accessing' stamp: 'cwp 11/17/2004 22:11'!\\nmodel: anObject\\n\\tmodel ifNotNil: [model removeDependent: self].\\n\\tanObject ifNotNil: [anObject addDependent: self].\\n\\tmodel := anObject! !\\n\\n!OBPaneScroller methodsFor: 'accessing' stamp: 'cwp 11/17/2004 23:09'!\\npanes\\n\\t^ panes ifNil: [self updatePanes. panes]! !\\n\\n!OBPaneScroller methodsFor: 'accessing' stamp: 'cwp 11/22/2004 23:19'!\\nsizing\\n\\t^ sizing ifNil: [self updateSizing]! !\\n\\n\\n!OBPaneScroller methodsFor: 'defaults' stamp: 'cwp 8/24/2003 15:13'!\\nseparatorWidth\\n\\t^ 4! !\\n\\n\\n!OBPaneScroller methodsFor: 'initialization' stamp: 'cwp 11/23/2004 01:28'!\\ninitialize\\n\\tsuper initialize.\\n\\tself \\n\\t\\tcolor: Color red;\\n\\t\\tborderWidth: 0;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\thResizing: #spaceFill.\\n\\tself \\n\\t\\tinitializeTransform;\\n\\t\\tinitializeScrollbar.\\n\\tself startStepping.! !\\n\\n!OBPaneScroller methodsFor: 'initialization' stamp: 'cwp 2/8/2004 11:01'!\\ninitializeScrollbar\\n\\tscrollBar _ OBScrollBar new model: self slotName: 'scrollBar'.\\n\\tscrollBar \\n\\t\\tborderWidth: 0;\\n\\t\\tborderColor: #inset;\\n\\t\\theight: self scrollBarHeight.\\n\\tself resizeScrollBar.\\n! !\\n\\n!OBPaneScroller methodsFor: 'initialization' stamp: 'cwp 2/8/2004 10:52'!\\ninitializeTransform\\n\\ttransform _ TransformMorph new.\\n\\ttransform\\n\\t\\tcolor: Color transparent;\\n\\t\\tborderWidth: 0;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tdisableTableLayout;\\n\\t\\tbounds: super innerBounds.\\n\\tself addMorphBack: transform.\\n! !\\n\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 2/8/2004 11:10'!\\nadjustPaneHeight\\n\\t\\\"This gets called after the scrollbar has been shown or hidden, to move the bottom\\n\\tof the panes to the right place.\\\"\\n\\t\\n\\ttransform bounds: self innerBounds.\\n\\ttransform submorphsDo: [:m | m bounds: (m bounds withHeight: self paneHeight)]\\n\\t\\t! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 11/21/2004 23:45'!\\nbounds: aRectangle\\n\\tsuper bounds: aRectangle.\\n\\tself layoutWidgets.\\n\\tself layoutPanes.\\n\\tself setScrollDeltas.\\n! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 2/26/2004 23:14'!\\ncomputeMorphWidths\\n\\t| paneWidths widths |\\n\\tpaneWidths _ self paneWidthsToFit: self totalPaneWidth.\\n\\twidths _ OrderedCollection new.\\n\\tpaneWidths do: [:w | widths add: w] separatedBy: [widths add: self separatorWidth].\\n\\t^ widths asArray\\n! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 2/8/2004 11:06'!\\ndoLayout\\n\\tself layoutWidgets.\\n\\tself layoutPanes.\\n\\tself hideOrShowScrollBar.\\n\\tself setScrollDeltas.\\n\\tself scrollToRight.! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 2/8/2004 10:54'!\\ninnerBounds\\n\\t| rect |\\n\\trect _ super innerBounds.\\n\\t^ self scrollBarIsVisible\\n\\t\\tifTrue: [rect withHeight: rect height - self scrollBarHeight - 1]\\n\\t\\tifFalse: [rect]! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 2/8/2004 01:22'!\\nlayoutPanes\\n\\t| widths rect |\\n\\twidths _ self computeMorphWidths.\\n\\trect _ 0@0 extent: (0 @ self paneHeight).\\n\\ttransform submorphs \\n\\t\\t\\t\\t\\twith: widths \\n\\t\\t\\t\\t\\tdo: [:m :w | \\n\\t\\t\\t\\t\\t\\trect _ rect withWidth: w.\\n\\t\\t\\t\\t\\t\\tm bounds: rect.\\n\\t\\t\\t\\t\\t\\trect _ rect translateBy: (w@0)]\\n\\t\\t\\t\\t\\t\\t\\n! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 8/25/2003 22:13'!\\nlayoutWidgets\\n\\t| inner outer |\\n\\touter _ super innerBounds.\\n\\tinner _ self innerBounds.\\n\\ttransform bounds: inner.\\n\\tscrollBar bounds: ((inner left @ inner bottom + 1)\\n\\t\\t\\t\\t\\t\\tcorner: outer bottomRight)! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 11/17/2004 23:09'!\\npaneCount\\n\\t^ self panes size! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 12/6/2003 17:08'!\\npaneHeight\\n\\t^ transform bounds height! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 2/26/2004 23:14'!\\npaneWidthsToFit: limit\\n\\t| padded |\\n\\tpadded _ Array new: self paneCount.\\n\\tpadded atAllPut: (limit / self sizing) floor.\\n\\t(1 to: limit - padded sum) do: [:i | padded at: i put: (padded at: i) + 1].\\n\\t^ padded\\n\\t\\n\\t! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 2/8/2004 11:03'!\\nresizeScrollBar\\n\\t| inner outer |\\n\\touter _ super innerBounds.\\n\\tinner _ outer withHeight: outer height - self scrollBarHeight - 1.\\n\\tscrollBar bounds: ((inner left @ inner bottom + 1)\\n\\t\\t\\t\\t\\t\\tcorner: outer bottomRight)! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 8/24/2003 14:29'!\\nscrollBarHeight\\n\\t^ 12! !\\n\\n!OBPaneScroller methodsFor: 'layout' stamp: 'cwp 2/25/2004 20:23'!\\ntotalPaneWidth\\n\\t^ self innerBounds width - ((self sizing - 1) * self separatorWidth)! !\\n\\n\\n!OBPaneScroller methodsFor: 'panes' stamp: 'cwp 12/6/2003 17:06'!\\nclearPanes\\n\\ttransform removeAllMorphs! !\\n\\n!OBPaneScroller methodsFor: 'panes' stamp: 'cwp 11/23/2004 01:22'!\\npopPanes: count\\n\\tcount * 2 timesRepeat: [transform removeMorph: transform lastSubmorph].\\n\\tpanes removeLast: count! !\\n\\n!OBPaneScroller methodsFor: 'panes' stamp: 'cwp 11/17/2004 22:46'!\\npushPane: aMorph\\n\\taMorph \\n\\t\\tborderWidth: 0;\\n\\t\\thResizing: #rigid;\\n\\t\\tvResizing: #rigid;\\n\\t\\tlayoutInset: 0.\\n\\ttransform hasSubmorphs ifTrue: [transform addMorphBack: self separator].\\n\\ttransform addMorphBack: aMorph.\\n! !\\n\\n!OBPaneScroller methodsFor: 'panes' stamp: 'cwp 11/27/2004 01:03'!\\nseparator\\n\\t^ BorderedSubpaneDividerMorph vertical \\n\\t\\tborderWidth: self separatorWidth / 2;\\n\\t\\tcolor: model defaultBackgroundColor duller;\\n\\t\\tborderRaised.! !\\n\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 2/8/2004 10:44'!\\nhideOrShowScrollBar\\n\\tself isScrollable ifTrue: [self showScrollBar] ifFalse: [self hideScrollBar]! !\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 2/8/2004 11:10'!\\nhideScrollBar\\n\\tself removeMorph: scrollBar.\\n\\tself adjustPaneHeight.! !\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 2/8/2004 10:42'!\\nisScrollable\\n\\t^ self leftoverScrollRange > 0! !\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 8/25/2003 21:04'!\\nleftoverScrollRange\\n\\t^ (self totalScrollRange - self innerBounds width roundTo: self scrollDeltaWidth) max: 0\\n! !\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 2/8/2004 10:56'!\\nscrollBarIsVisible\\n\\t^ submorphs includes: scrollBar! !\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 8/23/2003 16:21'!\\nscrollDeltaWidth\\n\\t^ 1! !\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 12/8/2003 21:42'!\\nscrollToRight\\n\\t^ scrollBar setValue: 1.! !\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 8/25/2003 21:14'!\\nsetScrollDeltas\\n\\t| range interval value |\\n\\ttransform hasSubmorphs ifFalse: [scrollBar interval: 1.0. ^ self].\\n\\trange _ self leftoverScrollRange.\\n\\trange = 0 ifTrue: [^ scrollBar interval: 1.0; setValue: 0].\\n\\tinterval _ ((self innerBounds width) / self totalScrollRange) asFloat.\\n\\tvalue _ (transform offset x / range min: 1.0) asFloat.\\n\\tscrollBar interval: interval.\\n\\tscrollBar setValue: value.! !\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 2/8/2004 11:11'!\\nshowScrollBar\\n\\tself scrollBarIsVisible ifTrue: [^ self].\\n\\tself resizeScrollBar.\\n\\tself addMorphFront: scrollBar.\\n\\tself adjustPaneHeight.\\n\\t! !\\n\\n!OBPaneScroller methodsFor: 'scrolling' stamp: 'cwp 8/25/2003 19:27'!\\ntotalScrollRange\\n\\t| submorphBounds |\\n\\tsubmorphBounds := transform localSubmorphBounds ifNil: [^ 0].\\n\\t^ submorphBounds width\\n! !\\n\\n\\n!OBPaneScroller methodsFor: 'stepping' stamp: 'cwp 11/21/2004 15:38'!\\nstep\\n\\tself reclaimPanes! !\\n\\n!OBPaneScroller methodsFor: 'stepping' stamp: 'cwp 11/24/2004 22:29'!\\nstepTime\\n\\t^ 250! !\\n\\n\\n!OBPaneScroller methodsFor: 'updating' stamp: 'cwp 11/23/2004 01:23'!\\nreclaimPanes\\n\\t| reclaimed |\\n\\treclaimed := model reclaimPanes.\\n\\treclaimed isZero\\tifFalse: \\n\\t\\t[self \\n\\t\\t \\tpopPanes: reclaimed;\\n\\t\\t\\tbasicUpdateSizing;\\n\\t\\t\\tlayoutPanes;\\n\\t\\t\\thideOrShowScrollBar;\\n\\t\\t\\tsetScrollDeltas]! !\\n\\n!OBPaneScroller methodsFor: 'updating' stamp: 'cwp 11/21/2004 13:51'!\\nscrollBarValue: value\\n\\ttransform hasSubmorphs ifFalse: [^ self].\\n\\ttransform offset: (self leftoverScrollRange * value) rounded @ 0.! !\\n\\n!OBPaneScroller methodsFor: 'updating' stamp: 'cwp 11/23/2004 01:34'!\\nupdatePanes\\n\\t| count |\\n\\tmodel ifNil: [panes := Array new. ^ self].\\n\\tcount := panes ifNotNil: [panes size] ifNil: [0].\\n\\tself basicUpdatePanes.\\n\\tself basicUpdateSizing.\\t\\n\\tself layoutPanes.\\n\\tpanes size = count\\n\\t\\tifFalse: [self hideOrShowScrollBar.\\n\\t\\t\\t\\tself setScrollDeltas].\\n\\tpanes size > count ifTrue: [self scrollToRight].\\n\\t^ panes! !\\n\\n!OBPaneScroller methodsFor: 'updating' stamp: 'cwp 11/23/2004 01:14'!\\nupdateSizing\\n\\t| old |\\n\\told := sizing.\\n\\tself basicUpdateSizing.\\n\\tsizing = old ifFalse: [self layoutPanes].\\n\\t^sizing! !\\n\\n!OBPaneScroller methodsFor: 'updating' stamp: 'cwp 11/17/2004 22:40'!\\nupdate: aSymbol\\n\\taSymbol = #sizing ifTrue: [^ self updateSizing].\\n\\taSymbol = #panes ifTrue: [^ self updatePanes].! !\\n\\n\\n!OBPaneScroller methodsFor: 'private' stamp: 'cwp 11/23/2004 01:31'!\\nbasicUpdatePanes\\n\\tpanes := model ifNotNil: [model panes] ifNil: [Array new].\\t\\t\\n\\tself clearPanes.\\n\\tpanes do: [:ea | self pushPane: ea].\\n! !\\n\\n!OBPaneScroller methodsFor: 'private' stamp: 'cwp 11/23/2004 01:14'!\\nbasicUpdateSizing\\n\\tmodel ifNil: [sizing := 1] ifNotNil: [sizing := model sizing]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBPaneScroller class\\n\\tinstanceVariableNames: ''!\\n\\n!OBPaneScroller class methodsFor: 'as yet unclassified' stamp: 'cwp 11/17/2004 22:01'!\\nwithModel: aModel\\n\\t^ self new model: aModel! !\\nObject subclass: #OBPanel\\n\\tinstanceVariableNames: 'browser'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Kernel'!\\n!OBPanel commentStamp: 'cwp 1/7/2005 23:23' prior: 0!\\nA panel is an object that manages part of the browser's window. It provides a protocol for receiving notifications when the current domain node changes, and reacts to these changes.!\\n\\n\\n!OBPanel methodsFor: 'accessing' stamp: 'cwp 4/17/2006 15:52'!\\nannouncer\\n\\t^ browser announcer! !\\n\\n!OBPanel methodsFor: 'accessing' stamp: 'cwp 11/16/2004 21:58'!\\nbrowser\\n\\t^ browser! !\\n\\n!OBPanel methodsFor: 'accessing' stamp: 'cwp 4/17/2006 22:17'!\\nbrowser: aBrowser\\n\\tbrowser _ aBrowser.\\n\\tself subscribe! !\\n\\n\\n!OBPanel methodsFor: 'testing' stamp: 'cwp 11/20/2004 21:09'!\\nisNavigation\\n\\t^ false! !\\n\\n\\n!OBPanel methodsFor: 'updating' stamp: 'cwp 4/17/2006 19:36'!\\nsubscribe! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBPanel class\\n\\tinstanceVariableNames: ''!\\n\\n!OBPanel class methodsFor: 'instance creation' stamp: 'cwp 8/31/2004 10:46'!\\ninBrowser: aBrowser\\n\\t^ self new browser: aBrowser! !\\nPluggableTextMorph subclass: #OBPluggableTextMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Morphic'!\\n!OBPluggableTextMorph commentStamp: 'cwp 12/7/2004 00:04' prior: 0!\\nThis is a trivial subclass of PluggableTextMorph. It overrides initialization methods to use an OBTextMorph rather than a regular TextMorph!\\n\\n\\n!OBPluggableTextMorph methodsFor: 'event handling' stamp: 'cwp 10/30/2004 23:07'!\\nkeyStroke: evt\\n\\t^ textMorph keyStroke: evt! !\\n\\n\\n!OBPluggableTextMorph methodsFor: 'model access' stamp: 'cwp 10/30/2004 22:57'!\\nsetText: aText\\n\\tscrollBar setValue: 0.0.\\n\\ttextMorph\\n\\t\\tifNil: [textMorph _ OBTextMorph new\\n\\t\\t\\t\\t\\t\\tcontents: aText wrappedTo: self innerBounds width-6.\\n\\t\\t\\t\\ttextMorph setEditView: self.\\n\\t\\t\\t\\tscroller addMorph: textMorph]\\n\\t\\tifNotNil: [textMorph newContents: aText].\\n\\tself hasUnacceptedEdits: false.\\n\\tself setScrollDeltas.! !\\nRectangleMorph subclass: #OBRadioButtonBar\\n\\tinstanceVariableNames: 'model buttons selection getListSelector getSelectionSelector setSelectionSelector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Morphic'!\\n!OBRadioButtonBar commentStamp: 'cwp 1/7/2005 23:27' prior: 0!\\nAn OBRadioButtonBar is similar to a PluggableListMorph except that it displays a row of buttons rather than a vertical list. Clicking on a button selects it.\\n\\nmodel\\t\\t\\t\\t- the model for this button bar\\nbuttons\\t\\t\\t- a collection of OBButtonModels, which are derived from the model's list\\nselection\\t\\t\\t- the index of the currently selected button\\ngetListSelector\\t \\t- the message for getting the list of labels for the buttons\\ngetSelectionSelector\\t- the message for getting the index of the currently selected item\\nsetSelectionSelector\\t- the message for informing the model that a button has been clicked!\\n\\n\\n!OBRadioButtonBar methodsFor: 'accessing' stamp: 'cwp 11/27/2004 02:09'!\\nlist\\n\\tbuttons ifNil: \\n\\t\\t\\t[| labels |\\n\\t\\t\\tlabels := model perform: getListSelector.\\n\\t\\t\\tbuttons := Array new: labels size.\\n\\t\\t\\tlabels withIndexDo: \\n\\t\\t\\t\\t\\t[:label :index | \\n\\t\\t\\t\\t\\tbuttons at: index put: (OBButtonModel withLabel: label inBar: self)].\\n\\t\\t\\tselection := self getSelectionIndex.\\n\\t\\t\\tself].\\n\\t^buttons collect: [:b | b label]! !\\n\\n\\n!OBRadioButtonBar methodsFor: 'callbacks' stamp: 'cwp 11/27/2004 19:18'!\\nisEnabled: aButton\\n\\t^ true! !\\n\\n!OBRadioButtonBar methodsFor: 'callbacks' stamp: 'cwp 2/24/2004 18:54'!\\nisSelected: aButton\\n\\t^ (buttons at: selection ifAbsent: [^ false]) == aButton! !\\n\\n!OBRadioButtonBar methodsFor: 'callbacks' stamp: 'cwp 2/24/2004 18:47'!\\npush: aButton\\n\\t| index |\\n\\tindex _ buttons indexOf: aButton.\\n\\tmodel perform: setSelectionSelector with: index.! !\\n\\n\\n!OBRadioButtonBar methodsFor: 'constructing' stamp: 'cwp 11/27/2004 20:58'!\\nadoptPaneColor: aColor\\n\\tself submorphs do: [:ea | ea onColor: aColor darker offColor: aColor lighter]! !\\n\\n!OBRadioButtonBar methodsFor: 'constructing' stamp: 'cwp 11/27/2004 21:02'!\\nnoteNewOwner: aMorph\\n\\t| window |\\n\\twindow := aMorph containingWindow.\\n\\twindow ifNotNil: [self adoptPaneColor: window paneColor]! !\\n\\n\\n!OBRadioButtonBar methodsFor: 'initialize-release' stamp: 'lr 3/23/2006 18:10'!\\ninitGeometry\\n\\tself\\n\\t\\tlayoutPolicy: TableLayout new;\\n\\t\\tlistDirection: #leftToRight;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\trubberBandCells: true;\\n\\t\\tcolor: Color transparent;\\n\\t\\tborderWidth: 0;\\n\\t\\tlayoutInset: 2;\\n\\t\\tcellInset: 2\\n! !\\n\\n!OBRadioButtonBar methodsFor: 'initialize-release' stamp: 'cwp 2/22/2004 16:51'!\\nmodel: aModel\\n\\tmodel ifNotNil: [model removeDependent: self].\\n\\tmodel _ aModel.\\n\\tmodel addDependent: self.! !\\n\\n!OBRadioButtonBar methodsFor: 'initialize-release' stamp: 'cwp 2/25/2004 00:36'!\\non: aModel list: listSelector selected: selectionGetter changeSelected: selectionSetter \\n\\tself model: aModel.\\n\\tselection _ 0.\\n\\tgetListSelector _ listSelector.\\n\\tgetSelectionSelector _ selectionGetter.\\n\\tsetSelectionSelector _ selectionSetter.\\n\\tself initGeometry.\\n\\tself updateList.! !\\n\\n\\n!OBRadioButtonBar methodsFor: 'updating' stamp: 'cwp 2/24/2004 18:53'!\\ngetSelectionIndex\\n\\t^ model perform: getSelectionSelector! !\\n\\n!OBRadioButtonBar methodsFor: 'updating' stamp: 'cwp 11/27/2004 17:58'!\\nupdateButtons\\n\\t| labels |\\n\\tlabels := model perform: getListSelector.\\n\\tbuttons := Array new: labels size.\\n\\tlabels withIndexDo: \\n\\t\\t\\t[:label :index | \\n\\t\\t\\tbuttons at: index put: (OBButtonModel withLabel: label inBar: self)].\\n\\tselection := self getSelectionIndex! !\\n\\n!OBRadioButtonBar methodsFor: 'updating' stamp: 'cwp 11/27/2004 17:58'!\\nupdateList\\n\\tself \\n\\t\\tupdateButtons; \\n\\t\\tupdateMorphs! !\\n\\n!OBRadioButtonBar methodsFor: 'updating' stamp: 'cwp 11/2/2004 01:09'!\\nupdateMorphs\\n\\tself removeAllMorphs.\\n\\tbuttons do: [:button | self addMorphBack: button morph].\\n\\tself bounds: (self bounds withHeight: submorphs first height)! !\\n\\n!OBRadioButtonBar methodsFor: 'updating' stamp: 'cwp 2/24/2004 19:39'!\\nupdateSelection\\n\\t| oldSelection |\\n\\toldSelection _ selection.\\n\\tselection _ self getSelectionIndex.\\n\\tself withButtonAt: oldSelection do: [:button | button selectionChanged].\\n\\tself withSelectedButtonDo: [:button | button selectionChanged]! !\\n\\n!OBRadioButtonBar methodsFor: 'updating' stamp: 'cwp 2/25/2004 00:35'!\\nupdate: aSymbol\\n\\taSymbol = getListSelector ifTrue: [self updateList. ^ self].\\n\\taSymbol = getSelectionSelector ifTrue: [self updateSelection]! !\\n\\n!OBRadioButtonBar methodsFor: 'updating' stamp: 'cwp 2/24/2004 19:38'!\\nwithButtonAt: index do: aBlock\\n\\t^ (buttons at: index ifAbsent: [nil]) ifNotNilDo: aBlock! !\\n\\n!OBRadioButtonBar methodsFor: 'updating' stamp: 'cwp 2/24/2004 19:38'!\\nwithSelectedButtonDo: aBlock\\n\\t^ self withButtonAt: selection do: aBlock! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBRadioButtonBar class\\n\\tinstanceVariableNames: ''!\\n\\n!OBRadioButtonBar class methodsFor: 'as yet unclassified' stamp: 'cwp 2/22/2004 16:44'!\\non: aModel list: listSelector selected: selectionSelector changeSelected: changedSelector \\n\\t^ self new\\n\\t\\t\\ton: aModel\\n\\t\\t\\tlist: listSelector\\n\\t\\t\\tselected: selectionSelector\\n\\t\\t\\tchangeSelected: changedSelector! !\\nOBListBrowser subclass: #OBReferencesBrowser\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBReferencesBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBReferencesBrowser class methodsFor: 'as yet unclassified' stamp: 'avi 9/17/2005 01:22'!\\ndefaultMetaNode\\n\\t| class method |\\n\\tclass := OBMetaNode named: 'Class'.\\n\\tmethod := OBMetaNode named: 'References'.\\n\\t\\n\\tclass\\n\\t\\tchildAt: #users put: method;\\n\\t\\taddActor: OBNodeActor new.\\n\\tmethod\\n\\t\\tdisplaySelector: #fullName;\\n\\t\\taddActor: OBNodeActor new.\\n\\t\\t\\n\\t^ class! !\\n\\n!OBReferencesBrowser class methodsFor: 'as yet unclassified' stamp: 'avi 9/17/2005 01:34'!\\ntitle\\n\\t^ 'References to'! !\\nOBAnnouncement subclass: #OBRefreshRequired\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\nObject subclass: #OBRequestor\\n\\tinstanceVariableNames: 'node browser'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Services'!\\n\\n!OBRequestor methodsFor: 'as yet unclassified' stamp: 'cwp 6/29/2006 00:12'!\\nannounce: anObject\\n\\t^ browser announcer announce: anObject! !\\n\\n!OBRequestor methodsFor: 'as yet unclassified' stamp: 'cwp 6/28/2006 00:41'!\\nbrowser: aBrowser\\n\\tbrowser _ aBrowser! !\\n\\n!OBRequestor methodsFor: 'as yet unclassified' stamp: 'cwp 6/28/2006 00:43'!\\ndoesNotUnderstand: aMessage\\n\\t^ aMessage sendTo: browser! !\\n\\n!OBRequestor methodsFor: 'as yet unclassified' stamp: 'cwp 6/28/2006 00:43'!\\nnode: aNode\\n\\tnode _ aNode! !\\n\\n!OBRequestor methodsFor: 'as yet unclassified' stamp: 'cwp 6/28/2006 00:38'!\\nrequestNode\\n\\t^ node! !\\n\\n!OBRequestor methodsFor: 'as yet unclassified' stamp: 'cwp 6/29/2006 00:12'!\\nselect: aNode\\n\\t(self announce: OBAboutToChange)\\n\\t\\tisVetoed ifFalse: [self announce: (OBSelectingNode node: aNode)]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBRequestor class\\n\\tinstanceVariableNames: ''!\\n\\n!OBRequestor class methodsFor: 'as yet unclassified' stamp: 'cwp 6/28/2006 00:40'!\\nfor: aBrowser\\n\\t^ self new browser: aBrowser! !\\nSlider subclass: #OBScrollBar\\n\\tinstanceVariableNames: 'upButton downButton pagingArea scrollDelta pageDelta interval menuSelector timeOfMouseDown timeOfLastScroll nextPageDirection currentScrollDelay'\\n\\tclassVariableNames: 'CachedImages UpArrow UpArrow8Bit'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Morphic'!\\n!OBScrollBar commentStamp: 'cwp 3/5/2004 12:01' prior: 0!\\nThis class is a relic. It was originally created to work around bugs in ScrollBar which prevented it from working correctly in horizontal orientation. At some point the bugs should be fixed, and ScrollBar should be used instead.!\\n\\n\\n!OBScrollBar methodsFor: 'access' stamp: 'cwp 11/23/2003 18:06'!\\ninterval: d\\n\\t\\\"Supply an optional floating fraction so slider can expand to indicate range\\\"\\n\\tinterval _ d min: 1.0.\\n\\tself expandSlider.\\n\\tself computeSlider.! !\\n\\n!OBScrollBar methodsFor: 'access' stamp: 'cwp 11/23/2003 18:06'!\\npagingArea\\n\\t^pagingArea! !\\n\\n!OBScrollBar methodsFor: 'access' stamp: 'md 2/24/2006 21:25'!\\nroundedScrollbarLook\\n\\t\\\"Rounded look currently only shows up in flop-out mode\\\"\\n\\t^false and: [self class alwaysShowFlatScrollbarForAlternativeLook not]\\n! !\\n\\n!OBScrollBar methodsFor: 'access' stamp: 'cwp 11/23/2003 18:06'!\\nscrollDelta\\n\\t^ scrollDelta! !\\n\\n!OBScrollBar methodsFor: 'access' stamp: 'cwp 11/23/2003 18:06'!\\nscrollDelta: d1 pageDelta: d2\\n\\t\\\"Supply optional increments for better scrolling of, eg, text\\\"\\n\\tscrollDelta _ d1.\\n\\tpageDelta _ d2.! !\\n\\n!OBScrollBar methodsFor: 'access' stamp: 'md 2/24/2006 16:26'!\\nsliderColor: aColor\\n\\t\\\"Change the color of the scrollbar to go with aColor.\\\"\\n\\t| buttonColor |\\n\\tsuper sliderColor: aColor.\\n\\tbuttonColor _ self thumbColor.\\n\\tupButton color: buttonColor.\\n\\tdownButton color: buttonColor.\\n\\tslider color: buttonColor.\\n\\tself roundedScrollbarLook\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[self color: Color transparent.\\n\\t\\t\\t\\tpagingArea color: aColor muchLighter.\\n\\t\\t\\t\\tself borderStyle style == #simple \\n\\t\\t\\t\\t\\tifTrue:[self borderColor: aColor darker darker]\\n\\t\\t\\t\\t\\tifFalse:[self borderStyle baseColor: aColor]]\\n\\t\\t\\tifFalse:\\n\\t\\t\\t\\t[pagingArea color: (aColor alphaMixed: 0.3 with: Color white).\\n\\t\\t\\t\\tself borderWidth: 0]\\n! !\\n\\n!OBScrollBar methodsFor: 'access' stamp: 'cwp 11/23/2003 18:06'!\\nsliderShadowColor\\n\\t^ self roundedScrollbarLook\\n\\t\\tifTrue: [self sliderColor darker]\\n\\t\\tifFalse: [super sliderShadowColor]\\n! !\\n\\n!OBScrollBar methodsFor: 'access' stamp: 'md 2/24/2006 16:27'!\\nthumbColor\\n\\t\\\"Problem: Part of the ScrollBar/Slider code uses 'slider' to mean the entire scrollbar/slider widget, and part of it uses 'slider' to mean only the draggable 'thumb'. This should be cleaned up so that 'thumb' is used instead of 'slider' where appropriate. For now, the meaning of thumbColor is clear, at least.\\\"\\n\\n\\t^self sliderColor alphaMixed: 0.7 with: (Color gray: 0.95).! !\\n\\n\\n!OBScrollBar methodsFor: 'accessing' stamp: 'md 2/24/2006 16:12'!\\nadoptPaneColor: aColor\\n\\t\\\"Adopt the given pane color\\\"\\n\\taColor ifNil:[^self].\\n\\tself sliderColor: aColor.! !\\n\\n!OBScrollBar methodsFor: 'accessing' stamp: 'cwp 11/23/2003 18:06'!\\ncachedImageAt: aKey ifAbsentPut: aBlock\\n\\n\\tCachedImages ifNil: [CachedImages _ Dictionary new].\\n\\t^CachedImages at: aKey ifAbsentPut: aBlock! !\\n\\n\\n!OBScrollBar methodsFor: 'geometry' stamp: 'cwp 11/23/2003 18:06'!\\nbuttonExtent\\n\\t^ bounds isWide\\n\\t\\tifTrue: [11 @ self innerBounds height]\\n\\t\\tifFalse: [self innerBounds width @ 11]! !\\n\\n!OBScrollBar methodsFor: 'geometry' stamp: 'cwp 11/23/2003 18:06'!\\nexpandSlider\\n\\t\\\"Compute the new size of the slider (use the old sliderThickness as a minimum).\\\"\\n\\t| r |\\n\\tr _ self totalSliderArea.\\n\\tslider extent: (bounds isWide\\n\\t\\tifTrue: [((r width * interval) asInteger max: self sliderThickness) @ slider height]\\n\\t\\tifFalse: [slider width @ ((r height * interval) asInteger max: self sliderThickness)])! !\\n\\n!OBScrollBar methodsFor: 'geometry' stamp: 'cwp 11/23/2003 18:06'!\\nextent: p\\n p x > p y\\n ifTrue: [super extent: (p max: 42@8)]\\n ifFalse: [super extent: (p max: 8@42)]! !\\n\\n!OBScrollBar methodsFor: 'geometry' stamp: 'cwp 11/23/2003 18:06'!\\nsliderExtent\\n\\t\\\"The sliderExtent is now stored in the slider itself, not hardcoded as it is in the superclass.\\\"\\n\\t^slider extent! !\\n\\n!OBScrollBar methodsFor: 'geometry' stamp: 'cwp 11/23/2003 18:07'!\\nsliderThickness\\n\\t^ self roundedScrollbarLook ifTrue:[15] ifFalse:[super sliderThickness]! !\\n\\n!OBScrollBar methodsFor: 'geometry' stamp: 'cwp 11/23/2003 18:07'!\\ntotalSliderArea\\n\\t| upperBoundsButton |\\n\\tupperBoundsButton _ upButton.\\n\\tupButton bottom > upperBoundsButton bottom\\n\\t\\tifTrue: [upperBoundsButton _ upButton].\\n\\t^ bounds isWide\\n\\t\\tifTrue: [upperBoundsButton bounds topRight corner: downButton bounds bottomLeft]\\n\\t\\tifFalse: [upperBoundsButton bounds bottomLeft corner: downButton bounds topRight].\\n! !\\n\\n\\n!OBScrollBar methodsFor: 'initialization' stamp: 'cwp 11/23/2003 18:07'!\\ninitialize\\n\\tsuper initialize.\\n\\tscrollDelta _ 0.02.\\n\\tpageDelta _ 0.2.\\n\\tself roundedScrollbarLook ifTrue:[\\n\\t\\tself borderStyle: ((BorderStyle complexFramed width: 2) \\\"baseColor: Color gray\\\")].! !\\n\\n\\n!OBScrollBar methodsFor: 'initialize' stamp: 'cwp 11/23/2003 18:06'!\\ninitializeDownButton\\n\\tdownButton := RectangleMorph\\n\\t\\tnewBounds: (self innerBounds bottomRight - self buttonExtent extent: self buttonExtent)\\n\\t\\tcolor: self thumbColor.\\n\\tdownButton on: #mouseDown send: #scrollDownInit to: self.\\n\\tdownButton on: #mouseUp send: #finishedScrolling to: self.\\n\\tdownButton addMorphCentered: (ImageMorph new image: \\n\\t\\t(self \\n\\t\\t\\tcachedImageAt: (bounds isWide ifTrue: ['right'] ifFalse: ['down']) \\n\\t\\t\\tifAbsentPut: [\\n\\t\\t\\t\\tself upArrow8Bit\\n\\t\\t\\t\\t\\trotateBy: (bounds isWide ifTrue: [#right] ifFalse: [#pi])\\n\\t\\t\\t\\t\\tcenterAt: 0@0\\n\\t\\t\\t]\\n\\t\\t)\\n\\t).\\n\\tself roundedScrollbarLook ifTrue:[\\n\\t\\tdownButton color: Color veryLightGray.\\n\\t\\tdownButton borderStyle: (BorderStyle complexRaised width: 3).\\n\\t] ifFalse:[\\n\\t\\tdownButton setBorderWidth: 1 borderColor: #raised.\\n\\t].\\n\\tself addMorph: downButton.\\n! !\\n\\n!OBScrollBar methodsFor: 'initialize' stamp: 'cwp 11/23/2003 18:06'!\\ninitializeEmbedded: aBool\\n\\t\\\"aBool == true => inboard scrollbar\\n\\taBool == false => flop-out scrollbar\\\"\\n\\tself roundedScrollbarLook ifFalse:[^self].\\n\\taBool ifTrue:[\\n\\t\\tself borderStyle: (BorderStyle inset width: 2).\\n\\t\\tself cornerStyle: #square.\\n\\t] ifFalse:[\\n\\t\\tself borderStyle: (BorderStyle width: 1 color: Color black).\\n\\t\\tself cornerStyle: #rounded.\\n\\t].\\n\\tself removeAllMorphs.\\n\\tself initializeSlider.! !\\n\\n!OBScrollBar methodsFor: 'initialize' stamp: 'cwp 11/23/2003 18:06'!\\ninitializePagingArea\\n\\tpagingArea := RectangleMorph newBounds: self totalSliderArea\\n\\t\\t\\t\\t\\t\\t\\t\\tcolor: (Color r: 0.6 g: 0.6 b: 0.8).\\n\\tpagingArea borderWidth: 0.\\n\\tpagingArea on: #mouseDown send: #scrollPageInit: to: self.\\n\\tpagingArea on: #mouseUp send: #finishedScrolling to: self.\\n\\tself addMorph: pagingArea.\\n\\tself roundedScrollbarLook \\n\\t\\tifTrue:[pagingArea color: (Color gray: 0.9)].! !\\n\\n!OBScrollBar methodsFor: 'initialize' stamp: 'cwp 11/23/2003 18:06'!\\ninitializeSlider\\n\\tself roundedScrollbarLook ifTrue:[\\n\\t\\tself \\n\\t\\t\\tinitializeUpButton;\\n\\t\\t\\tinitializeDownButton;\\n\\t\\t\\tinitializePagingArea.\\n\\t] ifFalse:[\\n\\t\\tself initializeUpButton; \\n\\t\\t\\tinitializeDownButton; \\n\\t\\t\\tinitializePagingArea.\\n\\t].\\n\\tsuper initializeSlider.\\n\\tself roundedScrollbarLook ifTrue:[\\n\\t\\tslider cornerStyle: #rounded.\\n\\t\\tslider borderStyle: (BorderStyle complexRaised width: 3).\\n\\t\\tsliderShadow cornerStyle: #rounded.\\n\\t].\\n\\tself sliderColor: self sliderColor.! !\\n\\n!OBScrollBar methodsFor: 'initialize' stamp: 'cwp 11/23/2003 18:06'!\\ninitializeUpButton\\n\\tupButton := self roundedScrollbarLook \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[RectangleMorph \\n\\t\\t\\t\\t\\t\\tnewBounds: (self innerBounds topLeft extent: self buttonExtent)]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[RectangleMorph \\n\\t\\t\\t\\t\\t\\tnewBounds: ((self innerBounds topLeft) extent: self buttonExtent)].\\n\\tupButton color: self thumbColor.\\n\\tupButton \\n\\t\\ton: #mouseDown\\n\\t\\tsend: #scrollUpInit\\n\\t\\tto: self.\\n\\tupButton \\n\\t\\ton: #mouseUp\\n\\t\\tsend: #finishedScrolling\\n\\t\\tto: self.\\n\\tupButton \\n\\t\\taddMorphCentered: (ImageMorph new image: (self \\n\\t\\t\\t\\t\\t\\tcachedImageAt: (bounds isWide ifTrue: ['left'] ifFalse: ['up'])\\n\\t\\t\\t\\t\\t\\tifAbsentPut: \\n\\t\\t\\t\\t\\t\\t\\t[bounds isWide \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [self upArrow8Bit rotateBy: #left centerAt: 0 @ 0]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [self upArrow8Bit]])).\\n\\tself roundedScrollbarLook \\n\\t\\tifTrue: \\n\\t\\t\\t[upButton color: Color veryLightGray.\\n\\t\\t\\tupButton borderStyle: (BorderStyle complexRaised width: 3)]\\n\\t\\tifFalse: [upButton setBorderWidth: 1 borderColor: #raised].\\n\\tself addMorph: upButton! !\\n\\n!OBScrollBar methodsFor: 'initialize' stamp: 'cwp 11/23/2003 18:06'!\\nupArrow8Bit\\n\\n\\t\\\"convert to 8-bit and convert white to transparent to avoid gratuitous conversion every time we put one in an ImageMorph\\\"\\n\\n\\t^UpArrow8Bit ifNil: [\\n\\t\\tUpArrow8Bit _ (ColorForm mappingWhiteToTransparentFrom: UpArrow) asFormOfDepth: 8\\n\\t]! !\\n\\n\\n!OBScrollBar methodsFor: 'model access' stamp: 'cwp 11/23/2003 18:06'!\\nsetValue: newValue\\n\\t\\\"Using roundTo: instead of truncateTo: ensures that scrollUp will scroll the same distance as scrollDown.\\\"\\n\\t^ super setValue: (newValue roundTo: scrollDelta)! !\\n\\n\\n!OBScrollBar methodsFor: 'other events' stamp: 'cwp 11/23/2003 18:06'!\\nmenuButtonMouseDown: event\\n\\tevent hand showTemporaryCursor: nil.\\n\\tself use: menuSelector orMakeModelSelectorFor: 'MenuButtonPressed:'\\n\\t\\tin: [:sel | menuSelector _ sel. model perform: sel with: event]! !\\n\\n!OBScrollBar methodsFor: 'other events' stamp: 'cwp 11/23/2003 18:06'!\\nmouseDownInSlider: event\\n\\tinterval = 1.0 ifTrue:\\n\\t\\t[\\\"make the entire scrollable area visible if a full scrollbar is clicked on\\\"\\n\\t\\tself setValue: 0.\\n\\t\\tself model hideOrShowScrollBar].\\n\\tsuper mouseDownInSlider: event! !\\n\\n\\n!OBScrollBar methodsFor: 'scroll timing' stamp: 'cwp 11/23/2003 18:07'!\\nresetTimer\\n\\ttimeOfMouseDown _ Time millisecondClockValue.\\n\\ttimeOfLastScroll _ timeOfMouseDown - 1000 max: 0.\\n\\tnextPageDirection _ nil.\\n\\tcurrentScrollDelay _ nil! !\\n\\n!OBScrollBar methodsFor: 'scroll timing' stamp: 'cwp 11/23/2003 18:07'!\\nwaitForDelay1: delay1 delay2: delay2 \\n\\t\\\"Return true if an appropriate delay has passed since the last scroll operation.\\n\\tThe delay decreases exponentially from delay1 to delay2.\\\"\\n\\n\\t| now scrollDelay |\\n\\ttimeOfLastScroll isNil ifTrue: [self resetTimer].\\t\\\"Only needed for old instances\\\"\\n\\tnow := Time millisecondClockValue.\\n\\t(scrollDelay := currentScrollDelay) isNil \\n\\t\\tifTrue: [scrollDelay := delay1\\t\\\"initial delay\\\"].\\n\\tcurrentScrollDelay := scrollDelay * 9 // 10 max: delay2.\\t\\\"decrease the delay\\\"\\n\\ttimeOfLastScroll := now.\\n\\t^true! !\\n\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\ndoScrollByPage\\n\\t\\\"Scroll automatically while mouse is down\\\"\\n\\t(self waitForDelay1: 300 delay2: 100) ifFalse: [^ self].\\n\\tnextPageDirection\\n\\t\\tifTrue: [self setValue: (value + pageDelta min: 1.0)]\\n\\t\\tifFalse: [self setValue: (value - pageDelta max: 0.0)]\\n! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\ndoScrollDown\\n\\t\\\"Scroll automatically while mouse is down\\\"\\n\\t(self waitForDelay1: 200 delay2: 40) ifFalse: [^ self].\\n\\tself setValue: (value + scrollDelta + 0.000001 min: 1.0)! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\ndoScrollUp\\n\\t\\\"Scroll automatically while mouse is down\\\"\\n\\t(self waitForDelay1: 200 delay2: 40) ifFalse: [^ self].\\n\\tself setValue: (value - scrollDelta - 0.000001 max: 0.0)! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nfinishedScrolling\\n\\tself stopStepping.\\n\\tself scrollBarAction: nil.\\n\\tself roundedScrollbarLook ifTrue:[\\n\\t\\tupButton borderStyle: (BorderStyle complexRaised width: upButton borderWidth).\\n\\t\\tdownButton borderStyle: (BorderStyle complexRaised width: downButton borderWidth).\\n\\t] ifFalse:[\\n\\t\\tdownButton borderRaised.\\n\\t\\tupButton borderRaised.\\n\\t].\\n\\n! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nscrollBarAction\\n\\t^self valueOfProperty: #scrollBarAction! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nscrollBarAction: aSymbol\\n\\tself setProperty: #scrollBarAction toValue: aSymbol! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nscrollDown\\n\\tself flag: #obsolete.\\n\\tdownButton eventHandler: nil.\\n\\tdownButton on: #mouseDown send: #scrollDownInit to: self.\\n\\tdownButton on: #mouseUp send: #finishedScrolling to: self.\\n\\t^self scrollDownInit! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nscrollDownInit\\n\\tdownButton borderInset.\\n\\tself resetTimer.\\n\\tself scrollBarAction: #doScrollDown.\\n\\tself startStepping.! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nscrollDown: count\\n\\tself setValue: (value + (scrollDelta * count) + 0.000001 min: 1.0)! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nscrollPageInit: evt\\n\\tself resetTimer.\\n\\tself setNextDirectionFromEvent: evt.\\n\\tself scrollBarAction: #doScrollByPage.\\n\\tself startStepping.! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nscrollUp\\n\\tself flag: #obsolete.\\n\\tupButton eventHandler: nil.\\n\\tupButton on: #mouseDown send: #scrollUpInit to: self.\\n\\tupButton on: #mouseUp send: #finishedScrolling to: self.\\n\\t^self scrollUpInit! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nscrollUpInit\\n\\tupButton borderInset.\\n\\tself resetTimer.\\n\\tself scrollBarAction: #doScrollUp.\\n\\tself startStepping.! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nscrollUp: count\\n\\tself setValue: (value - (scrollDelta * count) - 0.000001 max: 0.0)! !\\n\\n!OBScrollBar methodsFor: 'scrolling' stamp: 'cwp 11/23/2003 18:06'!\\nsetNextDirectionFromEvent: event\\n\\n\\tnextPageDirection _ bounds isWide ifTrue: [\\n\\t\\tevent cursorPoint x >= slider center x\\n\\t]\\n\\tifFalse: [\\n\\t\\tevent cursorPoint y >= slider center y\\n\\t]\\n\\n! !\\n\\n\\n!OBScrollBar methodsFor: 'stepping and presenter' stamp: 'cwp 11/23/2003 18:07'!\\nstep\\n\\t| action |\\n\\taction _ self scrollBarAction.\\n\\taction ifNotNil:[self perform: action].! !\\n\\n\\n!OBScrollBar methodsFor: 'testing' stamp: 'cwp 11/23/2003 18:06'!\\nstepTime\\n\\t^ currentScrollDelay ifNil: [300]! !\\n\\n!OBScrollBar methodsFor: 'testing' stamp: 'cwp 11/23/2003 18:06'!\\nwantsSteps\\n\\t^self scrollBarAction notNil! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBScrollBar class\\n\\tinstanceVariableNames: ''!\\n\\n!OBScrollBar class methodsFor: 'as yet unclassified' stamp: 'cwp 11/23/2003 18:07'!\\nalwaysShowFlatScrollbarForAlternativeLook\\n\\t\\\"Set this value to true, if you want to see the flat scrollbar look in flop-out mode as well as inboard. Otherwise the flop-out scrollbar will be rounded and inboard will be flat.\\\"\\n\\t^ false! !\\n\\n\\n!OBScrollBar class methodsFor: 'class initialization' stamp: 'cwp 11/23/2003 18:07'!\\ninitialize \\\"ScrollBar initialize\\\"\\n\\n\\tUpArrow _ Form\\n\\t\\textent: 6@3\\n\\t\\tfromArray: #(2r11e28 2r1111e27 2r111111e26)\\n\\t\\toffset: 0@0.! !\\nOBAnnouncement subclass: #OBSelectingNode\\n\\tinstanceVariableNames: 'node'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBSelectingNode methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 13:58'!\\nnode\\n\\t^ node! !\\n\\n!OBSelectingNode methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 13:58'!\\nnode: aNode\\n\\tnode _ aNode! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBSelectingNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBSelectingNode class methodsFor: 'as yet unclassified' stamp: 'cwp 6/4/2006 13:58'!\\nnode: aNode\\n\\t^ self new node: aNode! !\\nOBAnnouncement subclass: #OBSelectionChanged\\n\\tinstanceVariableNames: 'node column'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBSelectionChanged methodsFor: 'accessing' stamp: 'cwp 4/19/2006 00:53'!\\ncolumn\\n\\t^ column! !\\n\\n!OBSelectionChanged methodsFor: 'accessing' stamp: 'cwp 4/19/2006 00:52'!\\ncolumn: aColumn\\n\\tcolumn _ aColumn! !\\n\\n!OBSelectionChanged methodsFor: 'accessing' stamp: 'cwp 6/4/2006 12:19'!\\nnode\\n\\t^ column \\n\\t\\tifNil: [node]\\n\\t\\tifNotNil: [column selectedNode]! !\\n\\n!OBSelectionChanged methodsFor: 'accessing' stamp: 'cwp 6/4/2006 12:20'!\\nnode: aNode\\n\\tnode _ aNode! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBSelectionChanged class\\n\\tinstanceVariableNames: ''!\\n\\n!OBSelectionChanged class methodsFor: 'instance creation' stamp: 'cwp 4/19/2006 00:51'!\\ncolumn: aColumn \\n\\t^ self new column: aColumn! !\\n\\n\\n!OBSelectionChanged class methodsFor: 'as yet unclassified' stamp: 'cwp 4/19/2006 00:31'!\\nnode: aNode\\n\\t^ self new node: aNode! !\\nOBCodeNode subclass: #OBSelectorNode\\n\\tinstanceVariableNames: 'selector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBSelectorNode commentStamp: 'cwp 1/8/2005 13:03' prior: 0!\\nOBSelectorNode wraps an instance of Symbol. It typically serves as the root of a senders or implementors OBListBrowser, and is used when cmd-n or cmd-m is invoke from the definition panel, and so no OBMethodNode is available.!\\n\\n\\n!OBSelectorNode methodsFor: 'navigating' stamp: 'cwp 12/8/2004 23:48'!\\nimplementors\\n\\t^ (SystemNavigation default allImplementorsOf: self selector) asSortedArray\\n\\t\\t\\tcollect: [:ref | OBMethodNode on: ref]! !\\n\\n!OBSelectorNode methodsFor: 'navigating' stamp: 'cwp 1/7/2005 22:35'!\\nimplementorsHierarchically\\n\\t^ OBClassAwareNode sortHierarchically: self implementors! !\\n\\n!OBSelectorNode methodsFor: 'navigating' stamp: 'cwp 10/31/2004 01:12'!\\nname\\n\\t^ selector printString! !\\n\\n!OBSelectorNode methodsFor: 'navigating' stamp: 'cwp 10/31/2004 01:12'!\\nselectorAndMessages\\n\\t^ Array with: self! !\\n\\n!OBSelectorNode methodsFor: 'navigating' stamp: 'cwp 11/1/2004 02:22'!\\nsenders\\n\\t^ (SystemNavigation default allCallsOn: self selector) asSortedArray\\n\\t\\t\\tcollect: [:ref | OBMessageNode on: self selector inMethodReference: ref]! !\\n\\n!OBSelectorNode methodsFor: 'navigating' stamp: 'cwp 10/31/2004 01:48'!\\nsendersOfMessage\\n\\t^ (SystemNavigation default allCallsOn: self selector) asSortedArray\\n\\t\\t\\tcollect: [:ref | OBMessageNode on: self selector inMethodReference: ref]! !\\n\\n\\n!OBSelectorNode methodsFor: 'accessing' stamp: 'cwp 10/31/2004 01:11'!\\nselector\\n\\t^ selector! !\\n\\n!OBSelectorNode methodsFor: 'accessing' stamp: 'cwp 10/31/2004 01:10'!\\nselector: aSelector\\n\\tselector := aSelector! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBSelectorNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBSelectorNode class methodsFor: 'instance creation' stamp: 'cwp 10/31/2004 01:11'!\\non: aSelector\\n\\t^ self new selector: aSelector! !\\nOBListBrowser subclass: #OBSendersBrowser\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBSendersBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBSendersBrowser class methodsFor: 'as yet unclassified' stamp: 'cwp 3/2/2006 15:31'!\\ndefaultMetaNode\\n\\t| selector list chase |\\n\\tlist := OBMetaNode named: 'Senders'.\\n\\tlist \\n\\t\\tdisplaySelector: #fullName;\\n\\t\\taddActor: OBNodeActor new.\\n\\n\\tchase := OBMetaNode named: 'Send'.\\n\\tchase\\n\\t\\tdisplaySelector: #fullName;\\n\\t\\tchildAt: #senders put: chase;\\n\\t\\taddActor: OBNodeActor new.\\n\\n\\tselector := OBMetaNode named: 'Selector'.\\t\\n\\tselector \\n\\t\\tchildAt: #senders labeled: 'list' put: list;\\n\\t\\tchildAt: #senders labeled: 'chase' put: chase;\\n\\t\\tfilterClass: OBModalFilter.\\n\\n\\t^ selector! !\\n\\n!OBSendersBrowser class methodsFor: 'as yet unclassified' stamp: 'avi 9/17/2005 01:36'!\\ntitle\\n\\t^ 'Senders of'! !\\nObject subclass: #OBService\\n\\tinstanceVariableNames: 'action condition announcer label keystroke icon buttonLabel'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Services'!\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/18/2006 18:53'!\\naction\\n\\t^ action! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/18/2006 18:53'!\\naction: aValuable\\n\\taction _ aValuable! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 15:34'!\\nannouncer\\n\\t^ announcer! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 15:33'!\\nannouncer: anAnnouncer\\n\\tannouncer _ anAnnouncer! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 19:38'!\\nbuttonLabel\\n\\t^ buttonLabel! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 19:39'!\\nbuttonLabel: aString\\n\\tbuttonLabel _ aString! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 15:40'!\\ncondition\\n\\t^ condition! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 15:40'!\\ncondition: aValuable\\n\\tcondition _ aValuable! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/25/2006 00:41'!\\ndescription\\n\\t^ 'description'! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 19:24'!\\nicon\\n\\t^ icon! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 19:24'!\\nicon: anIcon\\n\\ticon _ anIcon! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 19:04'!\\nkeystroke\\n\\t^ keystroke! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 19:04'!\\nkeystroke: aCharacter\\n\\tkeystroke _ aCharacter! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 19:04'!\\nlabel\\n\\t^ label! !\\n\\n!OBService methodsFor: 'accessing' stamp: 'cwp 6/24/2006 18:58'!\\nlabel: aString\\n\\tlabel _ aString! !\\n\\n\\n!OBService methodsFor: 'morphic' stamp: 'cwp 6/24/2006 18:46'!\\naddServiceFor: aRequestor toMenu: aMenu\\n\\taMenu\\n\\t\\tadd: self labelWithKeystroke\\n\\t\\ttarget: self \\n\\t\\tselector: #executeFor:\\n\\t\\targument: aRequestor.\\n\\taMenu lastItem isEnabled: self isEnabled.\\n\\tPreferences menuWithIcons & self icon notNil\\n\\t\\tifTrue: [aMenu lastItem icon: self icon].\\n\\taMenu addBlankIconsIfNecessary: MenuIcons blankIcon.! !\\n\\n!OBService methodsFor: 'morphic' stamp: 'cwp 6/24/2006 19:41'!\\nbuttonLabelMorph\\n\\t^ StringMorph \\n\\t\\tcontents: self buttonLabel \\n\\t\\tfont: Preferences standardButtonFont! !\\n\\n!OBService methodsFor: 'morphic' stamp: 'cwp 6/24/2006 19:41'!\\nbuttonMorph\\n\\t^ (PluggableButtonMorph\\n\\t\\ton: self\\n\\t\\tgetState: nil\\n\\t\\taction: #trigger\\n\\t\\tlabel: #buttonLabelMorph)\\t\\n\\t\\t\\tonColor: Color lightGray lighter offColor: Color lightGray twiceLighter;\\n\\t\\t\\tborderWidth: 2;\\n\\t\\t\\tborderRaised;\\n\\t\\t\\thResizing: #spaceFill;\\n\\t\\t\\tvResizing: #spaceFill;\\n\\t\\t\\tsetBalloonText: label! !\\n\\n!OBService methodsFor: 'morphic' stamp: 'cwp 6/24/2006 19:05'!\\nlabelWithKeystroke\\n\\t^keystroke\\n\\t\\tifNil: [label]\\n\\t\\tifNotNil: [label, ' (', keystroke asString, ')']! !\\n\\n\\n!OBService methodsFor: 'execute' stamp: 'cwp 6/29/2006 01:12'!\\ncondExecuteFor: aRequestor\\n\\t^ (self isEnabledFor: aRequestor)\\n\\t\\t ifTrue: [self executeFor: aRequestor]! !\\n\\n!OBService methodsFor: 'execute' stamp: 'cwp 6/24/2006 18:15'!\\nexecute\\n\\t^ self executeFor: nil! !\\n\\n!OBService methodsFor: 'execute' stamp: 'cwp 6/24/2006 18:13'!\\nexecuteFor: aRequestor\\n\\taction valueWithPossibleArgs: {aRequestor}! !\\n\\n!OBService methodsFor: 'execute' stamp: 'cwp 6/24/2006 15:42'!\\ntrigger\\n\\t^ self isEnabled ifTrue: [self execute]! !\\n\\n\\n!OBService methodsFor: 'initialize-release' stamp: 'cwp 6/24/2006 19:05'!\\ninitialize\\n\\taction _ [].\\n\\tcondition _ [true].\\n\\tlabel _ 'a service'.! !\\n\\n\\n!OBService methodsFor: 'testing' stamp: 'cwp 6/29/2006 01:11'!\\nisEnabled\\n\\t^ self isEnabledFor: nil! !\\n\\n!OBService methodsFor: 'testing' stamp: 'cwp 6/29/2006 01:07'!\\nisEnabledFor: aRequestor\\n\\t^ condition valueWithPossibleArgs: {aRequestor}! !\\n\\n!OBService methodsFor: 'testing' stamp: 'cwp 6/25/2006 00:43'!\\nuseLineAfter\\n\\t^ false! !\\n\\n!OBService methodsFor: 'testing' stamp: 'cwp 6/24/2006 19:46'!\\nwantsButton\\n\\t^ self buttonLabel notNil! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBService class\\n\\tinstanceVariableNames: ''!\\n\\n!OBService class methodsFor: 'as yet unclassified' stamp: 'cwp 6/18/2006 18:53'!\\naction: aValuable\\n\\t^ self new action: aValuable! !\\n\\n!OBService class methodsFor: 'as yet unclassified' stamp: 'cwp 6/24/2006 15:40'!\\naction: aValuable condition: cValuable\\n\\t^ self new \\n\\t\\taction: aValuable;\\n\\t\\tcondition: cValuable;\\n\\t\\tyourself! !\\n\\n!OBService class methodsFor: 'as yet unclassified' stamp: 'cwp 6/24/2006 15:43'!\\nnew\\n\\t^ self basicNew initialize! !\\nOBAnnouncement subclass: #OBServiceScan\\n\\tinstanceVariableNames: 'services'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Announcements'!\\n\\n!OBServiceScan methodsFor: 'as yet unclassified' stamp: 'cwp 6/25/2006 00:31'!\\naddService: aService\\n\\tservices add: aService! !\\n\\n!OBServiceScan methodsFor: 'as yet unclassified' stamp: 'cwp 6/25/2006 00:31'!\\ninitialize\\n\\tservices _ OrderedCollection new! !\\n\\n!OBServiceScan methodsFor: 'as yet unclassified' stamp: 'cwp 6/25/2006 00:30'!\\nservices\\n\\t^ services! !\\nNotification subclass: #OBSourceFilesRequest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Utilities'!\\n!OBSourceFilesRequest commentStamp: 'cwp 1/8/2005 13:09' prior: 0!\\nOBSourceFilesRequest is used to work around the fact that Squeak's source files are stored in a global array called SourceFiles. When testing OBMethodVersion and OBVersionBrowser, we don't want to use the real source files, as they are too unpredictable. Instead the test cases supply a source file array with known contents.\\n\\nTherefore, OBMethodVersion never refers directly to the SourceFiles global. Instead it raises an OBSourceFiles request. If this occurs during a test, the test catches the notification and resumes using the test source files. Otherwise, the default action resumes using the global source file array.!\\n\\n\\n!OBSourceFilesRequest methodsFor: 'exceptionDescription'!\\ndefaultAction\\n\\t^ SourceFiles! !\\n\\n!OBSourceFilesRequest methodsFor: 'exceptionDescription' stamp: 'cwp 11/27/2004 22:49'!\\nisBrowseRequest\\n\\t^ false! !\\nOBCodeBrowser subclass: #OBSystemBrowser\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n!OBSystemBrowser commentStamp: 'cwp 1/7/2005 23:56' prior: 0!\\nThis is the basic system browser that is the work-horse of Smalltalk development tools. It presents four panes showing class categories, classes, method categories and methods.!\\n\\n\\n!OBSystemBrowser methodsFor: 'morphic' stamp: 'avi 11/29/2004 21:52'!\\ndefaultBackgroundColor\\n\\t^ Color lightGreen\\n\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBSystemBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBSystemBrowser class methodsFor: 'configuration' stamp: 'avi 9/17/2005 01:13'!\\nalphabeticalMetaNode\\n\\t^ self\\n\\t\\timageClass: #classes\\n\\t\\tcomment: #comments\\n\\t\\tmetaclass: #metaclasses\\n! !\\n\\n!OBSystemBrowser class methodsFor: 'configuration' stamp: 'avi 9/17/2005 01:54'!\\ndefaultMetaNode\\n\\t^self hierarchicalMetaNode! !\\n\\n!OBSystemBrowser class methodsFor: 'configuration' stamp: 'cwp 12/6/2004 22:02'!\\ndefaultRootNode\\n\\t^ OBEnvironmentNode forImage! !\\n\\n!OBSystemBrowser class methodsFor: 'configuration' stamp: 'avi 9/17/2005 01:54'!\\nhierarchicalMetaNode\\n\\t^self \\n\\t\\timageClass: #classesHierarchically\\n\\t\\tcomment: #commentsHierarchically\\n\\t\\tmetaclass: #metaclassesHierarchically! !\\n\\n!OBSystemBrowser class methodsFor: 'configuration' stamp: 'avi 9/17/2005 01:09'!\\nimageClass: classSel comment: commentSel metaclass: metaclassSel \\n\\t| env classCategory |\\n\\tenv := OBMetaNode named: 'Environment'.\\n\\tclassCategory := OBMetaNode named: 'ClassCategory'.\\n\\tenv childAt: #categories put: classCategory.\\n\\tself addTo: classCategory class: classSel comment: commentSel metaclass: metaclassSel.\\n\\t^env! !\\n\\n!OBSystemBrowser class methodsFor: 'configuration'!\\ntitle\\n\\t^ 'System Browser'! !\\n\\n\\n!OBSystemBrowser class methodsFor: 'initializing'!\\ninitialize\\n\\tself registerInOpenMenu! !\\n\\n!OBSystemBrowser class methodsFor: 'initializing'!\\nregisterInOpenMenu\\n\\tTheWorldMenu registerOpenCommand: {'Image Browser'. {self. #open}}.\\n! !\\n\\n\\n!OBSystemBrowser class methodsFor: 'instance creation' stamp: 'dvf 8/31/2005 13:17'!\\nonClass: aClass \\n\\t^self selection: aClass asNode! !\\n\\n!OBSystemBrowser class methodsFor: 'instance creation' stamp: 'cwp 12/15/2004 21:42'!\\nonClass: aClass category: aSymbol\\n\\t^ self selection: (OBMethodCategoryNode on: aSymbol inClass: aClass)! !\\n\\n!OBSystemBrowser class methodsFor: 'instance creation' stamp: 'cwp 12/5/2004 17:38'!\\nonClass: aClass selector: aSelector\\n\\t^ self selection: (OBMethodNode on: aSelector inClass: aClass)! !\\n\\n!OBSystemBrowser class methodsFor: 'instance creation' stamp: 'cwp 12/15/2004 21:45'!\\nonEnvironment: anEnvironment category: aSymbol\\n\\t^ self selection: (OBClassCategoryNode \\n\\t\\t\\t\\t\\t\\ton: aSymbol \\n\\t\\t\\t\\t\\t\\tinEnvironment: anEnvironment)! !\\n\\n\\n!OBSystemBrowser class methodsFor: 'opening' stamp: 'cwp 12/5/2004 18:32'!\\nopenOnClass: aClass\\n\\t^ (self onClass: aClass) open! !\\n\\n!OBSystemBrowser class methodsFor: 'opening' stamp: 'cwp 12/15/2004 21:47'!\\nopenOnClass: aClass category: aSymbol\\n\\t^ (self onClass: aClass category: aSymbol) open! !\\n\\n!OBSystemBrowser class methodsFor: 'opening' stamp: 'cwp 12/5/2004 17:38'!\\nopenOnClass: aClass selector: aSelector\\n\\t^ (self onClass: aClass selector: aSelector) open! !\\n\\n!OBSystemBrowser class methodsFor: 'opening' stamp: 'cwp 12/15/2004 21:54'!\\nopenOnEnvironment: anEnvironment category: aSymbol\\n\\t^ (self onEnvironment: anEnvironment category: aSymbol) open! !\\nObject subclass: #OBSystemBrowserAdaptor\\n\\tinstanceVariableNames: 'class selector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Utilities'!\\n!OBSystemBrowserAdaptor commentStamp: 'cwp 1/8/2005 13:35' prior: 0!\\nOBSystemBrowserAdaptor implements the protocol expected by the SystemBrowser app registry, and thus allows OmniBrowser to be chosen as the default system browser. \\n\\nCaveat: because the required protocol is a little ...odd.... it can't be implemented well by OBSystemBrowser directly. OBSystemBrowserAdaptor does this reasonably well, but it has no way to provide a more natural name than its class name to the app registry menu.!\\n\\n\\n!OBSystemBrowserAdaptor methodsFor: 'registry protocol' stamp: 'cwp 12/5/2004 21:50'!\\nlabelString\\n\\t^ 'System Browser'! !\\n\\n!OBSystemBrowserAdaptor methodsFor: 'registry protocol' stamp: 'cwp 12/5/2004 21:49'!\\nopenEditString: anUndefinedObject \\n\\t^ self! !\\n\\n!OBSystemBrowserAdaptor methodsFor: 'registry protocol' stamp: 'cwp 12/5/2004 21:49'!\\nsetClass: aClass selector: aSelector \\n\\tclass _ aClass.\\n\\tselector _ aSelector! !\\n\\n\\n!OBSystemBrowserAdaptor methodsFor: 'accessing' stamp: 'cwp 12/5/2004 21:55'!\\nselector\\n\\t^ selector! !\\n\\n!OBSystemBrowserAdaptor methodsFor: 'accessing' stamp: 'cwp 12/5/2004 21:55'!\\ntargetClass\\n\\t^ class! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBSystemBrowserAdaptor class\\n\\tinstanceVariableNames: ''!\\n\\n!OBSystemBrowserAdaptor class methodsFor: 'initializing' stamp: 'cwp 12/5/2004 22:01'!\\ninitialize\\n\\tself register! !\\n\\n!OBSystemBrowserAdaptor class methodsFor: 'initializing' stamp: 'cwp 1/8/2005 21:52'!\\nregister\\n\\tSmalltalk at: #SystemBrowser ifPresent: [:class | class register: self]! !\\n\\n!OBSystemBrowserAdaptor class methodsFor: 'initializing' stamp: 'cwp 1/8/2005 21:53'!\\nunregister\\n\\tSmalltalk at: #SystemBrowser ifPresent: [:class | class unregister: self]! !\\n\\n\\n!OBSystemBrowserAdaptor class methodsFor: 'registry protocol' stamp: 'lr 4/20/2006 08:48'!\\nfullOnClass: aClass selector: aSelector\\n\\t^ OBSystemBrowser \\n\\t\\topenOnClass: aClass\\n\\t\\tselector: aSelector! !\\n\\n!OBSystemBrowserAdaptor class methodsFor: 'registry protocol' stamp: 'lr 3/28/2006 09:10'!\\nopen\\n\\tOBSystemBrowser open! !\\n\\n!OBSystemBrowserAdaptor class methodsFor: 'registry protocol' stamp: 'cwp 12/5/2004 21:59'!\\nopenBrowser\\n\\tOBSystemBrowser open! !\\n\\n!OBSystemBrowserAdaptor class methodsFor: 'registry protocol' stamp: 'cwp 12/5/2004 21:56'!\\nopenBrowserView: adaptor label: ignored \\n\\t^ OBSystemBrowser \\n\\t\\topenOnClass: adaptor targetClass \\n\\t\\tselector: adaptor selector! !\\nTextMorphForEditView subclass: #OBTextMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Morphic'!\\n!OBTextMorph commentStamp: 'cwp 12/7/2004 00:07' prior: 0!\\nThis is a trivial subclass of TextMorph. It overrides editor creation to use OBTextMorphEditor rather than a regular TextMorphEditor.!\\n\\n\\n!OBTextMorph methodsFor: 'private' stamp: 'cwp 10/30/2004 23:06'!\\ninstallEditorToReplace: priorEditor\\n\\t\\\"Install an editor for my paragraph. This constitutes 'hasFocus'.\\n\\tIf priorEditor is not nil, then initialize the new editor from its state.\\n\\tWe may want to rework this so it actually uses the prior editor.\\\"\\n\\n\\t| stateArray |\\n\\tpriorEditor ifNotNil: [stateArray _ priorEditor stateArray].\\n\\teditor _ OBTextMorphEditor new morph: self.\\n\\teditor changeParagraph: self paragraph.\\n\\tpriorEditor ifNotNil: [editor stateArrayPut: stateArray].\\n\\tself selectionChanged.\\n\\t^ editor! !\\nTextMorphEditor subclass: #OBTextMorphEditor\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Morphic'!\\n!OBTextMorphEditor commentStamp: 'cwp 1/7/2005 23:27' prior: 0!\\nOBTextMorphEditor overrides the TextMorphEditors handling of command keys, passing them along to its model for processing, rather than hard-coding their implementations.!\\n\\n\\n!OBTextMorphEditor methodsFor: 'actions' stamp: 'cwp 10/31/2004 01:52'!\\nbrowseIt\\n\\t| symbol |\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\t(symbol _ self selectedSymbol) isNil ifTrue: [^ view flash].\\n\\n\\tself send: #browseIt: toModelWith: {symbol} orDo: [super browseIt]! !\\n\\n!OBTextMorphEditor methodsFor: 'actions' stamp: 'cwp 10/31/2004 00:40'!\\nimplementorsOfIt\\n\\t\\\"Open a senders browser on the selected selector\\\"\\n\\n\\t| selector |\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\t(selector _ self selectedSelector) == nil ifTrue: [^ view flash].\\n\\tself send: #implementorsOfIt: toModelWith: {selector} orDo: [super sendersOfIt]! !\\n\\n!OBTextMorphEditor methodsFor: 'actions' stamp: 'cwp 10/31/2004 01:10'!\\nreferencesToIt\\n\\n\\t| selector |\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\t(selector _ self selectedSelector) == nil ifTrue: [^ view flash].\\n\\tself send: #referencesToIt: toModelWith: {selector} orDo: [super referencesToIt]! !\\n\\n!OBTextMorphEditor methodsFor: 'actions' stamp: 'cwp 10/31/2004 00:26'!\\nsendersOfIt\\n\\t\\\"Open a senders browser on the selected selector\\\"\\n\\n\\t| selector |\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\t(selector _ self selectedSelector) == nil ifTrue: [^ view flash].\\n\\tself send: #sendersOfIt: toModelWith: {selector} orDo: [super sendersOfIt]! !\\n\\n\\n!OBTextMorphEditor methodsFor: 'model access' stamp: 'cwp 10/31/2004 00:24'!\\nsend: aSelector toModelWith: args orDo: aBlock\\n\\tself terminateAndInitializeAround:\\n\\t\\t[(model respondsTo: aSelector)\\n\\t\\t\\tifTrue: [(model perform: aSelector withArguments: args)\\n\\t\\t\\t\\t\\t\\tifFalse: [view flash]]\\n\\t\\t\\tifFalse: aBlock]! !\\nOBInteractionRequest subclass: #OBTextRequest\\n\\tinstanceVariableNames: 'prompt template'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Notifications'!\\n!OBTextRequest commentStamp: 'cwp 3/5/2004 12:35' prior: 0!\\nThis notification is used to ask the user to supply a short piece of text. Its defaultAction is to open a FillInTheBlank.\\n\\niVars:\\n\\nprompt\\t\\t- a string describing the text the user is asked to supply\\ntemplate\\t- a default reply !\\n\\n\\n!OBTextRequest methodsFor: 'accessing' stamp: 'cwp 2/2/2004 21:24'!\\nprompt\\n\\t^ prompt! !\\n\\n!OBTextRequest methodsFor: 'accessing' stamp: 'cwp 2/2/2004 21:23'!\\nprompt: aString\\n\\tprompt _ aString! !\\n\\n!OBTextRequest methodsFor: 'accessing' stamp: 'cwp 2/2/2004 21:00'!\\ntemplate\\n\\t^ template! !\\n\\n!OBTextRequest methodsFor: 'accessing' stamp: 'cwp 2/2/2004 20:59'!\\ntemplate: aString\\n\\ttemplate _ aString! !\\n\\n\\n!OBTextRequest methodsFor: 'user interaction' stamp: 'cwp 2/2/2004 21:27'!\\ndefaultAction\\n\\tself resume: self requestText! !\\n\\n!OBTextRequest methodsFor: 'user interaction' stamp: 'cwp 2/2/2004 21:27'!\\nrequestText\\n\\t^ FillInTheBlankMorph \\n\\t\\trequest: prompt\\n\\t\\tinitialAnswer: template\\n\\t\\tcenterAt: Sensor cursorPoint\\n\\t\\tinWorld: World\\n\\t\\tonCancelReturn: nil\\n\\t\\tacceptOnCR: true! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBTextRequest class\\n\\tinstanceVariableNames: ''!\\n\\n!OBTextRequest class methodsFor: 'as yet unclassified' stamp: 'cwp 2/2/2004 21:30'!\\nprompt: aString\\n\\t^ self new prompt: aString; template: ''! !\\n\\n!OBTextRequest class methodsFor: 'as yet unclassified' stamp: 'cwp 2/5/2004 20:31'!\\nprompt: promptString template: templateString\\n\\t^ (self new prompt: promptString; template: templateString) signal! !\\nOBPanel subclass: #OBVarButtonPanel\\n\\tinstanceVariableNames: 'morph'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OmniBrowser-Panels'!\\n!OBVarButtonPanel commentStamp: 'cwp 12/7/2004 00:21' prior: 0!\\nOBVarButtonPanel displays a horizontal row of buttons. In contrast to OBFixedButtonPanel, the buttons on display are updated to reflect the actions appropriate to the currently selected node.!\\n\\n\\n!OBVarButtonPanel methodsFor: 'constructing' stamp: 'cwp 11/27/2004 18:16'!\\nmorph\\n\\t^ morph _ (RectangleMorph new)\\n\\t\\t\\t\\t\\tlayoutPolicy: TableLayout new;\\n\\t\\t\\t\\t\\tlistDirection: #leftToRight;\\n\\t\\t\\t\\t\\thResizing: #spaceFill;\\n\\t\\t\\t\\t\\tvResizing: #spaceFill;\\n\\t\\t\\t\\t\\tborderWidth: 0;\\n\\t\\t\\t\\t\\twrapCentering: #center;\\n\\t\\t\\t\\t\\tcellPositioning: #leftCenter;\\n\\t\\t\\t\\t\\trubberBandCells: true;\\n\\t\\t\\t\\t\\tyourself! !\\n\\n!OBVarButtonPanel methodsFor: 'constructing' stamp: 'cwp 11/26/2004 22:41'!\\nmorphHeight\\n\\t^ 25! !\\n\\n\\n!OBVarButtonPanel methodsFor: 'updating' stamp: 'cwp 7/8/2006 12:54'!\\nselectionChanged: ann\\n\\t| node actions |\\n\\tmorph removeAllMorphs.\\n\\tnode _ browser currentNode ifNil: [^ self].\\n\\tactions _ (node metaNode actionsForNode: node) select: [:ea | ea wantsButton].\\n\\tactions do: [:ea | morph addMorphBack: ea buttonMorph]! !\\n\\n!OBVarButtonPanel methodsFor: 'updating' stamp: 'cwp 6/3/2006 22:30'!\\nsubscribe\\n\\tself announcer\\n\\t\\tobserve: OBSelectionChanged\\n\\t\\tsend: #selectionChanged:\\n\\t\\tto: self! !\\nOBClassAwareNode subclass: #OBVariableNode\\n\\tinstanceVariableNames: 'name'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Nodes'!\\n!OBVariableNode commentStamp: 'cwp 1/8/2005 12:46' prior: 0!\\nOBVariableNode is an abstract superclass for the two types of variables a class can contain - class variables and instance variables. The only difference between the two subclasses is how they search for methods that refer to them.!\\n\\n\\n!OBVariableNode methodsFor: 'actions' stamp: 'cwp 12/15/2004 22:38'!\\nactions\\n\\t^ {self browseAction}! !\\n\\n\\n!OBVariableNode methodsFor: 'displaying'!\\nname\\n\\t^ name! !\\n\\n\\n!OBVariableNode methodsFor: 'initializing'!\\nsetName: aString class: aClass\\n\\tname := aString.\\n\\tself theClass: aClass! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBVariableNode class\\n\\tinstanceVariableNames: ''!\\n\\n!OBVariableNode class methodsFor: 'instance creation'!\\non: instVarName inClass: aClassReference \\n\\t^ self new setName: instVarName class: aClassReference! !\\nOBListBrowser subclass: #OBVariablesBrowser\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBVariablesBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBVariablesBrowser class methodsFor: 'as yet unclassified' stamp: 'avi 9/17/2005 01:22'!\\ndefaultMetaNode\\n\\t| class method message var |\\n\\tclass := OBMetaNode named: 'Class'.\\n\\tvar := OBMetaNode named: 'Variable'.\\n\\tmethod := OBMetaNode named: 'Method'.\\n\\tmessage := OBMetaNode named: 'Message'.\\n\\tclass\\n\\t\\taddActor: OBNodeActor new;\\n\\t\\tchildAt: #instanceVariables labeled: 'instance' put: var;\\n\\t\\tchildAt: #classVariables labeled: 'class' put: var;\\n\\t\\tfilterClass: OBModalFilter.\\n\\tvar\\n\\t\\tchildAt: #accessors put: method;\\n\\t\\taddActor: OBNodeActor new;\\n\\t\\tfilterClass: OBModalFilter.\\n\\tmethod\\n\\t\\tdisplaySelector: #fullName;\\n\\t\\taddActor: OBNodeActor new;\\n\\t\\tchildAt: #senders put: message;\\n\\t\\tfilterClass: OBModalFilter.\\n\\tmessage\\n\\t\\tdisplaySelector: #fullName;\\n\\t\\taddActor: OBNodeActor new;\\n\\t\\tchildAt: #senders put: message;\\n\\t\\tfilterClass: OBModalFilter.\\n\\t\\n\\t^ class! !\\n\\n!OBVariablesBrowser class methodsFor: 'as yet unclassified' stamp: 'avi 9/17/2005 01:35'!\\ntitle\\n\\t^ 'Variables of'! !\\nOBCodeBrowser subclass: #OBVersionBrowser\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'OB-Standard-Browsers'!\\n!OBVersionBrowser commentStamp: 'cwp 1/7/2005 23:58' prior: 0!\\nOBVersionBrowser displays a list of OBMethodVersions, which represent versions of a method present in the source or changes files. !\\n\\n\\n!OBVersionBrowser methodsFor: 'morphic' stamp: 'avi 11/29/2004 21:52'!\\ndefaultBackgroundColor\\n\\t^ Color lightMagenta! !\\n\\n\\n!OBVersionBrowser methodsFor: 'accessing' stamp: 'cwp 11/27/2004 22:28'!\\ndefaultLabel\\n\\t^ 'Versions of ', self root name printString! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOBVersionBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!OBVersionBrowser class methodsFor: 'configuration' stamp: 'avi 9/17/2005 01:09'!\\ndefaultMetaNode\\n\\t| version |\\n\\tversion := OBMetaNode named: 'Version'.\\n\\tversion addActor: OBNodeActor new.\\n\\t^ (OBMetaNode named: 'Method') \\n\\t\\tchildAt: #versions put: version.! !\\n\\n!OBVersionBrowser class methodsFor: 'configuration' stamp: 'cwp 11/27/2004 22:32'!\\nmaxPanes\\n\\t^ 1! !\\n\\n!OBVersionBrowser class methodsFor: 'configuration' stamp: 'cwp 11/27/2004 22:32'!\\nminPanes\\n\\t^ 1! !\\n\\n!OBVersionBrowser class methodsFor: 'configuration' stamp: 'cwp 11/27/2004 22:34'!\\noptionalButtons\\n\\t^ #('browse' 'revert')! !\\n\\n\\n!OBVersionBrowser class methodsFor: 'opening' stamp: 'cwp 12/5/2004 15:42'!\\nopenOn: aMethodVersionNode\\n\\t^ (self root: aMethodVersionNode) open! !\\nProtoObject subclass: #Object\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'DependentsFields'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Objects'!\\n!Object commentStamp: '<historical>' prior: 0!\\nObject is the root class for almost all of the other classes in the class hierarchy. The exceptions are ProtoObject (the superclass of Object) and its subclasses.\\n\\nClass Object provides default behavior common to all normal objects, such as access, copying, comparison, error handling, message sending, and reflection. Also utility messages that all objects should respond to are defined here.\\n\\nObject has no instance variables, nor should any be added. This is due to several classes of objects that inherit from Object that have special implementations (SmallInteger and UndefinedObject for example) or the VM knows about and depends on the structure and layout of certain standard classes.\\n\\nClass Variables:\\n\\tDependentsFields\\t\\tan IdentityDictionary\\n\\t\\tProvides a virtual 'dependents' field so that any object may have one\\n\\t\\tor more dependent views, synchronized by the changed:/update: protocol.\\n\\t\\tNote that class Model has a real slot for its dependents, and overrides\\n\\t\\tthe associated protocol with more efficient implementations.\\n\\tEventsFields\\t\\t\\tan IdentityDictionary that maps each object to its dependents.\\n\\t\\tRegisters a message send (consisting of a selector and a receiver object)\\n\\t\\twhich should be performed when anEventSymbol is triggered by the receiver.\\n\\t\\tPart of a new event notification framework which could eventually replace\\n\\t\\tthe existing changed/update mechanism. It is intended to be compatible\\n\\t\\twith Dolphin Smalltalk and VSE as much as possible.\\n\\nBecause Object is the root of the inheritance tree, methods are often defined in Object to give all objects special behaviors needed by certain subsystems or applications, or to respond to certain general test messages such as isMorph.!\\n\\n\\n!Object methodsFor: 'accessing' stamp: 'sw 4/30/1998 12:18'!\\naddInstanceVarNamed: aName withValue: aValue\\n\\t\\\"Add an instance variable named aName and give it value aValue\\\"\\n\\tself class addInstVarName: aName asString.\\n\\tself instVarAt: self class instSize put: aValue! !\\n\\n!Object methodsFor: 'accessing' stamp: 'yo 6/29/2004 11:39'!\\nat: index \\n\\t\\\"Primitive. Assumes receiver is indexable. Answer the value of an \\n\\tindexable element in the receiver. Fail if the argument index is not an \\n\\tInteger or is out of bounds. Essential. See Object documentation \\n\\twhatIsAPrimitive.\\\"\\n\\n\\t<primitive: 60>\\n\\tindex isInteger ifTrue:\\n\\t\\t[self class isVariable\\n\\t\\t\\tifTrue: [self errorSubscriptBounds: index]\\n\\t\\t\\tifFalse: [self errorNotIndexable]].\\n\\tindex isNumber\\n\\t\\tifTrue: [^self at: index asInteger]\\n\\t\\tifFalse: [self errorNonIntegerIndex]! !\\n\\n!Object methodsFor: 'accessing'!\\nat: index modify: aBlock\\n\\t\\\"Replace the element of the collection with itself transformed by the block\\\"\\n\\t^ self at: index put: (aBlock value: (self at: index))! !\\n\\n!Object methodsFor: 'accessing' stamp: 'yo 6/29/2004 13:08'!\\nat: index put: value \\n\\t\\\"Primitive. Assumes receiver is indexable. Store the argument value in \\n\\tthe indexable element of the receiver indicated by index. Fail if the \\n\\tindex is not an Integer or is out of bounds. Or fail if the value is not of \\n\\tthe right type for this kind of collection. Answer the value that was \\n\\tstored. Essential. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 61>\\n\\tindex isInteger ifTrue:\\n\\t\\t[self class isVariable\\n\\t\\t\\tifTrue: [(index >= 1 and: [index <= self size])\\n\\t\\t\\t\\t\\tifTrue: [self errorImproperStore]\\n\\t\\t\\t\\t\\tifFalse: [self errorSubscriptBounds: index]]\\n\\t\\t\\tifFalse: [self errorNotIndexable]].\\n\\tindex isNumber\\n\\t\\tifTrue: [^self at: index asInteger put: value]\\n\\t\\tifFalse: [self errorNonIntegerIndex]! !\\n\\n!Object methodsFor: 'accessing' stamp: 'yo 9/20/2004 10:22'!\\nbasicAddInstanceVarNamed: aName withValue: aValue\\n\\t\\\"Add an instance variable named aName and give it value aValue\\\"\\n\\tself class addInstVarName: aName asString.\\n\\tself instVarAt: self class instSize put: aValue! !\\n\\n!Object methodsFor: 'accessing'!\\nbasicAt: index \\n\\t\\\"Primitive. Assumes receiver is indexable. Answer the value of an \\n\\tindexable element in the receiver. Fail if the argument index is not an \\n\\tInteger or is out of bounds. Essential. Do not override in a subclass. See \\n\\tObject documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 60>\\n\\tindex isInteger ifTrue: [self errorSubscriptBounds: index].\\n\\tindex isNumber\\n\\t\\tifTrue: [^self basicAt: index asInteger]\\n\\t\\tifFalse: [self errorNonIntegerIndex]! !\\n\\n!Object methodsFor: 'accessing'!\\nbasicAt: index put: value \\n\\t\\\"Primitive. Assumes receiver is indexable. Store the second argument \\n\\tvalue in the indexable element of the receiver indicated by index. Fail \\n\\tif the index is not an Integer or is out of bounds. Or fail if the value is \\n\\tnot of the right type for this kind of collection. Answer the value that \\n\\twas stored. Essential. Do not override in a subclass. See Object \\n\\tdocumentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 61>\\n\\tindex isInteger\\n\\t\\tifTrue: [(index >= 1 and: [index <= self size])\\n\\t\\t\\t\\t\\tifTrue: [self errorImproperStore]\\n\\t\\t\\t\\t\\tifFalse: [self errorSubscriptBounds: index]].\\n\\tindex isNumber\\n\\t\\tifTrue: [^self basicAt: index asInteger put: value]\\n\\t\\tifFalse: [self errorNonIntegerIndex]! !\\n\\n!Object methodsFor: 'accessing'!\\nbasicSize\\n\\t\\\"Primitive. Answer the number of indexable variables in the receiver. \\n\\tThis value is the same as the largest legal subscript. Essential. Do not \\n\\toverride in any subclass. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 62>\\n\\t\\\"The number of indexable fields of fixed-length objects is 0\\\"\\n\\t^0\\t! !\\n\\n!Object methodsFor: 'accessing'!\\nbindWithTemp: aBlock\\n\\t^ aBlock value: self value: nil! !\\n\\n!Object methodsFor: 'accessing' stamp: 'md 10/7/2004 15:43'!\\nifNil: nilBlock ifNotNilDo: aBlock \\n\\t\\\"Evaluate aBlock with the receiver as its argument.\\\"\\n\\n\\t^ aBlock value: self\\n! !\\n\\n!Object methodsFor: 'accessing' stamp: 'di 11/8/2000 21:04'!\\nifNotNilDo: aBlock\\n\\t\\\"Evaluate the given block with the receiver as its argument.\\\"\\n\\n\\t^ aBlock value: self\\n! !\\n\\n!Object methodsFor: 'accessing' stamp: 'md 10/7/2004 15:43'!\\nifNotNilDo: aBlock ifNil: nilBlock\\n\\t\\\"Evaluate aBlock with the receiver as its argument.\\\"\\n\\n\\t^ aBlock value: self\\n! !\\n\\n!Object methodsFor: 'accessing' stamp: 'ajh 1/21/2003 12:59'!\\nin: aBlock\\n\\t\\\"Evaluate the given block with the receiver as its argument.\\\"\\n\\n\\t^ aBlock value: self\\n! !\\n\\n!Object methodsFor: 'accessing' stamp: 'sw 10/17/2000 11:15'!\\npresenter\\n\\t\\\"Answer the presenter object associated with the receiver. For morphs, there is in effect a clear containment hierarchy of presenters (accessed via their association with PasteUpMorphs); for arbitrary objects the hook is simply via the current world, at least at present.\\\"\\n\\n\\t^ self currentWorld presenter! !\\n\\n!Object methodsFor: 'accessing'!\\nreadFromString: aString\\n\\t\\\"Create an object based on the contents of aString.\\\"\\n\\n\\t^self readFrom: (ReadStream on: aString)! !\\n\\n!Object methodsFor: 'accessing' stamp: 'di 3/29/1999 13:10'!\\nsize\\n\\t\\\"Primitive. Answer the number of indexable variables in the receiver. \\n\\tThis value is the same as the largest legal subscript. Essential. See Object \\n\\tdocumentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 62>\\n\\tself class isVariable ifFalse: [self errorNotIndexable].\\n\\t^ 0! !\\n\\n!Object methodsFor: 'accessing' stamp: 'md 5/16/2006 12:34'!\\nyourself\\n\\t\\\"Answer self.\\\"\\n\\t^self! !\\n\\n\\n!Object methodsFor: 'associating' stamp: 'md 7/22/2005 16:03'!\\n-> anObject\\n\\t\\\"Answer an Association between self and anObject\\\"\\n\\n\\t^Association basicNew key: self value: anObject! !\\n\\n\\n\\n!Object methodsFor: 'binding'!\\nbindingOf: aString\\n\\t^nil! !\\n\\n\\n!Object methodsFor: 'casing'!\\ncaseOf: aBlockAssociationCollection\\n\\t\\\"The elements of aBlockAssociationCollection are associations between blocks.\\n\\t Answer the evaluated value of the first association in aBlockAssociationCollection\\n\\t whose evaluated key equals the receiver. If no match is found, report an error.\\\"\\n\\n\\t^ self caseOf: aBlockAssociationCollection otherwise: [self caseError]\\n\\n\\\"| z | z _ {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z\\\"\\n\\\"| z | z _ {[#a]->[1+1]. ['d' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z\\\"\\n\\\"The following are compiled in-line:\\\"\\n\\\"#b caseOf: {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}\\\"\\n\\\"#b caseOf: {[#a]->[1+1]. ['d' asSymbol]->[2+2]. [#c]->[3+3]}\\\"! !\\n\\n!Object methodsFor: 'casing'!\\ncaseOf: aBlockAssociationCollection otherwise: aBlock\\n\\t\\\"The elements of aBlockAssociationCollection are associations between blocks.\\n\\t Answer the evaluated value of the first association in aBlockAssociationCollection\\n\\t whose evaluated key equals the receiver. If no match is found, answer the result\\n\\t of evaluating aBlock.\\\"\\n\\n\\taBlockAssociationCollection associationsDo:\\n\\t\\t[:assoc | (assoc key value = self) ifTrue: [^assoc value value]].\\n\\t^ aBlock value\\n\\n\\\"| z | z _ {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z otherwise: [0]\\\"\\n\\\"| z | z _ {[#a]->[1+1]. ['d' asSymbol]->[2+2]. [#c]->[3+3]}. #b caseOf: z otherwise: [0]\\\"\\n\\\"The following are compiled in-line:\\\"\\n\\\"#b caseOf: {[#a]->[1+1]. ['b' asSymbol]->[2+2]. [#c]->[3+3]} otherwise: [0]\\\"\\n\\\"#b caseOf: {[#a]->[1+1]. ['d' asSymbol]->[2+2]. [#c]->[3+3]} otherwise: [0]\\\"! !\\n\\n\\n!Object methodsFor: 'class membership'!\\nclass\\n\\t\\\"Primitive. Answer the object which is the receiver's class. Essential. See \\n\\tObject documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 111>\\n\\tself primitiveFailed! !\\n\\n!Object methodsFor: 'class membership' stamp: 'sw 9/27/2001 15:51'!\\ninheritsFromAnyIn: aList\\n\\t\\\"Answer whether the receiver inherits from any class represented by any element in the list. The elements of the list can be classes, class name symbols, or strings representing possible class names. This allows speculative membership tests to be made even when some of the classes may not be known to the current image, and even when their names are not interned symbols.\\\"\\n\\n\\t| aClass |\\n\\taList do:\\n\\t\\t[:elem | Symbol hasInterned: elem asString ifTrue: \\n\\t\\t\\t[:elemSymbol | (((aClass _ Smalltalk at: elemSymbol ifAbsent: [nil]) isKindOf: Class)\\n\\t\\t\\t\\t\\t\\tand: [self isKindOf: aClass])\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[^ true]]].\\n\\t^ false\\n\\n\\n\\\"\\n{3. true. 'olive'} do:\\n\\t[:token |\\n\\t\\t {{#Number. #Boolean}. {Number. Boolean }. {'Number'. 'Boolean'}} do:\\n\\t\\t\\t[:list |\\n\\t\\t\\t\\tTranscript cr; show: token asString, ' list element provided as a ', list first class name, ' - ', (token inheritsFromAnyIn: list) asString]]\\n\\\"! !\\n\\n!Object methodsFor: 'class membership'!\\nisKindOf: aClass \\n\\t\\\"Answer whether the class, aClass, is a superclass or class of the receiver.\\\"\\n\\n\\tself class == aClass\\n\\t\\tifTrue: [^true]\\n\\t\\tifFalse: [^self class inheritsFrom: aClass]! !\\n\\n!Object methodsFor: 'class membership' stamp: 'sw 2/16/98 02:08'!\\nisKindOf: aClass orOf: anotherClass\\n\\t\\\"Answer whether either of the classes, aClass or anotherClass,, is a superclass or class of the receiver. A convenience; could be somewhat optimized\\\"\\n\\t^ (self isKindOf: aClass) or: [self isKindOf: anotherClass]! !\\n\\n!Object methodsFor: 'class membership'!\\nisMemberOf: aClass \\n\\t\\\"Answer whether the receiver is an instance of the class, aClass.\\\"\\n\\n\\t^self class == aClass! !\\n\\n!Object methodsFor: 'class membership'!\\nrespondsTo: aSymbol \\n\\t\\\"Answer whether the method dictionary of the receiver's class contains \\n\\taSymbol as a message selector.\\\"\\n\\n\\t^self class canUnderstand: aSymbol! !\\n\\n!Object methodsFor: 'class membership' stamp: 'tk 10/21/1998 12:38'!\\nxxxClass\\n\\t\\\"For subclasses of nil, such as ObjectOut\\\"\\n\\t^ self class! !\\n\\n\\n!Object methodsFor: 'comparing' stamp: 'tk 4/16/1999 18:26'!\\ncloseTo: anObject\\n\\t\\\"Answer whether the receiver and the argument represent the same\\n\\tobject. If = is redefined in any subclass, consider also redefining the\\n\\tmessage hash.\\\"\\n\\n\\t| ans |\\n\\t[ans _ self = anObject] ifError: [:aString :aReceiver | ^ false].\\n\\t^ ans! !\\n\\n!Object methodsFor: 'comparing'!\\nhash\\n\\t\\\"Answer a SmallInteger whose value is related to the receiver's identity.\\n\\tMay be overridden, and should be overridden in any classes that define = \\\"\\n\\n\\t^ self identityHash! !\\n\\n!Object methodsFor: 'comparing' stamp: 'pm 9/23/97 09:36'!\\nhashMappedBy: map\\n\\t\\\"Answer what my hash would be if oops changed according to map.\\\"\\n\\n\\t^map newHashFor: self! !\\n\\n!Object methodsFor: 'comparing' stamp: 'di 9/27/97 20:23'!\\nidentityHashMappedBy: map\\n\\t\\\"Answer what my hash would be if oops changed according to map.\\\"\\n\\n\\t^map newHashFor: self! !\\n\\n!Object methodsFor: 'comparing' stamp: 'sw 8/20/1998 12:34'!\\nidentityHashPrintString\\n\\t\\\"'fred' identityHashPrintString\\\"\\n\\n\\t^ '(', self identityHash printString, ')'! !\\n\\n!Object methodsFor: 'comparing' stamp: 'ajh 2/2/2002 15:02'!\\nliteralEqual: other\\n\\n\\t^ self class == other class and: [self = other]! !\\n\\n!Object methodsFor: 'comparing'!\\n= anObject \\n\\t\\\"Answer whether the receiver and the argument represent the same \\n\\tobject. If = is redefined in any subclass, consider also redefining the \\n\\tmessage hash.\\\"\\n\\n\\t^self == anObject! !\\n\\n!Object methodsFor: 'comparing'!\\n~= anObject \\n\\t\\\"Answer whether the receiver and the argument do not represent the \\n\\tsame object.\\\"\\n\\n\\t^self = anObject == false! !\\n\\n\\n!Object methodsFor: 'converting' stamp: 'di 11/9/1998 12:15'!\\nadaptToFloat: rcvr andSend: selector\\n\\t\\\"If no method has been provided for adapting an object to a Float,\\n\\tthen it may be adequate to simply adapt it to a number.\\\"\\n\\t^ self adaptToNumber: rcvr andSend: selector! !\\n\\n!Object methodsFor: 'converting' stamp: 'di 11/9/1998 12:14'!\\nadaptToFraction: rcvr andSend: selector\\n\\t\\\"If no method has been provided for adapting an object to a Fraction,\\n\\tthen it may be adequate to simply adapt it to a number.\\\"\\n\\t^ self adaptToNumber: rcvr andSend: selector! !\\n\\n!Object methodsFor: 'converting' stamp: 'di 11/9/1998 12:15'!\\nadaptToInteger: rcvr andSend: selector\\n\\t\\\"If no method has been provided for adapting an object to a Integer,\\n\\tthen it may be adequate to simply adapt it to a number.\\\"\\n\\t^ self adaptToNumber: rcvr andSend: selector! !\\n\\n!Object methodsFor: 'converting' stamp: 'rw 4/27/2002 07:48'!\\nasActionSequence\\n\\n\\t^WeakActionSequence with: self! !\\n\\n!Object methodsFor: 'converting' stamp: 'rw 7/20/2003 16:03'!\\nasActionSequenceTrappingErrors\\n\\n\\t^WeakActionSequenceTrappingErrors with: self! !\\n\\n!Object methodsFor: 'converting' stamp: 'svp 5/16/2000 18:14'!\\nasDraggableMorph\\n\\t^(StringMorph contents: self printString)\\n\\t\\tcolor: Color white;\\n\\t\\tyourself! !\\n\\n!Object methodsFor: 'converting' stamp: 'sma 5/12/2000 17:39'!\\nasOrderedCollection\\n\\t\\\"Answer an OrderedCollection with the receiver as its only element.\\\"\\n\\n\\t^ OrderedCollection with: self! !\\n\\n!Object methodsFor: 'converting'!\\nasString\\n\\t\\\"Answer a string that represents the receiver.\\\"\\n\\n\\t^ self printString ! !\\n\\n!Object methodsFor: 'converting' stamp: 'ajh 3/11/2003 10:27'!\\nasStringOrText\\n\\t\\\"Answer a string that represents the receiver.\\\"\\n\\n\\t^ self printString ! !\\n\\n!Object methodsFor: 'converting'!\\nas: aSimilarClass\\n\\t\\\"Create an object of class aSimilarClass that has similar contents to the receiver.\\\"\\n\\n\\t^ aSimilarClass newFrom: self! !\\n\\n!Object methodsFor: 'converting' stamp: 'RAA 8/2/1999 12:41'!\\ncomplexContents\\n\\n\\t^self! !\\n\\n!Object methodsFor: 'converting' stamp: 'ajh 7/6/2003 20:37'!\\nmustBeBoolean\\n\\t\\\"Catches attempts to test truth of non-Booleans. This message is sent from the VM. The sending context is rewound to just before the jump causing this exception.\\\"\\n\\n\\t^ self mustBeBooleanIn: thisContext sender! !\\n\\n!Object methodsFor: 'converting' stamp: 'ajh 7/6/2003 20:40'!\\nmustBeBooleanIn: context\\n\\t\\\"context is the where the non-boolean error occurred. Rewind context to before jump then raise error.\\\"\\n\\n\\t| proceedValue |\\n\\tcontext skipBackBeforeJump.\\n\\tproceedValue _ NonBooleanReceiver new\\n\\t\\tobject: self;\\n\\t\\tsignal: 'proceed for truth.'.\\n\\t^ proceedValue ~~ false! !\\n\\n!Object methodsFor: 'converting' stamp: 'sw 3/26/2001 12:12'!\\nprintDirectlyToDisplay\\n\\t\\\"For debugging: write the receiver's printString directly to the display at (0, 100); senders of this are detected by the check-for-slips mechanism.\\\"\\n\\n\\tself asString displayAt: 0@100\\n\\n\\\"StringMorph someInstance printDirectlyToDisplay\\\"! !\\n\\n!Object methodsFor: 'converting' stamp: 'RAA 3/31/1999 12:13'!\\nwithoutListWrapper\\n\\n\\t^self! !\\n\\n\\n!Object methodsFor: 'copying'!\\nclone\\n\\n\\t<primitive: 148>\\n\\tself primitiveFailed! !\\n\\n!Object methodsFor: 'copying' stamp: 'ajh 8/18/2001 21:25'!\\ncopy\\n\\t\\\"Answer another instance just like the receiver. Subclasses typically override postCopy; they typically do not override shallowCopy.\\\"\\n\\n\\t^self shallowCopy postCopy! !\\n\\n!Object methodsFor: 'copying' stamp: 'tk 8/20/1998 16:01'!\\ncopyAddedStateFrom: anotherObject\\n\\t\\\"Copy over the values of instance variables added by the receiver's class from anotherObject to the receiver. These will be remapped in mapUniClasses, if needed.\\\"\\n\\n\\tself class superclass instSize + 1 to: self class instSize do:\\n\\t\\t[:index | self instVarAt: index put: (anotherObject instVarAt: index)]! !\\n\\n!Object methodsFor: 'copying' stamp: 'tpr 2/14/2004 21:53'!\\ncopyFrom: anotherObject\\n\\t\\\"Copy to myself all instance variables I have in common with anotherObject. This is dangerous because it ignores an object's control over its own inst vars. \\\"\\n\\n\\t| mine his |\\n\\t<primitive: 168>\\n\\tmine _ self class allInstVarNames.\\n\\this _ anotherObject class allInstVarNames.\\n\\t1 to: (mine size min: his size) do: [:ind |\\n\\t\\t(mine at: ind) = (his at: ind) ifTrue: [\\n\\t\\t\\tself instVarAt: ind put: (anotherObject instVarAt: ind)]].\\n\\tself class isVariable & anotherObject class isVariable ifTrue: [\\n\\t\\t1 to: (self basicSize min: anotherObject basicSize) do: [:ind |\\n\\t\\t\\tself basicAt: ind put: (anotherObject basicAt: ind)]].! !\\n\\n!Object methodsFor: 'copying' stamp: 'ajh 5/23/2002 00:38'!\\ncopySameFrom: otherObject\\n\\t\\\"Copy to myself all instance variables named the same in otherObject.\\n\\tThis ignores otherObject's control over its own inst vars.\\\"\\n\\n\\t| myInstVars otherInstVars match |\\n\\tmyInstVars _ self class allInstVarNames.\\n\\totherInstVars _ otherObject class allInstVarNames.\\n\\tmyInstVars doWithIndex: [:each :index |\\n\\t\\t(match _ otherInstVars indexOf: each) > 0 ifTrue:\\n\\t\\t\\t[self instVarAt: index put: (otherObject instVarAt: match)]].\\n\\t1 to: (self basicSize min: otherObject basicSize) do: [:i |\\n\\t\\tself basicAt: i put: (otherObject basicAt: i)].\\n! !\\n\\n!Object methodsFor: 'copying' stamp: 'tk 4/20/1999 14:44'!\\ncopyTwoLevel\\n\\t\\\"one more level than a shallowCopy\\\"\\n\\n\\t| newObject class index |\\n\\tclass _ self class.\\n\\tnewObject _ self clone.\\n\\tnewObject == self ifTrue: [^ self].\\n\\tclass isVariable\\n\\t\\tifTrue: \\n\\t\\t\\t[index _ self basicSize.\\n\\t\\t\\t[index > 0]\\n\\t\\t\\t\\twhileTrue: \\n\\t\\t\\t\\t\\t[newObject basicAt: index put: (self basicAt: index) shallowCopy.\\n\\t\\t\\t\\t\\tindex _ index - 1]].\\n\\tindex _ class instSize.\\n\\t[index > 0]\\n\\t\\twhileTrue: \\n\\t\\t\\t[newObject instVarAt: index put: (self instVarAt: index) shallowCopy.\\n\\t\\t\\tindex _ index - 1].\\n\\t^newObject! !\\n\\n!Object methodsFor: 'copying'!\\ndeepCopy\\n\\t\\\"Answer a copy of the receiver with its own copy of each instance \\n\\tvariable.\\\"\\n\\n\\t| newObject class index |\\n\\tclass _ self class.\\n\\t(class == Object) ifTrue: [^self].\\n\\tclass isVariable\\n\\t\\tifTrue: \\n\\t\\t\\t[index _ self basicSize.\\n\\t\\t\\tnewObject _ class basicNew: index.\\n\\t\\t\\t[index > 0]\\n\\t\\t\\t\\twhileTrue: \\n\\t\\t\\t\\t\\t[newObject basicAt: index put: (self basicAt: index) deepCopy.\\n\\t\\t\\t\\t\\tindex _ index - 1]]\\n\\t\\tifFalse: [newObject _ class basicNew].\\n\\tindex _ class instSize.\\n\\t[index > 0]\\n\\t\\twhileTrue: \\n\\t\\t\\t[newObject instVarAt: index put: (self instVarAt: index) deepCopy.\\n\\t\\t\\tindex _ index - 1].\\n\\t^newObject! !\\n\\n!Object methodsFor: 'copying' stamp: 'hg 11/23/1999 13:43'!\\ninitialDeepCopierSize\\n\\t\\\"default value is 4096; other classes may override this, esp. for smaller (=faster) sizes\\\"\\n\\n\\t^4096! !\\n\\n!Object methodsFor: 'copying' stamp: 'ajh 1/27/2003 18:45'!\\npostCopy\\n\\t\\\"self is a shallow copy, subclasses should copy fields as necessary to complete the full copy\\\"\\n\\n\\t^ self! !\\n\\n!Object methodsFor: 'copying' stamp: 'jm 11/14/97 11:08'!\\nshallowCopy\\n\\t\\\"Answer a copy of the receiver which shares the receiver's instance variables.\\\"\\n\\t| class newObject index |\\n\\t<primitive: 148>\\n\\tclass _ self class.\\n\\tclass isVariable\\n\\t\\tifTrue: \\n\\t\\t\\t[index _ self basicSize.\\n\\t\\t\\tnewObject _ class basicNew: index.\\n\\t\\t\\t[index > 0]\\n\\t\\t\\t\\twhileTrue: \\n\\t\\t\\t\\t\\t[newObject basicAt: index put: (self basicAt: index).\\n\\t\\t\\t\\t\\tindex _ index - 1]]\\n\\t\\tifFalse: [newObject _ class basicNew].\\n\\tindex _ class instSize.\\n\\t[index > 0]\\n\\t\\twhileTrue: \\n\\t\\t\\t[newObject instVarAt: index put: (self instVarAt: index).\\n\\t\\t\\tindex _ index - 1].\\n\\t^ newObject! !\\n\\n!Object methodsFor: 'copying' stamp: 'tk 3/11/2003 13:58'!\\nveryDeepCopy\\n\\t\\\"Do a complete tree copy using a dictionary. An object in the tree twice is only copied once. All references to the object in the copy of the tree will point to the new copy.\\\"\\n\\n\\t| copier new |\\n\\tcopier _ DeepCopier new initialize: self initialDeepCopierSize.\\n\\tnew _ self veryDeepCopyWith: copier.\\n\\tcopier mapUniClasses.\\n\\tcopier references associationsDo: [:assoc | \\n\\t\\tassoc value veryDeepFixupWith: copier].\\n\\tcopier fixDependents.\\n\\t^ new! !\\n\\n!Object methodsFor: 'copying' stamp: 'tk 3/11/2003 13:58'!\\nveryDeepCopySibling\\n\\t\\\"Do a complete tree copy using a dictionary. Substitute a clone of oldPlayer for the root. Normally, a Player or non systemDefined object would have a new class. We do not want one this time. An object in the tree twice, is only copied once. All references to the object in the copy of the tree will point to the new copy.\\\"\\n\\n\\t| copier new |\\n\\tcopier _ DeepCopier new initialize: self initialDeepCopierSize.\\n\\tcopier newUniClasses: false.\\n\\tnew _ self veryDeepCopyWith: copier.\\n\\tcopier mapUniClasses.\\n\\tcopier references associationsDo: [:assoc | \\n\\t\\tassoc value veryDeepFixupWith: copier].\\n\\tcopier fixDependents.\\n\\t^ new! !\\n\\n!Object methodsFor: 'copying' stamp: 'tk 5/13/2003 19:39'!\\nveryDeepCopyUsing: copier\\n\\t\\\"Do a complete tree copy using a dictionary. An object in the tree twice is only copied once. All references to the object in the copy of the tree will point to the new copy.\\n\\tSame as veryDeepCopy except copier (with dictionary) is supplied.\\n\\t** do not delete this method, even if it has no callers **\\\"\\n\\n\\t| new refs newDep newModel |\\n\\tnew _ self veryDeepCopyWith: copier.\\n\\tcopier mapUniClasses.\\n\\tcopier references associationsDo: [:assoc | \\n\\t\\tassoc value veryDeepFixupWith: copier].\\n\\t\\\"Fix dependents\\\"\\n\\trefs _ copier references.\\n\\tDependentsFields associationsDo: [:pair |\\n\\t\\tpair value do: [:dep | \\n\\t\\t\\t(newDep _ refs at: dep ifAbsent: [nil]) ifNotNil: [\\n\\t\\t\\t\\tnewModel _ refs at: pair key ifAbsent: [pair key].\\n\\t\\t\\t\\tnewModel addDependent: newDep]]].\\n\\t^ new! !\\n\\n!Object methodsFor: 'copying' stamp: 'tk 3/11/2003 14:12'!\\nveryDeepCopyWith: deepCopier\\n\\t\\\"Copy me and the entire tree of objects I point to. An object in the tree twice is copied once, and both references point to him. deepCopier holds a dictionary of objects we have seen. Some classes refuse to be copied. Some classes are picky about which fields get deep copied.\\\"\\n\\t| class index sub subAss new uc sup has mine |\\n\\tdeepCopier references at: self ifPresent: [:newer | ^ newer]. \\t\\\"already did him\\\"\\n\\tclass _ self class.\\n\\tclass isMeta ifTrue: [^ self].\\t\\t\\\"a class\\\"\\n\\tnew _ self clone.\\n\\t(class isSystemDefined not and: [deepCopier newUniClasses \\\"allowed\\\"]) ifTrue: [\\n\\t\\tuc _ deepCopier uniClasses at: class ifAbsent: [nil].\\n\\t\\tuc ifNil: [\\n\\t\\t\\tdeepCopier uniClasses at: class put: (uc _ self copyUniClassWith: deepCopier).\\n\\t\\t\\tdeepCopier references at: class put: uc].\\t\\\"remember\\\"\\n\\t\\tnew _ uc new.\\n\\t\\tnew copyFrom: self].\\t\\\"copy inst vars in case any are weak\\\"\\n\\tdeepCopier references at: self put: new.\\t\\\"remember\\\"\\n\\t(class isVariable and: [class isPointers]) ifTrue: \\n\\t\\t[index _ self basicSize.\\n\\t\\t[index > 0] whileTrue: \\n\\t\\t\\t[sub _ self basicAt: index.\\n\\t\\t\\t(subAss _ deepCopier references associationAt: sub ifAbsent: [nil])\\n\\t\\t\\t\\tifNil: [new basicAt: index put: (sub veryDeepCopyWith: deepCopier)]\\n\\t\\t\\t\\tifNotNil: [new basicAt: index put: subAss value].\\n\\t\\t\\tindex _ index - 1]].\\n\\t\\\"Ask each superclass if it wants to share (weak copy) any inst vars\\\"\\n\\tnew veryDeepInner: deepCopier.\\t\\t\\\"does super a lot\\\"\\n\\n\\t\\\"other superclasses want all inst vars deep copied\\\"\\n\\tsup _ class. index _ class instSize.\\n\\t[has _ sup compiledMethodAt: #veryDeepInner: ifAbsent: [nil].\\n\\thas _ has ifNil: [class isSystemDefined not \\\"is a uniClass\\\"] ifNotNil: [true].\\n\\tmine _ sup instVarNames.\\n\\thas ifTrue: [index _ index - mine size]\\t\\\"skip inst vars\\\"\\n\\t\\tifFalse: [1 to: mine size do: [:xx |\\n\\t\\t\\t\\tsub _ self instVarAt: index.\\n\\t\\t\\t\\t(subAss _ deepCopier references associationAt: sub ifAbsent: [nil])\\n\\t\\t\\t\\t\\t\\t\\\"use association, not value, so nil is an exceptional value\\\"\\n\\t\\t\\t\\t\\tifNil: [new instVarAt: index put: \\n\\t\\t\\t\\t\\t\\t\\t\\t(sub veryDeepCopyWith: deepCopier)]\\n\\t\\t\\t\\t\\tifNotNil: [new instVarAt: index put: subAss value].\\n\\t\\t\\t\\tindex _ index - 1]].\\n\\t(sup _ sup superclass) == nil] whileFalse.\\n\\tnew rehash.\\t\\\"force Sets and Dictionaries to rehash\\\"\\n\\t^ new\\n! !\\n\\n!Object methodsFor: 'copying' stamp: 'tk 1/6/1999 17:39'!\\nveryDeepFixupWith: deepCopier\\n\\t\\\"I have no fields and no superclass. Catch the super call.\\\"\\n! !\\n\\n!Object methodsFor: 'copying' stamp: 'tk 9/4/2001 10:30'!\\nveryDeepInner: deepCopier\\n\\t\\\"No special treatment for inst vars of my superclasses. Override when some need to be weakly copied. Object>>veryDeepCopyWith: will veryDeepCopy any inst var whose class does not actually define veryDeepInner:\\\"\\n! !\\n\\n\\n!Object methodsFor: 'creation' stamp: 'nk 2/26/2004 13:33'!\\nasMorph\\n\\t\\\"Open a morph, as best one can, on the receiver\\\"\\n\\n\\t^ self asStringMorph\\n\\n\\t\\\"\\n234 asMorph\\n(ScriptingSystem formAtKey: #TinyMenu) asMorph\\n'fred' asMorph\\n\\\"\\n\\n! !\\n\\n!Object methodsFor: 'creation' stamp: 'nk 2/26/2004 13:35'!\\nasStringMorph\\n\\t\\\"Open a StringMorph, as best one can, on the receiver\\\"\\n\\n\\t^ self asStringOrText asStringMorph\\n! !\\n\\n!Object methodsFor: 'creation' stamp: 'nk 2/26/2004 13:35'!\\nasTextMorph\\n\\t\\\"Open a TextMorph, as best one can, on the receiver\\\"\\n\\n\\t^ TextMorph new contentsAsIs: self asStringOrText\\n! !\\n\\n!Object methodsFor: 'creation' stamp: 'sw 1/29/2002 21:45'!\\nopenAsMorph\\n\\t\\\"Open a morph, as best one can, on the receiver\\\"\\n\\n\\t^ self asMorph openInHand\\n\\n\\\"\\n234 openAsMorph\\n(ScriptingSystem formAtKey: #TinyMenu) openAsMorph\\n'fred' openAsMorph\\n\\\"! !\\n\\n\\n!Object methodsFor: 'debugging' stamp: 'md 11/24/2004 11:45'!\\nhaltIf: condition\\n\\t\\\"This is the typical message to use for inserting breakpoints during \\n\\tdebugging. Param can be a block or expression, halt if true.\\n\\tIf the Block has one arg, the receiver is bound to that.\\n \\tIf the condition is a selector, we look up in the callchain. Halt if\\n any method's selector equals selector.\\\"\\n\\t| cntxt |\\n\\n\\tcondition isSymbol ifTrue:[\\n\\t\\t\\\"only halt if a method with selector symbol is in callchain\\\"\\n\\t\\tcntxt := thisContext.\\n\\t\\t[cntxt sender isNil] whileFalse: [\\n\\t\\t\\tcntxt := cntxt sender. \\n\\t\\t\\t(cntxt selector = condition) ifTrue: [Halt signal].\\n\\t\\t\\t].\\n\\t\\t^self.\\n\\t].\\n\\t(condition isBlock \\n\\t\\t\\tifTrue: [condition valueWithPossibleArgument: self] \\n\\t\\t\\tifFalse: [condition] \\n\\t) ifTrue: [\\n\\t\\tHalt signal\\n\\t].! !\\n\\n!Object methodsFor: 'debugging'!\\nneedsWork! !\\n\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:26'!\\ncheckHaltCountExpired\\n\\t| counter |\\n\\tcounter _ Smalltalk at: #HaltCount ifAbsent: [0].\\n\\t^counter = 0! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 5/19/2004 19:04'!\\nclearHaltOnce\\n\\t\\\"Turn on the halt once flag.\\\"\\n\\tSmalltalk at: #HaltOnce put: false! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:30'!\\ndecrementAndCheckHaltCount\\n\\tself decrementHaltCount.\\n\\t^self checkHaltCountExpired! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:28'!\\ndecrementHaltCount\\n\\t| counter |\\n\\tcounter := Smalltalk\\n\\t\\t\\t\\tat: #HaltCount\\n\\t\\t\\t\\tifAbsent: [0].\\n\\tcounter > 0 ifTrue: [\\n\\t\\tcounter _ counter - 1.\\n\\t\\tself setHaltCountTo: counter]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:42'!\\ndoExpiredHaltCount\\n\\tself clearHaltOnce.\\n\\tself removeHaltCount.\\n\\tself halt! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:44'!\\ndoExpiredHaltCount: aString\\n\\tself clearHaltOnce.\\n\\tself removeHaltCount.\\n\\tself halt: aString! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:45'!\\ndoExpiredInspectCount\\n\\tself clearHaltOnce.\\n\\tself removeHaltCount.\\n\\tself inspect! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:43'!\\nhaltOnCount: int \\n\\tself haltOnceEnabled\\n\\t\\tifTrue: [self hasHaltCount\\n\\t\\t\\t\\tifTrue: [self decrementAndCheckHaltCount\\n\\t\\t\\t\\t\\t\\tifTrue: [self doExpiredHaltCount]]\\n\\t\\t\\t\\tifFalse: [int = 1\\n\\t\\t\\t\\t\\t\\tifTrue: [self doExpiredHaltCount]\\n\\t\\t\\t\\t\\t\\tifFalse: [self setHaltCountTo: int - 1]]]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 5/19/2004 19:05'!\\nhaltOnce\\n\\t\\\"Halt unless we have already done it once.\\\"\\n\\tself haltOnceEnabled\\n\\t\\tifTrue: [self clearHaltOnce.\\n\\t\\t\\t^ self halt]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 5/19/2004 19:04'!\\nhaltOnceEnabled\\n\\t^ Smalltalk\\n\\t\\tat: #HaltOnce\\n\\t\\tifAbsent: [false]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 5/19/2004 19:05'!\\nhaltOnce: aString \\n\\t\\\"Halt unless we have already done it once.\\\"\\n\\tself haltOnceEnabled\\n\\t\\tifTrue: [self clearHaltOnce.\\n\\t\\t\\t^ self halt: aString]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:45'!\\nhalt: aString onCount: int \\n\\tself haltOnceEnabled\\n\\t\\tifTrue: [self hasHaltCount\\n\\t\\t\\t\\tifTrue: [self decrementAndCheckHaltCount\\n\\t\\t\\t\\t\\t\\tifTrue: [self doExpiredHaltCount: aString]]\\n\\t\\t\\t\\tifFalse: [int = 1\\n\\t\\t\\t\\t\\t\\tifTrue: [self doExpiredHaltCount: aString]\\n\\t\\t\\t\\t\\t\\tifFalse: [self setHaltCountTo: int - 1]]]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:36'!\\nhasHaltCount\\n\\t^Smalltalk\\n\\t\\t\\t\\tincludesKey: #HaltCount! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:46'!\\ninspectOnCount: int \\n\\tself haltOnceEnabled\\n\\t\\tifTrue: [self hasHaltCount\\n\\t\\t\\t\\tifTrue: [self decrementAndCheckHaltCount\\n\\t\\t\\t\\t\\t\\tifTrue: [self doExpiredInspectCount]]\\n\\t\\t\\t\\tifFalse: [int = 1\\n\\t\\t\\t\\t\\t\\tifTrue: [self doExpiredInspectCount]\\n\\t\\t\\t\\t\\t\\tifFalse: [self setHaltCountTo: int - 1]]]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 5/19/2004 19:05'!\\ninspectOnce\\n\\t\\\"Inspect unless we have already done it once.\\\"\\n\\tself haltOnceEnabled\\n\\t\\tifTrue: [self clearHaltOnce.\\n\\t\\t\\t^ self inspect]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 13:20'!\\ninspectUntilCount: int \\n\\tself haltOnceEnabled\\n\\t\\tifTrue: [self hasHaltCount\\n\\t\\t\\t\\tifTrue: [self decrementAndCheckHaltCount\\n\\t\\t\\t\\t\\t\\tifTrue: [self doExpiredInspectCount]\\n\\t\\t\\t\\t\\t\\tifFalse: [self inspect]]\\n\\t\\t\\t\\tifFalse: [int = 1\\n\\t\\t\\t\\t\\t\\tifTrue: [self doExpiredInspectCount]\\n\\t\\t\\t\\t\\t\\tifFalse: [self setHaltCountTo: int - 1]]]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:49'!\\nremoveHaltCount\\n\\t(Smalltalk includesKey: #HaltCount) ifTrue: [\\n\\t\\tSmalltalk removeKey: #HaltCount]! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 6/2/2004 08:25'!\\nsetHaltCountTo: int\\n\\tSmalltalk at: #HaltCount put: int! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 5/19/2004 19:04'!\\nsetHaltOnce\\n\\t\\\"Turn on the halt once flag.\\\"\\n\\tSmalltalk at: #HaltOnce put: true! !\\n\\n!Object methodsFor: 'debugging-haltOnce' stamp: 'sbw 5/19/2004 19:04'!\\ntoggleHaltOnce\\n\\tself haltOnceEnabled\\n\\t\\tifTrue: [self clearHaltOnce]\\n\\t\\tifFalse: [self setHaltOnce]! !\\n\\n\\n!Object methodsFor: 'dependents access' stamp: 'ar 2/11/2001 01:55'!\\naddDependent: anObject\\n\\t\\\"Make the given object one of the receiver's dependents.\\\"\\n\\n\\t| dependents |\\n\\tdependents _ self dependents.\\n\\t(dependents includes: anObject) ifFalse:\\n\\t\\t[self myDependents: (dependents copyWithDependent: anObject)].\\n\\t^ anObject! !\\n\\n!Object methodsFor: 'dependents access' stamp: 'sma 2/29/2000 19:53'!\\nbreakDependents\\n\\t\\\"Remove all of the receiver's dependents.\\\"\\n\\n\\tself myDependents: nil! !\\n\\n!Object methodsFor: 'dependents access' stamp: 'sma 2/29/2000 19:26'!\\ncanDiscardEdits\\n\\t\\\"Answer true if none of the views on this model has unaccepted edits that matter.\\\"\\n\\n\\tself dependents\\n\\t\\tdo: [:each | each canDiscardEdits ifFalse: [^ false]]\\n\\t\\twithout: self.\\n\\t^ true! !\\n\\n!Object methodsFor: 'dependents access' stamp: 'sma 2/29/2000 19:58'!\\ndependents\\n\\t\\\"Answer a collection of objects that are 'dependent' on the receiver;\\n\\t that is, all objects that should be notified if the receiver changes.\\\"\\n\\n\\t^ self myDependents ifNil: [#()]! !\\n\\n!Object methodsFor: 'dependents access'!\\nevaluate: actionBlock wheneverChangeIn: aspectBlock\\n\\t| viewerThenObject objectThenViewer |\\n\\tobjectThenViewer _ self.\\n\\tviewerThenObject _ ObjectViewer on: objectThenViewer.\\n\\tobjectThenViewer become: viewerThenObject.\\n\\t\\\"--- Then ---\\\"\\n\\tobjectThenViewer xxxViewedObject: viewerThenObject\\n\\t\\t\\tevaluate: actionBlock\\n\\t\\t\\twheneverChangeIn: aspectBlock! !\\n\\n!Object methodsFor: 'dependents access' stamp: 'sma 2/29/2000 19:59'!\\nhasUnacceptedEdits\\n\\t\\\"Answer true if any of the views on this object has unaccepted edits.\\\"\\n\\n\\tself dependents\\n\\t\\tdo: [:each | each hasUnacceptedEdits ifTrue: [^ true]]\\n\\t\\twithout: self.\\n\\t^ false! !\\n\\n!Object methodsFor: 'dependents access' stamp: 'sma 2/29/2000 19:55'!\\nmyDependents\\n\\t\\\"Private. Answer a list of all the receiver's dependents.\\\"\\n\\n\\t^ DependentsFields at: self ifAbsent: []! !\\n\\n!Object methodsFor: 'dependents access' stamp: 'sma 2/29/2000 19:52'!\\nmyDependents: aCollectionOrNil\\n\\t\\\"Private. Set (or remove) the receiver's dependents list.\\\"\\n\\n\\taCollectionOrNil\\n\\t\\tifNil: [DependentsFields removeKey: self ifAbsent: []]\\n\\t\\tifNotNil: [DependentsFields at: self put: aCollectionOrNil]! !\\n\\n!Object methodsFor: 'dependents access' stamp: 'reThink 2/18/2001 17:06'!\\nrelease\\n\\t\\\"Remove references to objects that may refer to the receiver. This message \\n\\tshould be overridden by subclasses with any cycles, in which case the \\n\\tsubclass should also include the expression super release.\\\"\\n\\n\\tself releaseActionMap! !\\n\\n!Object methodsFor: 'dependents access' stamp: 'sma 2/29/2000 20:23'!\\nremoveDependent: anObject\\n\\t\\\"Remove the given object as one of the receiver's dependents.\\\"\\n\\n\\t| dependents |\\n\\tdependents _ self dependents reject: [:each | each == anObject].\\n\\tself myDependents: (dependents isEmpty ifFalse: [dependents]).\\n\\t^ anObject! !\\n\\n\\n!Object methodsFor: 'drag and drop' stamp: 'bh 9/16/2001 18:10'!\\nacceptDroppingMorph: transferMorph event: evt inMorph: dstListMorph \\n\\t\\n\\t^false.! !\\n\\n!Object methodsFor: 'drag and drop' stamp: 'mir 5/16/2000 11:35'!\\ndragAnimationFor: item transferMorph: transferMorph \\n\\t\\\"Default do nothing\\\"! !\\n\\n!Object methodsFor: 'drag and drop' stamp: 'panda 4/28/2000 16:20'!\\ndragPassengerFor: item inMorph: dragSource \\n\\t^item! !\\n\\n!Object methodsFor: 'drag and drop' stamp: 'panda 4/28/2000 16:11'!\\ndragTransferType\\n\\t^nil! !\\n\\n!Object methodsFor: 'drag and drop' stamp: 'panda 4/28/2000 16:05'!\\ndragTransferTypeForMorph: dragSource \\n\\t^nil! !\\n\\n!Object methodsFor: 'drag and drop' stamp: 'mir 5/8/2000 17:19'!\\nwantsDroppedMorph: aMorph event: anEvent inMorph: destinationLM \\n\\t^false! !\\n\\n\\n!Object methodsFor: 'error handling' stamp: 'sma 5/6/2000 19:35'!\\nassert: aBlock\\n\\t\\\"Throw an assertion error if aBlock does not evaluates to true.\\\"\\n\\n\\taBlock value ifFalse: [AssertionFailure signal: 'Assertion failed']! !\\n\\n!Object methodsFor: 'error handling' stamp: 'nk 1/15/2004 10:54'!\\nassert: aBlock descriptionBlock: descriptionBlock\\n\\t\\\"Throw an assertion error if aBlock does not evaluate to true.\\\"\\n\\n\\taBlock value ifFalse: [AssertionFailure signal: descriptionBlock value asString ]! !\\n\\n!Object methodsFor: 'error handling' stamp: 'nk 10/25/2003 16:47'!\\nassert: aBlock description: aString\\n\\t\\\"Throw an assertion error if aBlock does not evaluates to true.\\\"\\n\\n\\taBlock value ifFalse: [AssertionFailure signal: aString ]! !\\n\\n!Object methodsFor: 'error handling' stamp: 'md 10/13/2004 15:59'!\\nbackwardCompatibilityOnly: anExplanationString\\n\\t\\\"Warn that the sending method has been deprecated. Methods that are tagt with #backwardCompatibility:\\n\\t are kept for compatibility.\\\"\\n\\n\\tPreferences showDeprecationWarnings ifTrue:\\n\\t\\t[Deprecation signal: thisContext sender printString, ' has been deprecated (but will be kept for compatibility). ', anExplanationString]! !\\n\\n!Object methodsFor: 'error handling'!\\ncaseError\\n\\t\\\"Report an error from an in-line or explicit case statement.\\\"\\n\\n\\tself error: 'Case not found, and no otherwise clause'! !\\n\\n!Object methodsFor: 'error handling' stamp: 'rbb 3/1/2005 09:26'!\\nconfirm: queryString\\n\\t\\\"Put up a yes/no menu with caption queryString. Answer true if the \\n\\tresponse is yes, false if no. This is a modal question--the user must \\n\\trespond yes or no.\\\"\\n\\n\\t\\\"nil confirm: 'Are you hungry?'\\\"\\n\\n\\t^ UIManager default confirm: queryString! !\\n\\n!Object methodsFor: 'error handling' stamp: 'rbb 3/1/2005 09:27'!\\nconfirm: aString orCancel: cancelBlock\\n\\t\\\"Put up a yes/no/cancel menu with caption aString. Answer true if \\n\\tthe response is yes, false if no. If cancel is chosen, evaluate \\n\\tcancelBlock. This is a modal question--the user must respond yes or no.\\\"\\n\\n\\t^ UIManager default confirm: aString orCancel: cancelBlock! !\\n\\n!Object methodsFor: 'error handling' stamp: 'dew 10/6/2003 18:20'!\\ndeprecated: anExplanationString\\n\\t\\\"Warn that the sending method has been deprecated.\\\"\\n\\n\\tPreferences showDeprecationWarnings ifTrue:\\n\\t\\t[Deprecation signal: thisContext sender printString, ' has been deprecated. ', anExplanationString]! !\\n\\n!Object methodsFor: 'error handling' stamp: 'dew 10/7/2003 00:26'!\\ndeprecated: anExplanationString block: aBlock \\n\\t \\\"Warn that the sender has been deprecated. Answer the value of aBlock on resumption. (Note that #deprecated: is usually the preferred method.)\\\"\\n\\n\\tPreferences showDeprecationWarnings ifTrue:\\n\\t\\t[Deprecation\\n\\t\\t\\tsignal: thisContext sender printString, ' has been deprecated. ', anExplanationString].\\n\\t^ aBlock value.\\n! !\\n\\n!Object methodsFor: 'error handling' stamp: 'md 2/22/2006 21:21'!\\ndoesNotUnderstand: aMessage \\n\\t \\\"Handle the fact that there was an attempt to send the given message to the receiver but the receiver does not understand this message (typically sent from the machine when a message is sent to the receiver and no method is defined for that selector).\\\"\\n\\t\\\"Testing: (3 activeProcess)\\\"\\n\\n\\tMessageNotUnderstood new \\n\\t\\tmessage: aMessage;\\n\\t\\treceiver: self;\\n\\t\\tsignal.\\n\\t^ aMessage sentTo: self.\\n! !\\n\\n!Object methodsFor: 'error handling' stamp: 'TRee 11/4/2003 16:47'!\\ndpsTrace: reportObject \\n\\tTranscript myDependents isNil ifTrue: [^self].\\n\\tself dpsTrace: reportObject levels: 1 withContext: thisContext\\n\\t\\t\\n\\\" nil dpsTrace: 'sludder'. \\\"! !\\n\\n!Object methodsFor: 'error handling' stamp: 'TRee 11/4/2003 16:49'!\\ndpsTrace: reportObject levels: anInt\\n\\tself dpsTrace: reportObject levels: anInt withContext: thisContext\\n\\n\\\"(1 to: 3) do: [:int | nil dpsTrace: int levels: 5.]\\\"! !\\n\\n!Object methodsFor: 'error handling' stamp: 'TRee 11/4/2003 17:02'!\\ndpsTrace: reportObject levels: anInt withContext: currentContext\\n\\t| reportString context displayCount |\\n\\treportString := (reportObject respondsTo: #asString) \\n\\t\\t\\tifTrue: [reportObject asString] ifFalse: [reportObject printString].\\n\\t(Smalltalk at: #Decompiler ifAbsent: [nil]) \\n\\tifNil: \\n\\t\\t[Transcript cr; show: reportString]\\n\\tifNotNil:\\n\\t\\t[context := currentContext.\\n\\t\\tdisplayCount := anInt > 1.\\n\\t\\t1 to: anInt do:\\n\\t\\t\\t[:count |\\n\\t\\t\\tTranscript cr.\\n\\t\\t\\tdisplayCount\\n\\t\\t\\t\\tifTrue: [Transcript show: count printString, ': '].\\n\\t\\t\\t\\n\\t\\t\\treportString notNil\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[Transcript show: context home class name \\n\\t\\t\\t, '/' , context sender selector, ' (' , reportString , ')'.\\n\\t\\t\\t\\tcontext := context sender.\\n\\t\\t\\t\\treportString := nil]\\n\\t\\t\\tifFalse:\\n\\t\\t\\t\\t[(context notNil and: [(context := context sender) notNil])\\n\\t\\t\\t\\tifTrue: [Transcript show: context receiver class name , '/' , context selector]]].\\n\\t\\t\\\"Transcript cr\\\"].! !\\n\\n!Object methodsFor: 'error handling' stamp: 'md 8/2/2005 22:17'!\\nerror\\n\\t\\\"Throw a generic Error exception.\\\"\\n\\n\\t^self error: 'Error!!'.! !\\n\\n!Object methodsFor: 'error handling' stamp: 'tfei 4/12/1999 12:55'!\\nerror: aString \\n\\t\\\"Throw a generic Error exception.\\\"\\n\\n\\t^Error new signal: aString! !\\n\\n!Object methodsFor: 'error handling' stamp: 'al 9/16/2005 14:12'!\\nexplicitRequirement\\n\\tself error: 'Explicitly required method'! !\\n\\n!Object methodsFor: 'error handling' stamp: 'al 2/13/2006 22:20'!\\nhalt\\n\\t\\\"This is the typical message to use for inserting breakpoints during \\n\\tdebugging. It behaves like halt:, but does not call on halt: in order to \\n\\tavoid putting this message on the stack. Halt is especially useful when \\n\\tthe breakpoint message is an arbitrary one.\\\"\\n\\n\\tHalt signal! !\\n\\n!Object methodsFor: 'error handling' stamp: 'tfei 4/12/1999 12:59'!\\nhalt: aString \\n\\t\\\"This is the typical message to use for inserting breakpoints during \\n\\tdebugging. It creates and schedules a Notifier with the argument, \\n\\taString, as the label.\\\"\\n\\t\\n\\tHalt new signal: aString! !\\n\\n!Object methodsFor: 'error handling' stamp: 'md 1/20/2006 16:24'!\\nhandles: exception\\n\\t\\\"This method exists in case a non exception class is the first arg in an on:do: (for instance using a exception class that is not loaded). We prefer this to raising an error during error handling itself. Also, semantically it makes sense that the exception handler is not active if its exception class is not loaded\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'error handling' stamp: 'ar 9/27/2005 20:24'!\\nnotifyWithLabel: aString \\n\\t\\\"Create and schedule a Notifier with aString as the window label as well as the contents of the window, in order to request confirmation before a process can proceed.\\\"\\n\\n\\tToolSet\\n\\t\\tdebugContext: thisContext\\n\\t\\tlabel: aString\\n\\t\\tcontents: aString\\n\\n\\t\\\"nil notifyWithLabel: 'let us see if this works'\\\"! !\\n\\n!Object methodsFor: 'error handling' stamp: 'hg 10/2/2001 20:49'!\\nnotify: aString \\n\\t\\\"Create and schedule a Notifier with the argument as the message in \\n\\torder to request confirmation before a process can proceed.\\\"\\n\\n\\tWarning signal: aString\\n\\n\\t\\\"nil notify: 'confirmation message'\\\"! !\\n\\n!Object methodsFor: 'error handling'!\\nnotify: aString at: location\\n\\t\\\"Create and schedule a Notifier with the argument as the message in \\n\\torder to request confirmation before a process can proceed. Subclasses can\\n\\toverride this and insert an error message at location within aString.\\\"\\n\\n\\tself notify: aString\\n\\n\\t\\\"nil notify: 'confirmation message' at: 12\\\"! !\\n\\n!Object methodsFor: 'error handling'!\\nprimitiveFailed\\n\\t\\\"Announce that a primitive has failed and there is no appropriate \\n\\tSmalltalk code to run.\\\"\\n\\n\\tself error: 'a primitive has failed'! !\\n\\n!Object methodsFor: 'error handling' stamp: 'al 9/16/2005 14:12'!\\nrequirement\\n\\tself error: 'Implicitly required method'! !\\n\\n!Object methodsFor: 'error handling' stamp: 'AFi 2/8/2003 22:52'!\\nshouldBeImplemented\\n\\t\\\"Announce that this message should be implemented\\\"\\n\\n\\tself error: 'This message should be implemented'! !\\n\\n!Object methodsFor: 'error handling'!\\nshouldNotImplement\\n\\t\\\"Announce that, although the receiver inherits this message, it should \\n\\tnot implement it.\\\"\\n\\n\\tself error: 'This message is not appropriate for this object'! !\\n\\n!Object methodsFor: 'error handling' stamp: 'md 2/17/2006 12:02'!\\nsubclassResponsibility\\n\\t\\\"This message sets up a framework for the behavior of the class' subclasses.\\n\\tAnnounce that the subclass should have implemented this message.\\\"\\n\\n\\tself error: 'My subclass should have overridden ', thisContext sender selector printString! !\\n\\n!Object methodsFor: 'error handling' stamp: 'al 12/16/2003 16:16'!\\ntraitConflict\\n\\tself error: 'A class or trait does not properly resolve a conflict between multiple traits it uses.'! !\\n\\n\\n!Object methodsFor: 'evaluating' stamp: 'reThink 3/12/2001 18:14'!\\nvalue\\n\\n\\t^self! !\\n\\n!Object methodsFor: 'evaluating' stamp: 'reThink 2/18/2001 15:23'!\\nvalueWithArguments: aSequenceOfArguments\\n\\n\\t^self! !\\n\\n\\n!Object methodsFor: 'events-accessing' stamp: 'nk 12/20/2002 17:48'!\\nactionForEvent: anEventSelector\\n \\\"Answer the action to be evaluated when <anEventSelector> has been triggered.\\\"\\n\\n\\t| actions |\\n\\tactions := self actionMap\\n\\t\\tat: anEventSelector asSymbol\\n\\t\\tifAbsent: [nil].\\n\\tactions ifNil: [^nil].\\n\\t^ actions asMinimalRepresentation! !\\n\\n!Object methodsFor: 'events-accessing' stamp: 'nk 12/20/2002 17:48'!\\nactionForEvent: anEventSelector\\nifAbsent: anExceptionBlock\\n \\\"Answer the action to be evaluated when <anEventSelector> has been triggered.\\\"\\n\\n\\t| actions |\\n\\tactions := self actionMap\\n\\t\\tat: anEventSelector asSymbol\\n\\t\\tifAbsent: [nil].\\n\\tactions ifNil: [^anExceptionBlock value].\\n\\t^ actions asMinimalRepresentation! !\\n\\n!Object methodsFor: 'events-accessing' stamp: 'reThink 2/18/2001 14:43'!\\nactionMap\\n\\n\\t^EventManager actionMapFor: self! !\\n\\n!Object methodsFor: 'events-accessing' stamp: 'rw 4/27/2002 08:35'!\\nactionSequenceForEvent: anEventSelector\\n\\n ^(self actionMap\\n at: anEventSelector asSymbol\\n ifAbsent: [^WeakActionSequence new])\\n asActionSequence! !\\n\\n!Object methodsFor: 'events-accessing' stamp: 'SqR 6/28/2001 13:19'!\\nactionsDo: aBlock\\n\\n\\tself actionMap do: aBlock! !\\n\\n!Object methodsFor: 'events-accessing' stamp: 'rw 2/10/2002 13:05'!\\ncreateActionMap\\n\\n\\t^IdentityDictionary new! !\\n\\n!Object methodsFor: 'events-accessing' stamp: 'SqR 2/19/2001 14:04'!\\nhasActionForEvent: anEventSelector\\n \\\"Answer true if there is an action associated with anEventSelector\\\"\\n\\n ^(self actionForEvent: anEventSelector) notNil! !\\n\\n!Object methodsFor: 'events-accessing' stamp: 'reThink 2/18/2001 15:29'!\\nsetActionSequence: actionSequence\\nforEvent: anEventSelector\\n\\n | action |\\n action := actionSequence asMinimalRepresentation.\\n action == nil\\n ifTrue:\\n [self removeActionsForEvent: anEventSelector]\\n ifFalse:\\n [self updateableActionMap\\n at: anEventSelector asSymbol\\n put: action]! !\\n\\n!Object methodsFor: 'events-accessing' stamp: 'reThink 2/25/2001 08:50'!\\nupdateableActionMap\\n\\n\\t^EventManager updateableActionMapFor: self! !\\n\\n\\n!Object methodsFor: 'events-registering' stamp: 'reThink 2/18/2001 15:04'!\\nwhen: anEventSelector evaluate: anAction \\n\\n\\t| actions |\\n\\tactions := self actionSequenceForEvent: anEventSelector.\\n\\t(actions includes: anAction)\\n\\t\\tifTrue: [^ self].\\n\\tself \\n\\t\\tsetActionSequence: (actions copyWith: anAction)\\n\\t\\tforEvent: anEventSelector! !\\n\\n!Object methodsFor: 'events-registering' stamp: 'rww 12/30/2002 10:37'!\\nwhen: anEventSelector\\nsend: aMessageSelector\\nto: anObject\\n \\n self\\n when: anEventSelector\\n evaluate: (WeakMessageSend\\n receiver: anObject\\n selector: aMessageSelector)! !\\n\\n!Object methodsFor: 'events-registering' stamp: 'rww 12/30/2002 10:37'!\\nwhen: anEventSelector\\nsend: aMessageSelector\\nto: anObject\\nwithArguments: anArgArray\\n \\n self\\n when: anEventSelector\\n evaluate: (WeakMessageSend\\n receiver: anObject\\n selector: aMessageSelector\\n\\t\\targuments: anArgArray)! !\\n\\n!Object methodsFor: 'events-registering' stamp: 'rww 12/30/2002 10:37'!\\nwhen: anEventSelector\\nsend: aMessageSelector\\nto: anObject\\nwith: anArg\\n \\n self\\n when: anEventSelector\\n evaluate: (WeakMessageSend\\n receiver: anObject\\n selector: aMessageSelector\\n\\t\\targuments: (Array with: anArg))! !\\n\\n\\n!Object methodsFor: 'events-removing' stamp: 'reThink 2/18/2001 15:33'!\\nreleaseActionMap\\n\\n\\tEventManager releaseActionMapFor: self! !\\n\\n!Object methodsFor: 'events-removing' stamp: 'reThink 2/18/2001 15:33'!\\nremoveActionsForEvent: anEventSelector\\n\\n | map |\\n map := self actionMap.\\n map removeKey: anEventSelector asSymbol ifAbsent: [].\\n map isEmpty\\n ifTrue: [self releaseActionMap]! !\\n\\n!Object methodsFor: 'events-removing' stamp: 'nk 8/25/2003 21:46'!\\nremoveActionsSatisfying: aBlock\\n\\n\\tself actionMap keys do:\\n\\t\\t[:eachEventSelector |\\n\\t\\t\\tself\\n \\t\\t\\t\\tremoveActionsSatisfying: aBlock\\n\\t\\t\\t\\tforEvent: eachEventSelector\\n\\t\\t]! !\\n\\n!Object methodsFor: 'events-removing' stamp: 'reThink 2/18/2001 15:31'!\\nremoveActionsSatisfying: aOneArgBlock \\nforEvent: anEventSelector\\n\\n self\\n setActionSequence:\\n ((self actionSequenceForEvent: anEventSelector)\\n reject: [:anAction | aOneArgBlock value: anAction])\\n forEvent: anEventSelector! !\\n\\n!Object methodsFor: 'events-removing' stamp: 'rw 7/29/2003 17:18'!\\nremoveActionsWithReceiver: anObject\\n\\n\\tself actionMap copy keysDo:\\n\\t\\t[:eachEventSelector |\\n\\t\\t\\tself\\n \\t\\t\\t\\tremoveActionsSatisfying: [:anAction | anAction receiver == anObject]\\n\\t\\t\\t\\tforEvent: eachEventSelector\\n\\t\\t]! !\\n\\n!Object methodsFor: 'events-removing' stamp: 'reThink 2/18/2001 15:36'!\\nremoveActionsWithReceiver: anObject\\nforEvent: anEventSelector\\n\\n self\\n removeActionsSatisfying:\\n [:anAction |\\n anAction receiver == anObject]\\n forEvent: anEventSelector! !\\n\\n!Object methodsFor: 'events-removing' stamp: 'reThink 2/18/2001 15:31'!\\nremoveAction: anAction\\nforEvent: anEventSelector\\n\\n self\\n removeActionsSatisfying: [:action | action = anAction]\\n forEvent: anEventSelector! !\\n\\n\\n!Object methodsFor: 'events-triggering' stamp: 'reThink 2/18/2001 15:22'!\\ntriggerEvent: anEventSelector\\n\\t\\\"Evaluate all actions registered for <anEventSelector>. Return the value of the last registered action.\\\"\\n\\n ^(self actionForEvent: anEventSelector) value! !\\n\\n!Object methodsFor: 'events-triggering' stamp: 'reThink 2/18/2001 17:09'!\\ntriggerEvent: anEventSelector\\nifNotHandled: anExceptionBlock\\n\\t\\\"Evaluate all actions registered for <anEventSelector>. Return the value of the last registered action.\\\"\\n\\n ^(self \\n\\t\\tactionForEvent: anEventSelector\\n\\t\\tifAbsent: [^anExceptionBlock value]) value\\n! !\\n\\n!Object methodsFor: 'events-triggering' stamp: 'reThink 2/18/2001 15:21'!\\ntriggerEvent: anEventSelector\\nwithArguments: anArgumentList\\n\\n ^(self actionForEvent: anEventSelector)\\n valueWithArguments: anArgumentList! !\\n\\n!Object methodsFor: 'events-triggering' stamp: 'reThink 2/18/2001 15:21'!\\ntriggerEvent: anEventSelector\\nwithArguments: anArgumentList\\nifNotHandled: anExceptionBlock\\n\\n ^(self \\n\\t\\tactionForEvent: anEventSelector\\n\\t\\tifAbsent: [^anExceptionBlock value])\\n valueWithArguments: anArgumentList! !\\n\\n!Object methodsFor: 'events-triggering' stamp: 'reThink 2/18/2001 14:59'!\\ntriggerEvent: anEventSelector\\nwith: anObject\\n\\n ^self \\n\\t\\ttriggerEvent: anEventSelector\\n\\t\\twithArguments: (Array with: anObject)! !\\n\\n!Object methodsFor: 'events-triggering' stamp: 'reThink 2/18/2001 14:59'!\\ntriggerEvent: anEventSelector\\nwith: anObject\\nifNotHandled: anExceptionBlock\\n\\n ^self \\n\\t\\ttriggerEvent: anEventSelector\\n\\t\\twithArguments: (Array with: anObject)\\n\\t\\tifNotHandled: anExceptionBlock! !\\n\\n\\n!Object methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 00:42'!\\nbyteEncode:aStream\\n\\tself flattenOnStream:aStream.\\n! !\\n\\n!Object methodsFor: 'filter streaming'!\\ndrawOnCanvas:aStream\\n\\tself flattenOnStream:aStream.\\n! !\\n\\n!Object methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 01:31'!\\nelementSeparator\\n\\t^nil.! !\\n\\n!Object methodsFor: 'filter streaming'!\\nencodePostscriptOn:aStream\\n\\tself byteEncode:aStream.\\n! !\\n\\n!Object methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 00:07'!\\nflattenOnStream:aStream\\n\\tself writeOnFilterStream:aStream.\\n! !\\n\\n!Object methodsFor: 'filter streaming' stamp: 'mpw 6/22/1930 22:56'!\\nfullDrawPostscriptOn:aStream\\n\\t^aStream fullDraw:self.\\n! !\\n\\n!Object methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 01:51'!\\nprintOnStream:aStream\\n\\tself byteEncode:aStream.\\n! !\\n\\n!Object methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 00:49'!\\nputOn:aStream\\n\\t^aStream nextPut:self.\\n! !\\n\\n!Object methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 01:53'!\\nstoreOnStream:aStream\\n\\tself printOnStream:aStream.\\n! !\\n\\n!Object methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 00:06'!\\nwriteOnFilterStream:aStream\\n\\taStream writeObject:self.\\n! !\\n\\n\\n!Object methodsFor: 'finalization' stamp: 'ar 3/21/98 16:26'!\\nactAsExecutor\\n\\t\\\"Prepare the receiver to act as executor for any resources associated with it\\\"\\n\\tself breakDependents! !\\n\\n!Object methodsFor: 'finalization' stamp: 'ar 3/20/98 22:19'!\\nexecutor\\n\\t\\\"Return an object which can act as executor for finalization of the receiver\\\"\\n\\t^self shallowCopy actAsExecutor! !\\n\\n!Object methodsFor: 'finalization' stamp: 'ar 5/19/2003 20:10'!\\nfinalizationRegistry\\n\\t\\\"Answer the finalization registry associated with the receiver.\\\"\\n\\t^WeakRegistry default! !\\n\\n!Object methodsFor: 'finalization' stamp: 'ar 3/21/98 16:27'!\\nfinalize\\n\\t\\\"Finalize the resource associated with the receiver. This message should only be sent during the finalization process. There is NO garantuee that the resource associated with the receiver hasn't been free'd before so take care that you don't run into trouble - this all may happen with interrupt priority.\\\"! !\\n\\n!Object methodsFor: 'finalization' stamp: 'ar 3/21/98 18:38'!\\nretryWithGC: execBlock until: testBlock\\n\\t\\\"Retry execBlock as long as testBlock returns false. Do an incremental GC after the first try, a full GC after the second try.\\\"\\n\\t| blockValue |\\n\\tblockValue := execBlock value.\\n\\t(testBlock value: blockValue) ifTrue:[^blockValue].\\n\\tSmalltalk garbageCollectMost.\\n\\tblockValue := execBlock value.\\n\\t(testBlock value: blockValue) ifTrue:[^blockValue].\\n\\tSmalltalk garbageCollect.\\n\\t^execBlock value.! !\\n\\n!Object methodsFor: 'finalization' stamp: 'ar 5/19/2003 20:14'!\\ntoFinalizeSend: aSelector to: aFinalizer with: aResourceHandle\\n\\t\\\"When I am finalized (e.g., garbage collected) close the associated resource handle by sending aSelector to the appropriate finalizer (the guy who knows how to get rid of the resource).\\n\\tWARNING: Neither the finalizer nor the resource handle are allowed to reference me. If they do, then I will NEVER be garbage collected. Since this cannot be validated here, it is up to the client to make sure this invariant is not broken.\\\"\\n\\tself == aFinalizer ifTrue:[self error: 'I cannot finalize myself'].\\n\\tself == aResourceHandle ifTrue:[self error: 'I cannot finalize myself'].\\n\\t^self finalizationRegistry add: self executor:\\n\\t\\t(ObjectFinalizer new\\n\\t\\t\\treceiver: aFinalizer\\n\\t\\t\\tselector: aSelector\\n\\t\\t\\targument: aResourceHandle)! !\\n\\n\\n!Object methodsFor: 'flagging' stamp: 'sw 8/4/97 16:49'!\\nisThisEverCalled\\n\\t^ self isThisEverCalled: thisContext sender printString! !\\n\\n!Object methodsFor: 'flagging'!\\nisThisEverCalled: msg\\n\\t\\\"Send this message, with some useful printable argument, from methods or branches of methods which you believe are never reached. 2/5/96 sw\\\"\\n\\n\\tself halt: 'This is indeed called: ', msg printString! !\\n\\n!Object methodsFor: 'flagging' stamp: 'jm 3/18/98 17:23'!\\nlogEntry\\n\\n\\tTranscript show: 'Entered ', thisContext sender printString; cr.\\n! !\\n\\n!Object methodsFor: 'flagging' stamp: 'jm 3/18/98 17:23'!\\nlogExecution\\n\\n\\tTranscript show: 'Executing ', thisContext sender printString; cr.\\n! !\\n\\n!Object methodsFor: 'flagging' stamp: 'jm 3/18/98 17:22'!\\nlogExit\\n\\n\\tTranscript show: 'Exited ', thisContext sender printString; cr.\\n! !\\n\\n\\n!Object methodsFor: 'graph model' stamp: 'dgd 9/18/2004 15:07'!\\naddModelYellowButtonMenuItemsTo: aCustomMenu forMorph: aMorph hand: aHandMorph \\n\\t\\\"The receiver serves as the model for aMorph; a menu is being constructed for the morph, and here the receiver is able to add its own items\\\"\\n\\tPreferences cmdGesturesEnabled ifTrue: [ \\\"build mode\\\"\\n\\t\\taCustomMenu add: 'inspect model' translated target: self action: #inspect.\\n\\t].\\n\\n\\t^aCustomMenu\\n! !\\n\\n!Object methodsFor: 'graph model' stamp: 'nk 1/23/2004 14:35'!\\nhasModelYellowButtonMenuItems\\n\\t^Preferences cmdGesturesEnabled! !\\n\\n\\n!Object methodsFor: 'locales' stamp: 'tak 8/4/2005 14:55'!\\nlocaleChanged\\n\\tself shouldBeImplemented! !\\n\\n\\n!Object methodsFor: 'macpal' stamp: 'sw 5/7/1998 23:00'!\\ncodeStrippedOut: messageString\\n\\t\\\"When a method is stripped out for external release, it is replaced by a method that calls this\\\"\\n\\n\\tself halt: 'Code stripped out -- ', messageString, '-- do not proceed.'! !\\n\\n!Object methodsFor: 'macpal' stamp: 'sw 1/28/1999 17:31'!\\ncontentsChanged\\n\\tself changed: #contents! !\\n\\n!Object methodsFor: 'macpal' stamp: 'ar 3/18/2001 00:03'!\\ncurrentEvent\\n\\t\\\"Answer the current Morphic event. This method never returns nil.\\\"\\n\\t^ActiveEvent ifNil:[self currentHand lastEvent]! !\\n\\n!Object methodsFor: 'macpal' stamp: 'nk 9/1/2004 10:41'!\\ncurrentHand\\n\\t\\\"Return a usable HandMorph -- the one associated with the object's current environment. This method will always return a hand, even if it has to conjure one up as a last resort. If a particular hand is actually handling events at the moment (such as a remote hand or a ghost hand), it will be returned.\\\"\\n\\n\\t^ActiveHand ifNil: [ self currentWorld primaryHand ]! !\\n\\n!Object methodsFor: 'macpal' stamp: 'sw 5/17/2001 12:08'!\\ncurrentVocabulary\\n\\t\\\"Answer the currently-prevailing default vocabulary.\\\"\\n\\n\\t^ Smalltalk isMorphic ifTrue:\\n\\t\\t\\t[ActiveWorld currentVocabulary]\\n\\t\\tifFalse:\\n\\t\\t\\t[Vocabulary fullVocabulary]! !\\n\\n!Object methodsFor: 'macpal' stamp: 'ar 3/18/2001 00:08'!\\ncurrentWorld\\n\\t\\\"Answer a morphic world that is the current UI focus.\\n\\t\\tIf in an embedded world, it's that world.\\n\\t\\tIf in a morphic project, it's that project's world. \\n\\t\\tIf in an mvc project, it is the topmost morphic-mvc-window's worldMorph. \\n\\t\\tIf in an mvc project that has no morphic-mvc-windows, then it's just some existing worldmorph instance.\\n\\t\\tIf in an mvc project in a Squeak that has NO WorldMorph instances, one is created.\\n\\n\\tThis method will never return nil, it will always return its best effort at returning a relevant world morph, but if need be -- if there are no worlds anywhere, it will create a new one.\\\"\\n\\n\\t| aView aSubview |\\n\\tActiveWorld ifNotNil:[^ActiveWorld].\\n\\tWorld ifNotNil:[^World].\\n\\taView _ ScheduledControllers controllerSatisfying:\\n\\t\\t[:ctrl | (aSubview _ ctrl view firstSubView) notNil and:\\n\\t\\t\\t[aSubview model isMorph and: [aSubview model isWorldMorph]]].\\n\\t^aView\\n\\t\\tifNotNil:\\n\\t\\t\\t[aSubview model]\\n\\t\\tifNil:\\n\\t\\t\\t[MVCWiWPasteUpMorph newWorldForProject: nil].! !\\n\\n!Object methodsFor: 'macpal' stamp: 'jm 5/6/1998 22:35'!\\nflash\\n\\t\\\"Do nothing.\\\"\\n! !\\n\\n!Object methodsFor: 'macpal' stamp: 'sw 6/16/1998 15:07'!\\ninstanceVariableValues\\n\\t\\\"Answer a collection whose elements are the values of those instance variables of the receiver which were added by the receiver's class\\\"\\n\\t| c |\\n\\tc _ OrderedCollection new.\\n\\tself class superclass instSize + 1 to: self class instSize do:\\n\\t\\t[:i | c add: (self instVarAt: i)].\\n\\t^ c! !\\n\\n!Object methodsFor: 'macpal' stamp: 'sw 3/20/2001 13:29'!\\nisUniversalTiles\\n\\t\\\"Return true if I (my world) uses universal tiles. This message can be called in places where the current World is not known, such as when writing out a project. For more information about the project-writing subtlety addressed by this protocol, kindly contact Ted Kaehler.\\\"\\n\\n\\t^ Preferences universalTiles! !\\n\\n!Object methodsFor: 'macpal' stamp: 'sw 10/24/2000 07:04'!\\nobjectRepresented\\n\\t\\\"most objects represent themselves; this provides a hook for aliases to grab on to\\\"\\n\\n\\t^ self! !\\n\\n!Object methodsFor: 'macpal' stamp: 'sw 5/22/2001 18:31'!\\nrefusesToAcceptCode\\n\\t\\\"Answer whether the receiver is a code-bearing instrument which at the moment refuses to allow its contents to be submitted\\\"\\n\\n\\t^ false\\n\\t! !\\n\\n!Object methodsFor: 'macpal' stamp: 'jm 2/24/1999 12:40'!\\nscriptPerformer\\n\\n\\t^ self\\n! !\\n\\n!Object methodsFor: 'macpal' stamp: 'sw 3/20/2001 13:40'!\\nslotInfo\\n\\t\\\"Answer a list of slot-information objects. Initally only provides useful info for players\\\"\\n\\n\\t^ Dictionary new! !\\n\\n\\n!Object methodsFor: 'message handling' stamp: 'md 1/20/2006 16:28'!\\nexecuteMethod: compiledMethod\\n\\t\\\"Execute compiledMethod against the receiver with no args\\\"\\n\\n\\t\\\"<primitive: 189>\\\" \\\"uncomment once prim 189 is in VM\\\"\\n\\t^ self withArgs: #() executeMethod: compiledMethod! !\\n\\n!Object methodsFor: 'message handling' stamp: 'di 3/26/1999 07:52'!\\nperform: aSymbol \\n\\t\\\"Send the unary selector, aSymbol, to the receiver.\\n\\tFail if the number of arguments expected by the selector is not zero.\\n\\tPrimitive. Optional. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 83>\\n\\t^ self perform: aSymbol withArguments: (Array new: 0)! !\\n\\n!Object methodsFor: 'message handling' stamp: 'sw 10/30/1998 18:27'!\\nperform: selector orSendTo: otherTarget\\n\\t\\\"If I wish to intercept and handle selector myself, do it; else send it to otherTarget\\\"\\n\\t^ otherTarget perform: selector! !\\n\\n!Object methodsFor: 'message handling' stamp: 'di 3/26/1999 07:55'!\\nperform: selector withArguments: argArray \\n\\t\\\"Send the selector, aSymbol, to the receiver with arguments in argArray.\\n\\tFail if the number of arguments expected by the selector \\n\\tdoes not match the size of argArray.\\n\\tPrimitive. Optional. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 84>\\n\\t^ self perform: selector withArguments: argArray inSuperclass: self class! !\\n\\n!Object methodsFor: 'message handling' stamp: 'ar 4/25/2005 13:35'!\\nperform: selector withArguments: argArray inSuperclass: lookupClass\\n\\t\\\"NOTE: This is just like perform:withArguments:, except that\\n\\tthe message lookup process begins, not with the receivers's class,\\n\\tbut with the supplied superclass instead. It will fail if lookupClass\\n\\tcannot be found among the receiver's superclasses.\\n\\tPrimitive. Essential. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 100>\\n\\t(selector isSymbol)\\n\\t\\tifFalse: [^ self error: 'selector argument must be a Symbol'].\\n\\t(selector numArgs = argArray size)\\n\\t\\tifFalse: [^ self error: 'incorrect number of arguments'].\\n\\t(self class == lookupClass or: [self class inheritsFrom: lookupClass])\\n\\t\\tifFalse: [^ self error: 'lookupClass is not in my inheritance chain'].\\n\\tself primitiveFailed! !\\n\\n!Object methodsFor: 'message handling' stamp: 'nk 4/11/2002 14:13'!\\nperform: selector withEnoughArguments: anArray\\n\\t\\\"Send the selector, aSymbol, to the receiver with arguments in argArray.\\n\\tOnly use enough arguments for the arity of the selector; supply nils for missing ones.\\\"\\n\\t| numArgs args |\\n\\tnumArgs _ selector numArgs.\\n\\tanArray size == numArgs\\n\\t\\tifTrue: [ ^self perform: selector withArguments: anArray asArray ].\\n\\n\\targs _ Array new: numArgs.\\n\\targs replaceFrom: 1\\n\\t\\tto: (anArray size min: args size)\\n\\t\\twith: anArray\\n\\t\\tstartingAt: 1.\\n\\n\\t^ self perform: selector withArguments: args! !\\n\\n!Object methodsFor: 'message handling' stamp: 'di 3/26/1999 07:52'!\\nperform: aSymbol with: anObject \\n\\t\\\"Send the selector, aSymbol, to the receiver with anObject as its argument.\\n\\tFail if the number of arguments expected by the selector is not one.\\n\\tPrimitive. Optional. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 83>\\n\\t^ self perform: aSymbol withArguments: (Array with: anObject)! !\\n\\n!Object methodsFor: 'message handling' stamp: 'di 3/26/1999 07:52'!\\nperform: aSymbol with: firstObject with: secondObject \\n\\t\\\"Send the selector, aSymbol, to the receiver with the given arguments.\\n\\tFail if the number of arguments expected by the selector is not two.\\n\\tPrimitive. Optional. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 83>\\n\\t^ self perform: aSymbol withArguments: (Array with: firstObject with: secondObject)! !\\n\\n!Object methodsFor: 'message handling' stamp: 'di 3/26/1999 07:51'!\\nperform: aSymbol with: firstObject with: secondObject with: thirdObject \\n\\t\\\"Send the selector, aSymbol, to the receiver with the given arguments.\\n\\tFail if the number of arguments expected by the selector is not three.\\n\\tPrimitive. Optional. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 83>\\n\\t^ self perform: aSymbol\\n\\t\\twithArguments: (Array with: firstObject with: secondObject with: thirdObject)! !\\n\\n!Object methodsFor: 'message handling' stamp: 'NS 1/28/2004 11:19'!\\nwithArgs: argArray executeMethod: compiledMethod\\n\\t\\\"Execute compiledMethod against the receiver and args in argArray\\\"\\n\\n\\t| selector |\\n\\t<primitive: 188>\\n\\tselector _ Symbol new.\\n\\tself class addSelectorSilently: selector withMethod: compiledMethod.\\n\\t^ [self perform: selector withArguments: argArray]\\n\\t\\tensure: [self class basicRemoveSelector: selector]! !\\n\\n!Object methodsFor: 'message handling' stamp: 'md 1/20/2006 16:28'!\\nwith: arg1 executeMethod: compiledMethod\\n\\t\\\"Execute compiledMethod against the receiver and arg1\\\"\\n\\n\\t\\\"<primitive: 189>\\\" \\\"uncomment once prim 189 is in VM\\\"\\n\\t^ self withArgs: {arg1} executeMethod: compiledMethod! !\\n\\n!Object methodsFor: 'message handling' stamp: 'md 1/20/2006 16:28'!\\nwith: arg1 with: arg2 executeMethod: compiledMethod\\n\\t\\\"Execute compiledMethod against the receiver and arg1 & arg2\\\"\\n\\n\\t\\\"<primitive: 189>\\\" \\\"uncomment once prim 189 is in VM\\\"\\n\\t^ self withArgs: {arg1. arg2} executeMethod: compiledMethod! !\\n\\n!Object methodsFor: 'message handling' stamp: 'md 1/20/2006 16:28'!\\nwith: arg1 with: arg2 with: arg3 executeMethod: compiledMethod\\n\\t\\\"Execute compiledMethod against the receiver and arg1, arg2, & arg3\\\"\\n\\n\\t\\\"<primitive: 189>\\\" \\\"uncomment once prim 189 is in VM\\\"\\n\\t^ self withArgs: {arg1. arg2. arg3} executeMethod: compiledMethod! !\\n\\n!Object methodsFor: 'message handling' stamp: 'md 1/20/2006 16:28'!\\nwith: arg1 with: arg2 with: arg3 with: arg4 executeMethod: compiledMethod\\n\\t\\\"Execute compiledMethod against the receiver and arg1, arg2, arg3, & arg4\\\"\\n\\n\\t\\\"<primitive: 189>\\\" \\\"uncomment once prim 189 is in VM\\\"\\n\\t^ self withArgs: {arg1. arg2. arg3. arg4} executeMethod: compiledMethod! !\\n\\n\\n!Object methodsFor: 'objects from disk' stamp: 'tk 4/8/1999 12:46'!\\ncomeFullyUpOnReload: smartRefStream\\n\\t\\\"Normally this read-in object is exactly what we want to store. 7/26/96 tk\\\"\\n\\n\\t^ self! !\\n\\n!Object methodsFor: 'objects from disk' stamp: 'RAA 12/20/2000 16:51'!\\nconvertToCurrentVersion: varDict refStream: smartRefStrm\\n\\n\\t\\\"subclasses should implement if they wish to convert old instances to modern ones\\\"! !\\n\\n!Object methodsFor: 'objects from disk' stamp: 'tk 11/29/2004 15:04'!\\nfixUponLoad: aProject seg: anImageSegment\\n\\n\\t\\\"change the object due to conventions that have changed on\\n\\nthe project level. (sent to all objects in the incoming project).\\n\\nSpecific classes should reimplement this.\\\"! !\\n\\n!Object methodsFor: 'objects from disk' stamp: 'RAA 1/10/2001 14:02'!\\nindexIfCompact\\n\\n\\t^0\\t\\t\\\"helps avoid a #respondsTo: in publishing\\\"! !\\n\\n!Object methodsFor: 'objects from disk' stamp: 'tk 2/24/1999 11:08'!\\nobjectForDataStream: refStrm\\n \\\"Return an object to store on an external data stream.\\\"\\n\\n ^ self! !\\n\\n!Object methodsFor: 'objects from disk' stamp: 'tk 4/8/1999 12:05'!\\nreadDataFrom: aDataStream size: varsOnDisk\\n\\t\\\"Fill in the fields of self based on the contents of aDataStream. Return self.\\n\\t Read in the instance-variables written by Object>>storeDataOn:.\\n\\t NOTE: This method must send beginReference: before reading any objects from aDataStream that might reference it.\\n\\t Allow aDataStream to have fewer inst vars. See SmartRefStream.\\\"\\n\\t| cntInstVars cntIndexedVars |\\n\\n\\tcntInstVars _ self class instSize.\\n\\tself class isVariable\\n\\t\\tifTrue: [cntIndexedVars _ varsOnDisk - cntInstVars.\\n\\t\\t\\t\\tcntIndexedVars < 0 ifTrue: [\\n\\t\\t\\t\\t\\tself error: 'Class has changed too much. Define a convertxxx method']]\\n\\t\\tifFalse: [cntIndexedVars _ 0.\\n\\t\\t\\t\\tcntInstVars _ varsOnDisk]. \\t\\\"OK if fewer than now\\\"\\n\\n\\taDataStream beginReference: self.\\n\\t1 to: cntInstVars do:\\n\\t\\t[:i | self instVarAt: i put: aDataStream next].\\n\\t1 to: cntIndexedVars do:\\n\\t\\t[:i | self basicAt: i put: aDataStream next].\\n\\t\\\"Total number read MUST be equal to varsOnDisk!!\\\"\\n\\t^ self\\t\\\"If we ever return something other than self, fix calls \\n\\t\\t\\ton (super readDataFrom: aDataStream size: anInteger)\\\"! !\\n\\n!Object methodsFor: 'objects from disk' stamp: 'CdG 10/17/2005 20:32'!\\nsaveOnFile\\n\\t\\\"Ask the user for a filename and save myself on a SmartReferenceStream file. Writes out the version and class structure. The file is fileIn-able. Does not file out the class of the object. tk 6/26/97 13:48\\\"\\n\\n\\t| aFileName fileStream |\\n\\taFileName := self class name asFileName.\\t\\\"do better?\\\"\\n\\taFileName := UIManager default \\n\\t\\t\\t\\trequest: 'File name?' translated initialAnswer: aFileName.\\n\\taFileName size == 0 ifTrue: [^ Beeper beep].\\n\\n\\tfileStream := FileStream newFileNamed: aFileName asFileName.\\n\\tfileStream fileOutClass: nil andObject: self.! !\\n\\n!Object methodsFor: 'objects from disk' stamp: 'tk 8/9/2001 15:40'!\\nstoreDataOn: aDataStream\\n\\t\\\"Store myself on a DataStream. Answer self. This is a low-level DataStream/ReferenceStream method. See also objectToStoreOnDataStream. NOTE: This method must send 'aDataStream beginInstance:size:' and then (nextPut:/nextPutWeak:) its subobjects. readDataFrom:size: reads back what we write here.\\\"\\n\\t| cntInstVars cntIndexedVars |\\n\\n\\tcntInstVars _ self class instSize.\\n\\tcntIndexedVars _ self basicSize.\\n\\taDataStream\\n\\t\\tbeginInstance: self class\\n\\t\\tsize: cntInstVars + cntIndexedVars.\\n\\t1 to: cntInstVars do:\\n\\t\\t[:i | aDataStream nextPut: (self instVarAt: i)].\\n\\n\\t\\\"Write fields of a variable length object. When writing to a dummy \\n\\t\\tstream, don't bother to write the bytes\\\"\\n\\t((aDataStream byteStream class == DummyStream) and: [self class isBits]) ifFalse: [\\n\\t\\t1 to: cntIndexedVars do:\\n\\t\\t\\t[:i | aDataStream nextPut: (self basicAt: i)]].\\n! !\\n\\n\\n!Object methodsFor: 'parts bin' stamp: 'sw 10/24/2001 16:34'!\\ndescriptionForPartsBin\\n\\t\\\"If the receiver is a member of a class that would like to be represented in a parts bin, answer the name by which it should be known, and a documentation string to be provided, for example, as balloon help. When the 'nativitySelector' is sent to the 'globalReceiver', it is expected that some kind of Morph will result. The parameters used in the implementation below are for documentation purposes only!!\\\"\\n\\n\\t^ DescriptionForPartsBin\\n\\t\\tformalName: 'PutFormalNameHere'\\n\\t\\tcategoryList: #(PutACategoryHere MaybePutAnotherCategoryHere)\\n\\t\\tdocumentation: 'Put the balloon help here'\\n\\t\\tglobalReceiverSymbol: #PutAGlobalHere\\n\\t\\tnativitySelector: #PutASelectorHere! !\\n\\n\\n!Object methodsFor: 'printing' stamp: 'di 6/20/97 08:57'!\\nfullPrintString\\n\\t\\\"Answer a String whose characters are a description of the receiver.\\\"\\n\\n\\t^ String streamContents: [:s | self printOn: s]! !\\n\\n!Object methodsFor: 'printing'!\\nisLiteral\\n\\t\\\"Answer whether the receiver has a literal text form recognized by the \\n\\tcompiler.\\\"\\n\\n\\t^false! !\\n\\n!Object methodsFor: 'printing' stamp: 'sma 6/1/2000 09:28'!\\nlongPrintOn: aStream\\n\\t\\\"Append to the argument, aStream, the names and values of all \\n\\tof the receiver's instance variables.\\\"\\n\\n\\tself class allInstVarNames doWithIndex:\\n\\t\\t[:title :index |\\n\\t\\taStream nextPutAll: title;\\n\\t\\t nextPut: $:;\\n\\t\\t space;\\n\\t\\t tab;\\n\\t\\t print: (self instVarAt: index);\\n\\t\\t cr]! !\\n\\n!Object methodsFor: 'printing' stamp: 'tk 10/19/2001 11:18'!\\nlongPrintOn: aStream limitedTo: sizeLimit indent: indent\\n\\t\\\"Append to the argument, aStream, the names and values of all of the receiver's instance variables. Limit is the length limit for each inst var.\\\"\\n\\n\\tself class allInstVarNames doWithIndex:\\n\\t\\t[:title :index |\\n\\t\\tindent timesRepeat: [aStream tab].\\n\\t\\taStream nextPutAll: title;\\n\\t\\t nextPut: $:;\\n\\t\\t space;\\n\\t\\t tab;\\n\\t\\t nextPutAll: \\n\\t\\t\\t((self instVarAt: index) printStringLimitedTo: (sizeLimit -3 -title size max: 1));\\n\\t\\t cr]! !\\n\\n!Object methodsFor: 'printing' stamp: 'tk 10/16/2001 19:41'!\\nlongPrintString\\n\\t\\\"Answer a String whose characters are a description of the receiver.\\\"\\n\\t\\n\\t| str |\\n\\tstr _ String streamContents: [:aStream | self longPrintOn: aStream].\\n\\t\\\"Objects without inst vars should return something\\\"\\n\\t^ str isEmpty ifTrue: [self printString, String cr] ifFalse: [str]! !\\n\\n!Object methodsFor: 'printing' stamp: 'BG 11/7/2004 13:39'!\\nlongPrintStringLimitedTo: aLimitValue\\n\\t\\\"Answer a String whose characters are a description of the receiver.\\\"\\n\\t\\n\\t| str |\\n\\tstr _ String streamContents: [:aStream | self longPrintOn: aStream limitedTo: aLimitValue indent: 0].\\n\\t\\\"Objects without inst vars should return something\\\"\\n\\t^ str isEmpty ifTrue: [self printString, String cr] ifFalse: [str]! !\\n\\n!Object methodsFor: 'printing' stamp: 'sw 3/7/2001 13:14'!\\nnominallyUnsent: aSelectorSymbol\\n\\t\\\"From within the body of a method which is not formally sent within the system, but which you intend to have remain in the system (for potential manual invocation, or for documentation, or perhaps because it's sent by commented-out-code that you anticipate uncommenting out someday, send this message, with the selector itself as the argument.\\n\\nThis will serve two purposes:\\n\\n\\t(1) The method will not be returned by searches for unsent selectors (because it, in a manner of speaking, sends itself).\\n\\t(2)\\tYou can locate all such methods by browsing senders of #nominallyUnsent:\\\"\\n\\n\\tfalse ifTrue: [self flag: #nominallyUnsent:] \\\"So that this method itself will appear to be sent\\\"\\n! !\\n\\n!Object methodsFor: 'printing' stamp: 'sma 6/1/2000 09:31'!\\nprintOn: aStream\\n\\t\\\"Append to the argument, aStream, a sequence of characters that \\n\\tidentifies the receiver.\\\"\\n\\n\\t| title |\\n\\ttitle _ self class name.\\n\\taStream\\n\\t\\tnextPutAll: (title first isVowel ifTrue: ['an '] ifFalse: ['a ']);\\n\\t\\tnextPutAll: title! !\\n\\n!Object methodsFor: 'printing' stamp: 'sma 6/1/2000 09:22'!\\nprintString\\n\\t\\\"Answer a String whose characters are a description of the receiver. \\n\\tIf you want to print without a character limit, use fullPrintString.\\\"\\n\\n\\t^ self printStringLimitedTo: 50000! !\\n\\n!Object methodsFor: 'printing' stamp: 'tk 5/7/1999 16:20'!\\nprintStringLimitedTo: limit\\n\\t\\\"Answer a String whose characters are a description of the receiver.\\n\\tIf you want to print without a character limit, use fullPrintString.\\\"\\n\\t| limitedString |\\n\\tlimitedString _ String streamContents: [:s | self printOn: s] limitedTo: limit.\\n\\tlimitedString size < limit ifTrue: [^ limitedString].\\n\\t^ limitedString , '...etc...'! !\\n\\n!Object methodsFor: 'printing' stamp: 'MPW 1/1/1901 00:30'!\\npropertyList\\n\\t\\\"Answer a String whose characters are a property-list description of the receiver.\\\"\\n\\n\\t^ PropertyListEncoder process:self.\\n! !\\n\\n!Object methodsFor: 'printing' stamp: 'sw 10/17/2000 11:16'!\\nreportableSize\\n\\t\\\"Answer a string that reports the size of the receiver -- useful for showing in a list view, for example\\\"\\n\\n\\t^ (self basicSize + self class instSize) printString! !\\n\\n!Object methodsFor: 'printing'!\\nstoreOn: aStream \\n\\t\\\"Append to the argument aStream a sequence of characters that is an \\n\\texpression whose evaluation creates an object similar to the receiver.\\\"\\n\\n\\taStream nextPut: $(.\\n\\tself class isVariable\\n\\t\\tifTrue: [aStream nextPutAll: '(', self class name, ' basicNew: ';\\n\\t\\t\\t\\t\\tstore: self basicSize;\\n\\t\\t\\t\\t\\tnextPutAll: ') ']\\n\\t\\tifFalse: [aStream nextPutAll: self class name, ' basicNew'].\\n\\t1 to: self class instSize do:\\n\\t\\t[:i |\\n\\t\\taStream nextPutAll: ' instVarAt: ';\\n\\t\\t\\tstore: i;\\n\\t\\t\\tnextPutAll: ' put: ';\\n\\t\\t\\tstore: (self instVarAt: i);\\n\\t\\t\\tnextPut: $;].\\n\\t1 to: self basicSize do:\\n\\t\\t[:i |\\n\\t\\taStream nextPutAll: ' basicAt: ';\\n\\t\\t\\tstore: i;\\n\\t\\t\\tnextPutAll: ' put: ';\\n\\t\\t\\tstore: (self basicAt: i);\\n\\t\\t\\tnextPut: $;].\\n\\taStream nextPutAll: ' yourself)'\\n! !\\n\\n!Object methodsFor: 'printing' stamp: 'di 6/20/97 09:12'!\\nstoreString\\n\\t\\\"Answer a String representation of the receiver from which the receiver \\n\\tcan be reconstructed.\\\"\\n\\n\\t^ String streamContents: [:s | self storeOn: s]! !\\n\\n!Object methodsFor: 'printing' stamp: 'sw 5/2/1998 13:55'!\\nstringForReadout\\n\\t^ self stringRepresentation! !\\n\\n!Object methodsFor: 'printing'!\\nstringRepresentation\\n\\t\\\"Answer a string that represents the receiver. For most objects this is simply its printString, but for strings themselves, it's themselves. 6/12/96 sw\\\"\\n\\n\\t^ self printString ! !\\n\\n\\n!Object methodsFor: 'scripting' stamp: 'ar 3/17/2001 20:11'!\\nadaptedToWorld: aWorld\\n\\t\\\"If I refer to a world or a hand, return the corresponding items in the new world.\\\"\\n\\t^self! !\\n\\n!Object methodsFor: 'scripting' stamp: 'sw 3/10/2000 13:57'!\\ndefaultFloatPrecisionFor: aGetSelector\\n\\t\\\"Answer a number indicating the default float precision to be used in a numeric readout for which the receiver is the model.\\\"\\n\\n\\t^ 1! !\\n\\n!Object methodsFor: 'scripting' stamp: 'RAA 3/9/2001 17:08'!\\nevaluateUnloggedForSelf: aCodeString\\n\\n\\t^Compiler evaluate:\\n\\t\\taCodeString\\n\\t\\tfor: self\\n\\t\\tlogged: false! !\\n\\n!Object methodsFor: 'scripting' stamp: 'yo 12/25/2003 16:43'!\\nmethodInterfacesForCategory: aCategorySymbol inVocabulary: aVocabulary limitClass: aLimitClass\\n\\t\\\"Return a list of methodInterfaces for the receiver in the given category, given a vocabulary. aCategorySymbol is the inherent category symbol, not necessarily the wording as expressed in the vocabulary.\\\"\\n\\n\\t| categorySymbol |\\n\\tcategorySymbol _ aCategorySymbol asSymbol.\\n\\n\\t(categorySymbol == ScriptingSystem nameForInstanceVariablesCategory) ifTrue: [\\n\\t\\t\\\"user-defined instance variables\\\"\\n\\t\\t^ self methodInterfacesForInstanceVariablesCategoryIn: aVocabulary].\\n\\t(categorySymbol == ScriptingSystem nameForScriptsCategory) ifTrue: [\\n\\t\\t\\\"user-defined scripts\\\"\\n\\t\\t^ self methodInterfacesForScriptsCategoryIn: aVocabulary].\\n\\t\\\"all others\\\"\\n\\t^ self usableMethodInterfacesIn: (aVocabulary methodInterfacesInCategory: categorySymbol\\n\\t\\tforInstance: self\\n\\t\\tofClass: self class\\n\\t\\tlimitClass: aLimitClass)\\n! !\\n\\n!Object methodsFor: 'scripting' stamp: 'sw 8/3/2001 13:54'!\\nmethodInterfacesForInstanceVariablesCategoryIn: aVocabulary\\n\\t\\\"Return a collection of methodInterfaces for the instance-variables category. The vocabulary parameter, at present anyway, is not used. And for non-players, the method is at present vacuous in any case\\\"\\n\\n\\t^ OrderedCollection new! !\\n\\n!Object methodsFor: 'scripting' stamp: 'sw 8/3/2001 13:53'!\\nmethodInterfacesForScriptsCategoryIn: aVocabulary\\n\\t\\\"Answer a list of method interfaces for the category #scripts, as seen in a viewer or other tool. The vocabulary argument is not presently used. Also, at present, only Players really do anyting interesting here.\\\"\\n\\n\\t^ OrderedCollection new! !\\n\\n!Object methodsFor: 'scripting' stamp: 'RAA 2/16/2001 19:37'!\\nselfWrittenAsIll\\n\\n\\t^self! !\\n\\n!Object methodsFor: 'scripting' stamp: 'RAA 2/16/2001 19:38'!\\nselfWrittenAsIm\\n\\n\\t^self! !\\n\\n!Object methodsFor: 'scripting' stamp: 'RAA 2/16/2001 19:37'!\\nselfWrittenAsMe\\n\\n\\t^self! !\\n\\n!Object methodsFor: 'scripting' stamp: 'RAA 2/16/2001 19:37'!\\nselfWrittenAsMy\\n\\n\\t^self! !\\n\\n!Object methodsFor: 'scripting' stamp: 'RAA 2/16/2001 19:38'!\\nselfWrittenAsThis\\n\\n\\t^self! !\\n\\n\\n!Object methodsFor: 'self evaluating' stamp: 'sd 7/31/2005 21:47'!\\nisSelfEvaluating\\n\\t^ self isLiteral! !\\n\\n\\n!Object methodsFor: 'system primitives'!\\nasOop\\n\\t\\\"Primitive. Answer a SmallInteger whose value is half of the receiver's \\n\\tobject pointer (interpreting object pointers as 16-bit signed quantities). \\n\\tFail if the receiver is a SmallInteger. Essential. See Object documentation \\n\\twhatIsAPrimitive.\\\"\\n\\n\\t<primitive: 75>\\n\\tself primitiveFailed! !\\n\\n!Object methodsFor: 'system primitives' stamp: 'di 1/9/1999 15:19'!\\nbecomeForward: otherObject \\n\\t\\\"Primitive. All variables in the entire system that used to point\\n\\tto the receiver now point to the argument.\\n\\tFails if either argument is a SmallInteger.\\\"\\n\\n\\t(Array with: self)\\n\\t\\telementsForwardIdentityTo:\\n\\t\\t\\t(Array with: otherObject)! !\\n\\n!Object methodsFor: 'system primitives' stamp: 'zz 3/3/2004 23:53'!\\nbecomeForward: otherObject copyHash: copyHash\\n\\t\\\"Primitive. All variables in the entire system that used to point to the receiver now point to the argument.\\n\\tIf copyHash is true, the argument's identity hash bits will be set to those of the receiver.\\n\\tFails if either argument is a SmallInteger.\\\"\\n\\n\\t(Array with: self)\\n\\t\\telementsForwardIdentityTo:\\n\\t\\t\\t(Array with: otherObject)\\n\\t\\t\\t\\tcopyHash: copyHash! !\\n\\n!Object methodsFor: 'system primitives' stamp: 'sw 10/16/2000 10:59'!\\nclassName\\n\\t\\\"Answer a string characterizing the receiver's class, for use in list views for example\\\"\\n\\n\\t^ self class name asString! !\\n\\n!Object methodsFor: 'system primitives' stamp: 'sw 10/16/2000 11:04'!\\ncreationStamp\\n\\t\\\"Answer a string which reports the creation particulars of the receiver. Intended perhaps for list views, but this is presently a feature not easily accessible\\\"\\n\\n\\t^ '<no creation stamp>'! !\\n\\n!Object methodsFor: 'system primitives'!\\ninstVarAt: index \\n\\t\\\"Primitive. Answer a fixed variable in an object. The numbering of the \\n\\tvariables corresponds to the named instance variables. Fail if the index \\n\\tis not an Integer or is not the index of a fixed variable. Essential. See \\n\\tObject documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 73>\\n\\t\\\"Access beyond fixed variables.\\\"\\n\\t^self basicAt: index - self class instSize\\t\\t! !\\n\\n!Object methodsFor: 'system primitives'!\\ninstVarAt: anInteger put: anObject \\n\\t\\\"Primitive. Store a value into a fixed variable in the receiver. The \\n\\tnumbering of the variables corresponds to the named instance variables. \\n\\tFail if the index is not an Integer or is not the index of a fixed variable. \\n\\tAnswer the value stored as the result. Using this message violates the \\n\\tprinciple that each object has sovereign control over the storing of \\n\\tvalues into its instance variables. Essential. See Object documentation \\n\\twhatIsAPrimitive.\\\"\\n\\n\\t<primitive: 74>\\n\\t\\\"Access beyond fixed fields\\\"\\n\\t^self basicAt: anInteger - self class instSize put: anObject! !\\n\\n!Object methodsFor: 'system primitives' stamp: 'sw 10/16/2000 11:09'!\\ninstVarNamed: aString\\n\\t\\\"Return the value of the instance variable in me with that name. Slow and unclean, but very useful. \\\"\\n\\n\\t^ self instVarAt: (self class allInstVarNames indexOf: aString asString)\\n\\n\\n! !\\n\\n!Object methodsFor: 'system primitives' stamp: 'sw 10/16/2000 11:10'!\\ninstVarNamed: aString put: aValue\\n\\t\\\"Store into the value of the instance variable in me of that name. Slow and unclean, but very useful. \\\"\\n\\n\\t^ self instVarAt: (self class allInstVarNames indexOf: aString asString) put: aValue\\n! !\\n\\n!Object methodsFor: 'system primitives' stamp: 'sw 10/17/2000 11:12'!\\noopString\\n\\t\\\"Answer a string that represents the oop of the receiver\\\"\\n\\n\\t^ self asOop printString! !\\n\\n!Object methodsFor: 'system primitives' stamp: 'ar 3/2/2001 01:34'!\\nprimitiveChangeClassTo: anObject\\n\\t\\\"Primitive. Change the class of the receiver into the class of the argument given that the format of the receiver matches the format of the argument's class. Fail if receiver or argument are SmallIntegers, or the receiver is an instance of a compact class and the argument isn't, or when the argument's class is compact and the receiver isn't, or when the format of the receiver is different from the format of the argument's class, or when the arguments class is fixed and the receiver's size differs from the size that an instance of the argument's class should have.\\n\\tNote: The primitive will fail in most cases that you think might work. This is mostly because of a) the difference between compact and non-compact classes, and b) because of differences in the format. As an example, '(Array new: 3) primitiveChangeClassTo: Morph basicNew' would fail for three of the reasons mentioned above. Array is compact, Morph is not (failure #1). Array is variable and Morph is fixed (different format - failure #2). Morph is a fixed-field-only object and the array is too short (failure #3).\\n\\tThe facility is really provided for certain, very specific applications (mostly related to classes changing shape) and not for casual use.\\\"\\n\\n\\t<primitive: 115>\\n\\tself primitiveFailed! !\\n\\n!Object methodsFor: 'system primitives' stamp: 'di 3/27/1999 12:21'!\\nrootStubInImageSegment: imageSegment\\n\\n\\t^ ImageSegmentRootStub new\\n\\t\\txxSuperclass: nil\\n\\t\\tformat: nil\\n\\t\\tsegment: imageSegment! !\\n\\n!Object methodsFor: 'system primitives'!\\nsomeObject\\n\\t\\\"Primitive. Answer the first object in the enumeration of all\\n\\t objects.\\\"\\n\\n\\t<primitive: 138>\\n\\tself primitiveFailed.! !\\n\\n\\n!Object methodsFor: 'testing' stamp: 'sw 9/26/2001 11:58'!\\nbasicType\\n\\t\\\"Answer a symbol representing the inherent type of the receiver\\\"\\n\\n\\t^ #Object! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 5/3/2001 16:19'!\\nbeViewed\\n\\t\\\"Open up a viewer on the receiver. The Presenter is invited to decide just how to present this viewer\\\"\\n\\n\\tself uniqueNameForReference. \\\"So the viewer will have something nice to refer to\\\"\\n\\tself presenter viewObject: self! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 10/16/2000 11:01'!\\ncostumes\\n\\t\\\"Answer a list of costumes associated with the receiver. The appearance of this method in class Object serves only as a backstop, probably only transitionally\\\"\\n\\n\\t^ nil! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 1/12/98 18:09'!\\nhaltIfNil! !\\n\\n!Object methodsFor: 'testing' stamp: 'md 1/20/2006 17:09'!\\nhasLiteralSuchThat: testBlock\\n\\t\\\"This is the end of the imbedded structure path so return false.\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'md 1/20/2006 17:10'!\\nhasLiteralThorough: literal\\n\\t\\\"Answer true if literal is identical to any literal in this array, even if imbedded in further structures. This is the end of the imbedded structure path so return false.\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 1/30/2001 22:24'!\\nhaveFullProtocolBrowsed\\n\\t\\\"Open up a Lexicon on the receiver\\\"\\n\\n\\t^ self haveFullProtocolBrowsedShowingSelector: nil\\n\\n\\t\\\"(2@3) haveFullProtocolBrowsed\\\"\\n! !\\n\\n!Object methodsFor: 'testing' stamp: 'ar 9/27/2005 21:04'!\\nhaveFullProtocolBrowsedShowingSelector: aSelector\\n\\t\\\"Open up a Lexicon on the receiver, having it open up showing aSelector, which may be nil\\\"\\n\\n\\t| aBrowser |\\n\\taBrowser := (Smalltalk at: #InstanceBrowser ifAbsent:[^nil]) new useVocabulary: Vocabulary fullVocabulary.\\n\\taBrowser openOnObject: self inWorld: ActiveWorld showingSelector: aSelector\\n\\n\\t\\\"(2@3) haveFullProtocolBrowsed\\\"! !\\n\\n!Object methodsFor: 'testing' stamp: 'md 7/30/2005 21:21'!\\nisArray\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'ar 7/9/1999 18:18'!\\nisBehavior\\n\\t\\\"Return true if the receiver is a behavior.\\n\\tNote: Do not override in any class except behavior.\\\"\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'ajh 1/21/2003 13:15'!\\nisBlock\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'md 11/21/2003 12:14'!\\nisBlockClosure\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'yo 8/28/2002 13:41'!\\nisCharacter\\n\\n\\t^ false.\\n! !\\n\\n!Object methodsFor: 'testing' stamp: 'ar 8/17/1999 19:43'!\\nisCollection\\n\\t\\\"Return true if the receiver is some sort of Collection and responds to basic collection messages such as #size and #do:\\\"\\n\\t^false! !\\n\\n!Object methodsFor: 'testing'!\\nisColor\\n\\t\\\"Answer true if receiver is a Color. False by default.\\\"\\n\\n\\t^ false\\n! !\\n\\n!Object methodsFor: 'testing' stamp: 'nk 4/17/2004 19:43'!\\nisColorForm\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'md 11/21/2003 12:14'!\\nisCompiledMethod\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'mk 10/27/2003 17:33'!\\nisComplex\\n\\t\\\"Answer true if receiver is a Complex number. False by default.\\\"\\n\\n\\t^ false\\n! !\\n\\n!Object methodsFor: 'testing' stamp: 'md 8/11/2005 16:45'!\\nisDictionary\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'di 11/9/1998 09:38'!\\nisFloat\\n\\t\\\"Overridden to return true in Float, natch\\\"\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'ar 10/30/2000 23:22'!\\nisForm\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'len 1/13/98 21:18'!\\nisFraction\\n\\t\\\"Answer true if the receiver is a Fraction.\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'rhi 8/14/2003 08:51'!\\nisHeap\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing'!\\nisInteger\\n\\t\\\"Overridden to return true in Integer.\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'rhi 8/12/2003 09:52'!\\nisInterval\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'nk 4/25/2002 08:04'!\\nisMessageSend\\n\\t^false\\n! !\\n\\n!Object methodsFor: 'testing' stamp: 'md 2/19/2006 11:24'!\\nisMethodProperties\\n\\t^false! !\\n\\n!Object methodsFor: 'testing'!\\nisMorph\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'ar 9/13/2000 15:37'!\\nisMorphicEvent\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'gm 2/22/2003 12:56'!\\nisMorphicModel\\n\\t\\\"Return true if the receiver is a morphic model\\\"\\n\\t^false\\n! !\\n\\n!Object methodsFor: 'testing'!\\nisNumber\\n\\t\\\"Overridden to return true in Number, natch\\\"\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'di 11/6/1998 08:04'!\\nisPoint\\n\\t\\\"Overridden to return true in Point.\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'ikp 9/26/97 14:45'!\\nisPseudoContext\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'md 10/2/2005 21:52'!\\nisRectangle\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'nk 6/14/2004 16:49'!\\nisSketchMorph\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'ar 12/23/1999 15:43'!\\nisStream\\n\\t\\\"Return true if the receiver responds to the stream protocol\\\"\\n\\t^false\\n! !\\n\\n!Object methodsFor: 'testing' stamp: 'sma 6/15/2000 15:48'!\\nisString\\n\\t\\\"Overridden to return true in String, natch\\\"\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'md 4/30/2003 15:30'!\\nisSymbol\\n\\t^ false ! !\\n\\n!Object methodsFor: 'testing' stamp: 'jam 3/9/2003 15:10'!\\nisSystemWindow\\n\\\"answer whatever the receiver is a SystemWindow\\\"\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing'!\\nisText\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'pmm 7/6/2006 20:46'!\\nisTrait\\n\\t\\\"Return true if the receiver is a trait.\\n\\tNote: Do not override in any class except TraitBehavior.\\\"\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'tk 10/21/97 12:45'!\\nisTransparent\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'ar 8/14/2001 23:19'!\\nisVariableBinding\\n\\t\\\"Return true if I represent a literal variable binding\\\"\\n\\t^false\\n\\t! !\\n\\n!Object methodsFor: 'testing' stamp: 'ls 7/14/1998 21:45'!\\nisWebBrowser\\n\\t\\\"whether this object is a web browser. See class: Scamper\\\"\\n\\t^false! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 10/27/2000 06:58'!\\nknownName\\n\\t\\\"If a formal name has been handed out for this object, answer it, else nil\\\"\\n\\t\\n\\t^ Preferences capitalizedReferences\\n\\t\\tifTrue:\\n\\t\\t\\t[References keyAtValue: self ifAbsent: [nil]]\\n\\t\\tifFalse:\\n\\t\\t\\t[nil]! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 9/27/96'!\\nname\\n\\t\\\"Answer a name for the receiver. This is used generically in the title of certain inspectors, such as the referred-to inspector, and specificially by various subsystems. By default, we let the object just print itself out.. \\\"\\n\\n\\t^ self printString! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 11/19/2001 13:28'!\\nnameForViewer\\n\\t\\\"Answer a name to be shown in a Viewer that is viewing the receiver\\\"\\n\\n\\t| aName |\\n\\t(aName _ self uniqueNameForReferenceOrNil) ifNotNil: [^ aName].\\n\\t(aName _ self knownName) ifNotNil: [^ aName].\\n\\n\\t^ [(self asString copyWithout: Character cr) truncateTo: 27] ifError:\\n\\t\\t[:msg :rcvr | ^ self class name printString]! !\\n\\n!Object methodsFor: 'testing'!\\nnotNil\\n\\t\\\"Coerces nil to false and everything else to true.\\\"\\n\\n\\t^true! !\\n\\n!Object methodsFor: 'testing' stamp: 'tk 9/6/2001 19:15'!\\nopenInstanceBrowserWithTiles\\n\\t\\\"Open up an instance browser on me with tiles as the code type, and with the search level as desired.\\\"\\n\\n\\t| aBrowser |\\n\\taBrowser _ InstanceBrowser new.\\n\\taBrowser useVocabulary: Vocabulary fullVocabulary.\\n\\taBrowser limitClass: self class.\\n\\taBrowser contentsSymbol: #tiles.\\t\\t\\\"preset it to make extra buttons (tile menus)\\\"\\n\\taBrowser openOnObject: self inWorld: ActiveWorld showingSelector: nil.\\n\\taBrowser contentsSymbol: #source.\\n\\taBrowser toggleShowingTiles.\\n\\n\\t\\\"\\n(2@3) openInstanceBrowserWithTiles.\\nWatchMorph new openInstanceBrowserWithTiles\\n\\\"! !\\n\\n!Object methodsFor: 'testing' stamp: 'tk 7/28/2005 04:50'!\\nrenameInternal: newName \\n\\t\\\"Change the internal name (because of a conflict) but leave the external name unchanged. Change Player class name, but do not change the names that appear in tiles. Any object that might be pointed to in the References dictionary might get this message sent to it upon reload\\\"\\n\\n\\t^ nil\\t\\\"caller will renameTo:. new name may be different\\\"! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 2/27/2002 14:55'!\\nrenameTo: newName\\n\\t\\\"If the receiver has an inherent idea about its own name, it should take action here. Any object that might be pointed to in the References dictionary might get this message sent to it upon reload\\\"! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 1/18/2001 13:43'!\\nshowDiffs\\n\\t\\\"Answer whether the receiver, serving as the model of a text-bearing entity, is 'showing differences' -- if it is, the editor may wish to show special feedback\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 10/20/1999 14:52'!\\nstepAt: millisecondClockValue in: aWindow\\n\\n\\t^ self stepIn: aWindow! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 10/19/1999 08:16'!\\nstepIn: aWindow\\n\\n\\t^ self step! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 10/19/1999 08:21'!\\nstepTime\\n\\t\\n\\t^ 1000 \\\"milliseconds -- default backstop for objects serving as models of system windows\\\"! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 10/19/1999 08:22'!\\nstepTimeIn: aSystemWindow\\n\\t\\n\\t^ 1000 \\\"milliseconds -- default backstop for objects serving as models of system windows\\\"! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 5/3/2001 18:22'!\\nvocabularyDemanded\\n\\t\\\"Answer a vocabulary that the receiver insists be used when it is looked at in a Viewer. This allows specific classes to insist on specific custom vocabularies\\\"\\n\\n\\t^ nil! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 11/13/2001 07:26'!\\nwantsDiffFeedback\\n\\t\\\"Answer whether the receiver, serving as the model of a text-bearing entity, would like for 'diffs' green pane-border feedback to be shown\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'di 1/8/1999 15:04'!\\nwantsSteps\\n\\t\\\"Overridden by morphic classes whose instances want to be stepped,\\n\\tor by model classes who want their morphic views to be stepped.\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'testing' stamp: 'sw 10/19/1999 08:26'!\\nwantsStepsIn: aSystemWindow\\n\\t\\n\\t^ self wantsSteps! !\\n\\n\\n!Object methodsFor: 'translation support'!\\ninline: inlineFlag\\n\\t\\\"For translation only; noop when running in Smalltalk.\\\"! !\\n\\n!Object methodsFor: 'translation support'!\\nvar: varSymbol declareC: declString\\n\\t\\\"For translation only; noop when running in Smalltalk.\\\"! !\\n\\n\\n!Object methodsFor: 'undo' stamp: 'di 9/11/2000 20:32'!\\ncapturedState\\n\\t\\\"May be overridden in subclasses.\\\"\\n\\n\\t^ self shallowCopy\\n! !\\n\\n!Object methodsFor: 'undo' stamp: 'di 9/11/2000 20:29'!\\ncommandHistory\\n\\t\\\"Return the command history for the receiver\\\"\\n\\t| w |\\n\\t(w _ self currentWorld) ifNotNil: [^ w commandHistory].\\n\\t^ CommandHistory new. \\\"won't really record anything but prevent breaking things\\\"! !\\n\\n!Object methodsFor: 'undo' stamp: 'di 12/12/2000 15:01'!\\npurgeAllCommands\\n\\t\\\"Purge all commands for this object\\\"\\n\\tPreferences useUndo ifFalse: [^ self]. \\\"get out quickly\\\"\\n\\tself commandHistory purgeAllCommandsSuchThat: [:cmd | cmd undoTarget == self].\\n! !\\n\\n!Object methodsFor: 'undo' stamp: 'di 9/12/2000 08:15'!\\nredoFromCapturedState: st \\n\\t\\\"May be overridden in subclasses. See also capturedState\\\"\\n\\n\\tself undoFromCapturedState: st \\\"Simple cases are symmetric\\\"\\n! !\\n\\n!Object methodsFor: 'undo' stamp: 'sw 11/16/2000 14:42'!\\nrefineRedoTarget: target selector: aSymbol arguments: arguments in: refineBlock \\n\\t\\\"Any object can override this method to refine its redo specification\\\"\\n\\n\\t^ refineBlock\\n\\t\\tvalue: target\\n\\t\\tvalue: aSymbol\\n\\t\\tvalue: arguments! !\\n\\n!Object methodsFor: 'undo' stamp: 'sw 11/16/2000 14:42'!\\nrefineUndoTarget: target selector: aSymbol arguments: arguments in: refineBlock \\n\\t\\\"Any object can override this method to refine its undo specification\\\"\\n\\n\\t^ refineBlock\\n\\t\\tvalue: target\\n\\t\\tvalue: aSymbol\\n\\t\\tvalue: arguments! !\\n\\n!Object methodsFor: 'undo' stamp: 'di 9/11/2000 20:30'!\\nrememberCommand: aCommand\\n\\t\\\"Remember the given command for undo\\\"\\n\\tPreferences useUndo ifFalse: [^ self]. \\\"get out quickly\\\"\\n\\t^ self commandHistory rememberCommand: aCommand! !\\n\\n!Object methodsFor: 'undo' stamp: 'di 9/11/2000 20:30'!\\nrememberUndoableAction: actionBlock named: caption\\n\\t| cmd result |\\n\\tcmd _ Command new cmdWording: caption.\\n\\tcmd undoTarget: self selector: #undoFromCapturedState: argument: self capturedState.\\n\\tresult _ actionBlock value.\\n\\tcmd redoTarget: self selector: #redoFromCapturedState: argument: self capturedState.\\n\\tself rememberCommand: cmd.\\n\\t^ result! !\\n\\n!Object methodsFor: 'undo' stamp: 'di 9/11/2000 20:32'!\\nundoFromCapturedState: st \\n\\t\\\"May be overridden in subclasses. See also capturedState\\\"\\n\\n\\tself copyFrom: st\\n! !\\n\\n\\n!Object methodsFor: 'updating'!\\nchanged\\n\\t\\\"Receiver changed in a general way; inform all the dependents by \\n\\tsending each dependent an update: message.\\\"\\n\\n\\tself changed: self! !\\n\\n!Object methodsFor: 'updating'!\\nchanged: aParameter \\n\\t\\\"Receiver changed. The change is denoted by the argument aParameter. \\n\\tUsually the argument is a Symbol that is part of the dependent's change \\n\\tprotocol. Inform all of the dependents.\\\"\\n\\n\\tself dependents do: [:aDependent | aDependent update: aParameter]! !\\n\\n!Object methodsFor: 'updating' stamp: 'nk 2/17/2004 11:12'!\\nchanged: anAspect with: anObject\\n\\t\\\"Receiver changed. The change is denoted by the argument anAspect. \\n\\tUsually the argument is a Symbol that is part of the dependent's change \\n\\tprotocol. Inform all of the dependents. Also pass anObject for additional information.\\\"\\n\\n\\tself dependents do: [:aDependent | aDependent update: anAspect with: anObject]! !\\n\\n!Object methodsFor: 'updating' stamp: 'sw 10/12/1999 18:15'!\\nhandledListVerification\\n\\t\\\"When a self-updating PluggableListMorph lazily checks to see the state of affairs, it first gives its model an opportunity to handle the list verification itself (this is appropriate for some models, such as VersionsBrowser); if a list's model has indeed handled things itself, it returns true here\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'updating' stamp: 'sw 10/31/1999 00:15'!\\nnoteSelectionIndex: anInteger for: aSymbol\\n\\t\\\"backstop\\\"! !\\n\\n!Object methodsFor: 'updating'!\\nokToChange\\n\\t\\\"Allows a controller to ask this of any model\\\"\\n\\t^ true! !\\n\\n!Object methodsFor: 'updating' stamp: 'sw 10/19/1999 14:39'!\\nupdateListsAndCodeIn: aWindow\\n\\tself canDiscardEdits ifFalse: [^ self].\\n\\taWindow updatablePanes do: [:aPane | aPane verifyContents]! !\\n\\n!Object methodsFor: 'updating' stamp: 'sma 2/29/2000 20:05'!\\nupdate: aParameter \\n\\t\\\"Receive a change notice from an object of whom the receiver is a \\n\\tdependent. The default behavior is to do nothing; a subclass might want \\n\\tto change itself in some way.\\\"\\n\\n\\t^ self! !\\n\\n!Object methodsFor: 'updating' stamp: 'nk 2/17/2004 11:13'!\\nupdate: anAspect with: anObject\\n\\t\\\"Receive a change notice from an object of whom the receiver is a \\n\\tdependent. The default behavior is to call update:,\\n\\twhich by default does nothing; a subclass might want \\n\\tto change itself in some way.\\\"\\n\\n\\t^ self update: anAspect! !\\n\\n!Object methodsFor: 'updating' stamp: 'jm 8/20/1998 18:26'!\\nwindowIsClosing\\n\\t\\\"This message is used to inform a models that its window is closing. Most models do nothing, but some, such as the Debugger, must do some cleanup. Note that this mechanism must be used with care by models that support multiple views, since one view may be closed while others left open.\\\"\\n! !\\n\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 10/4/1999 08:13'!\\naddModelItemsToWindowMenu: aMenu\\n\\t\\\"aMenu is being constructed to be presented to the user in response to the user's pressing on the menu widget in the title bar of a morphic window. Here, the model is given the opportunity to add any model-specific items to the menu, whose default target is the SystemWindow itself.\\\"! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 10/5/1998 14:39'!\\naddModelMenuItemsTo: aCustomMenu forMorph: aMorph hand: aHandMorph \\n\\t\\\"The receiver serves as the model for aMorph; a menu is being constructed for the morph, and here the receiver is able to add its own items\\\"\\n! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sma 11/12/2000 11:43'!\\nasExplorerString\\n\\t^ self printString! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 7/13/1999 15:53'!\\ndefaultBackgroundColor\\n\\t\\\"Answer the color to be used as the base window color for a window whose model is an object of the receiver's class\\\"\\n\\t\\n\\t^ Preferences windowColorFor: self class name! !\\n\\n!Object methodsFor: 'user interface'!\\ndefaultLabelForInspector\\n\\t\\\"Answer the default label to be used for an Inspector window on the receiver.\\\"\\n\\n\\t^ self class name! !\\n\\n!Object methodsFor: 'user interface' stamp: 'RAA 7/10/2000 08:11'!\\neToyStreamedRepresentationNotifying: aWidget\\n\\n\\t| outData |\\n\\t[ outData _ SmartRefStream streamedRepresentationOf: self ] \\n\\t\\ton: ProgressInitiationException\\n\\t\\tdo: [ :ex | \\n\\t\\t\\tex sendNotificationsTo: [ :min :max :curr |\\n\\t\\t\\t\\taWidget ifNotNil: [aWidget flashIndicator: #working].\\n\\t\\t\\t].\\n\\t\\t].\\n\\t^outData\\n! !\\n\\n!Object methodsFor: 'user interface' stamp: 'ar 9/27/2005 20:29'!\\nexplore\\n\\t^ToolSet explore: self! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 8/15/97 17:25'!\\nfullScreenSize\\n\\t\\\"Answer the size to which a window displaying the receiver should be set\\\"\\n\\t| adj |\\n\\tadj _ (3 * Preferences scrollBarWidth) @ 0.\\n\\t^ Rectangle origin: adj extent: (DisplayScreen actualScreenSize - adj)! !\\n\\n!Object methodsFor: 'user interface' stamp: 'RAA 6/21/1999 11:27'!\\nhasContentsInExplorer\\n\\n\\t^self basicSize > 0 or: [self class allInstVarNames isEmpty not]\\n! !\\n\\n!Object methodsFor: 'user interface' stamp: 'rbb 3/1/2005 09:28'!\\ninform: aString\\n\\t\\\"Display a message for the user to read and then dismiss. 6/9/96 sw\\\"\\n\\n\\taString isEmptyOrNil ifFalse: [UIManager default inform: aString]! !\\n\\n!Object methodsFor: 'user interface'!\\ninitialExtent\\n\\t\\\"Answer the desired extent for the receiver when a view on it is first opened on the screen. \\n\\t5/22/96 sw: in the absence of any override, obtain from RealEstateAgent\\\"\\n\\n\\t^ RealEstateAgent standardWindowExtent! !\\n\\n!Object methodsFor: 'user interface' stamp: 'ar 9/27/2005 20:30'!\\ninspectWithLabel: aLabel\\n\\t\\\"Create and schedule an Inspector in which the user can examine the receiver's variables.\\\"\\n\\t^ToolSet inspect: self label: aLabel! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 6/12/2001 11:09'!\\nlaunchPartVia: aSelector\\n\\t\\\"Obtain a morph by sending aSelector to self, and attach it to the morphic hand. This provides a general protocol for parts bins\\\"\\n\\n\\t| aMorph |\\n\\taMorph _ self perform: aSelector.\\n\\taMorph setProperty: #beFullyVisibleAfterDrop toValue: true.\\n\\taMorph openInHand! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 6/17/2004 01:47'!\\nlaunchPartVia: aSelector label: aString\\n\\t\\\"Obtain a morph by sending aSelector to self, and attach it to the morphic hand. This provides a general protocol for parts bins\\\"\\n\\n\\t| aMorph |\\n\\taMorph _ self perform: aSelector.\\n\\taMorph setNameTo: (ActiveWorld unusedMorphNameLike: aString).\\n\\taMorph setProperty: #beFullyVisibleAfterDrop toValue: true.\\n\\taMorph openInHand! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 10/16/2000 11:11'!\\nlaunchTileToRefer\\n\\t\\\"Create a tile to reference the receiver, and attach it to the hand\\\"\\n\\n\\tself currentHand attachMorph: self tileToRefer! !\\n\\n!Object methodsFor: 'user interface' stamp: 'di 5/11/1999 22:26'!\\nmodelSleep\\n\\t\\\"A window with me as model is being exited or collapsed or closed.\\n\\tDefault response is no-op\\\" ! !\\n\\n!Object methodsFor: 'user interface' stamp: 'di 5/11/1999 22:01'!\\nmodelWakeUp\\n\\t\\\"A window with me as model is being entered or expanded. Default response is no-op\\\" ! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 10/16/1999 22:45'!\\nmodelWakeUpIn: aWindow\\n\\t\\\"A window with me as model is being entered or expanded. Default response is no-op\\\" \\n\\tself modelWakeUp! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 3/8/1999 15:27'!\\nmouseUpBalk: evt\\n\\t\\\"A button I own got a mouseDown, but the user moved out before letting up. Certain kinds of objects (so-called 'radio buttons', for example, and other structures that must always have some selection, e.g. PaintBoxMorph) wish to take special action in this case; this default does nothing.\\\"\\n! !\\n\\n!Object methodsFor: 'user interface' stamp: 'sw 8/22/97 13:14'!\\nnewTileMorphRepresentative\\n\\t^ TileMorph new setLiteral: self! !\\n\\n!Object methodsFor: 'user interface' stamp: 'jcg 11/1/2001 13:13'!\\nnotYetImplemented\\n\\tself inform: 'Not yet implemented (', thisContext sender printString, ')'! !\\n\\n!Object methodsFor: 'user interface' stamp: 'di 6/10/1998 15:06'!\\nwindowActiveOnFirstClick\\n\\t\\\"Return true if my window should be active on first click.\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'user interface' stamp: 'di 6/10/1998 15:06'!\\nwindowReqNewLabel: labelString\\n\\t\\\"My window's title has been edited.\\n\\tReturn true if this is OK, and override for further behavior.\\\"\\n\\n\\t^ true! !\\n\\n\\n!Object methodsFor: 'world hacking' stamp: 'ar 3/17/2001 23:45'!\\ncouldOpenInMorphic\\n\\n \\\"is there an obvious morphic world in which to open a new morph?\\\"\\n\\n ^World notNil or: [ActiveWorld notNil]! !\\n\\n\\n!Object methodsFor: '*39Deprecated' stamp: 'gk 2/24/2004 08:49'!\\nbeep\\n\\t\\\"Deprecated.\\\"\\n\\t\\n\\tself deprecated: 'Use Beeper class>>beep instead.'.\\n\\tBeeper beep! !\\n\\n!Object methodsFor: '*39Deprecated' stamp: 'gk 2/24/2004 08:50'!\\nbeepPrimitive\\n\\t\\\"Deprecated. Beep in the absence of sound support.\\\"\\n\\t\\n\\tself deprecated: 'Use Beeper class>>beep or Beeper class>>beepPrimitive instead.'.\\n\\tBeeper beepPrimitive! !\\n\\n!Object methodsFor: '*39Deprecated' stamp: 'md 12/12/2003 17:02'!\\nbeep: soundName\\n\\t\\\"Make the given sound, unless the making of sound is disabled in Preferences.\\\"\\n\\n\\tself deprecated: 'Use SampledSound>>playSoundNamed: instead.'.\\n\\tPreferences soundsEnabled\\n\\t\\tifTrue: [self playSoundNamed: soundName]\\n! !\\n\\n!Object methodsFor: '*39Deprecated' stamp: 'sd 11/19/2004 16:57'!\\ncontentsGetz: x\\n\\tself deprecated: 'there is no method named contents in object and in addition only one sender in a method not called'. \\n\\tself contents: x! !\\n\\n!Object methodsFor: '*39Deprecated' stamp: 'sd 11/13/2003 21:10'!\\ndeprecatedExplanation: aString\\n \\\"This method is OBSOLETE. Use #deprecated: instead.\\\"\\n\\tself deprecated: 'Use Object>>deprecated: instead of deprecatedExplanation:.'.\\n\\n\\tPreferences showDeprecationWarnings ifTrue:\\n\\t\\t[Deprecation signal: ('{1} has been deprecated. {2}' translated format: {thisContext sender printString. aString})]! !\\n\\n!Object methodsFor: '*39Deprecated' stamp: 'sd 11/13/2003 21:11'!\\ndeprecated: aBlock explanation: aString \\n\\t \\\"This method is OBSOLETE. Use #deprecated:block: instead.\\\"\\n\\tself deprecated: 'Use Object>>deprecated:block: instead of deprecated:explanation:.'.\\n\\n\\tPreferences showDeprecationWarnings ifTrue:\\n\\t\\t[Deprecation\\n\\t\\t\\tsignal: ('{1} has been deprecated. {2}' translated format: {thisContext sender printString. aString})].\\n\\t^ aBlock value.\\n! !\\n\\n!Object methodsFor: '*39Deprecated' stamp: 'md 12/12/2003 16:25'!\\ndoIfNotNil: aBlock\\n\\tself deprecated: 'use ifNotNilDo:'.\\n\\t^ self ifNotNilDo: aBlock\\n! !\\n\\n!Object methodsFor: '*39Deprecated' stamp: 'md 11/27/2004 12:20'!\\nifKindOf: aClass thenDo: aBlock\\n\\tself deprecated: 'Deprecated. Just use #isKindOf:'.\\n\\t^ (self isKindOf: aClass) ifTrue: [aBlock value: self]! !\\n\\n!Object methodsFor: '*39Deprecated' stamp: 'gk 2/23/2004 20:51'!\\nplaySoundNamed: soundName\\n\\t\\\"Deprecated.\\n\\tPlay the sound with the given name.\\\"\\n\\n\\tself deprecated: 'Use \\\"SoundService default playSoundNamed: aName\\\" instead.'.\\n\\tSoundService default playSoundNamed: soundName! !\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n!Object methodsFor: '*monticello' stamp: 'dvf 8/10/2004 23:25'!\\nisConflict\\n\\t^false! !\\n\\n\\n!Object methodsFor: '*services-base' stamp: 'rr 3/21/2006 11:54'!\\nrequestor\\n\\t\\\"returns the focused window's requestor\\\"\\n\\n\\t\\\"SystemWindow focusedWindow ifNotNilDo: [:w | ^ w requestor].\\\"\\n\\n\\t\\\"triggers an infinite loop\\\"\\n\\n\\t^ Requestor default! !\\n\\n\\n!Object methodsFor: '*system-support' stamp: 'dvf 8/23/2003 12:27'!\\nsystemNavigation\\n\\n\\t^ SystemNavigation default! !\\n\\n\\n!Object methodsFor: '*Tools-Explorer' stamp: 'stephaneducasse 9/17/2005 21:52'!\\nexploreAndYourself\\n\\t\\\"i.e. explore; yourself. Thisway i can peek w/o typing all the parentheses\\\"\\n\\tself explore. \\n ^self! !\\n\\n!Object methodsFor: '*Tools-Explorer' stamp: 'stephaneducasse 9/17/2005 21:48'!\\nexploreWithLabel: label\\n\\n\\t^ ObjectExplorer new openExplorerFor: self withLabel:\\nlabel! !\\n\\n\\n\\n\\n\\n!Object methodsFor: '*tools-browser' stamp: 'mu 3/6/2004 15:13'!\\nbrowse\\n\\tself systemNavigation browseClass: self class! !\\n\\n!Object methodsFor: '*tools-browser' stamp: 'mu 3/11/2004 16:00'!\\nbrowseHierarchy\\n\\tself systemNavigation browseHierarchy: self class! !\\n\\n\\n!Object methodsFor: 'private'!\\nerrorImproperStore\\n\\t\\\"Create an error notification that an improper store was attempted.\\\"\\n\\n\\tself error: 'Improper store into indexable object'! !\\n\\n!Object methodsFor: 'private'!\\nerrorNonIntegerIndex\\n\\t\\\"Create an error notification that an improper object was used as an index.\\\"\\n\\n\\tself error: 'only integers should be used as indices'! !\\n\\n!Object methodsFor: 'private' stamp: 'yo 6/29/2004 11:37'!\\nerrorNotIndexable\\n\\t\\\"Create an error notification that the receiver is not indexable.\\\"\\n\\n\\tself error: ('Instances of {1} are not indexable' translated format: {self class name})! !\\n\\n!Object methodsFor: 'private'!\\nerrorSubscriptBounds: index \\n\\t\\\"Create an error notification that an improper integer was used as an index.\\\"\\n\\n\\tself error: 'subscript is out of bounds: ' , index printString! !\\n\\n!Object methodsFor: 'private' stamp: 'ar 2/6/2004 14:47'!\\nprimitiveError: aString \\n\\t\\\"This method is called when the error handling results in a recursion in \\n\\tcalling on error: or halt or halt:.\\\"\\n\\n\\t| context |\\n\\t(String\\n\\t\\tstreamContents: \\n\\t\\t\\t[:s |\\n\\t\\t\\ts nextPutAll: '***System error handling failed***'.\\n\\t\\t\\ts cr; nextPutAll: aString.\\n\\t\\t\\tcontext _ thisContext sender sender.\\n\\t\\t\\t20 timesRepeat: [context == nil ifFalse: [s cr; print: (context _ context sender)]].\\n\\t\\t\\ts cr; nextPutAll: '-------------------------------'.\\n\\t\\t\\ts cr; nextPutAll: 'Type CR to enter an emergency evaluator.'.\\n\\t\\t\\ts cr; nextPutAll: 'Type any other character to restart.'])\\n\\t\\tdisplayAt: 0 @ 0.\\n\\t[Sensor keyboardPressed] whileFalse.\\n\\tSensor keyboard = Character cr ifTrue: [Transcripter emergencyEvaluator].\\n\\tSmalltalk isMorphic\\n\\t\\tifTrue: [World install \\\"init hands and redisplay\\\"]\\n\\t\\tifFalse: [ScheduledControllers searchForActiveController]! !\\n\\n!Object methodsFor: 'private'!\\nspecies\\n\\t\\\"Answer the preferred class for reconstructing the receiver. For example, \\n\\tcollections create new collections whenever enumeration messages such as \\n\\tcollect: or select: are invoked. The new kind of collection is determined by \\n\\tthe species of the original collection. Species and class are not always the \\n\\tsame. For example, the species of Interval is Array.\\\"\\n\\n\\t^self class! !\\n\\n!Object methodsFor: 'private'!\\nstoreAt: offset inTempFrame: aContext\\n\\t\\\"This message had to get sent to an expression already on the stack\\n\\tas a Block argument being accessed by the debugger.\\n\\tJust re-route it to the temp frame.\\\"\\n\\t^ aContext tempAt: offset put: self! !\\n\\n\\n!Object methodsFor: '*Morphic-NewCurve-testing''' stamp: 'wiz 12/31/2005 21:31'!\\nisNonZero\\n\\\"Overriden in Number. This returns the backstop answer for non-numbers\\\"\\n^false.! !\\n\\n\\n!Object methodsFor: 'events' stamp: 'nk 8/27/2003 16:23'!\\nactionsWithReceiver: anObject forEvent: anEventSelector\\n\\n\\t^(self actionSequenceForEvent: anEventSelector)\\n select: [:anAction | anAction receiver == anObject ]! !\\n\\n!Object methodsFor: 'events' stamp: 'nk 8/27/2003 17:45'!\\nrenameActionsWithReceiver: anObject forEvent: anEventSelector toEvent: newEvent\\n\\n\\t| oldActions newActions |\\n\\toldActions _ Set new.\\n\\tnewActions _ Set new.\\n\\t(self actionSequenceForEvent: anEventSelector) do: [ :action |\\n\\t\\taction receiver == anObject\\n\\t\\t\\tifTrue: [ oldActions add: anObject ]\\n\\t\\t\\tifFalse: [ newActions add: anObject ]].\\n\\tself setActionSequence: (ActionSequence withAll: newActions) forEvent: anEventSelector.\\n\\toldActions do: [ :act | self when: newEvent evaluate: act ].! !\\n\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 10/16/2000 10:35'!\\nassureUniClass\\n\\t\\\"If the receiver is not yet an instance of a uniclass, create a uniclass for it and make the receiver become an instance of that class.\\\"\\n\\n\\t| anInstance |\\n\\tself belongsToUniClass ifTrue: [^ self].\\n\\tanInstance _ self class instanceOfUniqueClass.\\n\\tself become: (self as: anInstance class).\\n\\t^ anInstance! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 10/16/2000 10:41'!\\nbelongsToUniClass\\n\\t\\\"Answer whether the receiver belongs to a uniclass. For the moment (this is not entirely satisfactory) this is precisely equated with the classname ending in a digit\\\"\\n\\n\\t^ self class name endsWithDigit! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 12/11/2000 15:37'!\\nbrowseOwnClassSubProtocol\\n\\t\\\"Open up a ProtocolBrowser on the subprotocol of the receiver\\\"\\n\\n\\tProtocolBrowser openSubProtocolForClass: self class\\n! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 8/4/2001 00:51'!\\ncategoriesForViewer: aViewer\\n\\t\\\"Answer a list of categories to offer in the given viewer\\\"\\n\\n\\t^ aViewer currentVocabulary categoryListForInstance: self ofClass: self class limitClass: aViewer limitClass! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 8/3/2001 22:08'!\\ncategoriesForVocabulary: aVocabulary limitClass: aLimitClass\\n\\t\\\"Answer a list of categories of methods for the receiver when using the given vocabulary, given that one considers only methods that are implemented not further away than aLimitClass\\\"\\n\\n\\t^ aVocabulary categoryListForInstance: self ofClass: self class limitClass: aLimitClass! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 10/25/2000 07:20'!\\nchooseNewNameForReference\\n\\t\\\"Offer an opportunity for the receiver, presumed already to be known in the References registry, to be renamed\\\"\\n\\n\\t| nameSym current newName |\\n\\tcurrent _ References keyAtValue: self ifAbsent: [^ self error: 'not found in References'].\\n\\n\\tnewName _ FillInTheBlank request: 'Please enter new name' initialAnswer: current.\\n\\t\\\"Want to user some better way of determining the validity of the chosen identifier, and also want to give more precise diagnostic if the string the user types in is not acceptable. Work to be done here.\\\"\\n\\n\\tnewName isEmpty ifTrue: [^ nil].\\n\\t((Scanner isLiteralSymbol: newName) and: [(newName includes: $:) not])\\n\\t\\tifTrue:\\n\\t\\t\\t[nameSym _ newName capitalized asSymbol.\\n\\t\\t\\t(((References includesKey: nameSym) not and:\\n\\t\\t\\t\\t[(Smalltalk includesKey: nameSym) not]) and:\\n\\t\\t\\t\\t\\t\\t[(ScriptingSystem allKnownClassVariableNames includes: nameSym) not])\\n\\t\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t\\t[(References associationAt: current) key: nameSym.\\n\\t\\t\\t\\t\\t\\tReferences rehash.\\n\\t\\t\\t\\t\\t\\t^ nameSym]].\\n\\tself inform: 'Sorry, that name is not available.'.\\n\\t^ nil! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 8/3/2001 21:22'!\\ndefaultLimitClassForVocabulary: aVocabulary\\n\\t\\\"Answer the class to use, by default, as the limit class on a protocol browser or viewer opened up on the receiver, within the purview of the Vocabulary provided\\\"\\n\\n\\t^ (aVocabulary isKindOf: FullVocabulary)\\n\\t\\tifTrue:\\n\\t\\t\\t [self class superclass == Object\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[self class]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[self class superclass]]\\n\\t\\tifFalse:\\n\\t\\t\\t[ProtoObject]! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 2/14/2000 14:24'!\\ndefaultNameStemForInstances\\n\\t\\\"Answer a basis for names of default instances of the receiver. The default is to let the class specify, but certain instances will want to override. (PasteUpMorphs serving as Worlds come to mind\\\"\\n\\n\\t^ self class defaultNameStemForInstances! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 5/22/2001 16:53'!\\nelementTypeFor: aStringOrSymbol vocabulary: aVocabulary\\n\\t\\\"Answer a symbol characterizing what kind of element aStringOrSymbol represents. Realistically, at present, this always just returns #systemScript; a prototyped but not-incorporated architecture supported use of a leading colon to characterize an inst var of a system class, and for the moment we still see its remnant here.\\\"\\n\\n\\tself flag: #deferred. \\\"a loose end in the non-player case\\\"\\n\\t^ #systemScript! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 5/4/2001 07:04'!\\nexternalName\\n\\t\\\"Answer an external name by which the receiver is known. Generic implementation here is a transitional backstop. probably\\\"\\n\\n\\t^ self nameForViewer! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 5/4/2001 07:06'!\\ngraphicForViewerTab\\n\\t\\\"When a Viewer is open on the receiver, its tab needs some graphic to show to the user. Answer a form or a morph to serve that purpose. A generic image is used for arbitrary objects, but note my reimplementors\\\"\\n\\t\\n\\t^ ScriptingSystem formAtKey: 'Image'! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 5/4/2001 07:08'!\\nhasUserDefinedSlots\\n\\t\\\"Answer whether the receiver has any user-defined slots, in the omniuser sense of the term. This is needed to allow Viewers to look at any object, not just at Players.\\\"\\n\\n\\t^ false! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 8/22/2002 14:07'!\\ninfoFor: anElement inViewer: aViewer\\n\\t\\\"The user made a gesture asking for info/menu relating to me. Some of the messages dispatched here are not yet available in this image\\\"\\n\\n\\t| aMenu elementType |\\n\\telementType _ self elementTypeFor: anElement vocabulary: aViewer currentVocabulary.\\n\\t((elementType = #systemSlot) | (elementType == #userSlot))\\n\\t\\tifTrue:\\t[^ self slotInfoButtonHitFor: anElement inViewer: aViewer].\\n\\tself flag: #deferred. \\\"Use a traditional MenuMorph, and reinstate the pacify thing\\\"\\n\\taMenu _ MenuMorph new defaultTarget: aViewer.\\n\\t#(\\t('implementors'\\t\\t\\tbrowseImplementorsOf:)\\n\\t\\t('senders'\\t\\t\\t\\tbrowseSendersOf:)\\n\\t\\t('versions'\\t\\t\\t\\tbrowseVersionsOf:)\\n\\t\\t-\\n\\t\\t('browse full'\\t\\t\\tbrowseMethodFull:)\\n\\t\\t('inheritance'\\t\\t\\tbrowseMethodInheritance:)\\n\\t\\t-\\n\\t\\t('about this method'\\t\\taboutMethod:)) do:\\n\\n\\t\\t\\t[:pair |\\n\\t\\t\\t\\tpair = '-'\\n\\t\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t\\t[aMenu addLine]\\n\\t\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t\\t[aMenu add: pair first target: aViewer selector: pair second argument: anElement]].\\n\\taMenu addLine.\\n\\taMenu defaultTarget: self.\\n\\t#(\\t('destroy script'\\t\\tremoveScript:)\\n\\t\\t('rename script'\\t\\trenameScript:)\\n\\t\\t('pacify script'\\t\\tpacifyScript:)) do:\\n\\t\\t\\t[:pair |\\n\\t\\t\\t\\taMenu add: pair first target: self selector: pair second argument: anElement].\\n\\n\\taMenu addLine.\\n\\taMenu add: 'show categories....' target: aViewer selector: #showCategoriesFor: argument: anElement.\\n\\taMenu items size == 0 ifTrue: \\\"won't happen at the moment a/c the above\\\"\\n\\t\\t[aMenu add: 'ok' action: nil]. \\\"in case it was a slot -- weird, transitional\\\"\\n\\n\\taMenu addTitle: anElement asString, ' (', elementType, ')'.\\n\\n\\taMenu popUpInWorld: self currentWorld.\\n ! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 9/26/2001 11:58'!\\ninitialTypeForSlotNamed: aName\\n\\t\\\"Answer the initial type to be ascribed to the given instance variable\\\"\\n\\n\\t^ #Object! !\\n\\n!Object methodsFor: 'viewer' stamp: 'ar 5/26/2001 16:13'!\\nisPlayerLike\\n\\t\\\"Return true if the receiver is a player-like object\\\"\\n\\t^false! !\\n\\n!Object methodsFor: 'viewer' stamp: 'nk 9/11/2004 16:53'!\\nmethodInterfacesInPresentationOrderFrom: interfaceList forCategory: aCategory \\n\\t\\\"Answer the interface list sorted in desired presentation order, using a \\n\\tstatic master-ordering list, q.v. The category parameter allows an \\n\\tescape in case one wants to apply different order strategies in different \\n\\tcategories, but for now a single master-priority-ordering is used -- see \\n\\tthe comment in method EToyVocabulary.masterOrderingOfPhraseSymbols\\\"\\n\\n\\t| masterOrder ordered unordered index |\\n\\tmasterOrder := Vocabulary eToyVocabulary masterOrderingOfPhraseSymbols.\\n\\tordered := SortedCollection sortBlock: [:a :b | a key < b key].\\n\\tunordered := SortedCollection sortBlock: [:a :b | a wording < b wording].\\n\\n\\tinterfaceList do: [:interface | \\n\\t\\tindex := masterOrder indexOf: interface elementSymbol.\\n\\t\\tindex isZero\\n\\t\\t\\tifTrue: [unordered add: interface]\\n\\t\\t\\tifFalse: [ordered add: index -> interface]].\\n\\n\\t^ Array\\n\\t\\tstreamContents: [:stream | \\n\\t\\t\\tordered do: [:assoc | stream nextPut: assoc value].\\n\\t\\t\\tstream nextPutAll: unordered]! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 10/24/2000 11:36'!\\nnewScriptorAround: aPhraseTileMorph\\n\\t\\\"Sprout a scriptor around aPhraseTileMorph, thus making a new script. This is where generalized scriptors will be threaded in\\\"\\n\\n\\t^ nil! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 10/25/2000 17:42'!\\nofferViewerMenuForEvt: anEvent morph: aMorph\\n\\t\\\"Offer the viewer's primary menu to the user. aMorph is some morph within the viewer itself, the one within which a mousedown triggered the need for this menu, and it is used only to retrieve the Viewer itself\\\"\\n\\n\\tself offerViewerMenuFor: (aMorph ownerThatIsA: StandardViewer) event: anEvent! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 8/11/2002 02:03'!\\nofferViewerMenuFor: aViewer event: evt\\n\\t\\\"Offer the primary Viewer menu to the user. Copied up from Player code, but most of the functions suggested here don't work for non-Player objects, many aren't even defined, some relate to exploratory sw work not yet reflected in the current corpus. We are early in the life cycle of this method...\\\"\\n\\n\\t| aMenu |\\n\\taMenu _ MenuMorph new defaultTarget: self.\\n\\taMenu addStayUpItem.\\n\\taMenu title: '**CAUTION -- UNDER CONSTRUCTION!!**\\nMany things may not work!!\\n', self nameForViewer.\\n\\t(aViewer affordsUniclass and: [self belongsToUniClass not]) ifTrue:\\n\\t\\t[aMenu add: 'give me a Uniclass' action: #assureUniClass.\\n\\t\\taMenu addLine].\\n\\taMenu add: 'choose vocabulary...' target: aViewer action: #chooseVocabulary.\\n\\taMenu add: 'choose limit class...' target: aViewer action: #chooseLimitClass.\\n\\taMenu add: 'add search pane' target: aViewer action: #addSearchPane.\\n\\taMenu balloonTextForLastItem: 'Specify which class should be the most generic one to have its methods shown in this Viewer'.\\n\\taMenu addLine.\\n\\n\\tself belongsToUniClass ifTrue:\\n\\t\\t[aMenu add: 'add a new instance variable' target: self selector: #addInstanceVariableIn: argument: aViewer.\\n\\t\\taMenu add: 'add a new script' target: aViewer selector: #newPermanentScriptIn: argument: aViewer.\\n\\t\\taMenu addLine.\\n\\t\\taMenu add: 'make my class be first-class' target: self selector: #makeFirstClassClassIn: argument: aViewer.\\n\\t\\taMenu add: 'move my changes up to my superclass' target: self action: #promoteChangesToSuperclass.\\n\\t\\taMenu addLine].\\n\\n\\taMenu add: 'tear off a tile' target: self selector: #launchTileToRefer.\\n\\taMenu addLine.\\n\\n\\taMenu add: 'inspect me' target: self selector: #inspect.\\n\\taMenu add: 'inspect my class' target: self class action: #inspect.\\n\\taMenu addLine.\\n\\n\\taMenu add: 'browse vocabulary' action: #haveFullProtocolBrowsed.\\n\\taMenu add: 'inspect this Viewer' target: aViewer action: #inspect.\\n\\n\\taMenu popUpEvent: evt in: aViewer currentWorld\\n\\n\\\"\\n\\taMenu add: 'references to me' target: aViewer action: #browseReferencesToObject.\\n\\taMenu add: 'toggle scratch pane' target: aViewer selector: #toggleScratchPane.\\n\\taMenu add: 'make a nascent script for me' target: aViewer selector: #makeNascentScript.\\n\\taMenu add: 'rename me' target: aViewer selector: #chooseNewNameForReference.\\n\\taMenu add: 'browse full' action: #browseOwnClassFull.\\n\\taMenu add: 'browse hierarchy' action: #browseOwnClassHierarchy.\\n\\taMenu add: 'set user level...' target: aViewer action: #setUserLevel.\\n\\taMenu add: 'browse sub-protocol' action: #browseOwnClassSubProtocol.\\n\\taMenu addLine.\\n\\n\\\"! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 1/22/2001 15:20'!\\nrenameScript: oldSelector\\n\\t\\\"prompt the user for a new selector and apply it. Presently only works for players\\\"\\n\\n\\tself notYetImplemented! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 8/10/2004 11:53'!\\ntilePhrasesForCategory: aCategorySymbol inViewer: aViewer\\n\\t\\\"Return a collection of phrases for the category.\\\"\\n\\n\\t| interfaces |\\n\\tinterfaces _ self methodInterfacesForCategory: aCategorySymbol inVocabulary: aViewer currentVocabulary limitClass: aViewer limitClass.\\n\\tinterfaces _ self methodInterfacesInPresentationOrderFrom: interfaces forCategory: aCategorySymbol.\\n\\t^ self tilePhrasesForMethodInterfaces: interfaces inViewer: aViewer! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 8/10/2004 11:53'!\\ntilePhrasesForMethodInterfaces: methodInterfaceList inViewer: aViewer\\n\\t\\\"Return a collection of ViewerLine objects corresponding to the method-interface list provided. The resulting list will be in the same order as the incoming list, but may be smaller if the viewer's vocbulary suppresses some of the methods, or if, in classic tiles mode, the selector requires more arguments than can be handled.\\\"\\n\\n\\t| toSuppress interfaces resultType itsSelector |\\n\\ttoSuppress _ aViewer currentVocabulary phraseSymbolsToSuppress.\\n\\tinterfaces _ methodInterfaceList reject: [:int | toSuppress includes: int selector].\\n\\tPreferences universalTiles ifFalse: \\\"Classic tiles have their limitations...\\\"\\n\\t\\t[interfaces _ interfaces select:\\n\\t\\t\\t[:int |\\n\\t\\t\\t\\titsSelector _ int selector.\\n\\t\\t\\t\\titsSelector numArgs < 2 or:\\n\\t\\t\\t\\t\\t\\\"The lone two-arg loophole in classic tiles\\\"\\n\\t\\t\\t\\t\\t[#(color:sees:) includes: itsSelector]]].\\n\\n\\t^ interfaces collect:\\n\\t\\t[:aMethodInterface |\\n\\t\\t\\t((resultType _ aMethodInterface resultType) notNil and: [resultType ~~ #unknown]) \\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[aViewer phraseForVariableFrom: aMethodInterface]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[aViewer phraseForCommandFrom: aMethodInterface]]! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 8/10/2004 12:23'!\\ntilePhrasesForSelectorList: aList inViewer: aViewer\\n\\t\\\"Particular to the search facility in viewers. Answer a list, in appropriate order, of ViewerLine objects to put into the viewer.\\\"\\n\\n\\t| interfaces aVocab |\\n\\taVocab _ aViewer currentVocabulary.\\n\\tinterfaces _ self\\n\\t\\tmethodInterfacesInPresentationOrderFrom:\\n\\t\\t\\t(aList collect: [:aSel | aVocab methodInterfaceForSelector: aSel class: self class])\\n\\t\\tforCategory: #search.\\n\\t^ self tilePhrasesForMethodInterfaces: interfaces inViewer: aViewer! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 5/4/2001 04:51'!\\ntileToRefer\\n\\t\\\"Answer a reference tile that comprises an alias to me\\\"\\n\\n\\t^ TileMorph new setToReferTo: self! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sd 3/30/2005 22:04'!\\nuniqueInstanceVariableNameLike: aString excluding: takenNames\\n\\t\\\"Answer a nice instance-variable name to be added to the receiver which resembles aString, making sure it does not coincide with any element in takenNames\\\"\\n\\n\\t| okBase uniqueName usedNames |\\n\\tusedNames _ self class allInstVarNamesEverywhere.\\n\\tusedNames removeAllFoundIn: self class instVarNames.\\n\\tusedNames addAll: takenNames.\\n\\tokBase _ Scanner wellFormedInstanceVariableNameFrom: aString.\\n\\n\\tuniqueName _ Utilities keyLike: okBase satisfying: \\n\\t\\t[:aKey | (usedNames includes: aKey) not].\\n\\n\\t^ uniqueName! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 11/21/2001 15:16'!\\nuniqueNameForReference\\n\\t\\\"Answer a nice name by which the receiver can be referred to by other objects. At present this uses a global References dictionary to hold the database of references, but in due course this will need to acquire some locality\\\"\\n\\n\\t| aName nameSym stem knownClassVars |\\n\\t(aName _ self uniqueNameForReferenceOrNil) ifNotNil: [^ aName].\\n\\t(stem _ self knownName) ifNil:\\n\\t\\t[stem _ self defaultNameStemForInstances asString].\\n\\tstem _ stem select: [:ch | ch isLetter or: [ch isDigit]].\\n\\tstem size == 0 ifTrue: [stem _ 'A'].\\n\\tstem first isLetter ifFalse:\\n\\t\\t[stem _ 'A', stem].\\n\\tstem _ stem capitalized.\\n\\tknownClassVars _ ScriptingSystem allKnownClassVariableNames.\\n\\taName _ Utilities keyLike: stem satisfying:\\n\\t\\t[:jinaLake |\\n\\t\\t\\tnameSym _ jinaLake asSymbol.\\n\\t\\t\\t ((References includesKey: nameSym) not and:\\n\\t\\t\\t\\t[(Smalltalk includesKey: nameSym) not]) and:\\n\\t\\t\\t\\t\\t\\t[(knownClassVars includes: nameSym) not]].\\n\\n\\tReferences at: (aName _ aName asSymbol) put: self.\\n\\t^ aName! !\\n\\n!Object methodsFor: 'viewer' stamp: 'md 1/17/2006 17:58'!\\nuniqueNameForReferenceFrom: proposedName\\n\\t\\\"Answer a satisfactory symbol, similar to the proposedName but obeying the rules, to represent the receiver\\\"\\n\\n\\t| aName nameSym stem okay |\\n\\tproposedName = self uniqueNameForReferenceOrNil \\n\\t\\tifTrue: [^ proposedName]. \\\"No change\\\"\\n\\n\\tstem _ proposedName select: [:ch | ch isLetter or: [ch isDigit]].\\n\\tstem size == 0 ifTrue: [stem _ 'A'].\\n\\tstem first isLetter ifFalse:\\n\\t\\t[stem _ 'A', stem].\\n\\tstem _ stem capitalized.\\n\\taName _ Utilities keyLike: stem satisfying:\\n\\t\\t[:jinaLake |\\n\\t\\t\\tnameSym _ jinaLake asSymbol.\\n\\t\\t\\tokay _ true.\\n\\t\\t\\t(self class bindingOf: nameSym) ifNotNil: [okay _ false \\\"don't use it\\\"].\\n\\t\\t\\tokay].\\n\\t^ aName asSymbol! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 3/15/2004 23:01'!\\nuniqueNameForReferenceOrNil\\n\\t\\\"If the receiver has a unique name for reference, return it here, else return nil\\\"\\n\\n\\t^ References keyAtValue: self ifAbsent: [nil]! !\\n\\n!Object methodsFor: 'viewer' stamp: 'ar 5/16/2001 01:40'!\\nupdateThresholdForGraphicInViewerTab\\n\\t\\\"When a Viewer is open on the receiver, its tab needs some graphic to show to the user. Computing this graphic can take quite some time so we want to make the update frequency depending on how long it takes to compute the thumbnail. The threshold returned by this method defines that the viewer will update at most every 'threshold * timeItTakesToDraw' milliseconds. Thus, if the time for computing the receiver's thumbnail is 200 msecs and the the threshold is 10, the viewer will update at most every two seconds.\\\"\\n\\t^20 \\\"seems to be a pretty good general choice\\\"! !\\n\\n!Object methodsFor: 'viewer' stamp: 'sw 3/9/2001 13:48'!\\nusableMethodInterfacesIn: aListOfMethodInterfaces\\n\\t\\\"Filter aList, returning a subset list of apt phrases\\\"\\n\\n\\t^ aListOfMethodInterfaces\\n! !\\n\\n\\n!Object methodsFor: 'inspecting' stamp: 'ar 9/27/2005 18:31'!\\nbasicInspect\\n\\t\\\"Create and schedule an Inspector in which the user can examine the \\n\\treceiver's variables. This method should not be overriden.\\\"\\n\\t^ToolSet basicInspect: self! !\\n\\n!Object methodsFor: 'inspecting' stamp: 'md 1/18/2006 19:09'!\\ninspect\\n\\t\\\"Create and schedule an Inspector in which the user can examine the receiver's variables.\\\"\\n\\tToolSet inspect: self! !\\n\\n!Object methodsFor: 'inspecting' stamp: 'apb 7/14/2004 12:19'!\\ninspectorClass\\n\\t\\\"Answer the class of the inspector to be used on the receiver. Called by inspect; \\n\\tuse basicInspect to get a normal (less useful) type of inspector.\\\"\\n\\n\\t^ Inspector! !\\n\\n\\n!Object methodsFor: 'thumbnail' stamp: 'dgd 9/25/2004 23:17'!\\niconOrThumbnailOfSize: aNumberOrPoint \\n\\t\\\"Answer an appropiate form to represent the receiver\\\"\\n\\t^ nil! !\\n\\n\\n!Object methodsFor: 'scripts-kernel' stamp: 'nk 10/14/2004 10:55'!\\nuniversalTilesForGetterOf: aMethodInterface\\n\\t\\\"Return universal tiles for a getter on the given method interface.\\\"\\n\\n\\t| ms argTile argArray itsSelector |\\n\\titsSelector _ aMethodInterface selector.\\n\\targArray _ #().\\n\\n\\t\\\"Four gratuituous special cases...\\\"\\n\\n\\t(itsSelector == #color:sees:) ifTrue:\\n\\t\\t[argTile _ ScriptingSystem tileForArgType: #Color.\\n\\t\\targArray _ Array with: argTile colorSwatch color with: argTile colorSwatch color copy].\\n\\n\\titsSelector == #seesColor: ifTrue:\\n\\t\\t[argTile _ ScriptingSystem tileForArgType: #Color.\\n\\t\\targArray _ Array with: argTile colorSwatch color].\\n\\n\\t(#(touchesA: overlaps: overlapsAny:) includes: itsSelector) ifTrue:\\n\\t\\t[argTile _ ScriptingSystem tileForArgType: #Player.\\n\\t\\targArray _ Array with: argTile actualObject].\\n\\n\\tms _ MessageSend receiver: self selector: itsSelector arguments: argArray.\\n\\t^ ms asTilesIn: self class globalNames: (self class officialClass ~~ CardPlayer)\\n\\t\\t\\t\\\"For CardPlayers, use 'self'. For others, name it, and use its name.\\\"! !\\n\\n!Object methodsFor: 'scripts-kernel' stamp: 'tk 9/28/2001 13:30'!\\nuniversalTilesForInterface: aMethodInterface\\n\\t\\\"Return universal tiles for the given method interface. Record who self is.\\\"\\n\\n\\t| ms argTile itsSelector aType argList |\\n\\titsSelector _ aMethodInterface selector.\\n\\targList _ OrderedCollection new.\\n\\taMethodInterface argumentVariables doWithIndex:\\n\\t\\t[:anArgumentVariable :anIndex | \\n\\t\\t\\targTile _ ScriptingSystem tileForArgType: (aType _ aMethodInterface typeForArgumentNumber: anIndex).\\n\\t\\t\\targList add: (aType == #Player \\n\\t\\t\\t\\tifTrue: [argTile actualObject]\\n\\t\\t\\t\\tifFalse: [argTile literal]).\\t\\\"default value for each type\\\"].\\n\\n\\tms _ MessageSend receiver: self selector: itsSelector arguments: argList asArray.\\n\\t^ ms asTilesIn: self class globalNames: (self class officialClass ~~ CardPlayer)\\n\\t\\t\\t\\\"For CardPlayers, use 'self'. For others, name it, and use its name.\\\"! !\\n\\n\\n!Object methodsFor: 'breakpoint' stamp: 'bkv 7/1/2003 12:33'!\\nbreak\\n\\t\\\"This is a simple message to use for inserting breakpoints during debugging.\\n\\tThe debugger is opened by sending a signal. This gives a chance to restore\\n\\tinvariants related to multiple processes.\\\"\\n\\n\\tBreakPoint signal.\\n\\n\\t\\\"nil break.\\\"! !\\n\\n\\n\\n!Object methodsFor: '*omnibrowser-converting' stamp: 'cwp 4/17/2006 12:16'!\\nasAnnouncement\\n\\t^ self! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nObject class\\n\\tinstanceVariableNames: ''!\\n\\n!Object class methodsFor: 'class initialization' stamp: 'ar 2/11/2001 02:00'!\\nflushDependents\\n\\tDependentsFields keysAndValuesDo:[:key :dep|\\n\\t\\tkey ifNotNil:[key removeDependent: nil].\\n\\t].\\n\\tDependentsFields finalizeValues.! !\\n\\n!Object class methodsFor: 'class initialization' stamp: 'rw 2/10/2002 13:09'!\\nflushEvents\\n\\t\\\"Object flushEvents\\\"\\n\\n\\tEventManager flushEvents. ! !\\n\\n!Object class methodsFor: 'class initialization' stamp: 'rww 10/2/2001 07:35'!\\ninitialize\\n\\t\\\"Object initialize\\\"\\n\\tDependentsFields ifNil:[self initializeDependentsFields].! !\\n\\n!Object class methodsFor: 'class initialization' stamp: 'ar 2/11/2001 01:41'!\\ninitializeDependentsFields\\n\\t\\\"Object initialize\\\"\\n\\tDependentsFields _ WeakIdentityKeyDictionary new.\\n! !\\n\\n!Object class methodsFor: 'class initialization' stamp: 'ar 2/11/2001 01:45'!\\nreInitializeDependentsFields\\n\\t\\\"Object reInitializeDependentsFields\\\"\\n\\t| oldFields |\\n\\toldFields _ DependentsFields.\\n\\tDependentsFields _ WeakIdentityKeyDictionary new.\\n\\toldFields keysAndValuesDo:[:obj :deps|\\n\\t\\tdeps do:[:d| obj addDependent: d]].\\n! !\\n\\n\\n!Object class methodsFor: 'documentation'!\\nhowToModifyPrimitives\\n\\t\\\"You are allowed to write methods which specify primitives, but please use \\n\\tcaution. If you make a subclass of a class which contains a primitive method, \\n\\tthe subclass inherits the primitive. The message which is implemented \\n\\tprimitively may be overridden in the subclass (E.g., see at:put: in String's \\n\\tsubclass Symbol). The primitive behavior can be invoked using super (see \\n\\tSymbol string:). \\n\\t \\n\\tA class which attempts to mimic the behavior of another class without being \\n\\tits subclass may or may not be able to use the primitives of the original class. \\n\\tIn general, if the instance variables read or written by a primitive have the \\n\\tsame meanings and are in the same fields in both classes, the primitive will \\n\\twork. \\n\\n\\tFor certain frequently used 'special selectors', the compiler emits a \\n\\tsend-special-selector bytecode instead of a send-message bytecode. \\n\\tSpecial selectors were created because they offer two advantages. Code \\n\\twhich sends special selectors compiles into fewer bytes than normal. For \\n\\tsome pairs of receiver classes and special selectors, the interpreter jumps \\n\\tdirectly to a primitive routine without looking up the method in the class. \\n\\tThis is much faster than a normal message lookup. \\n\\t \\n\\tA selector which is a special selector solely in order to save space has a \\n\\tnormal behavior. Methods whose selectors are special in order to \\n\\tgain speed contain the comment, 'No Lookup'. When the interpreter \\n\\tencounters a send-special-selector bytecode, it checks the class of the \\n\\treceiver and the selector. If the class-selector pair is a no-lookup pair, \\n\\tthen the interpreter swiftly jumps to the routine which implements the \\n\\tcorresponding primitive. (A special selector whose receiver is not of the \\n\\tright class to make a no-lookup pair, is looked up normally). The pairs are \\n\\tlisted below. No-lookup methods contain a primitive number specification, \\n\\t<primitive: xx>, which is redundant. Since the method is not normally looked \\n\\tup, deleting the primitive number specification cannot prevent this \\n\\tprimitive from running. If a no-lookup primitive fails, the method is looked \\n\\tup normally, and the expressions in it are executed. \\n\\t \\n\\tNo Lookup pairs of (class, selector) \\n\\t \\n\\tSmallInteger with any of\\t\\t+ - * / \\\\\\\\ bitOr: bitShift: bitAnd: // \\n\\tSmallInteger with any of\\t\\t= ~= > < >= <= \\n\\tAny class with\\t\\t\\t\\t\\t== \\n\\tAny class with \\t\\t\\t\\t\\t@ \\n\\tPoint with either of\\t\\t\\t\\tx y \\n\\tContextPart with\\t\\t\\t\\t\\tblockCopy: \\n\\tBlockContext with either of \\t\\tvalue value:\\n\\t\\\"\\n\\n\\tself error: 'comment only'! !\\n\\n!Object class methodsFor: 'documentation'!\\nwhatIsAPrimitive\\n\\t\\\"Some messages in the system are responded to primitively. A primitive \\n\\tresponse is performed directly by the interpreter rather than by evaluating \\n\\texpressions in a method. The methods for these messages indicate the \\n\\tpresence of a primitive response by including <primitive: xx> before the \\n\\tfirst expression in the method. \\n\\t \\n\\tPrimitives exist for several reasons. Certain basic or 'primitive' \\n\\toperations cannot be performed in any other way. Smalltalk without \\n\\tprimitives can move values from one variable to another, but cannot add two \\n\\tSmallIntegers together. Many methods for arithmetic and comparison \\n\\tbetween numbers are primitives. Some primitives allow Smalltalk to \\n\\tcommunicate with I/O devices such as the disk, the display, and the keyboard. \\n\\tSome primitives exist only to make the system run faster; each does the same \\n\\tthing as a certain Smalltalk method, and its implementation as a primitive is \\n\\toptional. \\n\\t \\n\\tWhen the Smalltalk interpreter begins to execute a method which specifies a \\n\\tprimitive response, it tries to perform the primitive action and to return a \\n\\tresult. If the routine in the interpreter for this primitive is successful, \\n\\tit will return a value and the expressions in the method will not be evaluated. \\n\\tIf the primitive routine is not successful, the primitive 'fails', and the \\n\\tSmalltalk expressions in the method are executed instead. These \\n\\texpressions are evaluated as though the primitive routine had not been \\n\\tcalled. \\n\\t \\n\\tThe Smalltalk code that is evaluated when a primitive fails usually \\n\\tanticipates why that primitive might fail. If the primitive is optional, the \\n\\texpressions in the method do exactly what the primitive would have done (See \\n\\tNumber @). If the primitive only works on certain classes of arguments, the \\n\\tSmalltalk code tries to coerce the argument or appeals to a superclass to find \\n\\ta more general way of doing the operation (see SmallInteger +). If the \\n\\tprimitive is never supposed to fail, the expressions signal an error (see \\n\\tSmallInteger asFloat). \\n\\t \\n\\tEach method that specifies a primitive has a comment in it. If the primitive is \\n\\toptional, the comment will say 'Optional'. An optional primitive that is not \\n\\timplemented always fails, and the Smalltalk expressions do the work \\n\\tinstead. \\n\\t \\n\\tIf a primitive is not optional, the comment will say, 'Essential'. Some \\n\\tmethods will have the comment, 'No Lookup'. See Object \\n\\thowToModifyPrimitives for an explanation of special selectors which are \\n\\tnot looked up. \\n\\t \\n\\tFor the primitives for +, -, *, and bitShift: in SmallInteger, and truncated \\n\\tin Float, the primitive constructs and returns a 16-bit \\n\\tLargePositiveInteger when the result warrants it. Returning 16-bit \\n\\tLargePositiveIntegers from these primitives instead of failing is \\n\\toptional in the same sense that the LargePositiveInteger arithmetic \\n\\tprimitives are optional. The comments in the SmallInteger primitives say, \\n\\t'Fails if result is not a SmallInteger', even though the implementor has the \\n\\toption to construct a LargePositiveInteger. For further information on \\n\\tprimitives, see the 'Primitive Methods' part of the chapter on the formal \\n\\tspecification of the interpreter in the Smalltalk book.\\\"\\n\\n\\tself error: 'comment only'! !\\n\\n\\n!Object class methodsFor: 'file list services' stamp: 'nk 6/12/2004 11:41'!\\nfileReaderServicesForDirectory: aFileDirectory\\n\\t\\\"Backstop\\\"\\n\\t^#()! !\\n\\n!Object class methodsFor: 'file list services' stamp: 'nk 6/12/2004 11:30'!\\nfileReaderServicesForFile: fullName suffix: suffix\\n\\t\\\"Backstop\\\"\\n\\t^#()! !\\n\\n!Object class methodsFor: 'file list services' stamp: 'md 2/15/2006 17:20'!\\nservices\\n\\t\\\"Backstop\\\"\\n\\t^#()! !\\n\\n\\n!Object class methodsFor: 'instance creation' stamp: 'sw 1/23/2003 09:45'!\\ncategoryForUniclasses\\n\\n\\t\\\"Answer the default system category into which to place unique-class instances\\\"\\n\\n\\n\\n\\t^ 'UserObjects'! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'sw 7/28/97 15:56'!\\nchooseUniqueClassName\\n\\t| i className |\\n\\ti _ 1.\\n\\t[className _ (self name , i printString) asSymbol.\\n\\t Smalltalk includesKey: className]\\n\\t\\twhileTrue: [i _ i + 1].\\n\\t^ className! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'tk 8/22/1998 08:22'!\\ninitialInstance\\n\\t\\\"Answer the first instance of the receiver, generate an error if there is one already\\\"\\n\\t\\\"self instanceCount > 0 ifTrue: [self error: 'instance(s) already exist.'].\\\"\\n\\t\\t\\\"Debugging test that is very slow\\\"\\n\\t^ self new! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'sw 5/5/2000 09:30'!\\ninitializedInstance\\n\\t^ self new! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'sw 10/16/2000 10:58'!\\ninstanceOfUniqueClass\\n\\t\\\"Answer an instance of a unique subclass of the receiver\\\"\\n\\n\\t^ self instanceOfUniqueClassWithInstVarString: '' andClassInstVarString: ''! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'tk 8/22/1998 08:27'!\\ninstanceOfUniqueClassWithInstVarString: instVarString andClassInstVarString: classInstVarString\\n\\t\\\"Create a unique class for the receiver, and answer an instance of it\\\"\\n\\n\\t^ (self newUniqueClassInstVars: instVarString \\n\\t\\tclassInstVars: classInstVarString) initialInstance! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'sw 10/23/1999 22:51'!\\nisUniClass\\n\\t^ false! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'ajh 5/23/2002 00:35'!\\nnewFrom: aSimilarObject\\n\\t\\\"Create an object that has similar contents to aSimilarObject.\\n\\tIf the classes have any instance varaibles with the same names, copy them across.\\n\\tIf this is bad for a class, override this method.\\\"\\n\\n\\t^ (self isVariable\\n\\t\\tifTrue: [self basicNew: aSimilarObject basicSize]\\n\\t\\tifFalse: [self basicNew]\\n\\t ) copySameFrom: aSimilarObject! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'tk 6/29/1998 12:11'!\\nnewUniqueClassInstVars: instVarString classInstVars: classInstVarString\\n\\t\\\"Create a unique class for the receiver\\\"\\n\\n\\t| aName aClass |\\n\\tself isSystemDefined ifFalse:\\n\\t\\t[^ superclass newUniqueClassInstVars: instVarString classInstVars: classInstVarString].\\n\\taName _ self chooseUniqueClassName.\\n\\taClass _ self subclass: aName instanceVariableNames: instVarString \\n\\t\\tclassVariableNames: '' poolDictionaries: '' category: self categoryForUniclasses.\\n\\tclassInstVarString size > 0 ifTrue:\\n\\t\\t[aClass class instanceVariableNames: classInstVarString].\\n\\t^ aClass! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'sw 7/28/97 15:56'!\\nnewUserInstance\\n\\t\\\"Answer an instance of an appropriate class to serve as a user object in the containment hierarchy\\\"\\n\\n\\t^ self instanceOfUniqueClass! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'nk 8/30/2004 07:57'!\\nreadCarefullyFrom: textStringOrStream\\n\\t\\\"Create an object based on the contents of textStringOrStream. Return an error instead of putting up a SyntaxError window.\\\"\\n\\n\\t| object |\\n\\t(Compiler couldEvaluate: textStringOrStream)\\n\\t\\tifFalse: [^ self error: 'expected String, Stream, or Text'].\\n\\tobject _ Compiler evaluate: textStringOrStream for: nil \\n\\t\\t\\t\\tnotifying: #error: \\\"signal we want errors\\\" logged: false.\\n\\t(object isKindOf: self) ifFalse: [self error: self name, ' expected'].\\n\\t^object! !\\n\\n!Object class methodsFor: 'instance creation' stamp: 'nk 8/30/2004 07:57'!\\nreadFrom: textStringOrStream\\n\\t\\\"Create an object based on the contents of textStringOrStream.\\\"\\n\\n\\t| object |\\n\\t(Compiler couldEvaluate: textStringOrStream)\\n\\t\\tifFalse: [^ self error: 'expected String, Stream, or Text'].\\n\\tobject _ Compiler evaluate: textStringOrStream.\\n\\t(object isKindOf: self) ifFalse: [self error: self name, ' expected'].\\n\\t^object! !\\n\\n\\n!Object class methodsFor: 'objects from disk' stamp: 'tk 1/8/97'!\\ncreateFrom: aSmartRefStream size: varsOnDisk version: instVarList\\n\\t\\\"Create an instance of me so objects on the disk can be read in. Tricky part is computing the size if variable. Inst vars will be filled in later. \\\"\\n\\n\\t^ self isVariable\\n\\t\\tifFalse: [self basicNew]\\n\\t\\tifTrue: [\\\"instVarList is names of old class's inst vars plus a version number\\\" \\n\\t\\t\\t\\tself basicNew: (varsOnDisk - (instVarList size - 1))]\\n! !\\n\\n\\n!Object class methodsFor: 'window color' stamp: 'nk 6/10/2004 08:10'!\\nwindowColorSpecification\\n\\t\\\"Answer a WindowColorSpec object that declares my preference.\\n\\tThis is a backstop for classes that don't otherwise define a preference.\\\"\\n\\n\\t^ WindowColorSpec classSymbol: self name\\n\\t\\twording: 'Default' brightColor: #white\\n\\t\\tpastelColor: #white\\n\\t\\thelpMessage: 'Other windows without color preferences.'! !\\n\\n\\n!Object class methodsFor: 'private' stamp: 'mir 8/22/2001 15:20'!\\nreleaseExternalSettings\\n\\t\\\"Do nothing as a default\\\"! !\\nAbstractHierarchicalList subclass: #ObjectExplorer\\n\\tinstanceVariableNames: 'rootObject inspector monitorList'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tools-Explorer'!\\n!ObjectExplorer commentStamp: '<historical>' prior: 0!\\nObjectExplorer provides a hierarchical alternative to #inspect. Simply evaluate an expression like:\\n\\nWorld explore\\n\\nand enjoy.!\\n]style[(101 13 12)f1,f3cblue;,f1!\\n\\n\\n!ObjectExplorer methodsFor: 'accessing' stamp: 'RAA 9/23/1999 13:11'!\\ncontentsSelection\\n\\t\\\"Return the interval of text in the code pane to select when I set the pane's contents\\\"\\n\\n\\t^ 1 to: 0 \\\"null selection\\\"! !\\n\\n!ObjectExplorer methodsFor: 'accessing' stamp: 'RAA 9/23/1999 13:15'!\\ndoItContext\\n\\t\\\"Answer the context in which a text selection can be evaluated.\\\"\\n\\n\\t^nil! !\\n\\n!ObjectExplorer methodsFor: 'accessing' stamp: 'RAA 9/23/1999 13:19'!\\ndoItReceiver\\n\\t\\\"Answer the object that should be informed of the result of evaluating a\\n\\ttext selection.\\\"\\n\\n\\tcurrentSelection ifNil: [^rootObject].\\n\\t^currentSelection withoutListWrapper\\n! !\\n\\n!ObjectExplorer methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:27'!\\nexplorerFor: anObject\\n\\t| window listMorph |\\n\\trootObject := anObject.\\n\\twindow := (SystemWindow labelled: self label) model: self.\\n\\twindow addMorph: (listMorph := SimpleHierarchicalListMorph \\n\\t\\t\\ton: self\\n\\t\\t\\tlist: #getList\\n\\t\\t\\tselected: #getCurrentSelection\\n\\t\\t\\tchangeSelected: #noteNewSelection:\\n\\t\\t\\tmenu: #genericMenu:\\n\\t\\t\\tkeystroke: #explorerKey:from:)\\n\\t\\tframe: (0@0 corner: 1@0.8).\\n\\twindow addMorph: ((PluggableTextMorph on: self text: #trash accept: #trash:\\n\\t\\t\\t\\treadSelection: #contentsSelection menu: #codePaneMenu:shifted:)\\n\\t\\t\\t\\t\\taskBeforeDiscardingEdits: false)\\n\\t\\tframe: (0@0.8 corner: 1@1).\\n\\tlistMorph\\n\\t\\tautoDeselect: false.\\n ^ window! !\\n\\n!ObjectExplorer methodsFor: 'accessing' stamp: 'nk 7/24/2003 09:16'!\\ngetList\\n\\n\\t^Array with: (ObjectExplorerWrapper with: rootObject name: 'root' model: self parent: nil)\\n! !\\n\\n!ObjectExplorer methodsFor: 'accessing' stamp: 'hg 9/7/2001 12:12'!\\nlabel\\n\\n\\t^ rootObject printStringLimitedTo: 32! !\\n\\n!ObjectExplorer methodsFor: 'accessing' stamp: 'nk 7/24/2003 09:43'!\\nobject\\n\\t^currentSelection ifNotNilDo: [ :cs | cs withoutListWrapper ]! !\\n\\n!ObjectExplorer methodsFor: 'accessing' stamp: 'nk 7/24/2003 10:02'!\\nparentObject\\n\\tcurrentSelection ifNil: [ ^nil ].\\n\\tcurrentSelection parent ifNil: [ ^rootObject ].\\n\\t^currentSelection parent withoutListWrapper! !\\n\\n!ObjectExplorer methodsFor: 'accessing' stamp: 'nk 7/24/2003 09:47'!\\nselector\\n\\t^currentSelection ifNotNilDo: [ :cs | cs selector ]! !\\n\\n\\n!ObjectExplorer methodsFor: 'error handling' stamp: 'nk 7/24/2003 09:29'!\\ndoesNotUnderstand: aMessage\\n\\tinspector ifNotNil: [ (inspector respondsTo: aMessage selector) ifTrue: [ ^inspector perform: aMessage selector withArguments: aMessage arguments ]].\\n\\t^super doesNotUnderstand: aMessage! !\\n\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'sd 11/20/2005 21:27'!\\nchasePointers\\n\\t\\\"Open a PointerFinder on the selected item\\\"\\n\\t| path sel savedRoot saved |\\n\\tpath := OrderedCollection new.\\n\\tsel := currentSelection.\\n\\t[ sel isNil ] whileFalse: [ path addFirst: sel asString. sel := sel parent ].\\n\\tpath addFirst: #openPath.\\n\\tpath := path asArray.\\n\\tsavedRoot := rootObject.\\n\\tsaved := self object.\\n\\t[ rootObject := nil.\\n\\tself changed: #getList.\\n\\t(Smalltalk includesKey: #PointerFinder)\\n\\t\\tifTrue: [PointerFinder on: saved]\\n\\t\\tifFalse: [self objectReferencesToSelection ]]\\n\\t\\tensure: [ rootObject := savedRoot.\\n\\t\\t\\tself changed: #getList.\\n\\t\\t\\tself changed: path.\\n\\t\\t]! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'RAA 9/23/1999 13:22'!\\ncodePaneMenu: aMenu shifted: shifted\\n\\t\\\"Note that unless we override perform:orSendTo:, PluggableTextController will respond to all menu items\\\"\\n\\t^ StringHolder basicNew codePaneMenu: aMenu shifted: shifted\\n! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'sd 11/20/2005 21:27'!\\ndefsOfSelection\\n\\t\\\"Open a browser on all defining references to the selected instance variable, if that's what's currently selected.\\\"\\n\\t| aClass sel |\\n\\n\\t(aClass := self parentObject class) isVariable ifTrue: [^ self changed: #flash].\\n\\tsel := self selector.\\n\\tself systemNavigation browseAllStoresInto: sel from: aClass! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'sd 11/20/2005 21:27'!\\nexplorerKey: aChar from: view\\n\\n\\t\\\"Similar to #genericMenu:...\\\"\\n\\t| insideObject parentObject |\\n\\tcurrentSelection ifNotNil: [\\n\\t\\tinsideObject := self object.\\n\\t\\tparentObject := self parentObject.\\n\\t\\tinspector ifNil: [inspector := Inspector new].\\n\\t\\tinspector\\n\\t\\t\\tinspect: parentObject;\\n\\t\\t\\tobject: insideObject.\\n\\n\\t\\taChar == $i ifTrue: [^ self inspectSelection].\\n\\t\\taChar == $I ifTrue: [^ self exploreSelection].\\n\\n\\t\\taChar == $b ifTrue:\\t[^ inspector browseMethodFull].\\n\\t\\taChar == $h ifTrue:\\t[^ inspector classHierarchy].\\n\\t\\taChar == $c ifTrue: [^ inspector copyName].\\n\\t\\taChar == $p ifTrue: [^ inspector browseFullProtocol].\\n\\t\\taChar == $N ifTrue: [^ inspector browseClassRefs].\\n\\t\\taChar == $t ifTrue: [^ inspector tearOffTile].\\n\\t\\taChar == $v ifTrue: [^ inspector viewerForValue]].\\n\\n\\t^ self arrowKey: aChar from: view! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'nk 7/24/2003 10:26'!\\nexploreSelection\\n\\t\\\"Open an ObjectExplorer on the current selection\\\"\\n\\tself object explore! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'sd 11/20/2005 21:27'!\\ngenericMenu: aMenu \\n\\t\\\"Borrow a menu from my inspector\\\"\\n\\t| insideObject menu parentObject |\\n\\tcurrentSelection\\n\\t\\tifNil: [menu := aMenu.\\n\\t\\t\\tmenu\\n\\t\\t\\t\\tadd: '*nothing selected*'\\n\\t\\t\\t\\ttarget: self\\n\\t\\t\\t\\tselector: #yourself]\\n\\t\\tifNotNil: [insideObject := self object.\\n\\t\\t\\tparentObject := self parentObject.\\n\\t\\t\\tinspector\\n\\t\\t\\t\\tifNil: [inspector := Inspector new].\\n\\t\\t\\tinspector inspect: parentObject;\\n\\t\\t\\t\\t object: insideObject.\\n\\t\\t\\taMenu defaultTarget: inspector.\\n\\t\\t\\tinspector fieldListMenu: aMenu.\\n\\t\\t\\taMenu items\\n\\t\\t\\t\\tdo: [:i | (#(#inspectSelection #exploreSelection #referencesToSelection #defsOfSelection #objectReferencesToSelection #chasePointers ) includes: i selector)\\n\\t\\t\\t\\t\\t\\tifTrue: [i target: self]].\\n\\t\\t\\taMenu addLine;\\n\\t\\t\\t\\tadd: 'monitor changes'\\n\\t\\t\\t\\ttarget: self\\n\\t\\t\\t\\tselector: #monitor:\\n\\t\\t\\t\\targument: currentSelection].\\n\\tmonitorList isEmptyOrNil\\n\\t\\tifFalse: [aMenu addLine;\\n\\t\\t\\t\\tadd: 'stop monitoring all'\\n\\t\\t\\t\\ttarget: self\\n\\t\\t\\t\\tselector: #stopMonitoring].\\n\\t^ aMenu! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'nk 7/24/2003 10:26'!\\ninspectSelection\\n\\t\\\"Open an Inspector on the current selection\\\"\\n\\tself object inspect! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'nk 7/24/2003 10:00'!\\nobjectReferencesToSelection\\n\\t\\\"Open a browser on all references to the selected instance variable, if that's what currently selected. \\\"\\n\\tself systemNavigation\\n\\t\\tbrowseAllObjectReferencesTo: self object\\n\\t\\texcept: (Array with: self parentObject with: currentSelection with: inspector)\\n\\t\\tifNone: [:obj | self changed: #flash].\\n! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'sd 11/20/2005 21:27'!\\nreferencesToSelection\\n\\t\\\"Open a browser on all references to the selected instance variable, if that's what's currently selected.\\\"\\n\\t| aClass sel |\\n\\n\\t(aClass := self parentObject class) isVariable ifTrue: [^ self changed: #flash].\\n\\tsel := self selector.\\n\\tself systemNavigation browseAllAccessesTo: sel from: aClass! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'RAA 9/23/1999 13:19'!\\nselectedClass\\n\\t\\\"Answer the class of the receiver's current selection\\\"\\n\\n\\t^self doItReceiver class\\n! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'RAA 9/23/1999 13:10'!\\ntrash\\n\\t\\\"What goes in the bottom pane\\\"\\n\\t^ ''! !\\n\\n!ObjectExplorer methodsFor: 'menus' stamp: 'RAA 9/23/1999 13:10'!\\ntrash: newText\\n\\t\\\"Don't save it\\\"\\n\\t^ true! !\\n\\n\\n!ObjectExplorer methodsFor: 'monitoring' stamp: 'sd 11/20/2005 21:27'!\\nmonitorList\\n\\t^monitorList ifNil: [ monitorList := WeakIdentityKeyDictionary new ].! !\\n\\n!ObjectExplorer methodsFor: 'monitoring' stamp: 'nk 7/31/2004 15:02'!\\nmonitor: anObjectExplorerWrapper\\n\\t\\\"Start stepping and watching the given wrapper for changes.\\\"\\n\\tanObjectExplorerWrapper ifNil: [ ^self ].\\n\\tself world ifNil: [ ^self ].\\n\\tself monitorList at: anObjectExplorerWrapper put: anObjectExplorerWrapper asString.\\n\\tself world startStepping: self at: Time millisecondClockValue selector: #step arguments: #() stepTime: 200.! !\\n\\n!ObjectExplorer methodsFor: 'monitoring' stamp: 'nk 7/31/2004 15:01'!\\nrelease\\n\\tself world ifNotNil: [ self world stopStepping: self selector: #step ].\\n\\tsuper release.! !\\n\\n!ObjectExplorer methodsFor: 'monitoring' stamp: 'nk 7/12/2003 17:55'!\\nshouldGetStepsFrom: aWorld\\n\\t^self monitorList notEmpty! !\\n\\n!ObjectExplorer methodsFor: 'monitoring' stamp: 'sd 11/20/2005 21:27'!\\nstep\\n\\t\\\"If there's anything in my monitor list, see if the strings have changed.\\\"\\n\\t| string changes |\\n\\tchanges := false.\\n\\tself monitorList keysAndValuesDo: [ :k :v |\\n\\t\\tk ifNotNil: [\\n\\t\\t\\tk refresh.\\n\\t\\t\\t(string := k asString) ~= v ifTrue: [ self monitorList at: k put: string. changes := true ].\\n\\t\\t]\\n\\t].\\n\\tchanges ifTrue: [ | sel |\\n\\t\\tsel := currentSelection.\\n\\t\\tself changed: #getList.\\n\\t\\tself noteNewSelection: sel.\\n\\t].\\n\\tself monitorList isEmpty ifTrue: [ ActiveWorld stopStepping: self selector: #step ].! !\\n\\n!ObjectExplorer methodsFor: 'monitoring' stamp: 'sd 11/20/2005 21:27'!\\nstopMonitoring\\n\\tmonitorList := nil.\\n\\tself world stopStepping: self selector: #step! !\\n\\n!ObjectExplorer methodsFor: 'monitoring' stamp: 'nk 7/31/2004 15:01'!\\nworld\\n\\t^ActiveWorld! !\\n\\n\\n!ObjectExplorer methodsFor: 'user interface' stamp: 'stephaneducasse 9/17/2005 21:50'!\\nexplorerFor: anObject withLabel: label \\n\\t| window listMorph |\\n\\trootObject := anObject.\\n\\twindow := (SystemWindow labelled: label) \\n\\t\\t\\t\\tmodel: self.\\n\\twindow\\n\\t\\taddMorph: (listMorph := SimpleHierarchicalListMorph\\n\\t\\t\\t\\t\\t\\ton: self\\n\\t\\t\\t\\t\\t\\tlist: #getList\\n\\t\\t\\t\\t\\t\\tselected: #getCurrentSelection\\n\\t\\t\\t\\t\\t\\tchangeSelected: #noteNewSelection:\\n\\t\\t\\t\\t\\t\\tmenu: #genericMenu:\\n\\t\\t\\t\\t\\t\\tkeystroke: nil)\\n\\t\\tframe: (0 @ 0 corner: 1 @ 0.8).\\n\\twindow\\n\\t\\taddMorph: ((PluggableTextMorph\\n\\t\\t\\t\\ton: self\\n\\t\\t\\t\\ttext: #trash\\n\\t\\t\\t\\taccept: #trash:\\n\\t\\t\\t\\treadSelection: #contentsSelection\\n\\t\\t\\t\\tmenu: #codePaneMenu:shifted:)\\n\\t\\t\\t\\taskBeforeDiscardingEdits: false)\\n\\t\\tframe: (0 @ 0.8 corner: 1 @ 1).\\n\\tlistMorph autoDeselect: false.\\n\\t^ window! !\\n\\n!ObjectExplorer methodsFor: 'user interface' stamp: 'RAA 6/2/2000 16:23'!\\ninitialExtent\\n\\n\\t^300@500! !\\n\\n!ObjectExplorer methodsFor: 'user interface' stamp: 'ar 9/27/2005 20:31'!\\nopenBrowser: aClass\\n\\n\\tToolSet browse: aClass selector: nil! !\\n\\n!ObjectExplorer methodsFor: 'user interface' stamp: 'RAA 6/2/2000 16:24'!\\nopenExplorerFor: anObject\\n\\\"\\nObjectExplorer new openExplorerFor: Smalltalk\\n\\\"\\n\\n (self explorerFor: anObject) openInWorld.\\n ^ self\\n! !\\n\\n!ObjectExplorer methodsFor: 'user interface' stamp: 'stephaneducasse 9/17/2005 21:51'!\\nopenExplorerFor: anObject withLabel: label \\n \\\"ObjectExplorer new openExplorerFor: Smalltalk withLabel: 'Smalltalk'\\\"\\n\\n\\t(self explorerFor: anObject withLabel: label)\\nopenInWorld! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nObjectExplorer class\\n\\tinstanceVariableNames: ''!\\n\\n!ObjectExplorer class methodsFor: 'as yet unclassified' stamp: 'RAA 6/21/1999 15:55'!\\nabout\\n\\n\\tStringHolder new textContents: self comment; openLabel: 'about ',self asString! !\\nListItemWrapper subclass: #ObjectExplorerWrapper\\n\\tinstanceVariableNames: 'itemName parent'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Explorer'!\\n!ObjectExplorerWrapper commentStamp: '<historical>' prior: 0!\\nContributed by Bob Arning as part of the ObjectExplorer package.\\n!\\n\\n\\n!ObjectExplorerWrapper methodsFor: 'as yet unclassified' stamp: 'RAA 6/21/1999 15:48'!\\ncanBeDragged\\n\\n\\t^false! !\\n\\n!ObjectExplorerWrapper methodsFor: 'as yet unclassified' stamp: 'nk 7/24/2003 09:14'!\\nparent\\n\\t^parent! !\\n\\n!ObjectExplorerWrapper methodsFor: 'as yet unclassified' stamp: 'nk 7/24/2003 09:14'!\\nparent: anObject\\n\\tparent _ anObject! !\\n\\n!ObjectExplorerWrapper methodsFor: 'as yet unclassified' stamp: 'nk 7/24/2003 09:49'!\\nselector\\n\\tparent ifNil: [ ^nil ].\\n\\t^(parent withoutListWrapper class allInstVarNames includes: itemName) ifTrue: [ itemName asSymbol ]! !\\n\\n!ObjectExplorerWrapper methodsFor: 'as yet unclassified' stamp: 'RAA 6/21/1999 10:49'!\\nsetItem: anObject name: aString model: aModel\\n\\n\\titem _ anObject.\\n\\tmodel _ aModel.\\n\\titemName _ aString.! !\\n\\n!ObjectExplorerWrapper methodsFor: 'as yet unclassified' stamp: 'nk 7/24/2003 09:14'!\\nsetItem: anObject name: aString model: aModel parent: itemParent\\n\\tparent _ itemParent.\\n\\tself setItem: anObject name: aString model: aModel! !\\n\\n\\n!ObjectExplorerWrapper methodsFor: 'converting' stamp: 'edt 5/26/2003 12:36'!\\nasString\\n\\t| explorerString string |\\n\\texplorerString _ \\n\\t\\t[item asExplorerString]\\n\\t\\t\\ton: Error \\n\\t\\t\\tdo: ['<error: ', item class name, ' in asExplorerString: evaluate \\\"' , itemName , ' asExplorerString\\\" to debug>'].\\n\\tstring _ (itemName ifNotNil: [itemName , ': '] ifNil: ['']) , explorerString.\\n\\t(string includes: Character cr)\\n\\t\\tifTrue: [^ string withSeparatorsCompacted].\\n\\t^ string! !\\n\\n!ObjectExplorerWrapper methodsFor: 'converting' stamp: 'nk 7/24/2003 10:16'!\\nitemName\\n\\t^itemName! !\\n\\n\\n!ObjectExplorerWrapper methodsFor: 'monitoring' stamp: 'nk 7/12/2003 18:28'!\\nrefresh\\n\\t\\\"hack to refresh item given an object and a string that is either an index or an instance variable name.\\\"\\n\\t[ | index |\\n\\t\\t(model class allInstVarNames includes: itemName)\\n\\t\\t\\tifTrue: [ item _ model instVarNamed: itemName ]\\n\\t\\t\\tifFalse: [ index _ itemName asNumber.\\n\\t\\t\\t\\t(index between: 1 and: model basicSize) ifTrue: [ item _ model basicAt: index]]\\n\\t] on: Error do: [ :ex | item _ nil ]! !\\n\\n\\n!ObjectExplorerWrapper methodsFor: 'accessing' stamp: 'nk 7/24/2003 09:17'!\\ncontents\\n\\n\\t(item respondsTo: #explorerContents) ifTrue: [^item explorerContents].\\n\\t\\\"For all others, show named vars first, then indexed vars\\\"\\n\\t^(item class allInstVarNames asOrderedCollection withIndexCollect: [:each :index |\\n\\t\\tself class\\n\\t\\t\\twith: (item instVarAt: index)\\n\\t\\t\\tname: each\\n\\t\\t\\tmodel: item\\n\\t\\t\\tparent: self]) ,\\n\\t((1 to: item basicSize) collect: [:index |\\n\\t\\tself class\\n\\t\\t\\twith: (item basicAt: index)\\n\\t\\t\\tname: index printString\\n\\t\\t\\tmodel: item\\n\\t\\t\\tparent: self])! !\\n\\n!ObjectExplorerWrapper methodsFor: 'accessing' stamp: 'RAA 6/21/1999 11:27'!\\nhasContents\\n\\n\\t^item hasContentsInExplorer\\n\\t\\n! !\\n\\n!ObjectExplorerWrapper methodsFor: 'accessing' stamp: 'dgd 9/26/2004 18:34'!\\nicon\\n\\t\\\"Answer a form to be used as icon\\\"\\n\\t^ Preferences visualExplorer\\n\\t\\tifTrue: [item iconOrThumbnailOfSize: 16]\\n\\t\\tifFalse: [nil]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nObjectExplorerWrapper class\\n\\tinstanceVariableNames: ''!\\n\\n!ObjectExplorerWrapper class methodsFor: 'as yet unclassified' stamp: 'RAA 6/21/1999 10:50'!\\nwith: anObject name: aString model: aModel\\n\\n\\t^self new \\n\\t\\tsetItem: anObject name: aString model: aModel! !\\n\\n!ObjectExplorerWrapper class methodsFor: 'as yet unclassified' stamp: 'nk 7/24/2003 09:16'!\\nwith: anObject name: aString model: aModel parent: aParent\\n\\n\\t^self new \\n\\t\\tsetItem: anObject name: aString model: aModel parent: aParent\\n! !\\nObject subclass: #ObjectFinalizer\\n\\tinstanceVariableNames: 'receiver selector arguments'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Finalization'!\\n\\n!ObjectFinalizer methodsFor: 'finalization' stamp: 'ar 5/19/2003 20:13'!\\nfinalize\\n\\t\\\"Finalize the resource associated with the receiver. This message should only be sent during the finalization process. There is NO garantuee that the resource associated with the receiver hasn't been free'd before so take care that you don't run into trouble - this all may happen with interrupt priority.\\\"\\n\\t[receiver perform: selector withArguments: arguments] \\n\\t\\ton: Error do:[:ex| ex return].\\n! !\\n\\n\\n!ObjectFinalizer methodsFor: 'initialize' stamp: 'ar 5/19/2003 20:12'!\\nreceiver: aReceiver selector: aSelector argument: anObject\\n\\treceiver := aReceiver.\\n\\tselector := aSelector.\\n\\targuments := Array with: anObject! !\\nTestCase subclass: #ObjectFinalizerTests\\n\\tinstanceVariableNames: 'log'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Finalization'!\\n\\n!ObjectFinalizerTests methodsFor: 'finalization handling' stamp: 'apb 9/14/2005 08:33'!\\nfinalize: anObject\\n\\tlog addLast: anObject asString, ' ', 'finalized'.! !\\n\\n\\n!ObjectFinalizerTests methodsFor: 'running' stamp: 'apb 9/14/2005 08:39'!\\nsetUp\\n\\tsuper setUp.\\n\\tlog := OrderedCollection new.! !\\n\\n\\n!ObjectFinalizerTests methodsFor: 'tests' stamp: 'stephaneducasse 10/28/2005 21:15'!\\ntestFinalization\\n\\t\\\"self run: #testFinalization\\\"\\n\\t\\n\\t| repetitions |\\n\\trepetitions := 100.\\n\\t1 to: repetitions\\n\\t\\tdo: [:i | \\n\\t\\t\\tlog addLast: 'o' , i asString , ' created'.\\n\\t\\t\\tObject new\\n\\t\\t\\t\\ttoFinalizeSend: #finalize:\\n\\t\\t\\t\\tto: self\\n\\t\\t\\t\\twith: 'o' , i asString].\\n\\tSmalltalk garbageCollect.\\n\\tself finalizationRegistry finalizeValues.\\n\\t1 to: repetitions\\n\\t\\tdo: [:i | \\n\\t\\t\\tself assert: (log includes: 'o' , i asString , ' created').\\n\\t\\t\\tself assert: (log includes: 'o' , i asString , ' finalized')]! !\\n\\n!ObjectFinalizerTests methodsFor: 'tests' stamp: 'stephaneducasse 10/28/2005 21:15'!\\ntestFinalizationOfEquals\\n\\t\\\"self run: #testFinalizationOfEquals\\\"\\n\\t\\n\\t| bag o |\\n\\tbag := IdentityBag new.\\n\\t1 to: 5 do: [:n | o := n asString copy. bag add: n. o toFinalizeSend: #remove: to: bag with: n].\\n\\t1 to: 5 do: [:n | o := n asString copy. bag add: n. o toFinalizeSend: #remove: to: bag with: n].\\n\\tSmalltalk garbageCollect.\\n\\t1 to: 5 do: [:n | self deny: (bag includes: n)]\\n! !\\nProtoObject subclass: #ObjectOut\\n\\tinstanceVariableNames: 'url page recursionFlag'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Objects'!\\n!ObjectOut commentStamp: '<historical>' prior: 0!\\nI am a stand-in for an object that is out on the disk. The object that is out on the disk is the head of a tree of objects that are out. See SqueakPage.\\n\\nWhen any message is sent to me, I don't understand it, and bring in my true object. I become myself with the objects and resend the message. \\n\\nI may not represent the object nil. \\nThe file is represented as a url, and that url may point at any file on the net. \\n\\npage is a SqueakPage.\\nIf the cache already has an object, widely in use, that claims to be the object for my url, what do I do? I can't become him, since others believe that he is the true object. Run through memory and replace refs to me with refs to him. Be careful not to trigger a fault. Become me to a string, then find pointers and replace?\\n\\n[[[They don't want to end up holding an ObjectOut. (would oscillate back and forth) This is a problem. A user could bring in two trees that both refer to a 3rd url. (check with cache before installing any new ObjectOut) Two trees could be written to the same url.\\nOr, I remain an ObjectOut, and keep getting notUnderstood, and keep returning the other guy.\\nOr I smash the cache, and install MY page and object. Other guy is a copy -- still in, but with no place in the cache. When we both write to the same url, there will be trouble.] No -- search and replace.]]]\\n!\\n\\n\\n!ObjectOut methodsFor: 'access' stamp: 'tk 1/15/1999 11:43'!\\nurl: aString\\n\\n\\turl _ aString! !\\n\\n!ObjectOut methodsFor: 'access' stamp: 'tk 12/18/1998 21:29'!\\nxxxReset\\n\\t\\\"mark as never brought in\\\"\\n\\trecursionFlag _ nil! !\\n\\n\\n!ObjectOut methodsFor: 'basics' stamp: 'tk 10/30/1998 15:11'!\\nisInMemory\\n\\t\\\"We are a place holder for an object that is out.\\\"\\n\\t^ false! !\\n\\n!ObjectOut methodsFor: 'basics' stamp: 'tk 10/21/1998 12:28'!\\nxxxClass\\n\\t\\\"Primitive. Answer the object which is the receiver's class. Essential. See \\n\\tObject documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 111>\\n\\tself primitiveFailed! !\\n\\n!ObjectOut methodsFor: 'basics' stamp: 'tk 10/22/1998 15:31'!\\nxxxClone\\n\\n\\t<primitive: 148>\\n\\tself primitiveFailed! !\\n\\n!ObjectOut methodsFor: 'basics' stamp: 'tk 10/22/1998 15:19'!\\nxxxInstVarAt: index \\n\\t\\\"Primitive. Answer a fixed variable in an object. The numbering of the \\n\\tvariables corresponds to the named instance variables. Fail if the index \\n\\tis not an Integer or is not the index of a fixed variable. Essential. See \\n\\tObject documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 73>\\n\\tself primitiveFailed ! !\\n\\n!ObjectOut methodsFor: 'basics' stamp: 'tk 10/22/1998 14:39'!\\nxxxInstVarAt: anInteger put: anObject \\n\\t\\\"Primitive. Store a value into a fixed variable in the receiver. The \\n\\tnumbering of the variables corresponds to the named instance variables. \\n\\tFail if the index is not an Integer or is not the index of a fixed variable. \\n\\tAnswer the value stored as the result. Using this message violates the \\n\\tprinciple that each object has sovereign control over the storing of \\n\\tvalues into its instance variables. Essential. See Object documentation \\n\\twhatIsAPrimitive.\\\"\\n\\n\\t<primitive: 74>\\n\\tself primitiveFailed ! !\\n\\n\\n!ObjectOut methodsFor: 'fetch from disk' stamp: 'rbb 2/18/2005 14:55'!\\ndoesNotUnderstand: aMessage \\n\\t\\\"Bring in the object, install, then resend aMessage\\\"\\n\\t| realObject oldFlag response |\\n\\toldFlag _ recursionFlag.\\n\\trecursionFlag _ true.\\n\\t\\\"fetch the object\\\"\\n\\trealObject _ self xxxFetch.\\t\\t\\\"watch out for the become!!\\\"\\n\\t\\t\\t\\\"Now we ARE the realObject\\\"\\n\\toldFlag == true ifTrue: [\\n\\t\\tresponse _ (UIManager default chooseFrom: #('proceed normally' 'debug')\\n\\t\\t\\ttitle: 'Object being fetched for a second time.\\nShould not happen, and needs to be fixed later.').\\n\\t\\tresponse = 2 ifTrue: [self halt]].\\t\\\"We are already the new object\\\"\\n\\n\\t\\\"Can't be a super message, since this is the first message sent to this object\\\"\\n\\t^ realObject perform: aMessage selector withArguments: aMessage arguments! !\\n\\n!ObjectOut methodsFor: 'fetch from disk' stamp: 'tk 11/16/1998 09:57'!\\nxxxFetch\\n\\t\\\"Bring in my object and replace all references to me with references to him. First try looking up my url in the pageCache. Then try the page (and install it, under its url). Then start from scratch with the url.\\\"\\n\\n\\t| truePage object existing |\\n\\texisting _ SqueakPageCache pageCache at: url ifAbsent: [nil].\\n\\texisting ifNotNil: [existing isContentsInMemory\\n\\t\\tifTrue: [page _ truePage _ existing]].\\t\\\"This url already has an object in this image\\\"\\n\\ttruePage ifNil: [\\n\\t\\ttruePage _ SqueakPageCache atURL: url oldPage: page].\\n\\tobject _ truePage isContentsInMemory \\n\\t\\tifTrue: [truePage contentsMorph]\\n\\t\\tifFalse: [truePage fetchInformIfError].\\t\\\"contents, not the page\\\"\\n\\t\\t\\t\\\"Later, collect pointers to object and fix them up. Not scan memory\\\"\\n\\tobject ifNil: [^ 'Object could not be fetched.'].\\n\\t\\\"recursionFlag _ false.\\\" \\t\\\"while I still have a pointer to myself\\\"\\n\\ttruePage contentsMorph: object.\\n\\tpage _ truePage.\\n\\tself xxxFixup.\\n\\t^ object\\t\\\"the final object!!\\\"\\n ! !\\n\\n!ObjectOut methodsFor: 'fetch from disk' stamp: 'ar 9/27/2005 18:03'!\\nxxxFixup\\n\\t\\\"There is already an object in memory for my url. All pointers to me need to be pointers to him. Can't use become, because other pointers to him must stay valid.\\\"\\n\\n\\t| real temp list |\\n\\treal := page contentsMorph.\\n\\treal == self ifTrue: [page error: 'should be converted by now'].\\n\\ttemp := self.\\n\\tlist := (Utilities pointersTo: temp) asOrderedCollection.\\n\\tlist add: thisContext. list add: thisContext sender.\\n\\tlist do: [:holder |\\n\\t\\t1 to: holder class instSize do:\\n\\t\\t\\t[:i | (holder instVarAt: i) == temp ifTrue: [holder instVarAt: i put: real]].\\n\\t\\t1 to: holder basicSize do:\\n\\t\\t\\t[:i | (holder basicAt: i) == temp ifTrue: [holder basicAt: i put: real]].\\n\\t\\t].\\n\\t^ real! !\\n\\n!ObjectOut methodsFor: 'fetch from disk' stamp: 'tk 10/21/1998 13:01'!\\nxxxSetUrl: aString page: aSqkPage\\n\\n\\turl _ aString.\\n\\tpage _ aSqkPage.! !\\n\\n\\n!ObjectOut methodsFor: 'object storage' stamp: 'tk 2/17/2000 22:21'!\\ncomeFullyUpOnReload: smartRefStream\\n\\t\\\"Normally this read-in object is exactly what we want to store. Try to dock first. If it is here already, use that one.\\\"\\n\\n\\t| sp |\\n\\t\\\"Transcript show: 'has ref to: ', url; cr.\\\"\\n\\t(sp _ SqueakPageCache pageCache at: page ifAbsent: [nil]) ifNotNil: [\\n\\t\\tsp isContentsInMemory ifTrue: [^ sp contentsMorph]].\\n\\t^ self! !\\n\\n!ObjectOut methodsFor: 'object storage' stamp: 'tk 2/24/1999 11:14'!\\nobjectForDataStream: refStrm\\n \\\"Return an object to store on a data stream (externalize myself).\\\"\\n\\n ^ self! !\\n\\n!ObjectOut methodsFor: 'object storage' stamp: 'tk 10/22/1998 14:37'!\\nreadDataFrom: aDataStream size: varsOnDisk\\n\\t\\\"Make self be an object based on the contents of aDataStream, which was generated by the object's storeDataOn: method. Return self.\\\"\\n\\t| cntInstVars |\\n\\tcntInstVars _ self xxxClass instSize.\\n\\tself xxxClass isVariable\\n\\t\\tifTrue: [self xxxClass error: 'needs updating']\\t\\\"assume no variable subclasses\\\"\\n\\t\\tifFalse: [cntInstVars _ varsOnDisk].\\n\\n\\taDataStream beginReference: self.\\n\\t1 to: cntInstVars do:\\n\\t\\t[:i | self xxxInstVarAt: i put: aDataStream next].\\n\\\"\\t1 to: cntIndexedVars do:\\n\\t\\t[:i | self basicAt: i put: aDataStream next].\\n\\\"\\n\\t^ self! !\\n\\n!ObjectOut methodsFor: 'object storage' stamp: 'tk 10/22/1998 15:18'!\\nstoreDataOn: aDataStream\\n\\t\\\"Store myself on a DataStream. See also objectToStoreOnDataStream.\\n\\tmust send 'aDataStream beginInstance:size:'\\\"\\n\\t| cntInstVars |\\n\\n\\tcntInstVars _ self class instSize.\\n\\t\\\"cntIndexedVars _ self basicSize.\\\"\\n\\taDataStream\\n\\t\\tbeginInstance: self xxxClass\\n\\t\\tsize: cntInstVars \\\"+ cntIndexedVars\\\".\\n\\t1 to: cntInstVars do:\\n\\t\\t[:i | aDataStream nextPut: (self xxxInstVarAt: i)].\\n\\\"\\t1 to: cntIndexedVars do:\\n\\t\\t[:i | aDataStream nextPut: (self basicAt: i)]\\n\\\"! !\\n\\n!ObjectOut methodsFor: 'object storage' stamp: 'tk 10/22/1998 15:29'!\\nveryDeepCopyWith: deepCopier\\n\\t\\\"Copy me and the entire tree of objects I point to. An object in the tree twice is copied once, and both references point to him. deepCopier holds a dictionary of objects we have seen. Some classes refuse to be copied. Some classes are picky about which fields get deep copied.\\\"\\n\\t| class index sub subAss new absent |\\n\\tnew _ deepCopier references at: self ifAbsent: [absent _ true].\\n\\tabsent ifNil: [^ new].\\t\\\"already done\\\"\\n\\tclass _ self xxxClass.\\n\\tclass isMeta ifTrue: [^ self].\\t\\t\\\"a class\\\"\\n\\tnew _ self xxxClone.\\n\\t\\\"not a uniClass\\\"\\n\\tdeepCopier references at: self put: new.\\t\\\"remember\\\"\\n\\t\\\"class is not variable\\\"\\n\\tindex _ class instSize.\\n\\t[index > 0] whileTrue: \\n\\t\\t[sub _ self xxxInstVarAt: index.\\n\\t\\t(subAss _ deepCopier references associationAt: sub ifAbsent: [nil])\\n\\t\\t\\tifNil: [new xxxInstVarAt: index put: (sub veryDeepCopyWith: deepCopier)]\\n\\t\\t\\tifNotNil: [new xxxInstVarAt: index put: subAss value].\\n\\t\\tindex _ index - 1].\\n\\tnew rehash.\\t\\\"force Sets and Dictionaries to rehash\\\"\\n\\t^ new\\n! !\\n\\n\\n!ObjectOut methodsFor: '*MorphicExtras-access' stamp: 'tk 12/4/1998 13:01'!\\nsqkPage\\n\\t^ page! !\\n\\n!ObjectOut methodsFor: '*MorphicExtras-access' stamp: 'tk 12/4/1998 13:01'!\\nurl\\n\\t^ url! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nObjectOut class\\n\\tinstanceVariableNames: ''!\\nGenericPropertiesMorph subclass: #ObjectPropertiesMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Experimental'!\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:04'!\\nadjustTargetBorderWidth: aFractionalPoint\\n\\n\\t| n |\\n\\n\\tmyTarget borderWidth: (n _ (aFractionalPoint x * 10) rounded max: 0).\\n\\tself showSliderFeedback: n.! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:02'!\\nadjustTargetGradientDirection: aFractionalPoint\\n\\n\\t| fs p |\\n\\n\\t(fs _ myTarget fillStyle) isGradientFill ifFalse: [^self].\\n\\tfs direction: (p _ (aFractionalPoint * myTarget extent) rounded).\\n\\tself showSliderFeedback: p.\\n\\tmyTarget changed.\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:05'!\\nadjustTargetGradientOrigin: aFractionalPoint\\n\\n\\t| fs p |\\n\\n\\t(fs _ myTarget fillStyle) isGradientFill ifFalse: [^self].\\n\\tfs origin: (p _ myTarget topLeft + (aFractionalPoint * myTarget extent) rounded).\\n\\tself showSliderFeedback: p.\\n\\tmyTarget changed.\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:03'!\\nadjustTargetShadowOffset: aFractionalPoint\\n\\n\\t| n |\\n\\n\\tmyTarget changed; layoutChanged.\\n\\tmyTarget shadowOffset: (n _ (aFractionalPoint * 4) rounded).\\n\\tself showSliderFeedback: n.\\n\\tmyTarget changed; layoutChanged.\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:03'!\\ndoEnables\\n\\n\\t| itsName fs |\\n\\n\\tfs _ myTarget fillStyle.\\n\\tself allMorphsDo: [ :each |\\n\\t\\titsName _ each knownName.\\n\\t\\titsName == #pickerForColor ifTrue: [\\n\\t\\t\\tself enable: each when: fs isSolidFill | fs isGradientFill\\n\\t\\t].\\n\\t\\titsName == #pickerForBorderColor ifTrue: [\\n\\t\\t\\tself enable: each when: (myTarget respondsTo: #borderColor:)\\n\\t\\t].\\n\\t\\titsName == #pickerForShadowColor ifTrue: [\\n\\t\\t\\tself enable: each when: myTarget hasDropShadow\\n\\t\\t].\\n\\t\\titsName == #pickerFor2ndGradientColor ifTrue: [\\n\\t\\t\\tself enable: each when: fs isGradientFill\\n\\t\\t].\\n\\t].\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:03'!\\nmakeTargetGradientFill\\n\\n\\tmyTarget useGradientFill! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:02'!\\nmakeTargetSolidFill\\n\\n\\tmyTarget useSolidFill! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:04'!\\nnumberOneColor\\n\\n\\tmyTarget fillStyle isGradientFill ifFalse: [^myTarget color].\\n\\t^myTarget fillStyle colorRamp first value\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'gm 2/16/2003 20:36'!\\nnumberOneColor: aColor \\n\\tmyTarget fillStyle isGradientFill \\n\\t\\tifFalse: \\n\\t\\t\\t[^(myTarget isSystemWindow) \\n\\t\\t\\t\\tifTrue: [myTarget setWindowColor: aColor]\\n\\t\\t\\t\\tifFalse: [myTarget fillStyle: aColor]].\\n\\tmyTarget fillStyle \\n\\t\\tfirstColor: aColor\\n\\t\\tforMorph: myTarget\\n\\t\\thand: nil! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'dgd 10/8/2003 19:35'!\\nrebuild\\n\\n\\tself removeAllMorphs.\\n\\tself addARow: {\\n\\t\\tself lockedString: ('Properties for {1}' translated format: {myTarget name}).\\n\\t}.\\n\\tself addARow: {\\n\\t\\tself inAColumn: {\\n\\t\\t\\tself paneForCornerRoundingToggle.\\n\\t\\t\\tself paneForStickinessToggle.\\n\\t\\t\\tself paneForLockedToggle.\\n\\t\\t}.\\n\\t}.\\n\\n\\tself addARow: {\\n\\t\\tself paneForMainColorPicker.\\n\\t\\tself paneFor2ndGradientColorPicker.\\n\\t}.\\n\\tself addARow: {\\n\\t\\tself paneForBorderColorPicker.\\n\\t\\tself paneForShadowColorPicker.\\n\\t}.\\n\\n\\tself addARow: {\\n\\t\\tself \\n\\t\\t\\tbuttonNamed: 'Accept' translated action: #doAccept color: color lighter \\n\\t\\t\\thelp: 'keep changes made and close panel' translated.\\n\\t\\tself \\n\\t\\t\\tbuttonNamed: 'Cancel' translated action: #doCancel color: color lighter \\n\\t\\t\\thelp: 'cancel changes made and close panel' translated.\\n\\t}, self rebuildOptionalButtons.\\n\\n\\tthingsToRevert _ Dictionary new.\\n\\t\\\"thingsToRevert at: #fillStyle: put: myTarget fillStyle.\\\"\\n\\tmyTarget isSystemWindow ifTrue: [\\n\\t\\tthingsToRevert at: #setWindowColor: put: myTarget paneColorToUse\\n\\t].\\n\\tthingsToRevert at: #hasDropShadow: put: myTarget hasDropShadow.\\n\\tthingsToRevert at: #shadowColor: put: myTarget shadowColor.\\n\\t(myTarget respondsTo: #borderColor:) ifTrue: [\\n\\t\\tthingsToRevert at: #borderColor: put: myTarget borderColor.\\n\\t].\\n\\n\\tthingsToRevert at: #borderWidth: put: myTarget borderWidth.\\n\\tthingsToRevert at: #cornerStyle: put: myTarget cornerStyle.\\n\\tthingsToRevert at: #sticky: put: myTarget isSticky.\\n\\tthingsToRevert at: #lock: put: myTarget isLocked.\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'wiz 9/21/2005 22:42'!\\nrebuildOptionalButtons\\n\\n\\t| answer |\\n\\n\\tanswer _ #() .\\n\\t\\n\\tmyTarget isTextMorph ifTrue: [\\n\\t\\tanswer _ answer, {\\n\\t\\t\\tself \\n\\t\\t\\t\\tbuttonNamed: 'Text' translated action: #doTextProperties color: color lighter \\n\\t\\t\\t\\thelp: 'open a text properties panel for the morph' translated.\\n\\t\\t}.\\n\\t].\\n\\t^answer! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'ar 8/25/2001 18:30'!\\ntargetBorderColor\\n\\t^myTarget borderStyle baseColor! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'ar 11/26/2001 15:29'!\\ntargetBorderColor: aColor\\n\\t\\\"Need to replace the borderStyle or BorderedMorph will not 'feel' the change\\\"\\n\\tmyTarget borderStyle: (myTarget borderStyle copy baseColor: aColor).! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:04'!\\ntargetHasGradientFill\\n\\n\\t^myTarget fillStyle isGradientFill! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:01'!\\ntargetHasSolidFill\\n\\n\\t^myTarget fillStyle isSolidFill! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:03'!\\ntargetRadial\\n\\n\\tmyTarget fillStyle isGradientFill ifFalse: [^false].\\n\\t^myTarget fillStyle radial! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:03'!\\ntgt2ndGradientColor\\n\\n\\tmyTarget fillStyle isGradientFill ifFalse: [^Color black].\\n\\t^myTarget fillStyle colorRamp last value! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:03'!\\ntgt2ndGradientColor: aColor\\n\\n\\tmyTarget fillStyle lastColor: aColor forMorph: myTarget hand: nil\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 2/20/2001 17:45'!\\ntoggleTargetGradientFill\\n\\n\\tself targetHasGradientFill ifTrue: [\\n\\t\\tself makeTargetSolidFill\\n\\t] ifFalse: [\\n\\t\\tself makeTargetGradientFill\\n\\t].\\n\\tself doEnables! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 3/8/2001 18:02'!\\ntoggleTargetRadial\\n\\n\\t| fs |\\n\\n\\t(fs _ myTarget fillStyle) isGradientFill ifFalse: [^self].\\n\\tfs radial: fs radial not.\\n\\tmyTarget changed.\\n\\tself doEnables.! !\\n\\n!ObjectPropertiesMorph methodsFor: 'as yet unclassified' stamp: 'RAA 2/20/2001 17:48'!\\ntoggleTargetSolidFill\\n\\n\\tself targetHasSolidFill ifTrue: [\\n\\t\\tself makeTargetGradientFill\\n\\t] ifFalse: [\\n\\t\\tself makeTargetSolidFill\\n\\t].\\n\\tself doEnables! !\\n\\n\\n!ObjectPropertiesMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:44'!\\ndefaultBorderColor\\n\\\"answer the default border color/fill style for the receiver\\\"\\n\\t^ self defaultColor darker! !\\n\\n!ObjectPropertiesMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:44'!\\ndefaultColor\\n\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color\\n\\t\\tr: 0.548\\n\\t\\tg: 0.839\\n\\t\\tb: 0.452! !\\n\\n!ObjectPropertiesMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:44'!\\ninitialize\\n\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\\"\\\"\\n\\tmyTarget\\n\\t\\tifNil: [myTarget _ RectangleMorph new openInWorld].\\n\\tself rebuild! !\\n\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'sd 11/13/2003 21:03'!\\nborderPrototype: aBorderStyle help: helpString\\n\\t| selector proto |\\n\\tselector _ BorderedMorph new.\\n\\tselector borderWidth: 0.\\n\\tselector color: Color transparent.\\n\\tproto _ Morph new extent: 16@16.\\n\\tproto color: Color transparent.\\n\\tproto borderStyle: aBorderStyle.\\n\\tselector extent: proto extent + 4.\\n\\tselector addMorphCentered: proto.\\n\\t(myTarget canDrawBorder: aBorderStyle) ifTrue:[\\n\\t\\tselector setBalloonText: helpString.\\n\\t\\tselector on: #mouseDown send: #toggleBorderStyle:with:from: to: self withValue: proto.\\n\\t\\t(myTarget borderStyle species == aBorderStyle species and:[\\n\\t\\t\\tmyTarget borderStyle style == aBorderStyle style]) ifTrue:[selector borderWidth: 1].\\n\\t] ifFalse:[\\n\\t\\tselector setBalloonText: 'This border style cannot be used here' translated.\\n\\t\\tselector on: #mouseDown send: #beep to: Beeper.\\n\\t\\tselector addMorphCentered: ((Morph new) color: (Color black alpha: 0.5); extent: selector extent).\\n\\t].\\n\\t^selector! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:21'!\\npaneFor2ndGradientColorPicker\\n\\n\\t^self \\n\\t\\tinAColumn: {\\n\\t\\t\\t(self inAColumn: {\\n\\t\\t\\t\\tself colorPickerFor: self getter: #tgt2ndGradientColor setter: #tgt2ndGradientColor:.\\n\\t\\t\\t\\tself lockedString: '2nd gradient color' translated.\\n\\t\\t\\t\\tself paneForRadialGradientToggle hResizing: #shrinkWrap.\\n\\t\\t\\t\\t(\\n\\t\\t\\t\\t\\tself inARow: {self paneForGradientOrigin. self paneForGradientDirection}\\n\\t\\t\\t\\t) hResizing: #shrinkWrap.\\n\\t\\t\\t}\\n\\t\\t\\tnamed: #pickerFor2ndGradientColor) layoutInset: 0.\\n\\t\\t\\tself paneForGradientFillToggle hResizing: #shrinkWrap \\n\\t\\t}\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:23'!\\npaneForBorderColorPicker\\n\\n\\t^self \\n\\t\\tinAColumn: {\\n\\t\\t\\tself \\n\\t\\t\\t\\tcolorPickerFor: self\\n\\t\\t\\t\\tgetter: #targetBorderColor\\n\\t\\t\\t\\tsetter: #targetBorderColor:.\\n\\t\\t\\tself lockedString: 'Border Color' translated.\\n\\t\\t\\t(self paneForBorderStyle) hResizing: #shrinkWrap; layoutInset: 5.\\n\\t\\t\\tself lockedString: 'Border style' translated.\\n\\t\\t\\tself paneForBorderWidth.\\n\\t\\t} \\n\\t\\tnamed: #pickerForBorderColor.\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:25'!\\npaneForBorderStyle\\n\\n\\t^self inARow: {\\n\\t\\tself borderPrototype: (BorderStyle width: 4 color: Color black)\\n\\t\\t\\thelp:'Click to select a simple colored border' translated.\\n\\t\\tself borderPrototype: (BorderStyle raised width: 4)\\n\\t\\t\\thelp:'Click to select a simple raised border' translated.\\n\\t\\tself borderPrototype: (BorderStyle inset width: 4)\\n\\t\\t\\thelp:'Click to select a simple inset border' translated.\\n\\t\\tself borderPrototype: (BorderStyle complexFramed width: 4)\\n\\t\\t\\thelp:'Click to select a complex framed border' translated.\\n\\t\\tself borderPrototype: (BorderStyle complexRaised width: 4)\\n\\t\\t\\thelp:'Click to select a complex raised border' translated.\\n\\t\\tself borderPrototype: (BorderStyle complexInset width: 4)\\n\\t\\t\\thelp:'Click to select a complex inset border' translated.\\n\\t\\tself borderPrototype: (BorderStyle complexAltFramed width: 4)\\n\\t\\t\\thelp:'Click to select a complex framed border' translated.\\n\\t\\tself borderPrototype: (BorderStyle complexAltRaised width: 4)\\n\\t\\t\\thelp:'Click to select a complex raised border' translated.\\n\\t\\tself borderPrototype: (BorderStyle complexAltInset width: 4)\\n\\t\\t\\thelp:'Click to select a complex inset border' translated.\\n\\t}\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:29'!\\npaneForBorderWidth\\n\\n\\t^(self inARow: {\\n\\t\\tself\\n\\t\\t\\tbuildFakeSlider: 'Border width' translated\\n\\t\\t\\tselector: #adjustTargetBorderWidth:\\n\\t\\t\\thelp: 'Drag in here to change the border width' translated\\n\\t}) hResizing: #shrinkWrap\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:18'!\\npaneForCornerRoundingToggle\\n\\n\\t^self inARow: {\\n\\t\\tself\\n\\t\\t\\tdirectToggleButtonFor: myTarget \\n\\t\\t\\tgetter: #wantsRoundedCorners setter: #toggleCornerRounding\\n\\t\\t\\thelp: 'Turn rounded corners on or off' translated.\\n\\t\\tself lockedString: ' Rounded corners' translated.\\n\\t}\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:40'!\\npaneForDropShadowToggle\\n\\n\\t^self inARow: {\\n\\t\\tself\\n\\t\\t\\tdirectToggleButtonFor: myTarget \\n\\t\\t\\tgetter: #hasDropShadow setter: #toggleDropShadow\\n\\t\\t\\thelp: 'Turn drop shadows on or off' translated.\\n\\t\\tself lockedString: ' Drop shadow color' translated.\\n\\t}\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:22'!\\npaneForGradientDirection\\n\\n\\t^(self inARow: {\\n\\t\\tself\\n\\t\\t\\tbuildFakeSlider: 'Direction' translated\\n\\t\\t\\tselector: #adjustTargetGradientDirection:\\n\\t\\t\\thelp: 'Drag in here to change the direction of the gradient' translated\\n\\t}) hResizing: #shrinkWrap\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:22'!\\npaneForGradientFillToggle\\n\\n\\t^self inARow: {\\n\\t\\tself\\n\\t\\t\\tdirectToggleButtonFor: self \\n\\t\\t\\tgetter: #targetHasGradientFill\\n\\t\\t\\tsetter: #toggleTargetGradientFill\\n\\t\\t\\thelp: 'Turn gradient fill on or off' translated.\\n\\t\\tself lockedString: ' Gradient fill' translated.\\n\\t}\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:21'!\\npaneForGradientOrigin\\n\\n\\t^(self inARow: {\\n\\t\\tself\\n\\t\\t\\tbuildFakeSlider: 'Origin' translated\\n\\t\\t\\tselector: #adjustTargetGradientOrigin:\\n\\t\\t\\thelp: 'Drag in here to change the origin of the gradient' translated\\n\\t}) hResizing: #shrinkWrap\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:19'!\\npaneForLockedToggle\\n\\n\\t^self inARow: {\\n\\t\\tself\\n\\t\\t\\tdirectToggleButtonFor: myTarget \\n\\t\\t\\tgetter: #isLocked setter: #toggleLocked\\n\\t\\t\\thelp: 'Turn lock on or off' translated.\\n\\t\\tself lockedString: ' Lock' translated.\\n\\t}\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:20'!\\npaneForMainColorPicker\\n\\n\\t^self \\n\\t\\tinAColumn: {\\n\\t\\t\\tself \\n\\t\\t\\t\\tcolorPickerFor: self \\n\\t\\t\\t\\tgetter: #numberOneColor \\n\\t\\t\\t\\tsetter: #numberOneColor:.\\n\\t\\t\\tself lockedString: 'Color' translated.\\n\\t\\t\\t(self paneForSolidFillToggle) hResizing: #shrinkWrap.\\n\\t\\t} \\n\\t\\tnamed: #pickerForColor.\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:21'!\\npaneForRadialGradientToggle\\n\\n\\t^self inARow: {\\n\\t\\tself\\n\\t\\t\\tdirectToggleButtonFor: self \\n\\t\\t\\tgetter: #targetRadial setter: #toggleTargetRadial\\n\\t\\t\\thelp: 'Turn radial gradient on or off' translated.\\n\\t\\tself lockedString: ' Radial gradient' translated.\\n\\t}\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'RAA 3/8/2001 18:03'!\\npaneForShadowColorPicker\\n\\n\\t^self \\n\\t\\tinAColumn: {\\n\\t\\t\\t(self inAColumn: {\\n\\t\\t\\t\\tself colorPickerFor: myTarget getter: #shadowColor setter: #shadowColor:.\\n\\t\\t\\t\\tself paneForShadowOffset.\\n\\t\\t\\t}\\n\\t\\t\\tnamed: #pickerForShadowColor) layoutInset: 0.\\n\\t\\t\\tself paneForDropShadowToggle hResizing: #shrinkWrap.\\n\\t\\t}\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:36'!\\npaneForShadowOffset\\n\\n\\t^(self inARow: {\\n\\t\\tself\\n\\t\\t\\tbuildFakeSlider: 'Offset' translated\\n\\t\\t\\tselector: #adjustTargetShadowOffset:\\n\\t\\t\\thelp: 'Drag in here to change the offset of the shadow' translated\\n\\t}) hResizing: #shrinkWrap\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:20'!\\npaneForSolidFillToggle\\n\\n\\t^self inARow: {\\n\\t\\tself\\n\\t\\t\\tdirectToggleButtonFor: self \\n\\t\\t\\tgetter: #targetHasSolidFill\\n\\t\\t\\tsetter: #toggleTargetSolidFill\\n\\t\\t\\thelp: 'Turn solid fill on or off' translated.\\n\\t\\tself lockedString: ' Solid fill' translated.\\n\\t}\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'dgd 8/31/2003 21:18'!\\npaneForStickinessToggle\\n\\n\\t^self inARow: {\\n\\t\\tself\\n\\t\\t\\tdirectToggleButtonFor: myTarget \\n\\t\\t\\tgetter: #isSticky setter: #toggleStickiness\\n\\t\\t\\thelp: 'Turn stickiness on or off' translated.\\n\\t\\tself lockedString: ' Sticky' translated.\\n\\t}\\n\\n! !\\n\\n!ObjectPropertiesMorph methodsFor: 'panes' stamp: 'ar 8/25/2001 18:35'!\\ntoggleBorderStyle: provider with: arg1 from: arg2\\n\\t| oldStyle newStyle |\\n\\toldStyle _ myTarget borderStyle.\\n\\tnewStyle _ provider borderStyle copy.\\n\\toldStyle width = 0 \\n\\t\\tifTrue:[newStyle width: 2]\\n\\t\\tifFalse:[newStyle width: oldStyle width].\\n\\tnewStyle baseColor: oldStyle baseColor.\\n\\tmyTarget borderStyle: newStyle.\\n\\tprovider owner owner submorphsDo:[:m| m borderWidth: 0].\\n\\tprovider owner borderWidth: 1.! !\\nAlignmentMorph subclass: #ObjectRepresentativeMorph\\n\\tinstanceVariableNames: 'objectRepresented'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting'!\\n\\n!ObjectRepresentativeMorph methodsFor: 'as yet unclassified' stamp: 'ar 11/1/2000 15:55'!\\nobjectRepresented: anObject\\n\\t\\\"Set the receiver's representee. This clears out any preexisting state in the receiver\\\"\\n\\n\\tobjectRepresented _ anObject.\\n\\tself removeAllMorphs.\\n\\tself hResizing: #shrinkWrap. \\n\\tself vResizing: #shrinkWrap.\\n\\tself addMorphBack: (StringMorph new contents: anObject name asString).\\n\\tself setNameTo: anObject name\\n\\t! !\\n\\n!ObjectRepresentativeMorph methodsFor: 'as yet unclassified' stamp: 'ar 11/1/2000 15:55'!\\nobjectRepresented: anObject labelString: aLabel\\n\\t\\\"Set the receiver's representee as indicated, and use the given label to tag it\\\"\\n\\n\\tobjectRepresented _ anObject.\\n\\tself removeAllMorphs.\\n\\tself hResizing: #shrinkWrap. \\n\\tself vResizing: #shrinkWrap.\\n\\tself addMorphBack: (StringMorph new contents: aLabel asString).\\n\\tself setNameTo: aLabel asString\\n\\t! !\\n\\n\\n!ObjectRepresentativeMorph methodsFor: 'macpal' stamp: 'sw 10/17/2000 11:42'!\\nobjectRepresented\\n\\t\\\"Answer the object represented by the receiver\\\"\\n\\n\\t^ objectRepresented! !\\n\\n\\n!ObjectRepresentativeMorph methodsFor: 'naming' stamp: 'sw 10/31/2000 09:22'!\\nnameOfObjectRepresented\\n\\t\\\"Answer the external name of the object represented\\\"\\n\\n\\t^ objectRepresented externalName! !\\n\\n\\n!ObjectRepresentativeMorph methodsFor: 'scripting' stamp: 'sw 10/17/2000 11:35'!\\ncategoriesForViewer\\n\\t\\\"Answer a list of symbols representing the categories to offer in the viewer, in order\\\"\\n\\n\\t^ objectRepresented class organization categories\\n! !\\nObject subclass: #ObjectScanner\\n\\tinstanceVariableNames: 'pvt3SmartRefStrm'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Object Storage'!\\n!ObjectScanner commentStamp: '<historical>' prior: 0!\\nAn instance of this class is the compiler's context for filing in a SmartRefStream containing instance-specific classes. When the old name of a new object's class conflicts with an existing class name, install a class var in me. It has the old name but points at the new class. The compiler uses it when compiling the code in the fileIn. Fill the SmartRefStream's renamed class dictionary.\\n\\nAn object fileout:\\n!!ObjectScanner new initialize!! \\\"allow me to take control with scanFrom:\\\"\\n\\nPlayer subclass: Player23 instanceVariableNames: 'foo' classVariableNames: '' \\n\\tpoolDictionaries: nil category: 'Instance Specific'!!\\n\\t\\\"I prescan this and (self rename: #Player23 toBe: #Player30)\\\"\\n\\n!!Player23 methodsFor: 'all' stamp: 'tk 3/9/98 18:58'!!\\t\\\"actually sent to Player30\\\"\\nfoo\\n\\t^ foo!! !!\\n\\n!!self smartRefStream!!<binary representation of the objects>!!\\n\\n\\n!\\n\\n\\n!ObjectScanner methodsFor: 'accessing' stamp: 'tk 3/15/98 19:33'!\\nsmartRefStream\\n\\n\\t^ pvt3SmartRefStrm! !\\n\\n\\n!ObjectScanner methodsFor: 'initialize-release' stamp: 'tk 3/15/98 20:17'!\\nclear\\n\\t\\\"remove all old class vars. They were UniClasses being remapped to aviod a name conflict.\\\"\\n\\n\\tself class classPool keys do: [:key |\\n\\t\\tself class classPool removeKey: key].\\t\\\"brute force\\\"! !\\n\\n!ObjectScanner methodsFor: 'initialize-release' stamp: 'tk 8/15/1998 15:26'!\\ninitialize\\n\\t\\\"remove all old class vars that are not instance-specific classes being renamed\\\"\\n\\n\\tself clear.\\n\\t\\\"Most importantly, return self, so a fileIn will let ObjectScanner seize control. So UniClasses can be remapped. See the transfer of control where ReadWriteStream fileIn calls scanFrom:\\\"! !\\n\\n\\n!ObjectScanner methodsFor: 'scanning' stamp: 'yo 11/11/2002 10:27'!\\nlookAhead: aChunk\\n\\t\\\"See if this chunk is a class Definition, and if the new class name already exists and is instance-specific. Modify the chunk, and record the rename in the SmartRefStream and in me.\\\"\\n\\n\\t| pieces sup oldName existing newName newDefn |\\n\\taChunk size < 90 ifTrue: [^ aChunk].\\t\\t\\\"class defn is big!!\\\"\\n\\t(aChunk at: 1) == $!! ifTrue: [^ aChunk].\\t\\\"method def, fast exit\\\"\\n\\tpieces _ (aChunk copyFrom: 1 to: (300 min: aChunk size)) findTokens: ' #\\t\\\\' withCRs.\\n\\tpieces size < 3 ifTrue: [^ aChunk].\\t\\\"really bigger, but just took front\\\"\\n\\t(pieces at: 2) = 'subclass:' ifFalse: [^ aChunk].\\n\\tsup _ Smalltalk at: (pieces at: 1) asSymbol ifAbsent: [^ aChunk].\\n\\tsup class class == Metaclass ifFalse: [^ aChunk].\\n\\t((oldName _ pieces at: 3) at: 1) canBeGlobalVarInitial ifFalse: [^ aChunk].\\n\\toldName _ oldName asSymbol.\\n\\t(Smalltalk includesKey: oldName) ifFalse: [^ aChunk].\\t\\\"no conflict\\\"\\n\\texisting _ Smalltalk at: oldName.\\n\\t(existing isKindOf: Class) ifFalse: [^ aChunk].\\t\\\"Write over non-class global\\\"\\n\\texisting isSystemDefined ifTrue: [^ aChunk].\\t\\\"Go ahead and redefine it!!\\\"\\n\\t\\\"Is a UniClass\\\"\\n\\tnewName _ sup chooseUniqueClassName.\\n\\tnewDefn _ aChunk copyReplaceAll: oldName with: newName.\\n\\tCompiler evaluate: newDefn for: self logged: true.\\t\\\"Create the new class\\\"\\n\\tself rename: oldName toBe: newName.\\n\\t^ newName asString\\t\\t\\\"to be evaluated\\\"\\n! !\\n\\n!ObjectScanner methodsFor: 'scanning' stamp: 'tk 3/15/98 20:22'!\\nscanFrom: aByteStream\\n\\t\\\"Sieze control of the fileIn. Put myself in as the context. If any UniClasses (for just one instance) are defined, they will do it through me, and I will look for conflicting class names. If so, install the old name as a class var of me, so the compile will work. Tell my SmartRefStream about renaming the class.\\\"\\n\\n\\t| valWithOddName47 scannerNamed53 chunkNamed117 |\\n\\tpvt3SmartRefStrm _ SmartRefStream on: aByteStream.\\n\\taByteStream ascii.\\n\\t[aByteStream atEnd] whileFalse:\\n\\t\\t[aByteStream skipSeparators.\\n\\t\\tvalWithOddName47 _ (aByteStream peekFor: $!!)\\n\\t\\t\\tifTrue: [chunkNamed117 _ aByteStream nextChunk.\\t\\\"debug\\\"\\n\\t\\t\\t\\t\\tscannerNamed53 _ Compiler evaluate: chunkNamed117\\n\\t\\t\\t\\t\\t\\t\\tfor: self logged: false.\\n\\t\\t\\t\\t\\tscannerNamed53 class == self class \\n\\t\\t\\t\\t\\t\\tifTrue: [\\\"I already am the scanner for this file\\\"]\\n\\t\\t\\t\\t\\t\\tifFalse: [scannerNamed53 scanFrom: aByteStream]]\\n\\t\\t\\tifFalse: [chunkNamed117 _ aByteStream nextChunk.\\n\\t\\t\\t\\t\\tchunkNamed117 _ self lookAhead: chunkNamed117.\\n\\t\\t\\t\\t\\tCompiler evaluate: chunkNamed117 for: self logged: true].\\n\\t\\taByteStream skipStyleChunk].\\n\\t^ valWithOddName47! !\\n\\n\\n!ObjectScanner methodsFor: 'utilities' stamp: 'tk 3/15/98 20:21'!\\nrename: existingName toBe: newName\\n\\t\\\"See if there is a conflict between what the fileIn wants to call the new UniClass (Player23) and what already exists for another unique instance. If conflict, make a class variable to intercept the existingName and direct it to class newName.\\\"\\n\\n\\texistingName = newName ifFalse: [\\n\\t\\tself class ensureClassPool.\\t\\\"create the dictionary\\\"\\n\\t\\t\\\"can't use addClassVarName: because it checks for conflicts with Smalltalk\\\"\\n\\t\\t(self class classPool includesKey: existingName) ifFalse: \\n\\t\\t\\t[\\\"Pick up any refs in Undeclared\\\"\\n\\t\\t\\tself class classPool declare: existingName from: Undeclared].\\n\\t\\tself class classPool at: existingName put: (Smalltalk at: newName).\\n\\t\\tpvt3SmartRefStrm renamed at: existingName put: newName]! !\\nStream subclass: #ObjectSocket\\n\\tinstanceVariableNames: 'socket outBuf outBufIndex outBufSize inBuf inBufIndex inBufLastIndex outObjects inObjects'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Network-ObjectSocket'!\\n!ObjectSocket commentStamp: 'ls 2/10/2005 21:27' prior: 0!\\nThis is a socket which exchanges medium-level packets instead of low-level bytes. This class is abstract; see the subclasses for particular kinds of medium-level packets which can be used.!\\n\\n\\n!ObjectSocket methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\ndestroy\\n\\tsocket destroy.\\n\\tsocket := nil.! !\\n\\n!ObjectSocket methodsFor: 'as yet unclassified' stamp: 'RAA 7/20/2000 15:10'!\\nisConnected\\n\\n\\t^socket notNil and: [socket isConnected]! !\\n\\n!ObjectSocket methodsFor: 'as yet unclassified' stamp: 'ls 1/8/1999 16:14'!\\nprocessIO\\n\\t\\\"do some as much network IO as possible\\\"\\n\\n\\tself processOutput.\\n\\tself processInput.! !\\n\\n!ObjectSocket methodsFor: 'as yet unclassified' stamp: 'RAA 8/4/2000 15:38'!\\nremoteAddress\\n\\n\\tself isConnected ifFalse: [^nil].\\n\\t^socket remoteAddress! !\\n\\n\\n!ObjectSocket methodsFor: 'encoding/decoding' stamp: 'sd 11/20/2005 21:26'!\\naddToInBuf: aString\\n\\n\\t| newAlloc |\\n\\tnewAlloc := aString size * 2 max: 8000.\\n\\tinBuf ifNil: [\\n\\t\\tinBuf := String new: newAlloc.\\n\\t\\tinBufIndex := 1.\\n\\t\\tinBufLastIndex := 0.\\n\\t].\\n\\taString size > (inBuf size - inBufLastIndex) ifTrue: [\\n\\t\\tinBuf := inBuf , (String new: newAlloc)\\n\\t].\\n\\tinBuf \\n\\t\\treplaceFrom: inBufLastIndex + 1 \\n\\t\\tto: inBufLastIndex + aString size\\n\\t\\twith: aString \\n\\t\\tstartingAt: 1.\\n\\tinBufLastIndex := inBufLastIndex + aString size.\\n! !\\n\\n!ObjectSocket methodsFor: 'encoding/decoding' stamp: 'sd 11/20/2005 21:26'!\\nprocessOutput\\n\\t\\\"loop sending data as long as there is data to send, and the socket is ready to receive more data\\\"\\n\\t[ socket sendDone and: [ outBuf notNil or: [ outObjects isEmpty not ] ] ] whileTrue: [\\n\\t\\t| amountSent |\\n\\n\\t\\toutBuf isNil ifTrue: [\\n\\t\\t\\t| nextSize |\\n\\t\\t\\t\\\"no data in the current buffer; make a new buffer and encode some more\\\"\\n\\t\\t\\toutBuf := String new: ((self spaceToEncode: outObjects first) max: 8000).\\n\\t\\t\\toutBufIndex := 1.\\n\\t\\t\\toutBufSize := 0.\\n\\n\\t\\t\\t[\\toutObjects isEmpty not and: [\\n\\t\\t\\t\\t\\tnextSize := self spaceToEncode: outObjects first.\\n\\t\\t\\t\\t\\tnextSize <= (outBuf size - outBufSize + 1) ]\\n\\t\\t\\t] whileTrue: [\\n\\t\\t\\t\\tself encodeObject: outObjects first into: outBuf startingAt: outBufSize+1.\\n\\t\\t\\t\\toutBufSize := outBufSize + nextSize.\\n\\t\\t\\t\\toutObjects removeFirst ] ].\\n\\n\\t\\t\\\"at this point, the buffer definitely has data in it to send. Send some\\\"\\n\\t\\tamountSent := socket sendSomeData: outBuf startIndex: outBufIndex count: (outBufSize - outBufIndex + 1).\\n\\t\\toutBufIndex := outBufIndex + amountSent.\\n\\t\\toutBufIndex > outBufSize ifTrue: [ outBuf := nil ] ].\\n\\n! !\\n\\n!ObjectSocket methodsFor: 'encoding/decoding' stamp: 'sd 11/20/2005 21:26'!\\nshrinkInBuf\\n\\n\\tinBuf ifNil: [^self].\\n\\tinBufLastIndex < inBufIndex ifTrue: [\\n\\t\\tinBufLastIndex := 0.\\n\\t\\tinBufIndex := 1.\\n\\t\\tinBuf size > 20000 ifTrue: [inBuf := nil].\\t\\\"if really big, kill it\\\"\\n\\t\\t^self\\n\\t].\\n\\tinBuf := inBuf copyFrom: inBufIndex to: inBufLastIndex.\\n\\tinBufLastIndex := inBuf size.\\n\\tinBufIndex := 1.\\n\\n! !\\n\\n\\n!ObjectSocket methodsFor: 'stream protocol' stamp: 'ls 4/25/2000 18:48'!\\nnext\\n\\t^inObjects removeFirst\\t! !\\n\\n!ObjectSocket methodsFor: 'stream protocol' stamp: 'ls 4/25/2000 18:48'!\\nnextOrNil\\n\\tinObjects isEmpty\\n\\t\\tifTrue: [ ^nil ]\\n\\t\\tifFalse: [ ^inObjects removeFirst ]! !\\n\\n!ObjectSocket methodsFor: 'stream protocol' stamp: 'ls 4/25/2000 18:48'!\\nnextPut: anObject\\n\\toutObjects addLast: anObject! !\\n\\n\\n!ObjectSocket methodsFor: 'private-initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitialize: aSocket\\n\\tsocket := aSocket.\\n\\tinBuf := String new: 1000.\\n\\tinBufIndex := 1.\\n\\tinBufLastIndex := 0.\\n\\n\\toutBuf := nil.\\n\\n\\tinObjects := OrderedCollection new.\\n\\toutObjects := OrderedCollection new.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nObjectSocket class\\n\\tinstanceVariableNames: ''!\\n\\n!ObjectSocket class methodsFor: 'as yet unclassified' stamp: 'RAA 7/20/2000 15:47'!\\non: aSocket\\n\\n\\t^self basicNew initialize: aSocket! !\\nClassTestCase subclass: #ObjectTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'KernelTests-Objects'!\\n\\n!ObjectTest methodsFor: 'tests' stamp: 'md 11/26/2004 16:37'!\\ntestBecome\\n\\t\\\"self debug: #testBecome\\\"\\n\\t\\\"this test should that all the variables pointing to an object are pointing now to another one, and all\\n object pointing to the other are pointing to the object\\\"\\n\\n\\t| pt1 pt2 pt3 |\\n\\tpt1 := 0@0.\\n\\tpt2 := pt1.\\n\\tpt3 := 100@100.\\n\\n\\tpt1 become: pt3.\\n\\tself assert: pt2 = (100@100).\\n\\tself assert: pt3 = (0@0).\\n\\tself assert: pt1 = (100@100).! !\\n\\n!ObjectTest methodsFor: 'tests' stamp: 'md 11/26/2004 16:36'!\\ntestBecomeForward\\n\\t\\\"self debug: #testBecomeForward\\\"\\n\\t\\\"this test should that all the variables pointing to an object are pointing now to another one.\\n\\tNot that this inverse is not true. This kind of become is called oneWayBecome in VW\\\"\\n\\n\\t| pt1 pt2 pt3 |\\n\\tpt1 := 0@0.\\n\\tpt2 := pt1.\\n\\tpt3 := 100@100.\\n\\tpt1 becomeForward: pt3.\\n\\tself assert: pt2 = (100@100).\\n\\tself assert: pt3 == pt2.\\n\\tself assert: pt1 = (100@100)! !\\n\\n\\n!ObjectTest methodsFor: 'tests - debugging' stamp: 'sd 6/5/2005 09:05'!\\ntestAssert\\n\\n\\tself shouldnt: [Object assert: [true]] raise: Error.\\n\\tself shouldnt: [Object assert: true] raise: Error.\\n\\tself should: [Object assert: [false]] raise: AssertionFailure.\\n\\tself should: [Object assert: false] raise: AssertionFailure.! !\\n\\n!ObjectTest methodsFor: 'tests - debugging' stamp: 'sd 6/5/2005 09:05'!\\ntestHaltIf\\n\\n\\tself should: [self haltIf: true] raise: Halt.\\n\\tself shouldnt: [self haltIf: false] raise: Halt.\\n\\n\\tself should: [self haltIf: [true]] raise: Halt.\\n\\tself shouldnt: [self haltIf: [false]] raise: Halt.\\n\\n\\tself should: [self haltIf: #testHaltIf.] raise: Halt.\\n\\tself shouldnt: [self haltIf: #teadfasdfltIf.] raise: Halt.\\n\\n\\tself should: [self a] raise: Halt.\\n\\tself shouldnt: [self a1] raise: Halt.\\n\\n\\tself should: [self haltIf: [:o | o class = self class]] raise: Halt.\\n\\tself shouldnt: [self haltIf: [:o | o class ~= self class]] raise: Halt.\\n! !\\n\\n\\n!ObjectTest methodsFor: 'private' stamp: 'md 10/15/2004 13:45'!\\na\\n\\tself b.! !\\n\\n!ObjectTest methodsFor: 'private' stamp: 'md 10/15/2004 13:46'!\\na1\\n\\tself b1.! !\\n\\n!ObjectTest methodsFor: 'private' stamp: 'md 10/15/2004 13:45'!\\nb\\n\\tself haltIf: #testHaltIf.! !\\n\\n!ObjectTest methodsFor: 'private' stamp: 'md 10/15/2004 13:46'!\\nb1\\n\\tself haltIf: #testasdasdfHaltIf.! !\\nProtoObject subclass: #ObjectTracer\\n\\tinstanceVariableNames: 'tracedObject recursionFlag'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Objects'.\\nObjectTracer superclass: nil!\\n!ObjectTracer commentStamp: '<historical>' prior: 0!\\nAn ObjectTracer can be wrapped around another object, and then give you a chance to inspect it whenever it receives messages from the outside. For instance...\\n\\t(ObjectTracer on: Display) flash: (50@50 extent: 50@50)\\nwill give control to a debugger just before the message flash is sent.\\nObviously this facility can be embellished in many useful ways.\\nSee also the even more perverse subclass, ObjectViewer, and its example.\\n!\\n\\n\\n!ObjectTracer methodsFor: 'very few messages' stamp: 'ar 9/27/2005 20:24'!\\ndoesNotUnderstand: aMessage \\n\\t\\\"All external messages (those not caused by the re-send) get trapped here\\\"\\n\\t\\\"Present a dubugger before proceeding to re-send the message\\\"\\n\\n\\tToolSet debugContext: thisContext\\n\\t\\t\\t\\tlabel: 'About to perform: ', aMessage selector\\n\\t\\t\\t\\tcontents: nil.\\n\\t^ aMessage sentTo: tracedObject.\\n! !\\n\\n!ObjectTracer methodsFor: 'very few messages'!\\nxxxUnTrace\\n\\n\\ttracedObject become: self! !\\n\\n!ObjectTracer methodsFor: 'very few messages'!\\nxxxViewedObject\\n\\t\\\"This message name must not clash with any other (natch).\\\"\\n\\t^ tracedObject! !\\n\\n!ObjectTracer methodsFor: 'very few messages'!\\nxxxViewedObject: anObject\\n\\t\\\"This message name must not clash with any other (natch).\\\"\\n\\ttracedObject _ anObject! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nObjectTracer class\\n\\tinstanceVariableNames: ''!\\n\\n!ObjectTracer class methodsFor: 'instance creation'!\\non: anObject\\n\\t^ self new xxxViewedObject: anObject! !\\nObjectTracer subclass: #ObjectViewer\\n\\tinstanceVariableNames: 'valueBlock lastValue changeBlock'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Objects'!\\n!ObjectViewer commentStamp: '<historical>' prior: 0!\\nObjectViewers offers the same kind of interception of messages (via doesnotUnderstand:) as ObjectTracers, but instead of just being wrappers, they actually replace the object being viewed. This makes them a lot more dangerous to use, but one can do amazing things. For instance, the example below actually intercepts the InputSensor object, and prints the mouse coordinates asynchronously, every time they change:\\n\\tSensor evaluate: [Sensor cursorPoint printString displayAt: 0@0]\\n\\t\\twheneverChangeIn: [Sensor cursorPoint].\\nTo exit from this example, execute:\\n\\tSensor xxxUnTrace\\n!\\n\\n\\n!ObjectViewer methodsFor: 'very few messages'!\\ndoesNotUnderstand: aMessage \\n\\t\\\"Check for change after sending aMessage\\\"\\n\\t| returnValue newValue |\\n\\trecursionFlag ifTrue: [^ aMessage sentTo: tracedObject].\\n\\trecursionFlag _ true.\\n\\treturnValue _ aMessage sentTo: tracedObject.\\n\\tnewValue _ valueBlock value.\\n\\tnewValue = lastValue ifFalse:\\n\\t\\t[changeBlock value.\\n\\t\\tlastValue _ newValue].\\n\\trecursionFlag _ false.\\n\\t^ returnValue! !\\n\\n!ObjectViewer methodsFor: 'very few messages'!\\nxxxViewedObject: viewedObject evaluate: block1 wheneverChangeIn: block2\\n\\t\\\"This message name must not clash with any other (natch).\\\"\\n\\ttracedObject _ viewedObject.\\n\\tvalueBlock _ block2.\\n\\tchangeBlock _ block1.\\n\\trecursionFlag _ false! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nObjectViewer class\\n\\tinstanceVariableNames: ''!\\n\\n!ObjectViewer class methodsFor: 'instance creation'!\\non: viewedObject evaluate: block1 wheneverChangeIn: block2\\n\\t^ self new xxxViewedObject: viewedObject evaluate: block1 wheneverChangeIn: block2! !\\nObject subclass: #ObjectWithDocumentation\\n\\tinstanceVariableNames: 'authoringStamp properties elementSymbol naturalLanguageTranslations'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Protocols-Kernel'!\\n!ObjectWithDocumentation commentStamp: '<historical>' prior: 0!\\nObjectWithDocumentation - an abstract superclass for objects that allows maintenance of an authoring stamp, a body of documentation, and a properties dictionary.\\nThe Properties implementation has not happened yet -- it would closely mirror the implemenation of properties in the MorphExtension, for example.!\\n\\n\\n!ObjectWithDocumentation methodsFor: 'accessing' stamp: 'mir 7/12/2004 21:21'!\\ndocumentation\\n\\t\\\"Answer the receiver's documentation\\\"\\n\\n\\t^self helpMessage! !\\n\\n!ObjectWithDocumentation methodsFor: 'accessing' stamp: 'mir 7/12/2004 19:33'!\\ndocumentation: somethingUsefulHopefully\\n\\t\\\"Set the receiver's documentation, in the current langauge\\\"\\n\\n\\tself helpMessage: somethingUsefulHopefully! !\\n\\n!ObjectWithDocumentation methodsFor: 'accessing' stamp: 'sw 8/18/2004 20:23'!\\nhelpMessage\\n\\t\\\"Check if there is a getterSetterHelpMessage. \\n\\tOtherwise try the normal help message or return nil.\\\"\\n\\n\\t^ self getterSetterHelpMessage\\n\\t\\tifNil: [(self propertyAt: #helpMessage ifAbsent:\\n\\t\\t\\t[self legacyHelpMessage ifNil: [^ nil]]) translated]! !\\n\\n!ObjectWithDocumentation methodsFor: 'accessing' stamp: 'mir 7/12/2004 19:32'!\\nhelpMessage: somethingUsefulHopefully\\n\\t\\\"Set the receiver's documentation, in the current langauge\\\"\\n\\n\\tself propertyAt: #helpMessage put: somethingUsefulHopefully! !\\n\\n!ObjectWithDocumentation methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:39'!\\nlegacyHelpMessage\\n\\t\\\"If I have a help message stashed in my legacy naturalTranslations slot, answer its translated rendition, else answer nil. If I *do* come across a legacy help message, transfer it to my properties dictionary.\\\"\\n\\n\\t| untranslated |\\n\\tnaturalLanguageTranslations isEmptyOrNil \\\"only in legacy (pre-3.8) projects\\\"\\n\\t\\tifTrue: [^ nil].\\n\\tuntranslated := naturalLanguageTranslations first helpMessage ifNil: [^ nil].\\n\\tself propertyAt: #helpMessage put: untranslated.\\n\\tnaturalLanguageTranslations removeFirst.\\n\\tnaturalLanguageTranslations isEmpty ifTrue: [naturalLanguageTranslations := nil].\\n\\t^ untranslated translated! !\\n\\n!ObjectWithDocumentation methodsFor: 'accessing' stamp: 'mir 7/12/2004 23:57'!\\nuntranslatedHelpMessage\\n\\t\\\"Check if there is a getterSetterHelpMessage. \\n\\tOtherwise try the normal help message or return nil.\\\"\\n\\n\\t^(self propertyAt: #getterSetterHelpMessage ifAbsent: [nil])\\n\\t\\tifNil: [(self propertyAt: #helpMessage ifAbsent: [nil])]! !\\n\\n!ObjectWithDocumentation methodsFor: 'accessing' stamp: 'mir 7/12/2004 23:56'!\\nuntranslatedWording\\n\\t\\\"Answer the receiver's wording\\\"\\n\\n\\t^self propertyAt: #wording ifAbsent: [nil]! !\\n\\n!ObjectWithDocumentation methodsFor: 'accessing' stamp: 'mir 7/12/2004 21:34'!\\nwording\\n\\t\\\"Answer the receiver's wording\\\"\\n\\n\\t| wording |\\n\\t(wording := self propertyAt: #wording ifAbsent: [nil])\\n\\t\\tifNotNil: [^wording translated].\\n\\n\\tself initWordingAndDocumentation.\\n\\t^self propertyAt: #wording ifAbsent: ['']! !\\n\\n!ObjectWithDocumentation methodsFor: 'accessing' stamp: 'mir 7/12/2004 21:39'!\\nwording: aString\\n\\t\\\"Set the receiver's wording, in the current langauge\\\"\\n\\n\\tself propertyAt: #wording put: aString! !\\n\\n\\n!ObjectWithDocumentation methodsFor: 'documentation' stamp: 'rbb 3/1/2005 11:02'!\\neditDescription\\n\\t\\\"Allow the user to see and edit the documentation for this object\\\"\\n\\t| reply helpMessage |\\n\\thelpMessage := self documentation isNil\\n\\t\\t\\t\\tifTrue: [String new]\\n\\t\\t\\t\\tifFalse: [self documentation].\\n\\treply := UIManager default\\n\\t\\t\\t\\tmultiLineRequest: 'Kindly edit the description' translated\\n\\t\\t\\t\\tcenterAt: Sensor cursorPoint\\n\\t\\t\\t\\tinitialAnswer: helpMessage\\n\\t\\t\\t\\tanswerHeight: 200.\\n\\treply isEmptyOrNil\\n\\t\\tifFalse: [self documentation: reply]! !\\n\\n\\n!ObjectWithDocumentation methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:39'!\\ninitialize\\n\\t\\\"Initialize the receiver (automatically called when instances are created via 'new')\\\"\\n\\n\\tauthoringStamp := Utilities changeStampPerSe\\n! !\\n\\n\\n!ObjectWithDocumentation methodsFor: 'migration' stamp: 'mir 7/12/2004 23:45'!\\nmigrateWordAndHelpMessage\\n\\t\\\"Migrate the English wording and help message to the new structure\\\"\\n\\n\\t| englishElement |\\n\\tself initWordingAndDocumentation.\\n\\t(self properties includes: #wording)\\n\\t\\tifFalse: [\\n\\t\\t\\tenglishElement := self naturalLanguageTranslations\\n\\t\\t\\t\\tdetect: [:each | each language == #English] ifNone: [^nil].\\n\\t\\t\\tself wording: englishElement wording.\\n\\t\\t\\tself helpMessage: englishElement helpMessage]! !\\n\\n\\n!ObjectWithDocumentation methodsFor: 'miscellaneous' stamp: 'sw 9/12/2001 23:03'!\\nelementSymbol\\n\\t\\\"Answer the receiver's element symbol\\\"\\n\\n\\t^ elementSymbol! !\\n\\n!ObjectWithDocumentation methodsFor: 'miscellaneous' stamp: 'mir 7/12/2004 23:20'!\\nnaturalLanguageTranslations\\n\\t^naturalLanguageTranslations ifNil: [OrderedCollection new]! !\\n\\n\\n!ObjectWithDocumentation methodsFor: 'private' stamp: 'mir 7/12/2004 21:28'!\\ngetterSetterHelpMessage\\n\\t\\\"Returns a helpMessage that has been computed previously and needs to be translated and then formatted with the elementSymbol.\\n\\t'get value of {1}' translated format: {elSym}\\\"\\n\\n\\t^(self propertyAt: #getterSetterHelpMessage ifAbsent: [^nil])\\n\\t\\ttranslated format: {self elementSymbol}! !\\n\\n!ObjectWithDocumentation methodsFor: 'private' stamp: 'mir 7/12/2004 21:29'!\\ngetterSetterHelpMessage: aString\\n\\t\\\"Sets a helpMessage that needs to be translated and then formatted with the elementSymbol.\\n\\t'get value of {1}' translated format: {elSym}\\\"\\n\\n\\tself propertyAt: #getterSetterHelpMessage put: aString! !\\n\\n!ObjectWithDocumentation methodsFor: 'private' stamp: 'mir 7/12/2004 21:31'!\\ninitWordingAndDocumentation\\n\\t\\\"Initialize wording and documentation (helpMessage) for getters and setters\\\"\\n\\n\\t| elSym |\\n\\telSym := self elementSymbol.\\n\\telSym\\n\\t\\tifNil: [^self].\\n\\n\\t((elSym beginsWith: 'get')\\n\\t\\tand: [elSym size > 3])\\n\\t\\tifTrue: [\\n\\t\\t\\tself wording: (elSym allButFirst: 3) withFirstCharacterDownshifted.\\n\\t\\t\\tself getterSetterHelpMessage: 'get value of {1}']\\n\\t\\tifFalse: [\\n\\t\\t\\t((elSym beginsWith: 'set')\\n\\t\\t\\t\\tand: [elSym size > 4])\\n\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\tself wording: (elSym allButFirst: 3) withFirstCharacterDownshifted.\\n\\t\\t\\t\\t\\tself getterSetterHelpMessage: 'set value of {1}']]! !\\n\\n!ObjectWithDocumentation methodsFor: 'private' stamp: 'mir 7/12/2004 19:30'!\\nproperties\\n\\t^properties ifNil: [properties := Dictionary new]! !\\n\\n!ObjectWithDocumentation methodsFor: 'private' stamp: 'mir 7/12/2004 19:30'!\\npropertyAt: key\\n\\t^self propertyAt: key ifAbsent: [nil]! !\\n\\n!ObjectWithDocumentation methodsFor: 'private' stamp: 'mir 7/12/2004 19:29'!\\npropertyAt: key ifAbsent: aBlock\\n\\t^properties\\n\\t\\tifNil: aBlock\\n\\t\\tifNotNil: [properties at: key ifAbsent: aBlock]! !\\n\\n!ObjectWithDocumentation methodsFor: 'private' stamp: 'mir 7/12/2004 19:29'!\\npropertyAt: key put: aValue\\n\\tself properties at: key put: aValue! !\\nAbstractObjectsAsMethod subclass: #ObjectsAsMethodsExample\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tests-ObjectsAsMethods'!\\n\\n!ObjectsAsMethodsExample methodsFor: 'as yet unclassified' stamp: 'ar 5/17/2003 20:16'!\\nadd: a with: b\\n\\t^a + b! !\\n\\n!ObjectsAsMethodsExample methodsFor: 'as yet unclassified' stamp: 'ar 5/17/2003 20:16'!\\nanswer42\\n\\t^42! !\\n\\n!ObjectsAsMethodsExample methodsFor: 'as yet unclassified' stamp: 'md 3/1/2006 19:37'!\\nrun: oldSelector with: arguments in: aReceiver\\n\\t^self perform: oldSelector withArguments: arguments! !\\nAlignmentMorph subclass: #ObjectsTool\\n\\tinstanceVariableNames: 'searchString modeSymbol'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-PartsBin'!\\n!ObjectsTool commentStamp: '<historical>' prior: 0!\\nI am a Master Parts Bin that allows the user to drag out a new Morph from a voluminous iconic list.\\n\\nChoose \\\"objects\\\" from the world menu, or type Alt-o (Cmd-o on the Mac).\\n\\nTo add a new kinds of Morphs:\\nIn the class of the Morph, implement the message:\\n\\ndescriptionForPartsBin\\n\\t^ self partName:\\t'Rectangle'\\n\\t\\tcategories:\\t\\t#('Graphics' ' Basic 1 ')\\n\\t\\tdocumentation:\\t'A rectangular shape, with border and fill style'\\n\\nThe partName is the title that will show in the lower pane of the Object Tool.\\nWhen is categories mode, an object can be seen in more than one category. The list above tells which ones.\\nDocumentation is what will show in the balloon help for each object thumbnail.\\nThe message #initializeToStandAlone creates the actual instance.\\n\\nTo make a second variant object prototype coming from the same class, implement #supplementaryPartsDescriptions. In it, you get to specify the nativitySelector. It is sent to the class to get the variant objects. Often it is #authoringPrototype. (A class may supply supplementaryPartsDescriptions without implementing descriptionForPartsBin. This gives you better control.)\\n\\n!\\n\\n\\n!ObjectsTool methodsFor: 'alphabetic' stamp: 'dgd 4/4/2006 16:43'!\\nalphabeticTabs\\n\\t\\\"Answer a list of buttons which, when hit, will trigger the choice of a morphic category\\\"\\n\\n\\t| buttonList aButton tabLabels |\\n\\n\\tself flag: #todo. \\\"includes non-english characters\\\"\\n\\ttabLabels _ (($a to: $z) collect: [:ch | ch asString]) asOrderedCollection.\\n\\n\\tbuttonList _ tabLabels collect:\\n\\t\\t[:catName |\\n\\t\\t\\taButton _ SimpleButtonMorph new label: catName.\\n\\t\\t\\taButton actWhen: #buttonDown.\\n\\t\\t\\taButton target: self; actionSelector: #showAlphabeticCategory:fromButton:; arguments: {catName. aButton}].\\n\\t^ buttonList\\n\\n\\\"ObjectsTool new tabsForMorphicCategories\\\"! !\\n\\n!ObjectsTool methodsFor: 'alphabetic' stamp: 'nk 9/3/2004 13:47'!\\ninstallQuads: quads fromButton: aButton\\n\\t\\\"Install items in the bottom pane that correspond to the given set of quads, as triggered from the given button\\\"\\n\\n\\t| aPartsBin sortedQuads oldResizing |\\n\\taPartsBin _ self partsBin.\\n\\toldResizing := aPartsBin vResizing.\\n\\taPartsBin removeAllMorphs.\\n\\tsortedQuads _ (PartsBin translatedQuads: quads)\\n\\t\\t\\t\\t\\t\\t\\tasSortedCollection: [:a :b | a third < b third].\\n\\taPartsBin listDirection: #leftToRight quadList: sortedQuads.\\n\\taButton ifNotNil: [self tabsPane highlightOnlySubmorph: aButton].\\n\\taPartsBin vResizing: oldResizing.\\n\\taPartsBin layoutChanged; fullBounds.\\n\\tself isFlap ifFalse: [ self minimizePartsBinSize ].! !\\n\\n!ObjectsTool methodsFor: 'alphabetic' stamp: 'nk 9/3/2004 12:13'!\\nshowAlphabeticTabs\\n\\t\\\"Switch to the mode of showing alphabetic tabs\\\"\\n\\n\\tmodeSymbol == #alphabetic ifTrue: [ ^self ].\\n\\tself partsBin removeAllMorphs.\\n\\tself initializeWithTabs: self alphabeticTabs.\\n\\tself modeSymbol: #alphabetic.\\n\\tself tabsPane submorphs first doButtonAction! !\\n\\n\\n!ObjectsTool methodsFor: 'categories' stamp: 'nk 9/3/2004 13:43'!\\nshowCategories\\n\\t\\\"Set the receiver up so that it shows tabs for each of the standard categories\\\"\\n\\n\\tmodeSymbol == #categories ifTrue: [ ^self ].\\n\\n\\tself partsBin removeAllMorphs.\\n\\tself initializeWithTabs: self tabsForCategories.\\n\\tself modeSymbol: #categories.\\n\\tself tabsPane submorphs first doButtonAction.\\n! !\\n\\n!ObjectsTool methodsFor: 'categories' stamp: 'nk 9/3/2004 13:51'!\\nshowCategory: aCategoryName fromButton: aButton \\n\\t\\\"Project items from the given category into my lower pane\\\"\\n\\t| quads |\\n\\tself partsBin removeAllMorphs.\\n\\tCursor wait\\n\\t\\tshowWhile: [quads := OrderedCollection new.\\n\\t\\t\\tMorph withAllSubclasses\\n\\t\\t\\t\\tdo: [:aClass | aClass theNonMetaClass\\n\\t\\t\\t\\t\\t\\taddPartsDescriptorQuadsTo: quads\\n\\t\\t\\t\\t\\t\\tif: [:aDescription | aDescription translatedCategories includes: aCategoryName]].\\n\\t\\t\\tquads := quads\\n\\t\\t\\t\\t\\t\\tasSortedCollection: [:q1 :q2 | q1 third <= q2 third].\\n\\t\\t\\tself installQuads: quads fromButton: aButton]! !\\n\\n!ObjectsTool methodsFor: 'categories' stamp: 'nk 8/23/2004 18:18'!\\ntabsForCategories\\n\\t\\\"Answer a list of buttons which, when hit, will trigger the choice of a category\\\"\\n\\n\\t| buttonList aButton classes categoryList basic |\\n\\tclasses _ Morph withAllSubclasses.\\n\\tcategoryList _ Set new.\\n\\tclasses do: [:aClass |\\n\\t\\t(aClass class includesSelector: #descriptionForPartsBin) ifTrue:\\n\\t\\t\\t[categoryList addAll: aClass descriptionForPartsBin translatedCategories].\\n\\t\\t(aClass class includesSelector: #supplementaryPartsDescriptions) ifTrue:\\n\\t\\t\\t[aClass supplementaryPartsDescriptions do:\\n\\t\\t\\t\\t[:aDescription | categoryList addAll: aDescription translatedCategories]]].\\n\\n\\tcategoryList _ OrderedCollection withAll: (categoryList asSortedArray).\\n\\t\\n\\tbasic := categoryList remove: ' Basic' translated ifAbsent: [ ].\\n\\tbasic ifNotNil: [ categoryList addFirst: basic ].\\n\\n\\tbasic := categoryList remove: 'Basic' translated ifAbsent: [ ].\\n\\tbasic ifNotNil: [ categoryList addFirst: basic ].\\n\\n\\tbuttonList _ categoryList collect:\\n\\t\\t[:catName |\\n\\t\\t\\taButton _ SimpleButtonMorph new label: catName.\\n\\t\\t\\taButton actWhen: #buttonDown.\\n\\t\\t\\taButton target: self; actionSelector: #showCategory:fromButton:; arguments: {catName. aButton}].\\n\\t^ buttonList\\n\\n\\\"ObjectsTool new tabsForCategories\\\"! !\\n\\n\\n!ObjectsTool methodsFor: 'initialization' stamp: 'nk 9/3/2004 13:46'!\\ninitializeForFlap\\n\\t\\\"Initialize the receiver to operate in a flap at the top of the screen.\\\"\\n\\n\\t\\\"\\n\\tFlaps newObjectsFlap openInWorld\\n\\t\\\"\\n\\n\\t| buttonPane aBin aColor heights tabsPane |\\n\\tself basicInitialize.\\n\\n\\tself layoutInset: 0;\\n\\t\\tlayoutPolicy: ProportionalLayout new;\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #rigid;\\n\\t\\tborderWidth: 2; borderColor: Color darkGray;\\n\\t\\textent: (self minimumWidth @ self minimumHeight).\\n\\n\\t\\\"mode buttons\\\"\\n\\tbuttonPane := self paneForTabs: self modeTabs.\\n\\tbuttonPane\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tsetNameTo: 'ButtonPane';\\n\\t\\tcolor: (aColor := buttonPane color) darker;\\n\\t\\tlayoutInset: 6;\\n\\t\\twrapDirection: nil;\\n\\t\\twidth: self width;\\n\\t\\tlayoutChanged; fullBounds.\\n\\n\\t\\\"Place holder for a tabs or text pane\\\"\\n\\ttabsPane := Morph new\\n\\t\\tsetNameTo: 'TabPane';\\n\\t\\thResizing: #spaceFill;\\n\\t\\tyourself.\\n\\n\\theights := { buttonPane height. 40 }.\\n\\n\\tbuttonPane vResizing: #spaceFill.\\n\\tself\\n\\t\\taddMorph: buttonPane\\n\\t\\tfullFrame: (LayoutFrame\\n\\t\\t\\t\\tfractions: (0 @ 0 corner: 1 @ 0)\\n\\t\\t\\t\\toffsets: (0 @ 0 corner: 0 @ heights first)).\\n\\n\\tself\\n\\t\\taddMorph: tabsPane\\n\\t\\tfullFrame: (LayoutFrame\\n\\t\\t\\t\\tfractions: (0 @ 0 corner: 1 @ 0)\\n\\t\\t\\t\\toffsets: (0 @ heights first corner: 0 @ (heights first + heights second))).\\n\\n\\taBin := (PartsBin newPartsBinWithOrientation: #leftToRight from: #())\\n\\t\\tlistDirection: #leftToRight;\\n\\t\\twrapDirection: #topToBottom;\\n\\t\\tcolor: aColor lighter lighter;\\n\\t\\tsetNameTo: 'Parts';\\n\\t\\tdropEnabled: false;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\tyourself.\\n\\n\\tself\\n\\t\\taddMorph: aBin\\n\\t\\tfullFrame: (LayoutFrame\\n\\t\\t\\t\\tfractions: (0 @ 0 corner: 1 @ 1)\\n\\t\\t\\t\\toffsets: (0 @ (heights first + heights second) corner: 0 @ 0)).\\n\\n\\taBin color: (Color orange muchLighter);\\n\\t\\tsetNameTo: 'Objects' translated.\\n\\n\\tself color: (Color orange muchLighter);\\n\\t\\tsetNameTo: 'Objects' translated.\\n! !\\n\\n!ObjectsTool methodsFor: 'initialization' stamp: 'dgd 4/4/2006 16:47'!\\ninitializeToStandAlone\\n\\t\\\"Initialize the receiver so that it can live as a stand-alone morph\\\"\\n\\t| buttonPane aBin aColor heights tabsPane |\\n\\tself basicInitialize.\\n\\n\\tself layoutInset: 0;\\n\\t\\tlayoutPolicy: ProportionalLayout new;\\n\\t\\tuseRoundedCorners;\\n\\t\\thResizing: #rigid;\\n\\t\\tvResizing: #rigid;\\n\\t\\textent: (self minimumWidth @ self minimumHeight).\\n\\n\\t\\\"mode buttons\\\"\\n\\tbuttonPane := self paneForTabs: self modeTabs.\\n\\tbuttonPane color: ColorTheme current dialogColor.\\n\\tbuttonPane\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tsetNameTo: 'ButtonPane';\\n\\t\\taddMorphFront: self dismissButton;\\n\\t\\taddMorphBack: self helpButton;\\n\\t\\tcolor: (aColor := buttonPane color) darker;\\n\\t\\tlayoutInset: 5;\\n\\t\\twrapDirection: nil;\\n\\t\\twidth: self width;\\n\\t\\tlayoutChanged; fullBounds.\\n\\n\\t\\\"Place holder for a tabs or text pane\\\"\\n\\ttabsPane := Morph new.\\n\\ttabsPane\\n\\t\\tcolor: ColorTheme current dialogColor;\\n\\t\\tsetNameTo: 'TabPane';\\n\\t\\thResizing: #spaceFill.\\n\\n\\theights := { buttonPane height. 40 }.\\n\\n\\tbuttonPane vResizing: #spaceFill.\\n\\tself\\n\\t\\taddMorph: buttonPane\\n\\t\\tfullFrame: (LayoutFrame\\n\\t\\t\\t\\tfractions: (0 @ 0 corner: 1 @ 0)\\n\\t\\t\\t\\toffsets: (0 @ 0 corner: 0 @ heights first)).\\n\\n\\tself\\n\\t\\taddMorph: tabsPane\\n\\t\\tfullFrame: (LayoutFrame\\n\\t\\t\\t\\tfractions: (0 @ 0 corner: 1 @ 0)\\n\\t\\t\\t\\toffsets: (0 @ heights first corner: 0 @ (heights first + heights second))).\\n\\n\\taBin := (PartsBin newPartsBinWithOrientation: #leftToRight from: #())\\n\\t\\tlistDirection: #leftToRight;\\n\\t\\twrapDirection: #topToBottom;\\n\\t\\tcolor: aColor lighter lighter;\\n\\t\\tsetNameTo: 'Parts';\\n\\t\\tdropEnabled: false;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\tyourself.\\n\\n\\tself\\n\\t\\taddMorph: aBin\\n\\t\\tfullFrame: (LayoutFrame\\n\\t\\t\\t\\tfractions: (0 @ 0 corner: 1 @ 1)\\n\\t\\t\\t\\toffsets: (0 @ (heights first + heights second) corner: 0 @ 0)).\\n\\n\\tself\\n\\t\\tborderWidth: ColorTheme current dialogBorderWidth;\\n\\t\\tborderColor: ColorTheme current dialogBorderColor;\\n\\t\\tcolor: ColorTheme current dialogColor;\\n\\t\\tsetNameTo: 'Objects' translated;\\n\\t\\tshowCategories.\\n! !\\n\\n!ObjectsTool methodsFor: 'initialization' stamp: 'dgd 4/4/2006 16:45'!\\ntweakAppearanceAfterModeShift\\n\\t\\\"After the receiver has been put into a given mode, make an initial selection of category, if appropriate, and highlight the mode button.\\\"\\n\\n\\tself buttonPane submorphs do:\\n\\t\\t[:aButton | \\n\\t\\t\\t| aColor |\\n\\t\\t\\t\\\"aButton borderWidth: 1.\\\"\\n\\t\\t\\taColor := (aButton valueOfProperty: #modeSymbol) = modeSymbol\\n\\t\\t\\t\\tifTrue: [Color red]\\n\\t\\t\\t\\tifFalse: [Color black].\\n\\n\\t\\t\\taButton firstSubmorph color: aColor.\\n\\t\\t\\taButton borderColor: aColor.\\n\\t\\t].! !\\n\\n\\n!ObjectsTool methodsFor: 'layout' stamp: 'nk 9/3/2004 12:35'!\\nextent: anExtent\\n\\t\\\"The user has dragged the grow box such that the receiver's extent would be anExtent. Do what's needed\\\"\\n\\tself extent = anExtent ifTrue: [ ^self ].\\n\\tsuper extent: anExtent.\\n\\tself fixLayoutFrames.! !\\n\\n!ObjectsTool methodsFor: 'layout' stamp: 'nk 9/3/2004 13:44'!\\nfixLayoutFrames\\n\\t\\\"Adjust the boundary between the tabs or search pane and the parts bin, giving preference to the tabs.\\\"\\n\\n\\t| oldY newY tp tpHeight |\\n\\toldY := ((tp := self tabsPane\\n\\t\\t\\t\\t\\t\\tifNil: [self searchPane])\\n\\t\\t\\t\\tifNil: [^ self]) layoutFrame bottomOffset.\\n\\ttpHeight := tp hasSubmorphs\\n\\t\\t\\t\\tifTrue: [(tp submorphBounds outsetBy: tp layoutInset) height]\\n\\t\\t\\t\\tifFalse: [tp height].\\n\\tnewY := (self buttonPane\\n\\t\\t\\t\\tifNil: [^ self]) height + tpHeight.\\n\\toldY = newY\\n\\t\\tifTrue: [^ self].\\n\\ttp layoutFrame bottomOffset: newY.\\n\\t(self partsBin\\n\\t\\tifNil: [^ self]) layoutFrame topOffset: newY.\\n\\tsubmorphs\\n\\t\\tdo: [:m | m layoutChanged ]! !\\n\\n!ObjectsTool methodsFor: 'layout' stamp: 'nk 9/3/2004 13:47'!\\nminimizePartsBinSize\\n\\tself layoutChanged; fullBounds.\\n\\tself fixLayoutFrames.\\n\\tself setExtentFromHalo: (self minimumWidth @ self minimumHeight) ! !\\n\\n!ObjectsTool methodsFor: 'layout' stamp: 'nk 9/3/2004 10:35'!\\nminimumBottom\\n\\t| iconsBottom partsBin |\\n\\tpartsBin := self partsBin ifNil: [ ^self bottom ].\\n\\ticonsBottom := partsBin submorphs isEmpty\\n\\t\\tifTrue: [ partsBin top + 60 ]\\n\\t\\tifFalse: [ partsBin submorphBounds bottom + partsBin layoutInset ].\\n\\n\\t^iconsBottom + self layoutInset + self borderWidth! !\\n\\n!ObjectsTool methodsFor: 'layout' stamp: 'nk 9/3/2004 11:53'!\\nminimumHeight\\n\\t^(self minimumBottom - self top) max: 280! !\\n\\n!ObjectsTool methodsFor: 'layout' stamp: 'nk 9/3/2004 12:06'!\\nminimumWidth\\n\\t\\\"Answer a width that assures that the alphabet fits in two rows\\\"\\n\\n\\t^ 300! !\\n\\n!ObjectsTool methodsFor: 'layout' stamp: 'nk 9/3/2004 12:40'!\\nposition: aPoint\\n\\t\\\"The user has dragged the grow box such that the receiver's extent would be anExtent. Do what's needed\\\"\\n\\tself position = aPoint ifTrue: [ ^self ].\\n\\tsuper position: aPoint.\\n\\tself fixLayoutFrames.! !\\n\\n!ObjectsTool methodsFor: 'layout' stamp: 'nk 9/3/2004 12:44'!\\nsetExtentFromHalo: anExtent\\n\\t\\\"The user has dragged the grow box such that the receiver's extent would be anExtent. Do what's needed\\\"\\n\\tsuper setExtentFromHalo: ((anExtent x max: self minimumWidth) @ (anExtent y max: self minimumHeight)).\\n! !\\n\\n\\n!ObjectsTool methodsFor: 'major modes' stamp: 'sw 8/12/2001 16:30'!\\nmodeSymbol\\n\\t\\\"Answer the modeSymbol\\\"\\n\\n\\t^ modeSymbol! !\\n\\n!ObjectsTool methodsFor: 'major modes' stamp: 'nk 9/3/2004 13:32'!\\nmodeSymbol: aSymbol\\n\\t\\\"Set the receiver's modeSymbol as indicated\\\"\\n\\n\\tmodeSymbol _ aSymbol.\\n\\tself tweakAppearanceAfterModeShift.\\n! !\\n\\n!ObjectsTool methodsFor: 'major modes' stamp: 'dgd 4/4/2006 16:47'!\\nmodeTabs\\n\\t\\\"Answer a list of buttons which, when hit, will trigger the choice of mode of the receiver\\\"\\n\\n\\t| buttonList aButton tupleList |\\n\\ttupleList _ #(\\n\\t\\t('alphabetic'\\t\\talphabetic\\tshowAlphabeticTabs\\t'A separate tab for each letter of the alphabet')\\n\\t\\t('find'\\t\\t\\t\\tsearch\\t\\t\\tshowSearchPane\\t\\t\\t'Provides a type-in pane allowing you to match')\\n\\t\\t('categories'\\t\\tcategories\\tshowCategories\\t\\t\\t'Grouped by category')\\n\\n\\t\\t\\\"('standard'\\t\\tstandard\\t\\tshowStandardPane\\t\\t'Standard Squeak tools supplies for building')\\\"\\n\\t).\\n\\t\\t\\t\\t\\n\\tbuttonList _ tupleList collect:\\n\\t\\t[:tuple |\\n\\t\\t\\taButton _ SimpleButtonMorph new label: tuple first translated.\\n\\t\\t\\taButton actWhen: #buttonUp.\\n\\t\\t\\taButton setProperty: #modeSymbol toValue: tuple second.\\n\\t\\t\\taButton target: self; actionSelector: tuple third.\\n\\t\\t\\taButton setBalloonText: tuple fourth translated.\\n\\t\\t\\taButton borderWidth: 0.\\n\\t\\t\\taButton].\\n\\t^ buttonList\\n\\n\\\"ObjectsTool new modeTabs\\\"! !\\n\\n\\n!ObjectsTool methodsFor: 'menu' stamp: 'dgd 8/30/2003 16:22'!\\naddCustomMenuItems: aMenu hand: aHand\\n\\t\\\"Add items to the given halo-menu, given a hand\\\"\\n\\n\\tsuper addCustomMenuItems: aMenu hand: aHand.\\n\\taMenu addLine.\\n\\taMenu add: 'alphabetic' translated target: self selector: #showAlphabeticTabs.\\n\\taMenu add: 'find' translated target: self selector: #showSearchPane.\\n\\taMenu add: 'categories' translated target: self selector: #showCategories.\\n\\taMenu addLine.\\n\\taMenu add: 'reset thumbnails' translated target: self selector: #resetThumbnails.! !\\n\\n!ObjectsTool methodsFor: 'menu' stamp: 'nk 9/7/2003 07:42'!\\nresetThumbnails\\n\\t\\\"Reset the thumbnail cache\\\"\\n\\n\\tPartsBin clearThumbnailCache.\\n\\tmodeSymbol == #categories ifTrue: [self showCategories] ifFalse: [self showAlphabeticTabs]! !\\n\\n\\n!ObjectsTool methodsFor: 'search' stamp: 'nk 9/3/2004 11:20'!\\nnewSearchPane\\n\\t\\\"Answer a type-in pane for searches\\\"\\n\\n\\t| aTextMorph |\\n\\taTextMorph _ TextMorph new\\n\\t\\tsetProperty: #defaultContents toValue: ('' asText allBold addAttribute: (TextFontChange font3));\\n\\t\\tsetTextStyle: (TextStyle fontArray: { Preferences standardEToysFont });\\n\\t\\tsetDefaultContentsIfNil;\\n\\t\\ton: #keyStroke send: #searchPaneCharacter: to: self;\\n\\t\\tsetNameTo: 'SearchPane';\\n\\t\\tsetBalloonText: 'Type here and all entries that match will be shown.' translated;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tmargins: 4@6;\\n\\t\\tbackgroundColor: Color white.\\n\\t^ aTextMorph! !\\n\\n!ObjectsTool methodsFor: 'search' stamp: 'sw 6/30/2001 14:26'!\\nsearchPaneCharacter: evt\\n\\t\\\"A character represented by the event handed in was typed in the search pane by the user\\\"\\n\\n\\t^ self showMorphsMatchingSearchString\\n\\n\\\"\\t| char | *** The variant below only does a new search if RETURN or ENTER is hit ***\\n\\tchar _ evt keyCharacter.\\n\\t(char == Character enter or: [char == Character cr]) ifTrue:\\n\\t\\t[self showMorphsMatchingSearchString]\\\"! !\\n\\n!ObjectsTool methodsFor: 'search' stamp: 'nk 9/3/2004 10:39'!\\nsetSearchStringFromSearchPane\\n\\t\\\"Set the search string by obtaining its contents from the search pane, and doing a certain amount of munging\\\"\\n\\n\\tsearchString _ self searchPane text string asLowercase withBlanksTrimmed.\\n\\tsearchString _ searchString copyWithoutAll: {Character enter. Character cr}! !\\n\\n!ObjectsTool methodsFor: 'search' stamp: 'nk 9/3/2004 13:51'!\\nshowMorphsMatchingSearchString\\n\\t\\\"Put items matching the search string into my lower pane\\\"\\n\\t| quads |\\n\\tself setSearchStringFromSearchPane.\\n\\tself partsBin removeAllMorphs.\\n\\tCursor wait\\n\\t\\tshowWhile: [quads := OrderedCollection new.\\n\\t\\t\\tMorph withAllSubclasses\\n\\t\\t\\t\\tdo: [:aClass | aClass\\n\\t\\t\\t\\t\\t\\taddPartsDescriptorQuadsTo: quads\\n\\t\\t\\t\\t\\t\\tif: [:info | info formalName translated includesSubstring: searchString caseSensitive: false]].\\n\\t\\t\\tself installQuads: quads fromButton: nil]! !\\n\\n!ObjectsTool methodsFor: 'search' stamp: 'nk 9/3/2004 12:13'!\\nshowSearchPane\\n\\t\\\"Set the receiver up so that it shows the search pane\\\"\\n\\n\\t| tabsPane aPane frame |\\n\\tmodeSymbol == #search ifTrue: [ ^self ].\\n\\n\\tself partsBin removeAllMorphs.\\n\\n\\ttabsPane := self tabsPane.\\n\\taPane _ self newSearchPane.\\n\\taPane layoutChanged; fullBounds.\\n\\n\\taPane layoutFrame: (frame := tabsPane layoutFrame copy).\\n\\tframe bottomOffset: (frame topOffset + aPane height).\\n\\tself replaceSubmorph: tabsPane by: aPane.\\n\\tself partsBin layoutFrame topOffset: frame bottomOffset.\\n\\n\\tself modeSymbol: #search.\\n\\tself showMorphsMatchingSearchString.\\n\\tActiveHand newKeyboardFocus: aPane! !\\n\\n\\n!ObjectsTool methodsFor: 'submorph access' stamp: 'nk 9/3/2004 08:06'!\\nbuttonPane\\n\\t\\\"Answer the receiver's button pane, nil if none\\\"\\n\\n\\t^ self submorphNamed: 'ButtonPane' ifNone: [].! !\\n\\n!ObjectsTool methodsFor: 'submorph access' stamp: 'nk 9/3/2004 08:09'!\\npartsBin\\n\\t^self findDeeplyA: PartsBin.! !\\n\\n!ObjectsTool methodsFor: 'submorph access' stamp: 'nk 9/3/2004 10:40'!\\nsearchPane\\n\\t\\\"Answer the receiver's search pane, nil if none\\\"\\n\\n\\t^ self submorphNamed: 'SearchPane' ifNone: [].! !\\n\\n!ObjectsTool methodsFor: 'submorph access' stamp: 'nk 9/3/2004 13:51'!\\nshowAlphabeticCategory: aString fromButton: aButton \\n\\t\\\"Blast items beginning with a given letter into my lower pane\\\"\\n\\t| eligibleClasses quads uc |\\n\\tself partsBin removeAllMorphs.\\n\\tuc := aString asUppercase asCharacter.\\n\\tCursor wait\\n\\t\\tshowWhile: [eligibleClasses := Morph withAllSubclasses.\\n\\t\\t\\tquads := OrderedCollection new.\\n\\t\\t\\teligibleClasses\\n\\t\\t\\t\\tdo: [:aClass | aClass theNonMetaClass\\n\\t\\t\\t\\t\\t\\taddPartsDescriptorQuadsTo: quads\\n\\t\\t\\t\\t\\t\\tif: [:info | info formalName translated asUppercase first = uc]].\\n\\t\\t\\tself installQuads: quads fromButton: aButton]! !\\n\\n!ObjectsTool methodsFor: 'submorph access' stamp: 'nk 9/3/2004 08:06'!\\ntabsPane\\n\\t\\\"Answer the receiver's tabs pane, nil if none\\\"\\n\\n\\t^ self submorphNamed: 'TabPane' ifNone: [].! !\\n\\n\\n!ObjectsTool methodsFor: 'tabs' stamp: 'nk 9/3/2004 13:47'!\\ninitializeWithTabs: tabList\\n\\t\\\"Initialize the receiver to have the given tabs\\\"\\n\\t| oldPane newPane |\\n\\toldPane := self tabsPane ifNil: [ self searchPane ].\\n\\tnewPane := (self paneForTabs: tabList)\\n\\t\\tsetNameTo: 'TabPane';\\n\\t\\tyourself.\\n\\tnewPane layoutFrame: oldPane layoutFrame.\\n\\tself replaceSubmorph: oldPane by: newPane.\\n\\tnewPane layoutChanged; fullBounds.\\n\\tself fixLayoutFrames.\\n\\n! !\\n\\n!ObjectsTool methodsFor: 'tabs' stamp: 'dgd 4/4/2006 16:44'!\\npaneForTabs: tabList \\n\\t\\\"Answer a pane bearing tabs for the given list\\\"\\n\\t| aPane |\\n\\ttabList do: [:t |\\n\\t\\t\\tt color: Color transparent.\\n\\t\\t\\tt borderWidth: 1;\\n\\t\\t\\t\\tborderColor: Color black].\\n\\n\\taPane := AlignmentMorph newRow\\n\\t\\t\\t\\tcolor: ColorTheme current dialogColor;\\n\\t\\t\\t\\tlistDirection: #leftToRight;\\n\\t\\t\\t\\twrapDirection: #topToBottom;\\n\\t\\t\\t\\tvResizing: #spaceFill;\\n\\t\\t\\t\\thResizing: #spaceFill;\\n\\t\\t\\t\\tcellInset: 6;\\n\\t\\t\\t\\tlayoutInset: 4;\\n\\t\\t\\t\\tlistCentering: #center;\\n\\t\\t\\t\\tlistSpacing: #equal;\\n\\t\\t\\t\\taddAllMorphs: tabList;\\n\\t\\t\\t\\tyourself.\\n\\n\\taPane width: self layoutBounds width.\\n\\n\\t^ aPane! !\\n\\n!ObjectsTool methodsFor: 'tabs' stamp: 'dgd 8/30/2003 16:09'!\\npresentHelp\\n\\t\\\"Sent when a Help button is hit; provide the user with some form of help for the tool at hand\\\"\\n\\n'The Objects tool allows you to browse through, and obtain copies of, many kinds of objects. \\n\\nYou can obtain an Objects tool by choosing \\\"Objects\\\" from the world menu, or by the shortcut of typing alt-o (cmd-o) any time the cursor is over the desktop.\\n\\nThere are three ways to use Objects, corresponding to the three tabs seen at the top:\\n\\nalphabetic - gives you separate tabs for a, b, c, etc. Click any tab, and you will see the icons of all the objects whose names begin with that letter\\n\\nsearch - gives you a type-in pane for a search string. Type any letters there, and icons of all the objects whose names match what you have typed will appear in the bottom pane.\\n\\ncategories - provides tabs representing categories of related items. Click on any tab to see the icons of all the objects in the category.\\n\\nWhen the cursor lingers over the icon of any object, you will get balloon help for the item.\\n\\nWhen you drag an icon from Objects, it will result in a new copy of it in your hand; the new object will be deposited wherever you next click.' translated\\n\\n\\topenInWorkspaceWithTitle: 'About Objects' translated! !\\n\\n\\n!ObjectsTool methodsFor: 'thumbnail' stamp: 'dgd 9/22/2004 19:28'!\\nicon\\n\\t\\\"Answer a form with an icon to represent the receiver\\\"\\n\\t^ MenuIcons objectCatalogIcon! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nObjectsTool class\\n\\tinstanceVariableNames: ''!\\n\\n!ObjectsTool class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 10:45'!\\ninitialize\\n\\n\\tself registerInFlapsRegistry.\\t! !\\n\\n!ObjectsTool class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 10:47'!\\nregisterInFlapsRegistry\\n\\t\\\"Register the receiver in the system's flaps registry\\\"\\n\\tself environment\\n\\t\\tat: #Flaps\\n\\t\\tifPresent: [:cl | cl registerQuad: #(ObjectsTool\\t\\t\\tnewStandAlone\\t\\t\\t\\t'Object Catalog'\\t\\t'A tool that lets you browse the catalog of objects')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'PlugIn Supplies'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(ObjectsTool\\t\\tnewStandAlone\\t\\t\\t\\t'Object Catalog'\\t\\t'A tool that lets you browse the catalog of objects')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Widgets'.]! !\\n\\n!ObjectsTool class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 12:37'!\\nunload\\n\\t\\\"Unload the receiver from global registries\\\"\\n\\n\\tself environment at: #Flaps ifPresent: [:cl |\\n\\tcl unregisterQuadsWithReceiver: self] ! !\\n\\n\\n!ObjectsTool class methodsFor: 'parts bin' stamp: 'sw 8/11/2001 20:16'!\\ndescriptionForPartsBin\\n\\t^ self partName:\\t'Objects'\\n\\t\\tcategories:\\t\\t#('Useful')\\n\\t\\tdocumentation:\\t'A place to obtain many kinds of objects'! !\\nOldSocket subclass: #OldSimpleClientSocket\\n\\tinstanceVariableNames: 'buffer bufferPos'\\n\\tclassVariableNames: 'CR CrLf LF'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Kernel'!\\n!OldSimpleClientSocket commentStamp: '<historical>' prior: 0!\\nThis class supports client for simple network protocols based on sending textual commands and responses. Examples of such protocols include POP3 (mail retrieval), SMTP (mail posting), HTTP (web browsing), and NTTP (network news). Some simple examples are presented as class methods, but a full-service client of some service should be implemented as a subclass.\\n\\nThe basic services provided by this class are:\\n\\tsendCommand:\\t\\t\\t-- sends a command line terminate with <CR><LF>\\n\\tgetResponse\\t\\t\\t\\t-- gets a single-line response to a command\\n\\tgetMultilineResponse\\t-- gets a multiple line response terminated by a period\\n\\t\\t\\t\\t\\t\\t\\t-- on a line by itself\\n\\nThere are variants of the getResponse commands that display lines on the screen as they are being received. Linefeeds are stripped out of all responses.\\n\\nThe 'get' commands above make use of an internal buffer. So intermixing these two commands and regular Socket recieve commands can cause problems.!\\n\\n\\n!OldSimpleClientSocket methodsFor: 'as yet unclassified' stamp: 'di 4/13/1999 14:43'!\\ndisplayString: aString\\n\\t\\\"Display the given string on the Display. Used for testing.\\\"\\n\\n\\t| s |\\n\\taString isEmpty ifTrue: [^ self].\\n\\taString size > 60\\n\\t\\tifTrue: [s _ aString copyFrom: 1 to: 60] \\\"limit to 60 characters\\\"\\n\\t\\tifFalse: [s _ aString].\\n\\n\\ts displayOn: Display.\\n! !\\n\\n!OldSimpleClientSocket methodsFor: 'as yet unclassified' stamp: 'jm 9/15/97 15:43'!\\ngetMultilineResponse\\n\\t\\\"Get a multiple line response to the last command, filtering out LF characters. A multiple line response ends with a line containing only a single period (.) character.\\\"\\n\\n\\t^ self getMultilineResponseShowing: false.\\n! !\\n\\n!OldSimpleClientSocket methodsFor: 'as yet unclassified' stamp: 'ls 9/11/1998 03:34'!\\ngetMultilineResponseShowing: showFlag\\n\\t\\\"Get a multiple line response to the last command. A multiple line response ends with a line containing only a single period (.) character. Linefeed characters are filtered out. If showFlag is true, each line is shown in the upper-left corner of the Display as it is received.\\\"\\n\\n\\t| response done chunk |\\n\\tresponse _ WriteStream on: ''.\\n\\tdone _ false.\\n\\t[done] whileFalse: [\\n\\t\\tshowFlag\\n\\t\\t\\tifTrue: [chunk _ self getResponseShowing: true]\\n\\t\\t\\tifFalse: [chunk _ self getResponse].\\n\\t\\t(chunk beginsWith: '.')\\n\\t\\t\\tifTrue: [ response nextPutAll: (chunk copyFrom: 2 to: chunk size) ]\\n\\t\\t\\tifFalse: [ response nextPutAll: chunk ].\\n\\t\\tdone _ (chunk = ('.', String cr)) ].\\n\\n\\t^ response contents\\n! !\\n\\n!OldSimpleClientSocket methodsFor: 'as yet unclassified' stamp: 'ls 9/11/1998 02:10'!\\ngetResponse\\n\\t\\\"Get a one-line response from the server. The final LF is removed from the line, but the CR is left, so that the line is in Squeak's text format\\\"\\n\\n\\t^ self getResponseShowing: false\\n! !\\n\\n!OldSimpleClientSocket methodsFor: 'as yet unclassified' stamp: 'ls 9/11/1998 03:27'!\\ngetResponseShowing: showFlag\\n\\n\\t| line idx |\\n\\tline _ WriteStream on: String new.\\n\\n\\tbuffer ifNil: [\\n\\t\\tbuffer _ String new.\\n\\t\\tbufferPos _ 0 ].\\n\\n\\t[\\n\\t\\t\\\"look for a LF in the buffer\\\"\\n\\t\\tidx _ buffer indexOf: Character lf startingAt: bufferPos+1 ifAbsent: [ 0 ].\\n\\t\\tidx > 0 ifTrue: [\\n\\t\\t\\t\\\"found it!! we have a line\\\"\\n\\t\\t\\tline nextPutAll: (buffer copyFrom: bufferPos+1 to: idx-1).\\n\\t\\t\\tbufferPos _ idx.\\n\\t\\t\\t^line contents ].\\n\\t\\t\\n\\t\\t\\\"didn't find it. add the whole buffer to the line, and retrieve some more data\\\"\\n\\t\\tline nextPutAll: (buffer copyFrom: bufferPos+1 to: buffer size).\\n\\t\\tbufferPos _ 0.\\n\\t\\tbuffer _ String new.\\n\\t\\tself waitForDataQueryingUserEvery: 30.\\n\\t\\tbuffer _ self getData.\\n\\n\\t\\ttrue\\n\\t] whileTrue.! !\\n\\n!OldSimpleClientSocket methodsFor: 'as yet unclassified' stamp: 'jm 9/17/97 16:00'!\\nsendCommand: commandString\\n\\t\\\"Send the given command as a single line followed by a <CR><LF> terminator.\\\"\\n\\n\\tself sendData: commandString, CrLf.\\n! !\\n\\n!OldSimpleClientSocket methodsFor: 'as yet unclassified' stamp: 'jm 9/16/1998 14:37'!\\nwaitForDataQueryingUserEvery: seconds\\n\\t\\\"Wait for data to arrive, asking the user periodically if they wish to keep waiting. If they don't wish to keep waiting, destroy the socket and raise an error.\\\"\\n\\n\\t| gotData |\\n\\tgotData _ false.\\n\\t[gotData]\\n\\t\\twhileFalse: [\\n\\t\\t\\tgotData _ self waitForDataUntil: (Socket deadlineSecs: seconds).\\n\\t\\t\\tgotData ifFalse: [\\n\\t\\t\\t\\tself isConnected ifFalse: [\\n\\t\\t\\t\\t\\tself destroy.\\n\\t\\t\\t\\t\\tself error: 'server closed connection'].\\n\\t\\t\\t\\t(self confirm: 'server not responding; keep trying?')\\n\\t\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\t\\tself destroy.\\n\\t\\t\\t\\t\\t\\tself error: 'no response from server']]].\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOldSimpleClientSocket class\\n\\tinstanceVariableNames: ''!\\n\\n!OldSimpleClientSocket class methodsFor: 'class initialization' stamp: 'jm 9/15/97 11:42'!\\ninitialize\\n\\t\\\"SimpleClientSocket initialize\\\"\\n\\n\\tCR _ Character cr.\\n\\tLF _ Character linefeed.\\n\\n\\t\\\"string for command line termination:\\\"\\n\\tCrLf _ String with: CR with: LF.\\n! !\\n\\n\\n!OldSimpleClientSocket class methodsFor: 'net news example' stamp: 'mir 5/13/2003 10:45'!\\nnntpTest\\n\\t\\\"SimpleClientSocket nntpTest\\\"\\n\\n\\t| addr s headers msgs header allNewsGroups |\\n\\taddr _ NetNameResolver promptUserForHostAddress.\\n\\ts _ OldSimpleClientSocket new.\\n\\tTranscript show: '---------- Connecting ----------'; cr.\\n\\ts connectTo: addr port: 119. \\\"119 is the NNTP port number\\\"\\n\\ts waitForConnectionUntil: self standardDeadline.\\n\\tTranscript show: s getResponse.\\n\\ts sendCommand: 'group comp.lang.smalltalk'.\\n\\tTranscript show: s getResponse.\\n\\n\\t\\\"get all the message headers for the current newsgroup\\\"\\n\\ts sendCommand: 'xover 1-1000000'.\\n\\theaders _ s getMultilineResponseShowing: true.\\n\\n\\t\\\"print the headers of the first 10 messages of comp.lang.smalltalk\\\"\\n\\ts sendCommand: 'listgroup comp.lang.smalltalk'.\\n\\tmsgs _ self parseIntegerList: s getMultilineResponse.\\n\\tmsgs ifNotNil: [\\n\\t\\t1 to: 5 do: [:i |\\n\\t\\t\\ts sendCommand: 'head ', (msgs at: i) printString.\\n\\t\\t\\theader _ s getMultilineResponse.\\n\\t\\t\\tTranscript show: (self extractDateFromAndSubjectFromHeader: header); cr]].\\n\\n\\t\\\"get a full list of usenet newsgroups\\\"\\n\\ts sendCommand: 'newgroups 010101 000000'.\\n\\tallNewsGroups _ s getMultilineResponse.\\n\\tTranscript show: allNewsGroups size printString, ' bytes in full newsgroup list'; cr.\\n\\n\\tTranscript show: 'Sending quit...'; cr.\\n\\ts sendCommand: 'QUIT'.\\n\\tTranscript show: s getResponse.\\n\\ts closeAndDestroy.\\n\\tTranscript show: '---------- Connection Closed ----------'; cr; endEntry.\\n\\n\\t(headers ~~ nil and:\\n\\t [self confirm: 'show article headers from comp.lang.smalltalk?'])\\n\\t\\tifTrue: [\\n\\t\\t\\t(StringHolder new contents: (self parseHeaderList: headers))\\n\\t\\t\\t\\topenLabel: 'Newsgroup Headers'].\\n\\n\\t(allNewsGroups ~~ nil and:\\n\\t [self confirm: 'show list of all newsgroups available on your server?'])\\n\\t\\tifTrue: [\\n\\t\\t\\t(StringHolder new contents: allNewsGroups)\\n\\t\\t\\t\\topenLabel: 'All Usenet Newsgroups'].\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'net news example' stamp: 'jm 9/15/97 13:25'!\\nparseHeaderList: aString\\n\\t\\\"Parse a list of newsgroup headers.\\\"\\n\\n\\t| results s lineStart |\\n\\tresults _ WriteStream on: (String new: aString size).\\n\\ts _ ReadStream on: aString.\\n\\t[s atEnd]\\n\\t\\twhileFalse: [\\n\\t\\t\\tlineStart _ s position + 1.\\n\\t\\t\\t3 timesRepeat: [s skipTo: Character tab]. \\\"find fourth tab\\\"\\n\\t\\t\\tlineStart to: s position - 1 do: [:i | results nextPut: (aString at: i)].\\n\\t\\t\\tresults cr.\\n\\t\\t\\ts skipTo: Character cr].\\n\\t^ results contents\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'net news example' stamp: 'jm 9/15/97 13:26'!\\nparseIntegerList: aString\\n\\t\\\"Parse a list of integers, each on a line by itself.\\\"\\n\\n\\t| s out |\\n\\ts _ ReadStream on: aString.\\n\\ts skipTo: Character cr. \\\"skip the first line\\\"\\n\\tout _ OrderedCollection new.\\n\\t[s atEnd]\\n\\t\\twhileFalse: [\\n\\t\\t\\tout addLast: (Integer readFrom: s).\\n\\t\\t\\ts skipTo: Character cr].\\n\\t^ out asArray\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'net news example' stamp: 'jm 9/15/97 13:26'!\\nparseNTTPMsgList: aString\\n\\t\\\"Parse a list of integers, each on a line by itself.\\\"\\n\\n\\t| s out |\\n\\ts _ ReadStream on: aString.\\n\\ts skipTo: Character cr. \\\"skip the first line\\\"\\n\\tout _ OrderedCollection new.\\n\\t[s atEnd]\\n\\t\\twhileFalse: [\\n\\t\\t\\tout addLast: (Integer readFrom: s).\\n\\t\\t\\ts skipTo: Character cr].\\n\\t^ out asArray\\n! !\\n\\n\\n!OldSimpleClientSocket class methodsFor: 'other examples' stamp: 'mir 5/13/2003 10:45'!\\nfinger: userName\\n\\t\\\"OldSimpleClientSocket finger: 'stp'\\\"\\n\\n\\t| addr s |\\n\\taddr _ NetNameResolver promptUserForHostAddress.\\n\\ts _ OldSimpleClientSocket new.\\n\\tTranscript show: '---------- Connecting ----------'; cr.\\n\\ts connectTo: addr port: 79. \\\"finger port number\\\"\\n\\ts waitForConnectionUntil: self standardDeadline.\\n\\ts sendCommand: userName.\\n\\tTranscript show: s getResponse.\\n\\ts closeAndDestroy.\\n\\tTranscript show: '---------- Connection Closed ----------'; cr; endEntry.\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'other examples' stamp: 'mir 5/13/2003 10:45'!\\nhttpTestHost: hostName port: port url: url\\n\\t\\\"This test fetches a URL from the given host and port.\\\"\\n\\t\\\"SimpleClientSocket httpTestHost: 'www.disney.com' port: 80 url: '/'\\\"\\n\\t\\\"Tests URL fetch through a local HTTP proxie server:\\n\\t\\t(SimpleClientSocket\\n\\t\\t\\thttpTestHost: '127.0.0.1'\\n\\t\\t\\tport: 8080\\n\\t\\t\\turl: 'HTTP://www.exploratorium.edu/index.html')\\\"\\n\\n\\t| hostAddr s result buf bytes totalBytes t |\\n\\tTranscript cr; show: 'starting http test'; cr.\\n\\tSocket initializeNetwork.\\n\\thostAddr _ NetNameResolver addressForName: hostName timeout: 10.\\n\\thostAddr = nil ifTrue: [^ self inform: 'Could not find an address for ', hostName].\\n\\n\\ts _ OldSimpleClientSocket new.\\n\\tTranscript show: '---------- Connecting ----------'; cr.\\n\\ts connectTo: hostAddr port: port.\\n\\ts waitForConnectionUntil: \\\"self standardDeadline\\\" (Socket deadlineSecs: 10).\\n\\t(s isConnected) ifFalse: [\\n\\t\\ts destroy.\\n\\t\\t^ self inform: 'could not connect'].\\n\\tTranscript show: 'connection open; waiting for data'; cr.\\n\\n\\ts sendCommand: 'GET ', url, ' HTTP/1.0'.\\n\\ts sendCommand: 'User-Agent: Squeak 1.19'.\\n\\ts sendCommand: 'ACCEPT: text/html'.\\t\\\"always accept plain text\\\"\\n\\ts sendCommand: 'ACCEPT: application/octet-stream'. \\\"also accept binary data\\\"\\n\\ts sendCommand: ''. \\\"blank line\\\"\\n\\n\\tresult _ WriteStream on: (String new: 10000).\\n\\tbuf _ String new: 10000.\\n\\ttotalBytes _ 0.\\n\\tt _ Time millisecondsToRun: [\\n\\t\\t[s isConnected] whileTrue: [\\n\\t\\t\\ts waitForDataUntil: (Socket deadlineSecs: 5).\\n\\t\\t\\tbytes _ s receiveDataInto: buf.\\n\\t\\t\\t1 to: bytes do: [:i | result nextPut: (buf at: i)].\\n\\t\\t\\ttotalBytes _ totalBytes + bytes.\\n\\t\\t\\tTranscript show: totalBytes printString, ' bytes received'; cr]].\\n\\n\\ts destroy.\\n\\tTranscript show: '---------- Connection Closed ----------'; cr; endEntry.\\n\\tTranscript show: 'http test done; ', totalBytes printString, ' bytes read in '.\\n\\tTranscript show: ((t / 1000.0) roundTo: 0.01) printString, ' seconds'; cr.\\n\\tTranscript show: ((totalBytes asFloat / t) roundTo: 0.01) printString, ' kBytes/sec'; cr.\\n\\tTranscript endEntry.\\n\\t(StringHolder new contents: (result contents))\\n\\t\\topenLabel: 'HTTP Test Result: URL Contents'.\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'other examples' stamp: 'mir 5/13/2003 10:45'!\\ntimeTest\\n\\t\\\"SimpleClientSocket timeTest\\\"\\n\\n\\t| addr s |\\n\\taddr _ NetNameResolver promptUserForHostAddress.\\n\\ts _ OldSimpleClientSocket new.\\n\\tTranscript show: '---------- Connecting ----------'; cr.\\n\\ts connectTo: addr port: 13. \\\"time port number\\\"\\n\\ts waitForConnectionUntil: self standardDeadline.\\n\\tTranscript show: s getResponse.\\n\\ts closeAndDestroy.\\n\\tTranscript show: '---------- Connection Closed ----------'; cr; endEntry.\\n! !\\n\\n\\n!OldSimpleClientSocket class methodsFor: 'POP mail example' stamp: 'jm 9/15/97 14:47'!\\nextractDateFromAndSubjectFromHeader: headerString\\n\\n\\t| date from subject s lineBuf c line i |\\n\\tdate _ from _ subject _ ''.\\n\\ts _ ReadStream on: headerString.\\n\\tlineBuf _ WriteStream on: ''.\\n\\t[s atEnd] whileFalse: [\\n\\t\\tc _ s next.\\n\\t\\tc = CR\\n\\t\\t\\tifTrue: [\\n\\t\\t\\t\\tline _ lineBuf contents.\\n\\t\\t\\t\\t(line beginsWith: 'Date: ')\\tifTrue: [date _ line copyFrom: 7 to: line size].\\n\\t\\t\\t\\t(line beginsWith: 'From: ')\\tifTrue: [from _ line copyFrom: 7 to: line size].\\n\\t\\t\\t\\t(line beginsWith: 'Subject: ')\\tifTrue: [subject _ line copyFrom: 10 to: line size].\\n\\t\\t\\t\\tlineBuf _ WriteStream on: '']\\n\\t\\t\\tifFalse: [lineBuf nextPut: c]].\\n\\n\\ti _ date indexOf: $' ifAbsent: [0].\\n\\tdate _ date copyFrom: i + 1 to: date size.\\n\\t^ (self simpleDateString: date), ', ', from, ':\\n ', subject\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'POP mail example' stamp: 'rbb 3/1/2005 11:02'!\\npopTest\\n\\t\\\"SimpleClientSocket popTest\\\"\\n\\n\\t| addr userName userPassword s msgs header |\\n\\taddr := NetNameResolver promptUserForHostAddress.\\n\\tuserName := UIManager default\\n\\t\\trequest: 'What is your email name?'\\n\\t\\tinitialAnswer: 'johnm'.\\n\\tuserPassword := UIManager default\\n\\t\\trequest: 'What is your email password?'.\\n\\n\\ts := OldSimpleClientSocket new.\\n\\tTranscript show: '---------- Connecting ----------'; cr.\\n\\ts connectTo: addr port: 110. \\\"110 is the POP3 port number\\\"\\n\\ts waitForConnectionUntil: self standardDeadline.\\n\\tTranscript show: s getResponse.\\n\\ts sendCommand: 'USER ', userName.\\n\\tTranscript show: s getResponse.\\n\\ts sendCommand: 'PASS ', userPassword.\\n\\tTranscript show: s getResponse.\\n\\ts sendCommand: 'LIST'.\\n\\n\\t\\\"the following should be tweaked to handle an empy mailbox:\\\"\\n\\tmsgs := self parseIntegerList: s getMultilineResponse.\\n\\n\\t1 to: (msgs size min: 5) do: [ :i |\\n\\t\\ts sendCommand: 'TOP ', (msgs at: i) printString, ' 0'.\\n\\t\\theader := s getMultilineResponse.\\n\\t\\tTranscript show: (self extractDateFromAndSubjectFromHeader: header); cr].\\n\\n\\tmsgs size > 0 ifTrue: [\\n\\t\\t\\\"get the first message\\\"\\n\\t\\ts sendCommand: 'RETR 1'.\\n\\t\\tTranscript show: s getMultilineResponse].\\n\\n\\tTranscript show: 'closing connection'; cr.\\n\\ts sendCommand: 'QUIT'.\\n\\ts closeAndDestroy.\\n\\tTranscript show: '---------- Connection Closed ----------'; cr; endEntry.\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'POP mail example' stamp: 'tk 4/10/1998 06:47'!\\nsimpleDateString: dateString\\n\\n\\t| s |\\n\\ts _ ReadStream on: dateString.\\n\\ts skipTo: $,. \\\"scan thru first comma\\\"\\n\\ts atEnd ifTrue: [s reset]. \\\"no comma found; reset s\\\"\\n\\ts skipSeparators.\\n\\t^ (Date readFrom: s) mmddyyyy\\n! !\\n\\n\\n!OldSimpleClientSocket class methodsFor: 'queries' stamp: 'jm 2/26/98 09:50'!\\ncrLf\\n\\n\\t^ CrLf\\n! !\\n\\n\\n!OldSimpleClientSocket class methodsFor: 'remote cursor example' stamp: 'mir 5/13/2003 10:45'!\\nforkingRemoteCursorSender\\n\\t\\\"This is the client side of a test that sends samples of the local input sensor state to the server, which may be running on a local or remote host. This method opens the connection, then forks a process to send the cursor data. Data is sent continuously until the user clicks in a 20x20 pixel square at the top-left corner of the display. The server should be started first. Note the server's address, since this method will prompt you for it.\\\"\\n\\t\\\"SimpleClientSocket forkingRemoteCursorSender\\\"\\n\\n\\t| sock addr stopRect |\\n\\tTranscript show: 'starting remote cursor sender'; cr.\\n\\tTranscript show: 'initializing network'; cr.\\n\\tSocket initializeNetwork.\\n\\taddr _ NetNameResolver promptUserForHostAddress.\\n\\tTranscript show: 'opening connection'; cr.\\n\\tsock _ OldSimpleClientSocket new.\\n\\tsock connectTo: addr port: 54323.\\n\\tsock waitForConnectionUntil: self standardDeadline.\\n\\t(sock isConnected) ifFalse: [self error: 'sock not connected'].\\n\\tTranscript show: 'connection established'; cr.\\n\\n\\tstopRect _ 0@0 corner: 20@20. \\\"click in this rectangle to stop sending\\\"\\n\\tDisplay reverse: stopRect.\\n\\t[\\\"the sending process\\\"\\n\\t\\t[(stopRect containsPoint: Sensor cursorPoint) and:\\n\\t\\t [Sensor anyButtonPressed]]\\n\\t\\t\\twhileFalse: [\\n\\t\\t\\t\\tsock sendCommand: self sensorStateString.\\n\\t\\t\\t\\t(Delay forMilliseconds: 20) wait].\\n\\n\\t\\tsock waitForSendDoneUntil: self standardDeadline.\\n\\t\\tsock destroy.\\n\\t\\tTranscript show: 'remote cursor sender done'; cr.\\n\\t\\tDisplay reverse: stopRect.\\n\\t] fork.\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'remote cursor example' stamp: 'jm 9/15/97 14:49'!\\nparseSensorStateString: aString\\n\\t\\\"Parse the given sensor stat string and return an array whose first element is the cursor point and whose second is the cursor button state.\\\"\\n\\t\\\"SimpleClientSocket parseSensorStateString: SimpleClientSocket sensorStateString\\\"\\n\\n\\t| s buttons x y |\\n\\ts _ ReadStream on: aString.\\n\\tx _ Integer readFrom: s.\\n\\ts skipSeparators.\\n\\ty _ Integer readFrom: s.\\n\\ts skipSeparators.\\n\\tbuttons _ Integer readFrom: s.\\n\\t^ Array with: x@y with: buttons\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'remote cursor example' stamp: 'mir 5/13/2003 10:45'!\\nremoteCursorReceiver\\n\\t\\\"Wait for a connection, then display data sent by the client until the client closes the stream. This server process is usually started first (optionally in a forked process), then the sender process is started (optionally on another machine). Note this machine's address, which is printed in the transcript, since the sender process will ask for it.\\\"\\n\\t\\\"[SimpleClientSocket remoteCursorReceiver] fork\\\"\\n\\n\\t| sock response |\\n\\tTranscript show: 'starting remote cursor receiver'; cr.\\n\\tTranscript show: 'initializing network'; cr.\\n\\tSocket initializeNetwork.\\n\\tTranscript show: 'my address is ', NetNameResolver localAddressString; cr.\\n\\tTranscript show: 'opening connection'; cr.\\n\\tsock _ OldSimpleClientSocket new.\\n\\tsock listenOn: 54323.\\n\\tsock waitForConnectionUntil: (Socket deadlineSecs: 60).\\n\\tsock isConnected\\n\\t\\tifFalse: [\\n\\t\\t\\t sock destroy.\\n\\t\\t\\tTranscript show: 'remote cursor receiver did not receive a connection in 60 seconds; aborting.'.\\n\\t\\t\\t^ self].\\n\\tTranscript show: 'connection established'; cr.\\n\\n\\t[sock isConnected]\\n\\t\\twhileTrue: [\\n\\t\\t\\tsock dataAvailable\\n\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\tresponse _ sock getResponse.\\n\\t\\t\\t\\t\\tresponse displayOn: Display at: 10@10]\\n\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\t\\\"if no data available, let other processes run for a while\\\"\\n\\t\\t\\t\\t\\t(Delay forMilliseconds: 20) wait]].\\n\\n\\tsock destroy.\\n\\tTranscript show: 'remote cursor receiver done'; cr.\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'remote cursor example' stamp: 'mir 5/13/2003 10:45'!\\nremoteCursorTest\\n\\t\\\"This version of the remote cursor test runs both the client and the server code in the same loop.\\\"\\n\\t\\\"SimpleClientSocket remoteCursorTest\\\"\\n\\n\\t| sock1 sock2 samplesToSend samplesSent done t |\\n\\tTranscript show: 'starting remote cursor test'; cr.\\n\\tTranscript show: 'initializing network'; cr.\\n\\tSocket initializeNetwork.\\n\\tTranscript show: 'opening connection'; cr.\\n\\tsock1 _ OldSimpleClientSocket new.\\n\\tsock2 _ OldSimpleClientSocket new.\\n\\tsock1 listenOn: 54321.\\n\\tsock2 connectTo: (NetNameResolver localHostAddress) port: 54321.\\n\\tsock1 waitForConnectionUntil: self standardDeadline.\\n\\tsock2 waitForConnectionUntil: self standardDeadline.\\n\\t(sock1 isConnected) ifFalse: [self error: 'sock1 not connected'].\\n\\t(sock2 isConnected) ifFalse: [self error: 'sock2 not connected'].\\n\\tTranscript show: 'connection established'; cr.\\n\\n\\tsamplesToSend _ 100.\\n\\tt _ Time millisecondsToRun: [\\n\\t\\tsamplesSent _ 0.\\n\\t\\tdone _ false.\\n\\t\\t[done]\\n\\t\\t\\twhileFalse: [\\n\\t\\t\\t\\t(sock1 sendDone and: [samplesSent < samplesToSend]) ifTrue: [\\n\\t\\t\\t\\t\\tsock1 sendCommand: self sensorStateString.\\n\\t\\t\\t\\t\\tsamplesSent _ samplesSent + 1].\\n\\t\\t\\t\\tsock2 dataAvailable ifTrue: [\\n\\t\\t\\t\\t\\tsock2 getResponse displayOn: Display at: 10@10].\\n\\t\\t\\t\\tdone _ samplesSent = samplesToSend]].\\n\\tsock1 destroy.\\n\\tsock2 destroy.\\n\\tTranscript show: 'remote cursor test done'; cr.\\n\\tTranscript show:\\n\\t\\tsamplesSent printString, ' samples sent in ',\\n\\t\\tt printString, ' milliseconds'; cr.\\n\\tTranscript show: ((samplesSent * 1000) // t) printString, ' samples/sec'; cr.\\n! !\\n\\n!OldSimpleClientSocket class methodsFor: 'remote cursor example' stamp: 'jm 9/15/97 13:11'!\\nsensorStateString\\n\\t\\\"SimpleClientSocket sensorStateString\\\"\\n\\n\\t| pt buttons s |\\n\\tpt _ Sensor cursorPoint.\\n\\tbuttons _ Sensor primMouseButtons.\\n\\ts _ WriteStream on: (String new: 100).\\n\\ts nextPutAll: pt x printString.\\n\\ts space.\\n\\ts nextPutAll: pt y printString.\\n\\ts space.\\n\\ts nextPutAll: buttons printString.\\n\\t^ s contents\\n! !\\nObject subclass: #OldSocket\\n\\tinstanceVariableNames: 'semaphore socketHandle readSemaphore writeSemaphore primitiveOnlySupportsOneSemaphore'\\n\\tclassVariableNames: 'Connected DeadServer InvalidSocket OtherEndClosed Registry RegistryThreshold TCPSocketType ThisEndClosed UDPSocketType Unconnected WaitingForConnection'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Kernel'!\\n!OldSocket commentStamp: '<historical>' prior: 0!\\nA Socket represents a network connection point. Current sockets are designed to support the TCP/IP and UDP protocols\\n\\nSubclasses of socket provide support for network protocols such as POP, NNTP, HTTP, and FTP. Sockets also allow you to implement your own custom services and may be used to support Remote Procedure Call or Remote Method Invocation some day.\\n\\nJMM June 2nd 2000 Macintosh UDP support was added if you run open transport.\\n!\\n]style[(196 4 6 3 228)f1,f1LHTTPSocket Comment;,f1,f1LFTPSocket Comment;,f1!\\n\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'ar 4/30/1999 04:25'!\\naddress\\n\\t\\\"Shortcut\\\"\\n\\t^self localAddress! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'nk 2/24/2005 14:37'!\\nlocalAddress\\n\\tself waitForConnectionUntil: self class standardDeadline.\\n\\tself isConnected ifFalse: [^ByteArray new: 4].\\n\\t^self primSocketLocalAddress: socketHandle! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'nk 2/24/2005 14:37'!\\nlocalPort\\n\\tself waitForConnectionUntil: self class standardDeadline.\\n\\tself isConnected ifFalse: [^0].\\n\\t^self primSocketLocalPort: socketHandle! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'jm 3/13/98 12:11'!\\npeerName\\n\\t\\\"Return the name of the host I'm connected to, or nil if its name isn't known to the domain name server or the request times out.\\\"\\n\\t\\\"Note: Slow. Calls the domain name server, taking up to 20 seconds to time out. Even when sucessful, delays of up to 13 seconds have been observed during periods of high network load.\\\" \\n\\n\\t^ NetNameResolver\\n\\t\\tnameForAddress: self remoteAddress\\n\\t\\ttimeout: 20\\n! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'ar 4/30/1999 04:25'!\\nport\\n\\t\\\"Shortcut\\\"\\n\\t^self localPort! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'JMM 6/5/2000 10:12'!\\nprimitiveOnlySupportsOneSemaphore\\n\\t^primitiveOnlySupportsOneSemaphore! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'JMM 5/22/2000 22:49'!\\nreadSemaphore\\n\\tprimitiveOnlySupportsOneSemaphore ifTrue: [^semaphore].\\n\\t^readSemaphore! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'jm 9/17/97 14:34'!\\nremoteAddress\\n\\n\\t^ self primSocketRemoteAddress: socketHandle\\n! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'jm 9/17/97 14:34'!\\nremotePort\\n\\n\\t^ self primSocketRemotePort: socketHandle\\n! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'JMM 5/9/2000 15:32'!\\nsemaphore\\n\\t^semaphore! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'ar 7/16/1999 17:22'!\\nsocketHandle\\n\\t^socketHandle! !\\n\\n!OldSocket methodsFor: 'accessing' stamp: 'JMM 5/22/2000 22:49'!\\nwriteSemaphore\\n\\tprimitiveOnlySupportsOneSemaphore ifTrue: [^semaphore].\\n\\t^writeSemaphore! !\\n\\n\\n!OldSocket methodsFor: 'connection open/close' stamp: 'nk 2/24/2005 14:37'!\\naccept\\n\\t\\\"Accept a connection from the receiver socket.\\n\\tReturn a new socket that is connected to the client\\\"\\n\\n\\t^self class acceptFrom: self! !\\n\\n!OldSocket methodsFor: 'connection open/close' stamp: 'jm 9/11/97 20:29'!\\nclose\\n\\t\\\"Close this connection gracefully. For TCP, this sends a close request, but the stream remains open until the other side also closes it.\\\"\\n\\n\\tself primSocketCloseConnection: socketHandle. \\\"close this end\\\"\\n! !\\n\\n!OldSocket methodsFor: 'connection open/close' stamp: 'jm 11/4/97 07:15'!\\ncloseAndDestroy\\n\\t\\\"First, try to close this connection gracefully. If the close attempt fails or times out, abort the connection. In either case, destroy the socket. Do nothing if the socket has already been destroyed (i.e., if its socketHandle is nil).\\\"\\n\\n\\tself closeAndDestroy: 20.\\n\\n! !\\n\\n!OldSocket methodsFor: 'connection open/close' stamp: 'nk 2/24/2005 14:37'!\\ncloseAndDestroy: timeoutSeconds \\n\\t\\\"First, try to close this connection gracefully. If the close attempt fails or times out, abort the connection. In either case, destroy the socket. Do nothing if the socket has already been destroyed (i.e., if its socketHandle is nil).\\\"\\n\\n\\tsocketHandle = nil \\n\\t\\tifFalse: \\n\\t\\t\\t[self isConnected \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[self close.\\t\\\"close this end\\\"\\n\\t\\t\\t\\t\\t(self waitForDisconnectionUntil: (self class deadlineSecs: timeoutSeconds)) \\n\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t[\\\"if the other end doesn't close soon, just abort the connection\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\tself primSocketAbortConnection: socketHandle]].\\n\\t\\t\\tself destroy]! !\\n\\n!OldSocket methodsFor: 'connection open/close'!\\nconnectTo: hostAddress port: port\\n\\t\\\"Initiate a connection to the given port at the given host address. This operation will return immediately; follow it with waitForConnectionUntil: to wait until the connection is established.\\\"\\n\\n\\t| status |\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t(status == Unconnected)\\n\\t\\tifFalse: [self error: 'Socket status must Unconnected before opening a new connection'].\\n\\n\\tself primSocket: socketHandle connectTo: hostAddress port: port.\\n! !\\n\\n!OldSocket methodsFor: 'connection open/close' stamp: 'jm 3/10/98 11:56'!\\ndisconnect\\n\\t\\\"Break this connection, no matter what state it is in. Data that has been sent but not received will be lost.\\\"\\n\\n\\tself primSocketAbortConnection: socketHandle.\\n! !\\n\\n!OldSocket methodsFor: 'connection open/close'!\\nlistenOn: port\\n\\t\\\"Listen for a connection on the given port. This operation will return immediately; follow it with waitForConnectionUntil: to wait until a connection is established.\\\"\\n\\n\\t| status |\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t(status == Unconnected)\\n\\t\\tifFalse: [self error: 'Socket status must Unconnected before listening for a new connection'].\\n\\n\\tself primSocket: socketHandle listenOn: port.\\n! !\\n\\n!OldSocket methodsFor: 'connection open/close' stamp: 'ar 7/16/1999 18:26'!\\nlistenOn: portNumber backlogSize: backlog\\n\\t\\\"Listen for a connection on the given port.\\n\\tIf this method succeeds, #accept may be used to establish a new connection\\\"\\n\\t| status |\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t(status == Unconnected)\\n\\t\\tifFalse: [self error: 'Socket status must Unconnected before listening for a new connection'].\\n\\tself primSocket: socketHandle listenOn: portNumber backlogSize: backlog.\\n! !\\n\\n!OldSocket methodsFor: 'connection open/close' stamp: 'ikp 9/1/2003 20:47'!\\nlistenOn: portNumber backlogSize: backlog interface: ifAddr\\n\\t\\\"Listen for a connection on the given port.\\n\\tIf this method succeeds, #accept may be used to establish a new connection\\\"\\n\\t| status |\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t(status == Unconnected)\\n\\t\\tifFalse: [self error: 'Socket status must Unconnected before listening for a new connection'].\\n\\tself primSocket: socketHandle listenOn: portNumber backlogSize: backlog interface: ifAddr.\\n! !\\n\\n\\n!OldSocket methodsFor: 'datagrams' stamp: 'JMM 6/7/2000 14:58'!\\nreceiveDataInto: aStringOrByteArray fromHost: hostAddress port: portNumber\\n\\t| datagram |\\n\\t\\\"Receive a UDP packet from the given hostAddress/portNumber, storing the data in the given buffer, and return the number of bytes received. Note the given buffer may be only partially filled by the received data.\\\"\\n\\n\\tprimitiveOnlySupportsOneSemaphore ifTrue:\\n\\t\\t[self setPeer: hostAddress port: portNumber.\\n\\t\\t^self receiveDataInto: aStringOrByteArray].\\n\\t[true] whileTrue: \\n\\t\\t[datagram _ self receiveUDPDataInto: aStringOrByteArray.\\n\\t\\t((datagram at: 2) = hostAddress and: [(datagram at: 3) = portNumber]) \\n\\t\\t\\tifTrue: [^datagram at: 1]\\n\\t\\t\\tifFalse: [^0]]! !\\n\\n!OldSocket methodsFor: 'datagrams' stamp: 'JMM 6/3/2000 21:54'!\\nreceiveUDPDataInto: aStringOrByteArray\\n\\t\\\"Receive UDP data into the given buffer and return the number of bytes received. Note the given buffer may be only partially filled by the received data. What is returned is an array, the first element is the bytes read, the second the sending bytearray address, the third the senders port, the fourth, true if more of the datagram awaits reading\\\"\\n\\n\\t^ self primSocket: socketHandle\\n\\t\\treceiveUDPDataInto: aStringOrByteArray\\n\\t\\tstartingAt: 1\\n\\t\\tcount: aStringOrByteArray size\\n! !\\n\\n!OldSocket methodsFor: 'datagrams' stamp: 'JMM 5/25/2000 00:05'!\\nsendData: aStringOrByteArray toHost: hostAddress port: portNumber\\n\\t\\\"Send a UDP packet containing the given data to the specified host/port.\\\"\\n\\n\\tprimitiveOnlySupportsOneSemaphore ifTrue:\\n\\t\\t[self setPeer: hostAddress port: portNumber.\\n\\t\\t^self sendData: aStringOrByteArray].\\n\\t^self sendUDPData: aStringOrByteArray toHost: hostAddress port: portNumber! !\\n\\n!OldSocket methodsFor: 'datagrams' stamp: 'nk 2/24/2005 14:37'!\\nsendUDPData: aStringOrByteArray toHost: hostAddress port: portNumber \\n\\t\\\"Send a UDP packet containing the given data to the specified host/port.\\\"\\n\\n\\t| bytesToSend bytesSent count |\\n\\tbytesToSend := aStringOrByteArray size.\\n\\tbytesSent := 0.\\n\\t[bytesSent < bytesToSend] whileTrue: \\n\\t\\t\\t[(self waitForSendDoneUntil: (self class deadlineSecs: 20)) \\n\\t\\t\\t\\tifFalse: [self error: 'send data timeout; data not sent'].\\n\\t\\t\\tcount := self \\n\\t\\t\\t\\t\\t\\tprimSocket: socketHandle\\n\\t\\t\\t\\t\\t\\tsendUDPData: aStringOrByteArray\\n\\t\\t\\t\\t\\t\\ttoHost: hostAddress\\n\\t\\t\\t\\t\\t\\tport: portNumber\\n\\t\\t\\t\\t\\t\\tstartIndex: bytesSent + 1\\n\\t\\t\\t\\t\\t\\tcount: bytesToSend - bytesSent.\\n\\t\\t\\tbytesSent := bytesSent + count].\\n\\t^bytesSent! !\\n\\n!OldSocket methodsFor: 'datagrams' stamp: 'ar 4/30/1999 04:29'!\\nsetPeer: hostAddress port: port\\n\\t\\\"Set the default send/recv address.\\\"\\n\\n\\tself primSocket: socketHandle connectTo: hostAddress port: port.\\n! !\\n\\n!OldSocket methodsFor: 'datagrams' stamp: 'ar 4/30/1999 04:29'!\\nsetPort: port\\n\\t\\\"Associate a local port number with a UDP socket. Not applicable to TCP sockets.\\\"\\n\\n\\tself primSocket: socketHandle setPort: port.\\n! !\\n\\n\\n!OldSocket methodsFor: 'finalization' stamp: 'JMM 5/22/2000 22:52'!\\nfinalize\\n\\tself primSocketDestroyGently: socketHandle.\\n\\tSmalltalk unregisterExternalObject: semaphore.\\n\\tSmalltalk unregisterExternalObject: readSemaphore.\\n\\tSmalltalk unregisterExternalObject: writeSemaphore.\\n! !\\n\\n\\n!OldSocket methodsFor: 'initialize-destroy' stamp: 'JMM 5/22/2000 22:47'!\\nacceptFrom: aSocket\\n\\t\\\"Initialize a new socket handle from an accept call\\\"\\n\\t| semaIndex readSemaIndex writeSemaIndex |\\n\\n\\tprimitiveOnlySupportsOneSemaphore _ false.\\n\\tsemaphore _ Semaphore new.\\n\\treadSemaphore _ Semaphore new.\\n\\twriteSemaphore _ Semaphore new.\\n\\tsemaIndex _ Smalltalk registerExternalObject: semaphore.\\n\\treadSemaIndex _ Smalltalk registerExternalObject: readSemaphore.\\n\\twriteSemaIndex _ Smalltalk registerExternalObject: writeSemaphore.\\n\\tsocketHandle _ self primAcceptFrom: aSocket socketHandle\\n\\t\\t\\t\\t\\t\\treceiveBufferSize: 8000\\n\\t\\t\\t\\t\\t\\tsendBufSize: 8000\\n\\t\\t\\t\\t\\t\\tsemaIndex: semaIndex\\n\\t\\t\\t\\t\\t\\treadSemaIndex: readSemaIndex\\n\\t\\t\\t\\t\\t\\twriteSemaIndex: writeSemaIndex.\\n\\tsocketHandle = nil ifTrue: [ \\\"socket creation failed\\\"\\n\\t\\tSmalltalk unregisterExternalObject: semaphore.\\n\\t\\tSmalltalk unregisterExternalObject: readSemaphore.\\n\\t\\tSmalltalk unregisterExternalObject: writeSemaphore.\\n\\t\\treadSemaphore _ writeSemaphore _ semaphore _ nil\\n\\t] ifFalse:[self register].\\n! !\\n\\n!OldSocket methodsFor: 'initialize-destroy' stamp: 'JMM 5/22/2000 22:54'!\\ndestroy\\n\\t\\\"Destroy this socket. Its connection, if any, is aborted and its resources are freed. Do nothing if the socket has already been destroyed (i.e., if its socketHandle is nil).\\\"\\n\\n\\tsocketHandle = nil ifFalse: \\n\\t\\t[self isValid ifTrue: [self primSocketDestroy: socketHandle].\\n\\t\\tSmalltalk unregisterExternalObject: semaphore.\\n\\t\\tSmalltalk unregisterExternalObject: readSemaphore.\\n\\t\\tSmalltalk unregisterExternalObject: writeSemaphore.\\n\\t\\tsocketHandle _ nil.\\n\\t\\treadSemaphore _ writeSemaphore _ semaphore _ nil.\\n\\t\\tself unregister].\\n! !\\n\\n!OldSocket methodsFor: 'initialize-destroy' stamp: 'JMM 5/22/2000 23:04'!\\ninitialize: socketType\\n\\t\\\"Initialize a new socket handle. If socket creation fails, socketHandle will be set to nil.\\\"\\n\\t| semaIndex readSemaIndex writeSemaIndex |\\n\\n\\tprimitiveOnlySupportsOneSemaphore _ false.\\n\\tsemaphore _ Semaphore new.\\n\\treadSemaphore _ Semaphore new.\\n\\twriteSemaphore _ Semaphore new.\\n\\tsemaIndex _ Smalltalk registerExternalObject: semaphore.\\n\\treadSemaIndex _ Smalltalk registerExternalObject: readSemaphore.\\n\\twriteSemaIndex _ Smalltalk registerExternalObject: writeSemaphore.\\n\\tsocketHandle _\\n\\t\\tself primSocketCreateNetwork: 0\\n\\t\\t\\ttype: socketType\\n\\t\\t\\treceiveBufferSize: 8000\\n\\t\\t\\tsendBufSize: 8000\\n\\t\\t\\tsemaIndex: semaIndex\\n\\t\\t\\treadSemaIndex: readSemaIndex\\n\\t\\t\\twriteSemaIndex: writeSemaIndex.\\n\\n\\tsocketHandle = nil ifTrue: [ \\\"socket creation failed\\\"\\n\\t\\tSmalltalk unregisterExternalObject: semaphore.\\n\\t\\tSmalltalk unregisterExternalObject: readSemaphore.\\n\\t\\tSmalltalk unregisterExternalObject: writeSemaphore.\\n\\t\\treadSemaphore _ writeSemaphore _ semaphore _ nil\\n\\t] ifFalse:[self register].\\n! !\\n\\n\\n!OldSocket methodsFor: 'other' stamp: 'JMM 6/3/2000 19:39'!\\ngetOption: aName \\n\\t\\\"Get options on this socket, see Unix man pages for values for \\n\\tsockets, IP, TCP, UDP. IE SO_KEEPALIVE\\n\\treturns an array, element one is an status number (0 ok, -1 read only option)\\n\\telement two is the resulting of the requested option\\\"\\n\\n\\t(socketHandle == nil or: [self isValid not])\\n\\t\\tifTrue: [self error: 'Socket status must valid before getting an option'].\\n\\t^self primSocket: socketHandle getOption: aName\\n\\n\\\"| foo options |\\nSocket initializeNetwork.\\nfoo _ Socket newTCP.\\nfoo connectTo: (NetNameResolver addressFromString: '192.168.1.1') port: 80.\\nfoo waitForConnectionUntil: (Socket standardDeadline).\\n\\noptions _ {\\n'SO_DEBUG'. 'SO_REUSEADDR'. 'SO_REUSEPORT'. 'SO_DONTROUTE'.\\n'SO_BROADCAST'. 'SO_SNDBUF'. 'SO_RCVBUF'. 'SO_KEEPALIVE'.\\n'SO_OOBINLINE'. 'SO_PRIORITY'. 'SO_LINGER'. 'SO_RCVLOWAT'.\\n'SO_SNDLOWAT'. 'IP_TTL'. 'IP_HDRINCL'. 'IP_RCVOPTS'.\\n'IP_RCVDSTADDR'. 'IP_MULTICAST_IF'. 'IP_MULTICAST_TTL'.\\n'IP_MULTICAST_LOOP'. 'UDP_CHECKSUM'. 'TCP_MAXSEG'.\\n'TCP_NODELAY'. 'TCP_ABORT_THRESHOLD'. 'TCP_CONN_NOTIFY_THRESHOLD'. \\n'TCP_CONN_ABORT_THRESHOLD'. 'TCP_NOTIFY_THRESHOLD'.\\n'TCP_URGENT_PTR_TYPE'}.\\n\\n1 to: options size do: [:i | | fum |\\n\\tfum _foo getOption: (options at: i).\\n\\tTranscript show: (options at: i),fum printString;cr].\\n\\nfoo _ Socket newUDP.\\nfoo setPeer: (NetNameResolver addressFromString: '192.168.1.9') port: 7.\\nfoo waitForConnectionUntil: (Socket standardDeadline).\\n\\n1 to: options size do: [:i | | fum |\\n\\tfum _foo getOption: (options at: i).\\n\\tTranscript show: (options at: i),fum printString;cr].\\n\\\"! !\\n\\n!OldSocket methodsFor: 'other' stamp: 'nk 2/24/2005 14:37'!\\ngetResponseNoLF\\n\\t\\\"Get the response to the last command.\\\"\\n\\n\\t| buf response bytesRead c lf |\\n\\t(self waitForDataUntil: (self class deadlineSecs: 20)) \\n\\t\\tifFalse: [self error: 'getResponse timeout'].\\n\\tlf := Character lf.\\n\\tbuf := String new: 1000.\\n\\tresponse := WriteStream on: ''.\\n\\t[self dataAvailable] whileTrue: \\n\\t\\t\\t[bytesRead := self \\n\\t\\t\\t\\t\\t\\tprimSocket: socketHandle\\n\\t\\t\\t\\t\\t\\treceiveDataInto: buf\\n\\t\\t\\t\\t\\t\\tstartingAt: 1\\n\\t\\t\\t\\t\\t\\tcount: buf size.\\n\\t\\t\\t1 to: bytesRead\\n\\t\\t\\t\\tdo: [:i | (c := buf at: i) ~= lf ifTrue: [response nextPut: c]]].\\n\\t^response contents! !\\n\\n!OldSocket methodsFor: 'other' stamp: 'JMM 6/3/2000 19:39'!\\nsetOption: aName value: aValue \\n\\t| value |\\n\\t\\\"setup options on this socket, see Unix man pages for values for \\n\\tsockets, IP, TCP, UDP. IE SO_KEEPALIVE\\n\\treturns an array, element one is the error number\\n\\telement two is the resulting of the negotiated value.\\n\\tSee getOption for list of keys\\\"\\n\\n\\t(socketHandle == nil or: [self isValid not])\\n\\t\\tifTrue: [self error: 'Socket status must valid before setting an option'].\\n\\tvalue _ aValue asString.\\n\\taValue == true ifTrue: [value _ '1'].\\n\\taValue == false ifTrue: [value _ '0'].\\n\\t^ self primSocket: socketHandle setOption: aName value: value! !\\n\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimAcceptFrom: aHandle receiveBufferSize: rcvBufSize sendBufSize: sndBufSize semaIndex: semaIndex\\n\\t\\\"Create and return a new socket handle based on accepting the connection from the given listening socket\\\"\\n\\t<primitive: 'primitiveSocketAccept' module: 'SocketPlugin'>\\n\\t^self primitiveFailed! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'JMM 5/22/2000 22:55'!\\nprimAcceptFrom: aHandle receiveBufferSize: rcvBufSize sendBufSize: sndBufSize semaIndex: semaIndex readSemaIndex: aReadSema writeSemaIndex: aWriteSema\\n\\t\\\"Create and return a new socket handle based on accepting the connection from the given listening socket\\\"\\n\\t<primitive: 'primitiveSocketAccept3Semaphores' module: 'SocketPlugin'>\\n\\tprimitiveOnlySupportsOneSemaphore _ true.\\n\\t^self primAcceptFrom: aHandle receiveBufferSize: rcvBufSize sendBufSize: sndBufSize semaIndex: semaIndex ! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID connectTo: hostAddress port: port\\n\\t\\\"Attempt to establish a connection to the given port of the given host. This is an asynchronous call; query the socket status to discover if and when the connection is actually completed.\\\"\\n\\n\\t<primitive: 'primitiveSocketConnectToPort' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'JMM 5/25/2000 21:48'!\\nprimSocket: socketID getOption: aString \\n\\t\\\"Get some option information on this socket. Refer to the UNIX \\n\\tman pages for valid SO, TCP, IP, UDP options. In case of doubt\\n\\trefer to the source code.\\n\\tTCP_NODELAY, SO_KEEPALIVE are valid options for example\\n\\treturns an array containing the error code and the option value\\\"\\n\\n\\t<primitive: 'primitiveSocketGetOptions' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID listenOn: port\\n\\t\\\"Listen for a connection on the given port. This is an asynchronous call; query the socket status to discover if and when the connection is actually completed.\\\"\\n\\n\\t<primitive: 'primitiveSocketListenWithOrWithoutBacklog' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: aHandle listenOn: portNumber backlogSize: backlog\\n\\t\\\"Primitive. Set up the socket to listen on the given port.\\n\\tWill be used in conjunction with #accept only.\\\"\\n\\t<primitive: 'primitiveSocketListenWithOrWithoutBacklog' module: 'SocketPlugin'>\\n\\tself destroy. \\\"Accept not supported so clean up\\\"! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ikp 9/1/2003 20:55'!\\nprimSocket: aHandle listenOn: portNumber backlogSize: backlog interface: ifAddr\\n\\t\\\"Primitive. Set up the socket to listen on the given port.\\n\\tWill be used in conjunction with #accept only.\\\"\\n\\t<primitive: 'primitiveSocketListenOnPortBacklogInterface' module: 'SocketPlugin'>\\n\\tself destroy. \\\"Accept not supported so clean up\\\"! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID receiveDataInto: aStringOrByteArray startingAt: startIndex count: count\\n\\t\\\"Receive data from the given socket into the given array starting at the given index. Return the number of bytes read or zero if no data is available.\\\"\\n\\n\\t<primitive: 'primitiveSocketReceiveDataBufCount' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'JMM 5/24/2000 17:19'!\\nprimSocket: socketID receiveUDPDataInto: aStringOrByteArray startingAt: startIndex count: count\\n\\t\\\"Receive data from the given socket into the given array starting at the given index. \\n\\tReturn an Array containing the amount read, the host address byte array, the host port, and the more flag\\\"\\n\\n\\t<primitive: 'primitiveSocketReceiveUDPDataBufCount' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID sendData: aStringOrByteArray startIndex: startIndex count: count\\n\\t\\\"Send data to the remote host through the given socket starting with the given byte index of the given byte array. The data sent is 'pushed' immediately. Return the number of bytes of data actually sent; any remaining data should be re-submitted for sending after the current send operation has completed.\\\"\\n\\t\\\"Note: In general, it many take several sendData calls to transmit a large data array since the data is sent in send-buffer-sized chunks. The size of the send buffer is determined when the socket is created.\\\"\\n\\n\\t<primitive: 'primitiveSocketSendDataBufCount' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'JMM 5/25/2000 00:08'!\\nprimSocket: socketID sendUDPData: aStringOrByteArray toHost: hostAddress port: portNumber startIndex: startIndex count: count\\n\\t\\\"Send data to the remote host through the given socket starting with the given byte index of the given byte array. The data sent is 'pushed' immediately. Return the number of bytes of data actually sent; any remaining data should be re-submitted for sending after the current send operation has completed.\\\"\\n\\t\\\"Note: In general, it many take several sendData calls to transmit a large data array since the data is sent in send-buffer-sized chunks. The size of the send buffer is determined when the socket is created.\\\"\\n\\n\\t<primitive: 'primitiveSocketSendUDPDataBufCount' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 7/18/2000 11:42'!\\nprimSocket: socketID setOption: aString value: aStringValue\\n\\t\\\"Set some option information on this socket. Refer to the UNIX \\n\\tman pages for valid SO, TCP, IP, UDP options. In case of doubt\\n\\trefer to the source code.\\n\\tTCP_NODELAY, SO_KEEPALIVE are valid options for example\\n\\treturns an array containing the error code and the negotiated value\\\"\\n\\n\\t<primitive: 'primitiveSocketSetOptions' module: 'SocketPlugin'>\\n\\t^nil! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID setPort: port\\n\\t\\\"Set the local port associated with a UDP socket.\\n\\tNote: this primitive is overloaded. The primitive will not fail on a TCP socket, but\\n\\tthe effects will not be what was desired. Best solution would be to split Socket into\\n\\ttwo subclasses, TCPSocket and UDPSocket.\\\"\\n\\n\\t<primitive: 'primitiveSocketListenWithOrWithoutBacklog' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketAbortConnection: socketID\\n\\t\\\"Terminate the connection on the given port immediately without going through the normal close sequence. This is an asynchronous call; query the socket status to discover if and when the connection is actually terminated.\\\"\\n\\n\\t<primitive: 'primitiveSocketAbortConnection' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketCloseConnection: socketID\\n\\t\\\"Close the connection on the given port. The remote end is informed that this end has closed and will do no further sends. This is an asynchronous call; query the socket status to discover if and when the connection is actually closed.\\\"\\n\\n\\t<primitive: 'primitiveSocketCloseConnection' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketConnectionStatus: socketID\\n\\t\\\"Return an integer reflecting the connection status of this socket. For a list of possible values, see the comment in the 'initialize' method of this class. If the primitive fails, return a status indicating that the socket handle is no longer valid, perhaps because the Squeak image was saved and restored since the socket was created. (Sockets do not survive snapshots.)\\\"\\n\\n\\t<primitive: 'primitiveSocketConnectionStatus' module: 'SocketPlugin'>\\n\\t^ InvalidSocket\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketCreateNetwork: netType type: socketType receiveBufferSize: rcvBufSize sendBufSize: sendBufSize semaIndex: semaIndex\\n\\t\\\"Return a new socket handle for a socket of the given type and buffer sizes. Return nil if socket creation fails.\\n\\tThe netType parameter is platform dependent and can be used to encode both the protocol type (IP, Xerox XNS, etc.) and/or the physical network interface to use if this host is connected to multiple networks. A zero netType means to use IP protocols and the primary (or only) network interface.\\n\\tThe socketType parameter specifies:\\n\\t\\t0\\treliable stream socket (TCP if the protocol is IP)\\n\\t\\t1\\tunreliable datagram socket (UDP if the protocol is IP)\\n\\tThe buffer size parameters allow performance to be tuned to the application. For example, a larger receive buffer should be used when the application expects to be receiving large amounts of data, especially from a host that is far away. These values are considered requests only; the underlying implementation will ensure that the buffer sizes actually used are within allowable bounds. Note that memory may be limited, so an application that keeps many sockets open should use smaller buffer sizes. Note the macintosh implementation ignores this buffer size. Also see setOption to get/set socket buffer sizes which allows you to set/get the current buffer sizes for reading and writing.\\n \\tIf semaIndex is > 0, it is taken to be the index of a Semaphore in the external objects array to be associated with this socket. This semaphore will be signalled when the socket status changes, such as when data arrives or a send completes. All processes waiting on the semaphore will be awoken for each such event; each process must then query the socket state to figure out if the conditions they are waiting for have been met. For example, a process waiting to send some data can see if the last send has completed.\\\"\\n\\n\\t<primitive: 'primitiveSocketCreate' module: 'SocketPlugin'>\\n\\t^ nil \\\"socket creation failed\\\"\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'JMM 5/22/2000 22:48'!\\nprimSocketCreateNetwork: netType type: socketType receiveBufferSize: rcvBufSize sendBufSize: sendBufSize semaIndex: semaIndex readSemaIndex: aReadSema writeSemaIndex: aWriteSema\\n\\t\\\"See comment in primSocketCreateNetwork: with one semaIndex. However you should know that some implementations\\n\\tignore the buffer size and this interface supports three semaphores, one for open/close/listen and the other two for\\n\\treading and writing\\\"\\n\\n\\t<primitive: 'primitiveSocketCreate3Semaphores' module: 'SocketPlugin'>\\n\\tprimitiveOnlySupportsOneSemaphore _ true.\\n\\t^ self primSocketCreateNetwork: netType\\n\\t\\t\\ttype: socketType\\n\\t\\t\\treceiveBufferSize: rcvBufSize\\n\\t\\t\\tsendBufSize: sendBufSize\\n\\t\\t\\tsemaIndex: semaIndex! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketDestroy: socketID\\n\\t\\\"Release the resources associated with this socket. If a connection is open, it is aborted.\\\"\\n\\n\\t<primitive: 'primitiveSocketDestroy' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketDestroyGently: socketID\\n\\t\\\"Release the resources associated with this socket. If a connection is open, it is aborted.\\n\\tDo not fail if the receiver is already closed.\\\"\\n\\n\\t<primitive: 'primitiveSocketDestroy' module: 'SocketPlugin'>\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketError: socketID\\n\\t\\\"Return an integer encoding the most recent error on this socket. Zero means no error.\\\"\\n\\n\\t<primitive: 'primitiveSocketError' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketLocalAddress: socketID\\n\\t\\\"Return the local host address for this socket.\\\"\\n\\n\\t<primitive: 'primitiveSocketLocalAddress' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketLocalPort: socketID\\n\\t\\\"Return the local port for this socket, or zero if no port has yet been assigned.\\\"\\n\\n\\t<primitive: 'primitiveSocketLocalPort' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketReceiveDataAvailable: socketID\\n\\t\\\"Return true if data may be available for reading from the current socket.\\\"\\n\\n\\t<primitive: 'primitiveSocketReceiveDataAvailable' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketRemoteAddress: socketID\\n\\t\\\"Return the remote host address for this socket, or zero if no connection has been made.\\\"\\n\\n\\t<primitive: 'primitiveSocketRemoteAddress' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketRemotePort: socketID\\n\\t\\\"Return the remote port for this socket, or zero if no connection has been made.\\\"\\n\\n\\t<primitive: 'primitiveSocketRemotePort' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!OldSocket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketSendDone: socketID\\n\\t\\\"Return true if there is no send in progress on the current socket.\\\"\\n\\n\\t<primitive: 'primitiveSocketSendDone' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n\\n!OldSocket methodsFor: 'printing' stamp: 'jm 11/23/1998 11:57'!\\nprintOn: aStream\\n\\n\\tsuper printOn: aStream.\\n\\taStream nextPutAll: '[', self statusString, ']'.\\n! !\\n\\n\\n!OldSocket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:52'!\\ndataAvailable\\n\\t\\\"Return true if this socket has unread received data.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ self primSocketReceiveDataAvailable: socketHandle\\n! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:52'!\\nisConnected\\n\\t\\\"Return true if this socket is connected.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == Connected\\n! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'JMM 5/5/2000 12:15'!\\nisOtherEndClosed\\n\\t\\\"Return true if this socket had the other end closed.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == OtherEndClosed\\n! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'JMM 5/5/2000 12:17'!\\nisThisEndClosed\\n\\t\\\"Return true if this socket had the this end closed.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == ThisEndClosed\\n! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:54'!\\nisUnconnected\\n\\t\\\"Return true if this socket's state is Unconnected.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == Unconnected\\n! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:54'!\\nisUnconnectedOrInvalid\\n\\t\\\"Return true if this socket is completely disconnected or is invalid.\\\"\\n\\n\\t| status |\\n\\tsocketHandle == nil ifTrue: [^ true].\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t^ (status = Unconnected) | (status = InvalidSocket)\\n! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:51'!\\nisValid\\n\\t\\\"Return true if this socket contains a valid, non-nil socket handle.\\\"\\n\\n\\t| status |\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t^ status ~= InvalidSocket\\n! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:54'!\\nisWaitingForConnection\\n\\t\\\"Return true if this socket is waiting for a connection.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == WaitingForConnection\\n! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:54'!\\nsendDone\\n\\t\\\"Return true if the most recent send operation on this socket has completed.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ self primSocketSendDone: socketHandle\\n! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'JMM 5/8/2000 23:24'!\\nsocketError\\n\\t^self primSocketError: socketHandle! !\\n\\n!OldSocket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:56'!\\nstatusString\\n\\t\\\"Return a string describing the status of this socket.\\\"\\n\\n\\t| status |\\n\\tsocketHandle == nil ifTrue: [^ 'destroyed'].\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\tstatus = InvalidSocket ifTrue: [^ 'invalidSocketHandle'].\\n\\tstatus = Unconnected ifTrue: [^ 'unconnected'].\\n\\tstatus = WaitingForConnection ifTrue: [^ 'waitingForConnection'].\\n\\tstatus = Connected ifTrue: [^ 'connected'].\\n\\tstatus = OtherEndClosed ifTrue: [^ 'otherEndClosedButNotThisEnd'].\\n\\tstatus = ThisEndClosed ifTrue: [^ 'thisEndClosedButNotOtherEnd'].\\n\\t^ 'unknown socket status'\\n! !\\n\\n\\n!OldSocket methodsFor: 'registry' stamp: 'ar 3/21/98 17:40'!\\nregister\\n\\t^self class register: self! !\\n\\n!OldSocket methodsFor: 'registry' stamp: 'ar 3/21/98 17:41'!\\nunregister\\n\\t^self class unregister: self! !\\n\\n\\n!OldSocket methodsFor: 'sending-receiving' stamp: 'jm 9/15/97 12:22'!\\ndiscardReceivedData\\n\\t\\\"Discard any data received up until now, and return the number of bytes discarded.\\\"\\n\\n\\t| buf totalBytesDiscarded |\\n\\tbuf _ String new: 10000.\\n\\ttotalBytesDiscarded _ 0.\\n\\t[self isConnected and: [self dataAvailable]] whileTrue: [\\n\\t\\ttotalBytesDiscarded _\\n\\t\\t\\ttotalBytesDiscarded + (self receiveDataInto: buf)].\\n\\t^ totalBytesDiscarded\\n! !\\n\\n!OldSocket methodsFor: 'sending-receiving' stamp: 'nk 2/24/2005 14:37'!\\ngetData\\n\\t\\\"Get some data\\\"\\n\\n\\t| buf bytesRead |\\n\\t(self waitForDataUntil: self class standardDeadline) \\n\\t\\tifFalse: [self error: 'getData timeout'].\\n\\tbuf := String new: 4000.\\n\\tbytesRead := self \\n\\t\\t\\t\\tprimSocket: socketHandle\\n\\t\\t\\t\\treceiveDataInto: buf\\n\\t\\t\\t\\tstartingAt: 1\\n\\t\\t\\t\\tcount: buf size.\\n\\t^buf copyFrom: 1 to: bytesRead! !\\n\\n!OldSocket methodsFor: 'sending-receiving' stamp: 'nk 2/24/2005 14:37'!\\nreadInto: aStringOrByteArray startingAt: aNumber \\n\\t\\\"Read data into the given buffer starting at the given index and return the number of bytes received. Note the given buffer may be only partially filled by the received data.\\\"\\n\\n\\t(self waitForDataUntil: self class standardDeadline) \\n\\t\\tifFalse: [self error: 'receive timeout'].\\n\\t^self \\n\\t\\tprimSocket: socketHandle\\n\\t\\treceiveDataInto: aStringOrByteArray\\n\\t\\tstartingAt: aNumber\\n\\t\\tcount: aStringOrByteArray size - aNumber + 1! !\\n\\n!OldSocket methodsFor: 'sending-receiving' stamp: 'jm 9/15/97 12:21'!\\nreceiveDataInto: aStringOrByteArray\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. Note the given buffer may be only partially filled by the received data.\\\"\\n\\n\\t^ self primSocket: socketHandle\\n\\t\\treceiveDataInto: aStringOrByteArray\\n\\t\\tstartingAt: 1\\n\\t\\tcount: aStringOrByteArray size\\n! !\\n\\n!OldSocket methodsFor: 'sending-receiving' stamp: 'tak 3/16/2005 16:51'!\\nsendData: aStringOrByteArray\\n\\t\\\"Send all of the data in the given array, even if it requires multiple calls to send it all. Return the number of bytes sent.\\\"\\n\\n\\t\\\"An experimental version use on slow lines: Longer timeout and smaller writes to try to avoid spurious timeouts.\\\"\\n\\n\\t| bytesSent bytesToSend count |\\n\\tbytesToSend _ aStringOrByteArray size.\\n\\tbytesSent _ 0.\\n\\t[bytesSent < bytesToSend] whileTrue: [\\n\\t\\t(self waitForSendDoneUntil: (Socket deadlineSecs: 60))\\n\\t\\t\\tifFalse: [ConnectionTimedOut signal: 'send data timeout; data not sent'].\\n\\t\\tcount _ self primSocket: socketHandle\\n\\t\\t\\tsendData: aStringOrByteArray\\n\\t\\t\\tstartIndex: bytesSent + 1\\n\\t\\t\\tcount: (bytesToSend - bytesSent min: 5000).\\n\\t\\tbytesSent _ bytesSent + count].\\n\\n\\t^ bytesSent\\n! !\\n\\n!OldSocket methodsFor: 'sending-receiving' stamp: 'ar 7/20/1999 17:23'!\\nsendData: buffer count: n\\n\\t\\\"Send the amount of data from the given buffer\\\"\\n\\t| sent |\\n\\tsent _ 0.\\n\\t[sent < n] whileTrue:[\\n\\t\\tsent _ sent + (self sendSomeData: buffer startIndex: sent+1 count: (n-sent))].! !\\n\\n!OldSocket methodsFor: 'sending-receiving' stamp: 'ls 1/5/1999 15:05'!\\nsendSomeData: aStringOrByteArray\\n\\t\\\"Send as much of the given data as possible and answer the number of bytes actually sent.\\\"\\n\\t\\\"Note: This operation may have to be repeated multiple times to send a large amount of data.\\\"\\n\\n\\t^ self\\n\\t\\tsendSomeData: aStringOrByteArray\\n\\t\\tstartIndex: 1\\n\\t\\tcount: aStringOrByteArray size! !\\n\\n!OldSocket methodsFor: 'sending-receiving' stamp: 'ls 3/3/1999 18:59'!\\nsendSomeData: aStringOrByteArray startIndex: startIndex\\n\\t\\\"Send as much of the given data as possible starting at the given index. Answer the number of bytes actually sent.\\\"\\n\\t\\\"Note: This operation may have to be repeated multiple times to send a large amount of data.\\\"\\n\\n\\t^ self\\n\\t\\tsendSomeData: aStringOrByteArray\\n\\t\\tstartIndex: startIndex\\n\\t\\tcount: (aStringOrByteArray size - startIndex + 1)! !\\n\\n!OldSocket methodsFor: 'sending-receiving' stamp: 'nk 2/24/2005 14:37'!\\nsendSomeData: aStringOrByteArray startIndex: startIndex count: count \\n\\t\\\"Send up to count bytes of the given data starting at the given index. Answer the number of bytes actually sent.\\\"\\n\\n\\t\\\"Note: This operation may have to be repeated multiple times to send a large amount of data.\\\"\\n\\n\\t| bytesSent |\\n\\t(self waitForSendDoneUntil: (self class deadlineSecs: 20)) \\n\\t\\tifTrue: \\n\\t\\t\\t[bytesSent := self \\n\\t\\t\\t\\t\\t\\tprimSocket: socketHandle\\n\\t\\t\\t\\t\\t\\tsendData: aStringOrByteArray\\n\\t\\t\\t\\t\\t\\tstartIndex: startIndex\\n\\t\\t\\t\\t\\t\\tcount: count]\\n\\t\\tifFalse: [self error: 'send data timeout; data not sent'].\\n\\t^bytesSent! !\\n\\n\\n!OldSocket methodsFor: 'waiting' stamp: 'ar 7/20/1999 17:21'!\\nwaitForAcceptUntil: deadLine\\n\\t\\\"Wait and accept an incoming connection\\\"\\n\\tself waitForConnectionUntil: deadLine.\\n\\t^self isConnected\\n\\t\\tifTrue:[self accept]\\n\\t\\tifFalse:[nil]! !\\n\\n!OldSocket methodsFor: 'waiting' stamp: 'jm 3/2/98 18:15'!\\nwaitForConnectionUntil: deadline\\n\\t\\\"Wait up until the given deadline for a connection to be established. Return true if it is established by the deadline, false if not.\\\"\\n\\n\\t| status |\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t[(status = WaitingForConnection) and: [Time millisecondClockValue < deadline]]\\n\\t\\twhileTrue: [\\n\\t\\t\\tsemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue).\\n\\t\\t\\tstatus _ self primSocketConnectionStatus: socketHandle].\\n\\n\\t^ status = Connected\\n! !\\n\\n!OldSocket methodsFor: 'waiting' stamp: 'JMM 5/22/2000 22:04'!\\nwaitForDataUntil: deadline\\n\\t\\\"Wait up until the given deadline for data to arrive. Return true if data arrives by the deadline, false if not.\\\"\\n\\n\\t| dataArrived |\\n\\t[self isConnected & \\n\\t (dataArrived _ self primSocketReceiveDataAvailable: socketHandle) not\\n\\t\\t\\t\\\"Connection end and final data can happen fast, so test in this order\\\"\\n\\t\\tand: [Time millisecondClockValue < deadline]] whileTrue: [\\n\\t\\t\\tself readSemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue)].\\n\\n\\t^ dataArrived\\n! !\\n\\n!OldSocket methodsFor: 'waiting' stamp: 'JMM 5/17/2000 14:52'!\\nwaitForDisconnectionUntil: deadline\\n\\t\\\"Wait up until the given deadline for the the connection to be broken. Return true if it is broken by the deadline, false if not.\\\"\\n\\t\\\"Note: The client should know the the connect is really going to be closed (e.g., because he has called 'close' to send a close request to the other end) before calling this method.\\nJMM 00/5/17 note that other end can close which will terminate wait\\\"\\n\\n\\t| extraBytes status |\\n\\textraBytes _ 0.\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t[((status = Connected) or: [(status = ThisEndClosed)]) and:\\n\\t [Time millisecondClockValue < deadline]] whileTrue: [\\n\\t\\tself dataAvailable\\n\\t\\t\\tifTrue: [extraBytes _ extraBytes + self discardReceivedData].\\n\\t\\tsemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue).\\n\\t\\tstatus _ self primSocketConnectionStatus: socketHandle].\\n\\n\\textraBytes > 0\\n\\t\\tifTrue: [self inform: 'Discarded ', extraBytes printString, ' bytes while closing connection.'].\\n\\n\\t^ status ~= Connected\\n! !\\n\\n!OldSocket methodsFor: 'waiting' stamp: 'JMM 5/22/2000 22:05'!\\nwaitForSendDoneUntil: deadline\\n\\t\\\"Wait up until the given deadline for the current send operation to complete. Return true if it completes by the deadline, false if not.\\\"\\n\\n\\t| sendDone |\\n\\t[self isConnected & (sendDone _ self primSocketSendDone: socketHandle) not\\n\\t\\t\\t\\\"Connection end and final data can happen fast, so test in this order\\\"\\n\\t\\tand: [Time millisecondClockValue < deadline]] whileTrue: [\\n\\t\\t\\tself writeSemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue)].\\n\\n\\t^ sendDone! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOldSocket class\\n\\tinstanceVariableNames: ''!\\n\\n!OldSocket class methodsFor: 'class initialization' stamp: 'ar 12/12/2001 19:12'!\\ninitialize\\n\\t\\\"Socket initialize\\\"\\n\\n\\t\\\"Socket Types\\\"\\n\\tTCPSocketType _ 0.\\n\\tUDPSocketType _ 1.\\n\\n\\t\\\"Socket Status Values\\\"\\n\\tInvalidSocket _ -1.\\n\\tUnconnected _ 0.\\n\\tWaitingForConnection _ 1.\\n\\tConnected _ 2.\\n\\tOtherEndClosed _ 3.\\n\\tThisEndClosed _ 4.\\n\\n\\tRegistryThreshold _ 100. \\\"# of sockets\\\"! !\\n\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'nk 2/24/2005 14:38'!\\nclientServerTestUDP\\n\\t\\\"Socket clientServerTestUDP\\\"\\n\\n\\t\\\"Performa 6400/200, Linux-PPC 2.1.24:\\n\\t\\tclient/server UDP test done; time = 2820\\n\\t\\t2500 packets, 10000000 bytes sent (3546 kBytes/sec)\\n\\t\\t2500 packets, 10000000 bytes received (3546 kBytes/sec)\\n\\t\\t4000 bytes/packet, 886 packets/sec, 0 packets dropped\\\"\\n\\n\\t| sock1 sock2 bytesToSend sendBuf receiveBuf done bytesSent bytesReceived packetsSent packetsReceived t |\\n\\tTranscript\\n\\t\\tshow: 'starting client/server UDP test';\\n\\t\\tcr.\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: 'creating endpoints';\\n\\t\\tcr.\\n\\tsock1 := self newUDP.\\t\\\"the sender\\\"\\n\\tsock2 := self newUDP.\\t\\\"the recipient\\\"\\n\\tsock2 setPort: 54321.\\n\\tsock1 setPeer: NetNameResolver localHostAddress port: sock2 port.\\n\\tTranscript\\n\\t\\tshow: 'endpoints created';\\n\\t\\tcr.\\n\\tbytesToSend := 10000000.\\n\\tsendBuf := String new: 4000 withAll: $x.\\n\\treceiveBuf := String new: 50000.\\n\\tdone := false.\\n\\tbytesSent := bytesReceived := packetsSent := packetsReceived := 0.\\n\\tt := Time millisecondsToRun: \\n\\t\\t\\t\\t\\t[[done] whileFalse: \\n\\t\\t\\t\\t\\t\\t\\t[(sock1 sendDone and: [bytesSent < bytesToSend]) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsSent := packetsSent + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesSent := bytesSent + (sock1 sendData: sendBuf)].\\n\\t\\t\\t\\t\\t\\t\\tsock2 dataAvailable \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsReceived := packetsReceived + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesReceived := bytesReceived + (sock2 receiveDataInto: receiveBuf)].\\n\\t\\t\\t\\t\\t\\t\\tdone := bytesSent >= bytesToSend].\\n\\t\\t\\t\\t\\tsock1 waitForSendDoneUntil: self standardDeadline.\\n\\t\\t\\t\\t\\tbytesReceived := bytesReceived + sock2 discardReceivedData].\\n\\tTranscript\\n\\t\\tshow: 'closing endpoints';\\n\\t\\tcr.\\n\\tsock1 close.\\n\\tsock2 close.\\n\\tsock1 destroy.\\n\\tsock2 destroy.\\n\\tTranscript\\n\\t\\tshow: 'client/server UDP test done; time = ' , t printString;\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: packetsSent printString , ' packets, ' , bytesSent printString \\n\\t\\t\\t\\t\\t, ' bytes sent (' , (bytesSent * 1000 // t) printString \\n\\t\\t\\t\\t\\t, ' Bytes/sec)';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: packetsReceived printString , ' packets, ' \\n\\t\\t\\t\\t\\t, bytesReceived printString , ' bytes received (' \\n\\t\\t\\t\\t\\t, (bytesReceived * 1000 // t) printString , ' Bytes/sec)';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: (bytesSent // packetsSent) printString , ' bytes/packet, ' \\n\\t\\t\\t\\t\\t, (packetsReceived * 1000 // t) printString , ' packets/sec, ' \\n\\t\\t\\t\\t\\t, (packetsSent - packetsReceived) printString , ' packets dropped';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'nk 2/24/2005 14:38'!\\nclientServerTestUDP2\\n\\t\\\"Socket clientServerTestUDP2\\\"\\n\\n\\t| sock1 sock2 bytesToSend sendBuf receiveBuf done bytesSent bytesReceived packetsSent packetsReceived t datagramInfo |\\n\\tTranscript\\n\\t\\tshow: 'starting client/server UDP test';\\n\\t\\tcr.\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: 'creating endpoints';\\n\\t\\tcr.\\n\\tsock1 := self newUDP.\\t\\\"the sender\\\"\\n\\tsock2 := self newUDP.\\t\\\"the recipient\\\"\\n\\tsock2 setPort: 54321.\\n\\tTranscript\\n\\t\\tshow: 'endpoints created';\\n\\t\\tcr.\\n\\tbytesToSend := 100000000.\\n\\tsendBuf := String new: 4000 withAll: $x.\\n\\treceiveBuf := String new: 2000.\\n\\tdone := false.\\n\\tbytesSent := bytesReceived := packetsSent := packetsReceived := 0.\\n\\tt := Time millisecondsToRun: \\n\\t\\t\\t\\t\\t[[done] whileFalse: \\n\\t\\t\\t\\t\\t\\t\\t[(sock1 sendDone and: [bytesSent < bytesToSend]) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsSent := packetsSent + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesSent := bytesSent + (sock1 \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tsendData: sendBuf\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\ttoHost: NetNameResolver localHostAddress\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tport: sock2 port)].\\n\\t\\t\\t\\t\\t\\t\\tsock2 dataAvailable \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsReceived := packetsReceived + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tdatagramInfo := sock2 receiveUDPDataInto: receiveBuf.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesReceived := bytesReceived + (datagramInfo at: 1)].\\n\\t\\t\\t\\t\\t\\t\\tdone := bytesSent >= bytesToSend].\\n\\t\\t\\t\\t\\tsock1 waitForSendDoneUntil: self standardDeadline.\\n\\t\\t\\t\\t\\tbytesReceived := bytesReceived + sock2 discardReceivedData].\\n\\tTranscript\\n\\t\\tshow: 'closing endpoints';\\n\\t\\tcr.\\n\\tsock1 close.\\n\\tsock2 close.\\n\\tsock1 destroy.\\n\\tsock2 destroy.\\n\\tTranscript\\n\\t\\tshow: 'client/server UDP test done; time = ' , t printString;\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: packetsSent printString , ' packets, ' , bytesSent printString \\n\\t\\t\\t\\t\\t, ' bytes sent (' , (bytesSent * 1000 // t) printString \\n\\t\\t\\t\\t\\t, ' Bytes/sec)';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: packetsReceived printString , ' packets, ' \\n\\t\\t\\t\\t\\t, bytesReceived printString , ' bytes received (' \\n\\t\\t\\t\\t\\t, (bytesReceived * 1000 // t) printString , ' Bytes/sec)';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: (bytesSent // packetsSent) printString , ' bytes/packet, ' \\n\\t\\t\\t\\t\\t, (packetsReceived * 1000 // t) printString , ' packets/sec, ' \\n\\t\\t\\t\\t\\t, (packetsSent - packetsReceived) printString , ' packets dropped';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'rbb 3/1/2005 11:02'!\\nremoteTestClientTCP\\n\\t\\\"FIRST start up another image, and execute: Socket remoteTestServerTCP.\\n\\tTHEN come back to this image and execute:\\\"\\n\\n\\t\\\"Socket remoteTestClientTCP\\\"\\n\\n\\t\\\"Performa 6400/200, Linux-PPC 2.1.24, both images on same CPU:\\n\\t\\tremoteClient TCP test done; time = 5680\\n\\t\\t250 packets, 1000000 bytes sent (176 kBytes/sec)\\n\\t\\t60 packets, 1000000 bytes received (176 kBytes/sec)\\\"\\n\\n\\t| socket bytesToSend sendBuf receiveBuf done bytesSent bytesReceived packetsSent packetsReceived t serverName |\\n\\tTranscript\\n\\t\\tshow: 'starting client/server TCP test';\\n\\t\\tcr.\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tsocket := self newTCP.\\n\\tserverName := UIManager default request: 'What is your remote Test Server?'\\n\\t\\t\\t\\tinitialAnswer: ''.\\n\\tsocket connectTo: (NetNameResolver addressFromString: serverName)\\n\\t\\tport: 54321.\\n\\tsocket waitForConnectionUntil: self standardDeadline.\\n\\tTranscript\\n\\t\\tshow: 'client endpoint created';\\n\\t\\tcr.\\n\\tbytesToSend := 1000000.\\n\\tsendBuf := String new: 4000 withAll: $x.\\n\\treceiveBuf := String new: 50000.\\n\\tdone := false.\\n\\tbytesSent := bytesReceived := packetsSent := packetsReceived := 0.\\n\\tt := Time millisecondsToRun: \\n\\t\\t\\t\\t\\t[[done] whileFalse: \\n\\t\\t\\t\\t\\t\\t\\t[(socket sendDone and: [bytesSent < bytesToSend]) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsSent := packetsSent + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesSent := bytesSent + (socket sendData: sendBuf)].\\n\\t\\t\\t\\t\\t\\t\\tsocket dataAvailable \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsReceived := packetsReceived + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesReceived := bytesReceived + (socket receiveDataInto: receiveBuf)].\\n\\t\\t\\t\\t\\t\\t\\tdone := bytesSent >= bytesToSend].\\n\\t\\t\\t\\t\\t[bytesReceived < bytesToSend] whileTrue: \\n\\t\\t\\t\\t\\t\\t\\t[socket dataAvailable \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsReceived := packetsReceived + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesReceived := bytesReceived + (socket receiveDataInto: receiveBuf)]]].\\n\\tsocket closeAndDestroy.\\n\\tTranscript\\n\\t\\tshow: 'remoteClient TCP test done; time = ' , t printString;\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: packetsSent printString , ' packets, ' , bytesSent printString \\n\\t\\t\\t\\t\\t, ' bytes sent (' , (bytesSent * 1000 // t) printString \\n\\t\\t\\t\\t\\t, ' bytes/sec)';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: packetsReceived printString , ' packets, ' \\n\\t\\t\\t\\t\\t, bytesReceived printString , ' bytes received (' \\n\\t\\t\\t\\t\\t, (bytesReceived * 1000 // t) printString , ' bytes/sec)';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'rbb 3/1/2005 11:02'!\\nremoteTestClientTCPOpenClose1000\\n\\t\\\"Socket remoteTestClientTCPOpenClose1000\\\"\\n\\n\\t| number t1 socket serverName |\\n\\tTranscript\\n\\t\\tshow: 'starting client/server TCP test';\\n\\t\\tcr.\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tnumber := 1000.\\n\\tserverName := UIManager default request: 'What is your remote Test Server?'\\n\\t\\t\\t\\tinitialAnswer: ''.\\n\\tt1 := Time millisecondsToRun: \\n\\t\\t\\t\\t\\t[number timesRepeat: \\n\\t\\t\\t\\t\\t\\t\\t[socket := self newTCP.\\n\\t\\t\\t\\t\\t\\t\\tsocket connectTo: (NetNameResolver addressFromString: serverName)\\n\\t\\t\\t\\t\\t\\t\\t\\tport: 54321.\\n\\t\\t\\t\\t\\t\\t\\tsocket waitForConnectionUntil: self standardDeadline.\\n\\t\\t\\t\\t\\t\\t\\tsocket closeAndDestroy]].\\n\\tTranscript\\n\\t\\tcr;\\n\\t\\tshow: 'connects/close per second ' , (number / t1 * 1000.0) printString;\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'rbb 3/1/2005 11:03'!\\nremoteTestClientTCPOpenClosePutGet\\n\\t\\\"Socket remoteTestClientTCPOpenClosePutGet\\\"\\n\\n\\t| checkLength number bytesExpected sendBuf receiveBuf t1 socket bytesReceived serverName |\\n\\tTranscript\\n\\t\\tshow: 'starting client/server TCP test';\\n\\t\\tcr.\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tserverName := UIManager default request: 'What is your remote Test Server?'\\n\\t\\t\\t\\tinitialAnswer: ''.\\n\\tnumber := 1000.\\n\\tbytesExpected := 20000.\\n\\tsendBuf := String new: 80 withAll: $x.\\n\\treceiveBuf := String new: 50000.\\n\\tt1 := Time millisecondsToRun: \\n\\t\\t\\t\\t\\t[number timesRepeat: \\n\\t\\t\\t\\t\\t\\t\\t[socket := self newTCP.\\n\\t\\t\\t\\t\\t\\t\\tsocket connectTo: (NetNameResolver addressFromString: serverName)\\n\\t\\t\\t\\t\\t\\t\\t\\tport: 54321.\\n\\t\\t\\t\\t\\t\\t\\tsocket waitForConnectionUntil: self standardDeadline.\\n\\t\\t\\t\\t\\t\\t\\tsocket sendData: sendBuf.\\n\\t\\t\\t\\t\\t\\t\\tsocket waitForSendDoneUntil: (self deadlineSecs: 5).\\n\\t\\t\\t\\t\\t\\t\\tsocket waitForDataUntil: (self deadlineSecs: 5).\\n\\t\\t\\t\\t\\t\\t\\tbytesReceived := 0.\\n\\t\\t\\t\\t\\t\\t\\t[bytesReceived < bytesExpected] whileTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[checkLength := socket receiveDataInto: receiveBuf.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesReceived := bytesReceived + checkLength].\\n\\t\\t\\t\\t\\t\\t\\tsocket closeAndDestroy]].\\n\\tTranscript\\n\\t\\tcr;\\n\\t\\tshow: 'connects/get/put/close per second ' \\n\\t\\t\\t\\t\\t, (number / t1 * 1000.0) printString;\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'rbb 3/1/2005 11:03'!\\nremoteTestClientUDP\\n\\t\\\"FIRST start up another image, and execute: Socket remoteTestServerUDP.\\n\\tTHEN come back to this image and execute:\\\"\\n\\n\\t\\\"Socket remoteTestClientUDP\\\"\\n\\n\\t\\\"Performa 6400/200, Linux-PPC 2.1.24:\\n\\t\\tremoteClient UDP test done; time = 4580\\n\\t\\t2500 packets, 10000000 bytes sent (2183 kBytes/sec)\\n\\t\\t180 packets, 720000 bytes received (157 kBytes/sec)\\n\\t\\t4000 bytes/packet, 39 packets/sec, 2320 packets dropped\\\"\\n\\n\\t| socket bytesToSend sendBuf receiveBuf done bytesSent bytesReceived packetsSent packetsReceived t serverName |\\n\\tTranscript\\n\\t\\tshow: 'starting client/server UDP test';\\n\\t\\tcr.\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tserverName := UIManager default request: 'What is your remote Test Server?'\\n\\t\\t\\t\\tinitialAnswer: ''.\\n\\tsocket := self newUDP.\\n\\tsocket setPeer: (NetNameResolver addressFromString: serverName) port: 54321.\\n\\tTranscript\\n\\t\\tshow: 'client endpoint created';\\n\\t\\tcr.\\n\\tbytesToSend := 10000000.\\n\\tsendBuf := String new: 4000 withAll: $x.\\n\\treceiveBuf := String new: 4000.\\n\\tdone := false.\\n\\tbytesSent := bytesReceived := packetsSent := packetsReceived := 0.\\n\\tt := Time millisecondsToRun: \\n\\t\\t\\t\\t\\t[[done] whileFalse: \\n\\t\\t\\t\\t\\t\\t\\t[(socket sendDone and: [bytesSent < bytesToSend]) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsSent := packetsSent + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesSent := bytesSent + (socket sendData: sendBuf)].\\n\\t\\t\\t\\t\\t\\t\\tsocket dataAvailable \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsReceived := packetsReceived + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesReceived := bytesReceived + (socket receiveDataInto: receiveBuf)].\\n\\t\\t\\t\\t\\t\\t\\tdone := bytesSent >= bytesToSend].\\n\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t[socket waitForDataUntil: (self deadlineSecs: 1).\\n\\t\\t\\t\\t\\tsocket dataAvailable] \\n\\t\\t\\t\\t\\t\\t\\twhileTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t[packetsReceived := packetsReceived + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\tbytesReceived := bytesReceived + (socket receiveDataInto: receiveBuf)]].\\n\\tsocket closeAndDestroy.\\n\\tTranscript\\n\\t\\tshow: 'remoteClient UDP test done; time = ' , t printString;\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: packetsSent printString , ' packets, ' , bytesSent printString \\n\\t\\t\\t\\t\\t, ' bytes sent (' , (bytesSent * 1000 // t) printString \\n\\t\\t\\t\\t\\t, ' bytes/sec)';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: packetsReceived printString , ' packets, ' \\n\\t\\t\\t\\t\\t, bytesReceived printString , ' bytes received (' \\n\\t\\t\\t\\t\\t, (bytesReceived * 1000 // t) printString , ' bytes/sec)';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: (bytesSent // packetsSent) printString , ' bytes/packet, ' \\n\\t\\t\\t\\t\\t, (packetsReceived * 1000 // t) printString , ' packets/sec, ' \\n\\t\\t\\t\\t\\t, (packetsSent - packetsReceived) printString , ' packets dropped';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'nk 2/24/2005 14:38'!\\nremoteTestServerTCP\\n\\t\\\"See remoteTestClientTCP for instructions on running this method.\\\"\\n\\n\\t\\\"OldSocket remoteTestServerTCP\\\"\\n\\n\\t| socket client buffer n |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetwork.\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tsocket := OldSocket newTCP.\\n\\tsocket \\n\\t\\tlistenOn: 54321\\n\\t\\tbacklogSize: 5\\n\\t\\tinterface: (NetNameResolver addressFromString: '127.0.0.1').\\t\\\"or: 0.0.0.0\\\"\\n\\tTranscript\\n\\t\\tshow: 'server endpoint created -- run client test in other image';\\n\\t\\tcr.\\n\\tbuffer := String new: 4000.\\n\\tsocket waitForConnectionUntil: self standardDeadline.\\n\\tclient := socket accept.\\n\\t[client isConnected] whileTrue: \\n\\t\\t\\t[client dataAvailable \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[n := client receiveDataInto: buffer.\\n\\t\\t\\t\\t\\tclient sendData: buffer count: n]].\\n\\tclient closeAndDestroy.\\n\\tsocket closeAndDestroy.\\n\\tTranscript\\n\\t\\tcr;\\n\\t\\tshow: 'server endpoint destroyed';\\n\\t\\tcr.\\n\\t^socket! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'nk 2/24/2005 14:38'!\\nremoteTestServerTCPOpenClose1000\\n\\t\\\"The version of #remoteTestServerTCPOpenClose1000 using the BSD style accept() mechanism.\\\"\\n\\n\\t\\\"Socket remoteTestServerTCPOpenClose1000\\\"\\n\\n\\t| socket server |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tserver := self newTCP.\\n\\tserver listenOn: 54321 backlogSize: 20.\\n\\tserver isValid ifFalse: [self error: 'Accept() is not supported'].\\n\\tTranscript\\n\\t\\tshow: 'server endpoint created -- run client test in other image';\\n\\t\\tcr.\\n\\t1000 timesRepeat: \\n\\t\\t\\t[socket := server waitForAcceptUntil: (self deadlineSecs: 300).\\n\\t\\t\\tsocket closeAndDestroy].\\n\\tserver closeAndDestroy.\\n\\tTranscript\\n\\t\\tcr;\\n\\t\\tshow: 'server endpoint destroyed';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'nk 2/24/2005 14:38'!\\nremoteTestServerTCPOpenClosePutGet\\n\\t\\\"The version of #remoteTestServerTCPOpenClosePutGet using the BSD style accept() mechanism.\\\"\\n\\n\\t\\\"Socket remoteTestServerTCPOpenClosePutGet\\\"\\n\\n\\t| socket server bytesIWantToSend bytesExpected receiveBuf sendBuf checkLength |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tserver := self newTCP.\\n\\tserver listenOn: 54321 backlogSize: 20.\\n\\tserver isValid ifFalse: [self error: 'Accept() is not supported'].\\n\\tTranscript\\n\\t\\tshow: 'server endpoint created -- run client test in other image';\\n\\t\\tcr.\\n\\tbytesIWantToSend := 20000.\\n\\tbytesExpected := 80.\\n\\treceiveBuf := String new: 40000.\\n\\tsendBuf := String new: bytesIWantToSend withAll: $x.\\n\\t1000 timesRepeat: \\n\\t\\t\\t[socket := server waitForAcceptUntil: (self deadlineSecs: 300).\\n\\t\\t\\tsocket waitForDataUntil: (self deadlineSecs: 5).\\n\\t\\t\\tcheckLength := socket receiveDataInto: receiveBuf.\\n\\t\\t\\tcheckLength ~= bytesExpected ifTrue: [self halt].\\n\\t\\t\\tsocket sendData: sendBuf.\\n\\t\\t\\tsocket waitForSendDoneUntil: (self deadlineSecs: 5).\\n\\t\\t\\tsocket closeAndDestroy].\\n\\tserver closeAndDestroy.\\n\\tTranscript\\n\\t\\tcr;\\n\\t\\tshow: 'server endpoint destroyed';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'nk 2/24/2005 14:38'!\\nremoteTestServerTCPUsingAccept\\n\\t\\\"The version of #remoteTestServer using the BSD style accept() mechanism.\\\"\\n\\n\\t\\\"Socket remoteTestServerTCPUsingAccept\\\"\\n\\n\\t| socket buffer n server |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tserver := self newTCP.\\n\\tserver listenOn: 54321 backlogSize: 4.\\n\\tserver isValid ifFalse: [self error: 'Accept() is not supported'].\\n\\tTranscript\\n\\t\\tshow: 'server endpoint created -- run client test in other image';\\n\\t\\tcr.\\n\\tbuffer := String new: 40000.\\n\\t10 timesRepeat: \\n\\t\\t\\t[socket := server waitForAcceptUntil: (self deadlineSecs: 300).\\n\\t\\t\\t[socket isConnected] whileTrue: \\n\\t\\t\\t\\t\\t[socket dataAvailable \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[n := socket receiveDataInto: buffer.\\n\\t\\t\\t\\t\\t\\t\\tsocket sendData: buffer count: n]]].\\n\\tsocket closeAndDestroy.\\n\\tserver closeAndDestroy.\\n\\tTranscript\\n\\t\\tcr;\\n\\t\\tshow: 'server endpoint destroyed';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'nk 2/24/2005 14:38'!\\nremoteTestServerUDP\\n\\t\\\"See remoteTestClientUDP for instructions on running this method.\\\"\\n\\n\\t\\\"Socket remoteTestServerUDP\\\"\\n\\n\\t| socket buffer n |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tsocket := self newUDP.\\n\\tsocket setPort: 54321.\\n\\tTranscript\\n\\t\\tshow: 'server endpoint created -- run client test in other image';\\n\\t\\tcr.\\n\\tbuffer := String new: 4000.\\n\\t[true] whileTrue: \\n\\t\\t\\t[socket dataAvailable \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[n := socket receiveDataInto: buffer.\\n\\t\\t\\t\\t\\tsocket sendData: buffer count: n]]! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'nk 2/24/2005 14:38'!\\nremoteTestServerUDP2\\n\\t\\\"See remoteTestClientUDP for instructions on running this method.\\\"\\n\\n\\t\\\"Socket remoteTestServerUDP2\\\"\\n\\n\\t| socket buffer datagramInfo |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tsocket := self newUDP.\\n\\tsocket setPort: 54321.\\n\\tTranscript\\n\\t\\tshow: 'server endpoint created -- run client test in other image';\\n\\t\\tcr.\\n\\tbuffer := String new: 65000.\\n\\t[true] whileTrue: \\n\\t\\t\\t[socket dataAvailable \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[datagramInfo := socket receiveUDPDataInto: buffer.\\n\\t\\t\\t\\t\\tTranscript\\n\\t\\t\\t\\t\\t\\tshow: datagramInfo printString;\\n\\t\\t\\t\\t\\t\\tcr.\\n\\t\\t\\t\\t\\tsocket sendData: buffer count: (datagramInfo at: 1)]]! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'nk 2/24/2005 14:38'!\\nremoteTestSinkTCP\\n\\t\\\"See sendTest for instructions on running this method.\\\"\\n\\n\\t\\\"Socket remoteTestSinkTCP\\\"\\n\\n\\t| socket buffer n |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tsocket := self newTCP.\\n\\tsocket listenOn: 9.\\n\\tTranscript\\n\\t\\tshow: 'server endpoint created -- run client test in other image';\\n\\t\\tcr.\\n\\tbuffer := String new: 64000.\\n\\tsocket waitForConnectionUntil: self standardDeadline.\\n\\t[socket isConnected] whileTrue: \\n\\t\\t\\t[socket dataAvailable ifTrue: [n := socket receiveDataInto: buffer]].\\n\\tsocket closeAndDestroy.\\n\\tTranscript\\n\\t\\tcr;\\n\\t\\tshow: 'sink endpoint destroyed';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'rbb 3/1/2005 11:03'!\\ntimeTest\\n\\t\\\"OldSocket timeTest\\\"\\n\\n\\t| serverName serverAddr s |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tserverName := UIManager default request: 'What is your time server?'\\n\\t\\t\\t\\tinitialAnswer: 'localhost'.\\n\\tserverName isEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[^Transcript\\n\\t\\t\\t\\tshow: 'never mind';\\n\\t\\t\\t\\tcr].\\n\\tserverAddr := NetNameResolver addressForName: serverName timeout: 10.\\n\\tserverAddr = nil \\n\\t\\tifTrue: [self error: 'Could not find the address for ' , serverName].\\n\\ts := self new.\\n\\tTranscript\\n\\t\\tshow: '---------- Connecting ----------';\\n\\t\\tcr.\\n\\ts connectTo: serverAddr port: 13.\\t\\\"13 is the 'daytime' port number\\\"\\n\\ts waitForConnectionUntil: (self deadlineSecs: 1).\\n\\tTranscript show: 'the time server reports: ' , s getResponseNoLF.\\n\\ts closeAndDestroy.\\n\\tTranscript\\n\\t\\tshow: '---------- Connection Closed ----------';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'rbb 3/1/2005 11:03'!\\ntimeTestUDP\\n\\t\\\"Socket timeTestUDP\\\"\\n\\n\\t| serverName serverAddr s |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tserverName := UIManager default request: 'What is your time server?'\\n\\t\\t\\t\\tinitialAnswer: 'localhost'.\\n\\tserverName isEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[^Transcript\\n\\t\\t\\t\\tshow: 'never mind';\\n\\t\\t\\t\\tcr].\\n\\tserverAddr := NetNameResolver addressForName: serverName timeout: 10.\\n\\tserverAddr = nil \\n\\t\\tifTrue: [self error: 'Could not find the address for ' , serverName].\\n\\ts := self newUDP.\\t\\\"a 'random' port number will be allocated by the system\\\"\\n\\t\\\"Send a packet to the daytime port and it will reply with the current date.\\\"\\n\\tTranscript\\n\\t\\tshow: '---------- Sending datagram from port ' , s port printString \\n\\t\\t\\t\\t\\t, ' ----------';\\n\\t\\tcr.\\n\\ts \\n\\t\\tsendData: '!!'\\n\\t\\ttoHost: serverAddr\\n\\t\\tport: 13.\\t\\\"13 is the daytime service\\\"\\n\\tTranscript show: 'the time server reports: ' , s getResponseNoLF.\\n\\ts closeAndDestroy.\\n\\tTranscript\\n\\t\\tshow: '---------- Socket closed ----------';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'rbb 3/1/2005 11:03'!\\ntimeTestUDP2\\n\\t\\\"Socket timeTestUDP2\\\"\\n\\n\\t| serverName serverAddr s |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tserverName := UIManager default request: 'What is your time server?'\\n\\t\\t\\t\\tinitialAnswer: 'localhost'.\\n\\tserverName isEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[^Transcript\\n\\t\\t\\t\\tshow: 'never mind';\\n\\t\\t\\t\\tcr].\\n\\tserverAddr := NetNameResolver addressForName: serverName timeout: 10.\\n\\tserverAddr = nil \\n\\t\\tifTrue: [self error: 'Could not find the address for ' , serverName].\\n\\ts := self newUDP.\\n\\t\\\"The following associates a port with the UDP socket, but does NOT create a connectable endpoint\\\"\\n\\ts setPort: 54321.\\n\\t\\\"Send a packet to the daytime port and it will reply with the current date.\\\"\\n\\tTranscript\\n\\t\\tshow: '---------- Sending datagram from port ' , s port printString \\n\\t\\t\\t\\t\\t, ' ----------';\\n\\t\\tcr.\\n\\ts \\n\\t\\tsendData: '!!'\\n\\t\\ttoHost: serverAddr\\n\\t\\tport: 13.\\n\\tTranscript show: 'the time server reports: ' , s getResponseNoLF.\\n\\ts closeAndDestroy.\\n\\tTranscript\\n\\t\\tshow: '---------- Socket closed ----------';\\n\\t\\tcr! !\\n\\n!OldSocket class methodsFor: 'examples' stamp: 'rbb 3/1/2005 11:03'!\\ntimeTestUDP3\\n\\t\\\"Socket timeTestUDP3\\\"\\n\\n\\t| serverName serverAddr s |\\n\\tTranscript show: 'initializing network ... '.\\n\\tself initializeNetworkIfFail: [^Transcript show: 'failed'].\\n\\tTranscript\\n\\t\\tshow: 'ok';\\n\\t\\tcr.\\n\\tserverName := UIManager default request: 'What is your time server?'\\n\\t\\t\\t\\tinitialAnswer: 'localhost'.\\n\\tserverName isEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[^Transcript\\n\\t\\t\\t\\tshow: 'never mind';\\n\\t\\t\\t\\tcr].\\n\\tserverAddr := NetNameResolver addressForName: serverName timeout: 10.\\n\\tserverAddr = nil \\n\\t\\tifTrue: [self error: 'Could not find the address for ' , serverName].\\n\\ts := self newUDP.\\n\\t\\\"The following associates a port with the UDP socket, but does NOT create a connectable endpoint\\\"\\n\\ts setPort: self wildcardPort.\\t\\\"explicitly request a default port number\\\"\\n\\t\\\"Send a packet to the daytime port and it will reply with the current date.\\\"\\n\\tTranscript\\n\\t\\tshow: '---------- Sending datagram from port ' , s port printString \\n\\t\\t\\t\\t\\t, ' ----------';\\n\\t\\tcr.\\n\\ts \\n\\t\\tsendData: '!!'\\n\\t\\ttoHost: serverAddr\\n\\t\\tport: 13.\\n\\tTranscript show: 'the time server reports: ' , s getResponseNoLF.\\n\\ts closeAndDestroy.\\n\\tTranscript\\n\\t\\tshow: '---------- Socket closed ----------';\\n\\t\\tcr! !\\n\\n\\n!OldSocket class methodsFor: 'instance creation' stamp: 'ls 9/24/1999 09:45'!\\nacceptFrom: aSocket\\n\\t^[ super new acceptFrom: aSocket ]\\n\\t\\trepeatWithGCIf: [ :sock | sock isValid not ]! !\\n\\n!OldSocket class methodsFor: 'instance creation' stamp: 'ar 4/30/1999 04:15'!\\ncreateIfFail: failBlock\\n\\t\\\"Attempt to create a new socket. If successful, return the new socket. Otherwise, return the result of evaluating the given block. Socket creation can fail if the network isn't available or if there are not sufficient resources available to create another socket.\\\"\\n\\t\\\"Note: The default creates a TCP socket\\\"\\n\\t^self tcpCreateIfFail: failBlock! !\\n\\n!OldSocket class methodsFor: 'instance creation' stamp: 'ar 4/30/1999 04:13'!\\nnew\\n\\t\\\"Return a new, unconnected Socket. Note that since socket creation may fail, it is safer to use the method createIfFail: to handle such failures gracefully; this method is primarily for backward compatibility and may be disallowed in a future release.\\\"\\n\\t\\\"Note: The default creates a TCP socket - this is also backward compatibility.\\\"\\n\\t^self newTCP! !\\n\\n!OldSocket class methodsFor: 'instance creation' stamp: 'ls 9/24/1999 10:19'!\\nnewTCP\\n\\t\\\"Create a socket and initialise it for TCP\\\"\\n\\t^[ super new initialize: TCPSocketType ]\\n\\t\\trepeatWithGCIf: [ :socket | socket isValid not ]! !\\n\\n!OldSocket class methodsFor: 'instance creation' stamp: 'ls 9/24/1999 09:44'!\\nnewUDP\\n\\t\\\"Create a socket and initialise it for UDP\\\"\\n\\t^[ super new initialize: UDPSocketType ]\\n\\t\\trepeatWithGCIf: [ :socket | socket isValid not ]! !\\n\\n!OldSocket class methodsFor: 'instance creation' stamp: 'ar 4/30/1999 04:14'!\\ntcpCreateIfFail: failBlock\\n\\t\\\"Attempt to create a new socket. If successful, return the new socket. Otherwise, return the result of evaluating the given block. Socket creation can fail if the network isn't available or if there are not sufficient resources available to create another socket.\\\"\\n\\n\\t| sock |\\n\\tsock _ super new initialize: TCPSocketType.\\n\\tsock isValid ifFalse: [^ failBlock value].\\n\\t^ sock\\n! !\\n\\n!OldSocket class methodsFor: 'instance creation' stamp: 'ar 4/30/1999 04:14'!\\nudpCreateIfFail: failBlock\\n\\t\\\"Attempt to create a new socket. If successful, return the new socket. Otherwise, return the result of evaluating the given block. Socket creation can fail if the network isn't available or if there are not sufficient resources available to create another socket.\\\"\\n\\n\\t| sock |\\n\\tsock _ super new initialize: UDPSocketType.\\n\\tsock isValid ifFalse: [^ failBlock value].\\n\\t^ sock\\n! !\\n\\n\\n!OldSocket class methodsFor: 'network initialization' stamp: 'nk 2/24/2005 14:38'!\\nensureNetworkConnected\\n\\t\\\"Try to ensure that an intermittent network connection, such as a dialup or ISDN line, is actually connected. This is necessary to make sure a server is visible in order to accept an incoming connection.\\\"\\n\\n\\t\\\"Socket ensureNetworkConnected\\\"\\n\\n\\tself initializeNetwork.\\n\\tUtilities informUser: 'Contacting domain name server...'\\n\\t\\tduring: \\n\\t\\t\\t[NetNameResolver addressForName: 'bogusNameToForceDNSToBeConsulted.org'\\n\\t\\t\\t\\ttimeout: 30]! !\\n\\n!OldSocket class methodsFor: 'network initialization' stamp: 'mir 11/14/2002 19:36'!\\ninitializeNetwork\\n\\t\\\"Initialize the network drivers and the NetNameResolver. Do nothing if the network is already initialized.\\\"\\n\\t\\\"Note: The network must be re-initialized every time Squeak starts up, so applications that persist across snapshots should be prepared to re-initialize the network as needed. Such applications should call 'Socket initializeNetwork' before every network transaction. \\\"\\n\\n\\tNetNameResolver initializeNetwork! !\\n\\n!OldSocket class methodsFor: 'network initialization' stamp: 'mir 11/14/2002 19:36'!\\ninitializeNetworkIfFail: failBlock\\n\\t\\\"Initialize the network drivers. Do nothing if the network is already initialized. Evaluate the given block if network initialization fails, perhaps because this computer isn't currently connected to a network.\\\"\\n\\n\\tNetNameResolver initializeNetwork! !\\n\\n\\n!OldSocket class methodsFor: 'registry' stamp: 'ar 10/7/1998 14:40'!\\nregister: anObject\\n\\tWeakArray isFinalizationSupported ifFalse:[^anObject].\\n\\tself registry add: anObject! !\\n\\n!OldSocket class methodsFor: 'registry' stamp: 'ar 10/7/1998 14:40'!\\nregistry\\n\\tWeakArray isFinalizationSupported ifFalse:[^nil].\\n\\t^Registry isNil\\n\\t\\tifTrue:[Registry := WeakRegistry new]\\n\\t\\tifFalse:[Registry].! !\\n\\n!OldSocket class methodsFor: 'registry' stamp: 'ar 12/12/2001 19:12'!\\nregistryThreshold\\n\\t\\\"Return the registry threshold above which socket creation may fail due to too many already open sockets. If the threshold is reached, a full GC will be issued if the creation of a socket fails.\\\"\\n\\t^RegistryThreshold! !\\n\\n!OldSocket class methodsFor: 'registry' stamp: 'ar 12/12/2001 19:12'!\\nregistryThreshold: aNumber\\n\\t\\\"Return the registry threshold above which socket creation may fail due to too many already open sockets. If the threshold is reached, a full GC will be issued if the creation of a socket fails.\\\"\\n\\tRegistryThreshold _ aNumber! !\\n\\n!OldSocket class methodsFor: 'registry' stamp: 'ar 10/7/1998 15:22'!\\nunregister: anObject\\n\\tWeakArray isFinalizationSupported ifFalse:[^anObject].\\n\\tself registry remove: anObject ifAbsent:[]! !\\n\\n\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'tk 4/9/98 15:54'!\\ndeadServer\\n\\n\\t^ DeadServer! !\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'tk 4/9/98 15:56'!\\ndeadServer: aStringOrNil\\n\\t\\\"Keep the machine name of the most recently encoutered non-responding machine. Next time the user can move it to the last in a list of servers to try.\\\"\\n\\n\\tDeadServer _ aStringOrNil! !\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'jm 9/15/97 06:56'!\\ndeadlineSecs: secs\\n\\t\\\"Return a deadline time the given number of seconds from now.\\\"\\n\\n\\t^ Time millisecondClockValue + (secs * 1000)\\n! !\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'jm 1/14/1999 12:13'!\\nnameForWellKnownTCPPort: portNum\\n\\t\\\"Answer the name for the given well-known TCP port number. Answer a string containing the port number if it isn't well-known.\\\"\\n\\n\\t| portList entry |\\n\\tportList _ #(\\n\\t\\t(7 'echo') (9 'discard') (13 'time') (19 'characterGenerator')\\n\\t\\t(21 'ftp') (23 'telnet') (25 'smtp')\\n\\t\\t(80 'http') (110 'pop3') (119 'nntp')).\\n\\tentry _ portList detect: [:pair | pair first = portNum] ifNone: [^ 'port-', portNum printString].\\n\\t^ entry last\\n! !\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'nk 2/24/2005 14:38'!\\nping: hostName \\n\\t\\\"Ping the given host. Useful for checking network connectivity. The host must be running a TCP echo server.\\\"\\n\\n\\t\\\"Socket ping: 'squeak.cs.uiuc.edu'\\\"\\n\\n\\t| tcpPort sock serverAddr startTime echoTime |\\n\\ttcpPort := 7.\\t\\\"7 = echo port, 13 = time port, 19 = character generator port\\\"\\n\\tself initializeNetwork.\\n\\tserverAddr := NetNameResolver addressForName: hostName timeout: 10.\\n\\tserverAddr = nil \\n\\t\\tifTrue: [^self inform: 'Could not find an address for ' , hostName].\\n\\tsock := self new.\\n\\tsock connectTo: serverAddr port: tcpPort.\\n\\t\\n\\t[sock waitForConnectionUntil: (self deadlineSecs: 10).\\n\\tsock isConnected] \\n\\t\\t\\twhileFalse: \\n\\t\\t\\t\\t[(self confirm: 'Continue to wait for connection to ' , hostName , '?') \\n\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t[sock destroy.\\n\\t\\t\\t\\t\\t\\t^self]].\\n\\tsock sendData: 'echo!!'.\\n\\tstartTime := Time millisecondClockValue.\\n\\t\\n\\t[sock waitForDataUntil: (self deadlineSecs: 15).\\n\\tsock dataAvailable] \\n\\t\\t\\twhileFalse: \\n\\t\\t\\t\\t[(self confirm: 'Packet sent but no echo yet; keep waiting?') \\n\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t[sock destroy.\\n\\t\\t\\t\\t\\t\\t^self]].\\n\\techoTime := Time millisecondClockValue - startTime.\\n\\tsock destroy.\\n\\tself inform: hostName , ' responded in ' , echoTime printString \\n\\t\\t\\t\\t, ' milliseconds'! !\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'nk 2/24/2005 14:38'!\\npingPorts: portList on: hostName timeOutSecs: timeOutSecs \\n\\t\\\"Attempt to connect to each of the given sockets on the given host. Wait at most timeOutSecs for the connections to be established. Answer an array of strings indicating the available ports.\\\"\\n\\n\\t\\\"Socket pingPorts: #(7 13 19 21 23 25 80 110 119) on: 'squeak.cs.uiuc.edu' timeOutSecs: 15\\\"\\n\\n\\t| serverAddr sockets sock deadline done unconnectedCount connectedCount waitingCount result |\\n\\tself initializeNetwork.\\n\\tserverAddr := NetNameResolver addressForName: hostName timeout: 10.\\n\\tserverAddr = nil \\n\\t\\tifTrue: \\n\\t\\t\\t[self inform: 'Could not find an address for ' , hostName.\\n\\t\\t\\t^#()].\\n\\tsockets := portList collect: \\n\\t\\t\\t\\t\\t[:portNum | \\n\\t\\t\\t\\t\\tsock := self new.\\n\\t\\t\\t\\t\\tsock connectTo: serverAddr port: portNum].\\n\\tdeadline := self deadlineSecs: timeOutSecs.\\n\\tdone := false.\\n\\t[done] whileFalse: \\n\\t\\t\\t[unconnectedCount := 0.\\n\\t\\t\\tconnectedCount := 0.\\n\\t\\t\\twaitingCount := 0.\\n\\t\\t\\tsockets do: \\n\\t\\t\\t\\t\\t[:s | \\n\\t\\t\\t\\t\\ts isUnconnectedOrInvalid \\n\\t\\t\\t\\t\\t\\tifTrue: [unconnectedCount := unconnectedCount + 1]\\n\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t[s isConnected ifTrue: [connectedCount := connectedCount + 1].\\n\\t\\t\\t\\t\\t\\t\\ts isWaitingForConnection ifTrue: [waitingCount := waitingCount + 1]]].\\n\\t\\t\\twaitingCount = 0 ifTrue: [done := true].\\n\\t\\t\\tconnectedCount = sockets size ifTrue: [done := true].\\n\\t\\t\\tTime millisecondClockValue > deadline ifTrue: [done := true]].\\n\\tresult := (sockets select: [:s | s isConnected]) \\n\\t\\t\\t\\tcollect: [:s | self nameForWellKnownTCPPort: s remotePort].\\n\\tsockets do: [:s | s destroy].\\n\\t^result! !\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'nk 2/24/2005 14:38'!\\npingPortsOn: hostName \\n\\t\\\"Attempt to connect to a set of well-known sockets on the given host, and answer the names of the available ports.\\\"\\n\\n\\t\\\"Socket pingPortsOn: 'www.disney.com'\\\"\\n\\n\\t^self \\n\\t\\tpingPorts: #(7 13 19 21 23 25 80 110 119)\\n\\t\\ton: hostName\\n\\t\\ttimeOutSecs: 20! !\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'jm 9/15/97 06:56'!\\nstandardDeadline\\n\\t\\\"Return a default deadline time some seconds into the future.\\\"\\n\\n\\t^ self deadlineSecs: 45\\n! !\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'ar 4/30/1999 04:21'!\\nwildcardAddress\\n\\t\\\"Answer a don't-care address for use with UDP sockets.\\\"\\n\\n\\t^ByteArray new: 4\\t\\t\\\"0.0.0.0\\\"! !\\n\\n!OldSocket class methodsFor: 'utilities' stamp: 'ar 4/30/1999 04:21'!\\nwildcardPort\\n\\t\\\"Answer a don't-care port for use with UDP sockets. (The system will allocate an\\n\\tunused port number to the socket.)\\\"\\n\\n\\t^0! !\\nSwitch subclass: #OneOnSwitch\\n\\tinstanceVariableNames: 'connection'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Menus'!\\n!OneOnSwitch commentStamp: '<historical>' prior: 0!\\nI am a kind of Switch that can be connected to some related object, typically to a collection of my instances. When my instance is created, its connection is set to a particular object. When the object changes because an Switch it refers to is turned on, an update message is broadcasted. All the connected OneOnSwitches, except the changed one, turn off. This allows OneOnSwitches to maintain the constraint that at most one of them will be on at any time. OneOnSwitches can thus be made to act like \\\"car radio\\\" switches.!\\n\\n\\n!OneOnSwitch methodsFor: 'connection'!\\nconnection\\n\\t\\\"Answer the object that connects the receiver to other Switches.\\\"\\n\\n\\t^connection! !\\n\\n!OneOnSwitch methodsFor: 'connection'!\\nconnection: anObject \\n\\t\\\"Set anObject to be the connection among two or more Switches. Make the \\n\\treceiver a dependent of the argument, anObject.\\\"\\n\\n\\tconnection _ anObject.\\n\\tconnection addDependent: self! !\\n\\n!OneOnSwitch methodsFor: 'connection'!\\nisConnectionSet\\n\\t\\\"Answer whether the receiver is connected to an object that coordinates \\n\\tupdates among switches.\\\"\\n\\n\\tconnection == nil\\n\\t\\tifTrue: [^false]\\n\\t\\tifFalse: [^true]! !\\n\\n!OneOnSwitch methodsFor: 'connection'!\\nnotifyConnection\\n\\t\\\"Send the receiver's connection (if it exists) the message 'changed: self' in \\n\\torder for the connection to broadcast the change to other objects \\n\\tconnected by the connection.\\\"\\n\\t\\n\\tself isConnectionSet ifTrue: [self connection changed: self]! !\\n\\n\\n!OneOnSwitch methodsFor: 'initialize-release'!\\nrelease\\n\\n\\tsuper release.\\n\\tself isConnectionSet ifTrue: [connection removeDependent: self]! !\\n\\n\\n!OneOnSwitch methodsFor: 'state'!\\nturnOn\\n\\t\\\"Does nothing if it is already on. If it is not, it is set to 'on', its\\n\\tdependents are \\tnotified of the change, its connection is notified, and\\n\\tits action is executed.\\\"\\n\\n\\tself isOff\\n\\t\\tifTrue: \\n\\t\\t\\t[on _ true.\\n\\t\\t\\tself changed.\\n\\t\\t\\tself notifyConnection.\\n\\t\\t\\tself doAction: onAction]! !\\n\\n\\n!OneOnSwitch methodsFor: 'updating'!\\nupdate: aOneOnSwitch \\n\\t\\\"Does nothing if aOneOnSwitch is identical to this object. If it is not, this \\n\\tobject is turned off. This message is sent by the connection (an Object)\\n\\twhen some related OneOnSwitch (possibly this one) has changed. This\\n\\tallows a group of related OneOnSwitches to maintain the constraint that\\n\\tat most one will be on at any time.\\\"\\n\\n\\tself ~~ aOneOnSwitch ifTrue: [self turnOff]! !\\nURI subclass: #OpaqueURI\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-URI'!\\n\\n!OpaqueURI methodsFor: 'testing' stamp: 'mir 2/20/2002 16:55'!\\nisOpaque\\n\\t^true! !\\nSmallLandColorTheme subclass: #OrangeSmallLandColorTheme\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Support'!\\n\\n!OrangeSmallLandColorTheme methodsFor: 'initialization' stamp: 'dgd 3/12/2006 13:25'!\\nbaseColors\\n\\\"\\nOrangeSmallLandColorTheme apply.\\n\\\"\\n\\t^ Array\\n\\t\\twith: (Color fromArray: #(0.8 0.4 0.0 ))\\n\\t\\twith: (Color fromArray: #(1.0 0.8 0.0 ))\\n\\t\\twith: (Color fromArray: #(1.0 1.0 0.8 ))! !\\nSequenceableCollection subclass: #OrderedCollection\\n\\tinstanceVariableNames: 'array firstIndex lastIndex'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Collections-Sequenceable'!\\n!OrderedCollection commentStamp: '<historical>' prior: 0!\\nI represent a collection of objects ordered by the collector.!\\n\\n\\n!OrderedCollection methodsFor: 'accessing'!\\nat: anInteger \\n\\t\\\"Answer my element at index anInteger. at: is used by a knowledgeable\\n\\tclient to access an existing element\\\"\\n\\n\\t(anInteger < 1 or: [anInteger + firstIndex - 1 > lastIndex])\\n\\t\\tifTrue: [self errorNoSuchElement]\\n\\t\\tifFalse: [^ array at: anInteger + firstIndex - 1]! !\\n\\n!OrderedCollection methodsFor: 'accessing'!\\nat: anInteger put: anObject \\n\\t\\\"Put anObject at element index anInteger. at:put: cannot be used to\\n\\tappend, front or back, to an ordered collection; it is used by a\\n\\tknowledgeable client to replace an element.\\\"\\n\\n\\t| index |\\n\\tindex _ anInteger asInteger.\\n\\t(index < 1 or: [index + firstIndex - 1 > lastIndex])\\n\\t\\tifTrue: [self errorNoSuchElement]\\n\\t\\tifFalse: [^array at: index + firstIndex - 1 put: anObject]! !\\n\\n!OrderedCollection methodsFor: 'accessing' stamp: 'sma 5/12/2000 11:42'!\\ncapacity\\n\\t\\\"Answer the current capacity of the receiver.\\\"\\n\\n\\t^ array size! !\\n\\n!OrderedCollection methodsFor: 'accessing' stamp: 'sma 5/12/2000 11:39'!\\nsize\\n\\t\\\"Answer how many elements the receiver contains.\\\"\\n\\n\\t^ lastIndex - firstIndex + 1! !\\n\\n\\n!OrderedCollection methodsFor: 'adding'!\\nadd: newObject\\n\\n\\t^self addLast: newObject! !\\n\\n!OrderedCollection methodsFor: 'adding'!\\nadd: newObject after: oldObject \\n\\t\\\"Add the argument, newObject, as an element of the receiver. Put it in \\n\\tthe sequence just succeeding oldObject. Answer newObject.\\\"\\n\\t\\n\\t| index |\\n\\tindex _ self find: oldObject.\\n\\tself insert: newObject before: index + 1.\\n\\t^newObject! !\\n\\n!OrderedCollection methodsFor: 'adding' stamp: 'di 3/15/1999 14:01'!\\nadd: newObject afterIndex: index \\n\\t\\\"Add the argument, newObject, as an element of the receiver. Put it in \\n\\tthe sequence just after index. Answer newObject.\\\"\\n\\n\\tself insert: newObject before: firstIndex + index.\\n\\t^ newObject! !\\n\\n!OrderedCollection methodsFor: 'adding'!\\nadd: newObject before: oldObject \\n\\t\\\"Add the argument, newObject, as an element of the receiver. Put it in \\n\\tthe sequence just preceding oldObject. Answer newObject.\\\"\\n\\t\\n\\t| index |\\n\\tindex _ self find: oldObject.\\n\\tself insert: newObject before: index.\\n\\t^newObject! !\\n\\n!OrderedCollection methodsFor: 'adding' stamp: 'BG 1/9/2004 12:30'!\\nadd: newObject beforeIndex: index \\n \\\"Add the argument, newObject, as an element of the receiver. Put it in \\n the sequence just before index. Answer newObject.\\\"\\n\\n self add: newObject afterIndex: index - 1.\\n ^ newObject! !\\n\\n!OrderedCollection methodsFor: 'adding' stamp: 'sma 5/12/2000 11:26'!\\naddAll: aCollection \\n\\t\\\"Add each element of aCollection at my end. Answer\\taCollection.\\\"\\n\\n\\t^ self addAllLast: aCollection! !\\n\\n!OrderedCollection methodsFor: 'adding'!\\naddAllFirst: anOrderedCollection \\n\\t\\\"Add each element of anOrderedCollection at the beginning of the \\n\\treceiver. Answer anOrderedCollection.\\\"\\n\\n\\tanOrderedCollection reverseDo: [:each | self addFirst: each].\\n\\t^anOrderedCollection! !\\n\\n!OrderedCollection methodsFor: 'adding' stamp: 'sw 3/1/2001 11:03'!\\naddAllFirstUnlessAlreadyPresent: anOrderedCollection \\n\\t\\\"Add each element of anOrderedCollection at the beginning of the receiver, preserving the order, but do not add any items that are already in the receiver. Answer anOrderedCollection.\\\"\\n\\n\\tanOrderedCollection reverseDo:\\n\\t\\t[:each | (self includes: each) ifFalse: [self addFirst: each]].\\n\\t^ anOrderedCollection! !\\n\\n!OrderedCollection methodsFor: 'adding'!\\naddAllLast: anOrderedCollection \\n\\t\\\"Add each element of anOrderedCollection at the end of the receiver. \\n\\tAnswer anOrderedCollection.\\\"\\n\\n\\tanOrderedCollection do: [:each | self addLast: each].\\n\\t^anOrderedCollection! !\\n\\n!OrderedCollection methodsFor: 'adding'!\\naddFirst: newObject \\n\\t\\\"Add newObject to the beginning of the receiver. Answer newObject.\\\"\\n\\n\\tfirstIndex = 1 ifTrue: [self makeRoomAtFirst].\\n\\tfirstIndex _ firstIndex - 1.\\n\\tarray at: firstIndex put: newObject.\\n\\t^ newObject! !\\n\\n!OrderedCollection methodsFor: 'adding'!\\naddLast: newObject \\n\\t\\\"Add newObject to the end of the receiver. Answer newObject.\\\"\\n\\n\\tlastIndex = array size ifTrue: [self makeRoomAtLast].\\n\\tlastIndex _ lastIndex + 1.\\n\\tarray at: lastIndex put: newObject.\\n\\t^ newObject! !\\n\\n!OrderedCollection methodsFor: 'adding' stamp: 'ajh 5/22/2003 12:03'!\\nat: index ifAbsentPut: block\\n\\t\\\"Return value at index, however, if value does not exist (nil or out of bounds) then add block's value at index (growing self if necessary)\\\"\\n\\n\\t| v |\\n\\tindex <= self size ifTrue: [\\n\\t\\t^ (v _ self at: index)\\n\\t\\t\\tifNotNil: [v]\\n\\t\\t\\tifNil: [self at: index put: block value]\\n\\t].\\n\\t[self size < index] whileTrue: [self add: nil].\\n\\t^ self at: index put: block value! !\\n\\n!OrderedCollection methodsFor: 'adding'!\\ngrow\\n\\t\\\"Become larger. Typically, a subclass has to override this if the subclass\\n\\tadds instance variables.\\\"\\n\\t| newArray |\\n\\tnewArray _ Array new: self size + self growSize.\\n\\tnewArray replaceFrom: 1 to: array size with: array startingAt: 1.\\n\\tarray _ newArray! !\\n\\n!OrderedCollection methodsFor: 'adding'!\\ngrowSize\\n\\t^ array size max: 2! !\\n\\n\\n!OrderedCollection methodsFor: 'copying'!\\ncopyEmpty\\n\\t\\\"Answer a copy of the receiver that contains no elements.\\\"\\n\\n\\t^self species new! !\\n\\n!OrderedCollection methodsFor: 'copying' stamp: 'di 12/12/2000 10:15'!\\ncopyFrom: startIndex to: endIndex \\n\\t\\\"Answer a copy of the receiver that contains elements from position\\n\\tstartIndex to endIndex.\\\"\\n\\n\\t| targetCollection |\\n\\tendIndex < startIndex ifTrue: [^self species new: 0].\\n\\ttargetCollection _ self species new: endIndex + 1 - startIndex.\\n\\tstartIndex to: endIndex do: [:index | targetCollection addLast: (self at: index)].\\n\\t^ targetCollection! !\\n\\n!OrderedCollection methodsFor: 'copying'!\\ncopyReplaceFrom: start to: stop with: replacementCollection \\n\\t\\\"Answer a copy of the receiver with replacementCollection's elements in\\n\\tplace of the receiver's start'th to stop'th elements. This does not expect\\n\\ta 1-1 map from replacementCollection to the start to stop elements, so it\\n\\twill do an insert or append.\\\"\\n\\n\\t| newOrderedCollection delta startIndex stopIndex |\\n\\t\\\"if start is less than 1, ignore stop and assume this is inserting at the front. \\n\\tif start greater than self size, ignore stop and assume this is appending. \\n\\totherwise, it is replacing part of me and start and stop have to be within my \\n\\tbounds. \\\"\\n\\tdelta _ 0.\\n\\tstartIndex _ start.\\n\\tstopIndex _ stop.\\n\\tstart < 1\\n\\t\\tifTrue: [startIndex _ stopIndex _ 0]\\n\\t\\tifFalse: [startIndex > self size\\n\\t\\t\\t\\tifTrue: [startIndex _ stopIndex _ self size + 1]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[(stopIndex < (startIndex - 1) or: [stopIndex > self size])\\n\\t\\t\\t\\t\\t\\tifTrue: [self errorOutOfBounds].\\n\\t\\t\\t\\t\\tdelta _ stopIndex - startIndex + 1]].\\n\\tnewOrderedCollection _ \\n\\t\\tself species new: self size + replacementCollection size - delta.\\n\\t1 to: startIndex - 1 do: [:index | newOrderedCollection add: (self at: index)].\\n\\t1 to: replacementCollection size do: \\n\\t\\t[:index | newOrderedCollection add: (replacementCollection at: index)].\\n\\tstopIndex + 1 to: self size do: [:index | newOrderedCollection add: (self at: index)].\\n\\t^newOrderedCollection! !\\n\\n!OrderedCollection methodsFor: 'copying'!\\ncopyWith: newElement \\n\\t\\\"Answer a copy of the receiver that is 1 bigger than the receiver and \\n\\tincludes the argument, newElement, at the end.\\\"\\n\\n\\t| newCollection |\\n\\tnewCollection _ self copy.\\n\\tnewCollection add: newElement.\\n\\t^newCollection! !\\n\\n!OrderedCollection methodsFor: 'copying' stamp: 'sw 1/26/96'!\\nreversed\\n\\t\\\"Answer a copy of the receiver with element order reversed. \\\"\\n\\t| newCol |\\n\\tnewCol _ self species new.\\n\\tself reverseDo:\\n\\t\\t[:elem | newCol addLast: elem].\\n\\t^ newCol\\n\\n\\\"#(2 3 4 'fred') reversed\\\"! !\\n\\n\\n!OrderedCollection methodsFor: 'enumerating' stamp: 'sma 2/5/2000 15:22'!\\ncollect: aBlock \\n\\t\\\"Evaluate aBlock with each of my elements as the argument. Collect the \\n\\tresulting values into a collection that is like me. Answer the new \\n\\tcollection. Override superclass in order to use addLast:, not at:put:.\\\"\\n\\n\\t| newCollection |\\n\\tnewCollection _ self species new: self size.\\n\\tfirstIndex to: lastIndex do:\\n\\t\\t[:index |\\n\\t\\tnewCollection addLast: (aBlock value: (array at: index))].\\n\\t^ newCollection! !\\n\\n!OrderedCollection methodsFor: 'enumerating' stamp: 'bf 5/18/2000 17:34'!\\ncollect: aBlock from: fromIndex to: toIndex\\n\\t\\\"Override superclass in order to use addLast:, not at:put:.\\\"\\n\\t| result |\\n\\t(fromIndex < 1 or:[toIndex + firstIndex - 1 > lastIndex])\\n\\t\\tifTrue: [^self errorNoSuchElement].\\n\\tresult _ self species new: toIndex - fromIndex + 1.\\n\\tfirstIndex + fromIndex - 1 to: firstIndex + toIndex - 1 do:\\n\\t\\t[:index | result addLast: (aBlock value: (array at: index))].\\n\\t^ result\\n! !\\n\\n!OrderedCollection methodsFor: 'enumerating'!\\ndo: aBlock \\n\\t\\\"Override the superclass for performance reasons.\\\"\\n\\t| index |\\n\\tindex _ firstIndex.\\n\\t[index <= lastIndex]\\n\\t\\twhileTrue: \\n\\t\\t\\t[aBlock value: (array at: index).\\n\\t\\t\\tindex _ index + 1]! !\\n\\n!OrderedCollection methodsFor: 'enumerating'!\\nreverseDo: aBlock \\n\\t\\\"Override the superclass for performance reasons.\\\"\\n\\t| index |\\n\\tindex _ lastIndex.\\n\\t[index >= firstIndex]\\n\\t\\twhileTrue: \\n\\t\\t\\t[aBlock value: (array at: index).\\n\\t\\t\\tindex _ index - 1]! !\\n\\n!OrderedCollection methodsFor: 'enumerating' stamp: 'sma 2/5/2000 15:13'!\\nselect: aBlock \\n\\t\\\"Evaluate aBlock with each of my elements as the argument. Collect into\\n\\ta new collection like the receiver, only those elements for which aBlock\\n\\tevaluates to true.\\\"\\n\\n\\t| newCollection element |\\n\\tnewCollection _ self copyEmpty.\\n\\tfirstIndex to: lastIndex do:\\n\\t\\t[:index |\\n\\t\\t(aBlock value: (element _ array at: index))\\n\\t\\t\\tifTrue: [newCollection addLast: element]].\\n\\t^ newCollection! !\\n\\n!OrderedCollection methodsFor: 'enumerating' stamp: 'di 8/31/1999 13:13'!\\nwith: otherCollection collect: twoArgBlock \\n\\t\\\"Collect and return the result of evaluating twoArgBlock with \\n\\tcorresponding elements from this collection and otherCollection.\\\"\\n\\t| result |\\n\\totherCollection size = self size ifFalse: [self error: 'otherCollection must be the same size'].\\n\\tresult _ self species new: self size.\\n\\t1 to: self size do:\\n\\t\\t[:index | result addLast: (twoArgBlock value: (self at: index)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tvalue: (otherCollection at: index))].\\n\\t^ result! !\\n\\n!OrderedCollection methodsFor: 'enumerating' stamp: 'bf 5/16/2000 16:30'!\\nwithIndexCollect: elementAndIndexBlock \\n\\t\\\"Just like with:collect: except that the iteration index supplies the second argument to the block. Override superclass in order to use addLast:, not at:put:.\\\"\\n\\n\\t| newCollection |\\n\\tnewCollection _ self species new: self size.\\n\\tfirstIndex to: lastIndex do:\\n\\t\\t[:index |\\n\\t\\tnewCollection addLast: (elementAndIndexBlock\\n\\t\\t\\tvalue: (array at: index)\\n\\t\\t\\tvalue: index - firstIndex + 1)].\\n\\t^ newCollection! !\\n\\n\\n!OrderedCollection methodsFor: 'removing'!\\nremove: oldObject ifAbsent: absentBlock\\n\\n\\t| index |\\n\\tindex _ firstIndex.\\n\\t[index <= lastIndex]\\n\\t\\twhileTrue: \\n\\t\\t\\t[oldObject = (array at: index)\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[self removeIndex: index.\\n\\t\\t\\t\\t\\t^ oldObject]\\n\\t\\t\\t\\tifFalse: [index _ index + 1]].\\n\\t^ absentBlock value! !\\n\\n!OrderedCollection methodsFor: 'removing' stamp: 'raok 4/27/2001 15:35'!\\nremoveAllSuchThat: aBlock \\n\\t\\\"Remove each element of the receiver for which aBlock evaluates to true.\\n\\tThe method in Collection is O(N^2), this is O(N).\\\"\\n\\n\\t| n |\\n\\tn _ firstIndex.\\n\\tfirstIndex to: lastIndex do: [:index |\\n\\t (aBlock value: (array at: index)) ifFalse: [\\n\\t\\t\\tarray at: n put: (array at: index).\\n\\t\\t\\tn _ n + 1]].\\n\\tn to: lastIndex do: [:index | array at: index put: nil].\\n\\tlastIndex _ n - 1! !\\n\\n!OrderedCollection methodsFor: 'removing' stamp: 'ar 5/22/2000 12:19'!\\nremoveAt: index\\n\\t| removed |\\n\\tremoved _ self at: index.\\n\\tself removeIndex: index + firstIndex - 1.\\n\\t^removed! !\\n\\n!OrderedCollection methodsFor: 'removing'!\\nremoveFirst\\n\\t\\\"Remove the first element of the receiver and answer it. If the receiver is \\n\\tempty, create an error notification.\\\"\\n\\t| firstObject |\\n\\tself emptyCheck.\\n\\tfirstObject _ array at: firstIndex.\\n\\tarray at: firstIndex put: nil.\\n\\tfirstIndex _ firstIndex + 1.\\n\\t^ firstObject! !\\n\\n!OrderedCollection methodsFor: 'removing' stamp: 'ajh 6/22/2003 14:37'!\\nremoveFirst: n\\n\\t\\\"Remove first n object into an array\\\"\\n\\n\\t| list |\\n\\tlist _ Array new: n.\\n\\t1 to: n do: [:i |\\n\\t\\tlist at: i put: self removeFirst].\\n\\t^ list! !\\n\\n!OrderedCollection methodsFor: 'removing'!\\nremoveLast\\n\\t\\\"Remove the last element of the receiver and answer it. If the receiver is \\n\\tempty, create an error notification.\\\"\\n\\t| lastObject |\\n\\tself emptyCheck.\\n\\tlastObject _ array at: lastIndex.\\n\\tarray at: lastIndex put: nil.\\n\\tlastIndex _ lastIndex - 1.\\n\\t^ lastObject! !\\n\\n!OrderedCollection methodsFor: 'removing' stamp: 'ajh 6/22/2003 14:36'!\\nremoveLast: n\\n\\t\\\"Remove last n object into an array with last in last position\\\"\\n\\n\\t| list |\\n\\tlist _ Array new: n.\\n\\tn to: 1 by: -1 do: [:i |\\n\\t\\tlist at: i put: self removeLast].\\n\\t^ list! !\\n\\n\\n!OrderedCollection methodsFor: 'testing' stamp: 'bf 8/20/1999 15:08'!\\nhasContentsInExplorer\\n\\n\\t^self isEmpty not! !\\n\\n\\n!OrderedCollection methodsFor: '*Tools-Inspector' stamp: 'ar 9/27/2005 18:33'!\\ninspectorClass \\n\\t\\\"Answer the class of the inspector to be used on the receiver. Called by inspect; \\n\\tuse basicInspect to get a normal (less useful) type of inspector.\\\"\\n\\n\\t^OrderedCollectionInspector! !\\n\\n\\n!OrderedCollection methodsFor: 'private'!\\ncollector \\\"Private\\\"\\n\\t^ array! !\\n\\n!OrderedCollection methodsFor: 'private'!\\nerrorConditionNotSatisfied\\n\\n\\tself error: 'no element satisfies condition'! !\\n\\n!OrderedCollection methodsFor: 'private'!\\nerrorNoSuchElement\\n\\n\\tself error: 'attempt to index non-existent element in an ordered collection'! !\\n\\n!OrderedCollection methodsFor: 'private' stamp: 'BG 1/9/2004 12:26'!\\nfind: oldObject\\n \\\" This method answers an index in the range firstIndex .. lastIndex, which is meant for internal use only.\\n Never use this method in your code, the methods for public use are:\\n #indexOf:\\n #indexOf:ifAbsent: \\\"\\n\\n\\t| index |\\n\\tindex _ firstIndex.\\n\\t[index <= lastIndex]\\n\\t\\twhileTrue:\\n\\t\\t\\t[(array at: index) = oldObject ifTrue: [^ index].\\n\\t\\t\\tindex _ index + 1].\\n\\tself errorNotFound: oldObject! !\\n\\n!OrderedCollection methodsFor: 'private' stamp: 'BG 1/9/2004 12:29'!\\ninsert: anObject before: spot\\n\\n \\\" spot is an index in the range firstIndex .. lastIndex, such an index is not known from outside the collection. \\n Never use this method in your code, it is meant for private use by OrderedCollection only.\\n The methods for use are:\\n #add:before: to insert an object before another object\\n #add:beforeIndex: to insert an object before a given position. \\\"\\n\\t| \\\"index\\\" delta spotIndex|\\n\\tspotIndex _ spot.\\n\\tdelta _ spotIndex - firstIndex.\\n\\tfirstIndex = 1\\n\\t\\tifTrue: \\n\\t\\t\\t[self makeRoomAtFirst.\\n\\t\\t\\tspotIndex _ firstIndex + delta].\\n\\tfirstIndex _ firstIndex - 1.\\n\\tarray\\n\\t\\treplaceFrom: firstIndex\\n\\t\\tto: spotIndex - 2\\n\\t\\twith: array\\n\\t\\tstartingAt: firstIndex + 1.\\n\\tarray at: spotIndex - 1 put: anObject.\\n\\\"\\tindex _ firstIndex _ firstIndex - 1.\\n\\t[index < (spotIndex - 1)]\\n\\t\\twhileTrue: \\n\\t\\t\\t[array at: index put: (array at: index + 1).\\n\\t\\t\\tindex _ index + 1].\\n\\tarray at: index put: anObject.\\\"\\n\\t^ anObject! !\\n\\n!OrderedCollection methodsFor: 'private'!\\nmakeRoomAtFirst\\n\\t| delta index |\\n\\tdelta _ array size - self size.\\n\\tdelta = 0 ifTrue: \\n\\t\\t\\t[self grow.\\n\\t\\t\\tdelta _ array size - self size].\\n\\tlastIndex = array size ifTrue: [^ self]. \\\"just in case we got lucky\\\"\\n\\tindex _ array size.\\n\\t[index > delta]\\n\\t\\twhileTrue: \\n\\t\\t\\t[array at: index put: (array at: index - delta + firstIndex - 1).\\n\\t\\t\\tarray at: index - delta + firstIndex - 1 put: nil.\\n\\t\\t\\tindex _ index - 1].\\n\\tfirstIndex _ delta + 1.\\n\\tlastIndex _ array size! !\\n\\n!OrderedCollection methodsFor: 'private'!\\nmakeRoomAtLast\\n\\t| newLast delta |\\n\\tnewLast _ self size.\\n\\tarray size - self size = 0 ifTrue: [self grow].\\n\\t(delta _ firstIndex - 1) = 0 ifTrue: [^ self].\\n\\t\\\"we might be here under false premises or grow did the job for us\\\"\\n\\t1 to: newLast do:\\n\\t\\t[:index |\\n\\t\\tarray at: index put: (array at: index + delta).\\n\\t\\tarray at: index + delta put: nil].\\n\\tfirstIndex _ 1.\\n\\tlastIndex _ newLast! !\\n\\n!OrderedCollection methodsFor: 'private' stamp: 'BG 1/9/2004 12:28'!\\nremoveIndex: removedIndex\\n \\\" removedIndex is an index in the range firstIndex .. lastIndex, such an index is not known from outside the collection.\\n Never use this method in your code, it is meant for private use by OrderedCollection only.\\n The method for public use is:\\n #removeAt: \\\"\\n\\n\\tarray \\n\\t\\treplaceFrom: removedIndex \\n\\t\\tto: lastIndex - 1 \\n\\t\\twith: array \\n\\t\\tstartingAt: removedIndex+1.\\n\\tarray at: lastIndex put: nil.\\n\\tlastIndex _ lastIndex - 1.! !\\n\\n!OrderedCollection methodsFor: 'private' stamp: 'di 11/14/97 12:54'!\\nreset\\n\\tfirstIndex _ array size // 3 max: 1.\\n\\tlastIndex _ firstIndex - 1! !\\n\\n!OrderedCollection methodsFor: 'private' stamp: 'ar 4/16/1999 07:59'!\\nresetTo: index\\n\\tfirstIndex _ index.\\n\\tlastIndex _ firstIndex - 1! !\\n\\n!OrderedCollection methodsFor: 'private' stamp: 'di 11/14/97 12:54'!\\nsetCollection: anArray\\n\\tarray _ anArray.\\n\\tself reset! !\\n\\n!OrderedCollection methodsFor: 'private' stamp: 'apb 10/15/2000 18:10'!\\nsetContents: anArray\\n\\tarray _ anArray.\\n\\tfirstIndex _ 1.\\n\\tlastIndex _ array size.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nOrderedCollection class\\n\\tinstanceVariableNames: ''!\\n\\n!OrderedCollection class methodsFor: 'instance creation' stamp: 'sma 5/12/2000 17:41'!\\nnew\\n\\t^ self new: 10! !\\n\\n!OrderedCollection class methodsFor: 'instance creation' stamp: 'md 7/5/2005 15:16'!\\nnew: anInteger \\n\\t^ super basicNew setCollection: (Array new: anInteger)! !\\n\\n!OrderedCollection class methodsFor: 'instance creation'!\\nnewFrom: aCollection \\n\\t\\\"Answer an instance of me containing the same elements as aCollection.\\\"\\n\\n\\t| newCollection |\\n\\tnewCollection _ self new: aCollection size.\\n\\tnewCollection addAll: aCollection.\\n\\t^newCollection\\n\\n\\\"\\tOrderedCollection newFrom: {1. 2. 3}\\n\\t{1. 2. 3} as: OrderedCollection\\n\\t{4. 2. 7} as: SortedCollection\\n\\\"! !\\n\\n!OrderedCollection class methodsFor: 'instance creation' stamp: 'apb 10/15/2000 22:02'!\\nofSize: n\\n\\t\\\"Create a new collection of size n with nil as its elements.\\n\\tThis method exists because OrderedCollection new: n creates an\\n\\tempty collection, not one of size n.\\\"\\n\\t| collection |\\n\\tcollection _ self new: n.\\n\\tcollection setContents: (collection collector).\\n\\t^ collection\\n! !\\nInspector subclass: #OrderedCollectionInspector\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tools-Inspector'!\\n\\n!OrderedCollectionInspector methodsFor: 'as yet unclassified' stamp: 'dew 9/19/2001 03:27'!\\nfieldList\\n\\tobject ifNil: [ ^ OrderedCollection new].\\n\\t^ self baseFieldList ,\\n\\t\\t(object size <= (self i1 + self i2)\\n\\t\\t\\tifTrue: [(1 to: object size)\\n\\t\\t\\t\\t\\t\\tcollect: [:i | i printString]]\\n\\t\\t\\tifFalse: [(1 to: self i1) , (object size-(self i2-1) to: object size)\\n\\t\\t\\t\\t\\t\\tcollect: [:i | i printString]])\\n\\\"\\nOrderedCollection new inspect\\n(OrderedCollection newFrom: #(3 5 7 123)) inspect\\n(OrderedCollection newFrom: (1 to: 1000)) inspect\\n\\\"! !\\n\\n!OrderedCollectionInspector methodsFor: 'as yet unclassified' stamp: 'sw 9/16/97 22:38'!\\nreplaceSelectionValue: anObject \\n\\t\\\"The receiver has a list of variables of its inspected object. One of these \\n\\tis selected. The value of the selected variable is set to the value, anObject.\\\"\\n\\n\\t(selectionIndex - 2) <= object class instSize\\n\\t\\tifTrue: [^ super replaceSelectionValue: anObject].\\n\\tobject at: self selectedObjectIndex put: anObject! !\\n\\n!OrderedCollectionInspector methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:27'!\\nselectedObjectIndex\\n\\t\\\"Answer the index of the inspectee's collection that the current selection refers to.\\\"\\n\\n\\t| basicIndex |\\n\\tbasicIndex := selectionIndex - 2 - object class instSize.\\n\\t^ (object size <= (self i1 + self i2) or: [basicIndex <= self i1])\\n\\t\\tifTrue: [basicIndex]\\n\\t\\tifFalse: [object size - (self i1 + self i2) + basicIndex]! !\\n\\n!OrderedCollectionInspector methodsFor: 'as yet unclassified' stamp: 'sw 9/16/97 22:39'!\\nselection\\n\\t\\\"The receiver has a list of variables of its inspected object.\\n\\tOne of these is selected. Answer the value of the selected variable.\\\"\\n\\n\\t(selectionIndex - 2) <= object class instSize\\n\\t\\tifTrue: [^ super selection].\\n\\t^ object at: self selectedObjectIndex! !\\nClassTestCase subclass: #OrderedCollectionTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'CollectionsTests-Sequenceable'!\\n!OrderedCollectionTest commentStamp: 'BG 1/10/2004 22:07' prior: 0!\\nThese test cases demonstrate addition of items into an OrderedCollection as well as item removal.\\n\\nSome of the assertions are quite complicated and use a lot of collection protocol. Such methods do not test one single method, but protocol in general.!\\n\\n\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 19:00'!\\ntestAdd\\n\\t| l |\\n\\tl := #(1 2 3 4) asOrderedCollection.\\n\\tl add: 88.\\n\\tself assert: (l = #(1 2 3 4 88) asOrderedCollection).\\n\\tl add: 99.\\n\\tself assert: (l = #(1 2 3 4 88 99) asOrderedCollection). \\n\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 18:52'!\\ntestAddAfter\\n\\n\\t| l |\\n\\tl := #(1 2 3 4) asOrderedCollection.\\n\\tl add: 88 after: 1.\\n\\tself assert: (l = #(1 88 2 3 4) asOrderedCollection).\\n\\tl add: 99 after: 2.\\n\\tself assert: (l = #(1 88 2 99 3 4) asOrderedCollection). \\n\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 18:56'!\\ntestAddAfterIndex\\n\\n\\t| l |\\n\\tl := #(1 2 3 4) asOrderedCollection.\\n\\tl add: 88 afterIndex: 1.\\n\\tself assert: (l = #(1 88 2 3 4) asOrderedCollection).\\n\\tl add: 99 afterIndex: 2.\\n\\tself assert: (l = #(1 88 99 2 3 4) asOrderedCollection). \\n\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'sd 3/21/2006 22:36'!\\ntestAddAll\\n\\t\\\"Allows one to add each element of an orderedCollection at the end of another\\n\\torderedCollection \\\"\\n\\t\\\"self run:#testAddAll\\\" \\n\\t\\n\\t| c1 c2 |\\n\\tc1 := #(1 2 3 4 ) asOrderedCollection.\\n\\tc2 := #(5 6 7 8 9 ) asOrderedCollection.\\n\\tc1 addAll: c2.\\n\\tself assert: c1 = #(1 2 3 4 5 6 7 8 9) asOrderedCollection! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'sd 3/21/2006 22:36'!\\ntestAddAllFirst\\n\\t\\\"Allows one to add each element of an orderedCollection at the beginning of another\\n\\torderedCollection \\\"\\n\\t\\\"self run:#testAddAllFirst\\\" \\n\\t\\n\\t| c1 c2 |\\n\\tc1 := #(1 2 3 4 ) asOrderedCollection.\\n\\tc2 := #(5 6 7 8 9 ) asOrderedCollection.\\n\\tc2 addAllFirst: c1.\\n\\tself assert: c2 = #(1 2 3 4 5 6 7 8 9) asOrderedCollection! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'sd 3/21/2006 22:36'!\\ntestAddAllFirstUnlessAlreadyPresent\\n\\t\\\"Allows one to add each element of an orderedCollection at the beginning of\\n\\tanother orderedCollection preserving the order but no duplicate element\\\"\\n\\t\\\"self run:#testAddAllFirstUnlessAlreadyPresent\\\" \\n\\t\\n\\t| c1 c2 c3 |\\n\\tc1 := #(1 2 3 4 ) asOrderedCollection.\\n\\tc2 := #(5 6 7 8 9 ) asOrderedCollection.\\n\\tc3 := #(0 1 ) asOrderedCollection.\\n\\tc2 addAllFirstUnlessAlreadyPresent: c1.\\n\\tself assert: c2 = #(1 2 3 4 5 6 7 8 9 ) asOrderedCollection.\\n\\tc1 addAllFirstUnlessAlreadyPresent: c3.\\n\\tself deny: c1 = #(0 1 1 2 3 4 ) asOrderedCollection.\\n\\tself assert: c1 = #(0 1 2 3 4 ) asOrderedCollection.\\n\\t! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'sd 3/21/2006 22:36'!\\ntestAddAllLast\\n\\t\\\"Allows one to add each element of an orderedCollection at the beginning of another\\n\\torderedCollection \\\"\\n\\t\\\"self run:#testAddAllLast\\\" \\n\\t\\n\\t| c1 c2 |\\n\\tc1 := #(1 2 3 4 ) asOrderedCollection.\\n\\tc2 := #(5 6 7 8 9 ) asOrderedCollection.\\n\\tc1 addAllLast: c2.\\n\\tself assert: c1 = #(1 2 3 4 5 6 7 8 9) asOrderedCollection! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 18:57'!\\ntestAddBefore\\n\\n\\t| l |\\n\\tl := #(1 2 3 4) asOrderedCollection.\\n\\tl add: 88 before: 1.\\n\\tself assert: (l = #(88 1 2 3 4) asOrderedCollection).\\n\\tl add: 99 before: 2.\\n\\tself assert: (l = #(88 1 99 2 3 4) asOrderedCollection). \\n\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 13:42'!\\ntestAddBeforeAndRemove\\n\\n\\t| l initialCollection |\\n\\tl := #(1 2 3 4) asOrderedCollection.\\n\\tinitialCollection := l shallowCopy.\\n\\tl add: 88 before: 1.\\n\\tself assert: (l = #(88 1 2 3 4) asOrderedCollection).\\n\\tl add: 99 before: 2.\\n\\tself assert: (l = #(88 1 99 2 3 4) asOrderedCollection). \\n\\tl remove: 99.\\n\\tl remove: 88.\\n\\tself assert: l = initialCollection.\\n\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 18:57'!\\ntestAddBeforeIndex\\n\\n\\t| l |\\n\\tl := #(1 2 3 4) asOrderedCollection.\\n\\tl add: 88 beforeIndex: 1.\\n\\tself assert: (l = #(88 1 2 3 4) asOrderedCollection).\\n\\tl add: 99 beforeIndex: 2.\\n\\tself assert: (l = #(88 99 1 2 3 4) asOrderedCollection). \\n\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 13:43'!\\ntestAddDuplicateItem1\\n\\t| collection |\\n\\tcollection := #('Jim' 'Mary' 'John' 'Andrew' ) asOrderedCollection.\\n\\tcollection add: 'John' before: 'John'.\\n\\tself\\n\\t\\tassert: ((collection asBag occurrencesOf: 'John')\\n\\t\\t\\t\\t\\t= 2\\n\\t\\t\\t\\tand: [(collection at: (collection indexOf: 'John')\\n\\t\\t\\t\\t\\t\\t\\t+ 1)\\n\\t\\t\\t\\t\\t\\t= (collection\\n\\t\\t\\t\\t\\t\\t\\t\\tat: (collection indexOf: 'John'))])! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 18:58'!\\ntestAddFirst\\n\\t| l |\\n\\tl := #(1 2 3 4) asOrderedCollection.\\n\\tl addFirst: 88.\\n\\tself assert: (l = #(88 1 2 3 4) asOrderedCollection).\\n\\tl addFirst: 99.\\n\\tself assert: (l = #(99 88 1 2 3 4) asOrderedCollection). \\n\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'sd 6/5/2005 09:21'!\\ntestAddItem1\\n\\n | collection size |\\n collection := #('Jim' 'Mary' 'John' 'Andrew' ) asOrderedCollection.\\n size := collection size.\\n collection add: 'James' before: 'Jim'.\\n collection add: 'Margaret' before: 'Andrew'.\\n self assert: size + 2 = collection size.\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 19:07'!\\ntestAddItem2\\n\\t| collection |\\n\\tcollection := #('Jim' 'Mary' 'John' 'Andrew' ) asOrderedCollection.\\n\\tcollection add: 'James' before: 'Jim'.\\n\\tcollection add: 'Margaret' before: 'Andrew'.\\n\\tself assert: (collection indexOf: 'James')\\n\\t\\t\\t+ 1\\n\\t\\t\\t= (collection indexOf: 'Jim').\\n\\tself assert: (collection indexOf: 'Margaret')\\n\\t\\t\\t+ 1\\n\\t\\t\\t= (collection indexOf: 'Andrew')! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'zz 12/7/2005 18:59'!\\ntestAddLast\\n\\t| l |\\n\\tl := #(1 2 3 4) asOrderedCollection.\\n\\tl addLast: 88.\\n\\tself assert: (l = #(1 2 3 4 88) asOrderedCollection).\\n\\tl addLast: 99.\\n\\tself assert: (l = #(1 2 3 4 88 99) asOrderedCollection). \\n\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAdding' stamp: 'sd 3/21/2006 22:37'!\\ntestAtIfAbsentPut\\n\\t\\\"Allows one to add an element at an index if no element exist at this index\\\"\\n\\t\\\"self run:#testAtIfAbsentPut\\\" \\n\\t\\n\\t| c |\\n\\tc := #(1 2 3 4 ) asOrderedCollection.\\n\\tself\\n\\t\\tshouldnt: [c at: 2 ifAbsentPut: [5]]\\n\\t\\traise: Error.\\n\\tself assert: c = #(1 2 3 4 ) asOrderedCollection.\\n\\tc at: 5 ifAbsentPut: [5].\\n\\tself assert: c = #(1 2 3 4 5 ) asOrderedCollection.\\n\\tc at: 7 ifAbsentPut: [7].\\n\\tself assert: c = #(1 2 3 4 5 nil 7 ) asOrderedCollection! !\\n\\n\\n!OrderedCollectionTest methodsFor: 'testsAccessing' stamp: 'zz 12/7/2005 18:50'!\\ntestAt\\n\\t| collection |\\n\\tcollection := #('Jim' 'Mary' 'John' 'Andrew' ) asOrderedCollection.\\n\\tself assert: (collection at:1) = 'Jim'.\\n\\tself assert: (collection at:2) = 'Mary'! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAccessing' stamp: 'sd 3/21/2006 22:38'!\\ntestAtPut\\n\\t\\\"Allows one to replace an element but not at an off range index\\\"\\n\\t\\\"self run:#testAtPut\\\"\\n\\t| c |\\n\\tc := #(1 2 3 4 ) asOrderedCollection.\\n\\tc at: 2 put: 5.\\n\\tself assert: c = #(1 5 3 4 ) asOrderedCollection.\\n\\tself\\n\\t\\tshould: [c at: 5 put: 8]\\n\\t\\traise: Error.\\n\\tself deny: c = #(1 5 3 4 8 ) asOrderedCollection! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAccessing' stamp: 'sd 3/21/2006 22:39'!\\ntestCapacity\\n\\t\\\"Allows one to check the current capacity of an Ordered collection\\\"\\n\\t\\\"self run:#testCapacity\\\"\\n\\t\\n\\t| c1 c2 c3 |\\n\\tc1 := #(1 2 ) asOrderedCollection.\\n\\tself assert: (c1 capacity = 2).\\n\\tc2 := OrderedCollection new: 10.\\n\\tc2 add: 3.\\n\\tself assert: (c2 capacity = 10).\\t\\n\\tc3 := OrderedCollection new.\\n\\tself deny: (c3 capacity = 0).\\n\\t! !\\n\\n!OrderedCollectionTest methodsFor: 'testsAccessing' stamp: 'sd 3/21/2006 22:38'!\\ntestSize\\n\\t\\\"Allows one to check the size of an Ordered collection\\\"\\n\\t\\\"self run:#testSize\\\"\\n\\t\\n\\t| c1 c2 |\\n\\tc1 := #(1 2 ) asOrderedCollection.\\n\\tself assert: (c1 size = 2).\\n\\t\\n\\tc2 := OrderedCollection new.\\n\\tself assert: (c2 size = 0)\\n\\t! !\\n\\n\\n!OrderedCollectionTest methodsFor: 'testsEnumerating' stamp: 'sd 3/21/2006 22:41'!\\ntestCollect\\n\\t\\\"Allows one to collect some element of a collection into another collection\\\"\\n\\t\\\"self run: #testCollect\\\"\\n\\t \\n\\t| c1 c2 res |\\n\\tc1 := #(-1 2 -3 4) asOrderedCollection.\\n\\tc2 := #(1 2 3 4) asOrderedCollection.\\n\\tres := c1 collect: [:each | each abs].\\n\\tself assert: (c2 = res).! !\\n\\n!OrderedCollectionTest methodsFor: 'testsEnumerating' stamp: 'cm 3/8/2006 09:09'!\\ntestCollectFromTo\\n\\t\\\"Allows one to collect some element of a collection into another collection between a first index and an end index for the collect\\\"\\n\\t\\\"self run: #testCollectFromTo\\\"\\n\\t\\n\\t| c1 res |\\n\\tc1 := #(-1 2 -3 4 -5 6 -7 8) asOrderedCollection.\\n\\tres := c1 collect: [:each | each abs] from: 1 to: 3.\\n\\tself assert: (res = #(1 2 3) asOrderedCollection).\\n\\tself should: [c1 collect: [:each | each abs] from: 10 to: 13] raise: Error.\\n\\tself should: [c1 collect: [:each | each abs] from: 5 to: 2] raise: Error.! !\\n\\n!OrderedCollectionTest methodsFor: 'testsEnumerating' stamp: 'zz 12/7/2005 19:06'!\\ntestIndexOf\\n\\t| collection indices |\\n\\tcollection := #('Jim' 'Mary' 'John' 'Andrew' ) asOrderedCollection.\\n\\tindices := collection\\n\\t\\t\\t\\tcollect: [:item | collection indexOf: item].\\n\\tself assert: (1 to: 4) asOrderedCollection = indices! !\\n\\n!OrderedCollectionTest methodsFor: 'testsEnumerating' stamp: 'sd 6/5/2005 09:21'!\\ntestIndexOfWithDuplicates\\n\\n | collection indices bagOfIndices |\\n collection := #('Jim' 'Mary' 'John' 'Andrew' 'Mary' 'John' 'Jim' 'Micheal') asOrderedCollection.\\n indices := collection collect: [:item | collection indexOf: item].\\n self assert: indices asSet size = collection asSet size.\\n bagOfIndices := indices asBag.\\n self assert: (indices asSet \\n allSatisfy: [:index | (bagOfIndices occurrencesOf: index)\\n\\t = (collection occurrencesOf: (collection at: index))]).\\n\\n \\\" indexOf: returns the index of the first occurrence of an item.\\n For an item with n occurrences, the index of its first occurrence\\n is found n times. \\\"! !\\n\\n!OrderedCollectionTest methodsFor: 'testsEnumerating' stamp: 'cm 3/8/2006 10:02'!\\ntestWithCollect\\n\\t\\\"Allows one to collect some element of two collections into another collection with element corresponding to the condition in the blocks\\\"\\n\\t\\\"self run: #testWithCollect\\\"\\n\\t\\n\\t| c1 c2 res |\\n\\tc1 := #(-1 2 -3 4 -5 6 -7 8) asOrderedCollection.\\n\\tc2 := #(-9 10 -11 12 -13 14 -15 16) asOrderedCollection.\\n\\tres := c1 with: c2 collect: [:each1 :each2 | each1 < each2\\n\\t\\tifTrue: [each1]\\n\\t\\tifFalse: [each2]].\\n\\tself assert: (res = #(-9 2 -11 4 -13 6 -15 8) asOrderedCollection).\\n\\t! !\\n\\n\\n!OrderedCollectionTest methodsFor: 'testsCopying' stamp: 'sd 3/21/2006 22:40'!\\ntestCopyEmpty\\n\\t\\\"Allows one to create a copy of the receiver that contains no elements\\\"\\n\\t\\\"self run:#testCopyEmpty\\\"\\n\\t\\n\\t| c1 c2 |\\n\\tc1 := #(1 2 3 4 ) asOrderedCollection.\\n\\tc2 := c1 copyEmpty.\\n\\tself assert: (c2 size = 0).! !\\n\\n!OrderedCollectionTest methodsFor: 'testsCopying' stamp: 'sd 3/21/2006 22:41'!\\ntestCopyFromTo\\n\\t\\\"Allows one to create a copy of the receiver that contains elements from position start to end\\\"\\n\\t\\\"self run: #testCopyFromTo\\\"\\n\\t\\n\\t| c1 c2 c3 | \\n\\tc1 := #(1 2 3 4) asOrderedCollection.\\n\\tc2 := (c1 copyFrom: 1 to: 2).\\n\\tself assert: c2 = #(1 2) asOrderedCollection.\\n\\tself should: [c1 copyFrom: 10 to: 20] raise: Error.\\n\\t\\n\\tc3 := c1 copyFrom: 4 to: 2.\\n\\tself assert: c3 isEmpty.\\n\\t\\n\\tself should: [c1 copyFrom: 4 to: 5 ] raise: Error.\\n\\t\\n\\t\\n\\t\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsCopying' stamp: 'sd 3/21/2006 22:41'!\\ntestCopyReplaceFromToWith\\n\\t\\\"Allows one to create a copy from the receiver which elements between start and end of the \\treceiver being replace by \\telement of the collection after with:\\\"\\n\\t\\\"self run:#testCopyReplaceFromToWith\\\"\\n\\n\\t| c1 c2 c3 c4 |\\n\\tc1 := #(1 2 3 4) asOrderedCollection.\\n\\tc2 := #(5 6 7 8 9) asOrderedCollection.\\n\\tc3 := (c2 copyReplaceFrom: 1 to: 2 with: c1).\\n\\tself assert: c3 = #(1 2 3 4 7 8 9) asOrderedCollection.\\n\\tself should: [c2 copyReplaceFrom: 3 to: 1 with: c1] raise: Error.\\n\\t\\n\\tc4 := (c2 copyReplaceFrom: 10 to: 25 with: c1).\\n\\tself assert: c4 = #(5 6 7 8 9 1 2 3 4) asOrderedCollection.\\n\\t\\n\\t! !\\n\\n!OrderedCollectionTest methodsFor: 'testsCopying' stamp: 'sd 3/21/2006 22:41'!\\ntestCopyWith\\n\\t\\\"Allows one to create a copy of the receiver that contains the new element at the end\\\"\\n\\t\\\"self run: #testCopyWith\\\"\\n\\t\\n\\t| c1 | \\n\\tc1 := #(1 2 3 4) asOrderedCollection.\\n\\tc1 := c1 copyWith: 6.\\n\\tself assert: c1 = #(1 2 3 4 6) asOrderedCollection.\\n\\t\\n\\t\\n\\n\\t\\n\\t\\n\\t\\n! !\\n\\n!OrderedCollectionTest methodsFor: 'testsCopying' stamp: 'zz 12/7/2005 13:47'!\\ntestReversed\\n\\t| collection1 collection2 |\\n\\tcollection1 := #('Jim' 'Mary' 'John' 'Andrew' ) asOrderedCollection.\\n\\tcollection2 := collection1 reversed.\\n\\tself assert: collection2 first = 'Andrew'.\\n\\tself assert: collection2 last = 'Jim'! !\\n\\n\\n!OrderedCollectionTest methodsFor: 'testsRemoving' stamp: 'zz 12/7/2005 19:05'!\\ntestRemoveAllSuchThat\\n\\t| collection |\\n\\tcollection := (1 to: 10) asOrderedCollection.\\n\\tcollection\\n\\t\\tremoveAllSuchThat: [:e | e even].\\n\\tself assert: collection = (1 to: 10 by: 2) asOrderedCollection! !\\n\\n!OrderedCollectionTest methodsFor: 'testsRemoving' stamp: 'sd 3/21/2006 22:39'!\\ntestRemoveAt\\n\\t\\\"Allows one to remove an element from a collection at an index\\\"\\n\\t\\\"self run:#testRemoveAt\\\" \\n\\t\\n\\t| c1 |\\n\\tc1 := #(2 3 4 6) asOrderedCollection.\\n\\tc1 removeAt: 2.\\n\\tself assert: (c1 = #(2 4 6) asOrderedCollection).\\n\\tself should: [c1 removeAt: 10] raise: Error.\\n\\tself should: [c1 removeAt: -1] raise: Error.\\n\\t! !\\n\\n!OrderedCollectionTest methodsFor: 'testsRemoving' stamp: 'sd 3/21/2006 22:39'!\\ntestRemoveFirst\\n\\t\\\"Allows one to remove n element of a collection at the first\\\"\\n\\t\\\"self run:#testRemoveFirst\\\" \\n\\t\\n\\t| c1 |\\n\\tc1 := #(2 3 4 6) asOrderedCollection.\\n\\tc1 removeFirst: 1.\\n\\tself assert: (c1 = #(3 4 6) asOrderedCollection).\\n\\tc1 removeFirst: 2.\\n\\tself assert: (c1 = #(6) asOrderedCollection).\\n\\tself should: [c1 removeFirst: 10] raise: Error.\\n\\t\\n\\t! !\\n\\n!OrderedCollectionTest methodsFor: 'testsRemoving' stamp: 'sd 3/21/2006 22:39'!\\ntestRemoveIfAbsent\\n\\t\\\"Allows one to remove an element from a collection and to copy it in another collection.\\\"\\n\\t\\\"If the element isn't in the first collection, the second collection copy the element after ifAbsent\\\"\\n\\t\\\"self run:#testRemoveIfAbsent\\\"\\n\\t\\n\\t| c1 c2 |\\n\\tc1 := #(1 2 3 4) asOrderedCollection.\\n\\tc2 := OrderedCollection new.\\n\\t\\n\\tc2 add: (c1 remove: 2 ifAbsent: [6]).\\n\\tself assert: (c1 = #(1 3 4) asOrderedCollection).\\n\\tself assert: (c2 = #(2) asOrderedCollection).\\n\\t\\n\\tc2 add: (c1 remove: 18 ifAbsent: [6]).\\n\\tself assert: (c1 = #(1 3 4) asOrderedCollection).\\n\\tself assert: (c2 = #(2 6) asOrderedCollection).! !\\n\\n!OrderedCollectionTest methodsFor: 'testsRemoving' stamp: 'sd 3/21/2006 22:39'!\\ntestRemoveLast\\n\\t\\\"Allows one to remove n element of a collection at the end\\\"\\n\\t\\\"self run:#testRemoveLast\\\" \\n\\t\\n\\t| c1 |\\n\\tc1 := #(2 3 4 6) asOrderedCollection.\\n\\tc1 removeLast: 1.\\n\\tself assert: (c1 = #(2 3 4) asOrderedCollection).\\n\\tc1 removeLast: 2.\\n\\tself assert: (c1 = #(2) asOrderedCollection).\\n\\tself should: [c1 removeLast: 10] raise: Error.! !\\nFillStyle subclass: #OrientedFillStyle\\n\\tinstanceVariableNames: 'origin direction normal'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Balloon-Fills'!\\n!OrientedFillStyle commentStamp: '<historical>' prior: 0!\\nOrientedFill is an abstract superclass for fills which can be aligned appropriately.\\n\\nInstance variables:\\n\\torigin\\t<Point>\\tThe point at which to align the fill.\\n\\tdirection <Point>\\tThe direction in which the fill is defined\\n\\tnormal\\t<Point>\\tTypically, just the direction rotated by 90 degrees.!\\n\\n\\n!OrientedFillStyle methodsFor: 'accessing' stamp: 'ar 8/25/2001 17:03'!\\ndirection\\n\\t^direction ifNil:[direction := normal y @ normal x negated]! !\\n\\n!OrientedFillStyle methodsFor: 'accessing' stamp: 'ar 11/11/1998 22:37'!\\ndirection: aPoint\\n\\tdirection := aPoint! !\\n\\n!OrientedFillStyle methodsFor: 'accessing' stamp: 'ar 11/14/1998 23:31'!\\nnormal\\n\\t^normal ifNil:[normal := direction y negated @ direction x]! !\\n\\n!OrientedFillStyle methodsFor: 'accessing' stamp: 'ar 11/11/1998 22:37'!\\nnormal: aPoint\\n\\tnormal := aPoint! !\\n\\n!OrientedFillStyle methodsFor: 'accessing' stamp: 'ar 11/11/1998 22:38'!\\norigin\\n\\t^origin! !\\n\\n!OrientedFillStyle methodsFor: 'accessing' stamp: 'ar 11/11/1998 22:38'!\\norigin: aPoint\\n\\torigin := aPoint.! !\\n\\n\\n!OrientedFillStyle methodsFor: 'testing' stamp: 'ar 6/18/1999 07:57'!\\nisOrientedFill\\n\\t\\\"Return true if the receiver keeps an orientation (e.g., origin, direction, and normal)\\\"\\n\\t^true! !\\n\\n\\n!OrientedFillStyle methodsFor: '*Morphic-Balloon' stamp: 'dgd 10/17/2003 22:35'!\\naddFillStyleMenuItems: aMenu hand: aHand from: aMorph\\n\\t\\\"Add the items for changing the current fill style of the receiver\\\"\\n\\taMenu add: 'change origin' translated target: self selector: #changeOriginIn:event: argument: aMorph.\\n\\taMenu add: 'change orientation' translated target: self selector: #changeOrientationIn:event: argument: aMorph.! !\\n\\n!OrientedFillStyle methodsFor: '*Morphic-Balloon' stamp: 'ar 6/18/1999 07:41'!\\nchangeOrientationIn: aMorph event: evt\\n\\t\\\"Interactively change the origin of the receiver\\\"\\n\\t| handle |\\n\\thandle _ HandleMorph new forEachPointDo:[:pt|\\n\\t\\tself direction: pt - self origin.\\n\\t\\tself normal: nil.\\n\\t\\taMorph changed].\\n\\tevt hand attachMorph: handle.\\n\\thandle startStepping.! !\\n\\n!OrientedFillStyle methodsFor: '*Morphic-Balloon' stamp: 'ar 6/18/1999 07:28'!\\nchangeOriginIn: aMorph event: evt\\n\\t\\\"Interactively change the origin of the receiver\\\"\\n\\t| handle |\\n\\thandle _ HandleMorph new forEachPointDo:[:pt|\\n\\t\\tself origin: pt.\\n\\t\\taMorph changed].\\n\\tevt hand attachMorph: handle.\\n\\thandle startStepping.! !\\nNotification subclass: #OutOfScopeNotification\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Exceptions-Kernel'!\\n\\n!OutOfScopeNotification methodsFor: 'as yet unclassified' stamp: 'RAA 2/5/2001 10:41'!\\ndefaultAction\\n\\n\\tself resume: false! !\\nPBPreferenceView subclass: #PBBooleanPreferenceView\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PreferenceBrowser'!\\n!PBBooleanPreferenceView commentStamp: '<historical>' prior: 0!\\nI am responsible for building the visual representation of a preference that accepts true and false values. This view is aimed to be used inside a PreferenceBrowser panel.!\\n\\n\\n!PBBooleanPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 00:23'!\\nenabledButton\\n\\t| aButton aLabel |\\n\\taButton := UpdatingThreePhaseButtonMorph checkBox\\n\\t\\ttarget: self preference;\\n\\t\\tactionSelector: #togglePreferenceValue;\\n\\t\\tgetSelector: #preferenceValue;\\n\\t\\tyourself.\\n\\taLabel := (StringMorph contents: 'enabled' translated\\n\\t\\t\\t\\tfont: (StrikeFont familyName: TextStyle defaultFont familyName\\n\\t\\t\\t\\t\\t\\t\\tsize: TextStyle defaultFont pointSize - 1)).\\n\\t^self horizontalPanel\\n\\t\\taddMorphBack: aButton;\\n\\t\\taddMorphBack: aLabel;\\n\\t\\tyourself.! !\\n\\n!PBBooleanPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 00:27'!\\nlocalToProjectButton\\n\\t| aButton aLabel |\\n\\taButton := UpdatingThreePhaseButtonMorph checkBox\\n\\t\\ttarget: self preference;\\n\\t\\tactionSelector: #toggleProjectLocalness;\\n\\t\\tgetSelector: #localToProject;\\n\\t\\tyourself.\\n\\taLabel := (StringMorph contents: 'local' translated\\n\\t\\t\\t\\tfont: (StrikeFont familyName: TextStyle defaultFont familyName\\n\\t\\t\\t\\t\\t\\t\\tsize: TextStyle defaultFont pointSize - 1)).\\t\\t\\n\\t^self horizontalPanel\\n\\t\\taddMorphBack: aButton;\\n\\t\\taddMorphBack: aLabel;\\n\\t\\tyourself.! !\\n\\n!PBBooleanPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 00:25'!\\nrepresentativeButtonWithColor: aColor inPanel: aPreferencesPanel\\n\\t^self horizontalPanel\\n\\t\\tlayoutInset: 2;\\n\\t\\tcellInset: 7;\\n\\t\\tcolor: aColor;\\n\\t\\taddMorphBack: (StringMorph contents: self preference name);\\n\\t\\taddMorphBack: self horizontalFiller; \\n\\t\\taddMorphBack: self enabledButton;\\n\\t\\taddMorphBack: self localToProjectButton;\\n\\t\\tyourself.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPBBooleanPreferenceView class\\n\\tinstanceVariableNames: ''!\\n\\n!PBBooleanPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 9/26/2004 15:47'!\\ninitialize\\n\\tPreferenceViewRegistry ofBooleanPreferences register: self.\\n! !\\n\\n!PBBooleanPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 9/26/2004 15:47'!\\nunload\\n\\tPreferenceViewRegistry ofBooleanPreferences unregister: self.! !\\nPBPreferenceView subclass: #PBColorPreferenceView\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PreferenceBrowser'!\\n\\n!PBColorPreferenceView methodsFor: 'user interface' stamp: 'hpt 12/6/2004 21:24'!\\ncolorSwatch\\n\\t^UpdatingRectangleMorph new\\n\\t\\ttarget: self preference;\\n\\t\\tgetSelector: #preferenceValue;\\n\\t\\tputSelector: #preferenceValue:;\\n\\t\\textent: 22@22;\\n\\t\\tsetBalloonText: 'click here to change the color' translated;\\n\\t\\tyourself.! !\\n\\n!PBColorPreferenceView methodsFor: 'user interface' stamp: 'hpt 12/6/2004 21:12'!\\nrepresentativeButtonWithColor: aColor inPanel: aPreferenceBrowser\\n\\t^self horizontalPanel\\n\\t\\tlayoutInset: 2;\\n\\t\\tcolor: aColor;\\n\\t\\tcellInset: 20;\\n\\t\\tcellPositioning: #center;\\n\\t\\taddMorphBack: (StringMorph contents: self preference name);\\n\\t\\taddMorphBack: self horizontalFiller;\\n\\t\\taddMorphBack: self colorSwatch;\\n\\t\\tyourself! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPBColorPreferenceView class\\n\\tinstanceVariableNames: ''!\\n\\n!PBColorPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 12/6/2004 20:49'!\\ninitialize\\n\\tPreferenceViewRegistry ofColorPreferences register: self.! !\\n\\n!PBColorPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 12/6/2004 20:49'!\\nunload\\n\\tPreferenceViewRegistry ofColorPreferences unregister: self.! !\\nPBPreferenceView subclass: #PBHaloThemePreferenceView\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PreferenceBrowser'!\\n!PBHaloThemePreferenceView commentStamp: '<historical>' prior: 0!\\nI am responsible for building the button for the Halo Theme preference!\\n\\n\\n!PBHaloThemePreferenceView methodsFor: 'initialization' stamp: 'hpt 12/8/2004 18:12'!\\ninitialize\\n\\tself addActionTitled: 'edit custom halos' \\n\\t\\ttarget: Preferences \\n\\t\\tselector: #editCustomHalos \\n\\t\\targuments: {} \\n\\t\\tballoonText: 'Click here to edit the method that defines the custom halos' translated.! !\\n\\n\\n!PBHaloThemePreferenceView methodsFor: 'user interface' stamp: 'hpt 12/8/2004 18:18'!\\nhaloThemeRadioButtons\\n\\t\\\"Answer a column of butons representing the choices of halo theme\\\"\\n\\n\\t| buttonColumn aRow aRadioButton aLabel |\\n\\tbuttonColumn := self verticalPanel.\\n\\t#(\\t(iconicHaloSpecifications iconic iconicHalosInForce\\t'circular halos with icons inside')\\n\\t\\t(classicHaloSpecs\\tclassic\\tclassicHalosInForce\\t\\t'plain circular halos')\\n\\t\\t(simpleFullHaloSpecifications\\t\\tsimple\\tsimpleHalosInForce\\t'fewer, larger halos')\\n\\t\\t(customHaloSpecs\\tcustom\\tcustomHalosInForce\\t\\t'customizable halos')) do:\\n\\n\\t\\t[:quad |\\n\\t\\t\\taRadioButton := UpdatingThreePhaseButtonMorph radioButton\\n\\t\\t\\t\\ttarget: Preferences;\\n\\t\\t\\t\\tsetBalloonText: quad fourth;\\n\\t\\t\\t\\tactionSelector: #installHaloTheme:;\\n\\t\\t\\t\\tgetSelector: quad third;\\n\\t\\t\\t\\targuments: (Array with: quad first);\\n\\t\\t\\t\\tyourself.\\n\\t\\t\\taLabel := (StringMorph contents: quad second asString)\\n\\t\\t\\t\\t\\t\\tsetBalloonText: quad fourth;\\n\\t\\t\\t\\t\\t\\tyourself.\\n\\t\\t\\taRow := self horizontalPanel\\n\\t\\t\\t\\tcellInset: 4;\\n\\t\\t\\t\\taddMorphBack: aRadioButton;\\n\\t\\t\\t\\taddMorphBack: aLabel.\\n\\t\\t\\tbuttonColumn addMorphBack: aRow].\\n\\t^ buttonColumn\\n\\n\\t\\\"(Preferences preferenceAt: #haloTheme) view tearOffButton\\\"! !\\n\\n!PBHaloThemePreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 00:45'!\\nrepresentativeButtonWithColor: aColor inPanel: aPreferencesPanel\\n\\t| innerPanel |\\n\\tinnerPanel := self horizontalPanel\\n\\t\\taddMorphBack: (self blankSpaceOf: 10@0);\\n\\t\\taddMorphBack: self haloThemeRadioButtons;\\n\\t\\tyourself.\\n\\t^self verticalPanel\\n\\t\\tcolor: aColor;\\n\\t\\tlayoutInset: 2;\\n\\t\\taddMorphBack: (StringMorph contents: self preference name);\\n\\t\\taddMorphBack: innerPanel.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPBHaloThemePreferenceView class\\n\\tinstanceVariableNames: ''!\\n\\n!PBHaloThemePreferenceView class methodsFor: 'class initialization' stamp: 'hpt 9/26/2004 15:48'!\\ninitialize\\n\\tPreferenceViewRegistry ofHaloThemePreferences register: self.! !\\n\\n!PBHaloThemePreferenceView class methodsFor: 'class initialization' stamp: 'hpt 9/26/2004 15:48'!\\nunload\\n\\tPreferenceViewRegistry ofHaloThemePreferences unregister: self.! !\\nPBPreferenceView subclass: #PBNumericPreferenceView\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PreferenceBrowser'!\\n\\n!PBNumericPreferenceView methodsFor: 'user interface' stamp: 'hpt 12/9/2004 22:23'!\\npreferenceValue\\n\\t^self preference preferenceValue asString! !\\n\\n!PBNumericPreferenceView methodsFor: 'user interface' stamp: 'hpt 12/10/2004 22:53'!\\npreferenceValue: aTextOrString\\n\\t(aTextOrString notEmpty and: [aTextOrString asString isAllDigits])\\n\\t\\tifFalse: [^false].\\n\\tself preference preferenceValue: aTextOrString asNumber.\\n\\t^true.! !\\n\\n!PBNumericPreferenceView methodsFor: 'user interface' stamp: 'hpt 12/9/2004 22:19'!\\nrepresentativeButtonWithColor: aColor inPanel: aPreferenceBrowser\\n\\t^self horizontalPanel\\n\\t\\tlayoutInset: 2;\\n\\t\\tcolor: aColor;\\n\\t\\tcellInset: 20;\\n\\t\\tcellPositioning: #center;\\n\\t\\taddMorphBack: (StringMorph contents: self preference name);\\n\\t\\taddMorphBack: self textField;\\n\\t\\tyourself.! !\\n\\n!PBNumericPreferenceView methodsFor: 'user interface' stamp: 'hpt 12/9/2004 22:19'!\\ntextField\\n\\t^(PluggableTextMorph\\n\\t\\ton: self\\n\\t\\ttext: #preferenceValue\\n\\t\\taccept: #preferenceValue:)\\n\\t\\t\\thideVScrollBarIndefinitely: true;\\n\\t\\t\\tborderColor: #inset;\\n\\t\\t\\tacceptOnCR: true;\\n\\t\\t\\tcolor: Color gray veryMuchLighter;\\n\\t\\t\\tvResizing: #rigid;\\n\\t\\t\\thResizing: #spaceFill;\\n\\t\\t\\theight: TextStyle defaultFont height + 6;\\n\\t\\t\\tyourself.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPBNumericPreferenceView class\\n\\tinstanceVariableNames: ''!\\n\\n!PBNumericPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 12/9/2004 22:21'!\\ninitialize\\n\\tPreferenceViewRegistry ofNumericPreferences register: self.! !\\n\\n!PBNumericPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 12/9/2004 22:21'!\\nunload\\n\\tPreferenceViewRegistry ofNumericPreferences unregister: self.! !\\nMorph subclass: #PBPreferenceButtonMorph\\n\\tinstanceVariableNames: 'moreButton model preference preferenceMorphicView preferenceView'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PreferenceBrowser'!\\n\\n!PBPreferenceButtonMorph methodsFor: 'accessing' stamp: 'hpt 12/8/2004 15:34'!\\nmodel\\n\\t^model! !\\n\\n\\n!PBPreferenceButtonMorph methodsFor: 'extra controls' stamp: 'hpt 12/8/2004 18:15'!\\nactionButtons\\n\\t^self preferenceView actions collect: [:aTuple |\\n\\t\\tself basicButton\\n\\t\\t\\t\\tlabel: aTuple first;\\n\\t\\t\\t\\ttarget: aTuple second;\\n\\t\\t\\t\\tactionSelector: aTuple third;\\n\\t\\t\\t\\targuments: aTuple fourth;\\n\\t\\t\\t\\tsetBalloonText: aTuple fifth ]! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'extra controls' stamp: 'hpt 8/24/2005 20:33'!\\naddExtraControls\\n\\t| m |\\n\\tm := self horizontalPanel\\n\\t\\tcellInset: 3;\\n\\t\\taddAllMorphs: self actionButtons;\\n\\t\\taddMorphBack: self horizontalFiller;\\n\\t\\taddMorphBack: self moreButton;\\n\\t\\tyourself.\\n\\tself \\n\\t\\taddMorphBack: (self blankSpaceOf: 2@2);\\n\\t\\taddMorphBack: self preferenceHelpTextMorph;\\n\\t\\tfullBounds; \\\"to force a layout compute needed by the textMorphs's autoFit\\\"\\n\\t\\taddMorphBack: m\\n! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'extra controls' stamp: 'hpt 12/8/2004 17:16'!\\nadvancedOptionsSelected\\n\\tself preferenceView offerPreferenceNameMenu: self model! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'extra controls' stamp: 'hpt 12/8/2004 18:17'!\\nmoreButton\\n\\t^moreButton ifNil: \\n\\t\\t[moreButton := self basicButton \\n\\t\\t\\t\\t\\t\\tlabel: 'more' translated; \\n\\t\\t\\t\\t\\t\\tsetBalloonText: \\n\\t\\t\\t\\t\\t\\t\\t'Click here for advanced options'translated;\\n\\t\\t\\t\\t\\t\\tactionSelector: #advancedOptionsSelected]! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'extra controls' stamp: 'stephaneducasse 2/4/2006 20:39'!\\npreferenceHelpTextMorph\\n\\t| text tm |\\n\\ttext := self preferenceHelpText.\\n\\ttm := TextMorph new\\n\\t\\tcontents: text;\\n\\t\\twrapOnOff;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tlock: true;\\n\\t\\tvisible: text notEmpty;\\n\\t\\tyourself. \\\"we don't want an empty textmorph showing\\\"\\n\\ttm isAutoFit\\n\\t\\tifFalse: [tm autoFitOnOff].\\n\\t^tm.! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'extra controls' stamp: 'hpt 12/8/2004 16:40'!\\nremoveExtraControls\\n\\tself submorphs copyWithoutFirst do: [:ea | ea delete]! !\\n\\n\\n!PBPreferenceButtonMorph methodsFor: 'highlighting' stamp: 'hpt 12/8/2004 15:55'!\\nhighlightOff\\n\\tself beTransparent.\\n\\tself label color: Color black.\\n\\tself removeExtraControls.! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'highlighting' stamp: 'hpt 12/8/2004 17:25'!\\nhighlightOn\\n\\tself color: (Color gray alpha: 0.1).\\n\\tself label color: Color red.\\n\\tself addExtraControls.! !\\n\\n\\n!PBPreferenceButtonMorph methodsFor: 'initialization' stamp: 'hpt 12/8/2004 15:38'!\\ninitializeLayout\\n\\tself layoutPolicy: TableLayout new;\\n\\t\\tbeTransparent;\\n\\t\\tlayoutInset: 0;\\n\\t\\tcellInset: 0;\\n\\t\\tlistCentering: #topLeft;\\n\\t\\tcellPositioning: #topLeft;\\n\\t\\tlistDirection: #topToBottom;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #shrinkWrap.\\t\\t! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'initialization' stamp: 'hpt 12/8/2004 15:38'!\\ninitializeWithPreference: aPreference model: aModel\\n\\tpreference := aPreference.\\n\\tmodel := aModel.\\n\\tself initializeLayout.\\n\\tself addMorphBack: self preferenceMorphicView.\\n\\tself highlightOff.! !\\n\\n\\n!PBPreferenceButtonMorph methodsFor: 'preference accessing' stamp: 'hpt 12/8/2004 15:42'!\\nlabel\\n\\t^self preferenceMorphicView firstSubmorph! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'preference accessing' stamp: 'hpt 12/8/2004 15:13'!\\npreference\\n\\t^preference! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'preference accessing' stamp: 'hpt 12/8/2004 15:56'!\\npreferenceHelp\\n\\t| help name |\\n\\thelp := self preference helpString withBlanksTrimmed.\\n\\tname := self preference name.\\n\\t(self caseInsensitiveBeginsWith: name in: help)\\n\\t\\tifTrue: [help := help allButFirst: name size].\\n\\t(help notEmpty and: [help first = $:])\\n\\t\\tifTrue: [help := help allButFirst].\\n\\t^help withBlanksTrimmed.\\n! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'preference accessing' stamp: 'hpt 12/8/2004 15:25'!\\npreferenceHelpText\\n\\t^self preferenceHelp asText\\n\\t\\taddAttribute: TextEmphasis italic;\\n\\t\\tyourself.! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'preference accessing' stamp: 'hpt 12/8/2004 15:48'!\\npreferenceMorphicView\\n\\t^preferenceMorphicView\\n\\t\\tifNil: \\n\\t\\t\\t[preferenceMorphicView := self preferenceView\\n\\t\\t\\t\\trepresentativeButtonWithColor: Color transparent inPanel: self model.\\n\\t\\t\\tpreferenceMorphicView hResizing: #spaceFill.\\n\\t\\t\\t^preferenceMorphicView]! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'preference accessing' stamp: 'stephaneducasse 2/4/2006 20:39'!\\npreferenceView\\n\\t^preferenceView\\n\\t\\tifNil: [preferenceView := self preference viewForPanel: self model.]! !\\n\\n\\n!PBPreferenceButtonMorph methodsFor: 'utility methods' stamp: 'hpt 12/8/2004 17:06'!\\nbasicButton\\n\\t| button |\\n\\tbutton := SimpleButtonMorph new.\\n\\tbutton\\n\\t\\tborderWidth: 1;\\n\\t\\tborderColor: self paneColor;\\n\\t\\ton: #mouseEnter send: #value to: [button borderWidth: 2];\\n\\t\\ton: #mouseLeave send: #value to: [button borderWidth: 1];\\n\\t\\tvResizing: #rigid;\\n\\t\\theight: (TextStyle defaultFont height + 4);\\n\\t\\tuseSquareCorners;\\n\\t\\tclipSubmorphs: true;\\n\\t\\tcolor: self paneColor muchLighter;\\n\\t\\ttarget: self.\\n\\t^button! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'utility methods' stamp: 'hpt 12/8/2004 15:59'!\\nbasicPanel\\n\\t^BorderedMorph new\\n\\t\\tbeTransparent;\\n\\t\\textent: 0@0;\\n\\t\\tborderWidth: 0;\\n\\t\\tlayoutInset: 0;\\n\\t\\tcellInset: 0;\\n\\t\\tlayoutPolicy: TableLayout new;\\n\\t\\tlistCentering: #topLeft;\\n\\t\\tcellPositioning: #center;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tyourself! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'utility methods' stamp: 'hpt 12/8/2004 15:29'!\\nblankSpaceOf: aPoint\\n\\t^Morph new \\n\\t\\tbeTransparent;\\n\\t\\textent: aPoint; \\n\\t\\tyourself! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'utility methods' stamp: 'hpt 12/8/2004 15:43'!\\ncaseInsensitiveBeginsWith: prefix in: string\\n\\t^(string findString: prefix startingAt: 1 caseSensitive: false) = 1! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'utility methods' stamp: 'hpt 12/8/2004 16:42'!\\nhorizontalFiller\\n\\t^self horizontalPanel\\n\\t\\thResizing: #spaceFill;\\n\\t\\tyourself.! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'utility methods' stamp: 'hpt 12/8/2004 16:42'!\\nhorizontalPanel\\n\\t^self basicPanel\\n\\t\\tcellPositioning: #center;\\n\\t\\tlistDirection: #leftToRight;\\n\\t\\tyourself.! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'utility methods' stamp: 'stephaneducasse 2/4/2006 20:39'!\\npaneColor\\n\\t| browser |\\n\\tbrowser := (self ownerChain \\n\\t\\tdetect: [:ea | ea isKindOf: PreferenceBrowserMorph] \\n\\t\\tifNone: [^Color black]) .\\n\\t^browser paneColor! !\\n\\n!PBPreferenceButtonMorph methodsFor: 'utility methods' stamp: 'hpt 12/8/2004 15:27'!\\nverticalPanel\\n\\t^self basicPanel\\n\\t\\tcellPositioning: #topLeft;\\n\\t\\tlistDirection: #topToBottom;\\n\\t\\tyourself.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPBPreferenceButtonMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!PBPreferenceButtonMorph class methodsFor: 'instance creation' stamp: 'hpt 12/8/2004 15:20'!\\npreference: aPreference\\n\\t^self preference: aPreference model: nil! !\\n\\n!PBPreferenceButtonMorph class methodsFor: 'instance creation' stamp: 'hpt 12/8/2004 15:19'!\\npreference: aPreference model: aModel\\n\\t^self new\\n\\t\\tinitializeWithPreference: aPreference model: aModel;\\n\\t\\tyourself.! !\\nPreferenceView subclass: #PBPreferenceView\\n\\tinstanceVariableNames: 'actions'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PreferenceBrowser'!\\n!PBPreferenceView commentStamp: '<historical>' prior: 0!\\nI am just a refactor of all the common method of the PreferenceBrowser preference views!\\n\\n\\n!PBPreferenceView methodsFor: 'actions' stamp: 'stephaneducasse 2/4/2006 20:39'!\\nactions\\n\\t^actions ifNil: [actions := OrderedCollection new.]! !\\n\\n!PBPreferenceView methodsFor: 'actions' stamp: 'hpt 12/8/2004 18:13'!\\naddActionTitled: aTitle target: aTarget selector: aSelector arguments: aCollection balloonText: aText\\n\\tself actions add: { aTitle. aTarget. aSelector. aCollection. aText }! !\\n\\n\\n!PBPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 11:42'!\\nbasicPanel\\n\\t^BorderedMorph new\\n\\t\\tbeTransparent;\\n\\t\\textent: 0@0;\\n\\t\\tborderWidth: 0;\\n\\t\\tlayoutInset: 0;\\n\\t\\tcellInset: 2;\\n\\t\\tlayoutPolicy: TableLayout new;\\n\\t\\tlistCentering: #topLeft;\\n\\t\\tcellPositioning: #center;\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tyourself! !\\n\\n!PBPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 00:15'!\\nblankSpaceOf: aPoint\\n\\t^Morph new \\n\\t\\tbeTransparent;\\n\\t\\textent: aPoint; \\n\\t\\tyourself! !\\n\\n!PBPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 00:13'!\\nhorizontalFiller\\n\\t^self horizontalPanel\\n\\t\\thResizing: #spaceFill;\\n\\t\\tyourself.! !\\n\\n!PBPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 11:43'!\\nhorizontalPanel\\n\\t^self basicPanel\\n\\t\\tcellPositioning: #center;\\n\\t\\tlistDirection: #leftToRight;\\n\\t\\tyourself.! !\\n\\n!PBPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 00:48'!\\nofferPreferenceNameMenu: aPreferenceBrowser\\n\\t\\\"the user clicked on a preference name -- put up a menu\\\"\\n\\n\\t| aMenu |\\t\\t\\t\\n\\taMenu := MenuMorph new \\n\\t\\tdefaultTarget: self preference;\\n\\t\\taddTitle: self preference name.\\n\\n\\t(Preferences okayToChangeProjectLocalnessOf: self preference name) ifTrue:\\n\\t\\t[aMenu addUpdating: #isProjectLocalString target: self preference action: #toggleProjectLocalness.\\n\\t\\taMenu balloonTextForLastItem: 'Some preferences are best applied uniformly to all projects, and others are best set by each individual project. If this item is checked, then this preference will be printed in bold and will have a separate value for each project'].\\n\\n\\taMenu add: 'browse senders' translated target: self systemNavigation selector: #browseAllCallsOn: argument: self preference name.\\n\\taMenu balloonTextForLastItem: 'This will open a method-list browser on all methods that the send the preference \\\"', self preference name, '\\\".'. \\n\\taMenu add: 'show category...' target: aPreferenceBrowser selector: #findCategoryFromPreference: argument: self preference name.\\n\\taMenu balloonTextForLastItem: 'Allows you to find out which category, or categories, this preference belongs to.'.\\n\\n\\tSmalltalk isMorphic ifTrue:\\n\\t\\t[aMenu add: 'hand me a button for this preference' target: self selector: #tearOffButton.\\n\\t\\taMenu balloonTextForLastItem: 'Will give you a button that governs this preference, which you may deposit wherever you wish'].\\n\\n\\taMenu add: 'copy this name to clipboard' target: self preference selector: #copyName.\\n\\taMenu balloonTextForLastItem: 'Copy the name of the preference to the text clipboard, so that you can paste into code somewhere'.\\n\\n\\taMenu popUpInWorld! !\\n\\n!PBPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 11:43'!\\nverticalPanel\\n\\t^self basicPanel\\n\\t\\tcellPositioning: #topLeft;\\n\\t\\tlistDirection: #topToBottom;\\n\\t\\tyourself.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPBPreferenceView class\\n\\tinstanceVariableNames: ''!\\n\\n!PBPreferenceView class methodsFor: 'view registry' stamp: 'hpt 9/26/2004 16:09'!\\nhandlesPanel: aPreferencePanel\\n\\t^aPreferencePanel isKindOf: PreferenceBrowser! !\\nPBPreferenceView subclass: #PBTextPreferenceView\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PreferenceBrowser'!\\n\\n!PBTextPreferenceView methodsFor: 'user interface' stamp: 'hpt 12/10/2004 22:46'!\\npreferenceValue\\n\\t^self preference preferenceValue ifNil: ['']! !\\n\\n!PBTextPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 11:38'!\\npreferenceValue: aTextOrString\\n\\tself preference preferenceValue: aTextOrString asString.\\n\\t^true.! !\\n\\n!PBTextPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 11:41'!\\nrepresentativeButtonWithColor: aColor inPanel: aPreferenceBrowser\\n\\t^self horizontalPanel\\n\\t\\tlayoutInset: 2;\\n\\t\\tcolor: aColor;\\n\\t\\tcellInset: 20;\\n\\t\\tcellPositioning: #center;\\n\\t\\taddMorphBack: (StringMorph contents: self preference name);\\n\\t\\taddMorphBack: self textField;\\n\\t\\tyourself.! !\\n\\n!PBTextPreferenceView methodsFor: 'user interface' stamp: 'hpt 9/26/2004 11:41'!\\ntextField\\n\\t^(PluggableTextMorph\\n\\t\\ton: self\\n\\t\\ttext: #preferenceValue\\n\\t\\taccept: #preferenceValue:)\\n\\t\\t\\thideVScrollBarIndefinitely: true;\\n\\t\\t\\tborderColor: #inset;\\n\\t\\t\\tacceptOnCR: true;\\n\\t\\t\\tcolor: Color gray veryMuchLighter;\\n\\t\\t\\tvResizing: #rigid;\\n\\t\\t\\thResizing: #spaceFill;\\n\\t\\t\\theight: TextStyle defaultFont height + 6;\\n\\t\\t\\tyourself.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPBTextPreferenceView class\\n\\tinstanceVariableNames: ''!\\n\\n!PBTextPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 9/26/2004 17:01'!\\ninitialize\\n\\tPreferenceViewRegistry ofTextPreferences register: self.! !\\n\\n!PBTextPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 9/26/2004 17:01'!\\nunload\\n\\tPreferenceViewRegistry ofTextPreferences unregister: self.! !\\nPBColorPreferenceView subclass: #PBWindowColorPreferenceView\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PreferenceBrowser'!\\n\\n!PBWindowColorPreferenceView methodsFor: 'initialization' stamp: 'hpt 12/8/2004 18:38'!\\ninitialize\\n\\tsuper initialize.\\n\\tself addActionTitled: 'Bright' target: Preferences selector: #installBrightWindowColors arguments: {} balloonText: 'Use standard bright colors for all windows' translated.\\n\\tself addActionTitled: 'Pastel' target: Preferences selector: #installPastelWindowColors arguments: {} balloonText: 'Use standard pastel colors for all windows' translated.\\t\\n\\tself addActionTitled: 'White' target: Preferences selector: #installUniformWindowColors arguments: {} balloonText: 'Use white backgrounds for all standard windows' translated.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPBWindowColorPreferenceView class\\n\\tinstanceVariableNames: ''!\\n\\n!PBWindowColorPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 12/8/2004 18:40'!\\ninitialize\\n\\tself viewRegistry register: self.! !\\n\\n!PBWindowColorPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 12/8/2004 18:40'!\\nunload\\n\\tself viewRegistry unregister: self.! !\\n\\n!PBWindowColorPreferenceView class methodsFor: 'class initialization' stamp: 'hpt 12/8/2004 18:40'!\\nviewRegistry\\n\\t^(PreferenceViewRegistry registryOf: #windowColorPreferences)\\n\\t\\tviewOrder: 6;\\n\\t\\tyourself.! !\\nPrimCallControllerAbstract subclass: #PCCByCompilation\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tests-PrimCallController'!\\n!PCCByCompilation commentStamp: 'sr 6/16/2004 09:00' prior: 0!\\nThis class is for switching external prim calls (primitiveExternalCall) on and off.\\n\\nIt is best suited for permanently switching plugin calls off while preserving the possibility to switch them on later. For plugin testing purposes you probably should use PCCByLiterals for temporarily switch on/off them instead.\\n\\nIt works on a source code basis by compilation:\\n\\tDisabling works by putting an enabled prim call into a special comment followed by a recompile to transform it into a disabled one.\\n\\tEnabling works by pulling the disabled prim call out of the special comment followed by a recompile to transform it into an enabled one.\\n\\nAs a consequence, enabling of prims only works with method sources containing the mentioned special comment, which normally has been generated by this tool for disabling the corresponding prim.\\n\\nPlease look into superclass PrimCallControllerAbstract for more info and the user interface.\\n\\nStructure:\\n No instVars here: look into superclass.\\n\\nImplementation note:\\nTo harden it for sunit testing purposes some special accessing of the source code has been necessary: to avoid accessing different processes a sources file at once, followed by generating garbage, the process priority of actions leading to these accesses has been increased (sunit tests run in the background). A better solution would be to introduce a source file locking mechanism.!\\n]style[(107 11 138 13 5 11 62 14 3 9 124 8 245 9 36 9 26 28 26 93 20 384)f2FAccuny#12,f2FAccuny#12i,f2FAccuny#12,f2LPCCByLiterals Comment;,f2FAccuny#12,f2FAccuny#12i,f2FAccuny#12,f2FAccuny#12b,f2FAccuny#12,f2FAccuny#12i,f2FAccuny#12,f2FAccuny#12i,f2FAccuny#12,f2,f2FAccuny#12,f3FAccuny#12,f2FAccuny#12,f2,f2LPrimCallControllerAbstract Comment;,f2,FAccuny#15uf2,f2!\\n\\n\\n!PCCByCompilation methodsFor: 'string constants' stamp: 'sr 6/7/2004 03:30'!\\ncomment\\n\\t^ '{prim disabled by ', self className, '} '! !\\n\\n!PCCByCompilation methodsFor: 'string constants' stamp: 'sr 6/7/2004 03:31'!\\ndisabledPrimStartString\\n\\t^ '\\\"', self comment, self enabledPrimStartString! !\\n\\n!PCCByCompilation methodsFor: 'string constants' stamp: 'sr 6/7/2004 03:31'!\\ndisabledPrimStopChar\\n\\t\\\"end of disabling comment\\\"\\n\\t^ $\\\"! !\\n\\n!PCCByCompilation methodsFor: 'string constants' stamp: 'sr 6/7/2004 03:31'!\\nenabledPrimStartString\\n\\t^ '<primitive:'! !\\n\\n!PCCByCompilation methodsFor: 'string constants' stamp: 'sr 6/7/2004 03:31'!\\nenabledPrimStopChar\\n\\t^ $>! !\\n\\n\\n!PCCByCompilation methodsFor: 'ui querying' stamp: 'sr 6/11/2004 06:33'!\\nextractCallModuleNames: aMethodRef \\n\\t^ (self existsCompiledCallIn: aMethodRef)\\n\\t\\tifTrue: [self extractCallModuleNamesFromLiterals: aMethodRef]\\n\\t\\tifFalse: [| src | \\n\\t\\t\\t\\\"try source\\\"\\n\\t\\t\\t\\\"higher priority to avoid source file accessing errors\\\"\\n\\t\\t\\t[src := aMethodRef sourceString]\\n\\t\\t\\t\\tvalueAt: self higherPriority.\\n\\t\\t\\tself extractCallNamesFromPrimString: ((self extractDisabledPrimStringFrom: src)\\n\\t\\t\\t\\t\\tifNil: [\\\"no disabled prim string found\\\"\\n\\t\\t\\t\\t\\t\\t^ nil]) first]! !\\n\\n!PCCByCompilation methodsFor: 'ui querying' stamp: 'sr 6/14/2004 21:38'!\\nmethodsWithCall\\n\\t\\\"Expensive!! For just querying the system unaffected by an instance of \\n\\tthis class use PCCByLiterals instead.\\\"\\n\\t^ self methodsWithCompiledCall , self methodsWithDisabledCall! !\\n\\n!PCCByCompilation methodsFor: 'ui querying' stamp: 'md 8/27/2005 17:17'!\\nmethodsWithDisabledCall\\n\\t\\\"Answer a SortedCollection of all the methods that contain, in source \\n\\tcode, the substring indicating a disabled prim.\\\"\\n\\t\\\"The alternative implementation \\n\\t\\t^ SystemNavigation new allMethodsWithSourceString: self disabledPrimStartString\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tmatchCase: true \\n\\talso searches in class comments.\\\"\\n\\t| list classCount string |\\n\\tstring := self disabledPrimStartString.\\n\\tlist := Set new.\\n\\t'Searching all method source code...'\\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0\\n\\t\\tto: Smalltalk classNames size * 2 \\\"classes with their metaclasses\\\"\\n\\t\\tduring: [:bar |\\n\\t\\t\\tclassCount := 0.\\n\\t\\t\\tSystemNavigation default\\n\\t\\t\\t\\tallBehaviorsDo: [:class | \\n\\t\\t\\t\\t\\tbar value: (classCount := classCount + 1).\\n\\t\\t\\t\\t\\tclass\\n\\t\\t\\t\\t\\t\\tselectorsDo: [:sel | \\n\\t\\t\\t\\t\\t\\t\\t| src | \\n\\t\\t\\t\\t\\t\\t\\t\\\"higher priority to avoid source file accessing \\n\\t\\t\\t\\t\\t\\t\\terrors\\\"\\n\\t\\t\\t\\t\\t\\t\\t[src := class sourceCodeAt: sel]\\n\\t\\t\\t\\t\\t\\t\\t\\tvalueAt: self higherPriority.\\n\\t\\t\\t\\t\\t\\t\\t(src\\n\\t\\t\\t\\t\\t\\t\\t\\tfindString: string\\n\\t\\t\\t\\t\\t\\t\\t\\tstartingAt: 1\\n\\t\\t\\t\\t\\t\\t\\t\\tcaseSensitive: true) > 0\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [sel isDoIt ifFalse: [\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tlist add: (MethodReference new setStandardClass: class methodSymbol: sel)]]]]].\\n\\t^ list asSortedCollection! !\\n\\n\\n!PCCByCompilation methodsFor: 'ui testing' stamp: 'sr 6/11/2004 07:26'!\\nexistsCallIn: aMethodRef \\n\\t\\\"Here existsCompiledCallIn: (see also comment there) is sufficient to \\n\\tquery for enabled and failed, but not for disabled prim calls: so check \\n\\tfor disabled ones in sources, too.\\\"\\n\\t^ (self existsCompiledCallIn: aMethodRef)\\n\\t\\tor: [self existsDisabledCallIn: aMethodRef]! !\\n\\n!PCCByCompilation methodsFor: 'ui testing' stamp: 'sr 6/11/2004 07:07'!\\nexistsDisabledCallIn: aMethodRef \\n\\t| src |\\n\\t^ (self existsCompiledCallIn: aMethodRef) not\\n\\t\\tand: [\\\"higher priority to avoid source file accessing errors\\\"\\n\\t\\t\\t[src := aMethodRef sourceString]\\n\\t\\t\\t\\tvalueAt: self higherPriority.\\n\\t\\t\\tself methodSourceContainsDisabledCall: src]! !\\n\\n\\n!PCCByCompilation methodsFor: 'private' stamp: 'sr 6/7/2004 03:26'!\\ndisabled2EnabledPrimMethodString: aSourceString \\n\\t| start stop primString extract |\\n\\textract := self extractDisabledPrimStringFrom: aSourceString.\\n\\tprimString := extract at: 1.\\n\\tstart := extract at: 2.\\n\\tstop := start + primString size - 1.\\n\\t^ aSourceString\\n\\t\\tcopyReplaceFrom: start\\n\\t\\tto: stop\\n\\t\\twith: (self disabled2EnabledPrimString: primString)! !\\n\\n!PCCByCompilation methodsFor: 'private' stamp: 'sr 6/7/2004 03:26'!\\ndisabled2EnabledPrimString: aDisabledPrimString\\n\\t\\\"remove comment quotes and comment after first comment quote\\\"\\n\\t| enabledPrimString |\\n\\tenabledPrimString := aDisabledPrimString copyFrom: self comment size + 2 to: aDisabledPrimString size - 1.\\n\\t^ enabledPrimString! !\\n\\n!PCCByCompilation methodsFor: 'private' stamp: 'sr 6/7/2004 03:28'!\\nenabled2DisabledPrimMethodString: aSourceString \\n\\t| start stop primString extract |\\n\\textract := self extractEnabledPrimStringFrom: aSourceString.\\n\\tprimString := extract at: 1.\\n\\tstart := extract at: 2.\\n\\tstop := start + primString size - 1.\\n\\t^ aSourceString\\n\\t\\tcopyReplaceFrom: start\\n\\t\\tto: stop\\n\\t\\twith: (self enabled2DisabledPrimString: primString)! !\\n\\n!PCCByCompilation methodsFor: 'private' stamp: 'sr 6/7/2004 03:28'!\\nenabled2DisabledPrimString: anEnabledPrimString \\n\\t| disabledPrimString |\\n\\tdisabledPrimString := '\\\"' , self comment , anEnabledPrimString , '\\\"'.\\n\\t^ disabledPrimString! !\\n\\n!PCCByCompilation methodsFor: 'private' stamp: 'stephaneducasse 2/3/2006 22:39'!\\nextractCallNamesFromPrimString: aString\\n\\t\\\"method works for both enabled and disabled prim strings\\\"\\n\\t\\\"<primitive: 'doSomething' module:'ModuleFoo'\\\"\\n\\t| tokens |\\n\\ttokens := aString findTokens: ''''.\\n\\t^ (tokens at: 2) -> (tokens at: 4 ifAbsent: [nil])! !\\n\\n!PCCByCompilation methodsFor: 'private' stamp: 'sr 6/11/2004 07:10'!\\nextractDisabledPrimStringFrom: aSourceString \\n\\t| startString start stop |\\n\\tstartString := self disabledPrimStartString.\\n\\tstart := aSourceString findString: startString.\\n\\tstart = 0\\n\\t\\tifTrue: [^ nil].\\n\\tstop := aSourceString indexOf: self disabledPrimStopChar startingAt: start + startString size.\\n\\tstop = 0\\n\\t\\tifTrue: [^ nil].\\n\\t^ {aSourceString copyFrom: start to: stop. start}! !\\n\\n!PCCByCompilation methodsFor: 'private' stamp: 'sr 6/7/2004 03:29'!\\nextractEnabledPrimStringFrom: aSourceString \\n\\t| startString start stop |\\n\\tstartString := self enabledPrimStartString.\\n\\tstart := aSourceString findString: startString.\\n\\tstart = 0\\n\\t\\tifTrue: [^ nil].\\n\\tstop := aSourceString indexOf: self enabledPrimStopChar startingAt: start + startString size.\\n\\tstop = 0\\n\\t\\tifTrue: [^ nil].\\n\\t^ {aSourceString copyFrom: start to: stop. start}! !\\n\\n!PCCByCompilation methodsFor: 'private' stamp: 'sr 6/7/2004 03:29'!\\nhigherPriority\\n\\t\\\"this priority seems to be necessary to avoid source file accessing errors\\\"\\n\\t^ Processor userSchedulingPriority + 1! !\\n\\n!PCCByCompilation methodsFor: 'private' stamp: 'sr 6/11/2004 07:06'!\\nmethodSourceContainsDisabledCall: methodSource \\n\\t^ (methodSource findString: self disabledPrimStartString)\\n\\t\\t~= 0! !\\n\\n\\n!PCCByCompilation methodsFor: 'private user interface' stamp: 'sr 6/14/2004 01:37'!\\nprivateDisableCallIn: aMethodRef \\n\\t\\\"Disables enabled or failed external prim call by recompiling method \\n\\twith prim call commented out, will be called by superclass.\\\"\\n\\t| src newMethodSource |\\n\\t\\\"higher priority to avoid source file accessing errors\\\"\\n\\t[src := aMethodRef sourceString]\\n\\t\\tvalueAt: self higherPriority.\\n\\tnewMethodSource := self enabled2DisabledPrimMethodString: src.\\n\\t\\\"higher priority to avoid source file accessing errors\\\"\\n\\t[aMethodRef actualClass\\n\\t\\tcompile: newMethodSource\\n\\t\\tclassified: (aMethodRef actualClass whichCategoryIncludesSelector: aMethodRef methodSymbol)\\n\\t\\tnotifying: nil]\\n\\t\\tvalueAt: self higherPriority! !\\n\\n!PCCByCompilation methodsFor: 'private user interface' stamp: 'sr 6/14/2004 02:10'!\\nprivateEnableCallIn: aMethodRef \\n\\t\\\"Enables disabled external prim call by recompiling method with prim \\n\\tcall taken from disabling comment, will be called by superclass.\\\"\\n\\t| src newMethodSource |\\n\\t\\\"higher priority to avoid source file accessing errors\\\"\\n\\t[src := aMethodRef sourceString]\\n\\t\\tvalueAt: self higherPriority.\\n\\tnewMethodSource := self disabled2EnabledPrimMethodString: src.\\n\\t\\\"higher priority to avoid source file accessing errors\\\"\\n\\t[aMethodRef actualClass\\n\\t\\tcompile: newMethodSource\\n\\t\\tclassified: (aMethodRef actualClass whichCategoryIncludesSelector: aMethodRef methodSymbol)\\n\\t\\tnotifying: nil]\\n\\t\\tvalueAt: self higherPriority! !\\nPrimCallControllerAbstractTest subclass: #PCCByCompilationTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tests-PrimCallController'!\\n!PCCByCompilationTest commentStamp: 'sr 6/14/2004 22:05' prior: 0!\\nPCCByCompilation tests.\\n\\nTests are in the superclass and inherited from there.!\\n\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/11/2004 05:22'!\\nclassToBeTested\\n\\t^ PCCByCompilation! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/7/2004 10:36'!\\ndisabledCallSelectors\\n\\t^ #(#cDisabledRealExternalCall #cDisabledRealExternalCallNaked #cDisabledRealExternalCallOrPrimitiveFailed #cDisabledExternalCallWithoutModule )! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/7/2004 10:34'!\\nenabledCallSelectors\\n\\t^ #(#cRealExternalCall #cRealExternalCallNaked #cRealExternalCallOrPrimitiveFailed #cExternalCallWithoutModule )! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/7/2004 08:44'!\\nexampleModuleName\\n\\t^ 'CPCCT'! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/15/2004 02:42'!\\nfailModuleName\\n\\t^ 'CFailModule'! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/14/2004 00:14'!\\nfailedCallSelector\\n\\t^ #cFailedCall! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/7/2004 08:40'!\\nmethodSelectorsToExampleModule\\n\\t^ #(#cExternalCall1 #cExternalCall2 )! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/7/2004 08:47'!\\nmoduleNameNotWithSingularCallName\\n\\t^ 'CNotOne'! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/7/2004 08:47'!\\nmoduleNameWithSingularCallName\\n\\t^ 'COne'! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/7/2004 09:52'!\\nnoExternalCallSelector\\n\\t^ #cNoExternalCall! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/7/2004 10:28'!\\nrealExternalCallOrPrimitiveFailedSelector\\n\\t^ #cRealExternalCallOrPrimitiveFailed! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/7/2004 10:54'!\\nsingularCallName\\n\\t\\\"occurrs exactly once as prim call name in >>cSingularExternalCall\\\"\\n\\t^ 'cSingularExternalCall'! !\\n\\n!PCCByCompilationTest methodsFor: 'constants' stamp: 'sr 6/14/2004 23:33'!\\nsingularCallSelector\\n\\t^ #cSingularExternalCall! !\\n\\n\\n!PCCByCompilationTest methodsFor: 'example module' stamp: 'md 9/6/2005 19:39'!\\ncExternalCall1\\n\\t<primitive: 'prim1' module: 'CPCCT'>\\n! !\\n\\n!PCCByCompilationTest methodsFor: 'example module' stamp: 'md 9/6/2005 19:39'!\\ncExternalCall2\\n\\t\\t<primitive:'prim2'module:'CPCCT'>\\n\\t\\tself primitiveFailed! !\\n\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'sr 6/11/2004 05:36'!\\ncDisabledExternalCallWithoutModule\\n\\t\\\"{prim disabled by PCCByCompilation} <primitive: 'primGetModuleName'>\\\"\\n\\t^ 'Hello World!!'! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 23:54'!\\ncDisabledRealExternalCall\\n\\t\\\"{prim disabled by PCCByCompilation} <primitive: 'primGetModuleName' module:'LargeIntegers'>\\\"\\n\\t^ 'Hello World!!'! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 23:54'!\\ncDisabledRealExternalCallNaked\\n\\t\\\"{prim disabled by PCCByCompilation} <primitive: 'primGetModuleName' module:'LargeIntegers'>\\\"! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 23:54'!\\ncDisabledRealExternalCallOrPrimitiveFailed\\n\\t\\\"{prim disabled by PCCByCompilation} <primitive: 'primGetModuleName' module:'LargeIntegers'>\\\"\\n\\tself primitiveFailed! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'sr 6/7/2004 09:48'!\\ncExternalCallWithoutModule\\n\\t<primitive: 'primGetModuleName'>\\n\\t^ 'Hello World!!'! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'md 9/6/2005 19:39'!\\ncFailedCall\\n\\t<primitive: 'primGetModuleName' module:'CFailModule'>\\n\\t^ 'failed call'! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'sr 6/7/2004 09:48'!\\ncNoExternalCall\\n\\t^ 'Hello World!!'! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 21:14'!\\ncRealExternalCall\\n\\t<primitive: 'primGetModuleName' module:'LargeIntegers'>\\n\\t^ 'Hello World!!'! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 21:14'!\\ncRealExternalCallNaked\\n\\t<primitive: 'primGetModuleName' module:'LargeIntegers'>! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'md 9/6/2005 19:39'!\\ncRealExternalCallOrPrimitiveFailed\\n\\t<primitive: 'primGetModuleName' module:'LargeIntegers'>\\n\\tself primitiveFailed! !\\n\\n!PCCByCompilationTest methodsFor: 'test methods' stamp: 'sr 6/15/2004 04:35'!\\ncSingularExternalCall\\n\\t<primitive: 'cSingularExternalCall' module:'COne'>\\n\\t^ 'Hello World!!'! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPCCByCompilationTest class\\n\\tinstanceVariableNames: ''!\\n\\n!PCCByCompilationTest class methodsFor: 'Testing' stamp: 'sr 6/7/2004 12:01'!\\nisAbstract\\n\\t^ false! !\\nPrimCallControllerAbstract subclass: #PCCByLiterals\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tests-PrimCallController'!\\n!PCCByLiterals commentStamp: 'sr 6/16/2004 09:14' prior: 0!\\nThis class is for switching external prim calls (primitiveExternalCall) on and off.\\n\\nIt is best suited for plugin testing purposes with temporarily switching plugin calls off and on. For permanently switching plugin calls off while preserving the possibility to switch them on later, you should use PCCByCompilation instead.\\n\\nIt works by manipulating literals in the CompiledMethods:\\n\\tDisabling works by changing the function index in the first literal of the CompiledMethod to a negative value (-2). This leads to a fast fail (value -2 is used for disabling to make a difference to the standard failed value of -1).\\n\\tEnabling works by changing the function index in the first literal of the CompiledMethod to 0, followed by flushing the method cache. This enforces a fresh lookup.\\n\\nPlease look into superclass PrimCallControllerAbstract for more info and the user interface.\\n\\nStructure:\\n No instVars here: look into superclass.!\\n]style[(136 11 40 11 101 16 10 1 9 2 14 8 26 9 224 8 157 28 26 91)f2FAccuny#12,f2FAccuny#12i,f2FAccuny#12,f2FAccuny#12i,f2FAccuny#12,f2LPCCByCompilation Comment;,f2FAccuny#12,f2,f2FAccuny#12,f2FAccuny#12b,f2FAccuny#12,f2FAccuny#12b,f2FAccuny#12,f2FAccuny#12i,f2FAccuny#12,f2FAccuny#12i,f2FAccuny#12,f2,f2LPrimCallControllerAbstract Comment;,f2!\\n\\n\\n!PCCByLiterals methodsFor: 'ui querying' stamp: 'sr 6/11/2004 07:04'!\\nextractCallModuleNames: aMethodRef \\n\\t^ (self existsCallIn: aMethodRef)\\n\\t\\tifTrue: [self extractCallModuleNamesFromLiterals: aMethodRef]! !\\n\\n!PCCByLiterals methodsFor: 'ui querying' stamp: 'sr 6/11/2004 07:05'!\\nmethodsWithCall\\n\\t^ self methodsWithCompiledCall! !\\n\\n!PCCByLiterals methodsFor: 'ui querying' stamp: 'sr 6/14/2004 21:24'!\\nmethodsWithDisabledCall\\n\\t^ self methodsWithCompiledCall\\n\\t\\tselect: [:mRef | (mRef compiledMethod literals first at: 4)\\n\\t\\t\\t\\t= -2]! !\\n\\n\\n!PCCByLiterals methodsFor: 'ui testing' stamp: 'sr 6/11/2004 07:04'!\\nexistsCallIn: aMethodRef \\n\\t\\\"Here >>existsCompiledCallIn: (see also comment there) is sufficient to \\n\\tquery for all enabled, failed and disabled prim calls; for the by \\n\\tcompiler version it is not sufficient for disabled ones.\\\"\\n\\t^ self existsCompiledCallIn: aMethodRef! !\\n\\n!PCCByLiterals methodsFor: 'ui testing' stamp: 'sr 6/11/2004 07:30'!\\nexistsDisabledCallIn: aMethodRef \\n\\t^ (self existsCompiledCallIn: aMethodRef)\\n\\t\\tand: [(aMethodRef compiledMethod literals first at: 4)\\n\\t\\t\\t\\t= -2]! !\\n\\n\\n!PCCByLiterals methodsFor: 'private user interface' stamp: 'sr 6/14/2004 01:35'!\\nprivateDisableCallIn: aMethodRef \\n\\t\\\"Disables enabled or failed external prim call by filling function ref \\n\\tliteral with special fail value, will be called by superclass.\\\"\\n\\taMethodRef compiledMethod literals first at: 4 put: -2! !\\n\\n!PCCByLiterals methodsFor: 'private user interface' stamp: 'sr 6/14/2004 02:07'!\\nprivateEnableCallIn: aMethodRef\\n\\t\\\"Enables disabled external prim call.\\\"\\n\\tself privateEnableViaLiteralIn: aMethodRef! !\\nPrimCallControllerAbstractTest subclass: #PCCByLiteralsTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tests-PrimCallController'!\\n!PCCByLiteralsTest commentStamp: 'sr 6/14/2004 22:05' prior: 0!\\nPCCByLiterals tests.\\n\\nTests are in the superclass and inherited from there.!\\n\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/11/2004 05:23'!\\nclassToBeTested\\n\\t^ PCCByLiterals! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/7/2004 10:37'!\\ndisabledCallSelectors\\n\\t^ #(#lDisabledRealExternalCall #lDisabledRealExternalCallNaked #lDisabledRealExternalCallOrPrimitiveFailed #lDisabledExternalCallWithoutModule )! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/7/2004 10:34'!\\nenabledCallSelectors\\n\\t^ #(#lRealExternalCall #lRealExternalCallNaked #lRealExternalCallOrPrimitiveFailed #lExternalCallWithoutModule )! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/7/2004 08:45'!\\nexampleModuleName\\n\\t^ 'LPCCT'! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/15/2004 02:42'!\\nfailModuleName\\n\\t^ 'LFailModule'! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/14/2004 00:12'!\\nfailedCallSelector\\n\\t^ #lFailedCall! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/7/2004 08:41'!\\nmethodSelectorsToExampleModule\\n\\t^ #(#lExternalCall1 #lExternalCall2 )! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/7/2004 08:47'!\\nmoduleNameNotWithSingularCallName\\n\\t^ 'LNotOne'! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/7/2004 08:47'!\\nmoduleNameWithSingularCallName\\n\\t^ 'LOne'! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/7/2004 10:16'!\\nnoExternalCallSelector\\n\\t^ #lNoExternalCall! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/7/2004 10:29'!\\nrealExternalCallOrPrimitiveFailedSelector\\n\\t^ #lRealExternalCallOrPrimitiveFailed! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/7/2004 10:54'!\\nsingularCallName\\n\\t\\\"occurrs exactly once as prim call name in >>lSingularExternalCall\\\"\\n\\t^ 'lSingularExternalCall'! !\\n\\n!PCCByLiteralsTest methodsFor: 'constants' stamp: 'sr 6/14/2004 23:32'!\\nsingularCallSelector\\n\\t^ #lSingularExternalCall! !\\n\\n\\n!PCCByLiteralsTest methodsFor: 'example module' stamp: 'sr 6/7/2004 08:39'!\\nlExternalCall1\\n\\t<primitive: 'prim1' module: 'LPCCT'>\\n! !\\n\\n!PCCByLiteralsTest methodsFor: 'example module' stamp: 'sr 6/7/2004 08:39'!\\nlExternalCall2\\n\\t\\t<primitive:'prim2'module:'LPCCT'>\\n\\t\\tself primitiveFailed! !\\n\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/7/2004 08:51'!\\nlDisabledExternalCallWithoutModule\\n\\t<primitive: 'primGetModuleName'>\\n\\t^ 'Hello World!!'! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 21:14'!\\nlDisabledRealExternalCall\\n\\t<primitive: 'primGetModuleName' module:'LargeIntegers'>\\n\\t^ 'Hello World!!'! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 21:14'!\\nlDisabledRealExternalCallNaked\\n\\t<primitive: 'primGetModuleName' module:'LargeIntegers'>! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 21:14'!\\nlDisabledRealExternalCallOrPrimitiveFailed\\n\\t<primitive: 'primGetModuleName' module:'LargeIntegers'> \\\"primitiveExternalCall\\\" \\n\\tself primitiveFailed! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/7/2004 09:59'!\\nlExternalCallWithoutModule\\n\\t<primitive: 'primGetModuleName'> \\\"primitiveExternalCall\\\" \\n\\t^ 'Hello World!!'! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/15/2004 02:41'!\\nlFailedCall\\n\\t<primitive: 'primGetModuleName' module:'LFailModule'>\\n\\t^ 'failed call'! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/7/2004 09:57'!\\nlNoExternalCall\\n\\t^ 'Hello World!!'! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 21:14'!\\nlRealExternalCall\\n\\t<primitive: 'primGetModuleName' module:'LargeIntegers'>\\n\\t^ 'Hello World!!'! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 21:14'!\\nlRealExternalCallNaked\\n\\t<primitive: 'primGetModuleName' module:'LargeIntegers'>! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/13/2004 21:14'!\\nlRealExternalCallOrPrimitiveFailed\\n\\t<primitive: 'primGetModuleName' module:'LargeIntegers'>\\n\\tself primitiveFailed! !\\n\\n!PCCByLiteralsTest methodsFor: 'test methods' stamp: 'sr 6/7/2004 10:52'!\\nlSingularExternalCall\\n\\t<primitive: 'lSingularExternalCall' module:'LOne'>\\n\\t^ 'Hello World!!'! !\\n\\n\\n!PCCByLiteralsTest methodsFor: 'tests' stamp: 'sr 6/7/2004 11:30'!\\nsetUp\\n\\tsuper setUp.\\n\\t\\\"disable external calls\\\"\\n\\t(self class selectors\\n\\t\\tselect: [:sel | sel beginsWith: 'lDisabled'])\\n\\t\\tdo: [:sel | (self class >> sel) literals first at: 4 put: -2]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPCCByLiteralsTest class\\n\\tinstanceVariableNames: ''!\\n\\n!PCCByLiteralsTest class methodsFor: 'Testing' stamp: 'sr 6/7/2004 12:01'!\\nisAbstract\\n\\t^ false! !\\nImageReadWriter subclass: #PCXReadWriter\\n\\tinstanceVariableNames: 'version encoding colorPlanes isGrayScale width height bitsPerPixel colorPalette rowByteSize'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Graphics-Files'!\\n\\n!PCXReadWriter methodsFor: 'accessing' stamp: 'tao 10/6/97 10:11'!\\nnextImage\\n\\t\\\"Read in the next PCX image from the stream.\\\"\\n\\n\\t| bytes form |\\n\\tself readHeader.\\n\\tbytes _ self readBody.\\n\\tcolorPalette _ self readPalette.\\n\\tself close.\\n\\tform _ ColorForm extent: width@height depth: bitsPerPixel.\\n\\t(Form new hackBits: bytes) displayOn: (Form new hackBits: form bits).\\n\\tform colors: colorPalette.\\n\\t^ form\\n! !\\n\\n\\n!PCXReadWriter methodsFor: 'private-decoding' stamp: 'tao 10/6/97 08:38'!\\nnextWord\\n\\t^self next + (self next bitShift: 8)! !\\n\\n!PCXReadWriter methodsFor: 'private-decoding' stamp: 'tao 10/6/97 10:07'!\\nreadBody\\n\\n\\t| array scanLine rowBytes position byte count pad |\\n\\tpad _ #(0 3 2 1) at: (width \\\\\\\\ 4 + 1).\\n\\tarray _ ByteArray new: ((width + pad) * height * bitsPerPixel) // 8.\\n\\tscanLine _ ByteArray new: rowByteSize.\\n\\tposition _ 1.\\n\\t1 to: height do:\\n\\t\\t[:line |\\n\\t\\trowBytes _ 0.\\n\\t\\t[rowBytes < rowByteSize] whileTrue:\\n\\t\\t\\t[byte _ self next.\\n\\t\\t\\tbyte < 16rC0\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[rowBytes _ rowBytes + 1.\\n\\t\\t\\t\\t\\tscanLine at: rowBytes put: byte]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[count _ byte - 16rC0.\\n\\t\\t\\t\\t\\tbyte _ self next.\\n\\t\\t\\t\\t\\t1 to: count do: [:i | scanLine at: rowBytes + i put: byte].\\n\\t\\t\\t\\t\\trowBytes _ rowBytes + count]].\\n\\t\\tarray\\n\\t\\t\\treplaceFrom: position\\n\\t\\t\\tto: position + width - 1\\n\\t\\t\\twith: scanLine\\n\\t\\t\\tstartingAt: 1.\\n\\t\\tposition _ position + width + pad].\\n\\t^ array\\n! !\\n\\n!PCXReadWriter methodsFor: 'private-decoding' stamp: 'md 11/14/2003 16:51'!\\nreadHeader\\n\\n\\t| xMin xMax yMin yMax |\\n\\tself next.\\t\\\"skip over manufacturer field\\\"\\n\\tversion _ self next.\\n\\tencoding _ self next.\\n\\tbitsPerPixel _ self next.\\n\\txMin _ self nextWord.\\n\\tyMin _ self nextWord.\\n\\txMax _ self nextWord.\\n\\tyMax _ self nextWord.\\n\\twidth _ xMax - xMin + 1.\\n\\theight _ yMax - yMin + 1.\\n\\tself next: 4. \\\"skip over device resolution\\\"\\n\\tself next: 49. \\\"skip over EGA color palette\\\"\\n\\tcolorPlanes _ self next.\\n\\trowByteSize _ self nextWord.\\n\\tisGrayScale _ (self next: 2) = 2.\\n\\tself next: 58. \\\"skip over filler\\\"\\n\\n\\n\\n! !\\n\\n!PCXReadWriter methodsFor: 'private-decoding' stamp: 'tao 10/6/97 08:29'!\\nreadPalette\\n\\n\\t| r g b array |\\n\\tself next = 12 ifFalse: [self error: 'no Color Palette!!'].\\n\\tarray _ Array new: (1 bitShift: bitsPerPixel).\\n\\t1 to: array size do:\\n\\t\\t[:i |\\n\\t\\tr _ self next. g _ self next. b _ self next.\\n\\t\\tarray at: i put: (Color r: r g: g b: b range: 255)].\\n\\t^ array.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPCXReadWriter class\\n\\tinstanceVariableNames: ''!\\n\\n!PCXReadWriter class methodsFor: 'image reading/writing' stamp: 'nk 7/16/2003 17:57'!\\ntypicalFileExtensions\\n\\t\\\"Answer a collection of file extensions (lowercase) which files that I can read might commonly have\\\"\\n\\t^#('pcx')! !\\nObject subclass: #PHOReader\\n\\tinstanceVariableNames: 'stream phonemes events pitches time'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Speech-Support'!\\n!PHOReader commentStamp: '<historical>' prior: 0!\\nMy instances read PHO files with lines of the form 'phoneme duration time0 pitch0 time1 pitch1 ...'. Time is in milliseconds, and pitch is in hertz. Files on this format are used as inputs for the MBROLA synthesizer, and there are lots of them available on the web. Here's an example:\\n\\n_ 120 0 105\\nm 60 33 105\\nE 70 42 102\\nr 50 20 108\\nI 50 20 125 100 142\\nk 100\\nr 50 80 137\\nI 50 80 121\\ns 70\\nm 50\\n@ 90 33 111 88 108\\ns 90\\n!\\n\\n\\n!PHOReader methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:22'!\\naddPitches\\n\\t| offset |\\n\\toffset := 0.0.\\n\\tevents do: [ :each |\\n\\t\\teach pitchPoints: (self pitchesBetween: offset and: offset + each duration).\\n\\t\\toffset := offset + each duration].! !\\n\\n!PHOReader methodsFor: 'accessing' stamp: 'len 8/29/1999 02:16'!\\nevents\\n\\t^ CompositeEvent new addAll: events; yourself! !\\n\\n!PHOReader methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:22'!\\nnextEvent\\n\\t| line phonemeName phoneme duration answer ptime pitch |\\n\\tline := ReadStream on: stream nextLine.\\n\\tphonemeName := line upTo: Character space.\\n\\tphoneme := phonemes at: phonemeName.\\n\\t[line peek isSeparator] whileTrue: [line next].\\n\\tduration := (line upTo: Character space) asNumber / 1000.0.\\n\\tanswer := PhoneticEvent new phoneme: phoneme; duration: duration; loudness: 1.0.\\n\\t[line atEnd]\\n\\t\\twhileFalse: [ptime := (line upTo: Character space) asNumber * duration / 100.0.\\n\\t\\t\\t\\t\\tpitch := (line upTo: Character space) asNumber asFloat.\\n\\t\\t\\t\\t\\tpitches add: time + ptime @ pitch].\\n\\ttime := time + duration.\\n\\t^ answer! !\\n\\n!PHOReader methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:22'!\\npitchAt: t\\n\\t\\\"Answer the pitch of the receiver at a given time. (Do linear interpolation.)\\\"\\n\\t| xVal count x1 x2 y1 y2 |\\n\\txVal := pitches first x.\\n\\tcount := 1.\\n\\t[xVal < t]\\n\\t\\twhileTrue: [count := count + 1.\\n\\t\\t\\t\\t\\tcount > pitches size ifTrue: [^ pitches last y].\\n\\t\\t\\t\\t\\txVal := (pitches at: count) x].\\n\\txVal = t ifTrue: [^ (pitches at: count) y].\\n\\tcount = 1 ifTrue: [^ pitches first y].\\n\\tx1 := (pitches at: count - 1) x.\\n\\tx2 := (pitches at: count) x.\\n\\ty1 := (pitches at: count - 1) y.\\n\\ty2 := (pitches at: count) y.\\n\\t^ (t - x1) / (x2 - x1) * (y2 - y1) + y1! !\\n\\n!PHOReader methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:22'!\\npitchesBetween: t1 and: t2\\n\\t| step |\\n\\tstep := (t2 - t1 / 0.035) asInteger + 1. \\\"step small enough\\\"\\n\\t^ (t1 to: t2 by: t2 - t1 / step) collect: [ :each | each - t1 @ (self pitchAt: each)]! !\\n\\n!PHOReader methodsFor: 'accessing' stamp: 'len 6/17/1999 01:45'!\\nplotPitch\\n\\tUtilities plot: ((0 to: time by: 0.050) collect: [ :each | self pitchAt: each])! !\\n\\n!PHOReader methodsFor: 'accessing' stamp: 'len 6/15/1999 00:40'!\\nread\\n\\tstream reset.\\n\\t[stream atEnd] whileFalse: [events add: self nextEvent].\\n\\tself addPitches! !\\n\\n!PHOReader methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:22'!\\nstream: aStream\\n\\tstream := aStream! !\\n\\n\\n!PHOReader methodsFor: 'initialization' stamp: 'stephaneducasse 2/3/2006 22:22'!\\ninitialize\\n\\tevents := OrderedCollection new.\\n\\tpitches := OrderedCollection new.\\n\\ttime := 0.0.\\n\\tphonemes := PhonemeSet sampaToArpabet! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPHOReader class\\n\\tinstanceVariableNames: ''!\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'stephaneducasse 2/3/2006 22:23'!\\naliceExample\\n\\t| events |\\n\\tevents := self eventsFromString: self aliceExampleString.\\n\\tevents do: [ :each | each pitchBy: 0.63489].\\n\\t^ events! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'stephaneducasse 2/3/2006 22:23'!\\naliceExampleFemale\\n\\t| events |\\n\\tevents := self eventsFromString: self aliceExampleString.\\n\\tevents do: [ :each | each pitchBy: 1.3].\\n\\t^ events! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'stephaneducasse 2/3/2006 22:23'!\\naliceExampleMale\\n\\t| events |\\n\\tevents := self eventsFromString: self aliceExampleString.\\n\\tevents do: [ :each | each pitchBy: 0.63489].\\n\\t^ events! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'stephaneducasse 2/3/2006 22:23'!\\naliceShortExample\\n\\t| events |\\n\\tevents := self eventsFromString: self aliceShortExampleString.\\n\\tevents do: [ :each | each pitchBy: 1.3].\\n\\t^ events! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'stephaneducasse 2/3/2006 22:23'!\\naliceShortExampleMale\\n\\t| events |\\n\\tevents := self eventsFromString: self aliceShortExampleString.\\n\\tevents do: [ :each | each pitchBy: 0.4].\\n\\t^ events! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'len 7/27/1999 01:47'!\\nmbrolaExample\\n\\t^ self eventsFromString:\\n'_ 50\\nE 40 0 102\\nm 50\\nb 50\\nr 30\\n@U 80 5 119 35 126 70 140\\nl 50\\n@ 50 50 173\\nw 100 75 133\\nV 30 85 114\\nz 60 75 101\\nd 60\\n@ 40\\nv 40 85 105\\nE 60 75 121\\nl 50 70 121\\n@ 60 60 150\\np 50\\nd 70\\nb 70 0 90\\nAI 130 85 101\\nT 70\\nj 50 0 180\\nE 120 0 185 95 131\\nr 40\\ni 90 85 135\\nd 80 60 134\\n@ 50 0 119 50 114\\nt 70\\nw 70 10 117 65 127 85 115\\nA 180 0 102 55 91 95 85\\n_ 100\\n_ 100\\nI 80 18 111\\nt 80\\ns 50\\n@ 30\\ns 70\\np 80\\ni 80 25 171 85 200\\ntS 110\\ns 70\\nI 30 35 112\\nn 40\\nT 80\\n@ 40 85 108\\ns 80\\nAI 130 80 115\\nz 70 90 125\\nr= 120 75 111\\nb 80\\nEI 80 95 133\\nz 70\\nd 50\\nA 40\\nn 30\\nD 60\\n@ 30 65 121\\nk 90\\nA 30\\nn 30 100 140\\nk 80\\n{ 70 5 170\\nt 70\\n@ 40 50 186\\nn 40 75 163\\nEI 100 90 173\\nS 130\\n@ 40\\nn 30 65 153\\nV 40\\nv 70 0 148\\nd 60\\nAI 130 5 112 80 109\\nf 110\\n@U 160 87 88\\nn 70\\nz 210 88 82\\n_ 80\\n_ 100\\nI 40 0 140\\nt 50\\nt 100\\nEI 60 50 221\\nk 70\\ns 80\\n@ 30 0 190\\nl 50\\nI 30 65 180\\ns 110\\nt 70\\nV 50 20 171\\nv 50\\nf 90\\n@U 140 25 157\\nn 30\\ni 60 66 160\\nm 50 60 130\\nz 80\\n@ 40 62 78\\nz 80\\nI 70 78 134\\nn 50 70 163\\np 120\\nU 90 15 119 75 98\\nt 90\\n_ 140\\n_ 100\\nt 60 0 111\\nu 50 80 119\\ng 70\\nE 50 90 145\\nD 50\\nr= 50 40 139 90 163\\nw 90\\nI 30 15 114\\nD 50\\n_ 40\\np 50\\nr 30 0 102\\n@ 30 65 110\\ns 120\\nA 50 90 148\\nd 80\\nI 50 50 178\\nk 80\\nI 50 66 167\\nn 60\\nf 50\\nr= 50 90 125\\nm 50\\nEI 140 95 96\\nS 140\\n@ 80 35 168\\nn 100 95 142\\n_ 190\\n{ 90 0 133\\nn 30\\nd 30\\np 80\\nr 40\\n@ 40 0 97 65 103\\nd 70\\nj 20\\nu 60 65 150\\ns 90\\nI 30 50 210\\nz 50\\ns 140\\np 70\\ni 130 0 138 95 98\\ntS 160\\n{ 70 0 127\\nt 50\\nD 50\\n@ 30 15 93\\ns 140\\n{ 30 35 127\\nm 50\\np 70\\nl 50\\nI 30 35 184\\nN 70\\nf 70\\nr 60\\ni 90 30 125\\nk 40\\nw 30\\n@ 30 15 185\\nn 30\\ns 100\\ni 50 20 148 70 142\\nV 30 5 148\\nv 40\\nD 80\\n@ 40 25 106\\nd 80\\nAI 150 95 115\\nf 90\\n@U 130 95 114\\nn 70\\nd 80\\nEI 80 80 137\\n4 50\\n@ 30\\nb 100\\nEI 120 95 78\\ns 210\\n_ 80'! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'len 7/27/1999 01:48'!\\npushExample\\n\\t^ self eventsFromString:\\n'_ 60 0 137\\np 50 100 137\\nu 110 90 137\\nS 100 10 121\\nD 90\\n@ 70 57 114 100 102\\ns 70\\nt 50\\nA 100 57 121 64 121\\nr 40\\nt 50\\nb 110\\nV 140 21 117 57 100 92 100\\n_ 3\\nn 130 25 102 50 105\\nt 60\\nu 70 28 129 71 111\\nb 70\\ni 70 50 102\\ng 20 10 100 80 102\\ni 130 25 117 66 114\\nn 260 3 111 23 105 42 97 61 93 73 93\\n_ 140 92 93 100 100'! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'stephaneducasse 2/3/2006 22:23'!\\npushExampleFemale\\n\\t| events |\\n\\tevents := self pushExample.\\n\\tevents do: [ :each | each pitchBy: 1.93489].\\n\\t^ events! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'stephaneducasse 2/3/2006 22:23'!\\npushShortExample\\n\\t^ self eventsFromString:\\n'i 70 50 102\\ng 20 10 100 80 102\\ni 130 25 117 66 114\\nn 260 3 111 23 105 42 97 61 93 73 93'.\\n\\\"\\n':= 3\\nn 130 25 102 50 105\\nt 60\\nu 70 28 129 71 111\\nb 70\\ni 70 50 102\\ng 20 10 100 80 102\\ni 130 25 117 66 114\\nn 260 3 111 23 105 42 97 61 93 73 93\\n:= 140 92 93 100 100'\\\"! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'len 7/27/1999 01:48'!\\nxmasExample\\n\\t^ self eventsFromString:\\n'_ 120 0 105\\nm 60 33 105\\nE 70 42 102\\nr 50 20 108\\nI 50 20 125 100 142\\nk 100\\nr 50 80 137\\nI 50 80 121\\ns 70\\nm 50\\n@ 90 33 111 88 108\\ns 90\\n{ 70\\nn 100 50 105 100 97\\nd 50 80 93\\nh 50 20 93\\n{ 50 20 102 60 114\\np 50\\ni 50 100 125\\nn 60 83 121\\nu 100\\nj 130 7 121 23 121 100 108\\nr= 250 41 102 83 97\\n_ 210 95 86 100 100'\\n! !\\n\\n!PHOReader class methodsFor: 'examples' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nxmasKidExample\\n\\t| events |\\n\\tevents := self xmasExample.\\n\\tevents do: [ :each | each pitchBy: 1.6].\\n\\t^ events! !\\n\\n\\n!PHOReader class methodsFor: 'examples-private' stamp: 'len 7/27/1999 01:45'!\\naliceExampleString\\n\\t^ '_ 48 0 222\\n{ 80 40 222 90 235\\nl 72 44 250 66 250\\nI 80\\ns 88\\nw 40 80 235\\n@ 40 80 210\\nz 64 12 210 50 181 75 181\\nb 72 33 173 88 181\\nI 56 71 181\\ng 56 28 153 100 166\\nI 64 62 160\\nn 40 60 160\\nI 88 27 166\\nN 40 100 166\\nt 80 20 160\\nU 40 40 181 80 166\\ng 48 100 166\\nE 104 38 153 76 137\\nt 56\\nv 48\\nE 72 11 166 66 153\\nr 88 18 160 63 166\\ni 112.8 14 166 49 173 77 173\\nt 104.8 98 137\\nAI 178.4 21 148 70 148 92 137\\nr= 108 25 137 62 133 98 129\\nd 49\\n@ 59.2 6 137 73 133\\nv 46\\ns 89\\nI 40 40 173\\nt 40 40 166\\nI 64 62 166\\nN 72 22 160 77 153\\nb 40 40 142 100 153\\nAI 136 29 142\\nh 80 30 142 100 148\\nr= 64 62 153 100 153\\ns 125\\nI 64 37 210 100 190\\ns 72 11 190\\nt 72\\nr= 104 30 160 69 142\\nO 72\\nn 40 40 142\\nD 40 40 153\\n@ 40 40 160\\nb 40 40 153 100 160\\n{ 216 18 166 51 166 70 153 88 137 100 133\\nn 40\\nk 56\\n_ 144 94 129 100 100\\n_ 100 0 137\\n{ 40\\nn 88 9 137 36 137 72 142\\nt 40 40 137 60 133\\n@ 48 16 148 100 148\\nh 40 100 142\\n{ 48 83 148\\nv 48 16 142\\nI 56 14 148 85 137\\nN 56 71 137\\nn 64 37 137 100 142\\nO 96 41 137 83 153 100 153\\nT 64\\nI 56 42 166\\nN 64 12 160 75 153\\nt 80 30 142\\n@ 56 28 166 100 148\\nd 56 71 137\\nu 160 15 160 45 160 70 153 95 142\\nw 136 23 137 58 137 88 148\\nA 112 21 153 57 160 92 173\\nn 64 50 166 62 153\\ns 56\\nO 48 50 153\\nr 40 40 142 100 133\\nt 130\\nw 56 57 166\\nAI 168 9 173 33 166 57 153 80 148 100 148\\ns 88\\n_ 300\\nS 92\\ni 48 50 235\\nh 40 40 235 100 250\\n@ 40 60 210 100 210\\nd 40\\np 40\\ni 150\\nk 56\\nd 56\\nI 72 44 222 100 210\\nn 40 80 210\\nt 56\\n@ 48 83 181\\nD 40 39 173 99 173\\n@ 39.2 100 160\\nb 104 30 153 100 153\\nU 112 35 153 85 153 100 153\\nk 72\\nh 56\\nr= 48 50 200\\ns 136 5 181\\nI 64 25 166 87 142\\ns 56 14 137\\nt 56\\nr= 56 28 173 100 173\\nw 56 71 166\\n@ 56 42 181\\nz 48 16 181 50 173\\nr 120 73 181\\ni 104 7 190 69 190 100 181\\nd 40\\nI 112 7 166 50 137 85 129\\nN 80 30 114 50 111\\n_ 56 83 111 100 100\\n_ 140 0 153\\nb 40 60 153 100 153\\nU 64 75 148\\n4 40 80 148 100 142\\nI 40\\nt 40 40 148\\nh 40 40 142\\n{ 48 33 137\\nd 136 5 133 11 129 88 148\\nn 48 66 148\\n@U 144 16 160 44 173 72 190 100 210\\np 80\\nI 96 75 190 100 181\\nk 56\\ntS 96\\nr= 104 30 190 69 181\\nz 72 11 181 33 173\\nO 40 60 173\\nr 64 37 160 100 153\\nk 72 11 153\\nO 152 63 190 89 200\\nn 40 60 181\\nv 40 60 166\\nr= 40 60 160\\ns 104 15 142\\nEI 120 20 190 53 190 86 210\\nS 104 7 210\\n@ 56 28 181 100 160\\nn 64 62 153 100 137\\nz 40\\nI 56 14 148 85 133\\nn 40 100 133\\nI 96 41 129 83 125\\nt 80\\n_ 64 85 125 100 100\\n_ 140 0 222\\n{ 56 14 222 28 220 42 235 85 235 100 220\\nn 96 33 222 75 235 100 235\\nw 48 33 222 66 250\\nO 90\\n4 48 50 222 66 252\\nI 48 33 250\\nz 64 12 235 62 210\\nD 56\\n@ 56 71 190\\nj 104 23 166 61 166 100 181\\nu 112 35 190 42 210 71 210 100 210\\ns 150\\n@ 56 42 200\\nv 40 20 160 60 148\\n@ 64 25 153 87 142\\nb 136 23 133 47 137\\nU 96 8 160 50 173 91 181 100 181\\nk 56\\n_ 56\\nT 56\\nO 119.2 20 166 53 142 80 137\\n4 40 20 133\\n{ 136 5 137 35 129 64 125\\nl 48 16 125 100 133\\nI 80 50 153 100 181\\ns 120\\n_ 40\\n_ 40\\nw 88 9 166 54 142\\nI 40 40 142\\nD 40 40 137\\naU 62.4 38 137 63 133\\nt 80\\np 55\\nI 72 16 210 38 210\\nk 40\\ntS 75.2 99 173\\nr= 136 29 160 64 160 76 166\\nz 48\\nO 44 90 185\\nr 60 6 198 46 200 72 190\\nk 40\\nO 81.6 12 148 61 133\\nn 40 20 133\\nv 48 33 133\\nr= 56 28 181 100 181\\ns 120 6 173\\nEI 136 11 222 41 210 94 210\\nS 120\\n@ 128 12 190 43 148 75 137\\nn 64 12 129 50 125\\n_ 80 88 125 100 100'! !\\n\\n!PHOReader class methodsFor: 'examples-private' stamp: 'len 7/27/1999 01:46'!\\naliceShortExampleString\\n\\t^ '_ 48 0 222\\n{ 80 40 222 90 235\\nl 72 44 250 66 250\\nI 80\\ns 88\\nw 40 80 235\\n@ 40 80 210\\nz 64 12 210 50 181 75 181\\nb 72 33 173 88 181\\nI 56 71 181\\ng 56 28 153 100 166\\nI 64 62 160\\nn 40 60 160\\nI 88 27 166\\nN 40 100 166\\nt 80 20 160\\nU 40 40 181 80 166\\ng 48 100 166\\nE 104 38 153 76 137\\nt 56\\nv 48\\nE 72 11 166 66 153\\nr 88 18 160 63 166\\ni 112.8 14 166 49 173 77 173\\nt 104.8 98 137\\nAI 178.4 21 148 70 148 92 137\\nr= 108 25 137 62 133 98 129\\nd 49\\n@ 59.2 6 137 73 133\\nv 46\\ns 89\\nI 40 40 173\\nt 40 40 166\\nI 64 62 166\\nN 72 22 160 77 153\\nb 40 40 142 100 153\\nAI 136 29 142\\nh 80 30 142 100 148\\n@ 60 50 150\\nr= 64 62 153 100 153\\ns 125\\nI 64 37 210 100 190\\ns 72 11 190\\nt 72\\nr= 104 30 160 69 142\\nO 72\\nn 40 40 142\\nD 40 40 153\\n@ 40 40 160\\nb 40 40 153 100 160\\n{ 216 18 166 51 166 70 153 88 137 100 133\\nn 40\\nk 56\\n_ 144 94 129 100 100'! !\\n\\n\\n!PHOReader class methodsFor: 'instance creation' stamp: 'len 6/15/1999 00:48'!\\neventsFromStream: aStream\\n\\t^ self new stream: aStream; read; events! !\\n\\n!PHOReader class methodsFor: 'instance creation' stamp: 'len 6/15/1999 00:49'!\\neventsFromString: aString\\n\\t^ self eventsFromStream: (ReadStream on: aString)! !\\n\\n!PHOReader class methodsFor: 'instance creation' stamp: 'len 6/17/1999 01:47'!\\nplotPitchFromStream: aStream\\n\\t^ self new stream: aStream; read; plotPitch! !\\n\\n!PHOReader class methodsFor: 'instance creation' stamp: 'len 6/17/1999 01:47'!\\nplotPitchFromString: aString\\n\\t^ self plotPitchFromStream: (ReadStream on: aString)! !\\nImageReadWriter subclass: #PNGReadWriter\\n\\tinstanceVariableNames: 'chunk form width height depth backColor bitsPerChannel colorType interlaceMethod bitsPerPixel bytesPerScanline thisScanline prevScanline rowSize globalDataChunk unknownChunks palette transparentPixelValue filtersSeen swizzleMap cachedDecoderMap bigEndian'\\n\\tclassVariableNames: 'BPP BlockHeight BlockWidth Debugging StandardColors StandardSwizzleMaps'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Graphics-Files'!\\n!PNGReadWriter commentStamp: '<historical>' prior: 0!\\nI am a subclass of ImageReadWriter that decodes Portable Network Graphics\\n(PNG) images.\\n\\nSubmitted by Duane Maxwell!\\n\\n\\n!PNGReadWriter methodsFor: 'accessing' stamp: 'RAA 11/7/2000 09:20'!\\ndebugging\\n\\n\\t^Debugging == true! !\\n\\n!PNGReadWriter methodsFor: 'accessing' stamp: 'nk 7/30/2004 17:51'!\\nnextImage\\n\\tbigEndian := SmalltalkImage current isBigEndian.\\n\\tfiltersSeen := Bag new.\\n\\tglobalDataChunk := nil.\\n\\ttransparentPixelValue := nil.\\n\\tunknownChunks := Set new.\\n\\tstream reset.\\n\\tstream binary.\\n\\tstream skip: 8.\\n\\t[stream atEnd] whileFalse: [self processNextChunk].\\n\\t\\\"Set up our form\\\"\\n\\tpalette ifNotNil: \\n\\t\\t\\t[\\\"Dump the palette if it's the same as our standard palette\\\"\\n\\n\\t\\t\\tpalette = (StandardColors copyFrom: 1 to: palette size) \\n\\t\\t\\t\\tifTrue: [palette := nil]].\\n\\t(depth <= 8 and: [palette notNil]) \\n\\t\\tifTrue: \\n\\t\\t\\t[form := ColorForm extent: width @ height depth: depth.\\n\\t\\t\\tform colors: palette]\\n\\t\\tifFalse: [form := Form extent: width @ height depth: depth].\\n\\tbackColor ifNotNil: [form fillColor: backColor].\\n\\tchunk := globalDataChunk ifNil: [self error: 'image data is missing'].\\n\\tchunk ifNotNil: [self processIDATChunk].\\n\\tunknownChunks isEmpty \\n\\t\\tifFalse: \\n\\t\\t\\t[\\\"Transcript show: ' ',unknownChunks asSortedCollection asArray printString.\\\"\\n\\n\\t\\t\\t].\\n\\tself debugging \\n\\t\\tifTrue: \\n\\t\\t\\t[Transcript\\n\\t\\t\\t\\tcr;\\n\\t\\t\\t\\tshow: 'form = ' , form printString.\\n\\t\\t\\tTranscript\\n\\t\\t\\t\\tcr;\\n\\t\\t\\t\\tshow: 'colorType = ' , colorType printString.\\n\\t\\t\\tTranscript\\n\\t\\t\\t\\tcr;\\n\\t\\t\\t\\tshow: 'interlaceMethod = ' , interlaceMethod printString.\\n\\t\\t\\tTranscript\\n\\t\\t\\t\\tcr;\\n\\t\\t\\t\\tshow: 'filters = ' , filtersSeen sortedCounts asArray printString].\\n\\t^form! !\\n\\n!PNGReadWriter methodsFor: 'accessing' stamp: 'DSM 3/24/2000 01:12'!\\nunderstandsImageFormat\\n\\t#(137 80 78 71 13 10 26 10) do: [ :byte |\\n\\t\\tstream next = byte ifFalse: [^ false]].\\n\\t^ true\\n! !\\n\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'ar 2/10/2004 23:55'!\\nprocessBackgroundChunk\\n\\n\\t| val red green blue max |\\n\\n\\t\\\"Transcript show: ' BACKGROUND: ',chunk printString.\\\"\\n\\tcolorType = 3 ifTrue: [\\n\\t\\tbackColor := palette at: chunk first + 1.\\n\\t\\t^self\\n\\t].\\n\\tmax _ (2 raisedTo: bitsPerChannel) - 1.\\n\\t(colorType = 0 or: [colorType = 4]) ifTrue: [\\n\\t\\tval _ chunk unsignedShortAt: 1 bigEndian: true.\\n\\t\\tbackColor := Color gray: val / max.\\n\\t\\t^self\\n\\t].\\n\\t(colorType = 2 or: [colorType = 6]) ifTrue: [\\n\\t\\tred _ chunk unsignedShortAt: 1 bigEndian: true.\\n\\t\\tgreen _ chunk unsignedShortAt: 3 bigEndian: true.\\n\\t\\tblue _ chunk unsignedShortAt: 5 bigEndian: true.\\n\\t\\tbackColor := Color r: red/max g: green/max b: blue/max.\\n\\t\\t^self\\n\\t].\\n\\\"self halt.\\\"\\n\\n\\\"====\\nThe bKGD chunk specifies a default background color to present the image against. Note that viewers are not bound to honor this chunk; a viewer can choose to use a different background. \\n\\nFor color type 3 (indexed color), the bKGD chunk contains: \\n\\n\\n Palette index: 1 byte\\n\\nThe value is the palette index of the color to be used as background. \\n\\nFor color types 0 and 4 (grayscale, with or without alpha), bKGD contains: \\n\\n\\n Gray: 2 bytes, range 0 .. (2^bitdepth)-1\\n\\n(For consistency, 2 bytes are used regardless of the image bit depth.) The value is the gray level to be used as background. \\n\\nFor color types 2 and 6 (truecolor, with or without alpha), bKGD contains: \\n\\n\\n Red: 2 bytes, range 0 .. (2^bitdepth)-1\\n Green: 2 bytes, range 0 .. (2^bitdepth)-1\\n Blue: 2 bytes, range 0 .. (2^bitdepth)-1\\n\\n(For consistency, 2 bytes per sample are used regardless of the image bit depth.) This is the RGB color to be used as background. \\n\\nWhen present, the bKGD chunk must precede the first IDAT chunk, and must follow the PLTE chunk, if any. \\n===\\\"\\n! !\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'RAA 11/4/2000 17:00'!\\nprocessIDATChunk\\n\\n\\tinterlaceMethod = 0\\n\\t\\tifTrue: [ self processNonInterlaced ]\\n\\t\\tifFalse: [ self processInterlaced ]\\n! !\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'ar 2/10/2004 23:55'!\\nprocessIHDRChunk\\n\\twidth _ chunk longAt: 1 bigEndian: true.\\n\\theight _ chunk longAt: 5 bigEndian: true.\\n\\tbitsPerChannel _ chunk at: 9.\\n\\tcolorType _ chunk at: 10.\\n\\t\\\"compression _ chunk at: 11.\\\" \\\"TODO - validate compression\\\"\\n\\t\\\"filterMethod _ chunk at: 12.\\\" \\\"TODO - validate filterMethod\\\"\\n\\tinterlaceMethod _ chunk at: 13. \\\"TODO - validate interlace method\\\"\\n\\t(#(2 4 6) includes: colorType)\\n\\t\\tifTrue: [depth _ 32].\\n\\t(#(0 3) includes: colorType) ifTrue: [\\n\\t\\tdepth _ bitsPerChannel min: 8.\\n\\t\\tcolorType = 0 ifTrue: [ \\\"grayscale\\\"\\n\\t\\t\\tpalette := self grayColorsFor: depth.\\n\\t\\t].\\n\\t].\\n\\tbitsPerPixel _ (BPP at: colorType+1) at: bitsPerChannel highBit.\\n\\tbytesPerScanline _ width * bitsPerPixel + 7 // 8.\\n\\trowSize _ width * depth + 31 >> 5.\\n! !\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'ar 2/29/2004 04:19'!\\nprocessInterlaced\\n\\t| z filter bytesPerPass startingCol colIncrement rowIncrement startingRow cx sc temp |\\n\\tstartingCol _ #(0 4 0 2 0 1 0 ).\\n\\tcolIncrement _ #(8 8 4 4 2 2 1 ).\\n\\trowIncrement _ #(8 8 8 4 4 2 2 ).\\n\\tstartingRow _ #(0 0 4 0 2 0 1 ).\\n\\tz _ ZLibReadStream on: chunk from: 1 to: chunk size.\\n\\t1 to: 7 do: [:pass |\\n\\t\\t(self doPass: pass)\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[cx _ colIncrement at: pass.\\n\\t\\t\\t\\tsc _ startingCol at: pass.\\n\\t\\t\\t\\tbytesPerPass _ width - sc + cx - 1 // cx * bitsPerPixel + 7 // 8.\\n\\t\\t\\t\\tprevScanline _ ByteArray new: bytesPerPass.\\n\\t\\t\\t\\tthisScanline _ ByteArray new: bytesPerScanline.\\n\\t\\t\\t\\t(startingRow at: pass)\\n\\t\\t\\t\\t\\tto: height - 1\\n\\t\\t\\t\\t\\tby: (rowIncrement at: pass)\\n\\t\\t\\t\\t\\tdo: [:y |\\n\\t\\t\\t\\t\\t\\tfilter _ z next.\\n\\t\\t\\t\\t\\t\\tfiltersSeen add: filter.\\n\\t\\t\\t\\t\\t\\t(filter isNil or: [(filter between: 0 and: 4) not])\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [^ self].\\n\\t\\t\\t\\t\\t\\tthisScanline _ z next: bytesPerPass into: thisScanline startingAt: 1.\\n\\t\\t\\t\\t\\t\\tself filterScanline: filter count: bytesPerPass.\\n\\t\\t\\t\\t\\t\\tself copyPixels: y at: sc by: cx.\\n\\t\\t\\t\\t\\t\\ttemp := prevScanline.\\n\\t\\t\\t\\t\\t\\tprevScanline := thisScanline.\\n\\t\\t\\t\\t\\t\\tthisScanline := temp.\\n\\t\\t\\t\\t\\t]\\n\\t\\t\\t\\t]\\n\\t].\\n\\tz atEnd ifFalse:[self error:'Unexpected data'].! !\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'ar 2/11/2004 12:14'!\\nprocessNextChunk\\n\\n\\t| length chunkType crc chunkCrc |\\n\\n\\tlength _ self nextLong.\\n\\n\\tchunkType _ (self next: 4) asString.\\n\\tchunk _ self next: length.\\n\\tchunkCrc := self nextLong bitXor: 16rFFFFFFFF.\\n\\tcrc := self updateCrc: 16rFFFFFFFF from: 1 to: 4 in: chunkType.\\n\\tcrc := self updateCrc: crc from: 1 to: length in: chunk.\\n\\tcrc = chunkCrc ifFalse:[\\n\\t\\tself error: 'PNGReadWriter crc error in chunk ', chunkType.\\n\\t].\\n\\n\\tchunkType = 'IEND' ifTrue: [^self\\t\\\"*should* be the last chunk\\\"].\\n\\tchunkType = 'sBIT' ifTrue: [^self processSBITChunk \\\"could indicate unusual sample depth in original\\\"].\\n\\tchunkType = 'gAMA' ifTrue: [^self \\t\\\"indicates gamma correction value\\\"].\\n\\tchunkType = 'bKGD' ifTrue: [^self processBackgroundChunk].\\n\\tchunkType = 'pHYs' ifTrue: [^self processPhysicalPixelChunk].\\n\\tchunkType = 'tRNS' ifTrue: [^self processTransparencyChunk].\\n\\n\\tchunkType = 'IHDR' ifTrue: [^self processIHDRChunk].\\n\\tchunkType = 'PLTE' ifTrue: [^self processPLTEChunk].\\n\\tchunkType = 'IDAT' ifTrue: [\\n\\t\\t\\\"---since the compressed data can span multiple\\n\\t\\tchunks, stitch them all together first. later,\\n\\t\\tif memory is an issue, we need to figure out how\\n\\t\\tto do this on the fly---\\\"\\n\\t\\tglobalDataChunk _ globalDataChunk ifNil: [chunk] ifNotNil:\\n\\t\\t\\t[globalDataChunk,chunk].\\n\\t\\t^self\\n\\t].\\n\\tunknownChunks add: chunkType.\\n! !\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'ar 2/29/2004 04:19'!\\nprocessNonInterlaced\\n\\t| z filter temp copyMethod debug |\\n\\tdebug := self debugging.\\n\\tcopyMethod _ #(copyPixelsGray: nil copyPixelsRGB: copyPixelsIndexed:\\n\\t\\t copyPixelsGrayAlpha: nil copyPixelsRGBA:) at: colorType+1.\\n\\tdebug ifTrue: [ Transcript cr; nextPutAll: 'NI chunk size='; print: chunk size ].\\n\\tz _ ZLibReadStream on: chunk from: 1 to: chunk size.\\n\\tprevScanline _ ByteArray new: bytesPerScanline.\\n\\tthisScanline := ByteArray new: bytesPerScanline.\\n\\t0 to: height-1 do: [ :y |\\n\\t\\tfilter _ (z next: 1) first.\\n\\t\\tdebug ifTrue:[filtersSeen add: filter].\\n\\t\\tthisScanline _ z next: bytesPerScanline into: thisScanline startingAt: 1.\\n\\t\\t(debug and: [ thisScanline size < bytesPerScanline ]) ifTrue: [ Transcript nextPutAll: ('wanted {1} but only got {2}' format: { bytesPerScanline. thisScanline size }); cr ].\\n\\t\\tfilter = 0 ifFalse:[self filterScanline: filter count: bytesPerScanline].\\n\\t\\tself perform: copyMethod with: y.\\n\\t\\ttemp := prevScanline.\\n\\t\\tprevScanline := thisScanline.\\n\\t\\tthisScanline := temp.\\n\\t\\t].\\n\\tz atEnd ifFalse:[self error:'Unexpected data'].\\n\\tdebug ifTrue: [Transcript nextPutAll: ' compressed size='; print: z position ].\\n! !\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'ar 2/11/2004 01:02'!\\nprocessPLTEChunk\\n\\n\\t| colorCount i |\\n\\n\\tcolorCount _ chunk size // 3. \\\"TODO - validate colorCount against depth\\\"\\n\\tpalette _ Array new: colorCount.\\n\\t0 to: colorCount-1 do: [ :index |\\n\\t\\ti _ index * 3 + 1.\\n\\t\\tpalette at: index+1 put:\\n\\t\\t\\t(Color r: (chunk at: i)/255.0 g: (chunk at: i+1)/255.0 b: (chunk at: i+2)/255.0)\\n\\t\\t].! !\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'RAA 11/5/2000 11:24'!\\nprocessPhysicalPixelChunk\\n\\n\\t\\\"Transcript show: ' PHYSICAL: ',chunk printString.\\\"\\n! !\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'ar 12/12/2003 18:33'!\\nprocessSBITChunk\\n\\t| rBits gBits bBits aBits |\\n\\tcolorType = 6 ifFalse:[^self].\\n\\trBits := chunk at: 1.\\n\\tgBits := chunk at: 2.\\n\\tbBits := chunk at: 3.\\n\\taBits := chunk at: 4.\\n\\t(rBits = 5 and:[gBits = 5 and:[bBits = 5 and:[aBits = 1]]]) ifTrue:[\\n\\t\\tdepth := 16.\\n\\t].! !\\n\\n!PNGReadWriter methodsFor: 'chunks' stamp: 'RAA 11/4/2000 16:22'!\\nprocessTransparencyChunk\\n\\n\\t| red green blue |\\n\\n\\t\\\"Transcript show: ' TRANSPARENCY ',chunk printString.\\\"\\n\\tcolorType = 0 ifTrue: [\\n\\t\\ttransparentPixelValue _ chunk unsignedShortAt: 1 bigEndian: true.\\n\\t\\t^self\\n\\t].\\n\\tcolorType = 2 ifTrue: [\\n\\t\\tred _ chunk at: 2.\\n\\t\\tgreen _ chunk at: 2.\\n\\t\\tblue _ chunk at: 2.\\n\\t\\ttransparentPixelValue _ 16rFF00 + red << 8 + green << 8 + blue.\\n\\t\\t^self\\n\\t].\\n\\tcolorType = 3 ifTrue: [\\n\\t\\tchunk withIndexDo: [ :alpha :index |\\n\\t\\t\\tpalette at: index put: ((palette at: index) alpha: alpha/255)\\n\\t\\t].\\n\\t\\t^self\\n\\t].\\n! !\\n\\n\\n!PNGReadWriter methodsFor: 'filtering' stamp: 'RAA 11/7/2000 09:43'!\\nfilterAverage: count\\n\\t\\\"Use the average of the pixel to the left and the pixel above as a predictor\\\"\\n\\n\\t| delta |\\n\\tdelta _ bitsPerPixel // 8 max: 1.\\n\\t1 to: delta do: [:i |\\n\\t\\tthisScanline at: i put: ((thisScanline at: i) + ((prevScanline at: i) // 2) bitAnd: 255)].\\n\\tdelta + 1 to: count do: [:i |\\n\\t\\tthisScanline at: i put:\\n\\t\\t\\t((thisScanline at: i)\\n\\t\\t\\t+ ((prevScanline at: i)\\n\\t\\t\\t+ (thisScanline at: i - delta) // 2) bitAnd: 255)]! !\\n\\n!PNGReadWriter methodsFor: 'filtering' stamp: 'DSM 3/25/2000 17:54'!\\nfilterHorizontal: count\\n\\t\\\"Use the pixel to the left as a predictor\\\"\\n\\n\\t| delta |\\n\\tdelta _ bitsPerPixel // 8 max: 1.\\n\\tdelta+1 to: count do: [ :i |\\n\\t\\tthisScanline at: i put: (((thisScanline at: i) +\\n(thisScanline at: i-delta)) bitAnd: 255) ]\\n\\n\\n! !\\n\\n!PNGReadWriter methodsFor: 'filtering' stamp: 'DSM 3/25/2000 17:55'!\\nfilterNone: count\\n! !\\n\\n!PNGReadWriter methodsFor: 'filtering' stamp: 'RAA 11/7/2000 09:45'!\\nfilterPaeth: count\\n\\t\\\"Select one of (the pixel to the left, the pixel above and the pixel to above left) to\\n\\tpredict the value of this pixel\\\"\\n\\n\\t| delta |\\n\\tdelta _ bitsPerPixel // 8 max: 1.\\n\\t1 to: delta do: [ :i |\\n\\t\\tthisScanline at: i put:\\n\\t\\t\\t(((thisScanline at: i) + (prevScanline at: i)) bitAnd: 255)].\\n\\tdelta+1 to: count do: [ :i |\\n\\t\\tthisScanline\\n\\t\\t\\tat: i\\n\\t\\t\\tput: (((thisScanline at: i) + (self\\n\\t\\t\\t\\tpaethPredictLeft: (thisScanline at: i-delta)\\n\\t\\t\\t\\tabove: (prevScanline at: i)\\n\\t\\t\\t\\taboveLeft: (prevScanline at: i-delta)))\\n\\t\\t\\t\\t\\tbitAnd: 255)]\\n\\n! !\\n\\n!PNGReadWriter methodsFor: 'filtering' stamp: 'eat 9/11/2000 20:08'!\\nfilterScanline: filterType count: count\\n\\n\\tself\\n\\t\\tperform: (\\n\\t\\t\\t#(filterNone: filterHorizontal: filterVertical: filterAverage: filterPaeth:)\\n\\t\\t\\t\\tat: filterType+1)\\n\\t\\twith: count.\\n\\n! !\\n\\n!PNGReadWriter methodsFor: 'filtering' stamp: 'DSM 3/25/2000 17:54'!\\nfilterVertical: count\\n\\t\\\"Use the pixel above as a predictor\\\"\\n\\n\\t1 to: count do: [ :i |\\n\\t\\tthisScanline at: i put: (((thisScanline at: i) +\\n(prevScanline at: i)) bitAnd: 255) ]\\n\\n! !\\n\\n!PNGReadWriter methodsFor: 'filtering' stamp: 'eat 9/11/2000 20:05'!\\npaethPredictLeft: a above: b aboveLeft: c\\n\\t\\\"Predicts the value of a pixel based on nearby pixels, based on\\nPaeth (GG II, 1991)\\\"\\n\\n\\t| pa pb pc |\\n\\tpa _ b > c ifTrue: [b - c] ifFalse: [c - b].\\n\\tpb _ a > c ifTrue: [a - c] ifFalse: [c - a].\\n\\tpc _ a + b - c - c.\\n\\tpc < 0 ifTrue: [\\n\\t\\tpc := pc * -1].\\n\\t((pa <= pb) and: [pa <= pc]) ifTrue: [^ a].\\n\\t(pb <= pc) ifTrue: [^ b].\\n\\t^ c\\n! !\\n\\n\\n!PNGReadWriter methodsFor: 'miscellaneous' stamp: 'DSM 4/27/2000 13:09'!\\ndoPass: pass\\n\\t\\\"Certain interlace passes are skipped with certain small image\\ndimensions\\\"\\n\\n\\tpass = 1 ifTrue: [ ^ true ].\\n\\t((width = 1) and: [height = 1]) ifTrue: [ ^ false ].\\n\\tpass = 2 ifTrue: [ ^ width >= 5 ].\\n\\tpass = 3 ifTrue: [ ^ height >= 5 ].\\n\\tpass = 4 ifTrue: [ ^ (width >=3 ) or: [height >= 5] ].\\n\\tpass = 5 ifTrue: [ ^ height >=3 ].\\n\\tpass = 6 ifTrue: [ ^ width >=2 ].\\n\\tpass = 7 ifTrue: [ ^ height >=2 ].\\n\\n! !\\n\\n!PNGReadWriter methodsFor: 'miscellaneous' stamp: 'ar 2/11/2004 01:27'!\\ngrayColorsFor: d\\n\\t\\\"return a color table for a gray image\\\"\\n\\n\\tpalette _ Array new: 1<<d.\\n\\td = 1 ifTrue: [\\n\\t\\tpalette at: 1 put: Color black.\\n\\t\\tpalette at: 2 put: Color white.\\n\\t\\t^ palette,{Color transparent}\\n\\t\\t].\\n\\td = 2 ifTrue: [\\n\\t\\tpalette at: 1 put: Color black.\\n\\t\\tpalette at: 2 put: (Color gray: 85.0 / 255.0).\\n\\t\\tpalette at: 3 put: (Color gray: 170.0 / 255.0).\\n\\t\\tpalette at: 4 put: Color white.\\n\\t\\t^ palette,{Color transparent}.\\n\\t\\t].\\n\\td = 4 ifTrue: [\\n\\t\\t0 to: 15 do: [ :g |\\n\\t\\t\\tpalette at: g+1 put: (Color gray: (g/15) asFloat) ].\\n\\t\\t^ palette,{Color transparent}\\n\\t\\t].\\n\\td = 8 ifTrue: [\\n\\t\\t0 to: 255 do: [ :g |\\n\\t\\t\\tpalette at: g+1 put: (Color gray: (g/255) asFloat) ].\\n\\t\\t^ palette\\t\\t\\\"??transparent??\\\"\\n\\t\\t].\\n! !\\n\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'DSM 3/26/2000 21:32'!\\ncopyPixels: y\\n\\t\\\"Handle non-interlaced pixels of supported colorTypes\\\"\\n\\n\\t| s |\\n\\ts _ #(copyPixelsGray: nil copyPixelsRGB: copyPixelsIndexed:\\n\\t\\t copyPixelsGrayAlpha: nil copyPixelsRGBA:) at: colorType+1.\\n\\tself perform: s asSymbol with: y\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'RAA 11/4/2000 16:08'!\\ncopyPixels: y at: startX by: incX\\n\\t\\\"Handle interlaced pixels of supported colorTypes\\\"\\n\\n\\t| s |\\n\\ts _ #(copyPixelsGray:at:by: nil copyPixelsRGB:at:by: copyPixelsIndexed:at:by:\\n\\t\\t copyPixelsGrayAlpha:at:by: nil copyPixelsRGBA:at:by:) at: colorType+1.\\n\\tself perform: s asSymbol with: y with: startX with: incX\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'RAA 11/4/2000 16:12'!\\ncopyPixelsGray: y \\n\\t\\\"Handle non-interlaced grayscale color mode (colorType = 0)\\\"\\n\\t| blitter pixPerByte mask shifts pixelNumber rawByte pixel transparentIndex |\\n\\tblitter _ BitBlt current bitPokerToForm: form.\\n\\ttransparentIndex _ form colors size.\\n\\tbitsPerChannel = 16\\n\\t\\tifTrue: [0\\n\\t\\t\\t\\tto: width - 1\\n\\t\\t\\t\\tdo: [:x | blitter pixelAt: x @ y put: 255\\n\\t\\t\\t\\t\\t\\t\\t- (thisScanline at: x << 1 + 1)].\\n\\t\\t\\t^ self]\\n\\t\\tifFalse: [bitsPerChannel = 8\\n\\t\\t\\t\\tifTrue: [1\\n\\t\\t\\t\\t\\t\\tto: width\\n\\t\\t\\t\\t\\t\\tdo: [:x | blitter\\n\\t\\t\\t\\t\\t\\t\\t\\tpixelAt: x - 1 @ y\\n\\t\\t\\t\\t\\t\\t\\t\\tput: (thisScanline at: x)].\\n\\t\\t\\t\\t\\t^ self].\\n\\t\\t\\tbitsPerChannel = 1\\n\\t\\t\\t\\tifTrue: [pixPerByte _ 8.\\n\\t\\t\\t\\t\\tmask _ 1.\\n\\t\\t\\t\\t\\tshifts _ #(7 6 5 4 3 2 1 0 )].\\n\\t\\t\\tbitsPerChannel = 2\\n\\t\\t\\t\\tifTrue: [pixPerByte _ 4.\\n\\t\\t\\t\\t\\tmask _ 3.\\n\\t\\t\\t\\t\\tshifts _ #(6 4 2 0 )].\\n\\t\\t\\tbitsPerChannel = 4\\n\\t\\t\\t\\tifTrue: [pixPerByte _ 2.\\n\\t\\t\\t\\t\\tmask _ 15.\\n\\t\\t\\t\\t\\tshifts _ #(4 0 )].\\n\\t\\t\\tpixelNumber _ 0.\\n\\t\\t\\t0 to: width - 1 do: [:x | \\n\\t\\t\\t\\trawByte _ thisScanline at: pixelNumber // pixPerByte + 1.\\n\\t\\t\\t\\tpixel _ rawByte\\n\\t\\t\\t\\t\\t\\t\\t>> (shifts at: pixelNumber \\\\\\\\ pixPerByte + 1) bitAnd: mask.\\n\\t\\t\\t\\tpixel = transparentPixelValue ifTrue: [pixel _ transparentIndex].\\n\\t\\t\\t\\tblitter pixelAt: x @ y put: pixel.\\n\\t\\t\\t\\tpixelNumber _ pixelNumber + 1\\n\\t\\t\\t]\\n\\t\\t]! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'RAA 11/4/2000 16:09'!\\ncopyPixelsGray: y at: startX by: incX\\n\\t\\\"Handle interlaced grayscale color mode (colorType = 0)\\\"\\n\\n\\t| b offset bits w pixel mask blitter pixelNumber pixPerByte rawByte\\nshifts |\\n\\tbitsPerChannel = 16\\n\\t\\tifTrue: [\\n\\t\\t\\tb _ BitBlt current bitPokerToForm: form.\\n\\t\\t\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\t\\t\\tb pixelAt: x@y put: 255 - (thisScanline at: (x//incX<<1)+1).\\n\\t\\t\\t\\t].\\n\\t\\t\\t^ self\\n\\t\\t\\t].\\n\\toffset _ y*rowSize+1.\\n\\tbits _ form bits.\\n\\tbitsPerChannel = 8 ifTrue: [\\n\\t\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\t\\tw _ offset + (x>>2).\\n\\t\\t\\tb _ 3- (x \\\\\\\\ 4) * 8.\\n\\t\\t\\tpixel _ (thisScanline at: x // incX + 1)<<b.\\n\\t\\t\\tmask _ (255<<b) bitInvert32.\\n\\t\\t\\tbits at: w put: (((bits at: w) bitAnd: mask) bitOr: pixel)\\n\\t\\t].\\n\\t\\t^ self\\n\\t].\\n\\tbitsPerChannel = 1 ifTrue: [\\n\\t\\tpixPerByte _ 8.\\n\\t\\tmask _ 1.\\n\\t\\tshifts _ #(7 6 5 4 3 2 1 0).\\n\\t].\\n\\tbitsPerChannel = 2 ifTrue: [\\n\\t\\tpixPerByte _ 4.\\n\\t\\tmask _ 3.\\n\\t\\tshifts _ #(6 4 2 0).\\n\\t].\\n\\tbitsPerChannel = 4 ifTrue: [\\n\\t\\tpixPerByte _ 2.\\n\\t\\tmask _ 15.\\n\\t\\tshifts _ #(4 0).\\n\\t].\\n\\n\\tblitter _ BitBlt current bitPokerToForm: form.\\n\\tpixelNumber _ 0.\\n\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\trawByte _ thisScanline at: (pixelNumber // pixPerByte) + 1.\\n\\t\\tpixel _ (rawByte >> (shifts at: (pixelNumber \\\\\\\\ pixPerByte) + 1)) bitAnd: mask.\\n\\t\\tblitter pixelAt: (x@y) put: pixel.\\n\\t\\tpixelNumber _ pixelNumber + 1.\\n\\t].\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'RAA 11/4/2000 16:09'!\\ncopyPixelsGrayAlpha: y\\n\\t\\\"Handle non-interlaced grayscale with alpha color mode (colorType = 4)\\\"\\n\\n\\t| i pixel gray b |\\n\\tb _ BitBlt current bitPokerToForm: form.\\n\\tbitsPerChannel = 8\\n\\t\\tifTrue: [\\n\\t\\t\\t0 to: width-1 do: [ :x |\\n\\t\\t\\t\\ti _ (x << 1) + 1.\\n\\t\\t\\t\\tgray _ thisScanline at: i.\\n\\t\\t\\t\\tpixel _ ((thisScanline at: i+1)<<24) + (gray<<16) + (gray<<8) + gray.\\n\\t\\t\\t\\tb pixelAt: x@y put: pixel.\\n\\t\\t\\t\\t]\\n\\t\\t\\t]\\n\\t\\tifFalse: [\\n\\t\\t\\t0 to: width-1 do: [ :x |\\n\\t\\t\\t\\ti _ (x << 2) + 1.\\n\\t\\t\\t\\tgray _ thisScanline at: i.\\n\\t\\t\\t\\tpixel _ ((thisScanline at: i+2)<<24) + (gray<<16) + (gray<<8) + gray.\\n\\t\\t\\t\\tb pixelAt: x@y put: pixel.\\n\\t\\t\\t\\t]\\n\\t\\t\\t]\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'RAA 11/4/2000 16:09'!\\ncopyPixelsGrayAlpha: y at: startX by: incX\\n\\t\\\"Handle interlaced grayscale with alpha color mode (colorType = 4)\\\"\\n\\n\\t| i pixel gray b |\\n\\tb _ BitBlt current bitPokerToForm: form.\\n\\tbitsPerChannel = 8\\n\\t\\tifTrue: [\\n\\t\\t\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\t\\t\\ti _ (x // incX << 1) + 1.\\n\\t\\t\\t\\tgray _ thisScanline at: i.\\n\\t\\t\\t\\tpixel _ ((thisScanline at: i+1)<<24) + (gray<<16) + (gray<<8) + gray.\\n\\t\\t\\t\\tb pixelAt: x@y put: pixel.\\n\\t\\t\\t\\t]\\n\\t\\t\\t]\\n\\t\\tifFalse: [\\n\\t\\t\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\t\\t\\ti _ (x // incX << 2) + 1.\\n\\t\\t\\t\\tgray _ thisScanline at: i.\\n\\t\\t\\t\\tpixel _ ((thisScanline at: i+2)<<24) + (gray<<16) + (gray<<8) + gray.\\n\\t\\t\\t\\tb pixelAt: x@y put: pixel.\\n\\t\\t\\t\\t]\\n\\t\\t\\t]\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'ar 1/1/1970 21:00'!\\ncopyPixelsIndexed: y\\n\\t\\\"Handle non-interlaced indexed color mode (colorType = 3)\\\"\\n\\t| hack hackBlt swizzleHack swizzleBlt scanline hackDepth |\\n\\tscanline := ByteArray new: bytesPerScanline + 3 // 4 * 4.\\n\\tscanline replaceFrom: 1 to: thisScanline size with: thisScanline startingAt: 1.\\n\\thackDepth := bigEndian ifTrue:[form depth] ifFalse:[form depth negated].\\n\\thack := Form extent: width@1 depth: hackDepth bits: scanline.\\n\\thackBlt := BitBlt toForm: form.\\n\\thackBlt sourceForm: hack.\\n\\thackBlt combinationRule: Form over.\\n\\thackBlt destOrigin: 0@y.\\n\\thackBlt width: width; height: 1.\\n\\n\\t(form depth < 8 and:[bigEndian not]) ifTrue:[\\n\\t\\tswizzleHack := Form new hackBits: scanline.\\n\\t\\tswizzleBlt := BitBlt toForm: swizzleHack.\\n\\t\\tswizzleBlt sourceForm: swizzleHack.\\n\\t\\tswizzleBlt combinationRule: Form over.\\n\\t\\tswizzleBlt colorMap: (StandardSwizzleMaps at: form depth).\\n\\t\\tswizzleBlt copyBits.\\n\\t].\\n\\n\\thackBlt copyBits.! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'RAA 11/4/2000 16:23'!\\ncopyPixelsIndexed: y at: startX by: incX\\n\\t\\\"Handle interlaced indexed color mode (colorType = 3)\\\"\\n\\n\\t| offset b bits w pixel mask pixPerByte shifts blitter pixelNumber rawByte |\\n\\toffset _ y*rowSize+1.\\n\\tbits _ form bits.\\n\\tbitsPerChannel = 8\\n\\t\\tifTrue: [\\n\\t\\t\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\t\\t\\tw _ offset + (x>>2).\\n\\t\\t\\t\\tb _ 3 - (x \\\\\\\\ 4) * 8.\\n\\t\\t\\t\\tpixel _ (thisScanline at: x // incX + 1)<<b.\\n\\t\\t\\t\\tmask _ (255<<b) bitInvert32.\\n\\t\\t\\t\\tbits at: w put: (((bits at: w) bitAnd: mask) bitOr: pixel)].\\n\\t\\t\\t^ self ].\\n\\tbitsPerChannel = 1 ifTrue: [\\n\\t\\tpixPerByte _ 8.\\n\\t\\tmask _ 1.\\n\\t\\tshifts _ #(7 6 5 4 3 2 1 0).\\n\\t].\\n\\tbitsPerChannel = 2 ifTrue: [\\n\\t\\tpixPerByte _ 4.\\n\\t\\tmask _ 3.\\n\\t\\tshifts _ #(6 4 2 0).\\n\\t].\\n\\tbitsPerChannel = 4 ifTrue: [\\n\\t\\tpixPerByte _ 2.\\n\\t\\tmask _ 15.\\n\\t\\tshifts _ #(4 0).\\n\\t].\\n\\n\\tblitter _ BitBlt current bitPokerToForm: form.\\n\\tpixelNumber _ 0.\\n\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\trawByte _ thisScanline at: (pixelNumber // pixPerByte) + 1.\\n\\t\\tpixel _ (rawByte >> (shifts at: (pixelNumber \\\\\\\\ pixPerByte) + 1)) bitAnd: mask.\\n\\t\\tblitter pixelAt: (x@y) put: pixel.\\n\\t\\tpixelNumber _ pixelNumber + 1.\\n\\t].\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'RAA 11/7/2000 09:30'!\\ncopyPixelsRGB: y\\n\\t\\\"Handle non-interlaced RGB color mode (colorType = 2)\\\"\\n\\n\\t| i pixel tempForm tempBits |\\n\\n\\ttempForm _ Form extent: width@1 depth: 32.\\n\\ttempBits _ tempForm bits.\\n\\tpixel := LargePositiveInteger new: 4.\\n\\tpixel at: 4 put: 16rFF.\\n\\tbitsPerChannel = 8 ifTrue: [\\n\\t\\ti := 1.\\n\\t\\t1 to: width do: [ :x |\\n\\t\\t\\tpixel\\n\\t\\t\\t\\tat: 3 put: (thisScanline at: i);\\n\\t\\t\\t\\tat: 2 put: (thisScanline at: i+1);\\n\\t\\t\\t\\tat: 1 put: (thisScanline at: i+2).\\n\\t\\t\\ttempBits at: x put: pixel.\\n\\t\\t\\ti _ i + 3.\\n\\t\\t]\\n\\t] ifFalse: [\\n\\t\\ti := 1.\\n\\t\\t1 to: width do: [ :x |\\n\\t\\t\\tpixel\\n\\t\\t\\t\\tat: 3 put: (thisScanline at: i);\\n\\t\\t\\t\\tat: 2 put: (thisScanline at: i+2);\\n\\t\\t\\t\\tat: 1 put: (thisScanline at: i+4).\\n\\t\\t\\ttempBits at: x put: pixel.\\n\\t\\t\\ti _ i + 6.\\n\\t\\t]\\n\\t].\\n\\ttransparentPixelValue ifNotNil: [\\n\\t\\t1 to: width do: [ :x |\\n\\t\\t\\t(tempBits at: x) = transparentPixelValue ifTrue: [\\n\\t\\t\\t\\ttempBits at: x put: 0.\\n\\t\\t\\t].\\n\\t\\t].\\n\\t].\\n\\ttempForm displayOn: form at: 0@y rule: Form paint.\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'nk 7/27/2004 17:18'!\\ncopyPixelsRGB: y at: startX by: incX\\n\\t\\\"Handle interlaced RGB color mode (colorType = 2)\\\"\\n\\n\\t| i pixel tempForm tempBits xx loopsToDo |\\n\\n\\ttempForm _ Form extent: width@1 depth: 32.\\n\\ttempBits _ tempForm bits.\\n\\tpixel := LargePositiveInteger new: 4.\\n\\tpixel at: 4 put: 16rFF.\\n\\tloopsToDo _ width - startX + incX - 1 // incX.\\n\\tbitsPerChannel = 8 ifTrue: [\\n\\t\\ti _ (startX // incX * 3) + 1.\\n\\t\\txx _ startX+1.\\n\\t\\t1 to: loopsToDo do: [ :j |\\n\\t\\t\\tpixel\\n\\t\\t\\t\\tat: 3 put: (thisScanline at: i);\\n\\t\\t\\t\\tat: 2 put: (thisScanline at: i+1);\\n\\t\\t\\t\\tat: 1 put: (thisScanline at: i+2).\\n\\t\\t\\ttempBits at: xx put: pixel.\\n\\t\\t\\ti _ i + 3.\\n\\t\\t\\txx _ xx + incX.\\n\\t\\t]\\n\\t] ifFalse: [\\n\\t\\ti _ (startX // incX * 6) + 1.\\n\\t\\txx _ startX+1.\\n\\t\\t1 to: loopsToDo do: [ :j |\\n\\t\\t\\tpixel\\n\\t\\t\\t\\tat: 3 put: (thisScanline at: i);\\n\\t\\t\\t\\tat: 2 put: (thisScanline at: i+2);\\n\\t\\t\\t\\tat: 1 put: (thisScanline at: i+4).\\n\\t\\t\\ttempBits at: xx put: pixel.\\n\\t\\t\\ti _ i + 6.\\n\\t\\t\\txx _ xx + incX.\\n\\t\\t].\\n\\t].\\n\\ttransparentPixelValue ifNotNil: [\\n\\t\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\t\\t(tempBits at: x+1) = transparentPixelValue ifTrue: [\\n\\t\\t\\t\\ttempBits at: x+1 put: 0.\\n\\t\\t\\t].\\n\\t\\t].\\n\\t].\\n\\ttempForm displayOn: form at: 0@y rule: Form paint.\\n\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'ar 2/18/2004 23:58'!\\ncopyPixelsRGBA: y\\n\\t\\\"Handle non-interlaced RGBA color modes (colorType = 6)\\\"\\n\\n\\t| i pixel tempForm tempBits ff |\\n\\tbitsPerChannel = 8 ifTrue: [\\n\\t\\tff := Form extent: width@1 depth: 32 bits: thisScanline.\\n\\t\\tcachedDecoderMap \\n\\t\\t\\tifNil:[cachedDecoderMap := self rgbaDecoderMapForDepth: depth].\\n\\t\\t(BitBlt toForm: form)\\n\\t\\t\\tsourceForm: ff;\\n\\t\\t\\tdestOrigin: 0@y;\\n\\t\\t\\tcombinationRule: Form over;\\n\\t\\t\\tcolorMap: cachedDecoderMap;\\n\\t\\t\\tcopyBits.\\n\\t\\t^self.\\n\\t].\\n\\ttempForm _ Form extent: width@1 depth: 32.\\n\\ttempBits _ tempForm bits.\\n\\tpixel := LargePositiveInteger new: 4.\\n\\ti := -7.\\n\\t0 to: width-1 do: [ :x |\\n\\t\\t\\ti := i + 8.\\n\\t\\t\\tpixel at: 4 put: (thisScanline at: i+6);\\n\\t\\t\\t\\tat: 3 put: (thisScanline at: i);\\n\\t\\t\\t\\tat: 2 put: (thisScanline at: i+2);\\n\\t\\t\\t\\tat: 1 put: (thisScanline at: i+4).\\n\\t\\t\\ttempBits at: x+1 put: pixel.\\n\\t].\\n\\ttempForm displayOn: form at: 0@y rule: Form over.\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'nk 7/27/2004 17:57'!\\ncopyPixelsRGBA: y at: startX by: incX\\n\\t\\\"Handle interlaced RGBA color modes (colorType = 6)\\\"\\n\\n\\t| i pixel tempForm tempBits |\\n\\n\\ttempForm _ Form extent: width@1 depth: 32.\\n\\ttempBits _ tempForm bits.\\n\\tpixel := LargePositiveInteger new: 4.\\n\\tbitsPerChannel = 8 ifTrue: [\\n\\t\\ti _ (startX // incX << 2) + 1.\\n\\t\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\t\\tpixel at: 4 put: (thisScanline at: i+3);\\n\\t\\t\\t\\tat: 3 put: (thisScanline at: i);\\n\\t\\t\\t\\tat: 2 put: (thisScanline at: i+1);\\n\\t\\t\\t\\tat: 1 put: (thisScanline at: i+2).\\n\\t\\t\\ttempBits at: x+1 put: pixel.\\n\\t\\t\\ti _ i + 4.\\n\\t\\t]\\n\\t] ifFalse: [\\n\\t\\ti _ (startX // incX << 3) +1.\\n\\t\\tstartX to: width-1 by: incX do: [ :x |\\n\\t\\t\\tpixel at: 4 put: (thisScanline at: i+6);\\n\\t\\t\\t\\tat: 3 put: (thisScanline at: i);\\n\\t\\t\\t\\tat: 2 put: (thisScanline at: i+2);\\n\\t\\t\\t\\tat: 1 put: (thisScanline at: i+4).\\n\\t\\t\\ttempBits at: x+1 put: pixel.\\n\\t\\t\\ti _ i + 8.\\n\\t\\t].\\n\\t].\\n\\ttempForm displayOn: form at: 0@y rule: Form paintAlpha.\\n\\n! !\\n\\n!PNGReadWriter methodsFor: 'pixel copies' stamp: 'ar 2/19/2004 00:10'!\\nrgbaDecoderMapForDepth: decoderDepth\\n\\tbigEndian ifTrue:[\\n\\t\\tdepth = 16 ifTrue:[\\n\\t\\t\\t\\\"Big endian, 32 -> 16 color mapping.\\\"\\n\\t\\t\\t^ColorMap\\n\\t\\t\\t\\tshifts: #(-17 -14 -11 0)\\n\\t\\t\\t\\tmasks: #(16rF8000000 16rF80000 16rF800 16r00)\\n\\t\\t] ifFalse:[\\n\\t\\t\\t\\\"Big endian, 32 -> 32 color mapping\\\"\\n\\t\\t\\t^ColorMap \\n\\t\\t\\t\\tshifts: #(-8 -8 -8 24) \\n\\t\\t\\t\\tmasks: #(16rFF000000 16rFF0000 16rFF00 16rFF).\\n\\t\\t].\\n\\t].\\n\\tdepth = 16 ifTrue:[\\n\\t\\t\\\"Little endian, 32 -> 16 color mapping.\\\"\\n\\t\\t^ColorMap\\n\\t\\t\\tshifts: #(7 -6 -19 0)\\n\\t\\t\\tmasks: #(16rF8 16rF800 16rF80000 0)\\n\\t] ifFalse:[\\n\\t\\t\\\"Little endian, 32 -> 32 color mapping\\\"\\n\\t\\t^ColorMap \\n\\t\\t\\tshifts: #(-16 0 16 0) \\n\\t\\t\\tmasks: #(16rFF0000 16rFF00 16rFF 16rFF000000).\\n\\t].! !\\n\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'ar 12/12/2003 16:37'!\\nnextPutImage: aForm\\n\\t\\\"Write out the given form. We're keeping it simple here, no interlacing, no filters.\\\"\\n\\t^self nextPutImage: aForm interlace: 0 filter: 0. \\\"no filtering\\\"! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'nk 7/30/2004 17:51'!\\nnextPutImage: aForm interlace: aMethod filter: aFilterType \\n\\t\\\"Note: For now we keep it simple - interlace and filtering are simply ignored\\\"\\n\\n\\t| crcStream |\\n\\tbigEndian := SmalltalkImage current isBigEndian.\\n\\tform := aForm.\\n\\twidth := aForm width.\\n\\theight := aForm height.\\n\\taForm depth <= 8 \\n\\t\\tifTrue: \\n\\t\\t\\t[bitsPerChannel := aForm depth.\\n\\t\\t\\tcolorType := 3.\\n\\t\\t\\tbytesPerScanline := (width * aForm depth + 7) // 8]\\n\\t\\tifFalse: \\n\\t\\t\\t[bitsPerChannel := 8.\\n\\t\\t\\tcolorType := 6.\\n\\t\\t\\tbytesPerScanline := width * 4].\\n\\tself writeFileSignature.\\n\\tcrcStream := WriteStream on: (ByteArray new: 1000).\\n\\tcrcStream resetToStart.\\n\\tself writeIHDRChunkOn: crcStream.\\n\\tself writeChunk: crcStream.\\n\\tform depth <= 8 \\n\\t\\tifTrue: \\n\\t\\t\\t[crcStream resetToStart.\\n\\t\\t\\tself writePLTEChunkOn: crcStream.\\n\\t\\t\\tself writeChunk: crcStream.\\n\\t\\t\\tform isColorForm \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[crcStream resetToStart.\\n\\t\\t\\t\\t\\tself writeTRNSChunkOn: crcStream.\\n\\t\\t\\t\\t\\tself writeChunk: crcStream]].\\n\\tform depth = 16 \\n\\t\\tifTrue: \\n\\t\\t\\t[crcStream resetToStart.\\n\\t\\t\\tself writeSBITChunkOn: crcStream.\\n\\t\\t\\tself writeChunk: crcStream].\\n\\tcrcStream resetToStart.\\n\\tself writeIDATChunkOn: crcStream.\\n\\tself writeChunk: crcStream.\\n\\tcrcStream resetToStart.\\n\\tself writeIENDChunkOn: crcStream.\\n\\tself writeChunk: crcStream! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'nk 2/17/2004 16:51'!\\nupdateCrc: oldCrc from: start to: stop in: aCollection\\n\\t^ZipWriteStream updateCrc: oldCrc from: start to: stop in: aCollection! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'BG 3/16/2005 08:26'!\\nwriteChunk: crcStream\\n\\t| bytes length crc debug |\\n\\tdebug _ self debugging.\\n\\tbytes := crcStream originalContents.\\n\\tlength := crcStream position.\\n\\tcrc := self updateCrc: 16rFFFFFFFF from: 1 to: length in: bytes.\\n\\tcrc := crc bitXor: 16rFFFFFFFF.\\n\\tdebug ifTrue: [ Transcript cr;\\n\\t\\tprint: stream position; space;\\n\\t\\tnextPutAll: (bytes copyFrom: 1 to: 4) asString;\\n\\t\\tnextPutAll: ' len='; print: length;\\n\\t\\tnextPutAll: ' crc=0x'; nextPutAll: crc printStringHex ].\\n\\tstream nextNumber: 4 put: length-4. \\\"exclude chunk name\\\"\\n\\tstream next: length putAll: bytes startingAt: 1.\\n\\tstream nextNumber: 4 put: crc.\\n\\tdebug ifTrue: [ Transcript nextPutAll: ' afterPos='; print: stream position ].\\n\\tcrcStream resetToStart.! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'ar 12/12/2003 16:40'!\\nwriteFileSignature\\n\\tstream nextPutAll: #(16r89 16r50 16r4E 16r47 16r0D 16r0A 16r1A 16r0A) asByteArray! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'nk 2/17/2004 14:57'!\\nwriteIDATChunkOn: aStream\\n\\t\\\"Write the IDAT chunk\\\"\\n\\t| z |\\n\\taStream nextPutAll: 'IDAT' asByteArray.\\n\\tz _ ZLibWriteStream on: aStream.\\n\\tform depth <= 8 \\n\\t\\tifTrue:[self writeType3DataOn: z]\\n\\t\\tifFalse:[ self writeType6DataOn: z].\\n\\tself debugging ifTrue: [\\n\\t\\tTranscript cr;\\n\\t\\t\\tnextPutAll: 'compressed size=';\\n\\t\\t\\tprint: aStream position;\\n\\t\\t\\tnextPutAll: ' uncompressed size=';\\n\\t\\t\\tprint: z position ]\\n! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'ar 12/12/2003 17:08'!\\nwriteIENDChunkOn: aStream\\n\\t\\\"Write the IEND chunk\\\"\\n\\taStream nextPutAll: 'IEND' asByteArray.! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'ar 12/12/2003 17:21'!\\nwriteIHDRChunkOn: aStream\\n\\t\\\"Write the IHDR chunk\\\"\\n\\taStream nextPutAll: 'IHDR' asByteArray.\\n\\taStream nextInt32Put: width.\\n\\taStream nextInt32Put: height.\\n\\taStream nextNumber: 1 put: bitsPerChannel.\\n\\taStream nextNumber: 1 put: colorType.\\n\\taStream nextNumber: 1 put: 0. \\\"compression\\\"\\n\\taStream nextNumber: 1 put: 0. \\\"filter method\\\"\\n\\taStream nextNumber: 1 put: 0. \\\"interlace method\\\"\\n! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'nk 4/17/2004 19:44'!\\nwritePLTEChunkOn: aStream\\n\\t\\\"Write the PLTE chunk\\\"\\n\\t| r g b colors |\\n\\taStream nextPutAll: 'PLTE' asByteArray.\\n\\t(form isColorForm) \\n\\t\\tifTrue:[colors := form colors]\\n\\t\\tifFalse:[colors := Color indexedColors copyFrom: 1 to: (1 bitShift: form depth)].\\n\\tcolors do:[:aColor|\\n\\t\\tr := (aColor red * 255) truncated.\\n\\t\\tg := (aColor green * 255) truncated.\\n\\t\\tb := (aColor blue * 255) truncated.\\n\\t\\taStream nextPut: r; nextPut: g; nextPut: b.\\n\\t].! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'ar 12/12/2003 18:29'!\\nwriteSBITChunkOn: aStream\\n\\t\\\"Write the IDAT chunk\\\"\\n\\taStream nextPutAll: 'sBIT' asByteArray.\\n\\tform depth = 16 ifFalse:[self error: 'Unimplemented feature'].\\n\\taStream nextPut: 5.\\n\\taStream nextPut: 5.\\n\\taStream nextPut: 5.\\n\\taStream nextPut: 1.! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'ar 12/12/2003 17:34'!\\nwriteTRNSChunkOn: aStream\\n\\t\\\"Write out tRNS chunk\\\"\\n\\taStream nextPutAll: 'tRNS' asByteArray.\\n\\tform colors do:[:aColor|\\n\\t\\taStream nextPut: (aColor alpha * 255) truncated.\\n\\t].! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'ar 1/1/1970 20:58'!\\nwriteType3DataOn: zStream\\n\\t\\\"Write color indexed data.\\\"\\n\\t| scanline hack hackBlt swizzleBlt swizzleHack hackDepth |\\n\\tscanline := ByteArray new: bytesPerScanline + 3 // 4 * 4.\\n\\thackDepth := bigEndian ifTrue:[form depth] ifFalse:[form depth negated].\\n\\thack := Form extent: width@1 depth: hackDepth bits: scanline.\\n\\thackBlt := BitBlt toForm: hack.\\n\\thackBlt sourceForm: form.\\n\\thackBlt combinationRule: Form over.\\n\\thackBlt destOrigin: 0@0.\\n\\thackBlt width: width; height: 1.\\n\\t(form depth < 8 and:[bigEndian not]) ifTrue:[\\n\\t\\tswizzleHack := Form new hackBits: scanline.\\n\\t\\tswizzleBlt := BitBlt toForm: swizzleHack.\\n\\t\\tswizzleBlt sourceForm: swizzleHack.\\n\\t\\tswizzleBlt combinationRule: Form over.\\n\\t\\tswizzleBlt colorMap: (StandardSwizzleMaps at: form depth).\\n\\t].\\n\\t0 to: height-1 do:[:i|\\n\\t\\thackBlt sourceOrigin: 0@i; copyBits.\\n\\t\\tswizzleBlt ifNotNil:[swizzleBlt copyBits].\\n\\t\\tzStream nextPut: 0. \\\"filterType\\\"\\n\\t\\tzStream next: bytesPerScanline putAll: scanline startingAt: 1.\\n\\t].\\n\\tzStream close.! !\\n\\n!PNGReadWriter methodsFor: 'writing' stamp: 'ar 2/19/2004 00:10'!\\nwriteType6DataOn: zStream\\n\\t\\\"Write RGBA data.\\\"\\n\\t| scanline hack hackBlt cm miscBlt |\\n\\tscanline := ByteArray new: bytesPerScanline.\\n\\thack := Form extent: width@1 depth: 32 bits: scanline.\\n\\tform depth = 16 ifTrue:[\\n\\t\\t\\\"Expand 16 -> 32\\\"\\n\\t\\tmiscBlt := BitBlt toForm: hack.\\n\\t\\tmiscBlt sourceForm: form.\\n\\t\\tmiscBlt combinationRule: Form over.\\n\\t\\tmiscBlt destOrigin: 0@0.\\n\\t\\tmiscBlt width: width; height: 1.\\n\\t].\\n\\thackBlt := BitBlt toForm: hack.\\n\\thackBlt sourceForm: (miscBlt ifNil:[form] ifNotNil:[hack]).\\n\\thackBlt combinationRule: Form over.\\n\\thackBlt destOrigin: 0@0.\\n\\thackBlt width: width; height: 1.\\n\\tbigEndian ifTrue:[\\n\\t\\tcm := ColorMap \\n\\t\\t\\tshifts: #(8 8 8 -24) \\n\\t\\t\\tmasks: #(16rFF0000 16rFF00 16rFF 16rFF000000).\\n\\t] ifFalse:[\\n\\t\\tcm := ColorMap \\n\\t\\t\\tshifts: #(-16 0 16 0) \\n\\t\\t\\tmasks: #(16rFF0000 16rFF00 16rFF 16rFF000000).\\n\\t].\\n\\thackBlt colorMap: cm.\\n\\t0 to: height-1 do:[:i|\\n\\t\\tmiscBlt ifNil:[\\n\\t\\t\\thackBlt sourceOrigin: 0@i; copyBits.\\n\\t\\t] ifNotNil:[\\n\\t\\t\\tmiscBlt sourceOrigin: 0@i; copyBits.\\n\\t\\t\\thack fixAlpha.\\n\\t\\t\\thackBlt copyBits.\\n\\t\\t].\\n\\t\\tzStream nextPut: 0. \\\"filterType\\\"\\n\\t\\tzStream nextPutAll: scanline.\\n\\t].\\n\\tzStream close.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPNGReadWriter class\\n\\tinstanceVariableNames: ''!\\n\\n!PNGReadWriter class methodsFor: 'as yet unclassified' stamp: 'ar 2/11/2004 00:54'!\\ncomputeSwizzleMapForDepth: depth\\n\\t\\\"Answer a map that maps pixels in a word to their opposite location. Used for 'middle-endian' forms where the byte-order is different from the bit order (good joke, eh?).\\\"\\n\\t| map swizzled |\\n\\tmap := Bitmap new: 256.\\n\\tdepth = 4 ifTrue:[\\n\\t\\t0 to: 255 do:[:pix|\\n\\t\\t\\tswizzled := 0.\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: 0) bitAnd: 15) bitShift: 4).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -4) bitAnd: 15) bitShift: 0).\\n\\t\\t\\tmap at: pix+1 put: swizzled.\\n\\t\\t].\\n\\t\\t^ColorMap colors: map\\n\\t].\\n\\n\\tdepth = 2 ifTrue:[\\n\\t\\t0 to: 255 do:[:pix|\\n\\t\\t\\tswizzled := 0.\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: 0) bitAnd: 3) bitShift: 6).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -2) bitAnd: 3) bitShift: 4).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -4) bitAnd: 3) bitShift: 2).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -6) bitAnd: 3) bitShift: 0).\\n\\t\\t\\tmap at: pix+1 put: swizzled.\\n\\t\\t].\\n\\t\\t^ColorMap colors: map\\n\\t].\\n\\n\\tdepth = 1 ifTrue:[\\n\\t\\t0 to: 255 do:[:pix|\\n\\t\\t\\tswizzled := 0.\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: 0) bitAnd: 1) bitShift: 7).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -1) bitAnd: 1) bitShift: 6).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -2) bitAnd: 1) bitShift: 5).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -3) bitAnd: 1) bitShift: 4).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -4) bitAnd: 1) bitShift: 3).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -5) bitAnd: 1) bitShift: 2).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -6) bitAnd: 1) bitShift: 1).\\n\\t\\t\\tswizzled := swizzled bitOr: (((pix bitShift: -7) bitAnd: 1) bitShift: 0).\\n\\t\\t\\tmap at: pix+1 put: swizzled.\\n\\t\\t].\\n\\t\\t^ColorMap colors: map\\n\\t].\\n\\tself error: 'Unrecognized depth'! !\\n\\n!PNGReadWriter class methodsFor: 'as yet unclassified' stamp: 'RAA 11/7/2000 09:22'!\\ncreateAFormFrom: data\\n\\n\\t| error f |\\n\\n\\terror _ ''.\\n\\tf _ [\\n\\t\\tself formFromStream: (RWBinaryOrTextStream with: data)\\n\\t] ifError: [ :a :b |\\n\\t\\terror _ a printString,' ',b printString.\\n\\t\\t(StringMorph contents: error) color: Color red; imageForm\\n\\t].\\n\\t^{f. error}! !\\n\\n!PNGReadWriter class methodsFor: 'as yet unclassified' stamp: 'RAA 11/7/2000 09:20'!\\ndebugging: aBoolean\\n\\n\\tDebugging _ aBoolean! !\\n\\n!PNGReadWriter class methodsFor: 'as yet unclassified' stamp: 'ar 2/11/2004 00:55'!\\ninitialize\\n\\t\\\"\\n\\tPNGReadWriter initialize\\n\\t\\\"\\n\\n\\tBPP _ {\\t#(1 2 4 8 16).\\n\\t\\t\\t#(0 0 0 0 0).\\n\\t\\t\\t#(0 0 0 24 48).\\n\\t\\t\\t#(1 2 4 8 0).\\n\\t\\t\\t#(0 0 0 16 32).\\n\\t\\t\\t#(0 0 0 0 0).\\n\\t\\t\\t#(0 0 0 32 64).\\n\\t\\t\\t#(0 0 0 0 0) }.\\n\\n\\tBlockHeight _ #(8 8 4 4 2 2 1).\\n\\tBlockWidth _ #(8 4 4 2 2 1 1).\\n\\n\\tStandardColors := Color indexedColors collect:[:aColor|\\n\\t\\tColor \\n\\t\\t\\tr: (aColor red * 255) truncated / 255\\n\\t\\t\\tg: (aColor green * 255) truncated / 255\\n\\t\\t\\tb: (aColor blue * 255) truncated / 255.\\n\\t].\\n\\n\\tStandardSwizzleMaps := Array new: 4.\\n\\t#(1 2 4) do:[:i| StandardSwizzleMaps at: i put: (self computeSwizzleMapForDepth: i)].! !\\n\\n!PNGReadWriter class methodsFor: 'as yet unclassified' stamp: 'RAA 11/7/2000 09:15'!\\ninsertMorph: aMorph named: aString into: aBook\\n\\n\\t| newPage |\\n\\n\\taBook ifNil: [^self].\\n\\tnewPage _ aBook insertPageLabel: aString morphs: {aMorph}.\\n\\tnewPage color: Color lightYellow.\\n\\tnewPage extent: (\\n\\t\\tnewPage submorphs inject: 10@10 into: [ :ex :m |\\n\\t\\t\\tm left: 10.\\n\\t\\t\\tex max: m width @ m bottom\\n\\t\\t]\\n\\t) + (20@20).\\n! !\\n\\n!PNGReadWriter class methodsFor: 'as yet unclassified' stamp: 'RAA 12/10/2000 10:11'!\\ntest1\\n\\\"PNGReadWriter test1\\\"\\n\\t| data t error d0 d1 f fileInfo book result d2 |\\n\\n\\tDebugging _ true.\\n\\t1 = 1 ifTrue: [\\n\\t\\tbook _ BookMorph new.\\n\\t\\tbook setProperty: #transitionSpec toValue: {'silence'. #none. #none}.\\n\\t].\\n\\td0 _ FileDirectory default.\\n\\td1 _ d0 directoryNamed: 'PngSuite Folder'.\\n\\td2 _ d0 directoryNamed: 'BIG PNG'.\\n\\t{d0. d1. d2}.\\t\\t\\\"keep compiler quiet\\\"\\n\\\"==\\ncitrus_none_sub.png\\ncitrus_adm7_adap.png\\ncitrus_adm7_aver.png\\ncitrus_adm7_non.png\\ncitrus_adm7_paeth.png\\npngs-img-ie5mac.png\\n==\\\"\\n\\tfileInfo _ {\\n\\t\\td2. {'citrus_adm7_adap.png'}.\\n\\t\\t\\\"d1. d1 fileNames.\\\"\\n\\t}.\\n\\tfileInfo pairsDo: [ :dir :fileNames |\\n\\t\\tfileNames do: [ :each |\\n\\t\\t\\tTranscript cr; show: each.\\n\\t\\t\\tdata _ (dir fileNamed: each) contentsOfEntireFile.\\n\\t\\t\\terror _ ''.\\n\\t\\t\\tMessageTally spyOn: [\\n\\t\\t\\t\\tt _ [\\n\\t\\t\\t\\t\\tresult _ self createAFormFrom: data.\\n\\t\\t\\t\\t\\tf_ result first.\\n\\t\\t\\t\\t\\terror _ result second.\\n\\t\\t\\t\\t] timeToRun.].\\n\\t\\t\\tself insertMorph: f asMorph named: each into: book.\\n\\t\\t\\tTranscript show: each,' ',data size printString,' = ',t printString,' ms',error; cr.\\n\\t\\t].\\n\\t].\\n\\tbook ifNotNil: [book openInWorld].\\n\\tDebugging _ false.! !\\n\\n\\n!PNGReadWriter class methodsFor: 'image reading/writing' stamp: 'nk 7/16/2003 17:57'!\\ntypicalFileExtensions\\n\\t\\\"Answer a collection of file extensions (lowercase) which files that I can read might commonly have\\\"\\n\\t^#('png')! !\\nTestCase subclass: #PNGReadWriterTest\\n\\tinstanceVariableNames: 'fileName'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'GraphicsTests-Files'!\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'ar 2/11/2004 00:42'!\\ndrawStuffOn: aForm\\n\\t\\\"Draw stuff on aForm. Avoid any symmetry.\\\"\\n\\t| canvas |\\n\\tcanvas := FormCanvas on: aForm.\\n\\tcanvas frameAndFillRectangle: (1@1 corner: aForm extent - 15) fillColor: Color red borderWidth: 3 borderColor: Color green.\\n\\tcanvas fillOval: (aForm boundingBox topRight - (15@-5) extent: 20@20) color: Color blue borderWidth: 1 borderColor: Color white.\\n\\t^aForm\\n\\t\\\"(PNGReadWriterTest new drawStuffOn: (Form extent: 32@32 depth: 16)) display\\\"! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'ar 2/11/2004 00:42'!\\ndrawTransparentStuffOn: aForm\\n\\t\\\"Draw stuff on aForm. Avoid any symmetry.\\\"\\n\\t| canvas |\\n\\tcanvas := FormCanvas on: aForm.\\n\\tcanvas frameAndFillRectangle: (1@1 corner: aForm extent - 15) fillColor: (Color red alpha: 0.25) borderWidth: 3 borderColor: (Color green alpha: 0.5).\\n\\tcanvas fillOval: (aForm boundingBox topRight - (15@-5) extent: 20@20) color: (Color white alpha: 0.75) borderWidth: 1 borderColor: Color blue.\\n\\t^aForm\\n\\t\\\"(PNGReadWriterTest new drawStuffOn: (Form extent: 32@32 depth: 16)) display\\\"! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'nk 4/17/2004 19:45'!\\nencodeAndDecode: original\\n\\t\\\"Make sure that the given form is encoded and decoded correctly\\\"\\n\\t| stream bytes decoded maxErr |\\n\\t\\\"encode\\\"\\n\\tstream := ByteArray new writeStream.\\n\\t(PNGReadWriter on: stream) nextPutImage: original; close.\\n\\tbytes := stream contents.\\n\\n\\tself writeEncoded: bytes.\\n\\n\\t\\\"decode\\\"\\n\\tstream := self readEncoded: bytes.\\n\\tdecoded := (PNGReadWriter new on: stream) nextImage.\\n\\tdecoded display.\\n\\n\\t\\\"compare\\\"\\n\\tself assert: original width = decoded width.\\n\\tself assert: original height = decoded height.\\n\\tself assert: original depth = decoded depth.\\n\\tself assert: original bits = decoded bits.\\n\\tself assert: original class == decoded class.\\n\\t(original isColorForm) ifTrue:[\\n\\t\\toriginal colors with: decoded colors do:[:c1 :c2|\\n\\t\\t\\t\\\"we must round here due to encoding errors\\\"\\n\\t\\t\\tmaxErr := 1. \\\"max. error for 8bit rgb component\\\"\\n\\t\\t\\tself assert: ((c1 red * 255) truncated - (c2 red * 255) truncated) abs <= maxErr.\\n\\t\\t\\tself assert: ((c1 green * 255) truncated - (c2 green * 255) truncated) abs <= maxErr.\\n\\t\\t\\tself assert: ((c1 blue * 255) truncated - (c2 blue * 255) truncated) abs <= maxErr.\\n\\t\\t\\tself assert: ((c1 alpha * 255) truncated - (c2 alpha * 255) truncated) abs <= maxErr.\\n\\t\\t].\\n\\t].! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'ar 2/12/2004 22:49'!\\nencodeAndDecodeAlpha: original\\n\\tfileName := 'testAlpha', original depth printString,'.png'.\\n\\tself encodeAndDecode: original.! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'ar 2/18/2004 23:49'!\\nencodeAndDecodeColor: aColor depth: aDepth\\n\\t| aForm |\\n\\tfileName := 'testColor', aColor name, aDepth printString,'.png'.\\n\\taForm := Form extent: 32@32 depth: aDepth.\\n\\taForm fillColor: aColor.\\n\\tself encodeAndDecode: aForm.\\n! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'nk 2/17/2004 11:02'!\\nencodeAndDecodeDisplay: depth\\n\\t| form |\\n\\tfileName := 'testDisplay', depth printString,'.png'.\\n\\tform := Form extent: (Display extent min: 560@560) depth: depth.\\n\\tSmalltalk isMorphic \\n\\t\\tifTrue:[World fullDrawOn: form getCanvas]\\n\\t\\tifFalse:[Display displayOn: form].\\n\\tself encodeAndDecode: form.! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'ar 2/12/2004 22:50'!\\nencodeAndDecodeForm: original\\n\\tfileName := 'testForm', original depth printString,'.png'.\\n\\tself encodeAndDecode: original.! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'nk 4/17/2004 19:45'!\\nencodeAndDecodeReverse: original\\n\\t\\\"Make sure that the given form is encoded and decoded correctly\\\"\\n\\t| stream bytes decoded maxErr reversed |\\n\\tfileName := 'testReverse', original depth printString,'.png'.\\n\\tself assert: original class == Form. \\\"won't work with ColorForm\\\"\\n\\t\\\"Switch pixel order\\\"\\n\\treversed := Form extent: original extent depth: original depth negated.\\n\\toriginal displayOn: reversed.\\n\\tself assert: original width = reversed width.\\n\\tself assert: original height = reversed height.\\n\\tself assert: original depth = reversed depth.\\n\\tself deny: original nativeDepth = reversed nativeDepth.\\n\\toriginal depth = 32\\n\\t\\tifTrue:[self assert: original bits = reversed bits]\\n\\t\\tifFalse:[self deny: original bits = reversed bits].\\n\\n\\t\\\"encode\\\"\\n\\tstream := ByteArray new writeStream.\\n\\t(PNGReadWriter on: stream) nextPutImage: reversed; close.\\n\\tbytes := stream contents.\\n\\tself writeEncoded: bytes.\\n\\n\\t\\\"decode\\\"\\n\\tstream := bytes readStream.\\n\\tdecoded := (PNGReadWriter new on: stream) nextImage.\\n\\tdecoded display.\\n\\n\\t\\\"compare\\\"\\n\\tself assert: original width = decoded width.\\n\\tself assert: original height = decoded height.\\n\\tself assert: original depth = decoded depth.\\n\\tself assert: original bits = decoded bits.\\n\\tself assert: original class == decoded class.\\n\\t(original isColorForm) ifTrue:[\\n\\t\\toriginal colors with: decoded colors do:[:c1 :c2|\\n\\t\\t\\t\\\"we must round here due to encoding errors\\\"\\n\\t\\t\\tmaxErr := 1. \\\"max. error for 8bit rgb component\\\"\\n\\t\\t\\tself assert: ((c1 red * 255) truncated - (c2 red * 255) truncated) abs <= maxErr.\\n\\t\\t\\tself assert: ((c1 green * 255) truncated - (c2 green * 255) truncated) abs <= maxErr.\\n\\t\\t\\tself assert: ((c1 blue * 255) truncated - (c2 blue * 255) truncated) abs <= maxErr.\\n\\t\\t\\tself assert: ((c1 alpha * 255) truncated - (c2 alpha * 255) truncated) abs <= maxErr.\\n\\t\\t].\\n\\t].! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'nk 2/17/2004 18:18'!\\nencodeAndDecodeStream: file\\n\\t| aForm |\\n\\tfile reset.\\n\\t(PNGReadWriter new on: file) understandsImageFormat ifFalse:[^self error: 'don''t understand format!!' ].\\n\\tfile reset.\\n\\taForm := (PNGReadWriter new on: file) nextImage.\\n\\taForm ifNil:[^self error: 'nil form' ].\\n\\taForm display.\\n\\tself encodeAndDecode: aForm.\\n! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'ar 2/12/2004 22:36'!\\nencodeAndDecodeWithColors: aColorForm\\n\\t\\\"Screw around with aColorForm colors\\\"\\n\\t| colors nColors indexedColors max myRandom |\\n\\tfileName := 'testColors', aColorForm depth printString,'.png'.\\n\\tindexedColors := Color indexedColors.\\n\\tnColors := 1 bitShift: aColorForm depth.\\n\\tcolors := WriteStream on: Array new.\\n\\n\\t\\\"Make first half translucent\\\"\\n\\tmax := nColors // 2.\\n\\t1 to: max do:[:i|\\n\\t\\tcolors nextPut: ((indexedColors at: i) alpha: i / max asFloat).\\n\\t].\\n\\n\\t\\\"Make random choices for second half\\\"\\n\\tmyRandom := Random seed: 42315.\\n\\tmax to: nColors do:[:i|\\n\\t\\tcolors nextPut: (indexedColors atRandom: myRandom).\\n\\t].\\n! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'ar 2/29/2004 03:55'!\\nencodeAndDecodeWithError: aStream\\n\\tself should:[self encodeAndDecodeStream: aStream] raise: Error! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'nk 2/17/2004 11:10'!\\nreadEncoded: bytes\\n\\t\\\"Answer a ReadStream on the file named by fileName, if possible; else a ReadStream on bytes\\\"\\n\\n\\tfileName ifNil:[^ bytes readStream ].\\n\\t^(FileStream oldFileOrNoneNamed: fileName) ifNil: [ \\n\\t\\tTranscript nextPutAll: 'can''t open ', fileName; cr.\\n\\t\\tbytes readStream ].\\n! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'ar 2/12/2004 22:45'!\\nsetUp\\n\\tfileName := nil.! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'nk 2/17/2004 11:29'!\\ntearDown\\n\\tWorld changed.! !\\n\\n!PNGReadWriterTest methodsFor: 'helpers' stamp: 'ar 2/12/2004 22:51'!\\nwriteEncoded: bytes\\n\\t| file |\\n\\tfileName ifNil:[^self].\\n\\tfalse ifTrue:[^self].\\n\\tfile := FileStream forceNewFileNamed: fileName.\\n\\t[file nextPutAll: bytes] ensure:[file close].! !\\n\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/12/2004 22:50'!\\ntest16Bit\\n\\tself encodeAndDecodeForm: (self drawStuffOn: (Form extent: 33@33 depth: 16))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:39'!\\ntest16BitDisplay\\n\\tself encodeAndDecodeDisplay: 16! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 01:57'!\\ntest16BitReversed\\n\\tself encodeAndDecodeReverse: (self drawStuffOn: (Form extent: 33@33 depth: 16))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/12/2004 22:50'!\\ntest1Bit\\n\\tself encodeAndDecodeForm: (self drawStuffOn: (Form extent: 33@33 depth: 1))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:43'!\\ntest1BitColors\\n\\tself encodeAndDecodeWithColors: (self drawStuffOn: (Form extent: 33@33 depth: 1))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:39'!\\ntest1BitDisplay\\n\\tself encodeAndDecodeDisplay: 1! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 01:56'!\\ntest1BitReversed\\n\\tself encodeAndDecodeReverse: (self drawStuffOn: (Form extent: 33@33 depth: 1))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/12/2004 22:50'!\\ntest2Bit\\n\\tself encodeAndDecodeForm: (self drawStuffOn: (Form extent: 33@33 depth: 2))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:43'!\\ntest2BitColors\\n\\tself encodeAndDecodeWithColors: (self drawStuffOn: (Form extent: 33@33 depth: 2))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:39'!\\ntest2BitDisplay\\n\\tself encodeAndDecodeDisplay: 2! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 01:56'!\\ntest2BitReversed\\n\\tself encodeAndDecodeReverse: (self drawStuffOn: (Form extent: 33@33 depth: 2))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/12/2004 22:50'!\\ntest32Bit\\n\\tself encodeAndDecodeForm: (self drawStuffOn: (Form extent: 33@33 depth: 32))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:39'!\\ntest32BitDisplay\\n\\tself encodeAndDecodeDisplay: 32! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 01:57'!\\ntest32BitReversed\\n\\tself encodeAndDecodeReverse: (self drawStuffOn: (Form extent: 33@33 depth: 32))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/12/2004 22:50'!\\ntest4Bit\\n\\tself encodeAndDecodeForm: (self drawStuffOn: (Form extent: 33@33 depth: 4))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:44'!\\ntest4BitColors\\n\\tself encodeAndDecodeWithColors: (self drawStuffOn: (Form extent: 33@33 depth: 4))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:39'!\\ntest4BitDisplay\\n\\tself encodeAndDecodeDisplay: 4! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 01:56'!\\ntest4BitReversed\\n\\tself encodeAndDecodeReverse: (self drawStuffOn: (Form extent: 33@33 depth: 4))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/12/2004 22:50'!\\ntest8Bit\\n\\tself encodeAndDecodeForm: (self drawStuffOn: (Form extent: 33@33 depth: 8))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:44'!\\ntest8BitColors\\n\\tself encodeAndDecodeWithColors: (self drawStuffOn: (Form extent: 33@33 depth: 8))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 00:39'!\\ntest8BitDisplay\\n\\tself encodeAndDecodeDisplay: 8! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/11/2004 01:57'!\\ntest8BitReversed\\n\\tself encodeAndDecodeReverse: (self drawStuffOn: (Form extent: 33@33 depth: 8))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/12/2004 22:49'!\\ntestAlphaCoding\\n\\tself encodeAndDecodeAlpha: (self drawTransparentStuffOn: (Form extent: 33@33 depth: 32))! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - bits' stamp: 'ar 2/29/2004 03:55'!\\ntestPngSuite\\n\\t\\\"Requires the suite from \\n\\t\\tftp://swrinde.nde.swri.edu/pub/png/images/suite/PngSuite.zip\\n\\tto be present as PngSuite.zip\\\"\\n\\t| file zip entries |\\n\\t[file := FileStream readOnlyFileNamed: 'PngSuite.zip'] on: Error do:[:ex| ex return].\\n\\tfile ifNil:[^self].\\n\\t[zip := ZipArchive new readFrom: file.\\n\\tentries := zip members select:[:mbr| mbr fileName asLowercase endsWith: '.png'].\\n\\tentries do:[:mbr| \\n\\t\\t(mbr fileName asLowercase first = $x)\\n\\t\\t\\tifTrue: [self encodeAndDecodeWithError: mbr contentStream ]\\n\\t\\t\\tifFalse: [self encodeAndDecodeStream: mbr contentStream ] ].\\n\\t] ensure:[file close].! !\\n\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:50'!\\ntestBlack16\\n\\tself encodeAndDecodeColor: Color blue depth: 16! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:50'!\\ntestBlack32\\n\\tself encodeAndDecodeColor: Color blue depth: 32! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:50'!\\ntestBlack8\\n\\tself encodeAndDecodeColor: Color blue depth: 8! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:50'!\\ntestBlue16\\n\\tself encodeAndDecodeColor: Color blue depth: 16! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:50'!\\ntestBlue32\\n\\tself encodeAndDecodeColor: Color blue depth: 32! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:50'!\\ntestBlue8\\n\\tself encodeAndDecodeColor: Color blue depth: 8! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:50'!\\ntestGreen16\\n\\tself encodeAndDecodeColor: Color green depth: 16! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:50'!\\ntestGreen32\\n\\tself encodeAndDecodeColor: Color green depth: 32! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:49'!\\ntestGreen8\\n\\tself encodeAndDecodeColor: Color green depth: 8! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:49'!\\ntestRed16\\n\\tself encodeAndDecodeColor: Color red depth: 16! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:48'!\\ntestRed32\\n\\tself encodeAndDecodeColor: Color red depth: 32! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - colors' stamp: 'ar 2/18/2004 23:49'!\\ntestRed8\\n\\tself encodeAndDecodeColor: Color red depth: 8! !\\n\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:25'!\\ncoloredFiles16\\n\\t\\\"Created by\\n\\t\\t{Color red. Color green. Color blue. Color black} collect:[:fillC|\\n\\t\\t\\t| ff bytes |\\n\\t\\t\\tff := Form extent: 32@32 depth: 16.\\n\\t\\t\\tff fillColor: fillC.\\n\\t\\t\\tbytes := WriteStream on: ByteArray new.\\n\\t\\t\\tPNGReadWriter putForm: ff onStream: bytes.\\n\\t\\t\\tfillC ->\\n\\t\\t\\t\\t(Base64MimeConverter mimeEncode: (bytes contents readStream)) contents\\n\\t\\t].\\n\\t\\\"\\n\\t^{Color red-> \\n'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQFBQUBSsjp7wAAADZJ\\nREFUeF7lziEBAAAMAjD6J8b9MRAT80uT65Af8AN+wA/4AT/gB/yAH/ADfsAP+AE/4AfmgQdc\\nz9xqBS2pdAAAAABJRU5ErkJggg=='.\\n\\tColor green->\\n'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQFBQUBSsjp7wAAADVJ\\nREFUeF7lziEBAAAMAjD6J77jMRAT80sunfIDfsAP+AE/4Af8gB/wA37AD/gBP+AH/MA68HyT\\n3Gqf2I6NAAAAAElFTkSuQmCC'.\\n\\t\\tColor blue->\\n'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQFBQUBSsjp7wAAADVJ\\nREFUeF7lziEBAAAMAjD6J77jMRAT80ty3fIDfsAP+AE/4Af8gB/wA37AD/gBP+AH/MA48JxX\\n3GpYhihrAAAAAElFTkSuQmCC'.\\n\\tColor black->\\n'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQFBQUBSsjp7wAAADVJ\\nREFUeF7lziEBAAAMAjDk+xfmMRAT80ty3fIDfsAP+AE/4Af8gB/wA37AD/gBP+AH/MA48LbT\\nHD3MKH3GAAAAAElFTkSuQmCC'\\n}! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:24'!\\ncoloredFiles32\\n\\t\\\"Created by\\n\\t\\t{Color red. Color green. Color blue. Color black} collect:[:fillC|\\n\\t\\t\\t| ff bytes |\\n\\t\\t\\tff := Form extent: 32@32 depth: 32.\\n\\t\\t\\tff fillColor: fillC.\\n\\t\\t\\tbytes := WriteStream on: ByteArray new.\\n\\t\\t\\tPNGReadWriter putForm: ff onStream: bytes.\\n\\t\\t\\tfillC ->\\n\\t\\t\\t\\t(Base64MimeConverter mimeEncode: (bytes contents readStream)) contents\\n\\t\\t].\\n\\t\\\"\\n\\t^{\\n\\t\\tColor red -> 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAANUlEQVR4XuXOIQEAAAwEoe9f\\n+hZjAoFnbfVo+QE/4Af8gB/wA37AD/gBP+AH/IAf8AN+4DlwVA34ajP6EEoAAAAASUVORK5C\\nYII='.\\n\\t\\tColor green -> 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAM0lEQVR4XuXOMQ0AAAACIPuX\\n1hgejAIkPfMDfsAP+AE/4Af8gB/wA37AD/gBP+AH/MA7MFfR+Grvv2BdAAAAAElFTkSuQmCC'.\\n\\n\\tColor blue->\\n'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAANElEQVR4XuXOIQEAAAACIP+f\\n1hkGAp0k7Zcf8AN+wA/4AT/gB/yAH/ADfsAP+AE/4AfOgQFblfhqnnPWHAAAAABJRU5ErkJg\\ngg=='.\\n\\t\\tColor black -> 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAANUlEQVR4XuXOMQEAAAwCINc/\\ntIvhwcFPkuuWH/ADfsAP+AE/4Af8gB/wA37AD/gBP+AHxoEH95UAPU59TTMAAAAASUVORK5C\\nYII='\\n}! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:19'!\\ncoloredFiles8\\n\\t\\\"Created by\\n\\t\\t{Color red. Color green. Color blue. Color black} collect:[:fillC|\\n\\t\\t\\t| ff bytes |\\n\\t\\t\\tff := Form extent: 32@32 depth: 8.\\n\\t\\t\\tff fillColor: fillC.\\n\\t\\t\\tbytes := WriteStream on: ByteArray new.\\n\\t\\t\\tPNGReadWriter putForm: ff onStream: bytes.\\n\\t\\t\\tfillC ->\\n\\t\\t\\t\\t(Base64MimeConverter mimeEncode: (bytes contents readStream)) contents\\n\\t\\t].\\n\\t\\\"\\n\\t^{Color red->\\n'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAADAFBMVEX///8AAAD///9/f3//\\nAAAA/wAAAP8A/////wD/AP8fHx8/Pz9fX1+fn5+/v7/f398HBwcPDw8XFxcnJycvLy83NzdH\\nR0dPT09XV1dnZ2dvb293d3eHh4ePj4+Xl5enp6evr6+3t7fHx8fPz8/X19fn5+fv7+/39/cA\\nAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UA\\nAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8y\\nAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2Uy\\nAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9l\\nAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2Vl\\nAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+Y\\nAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WY\\nAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///L\\nAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XL\\nAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////\\nAAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/ZWX/mGX/y2X//2X/\\nAJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8v/AP//Mv//Zf//mP//y/////9E\\nCiHUAAAAGklEQVR4XmO4cwc/YLgz8hWMfAUjX8EIVQAAbnlwLukXXkcAAAAASUVORK5CYII='.\\n\\n\\tColor green->\\n'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAADAFBMVEX///8AAAD///9/f3//\\nAAAA/wAAAP8A/////wD/AP8fHx8/Pz9fX1+fn5+/v7/f398HBwcPDw8XFxcnJycvLy83NzdH\\nR0dPT09XV1dnZ2dvb293d3eHh4ePj4+Xl5enp6evr6+3t7fHx8fPz8/X19fn5+fv7+/39/cA\\nAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UA\\nAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8y\\nAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2Uy\\nAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9l\\nAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2Vl\\nAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+Y\\nAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WY\\nAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///L\\nAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XL\\nAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////\\nAAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/ZWX/mGX/y2X//2X/\\nAJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8v/AP//Mv//Zf//mP//y/////9E\\nCiHUAAAAGUlEQVR4XmPQ1cUPGHRHvoKRr2DkKxihCgBZ3bQBCq5u/AAAAABJRU5ErkJggg=='.\\n\\n\\tColor blue->\\n'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAADAFBMVEX///8AAAD///9/f3//\\nAAAA/wAAAP8A/////wD/AP8fHx8/Pz9fX1+fn5+/v7/f398HBwcPDw8XFxcnJycvLy83NzdH\\nR0dPT09XV1dnZ2dvb293d3eHh4ePj4+Xl5enp6evr6+3t7fHx8fPz8/X19fn5+fv7+/39/cA\\nAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UA\\nAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8y\\nAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2Uy\\nAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9l\\nAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2Vl\\nAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+Y\\nAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WY\\nAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///L\\nAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XL\\nAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////\\nAAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/ZWX/mGX/y2X//2X/\\nAJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8v/AP//Mv//Zf//mP//y/////9E\\nCiHUAAAAGUlEQVR4XmNwc8MPGNxGvoKRr2DkKxihCgCl7xgQRbPxcwAAAABJRU5ErkJggg=='.\\n\\n\\tColor black->\\n'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAADAFBMVEX///8AAAD///9/f3//\\nAAAA/wAAAP8A/////wD/AP8fHx8/Pz9fX1+fn5+/v7/f398HBwcPDw8XFxcnJycvLy83NzdH\\nR0dPT09XV1dnZ2dvb293d3eHh4ePj4+Xl5enp6evr6+3t7fHx8fPz8/X19fn5+fv7+/39/cA\\nAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UA\\nAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8y\\nAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2Uy\\nAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9l\\nAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2Vl\\nAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+Y\\nAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WY\\nAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///L\\nAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XL\\nAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////\\nAAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/ZWX/mGX/y2X//2X/\\nAJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8v/AP//Mv//Zf//mP//y/////9E\\nCiHUAAAAGUlEQVR4XmNgZMQPGBhHvoKRr2DkKxihCgBEmAQBphO0cAAAAABJRU5ErkJggg=='\\n}! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:25'!\\ndecodeColors: colorsAndFiles depth: requiredDepth\\n\\t| color bytes form |\\n\\tcolorsAndFiles do:[:assoc|\\n\\t\\tcolor := assoc key.\\n\\t\\tbytes := Base64MimeConverter mimeDecodeToBytes: assoc value readStream.\\n\\t\\tform := PNGReadWriter formFromStream: bytes.\\n\\t\\tself assert: form depth = requiredDepth.\\n\\t\\tself assert: (form pixelValueAt: 1@1) = (color pixelValueForDepth: requiredDepth).\\n\\t].! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:30'!\\nencodeColors: colorsAndFiles depth: requiredDepth\\n\\t| color original ff encoded |\\n\\tcolorsAndFiles do:[:assoc|\\n\\t\\tcolor := assoc key.\\n\\t\\toriginal := Base64MimeConverter mimeDecodeToBytes: assoc value readStream.\\n\\t\\tff := Form extent: 32@32 depth: requiredDepth.\\n\\t\\tff fillColor: color.\\n\\t\\tencoded := WriteStream on: ByteArray new.\\n\\t\\tPNGReadWriter putForm: ff onStream: encoded.\\n\\t\\tself assert: (encoded contents = original contents).\\n\\t].! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:20'!\\ntestPngDecodingColors16\\n\\tself decodeColors: self coloredFiles16 depth: 16.! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:20'!\\ntestPngDecodingColors32\\n\\tself decodeColors: self coloredFiles32 depth: 32.! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:20'!\\ntestPngDecodingColors8\\n\\tself decodeColors: self coloredFiles8 depth: 8.! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:28'!\\ntestPngEncodingColors16\\n\\tself encodeColors: self coloredFiles16 depth: 16.! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:28'!\\ntestPngEncodingColors32\\n\\tself encodeColors: self coloredFiles32 depth: 32.! !\\n\\n!PNGReadWriterTest methodsFor: 'tests - decoding' stamp: 'ar 2/19/2004 00:28'!\\ntestPngEncodingColors8\\n\\tself encodeColors: self coloredFiles8 depth: 8.! !\\nImageReadWriter subclass: #PNMReadWriter\\n\\tinstanceVariableNames: 'first type origin cols rows depth maxValue tupleType pragma'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Graphics-Files'!\\n!PNMReadWriter commentStamp: 'jdr 10/20/2003 17:08' prior: 0!\\nI am a subclass of ImageReadWriter that decodes portable anymap file formats\\n(pbm, pgm, ppm and pam) images.\\n\\nI accept the #origin pragma for SE files as described in:\\nAlgoritms For Image Processing And Computer Vision. J. R. Parker\\n\\nDon't work with 2 bytes samples (16 bit grays, > 32 bits color, etc...), \\npam files preliminary support.\\n\\nf _ ImageReadWriter formFromFileNamed: 'Tools:Squeak3.4:Carmen.ppm'.\\nf morphEdit\\n\\nSubmitted by Javier Diaz Reinoso, Oct/2003!\\n]style[(361 18 2 26 3 11 1 43)f1,cblack;f1,f1b,f1,f1b,f1,f1b,f1!\\n\\n\\n!PNMReadWriter methodsFor: 'accessing' stamp: 'jdr 10/16/2003 14:52'!\\norigin\\n\\t^origin! !\\n\\n!PNMReadWriter methodsFor: 'accessing' stamp: 'jdr 10/15/2003 15:35'!\\npragma: s\\n\\tpragma _ s! !\\n\\n!PNMReadWriter methodsFor: 'accessing' stamp: 'jdr 10/10/2003 18:04'!\\nstream: s\\n\\tstream _ s! !\\n\\n!PNMReadWriter methodsFor: 'accessing' stamp: 'jdr 10/16/2003 14:53'!\\ntupleType\\n\\t^tupleType! !\\n\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/16/2003 17:19'!\\ncleanLine\\n\\t\\\"upTo LF or CR, tab as space\\\"\\n\\n\\t| line loop b |\\n\\tline _ WriteStream with: ''.\\n\\tloop _ true.\\n\\t[loop] whileTrue: [\\n\\t\\tb _ stream next.\\n\\t\\tb ifNil:[\\n\\t\\t\\tloop _ false\\t\\t\\\"EOS\\\"\\n\\t\\t]\\n\\t\\tifNotNil: [\\n\\t\\t\\t(b = (Character cr) or:[b = Character lf]) ifTrue:[\\n\\t\\t\\t\\tloop _ false.\\n\\t\\t\\t]\\n\\t\\t\\tifFalse:[\\n\\t\\t\\t\\tb = (Character tab) ifTrue:[b _ Character space].\\n\\t\\t\\t\\tline nextPut: b.\\n\\t\\t\\t]\\n\\t\\t]\\n\\t].\\n\\t^line contents! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/15/2003 12:20'!\\ngetTokenPbm: aCollection\\n\\t\\\"get a number, return rest of collection\\\"\\n\\t| line tokens token |\\n\\ttokens _ aCollection.\\n\\ttokens size = 0 ifTrue:[\\n\\t\\t[\\n\\t\\t\\tline _ self pbmGetLine.\\n\\t\\t\\tline ifNil:[^{nil . nil}].\\n\\t\\t\\ttokens _ line findTokens: ' '.\\n\\t\\t\\ttokens size = 0\\n\\t\\t] whileTrue:[].\\n\\t].\\n\\t\\\"Transcript cr; show: tokens asString.\\\"\\n\\ttoken _ tokens removeFirst.\\n\\t^{token asInteger . tokens}\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/16/2003 16:39'!\\nnextImage\\n\\t\\\"read one image\\\"\\n\\t| data p |\\n\\tfirst ifNil:[\\n\\t\\tfirst _ false.\\n\\t\\tdata _ stream contentsOfEntireFile.\\n\\t\\tstream _ (RWBinaryOrTextStream with: data) reset.\\n\\t]\\n\\tifNotNil:[\\n\\t\\ttype < 4 ifTrue:[\\n\\t\\t\\tself error:'Plain PBM, PGM or PPM have only one image'\\n\\t\\t].\\n\\t].\\n\\tstream ascii.\\n\\tp _ stream next.\\n\\ttype _ (stream next) asInteger - 48.\\n\\t(p = $P and:[type > 0 and:[type < 8]]) ifFalse:[\\n\\t\\tself error:'Not a PNM file'\\n\\t].\\n\\ttype = 7 ifTrue:[\\n\\t\\tself readHeaderPAM\\n\\t]\\n\\tifFalse: [\\n\\t\\tself readHeader\\n\\t].\\n\\ttype caseOf: {\\n\\t\\t[1] \\t->\\t[^self readPlainBW].\\n\\t\\t[2] \\t->\\t[^self readPlainGray].\\n\\t\\t[3] \\t->\\t[^self readPlainRGB].\\n\\t\\t[4] \\t->\\t[^self readBWreverse: false].\\n\\t\\t[5] \\t->\\t[^self readGray].\\n\\t\\t[6] \\t->\\t[^self readRGB].\\n\\t\\t[7] \\t->\\t[\\t\\\"PAM\\\"\\n\\t\\t\\t\\t\\t(tupleType asUppercase) caseOf: {\\n\\t\\t\\t\\t\\t\\t['BLACKANDWHITE'] \\t\\t-> [^self readBWreverse: true].\\n\\t\\t\\t\\t\\t\\t['GRAYSCALE'] \\t\\t\\t-> [^self readGray].\\n\\t\\t\\t\\t\\t\\t['RGB'] \\t\\t\\t\\t\\t-> [^self readRGB].\\n\\t\\t\\t\\t\\t\\t['RGB_ALPHA'] \\t\\t\\t-> [^self error:'Not implemented'].\\n\\t\\t\\t\\t\\t\\t['GRAYSCALE_ALPHA'] \\t-> [^self error:'Not implemented'].\\n\\t\\t\\t\\t\\t} otherwise: [^self readData].\\n\\t\\t\\t\\t]\\n\\t}! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/10/2003 15:09'!\\npbmGetLine\\n\\t\\\"Get the next non-comment line from the PBM stream\\n\\tLook for 'pragmas' - commands hidden in the comments\\\"\\n\\t\\n \\t| line |\\n\\t[\\n\\t\\tline _ self cleanLine.\\n\\t\\tline ifNil: [^nil].\\n\\t\\t(line size > 0 and:[(line at: 1) = $#]) ifTrue:[\\n\\t\\t\\tself pbmParam: line.\\n\\t\\t].\\n\\t\\t(line size = 0) or:[(line at: 1) = $#]\\n\\t]\\n \\twhileTrue: [].\\n\\t^line! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/10/2003 15:11'!\\npbmParam: line\\n\\t\\\"Look for a parameter hidden in a comment\\\"\\n\\t| key tokens |\\n\\ttokens _ line findTokens: ' '.\\n\\tkey _ (tokens at: 1) asLowercase.\\n\\t(key = '#origin' and:[tokens size = 3]) ifTrue:[\\t\\\"ORIGIN key word\\\"\\n\\t\\t\\\"This is for SE files as described in:\\n\\t\\tAlgoritms For Image Processing And Computer Vision. J. R. Parker\\\"\\n\\t\\torigin _ ((tokens at: 2) asInteger) @ ((tokens at: 3) asInteger)\\n\\t].\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 7/18/2005 17:02'!\\nr: r g: g b: b for: aDepth\\n\\t\\\"integer value according depth\\\"\\n\\t| val |\\n\\taDepth = 16 ifTrue: [\\n\\t\\tval := (1 << 15) + (r << 10) + (g << 5) + b.\\n\\t]\\n\\tifFalse:[\\n\\t\\tval := (16rFF << 24) + (r << 16) + (g << 8) + b.\\n\\t].\\n\\t^val\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/16/2003 15:49'!\\nreadBWreverse: flagXor\\n\\t\\\"B&W for PAM\\\"\\n\\t| val form bytesRow nBytes |\\n\\tstream binary.\\n\\tform _ Form extent: cols@rows depth: 1.\\n\\tnBytes _ (cols/8) ceiling.\\n\\tbytesRow _ (cols/32) ceiling * 4.\\n\\t0 to: rows-1 do: [:y | | i |\\n\\t\\ti _ 1 + (bytesRow*y).\\n\\t\\t0 to: nBytes-1 do: [:x |\\n\\t\\t\\tval _ stream next.\\n\\t\\t\\tflagXor ifTrue:[val _ val bitXor: 16rFF].\\n\\t\\t\\tform bits byteAt: i put: val.\\n\\t\\t\\ti _ i+1.\\n\\t\\t]\\n\\t].\\n\\t^form\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'md 10/20/2004 15:45'!\\nreadData\\n\\t\\\"generic data\\\"\\n\\t| data nBits nBytes val sample |\\n\\tstream binary.\\n\\tdata _ OrderedCollection new.\\n\\tnBits _ maxValue floorLog:2.\\n\\tnBytes _ (nBits+1) >> 3.\\n\\t(nBits+1 rem: 8) > 0 ifTrue:[nBytes _ nBytes+1].\\n\\n\\t0 to: rows-1 do: [:y |\\n\\t\\t0 to: cols-1 do: [:x |\\n\\t\\t\\tval _ 0.\\n\\t\\t\\t1 to: nBytes do: [:n |\\n\\t\\t\\t\\tsample _ stream next.\\n\\t\\t\\t\\tval _ val << 8 + sample.\\n\\t\\t\\t].\\n\\t\\t\\tdata add: val.\\n\\t\\t]\\n\\t].\\n\\t^data\\n\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/16/2003 15:44'!\\nreadGray\\n\\t\\\"gray form\\\"\\n\\t| val form poker |\\n\\tmaxValue > 255 ifTrue:[self error:'Gray value > 8 bits not supported in Squeak'].\\n\\tstream binary.\\n\\tform _ Form extent: cols@rows depth: depth.\\n\\tpoker _ BitBlt current bitPokerToForm: form.\\n\\t0 to: rows-1 do: [:y |\\n\\t\\t0 to: cols-1 do: [:x |\\n\\t\\t\\tval _ stream next.\\n\\t\\t\\tpoker pixelAt: x@y put: val.\\n\\t\\t]\\n\\t].\\n\\t^form\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/15/2003 15:44'!\\nreadHeader\\n\\t\\\"read header for pbm, pgm or ppm\\\"\\n\\t| tokens aux d c |\\n\\ttokens _ OrderedCollection new.\\n\\taux _ self getTokenPbm: tokens.\\n\\tcols _ aux at: 1. tokens _ aux at: 2.\\n\\taux _ self getTokenPbm: tokens.\\n\\trows _ aux at: 1. tokens _ aux at: 2.\\n\\n\\t(type = 1 or:[type = 4]) ifTrue:[\\n\\t\\tmaxValue _ 1\\n\\t]\\n\\tifFalse: [\\n\\t\\taux _ self getTokenPbm: tokens.\\n\\t\\tmaxValue _ aux at: 1. tokens _ aux at: 2.\\n\\t].\\n\\td _ {1 . 2 . 4 . \\t8 . \\t\\t16 . 32}.\\n\\tc _ {2 . 4 . 16 . 256 . 32768 . 16777216}. \\n\\t(type = 3 or:[type = 6]) ifTrue: [\\n\\t\\tmaxValue >= 65536 ifTrue:[\\n\\t\\t\\tself error:'Pixmap > 48 bits not supported in PPM'\\n\\t\\t].\\n\\t\\tmaxValue >= 256 ifTrue:[\\n\\t\\t\\tself error:'Pixmap > 32 bits are not supported in Squeak'\\n\\t\\t].\\n\\t\\tmaxValue < 32 ifTrue:[depth _ 16] ifFalse:[depth _ 32].\\n\\t]\\n\\tifFalse: [\\n\\t\\tdepth _ nil.\\n\\t\\t1 to: c size do:[:i| ((c at: i) > maxValue and:[depth = nil]) ifTrue:[depth_d at: i]].\\n\\t].\\n\\tTranscript cr; show: 'PBM file class ', type asString, ' size ', cols asString, ' x ', \\n\\t\\trows asString, ' maxValue =', maxValue asString, ' depth=', depth asString.\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/15/2003 12:35'!\\nreadHeaderPAM\\n\\t\\\"read pam header, not tested\\\"\\n\\t| loop line tokens key val |\\n\\ttupleType _ ''.\\n\\tloop _ true.\\n\\tloop whileTrue:[\\n\\t\\tline _ self pbmGetLine.\\n\\t\\ttokens _ line findTokens: ' '.\\n\\t\\ttokens size = 2 ifTrue:[\\n\\t\\t\\tkey _ tokens at: 1 asUppercase.\\n\\t\\t\\tval _ tokens at: 2.\\n\\t\\t\\tkey caseOf: {\\n\\t\\t\\t\\t['WIDTH'] \\t\\t-> [cols _ val asInteger].\\n\\t\\t\\t\\t['HEIGHT'] \\t\\t-> [rows _ val asInteger].\\n\\t\\t\\t\\t['DEPTH'] \\t\\t-> [depth _ val asInteger].\\n\\t\\t\\t\\t['MAXVAL']\\t\\t-> [maxValue _ val asInteger].\\n\\t\\t\\t\\t['TUPLETYPE']\\t-> [tupleType _ tupleType, ' ', val].\\n\\t\\t\\t\\t['ENDHDR']\\t\\t-> [loop _ false].\\n\\t\\t\\t}\\n\\t\\t]\\n\\t].\\n\\tTranscript cr; show: 'PAM file class ', type asString, ' size ', cols asString, ' x ', \\n\\t\\trows asString, ' maxValue =', maxValue asString, ' depth=', depth asString.\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/16/2003 16:03'!\\nreadPlainBW\\n\\t\\\"plain BW\\\"\\n\\t| val form poker |\\n\\tform _ Form extent: cols@rows depth: depth.\\n\\tpoker _ BitBlt current bitPokerToForm: form.\\n\\t0 to: rows-1 do: [:y |\\n\\t\\t0 to: cols-1 do: [:x |\\n\\t\\t\\t[val _ stream next. (val = $0 or:[val = $1])] whileFalse:[\\n\\t\\t\\t\\tval ifNil:[self error:'End of file reading PBM'].\\n\\t\\t\\t].\\n\\t\\t\\tpoker pixelAt: x@y put: (val asInteger).\\n\\t\\t]\\n\\t].\\n\\t^form\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/16/2003 15:44'!\\nreadPlainGray\\n\\t\\\"plain gray\\\"\\n\\t| val form poker aux tokens |\\n\\tform _ Form extent: cols@rows depth: depth.\\n\\tpoker _ BitBlt current bitPokerToForm: form.\\n\\ttokens _ OrderedCollection new.\\n\\t0 to: rows-1 do: [:y |\\n\\t\\t0 to: cols-1 do: [:x |\\n\\t\\t\\taux _ self getTokenPbm: tokens.\\n\\t\\t\\tval _ aux at: 1. tokens _ aux at: 2.\\n\\t\\t\\tpoker pixelAt: x@y put: val.\\n\\t\\t]\\n\\t].\\n\\t^form\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 10/15/2003 12:49'!\\nreadPlainRGB\\n\\t\\\"RGB form, use 32 bits\\\"\\n\\t| val form poker tokens aux |\\n\\tmaxValue > 255 ifTrue:[self error:'RGB value > 32 bits not supported in Squeak'].\\n\\tform _ Form extent: cols@rows depth: 32.\\n\\tpoker _ BitBlt current bitPokerToForm: form.\\n\\ttokens _ OrderedCollection new.\\n\\t0 to: rows-1 do: [:y |\\n\\t\\t0 to: cols-1 do: [:x | | r g b|\\n\\t\\t\\taux _ self getTokenPbm: tokens. r _ aux at: 1. tokens _ aux at: 2.\\n\\t\\t\\taux _ self getTokenPbm: tokens. g _ aux at: 1. tokens _ aux at: 2.\\n\\t\\t\\taux _ self getTokenPbm: tokens. b _ aux at: 1. tokens _ aux at: 2.\\n\\t\\t\\tval _ self r: r g: g b: b for: depth.\\n\\t\\t\\tpoker pixelAt: x@y put: val.\\n\\t\\t]\\n\\t].\\n\\t^form\\n! !\\n\\n!PNMReadWriter methodsFor: 'reading' stamp: 'jdr 7/18/2005 16:58'!\\nreadRGB\\n\\t\\\"RGB form, use 16/32 bits\\\"\\n\\t| val form poker sample shift |\\n\\tmaxValue > 255 ifTrue:[self error:'RGB value > 32 bits not supported in Squeak'].\\n\\tstream binary.\\n\\tform := Form extent: cols@rows depth: depth.\\n\\tpoker := BitBlt current bitPokerToForm: form.\\n\\tdepth = 32 ifTrue:[shift := 8] ifFalse:[shift := 5].\\n\\t0 to: rows-1 do: [:y |\\n\\t\\t0 to: cols-1 do: [:x |\\n\\t\\t\\tval := 16rFF.\\t\\\"no transparency\\\"\\n\\t\\t\\t1 to: 3 do: [:i |\\n\\t\\t\\t\\tsample := stream next.\\n\\t\\t\\t\\tval := val << shift + sample.\\n\\t\\t\\t].\\n\\t\\t\\tpoker pixelAt: x@y put: val.\\n\\t\\t]\\n\\t].\\n\\t^form\\n! !\\n\\n\\n!PNMReadWriter methodsFor: 'testing' stamp: 'jdr 10/11/2003 14:52'!\\nunderstandsImageFormat\\n\\t\\\"P1 to P7\\\"\\n\\t| p |\\n\\tp _ stream next asCharacter.\\n\\ttype _ stream next - 48.\\n\\t^(p = $P and:[type > 0 and:[type < 8]])\\n\\t! !\\n\\n\\n!PNMReadWriter methodsFor: 'writing' stamp: 'jdr 10/16/2003 16:08'!\\nnextPutBW: aForm reverse: flagXor\\n\\t| myType val nBytes bytesRow |\\n\\tcols _ aForm width.\\n\\trows _ aForm height.\\n\\tdepth _ aForm depth.\\n\\t\\\"stream position: 0.\\\"\\n\\taForm depth = 1 ifTrue:[myType _ $4] ifFalse:[myType _ $5].\\n\\tself writeHeader: myType.\\n\\tstream binary.\\n\\tnBytes _ (cols/8) ceiling.\\n\\tbytesRow _ (cols/32) ceiling * 4.\\n\\t0 to: rows-1 do: [:y | | i |\\n\\t\\ti _ 1 + (bytesRow*y).\\n\\t\\t0 to: nBytes-1 do: [:x |\\n\\t\\t\\tval _ aForm bits byteAt: i.\\n\\t\\t\\tflagXor ifTrue:[val _ val bitXor: 16rFF].\\n\\t\\t\\tstream nextPut: val.\\n\\t\\t\\ti _ i+1.\\n\\t\\t]\\n\\t].\\n! !\\n\\n!PNMReadWriter methodsFor: 'writing' stamp: 'jdr 10/16/2003 16:08'!\\nnextPutGray: aForm\\n\\t| myType peeker val |\\n\\tcols _ aForm width.\\n\\trows _ aForm height.\\n\\tdepth _ aForm depth.\\n\\t\\\"stream position: 0.\\\"\\n\\taForm depth = 1 ifTrue:[myType _ $4] ifFalse:[myType _ $5].\\n\\tself writeHeader: myType.\\n\\tpeeker _ BitBlt current bitPeekerFromForm: aForm.\\n\\t0 to: rows-1 do: [:y |\\n\\t\\t0 to: cols-1 do: [:x |\\n\\t\\t\\tval _ peeker pixelAt: x@y.\\n\\t\\t\\tstream nextPut: val.\\n\\t\\t]\\n\\t].\\n! !\\n\\n!PNMReadWriter methodsFor: 'writing' stamp: 'jdr 10/16/2003 14:22'!\\nnextPutImage: aForm\\n\\taForm unhibernate.\\n\\taForm depth\\t caseOf: {\\n\\t\\t[1] \\t\\t-> [self nextPutBW: aForm reverse: false].\\n\\t\\t[16] \\t-> [self nextPutRGB: aForm].\\n\\t\\t[32] \\t-> [self nextPutRGB: aForm].\\n\\t} otherwise: [\\n\\t\\t(aForm respondsTo: #colors) ifTrue:[\\n\\t\\t\\taForm colors ifNil: [\\n\\t\\t\\t\\tself nextPutGray: aForm\\n\\t\\t\\t]\\n\\t\\t\\tifNotNil: [\\n\\t\\t\\t\\tself nextPutRGB: aForm\\n\\t\\t\\t]\\n\\t\\t]\\n\\t\\tifFalse:[\\n\\t\\t\\tself nextPutGray: aForm\\n\\t\\t]\\n\\t]! !\\n\\n!PNMReadWriter methodsFor: 'writing' stamp: 'jdr 10/16/2003 16:08'!\\nnextPutRGB: aForm\\n\\t| myType peeker f shift mask |\\n\\tcols _ aForm width.\\n\\trows _ aForm height.\\n\\tdepth _ aForm depth.\\n\\tf _ aForm.\\n\\tdepth < 16 ifTrue:[\\n\\t\\tf _ aForm asFormOfDepth: 32.\\n\\t\\tdepth _ 32.\\n\\t].\\n\\tmyType _ $6.\\n\\t\\\"stream position: 0.\\\"\\n\\tself writeHeader: myType.\\n\\tdepth = 32 ifTrue:[shift _ 8. mask _ 16rFF] ifFalse:[shift _ 5. mask _ 16r1F].\\n\\tpeeker _ BitBlt current bitPeekerFromForm: f.\\n\\t0 to: rows-1 do: [:y |\\n\\t\\t0 to: cols-1 do: [:x | | p r g b |\\n\\t\\t\\tp _ peeker pixelAt: x@y.\\n\\t\\t\\tb _ p bitAnd: mask. p _ p >> shift.\\n\\t\\t\\tg _ p bitAnd: mask. p _ p >> shift.\\n\\t\\t\\tr _ p bitAnd: mask.\\n\\t\\t\\tstream nextPut: r.\\n\\t\\t\\tstream nextPut: g.\\n\\t\\t\\tstream nextPut: b.\\n\\t\\t]\\n\\t].\\n! !\\n\\n!PNMReadWriter methodsFor: 'writing' stamp: 'jdr 10/15/2003 15:48'!\\nwriteHeader: myType\\n\\t\\\"this is ascii\\\"\\n\\tstream nextPut: ($P asciiValue).\\n\\tstream nextPut: (myType asciiValue).\\n\\tstream nextPut: 10.\\t\\t\\\"nl\\\"\\n\\tpragma ifNotNil:[\\n\\t\\tstream nextPutAll: (pragma asByteArray).\\n\\t].\\n\\tstream nextPutAll: (cols printString) asByteArray.\\n\\tstream nextPut: 32.\\t\\t\\\" \\\"\\n\\tstream nextPutAll: (rows printString) asByteArray.\\n\\tstream nextPut: 10.\\t\\t\\\"nl\\\"\\n\\tdepth > 1 ifTrue: [| d c maxV |\\n\\t\\td _ {1 . 2 . 4 . 8 . 16 . 32}.\\n\\t\\tc _ {1 . 3 . 15 . 255 . 31 . 255}. \\n\\t\\tmaxV _ nil.\\n\\t\\t1 to: d size do:[:i| ((d at: i) = depth and:[maxV = nil]) ifTrue:[maxV _ c at: i]].\\n\\t\\tstream nextPutAll: (maxV printString) asByteArray.\\n\\t\\tstream nextPut: 10.\\t\\t\\\"nl\\\"\\n\\t]\\n\\t! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPNMReadWriter class\\n\\tinstanceVariableNames: ''!\\n\\n!PNMReadWriter class methodsFor: 'image reading/writing' stamp: 'jdr 7/18/2005 16:25'!\\ntypicalFileExtensions\\n\\t\\\"Answer a collection of file extensions (lowercase) which files that I can read might commonly have\\\"\\n\\t^#('pbm' 'pnm' 'ppm' 'pam')! !\\n\\n\\n!PNMReadWriter class methodsFor: 'testing' stamp: 'jdr 10/11/2003 14:49'!\\ntestFromSEFile: filename\\n\\t\\\"read SE file, check origin\\n\\t\\tPNMReadWriter testFromSEFile: 'Tools:Squeak3.4:eliseSE.pbm'.\\n\\t\\\"\\n\\t| prw f |\\n\\tprw _ self new.\\n\\tprw stream: (FileStream readOnlyFileNamed: filename).\\n\\tf _ prw nextImage.\\n\\tf morphEdit.\\n\\tprw inspect! !\\n\\n!PNMReadWriter class methodsFor: 'testing' stamp: 'jdr 10/16/2003 17:22'!\\ntestFromString\\n\\t\\\"read SE file from string\\n\\t\\tPNMReadWriter testFromString\\n\\t\\\"\\n\\t| prw f s |\\n\\tprw _ self new.\\n\\ts _ \\n'P1\\n#origin 1 0\\n3 1\\n1\\t01'.\\n\\tprw stream: (ReadStream on: s from: 1 to: (s size)).\\n\\tf _ prw nextImage.\\n\\tf morphEdit.\\n\\tTranscript cr;show:'Origin=', prw origin asString; cr.! !\\n\\n!PNMReadWriter class methodsFor: 'testing' stamp: 'jdr 7/18/2005 17:03'!\\ntestMultiFile: filename\\n\\t\\\"write two files from user, then read\\n\\t\\tPNMReadWriter testMultiFile: 'Tools:Squeak3.6:outMulti.pbm'.\\n\\t\\\"\\n\\t| prw f |\\n\\tprw := self new.\\n\\tprw stream: ((FileStream newFileNamed: filename) binary).\\n\\tprw pragma: '#Squeak test', String lf.\\n\\tf := Form fromUser. prw nextPutImage: f. \\n\\tf := Form fromUser.prw nextPutImage: f.\\t\\n\\tprw close.\\n\\tprw stream: (StandardFileStream readOnlyFileNamed: filename).\\n\\tf := prw nextImage. (SketchMorph withForm: f) openInWorld.\\n\\tf := prw nextImage. (SketchMorph withForm: f) openInWorld.\\n! !\\n\\n!PNMReadWriter class methodsFor: 'testing' stamp: 'jdr 10/15/2003 15:43'!\\ntestToSEFile: filename\\n\\t\\\"write SE file with origin\\n\\t\\tPNMReadWriter testToSEFile: 'Tools:Squeak3.4:outSE.pbm'.\\n\\t\\\"\\n\\t| prw f |\\n\\tprw _ self new.\\n\\tprw stream: ((FileStream newFileNamed: filename) binary).\\n\\tprw pragma: '#origin 10 10', String lf.\\n\\tf _ Form fromUser.\\n\\tprw nextPutImage: f! !\\nProtocolClient subclass: #POP3Client\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Protocols'!\\n!POP3Client commentStamp: 'mir 5/12/2003 17:57' prior: 0!\\nThis class implements POP3 (Post Office Protocol 3) as specified in RFC 1939. (see http://www.ietf.org/rfc.html)\\n\\nYou can use it to download email from the mail server to your personal mail program.\\n\\nTo see an example of it's use, see POPSocket class>>example.!\\n\\n\\n!POP3Client methodsFor: 'public protocol' stamp: 'mir 3/7/2002 14:58'!\\napopLoginUser: userName password: password\\n\\n\\tself loginUser: userName password: password loginMethod: #APOP! !\\n\\n!POP3Client methodsFor: 'public protocol' stamp: 'mir 3/7/2002 14:35'!\\ndeleteMessage: num\\n\\t\\\"delete the numbered message\\\"\\n\\n\\tself ensureConnection.\\n\\tself sendCommand: 'DELE ', num printString.\\n\\tself checkResponse.\\n\\tself logProgress: self lastResponse! !\\n\\n!POP3Client methodsFor: 'public protocol' stamp: 'mir 3/7/2002 14:57'!\\nloginUser: userName password: password\\n\\n\\tself loginUser: userName password: password loginMethod: #clearText! !\\n\\n!POP3Client methodsFor: 'public protocol' stamp: 'mir 3/8/2002 11:40'!\\nloginUser: userName password: password loginMethod: aLoginMethod\\n\\n\\tself user: userName.\\n\\tself password: password.\\n\\tself loginMethod: aLoginMethod.\\n\\tself login! !\\n\\n!POP3Client methodsFor: 'public protocol' stamp: 'mir 4/7/2003 17:17'!\\nmessageCount\\n\\t\\\"Query the server and answer the number of messages that are in the user's mailbox.\\\"\\n\\n\\t| answerString numMessages |\\n\\tself ensureConnection.\\n\\tself sendCommand: 'STAT'.\\n\\tself checkResponse.\\n\\tself logProgress: self lastResponse.\\n\\n\\t[answerString _ (self lastResponse findTokens: Character separators) second.\\n\\tnumMessages _ answerString asNumber asInteger]\\n\\t\\ton: Error\\n\\t\\tdo: [:ex | (ProtocolClientError protocolInstance: self) signal: 'Invalid STAT response.'].\\n\\t^numMessages! !\\n\\n!POP3Client methodsFor: 'public protocol' stamp: 'len 12/14/2002 17:50'!\\nquit\\n\\t\\\"QUIT <CRLF>\\\"\\n\\n\\tself sendCommand: 'QUIT'.\\n\\tself checkResponse.! !\\n\\n!POP3Client methodsFor: 'public protocol' stamp: 'mir 3/7/2002 14:35'!\\nretrieveMessage: number\\n\\t\\\"retrieve the numbered message\\\"\\n\\n\\tself ensureConnection.\\n\\tself sendCommand: 'RETR ', number printString.\\n\\tself checkResponse.\\n\\tself logProgress: self lastResponse.\\n\\n\\t^self getMultilineResponse! !\\n\\n\\n!POP3Client methodsFor: 'private' stamp: 'mir 11/11/2002 16:20'!\\nloginMethod\\n\\t^self connectionInfo at: #loginMethod ifAbsent: [nil]! !\\n\\n!POP3Client methodsFor: 'private' stamp: 'mir 3/8/2002 11:41'!\\nloginMethod: aSymbol\\n\\t^self connectionInfo at: #loginMethod put: aSymbol! !\\n\\n\\n!POP3Client methodsFor: 'private protocol' stamp: 'BG 3/16/2005 08:27'!\\napopLogin\\n\\n\\t\\\"Attempt to authenticate ourselves to the server without sending the password as cleartext.\\\"\\n\\n\\t\\\"For secure authentication, we look for a timestamp in the initial response string we get from the server, and then try the APOP command as specified in RFC 1939. If the initial response from the server is\\n\\t+OK POP3 server ready <1896.697170952@dbc.mtview.ca.us>\\nwe extract the timestamp\\n\\t<1896.697170952@dbc.mtview.ca.us>\\nthen form a string of the form\\n\\t<1896.697170952@dbc.mtview.ca.us>USERPASSWORD\\nand then send only the MD5 hash of that to the server. Thus the password never hits the wire\\\"\\n\\n\\t| timestamp hash |\\n\\n\\t[\\n\\t\\\"Look for a timestamp in the response we received from the server\\\"\\n\\ttimestamp _ self lastResponse findTokens: '<>' includes: '@'.\\n\\ttimestamp\\n\\t\\tifNil: [(POP3LoginError protocolInstance: self) signal: 'APOP not supported.'].\\n\\n\\t(Smalltalk includesKey: #MD5)\\n\\t\\tifTrue: [\\n\\t\\t\\thash _ ((Smalltalk at: #MD5) hashMessage: ('<', timestamp, '>', self password)) storeStringHex asLowercase.\\n\\t\\t\\t\\\"trim starting 16r and zero pad it to 32 characters if needed\\\"\\n\\t\\t\\thash _ hash padded: #left to: 32 with: $0]\\n\\t\\tifFalse: [(POP3LoginError protocolInstance: self) signal: 'APOP (MD5) not supported.'].\\n\\n\\tself sendCommand: 'APOP ', self user, ' ', hash.\\n\\tself checkResponse.\\n\\tself logProgress: self lastResponse]\\n\\t\\ton: ProtocolClientError\\n\\t\\tdo: [:ex |\\n\\t\\t\\tself close.\\n\\t\\t\\t(LoginFailedException protocolInstance: self) signal: 'Login failed.']! !\\n\\n!POP3Client methodsFor: 'private protocol' stamp: 'mir 4/7/2003 17:38'!\\nclearTextLogin\\n\\n\\t[self sendCommand: 'USER ', self user.\\n\\tself checkResponse.\\n\\tself logProgress: self lastResponse.\\n\\n\\tself sendCommand: 'PASS ', self password.\\n\\tself checkResponse.\\n\\tself logProgress: self lastResponse]\\n\\t\\ton: TelnetProtocolError\\n\\t\\tdo: [:ex |\\n\\t\\t\\t\\\"Neither authentication worked. Indicate an error and close up\\\"\\n\\t\\t\\tself close.\\n\\t\\t\\tex resignalAs: ((LoginFailedException protocolInstance: self) signal: 'Login failed.')]! !\\n\\n!POP3Client methodsFor: 'private protocol' stamp: 'mir 11/14/2002 17:40'!\\ngetMultilineResponse\\n\\t\\\"Get a multiple line response to the last command, filtering out LF characters. A multiple line response ends with a line containing only a single period (.) character.\\\"\\n\\n\\t| response done chunk |\\n\\tresponse _ WriteStream on: ''.\\n\\tdone _ false.\\n\\t[done] whileFalse: [\\n\\t\\tchunk _ self stream nextLine.\\n\\t\\t(chunk beginsWith: '.')\\n\\t\\t\\tifTrue: [response nextPutAll: (chunk copyFrom: 2 to: chunk size); cr ]\\n\\t\\t\\tifFalse: [response nextPutAll: chunk; cr ].\\n\\t\\tdone _ (chunk = '.') ].\\n\\n\\t^ response contents\\n! !\\n\\n!POP3Client methodsFor: 'private protocol' stamp: 'mir 4/7/2003 17:39'!\\nlogin\\n\\tself loginMethod\\n\\t\\tifNil: [^self].\\n\\tself loginMethod == #clearText\\n\\t\\tifTrue: [^self clearTextLogin].\\n\\tself loginMethod == #APOP\\n\\t\\tifTrue: [^self apopLogin].\\n\\t(POP3LoginError protocolInstance: self) signal: 'Unsupported login procedure.'! !\\n\\n\\n!POP3Client methodsFor: 'private testing' stamp: 'mir 3/7/2002 13:43'!\\nresponseIsError\\n\\t^self lastResponse beginsWith: '-'! !\\n\\n!POP3Client methodsFor: 'private testing' stamp: 'mir 11/11/2002 15:44'!\\nresponseIsWarning\\n\\t^self lastResponse beginsWith: '-'! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPOP3Client class\\n\\tinstanceVariableNames: ''!\\n\\n!POP3Client class methodsFor: 'accessing' stamp: 'mir 3/7/2002 12:51'!\\ndefaultPortNumber\\n\\t^110! !\\n\\n!POP3Client class methodsFor: 'accessing' stamp: 'mir 3/7/2002 12:52'!\\nlogFlag\\n\\t^#pop! !\\n\\n\\n!POP3Client class methodsFor: 'example' stamp: 'rbb 3/1/2005 11:05'!\\nexample\\n\\t\\\"POP3Client example\\\"\\n\\t\\\"download a user's messages into an OrderedCollection and inspect the OrderedCollection\\\"\\n\\n\\t| ps messages userName password |\\n\\tuserName := (UIManager default request: 'POP username').\\n\\tpassword := (UIManager default request: 'POP password').\\n\\tps := POP3Client openOnHostNamed: (UIManager default request: 'POP server').\\n\\t[\\n\\tps loginUser: userName password: password.\\n\\tps logProgressToTranscript.\\n\\n\\tmessages := OrderedCollection new.\\n\\t1 to: ps messageCount do: [ :messageNr |\\n\\t\\tmessages add: (ps retrieveMessage: messageNr) ]]\\n\\t\\tensure: [ps close].\\n\\n\\tmessages inspect.! !\\nProtocolClientError subclass: #POP3LoginError\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Protocols'!\\n!POP3LoginError commentStamp: 'mir 5/12/2003 17:58' prior: 0!\\nException for signaling POP3 login failures.!\\n\\nObject subclass: #PRServerDirectory\\n\\tinstanceVariableNames: 'server directories'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-RemoteDirectory'!\\n!PRServerDirectory commentStamp: 'md 1/26/2004 12:40' prior: 0!\\nAdd support to publish or download projects from Small-Land Project\\nRepository (SLPR).\\n\\nThe SLPR has virtual folders where the projects appears. The SLPR can\\nbe acceded from the FileList or from the web interface at\\nhttp://repository.small-land.org:8080\\n\\nBasically it's a type of superswiki (but better ;)).\\n\\nThe features in SMPR not present in SuperSwiki are:\\n\\n- Both the web interface and the squeak-side interface are full\\ntranslatable. The server has translations for English and Spanish just\\nnow, but it's almost trivial to include other translations... Stef?\\nMarcus? ;)\\n\\n- The projects are categorized in \\\"virtual\\\" folder. These folders (By\\nCategory, By Author, By Language, Alphabetical, etc) give us good\\nsearching behaviour just using the FileList and mouse clicks.\\n\\n- The web interface (also full translatable) has a search a la google.\\n\\n- All the urls to query the web interface are \\\"clean enough\\\" so google\\ncan make a good job indexing our content in .pr files.\\n\\n\\nIt's planned to add \\\"editing\\\" features to the web interface to\\nre-categorize, remove, etc projects.\\n\\n\\nEnjoy it,\\n\\n-- \\nDiego Gomez Deck\\nhttp://www.small-land.org!\\n\\n\\n!PRServerDirectory methodsFor: 'accessing' stamp: 'dgd 12/22/2003 07:35'!\\ndirectories\\n\\t\\\"answer the receiver's directories\\\"\\n\\t^ directories! !\\n\\n!PRServerDirectory methodsFor: 'accessing' stamp: 'dgd 12/22/2003 20:44'!\\ndirectory\\n\\t\\\"answer the receiver's directory\\\"\\n\\t| result |\\n\\tresult := String new writeStream.\\n\\tself directories\\n\\t\\tdo: [:each | result nextPutAll: each]\\n\\t\\tseparatedBy: [result nextPutAll: self slash].\\n\\t^ result contents! !\\n\\n!PRServerDirectory methodsFor: 'accessing' stamp: 'dgd 12/22/2003 21:01'!\\ndirectoryWrapperClass\\n\\t\\\"answer the class to be used as a wrapper in FileList2\\\"\\n\\t^ FileDirectoryWrapper! !\\n\\n!PRServerDirectory methodsFor: 'accessing' stamp: 'dgd 12/22/2003 20:44'!\\ndownloadUrl\\n\\t\\\"The url under which files will be accessible.\\\"\\n\\t^ (self urlFromServer: self server directories: {'programmatic'})\\n\\t\\t, self slash! !\\n\\n!PRServerDirectory methodsFor: 'accessing' stamp: 'dgd 12/27/2003 11:06'!\\nmoniker\\n\\t\\\"a plain language name for this directory\\\"\\n\\t^ self server! !\\n\\n!PRServerDirectory methodsFor: 'accessing' stamp: 'dgd 12/22/2003 20:53'!\\nrealUrl\\n\\t\\\"a fully expanded version of the url we represent.\\\"\\n\\t^self urlFromServer: self server directories: self directories! !\\n\\n!PRServerDirectory methodsFor: 'accessing' stamp: 'dgd 12/22/2003 07:40'!\\nserver\\n\\t\\\"answer the receiver's server\\\"\\n\\t^ server! !\\n\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:25'!\\ncreateDirectory: localName \\n\\t\\\"Create a new sub directory within the current one\\\"\\n\\t^ self inform: 'operation not supported' translated! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:24'!\\ndeleteFileNamed: localFileName \\n\\t\\\"Delete the file with the given name in this directory.\\\"\\n\\t^ self inform: 'operation not supported' translated! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:45'!\\ndirectoryNamed: aString \\n\\t\\\"Return the subdirectory of this directory with the given name.\\\"\\n\\t^ self class server: self server directory: self directory , self slash, aString! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 21:30'!\\ndirectoryNames\\n\\t\\\"Return a collection of names for the subdirectories of this \\n\\tdirectory. \\\"\\n\\t^ self entries\\n\\t\\tselect: [:entry | entry isDirectory]\\n\\t\\tthenCollect: [:entry | entry name]! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:40'!\\nentries\\n\\t\\\"Return a collection of directory entries for the files and \\n\\tdirectories in this directory.\\\"\\n\\t| lines |\\n\\tlines := self getLines.\\n\\t^ lines isNil\\n\\t\\tifTrue: [#()] ifFalse:[\\n\\t\\n\\tself parseLines: lines]! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 21:30'!\\nfileNames\\n\\t\\\"Return a collection of names for the files (but not directories) in this directory.\\\"\\n\\t^ self entries\\n\\t\\tselect: [:entry | entry isDirectory not]\\n\\t\\tthenCollect: [:entry | entry name]! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:30'!\\nfullNameFor: aString \\n\\\"Return a corrected, fully-qualified name for the given file name.\\\"\\n\\t^ self urlFromServer: self server directories: self directories , {aString}! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/27/2003 12:36'!\\ngetOnly: numberOfBytes from: fileNameOnServer \\n\\t\\\"Just capture the first numberOfBytes of the file. \\n\\t \\n\\tGoes faster for long files. Return the contents, not a stream.\\\"\\n\\t| fileName |\\n\\tself flag: #todo.\\n\\t\\\"use LRUCache\\\"\\n\\tfileName := fileNameOnServer\\n\\t\\t\\t\\tallButFirst: (fileNameOnServer lastIndexOf: self pathNameDelimiter).\\n\\t\\\"\\\"\\n\\t^ self getOnly: numberOfBytes ofProjectContents: fileName! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:33'!\\noldFileNamed: aName \\\"Open the existing file with the given name in this directory.\\\"\\n\\t^ self oldFileOrNoneNamed: aName! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/27/2003 11:35'!\\noldFileOrNoneNamed: fullName \\n\\t\\\"If the file exists, answer a read-only FileStream on it. If it \\n\\tdoesn't, answer nil.\\\"\\n\\t| fileName contents |\\n\\tfileName := fullName\\n\\t\\t\\t\\tallButFirst: (fullName lastIndexOf: self pathNameDelimiter).\\n\\t\\\"\\\"\\n\\tcontents := self getFullProjectContents: fileName.\\n\\tcontents isNil\\n\\t\\tifTrue: [^ nil].\\n\\t\\\"\\\"\\n\\t^ (SwikiPseudoFileStream with: contents) directory: self;\\n\\t\\t localName: fileName;\\n\\t\\t reset;\\n\\t\\t yourself! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 07:58'!\\non: fullName \\n\\t\\\"Answer another ServerDirectory on the partial path name. \\n\\tfullName is directory path, and does include the name of the \\n\\tserver.\\\"\\n\\t^ self class fullPath: fullName!\\n]style[(4 8 3 133 4 4 17 8)f3b,f3cblue;b,f3,f3c146044000,f3,f3cmagenta;,f3,f3cblue;i! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:39'!\\npathName\\\"Path name as used in reading the file. \\\"\\n\\t^ self urlFromServer: self server directories: self directories! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 08:08'!\\npathParts\\n\\t\\\"Return the path from the root of the file system to this \\n\\tdirectory as an array of directory names. On a remote server.\\\"\\n\\t^ (OrderedCollection with: self server) addAll: self directories;\\n\\t\\t yourself! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:34'!\\nreadOnlyFileNamed: aName \\n\\\"Open the existing file with the given name in this directory for read-only access.\\\"\\n\\t^ self oldFileNamed: aName! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:26'!\\nrename: fullName toBe: newName \\n\\t\\\"Rename a remote file. fullName is just be a fileName, or can \\n\\tbe directory path that includes name of the server. newName \\n\\tis just a fileName\\\"\\n\\t^ self inform: 'operation not supported' translated! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:37'!\\nsleep\\\"Leave the FileList window. Do nothing. \\\"\\n\\t^ self! !\\n\\n!PRServerDirectory methodsFor: 'file directory' stamp: 'dgd 12/22/2003 20:32'!\\nwakeUp\\\"Entering a FileList window. Do nothing.\\\"\\n\\t^ self! !\\n\\n\\n!PRServerDirectory methodsFor: 'initialization' stamp: 'dgd 12/22/2003 20:46'!\\ninitializeServer: serverString directories: directoriesCollection \\n\\t\\\"initialize the receiver's server and directories\\\"\\n\\tserver := serverString withBlanksTrimmed.\\n\\tserver last = self pathNameDelimiter\\n\\t\\tifTrue: [server := server allButLast withBlanksTrimmed].\\n\\t\\\"\\\"\\n\\tdirectories := directoriesCollection! !\\n\\n\\n!PRServerDirectory methodsFor: 'path access' stamp: 'dgd 12/22/2003 20:41'!\\npathNameDelimiter\\\"Return the delimiter character for this kind of directory.\\\"\\n\\t^ $/! !\\n\\n!PRServerDirectory methodsFor: 'path access' stamp: 'dgd 12/22/2003 20:44'!\\nslash\\n\\\"answer the recevier 'slash'\\\"\\n\\t^ self pathNameDelimiter asString! !\\n\\n\\n!PRServerDirectory methodsFor: 'squeaklets' stamp: 'dgd 3/8/2006 17:38'!\\nwriteProject: aProject inFileNamed: fileNameString fromDirectory: localDirectory \\n\\t\\\"write aProject (a file version can be found in the file named \\n\\tfileNameString in localDirectory)\\\"\\n\\t| url arguments answer string |\\n\\turl := self urlFromServer: self server directories: {'programmatic'. 'uploadproject'}.\\n\\targuments := self\\n\\t\\t\\t\\tgetPostArgsFromProject: aProject\\n\\t\\t\\t\\tfileNamed: fileNameString\\n\\t\\t\\t\\tfromDirectory: localDirectory.\\n\\t\\\"\\\"\\n\\tCursor read\\n\\t\\tshowWhile: [\\\"\\\"\\n\\t\\t\\tanswer := HTTPClient httpPostDocument: url args: arguments.\\n\\t\\t\\t\\\"answer := HTTPSocket httpGetDocument: url args: arguments.\\\"\\n\\t\\t\\tstring := answer contents.\\n\\t\\t\\t(string beginsWith: '--OK--')\\n\\t\\t\\t\\tifTrue: [^ true]].\\n\\t\\\"\\\"\\n\\tself\\n\\t\\tinform: ('Server responded: {1}' translated format: {string}).\\n\\t^ false! !\\n\\n\\n!PRServerDirectory methodsFor: 'testing' stamp: 'dgd 12/22/2003 20:39'!\\nacceptsUploads\\n\\t\\\"answer whatever the receiver accepts uploads\\\"\\n\\t^ true! !\\n\\n!PRServerDirectory methodsFor: 'testing' stamp: 'dgd 12/22/2003 00:42'!\\nisProjectSwiki\\n\\t\\\"answer whatever the receiver is a project swiki\\\"\\n\\t^ true! !\\n\\n!PRServerDirectory methodsFor: 'testing' stamp: 'dgd 12/27/2003 11:04'!\\nisRemoteDirectory\\n\\t\\\"answer whatever the receiver is a remote directory\\\"\\n\\t^ true! !\\n\\n!PRServerDirectory methodsFor: 'testing' stamp: 'dgd 12/21/2003 23:31'!\\nisSearchable\\n\\t\\\"answer whatever the receiver is searchable\\\"\\n\\t^ true! !\\n\\n!PRServerDirectory methodsFor: 'testing' stamp: 'dgd 8/17/2004 22:14'!\\nqueryProjectsAndShow: thingsToSearchForCollection \\n\\t\\\"query the server for all the projects that match \\n\\tthingsToSearchForCollection\\\"\\n\\t| url arguments answer string |\\n\\turl := self urlFromServer: self server directories: {'programmatic'. 'queryprojects'}.\\n\\targuments := self getPostArgsFromThingsToSearchFor: thingsToSearchForCollection.\\n\\t\\\"\\\"\\n\\tCursor read\\n\\t\\tshowWhile: [\\\"\\\"\\n\\t\\t\\t\\\"answer := HTTPClient httpPostDocument: url args: \\n\\t\\t\\targs.\\\"\\n\\t\\t\\tanswer := HTTPSocket httpGetDocument: url args: arguments.\\n\\t\\t\\tstring := answer contents.\\n\\t\\t\\t(string beginsWith: '--OK--')\\n\\t\\t\\t\\tifTrue: [^ true]].\\n\\t\\\"\\\"\\n\\tself\\n\\t\\tinform: ('Server responded: {1}' translated format: {string}).\\n\\t^ false! !\\n\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 12/27/2003 11:34'!\\ngetFullProjectContents: aString \\n\\t\\\"private - get the project content from the server\\\"\\n\\t^ self getOnly: nil ofProjectContents: aString! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 8/17/2004 22:23'!\\ngetLines\\n\\t\\\"private - answer a collection of lines with the server response\\\"\\n\\t| url answer string lines |\\n\\turl := self urlFromServer: self server directories: {'programmatic'} , self directories.\\n\\turl := url , self slash.\\n\\t\\\"\\\"\\n\\tCursor read\\n\\t\\tshowWhile: [\\\"\\\"\\n\\t\\t\\tanswer := HTTPClient httpGetDocument: url.\\n\\t\\t\\tstring := answer contents.\\n\\t\\t\\t(string beginsWith: '--OK--')\\n\\t\\t\\t\\tifFalse: [^ nil]].\\n\\t\\\"\\\"\\n\\tlines := OrderedCollection new.\\n\\t(string allButFirst: 6)\\n\\t\\tlinesDo: [:line | lines add: line squeakToIso].\\n\\t\\\"\\\"\\n\\t^ lines! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 12/27/2003 12:37'!\\ngetOnly: numberOfBytes ofProjectContents: aString \\n\\t\\\"private - get numberOfBytes of the project contents\\\"\\n\\t| url answer contents args |\\n\\tself flag: #todo.\\n\\t\\\"use an LRUCache\\\"\\n\\turl := self urlFromServer: self server directories: {'programmatic'. aString}.\\n\\t\\\"\\\"\\n\\targs := numberOfBytes isNil\\n\\t\\t\\t\\tifFalse: ['numberOfBytes=' , numberOfBytes asString].\\n\\t\\\"\\\"\\n\\tCursor read\\n\\t\\tshowWhile: [\\\"\\\"\\n\\t\\t\\tanswer := HTTPSocket httpGetDocument: url args: args.\\n\\t\\t\\tcontents := answer contents].\\\"\\\"\\n\\t(contents beginsWith: '--OK--')\\n\\t\\tifFalse: [^ nil].\\n\\t\\\"\\\"\\n\\t^ contents allButFirst: 6! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 4/3/2006 13:27'!\\ngetPostArgsFromProject: aProject fileNamed: fileNameString fromDirectory: localDirectory \\n\\t| args thumbnail uploader |\\n\\targs := Dictionary new.\\n\\n\\t\\\"args at: 'contents' put: {(localDirectory oldFileNamed: fileNameString) contentsOfEntireFile}.\\\"\\n\\targs at: 'contents' put: {(StandardFileStream\\n\\t\\t\\treadOnlyFileNamed: (localDirectory fullNameFor: fileNameString)) contentsOfEntireFile}.\\n\\n\\targs at: 'name' put: {aProject name isoToSqueak}.\\n\\targs at: 'version' put: {(Project parseProjectFileName: fileNameString) second asString}.\\n\\targs at: 'language' put: {aProject naturalLanguage asString}.\\n\\n\\tuploader := Utilities authorNamePerSe.\\n\\tuploader isEmptyOrNil\\n\\t\\tifTrue: [uploader := Utilities authorInitialsPerSe].\\n\\tuploader isEmptyOrNil\\n\\t\\tifFalse: [args at: 'uploader' put: {uploader}].\\n\\n\\tself putSmalltalkInfoInto: args.\\n\\n\\tthumbnail := self getProjectThumbnail: aProject.\\n\\tthumbnail isNil\\n\\t\\tifFalse: [args at: 'thumbnailcontents' put: {thumbnail}].\\n\\n\\tself putProjectDetailsFrom: aProject to: args.\\n\\n\\t^ args! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 8/17/2004 22:14'!\\ngetPostArgsFromThingsToSearchFor: thingsToSearchForCollection \\n\\t| args |\\n\\targs := Dictionary new.\\n\\t\\\"\\\"\\n\\tthingsToSearchForCollection\\n\\t\\tdo: [:each | \\n\\t\\t\\t| pos | \\n\\t\\t\\tpos := each indexOf: $:.\\n\\t\\t\\tpos isZero\\n\\t\\t\\t\\tifFalse: [| key value | \\n\\t\\t\\t\\t\\tkey := (each first: pos - 1) withBlanksTrimmed.\\n\\t\\t\\t\\t\\tvalue := (each allButFirst: pos) withBlanksTrimmed.\\n\\t\\t\\t\\t\\t(value beginsWith: '*')\\n\\t\\t\\t\\t\\t\\tifTrue: [value := value allButFirst].\\n\\t\\t\\t\\t\\t(value endsWith: '*')\\n\\t\\t\\t\\t\\t\\tifTrue: [value := value allButLast].\\n\\t\\t\\t\\t\\t\\\"\\\"\\n\\t\\t\\t\\t\\targs at: key put: {value}]].\\n\\t\\\"\\\"\\n\\t^ args! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 12/24/2003 11:33'!\\ngetProjectThumbnail: aProject \\n\\t\\\"private - answer a stream with the aProject's thumbnail or nil if none\\\"\\n\\t| form stream |\\n\\tform := aProject thumbnail.\\n\\tform isNil\\n\\t\\tifTrue: [^ nil].\\n\\t\\\"\\\"\\n\\tform unhibernate.\\n\\tform := form colorReduced.\\n\\t\\\"\\\"\\n\\tself flag: #todo.\\n\\t\\\"use a better image format than GIF\\\"\\n\\tstream := RWBinaryOrTextStream on: String new.\\n\\tGIFReadWriter putForm: form onStream: stream.\\n\\tstream reset.\\n\\t\\\"\\\"\\n\\t^ stream contents asString! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 12/22/2003 20:34'!\\nparseLine: aString \\n\\\"private - parse a line from a server response\\\"\\n\\t| tokens |\\n\\ttokens := aString findTokens: '|'.\\n\\t\\\"\\\"\\n\\t^ tokens first = 'D'\\n\\t\\tifTrue: [\\\"\\\"\\n\\t\\t\\tDirectoryEntry\\n\\t\\t\\t\\tname: tokens second\\n\\t\\t\\t\\tcreationTime: 0\\n\\t\\t\\t\\tmodificationTime: 0\\n\\t\\t\\t\\tisDirectory: true\\n\\t\\t\\t\\tfileSize: 0]\\n\\t\\tifFalse: [\\\"\\\"\\n\\t\\t\\tDirectoryEntry\\n\\t\\t\\t\\tname: tokens second\\n\\t\\t\\t\\tcreationTime: tokens third asInteger\\n\\t\\t\\t\\tmodificationTime: tokens fourth asInteger\\n\\t\\t\\t\\tisDirectory: false\\n\\t\\t\\t\\tfileSize: tokens fifth asInteger]! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 12/22/2003 20:38'!\\nparseLines: aCollection \\n\\\"private - parse aCollection of lines from a server response\\\"\\n\\t^ aCollection\\n\\t\\tcollect: [:each | self parseLine: each]! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 9/7/2004 12:16'!\\nputProjectDetailsFrom: aProject to: args \\n\\t| projectDetails |\\n\\tprojectDetails := aProject world\\n\\t\\t\\t\\tvalueOfProperty: #ProjectDetails\\n\\t\\t\\t\\tifAbsent: [^ self].\\n\\t\\\"\\\"\\n\\tself flag: #todo.\\n\\t\\\"projectname ?\\\"\\n\\tprojectDetails\\n\\t\\tat: 'projectdescription'\\n\\t\\tifPresent: [:value | args at: 'description' put: {value isoToSqueak}].\\n\\tprojectDetails\\n\\t\\tat: 'projectauthor'\\n\\t\\tifPresent: [:value | args at: 'author' put: {value isoToSqueak}].\\n\\tprojectDetails\\n\\t\\tat: 'projectcategory'\\n\\t\\tifPresent: [:value | args at: 'category' put: {value isoToSqueak}].\\n\\tprojectDetails\\n\\t\\tat: 'projectsubcategory'\\n\\t\\tifPresent: [:value | args at: 'subcategory' put: {value isoToSqueak}].\\n\\tprojectDetails\\n\\t\\tat: 'projectkeywords'\\n\\t\\tifPresent: [:value | args at: 'keywords' put: {value isoToSqueak}]! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 9/7/2004 12:13'!\\nputSmalltalkInfoInto: args \\n\\t\\\"private - fills args with information from Smalltalk\\\"\\n\\tself flag: #todo.\\n\\t\\\" \\n\\tlastest small-land changeset / small-land version \\n\\t\\\"\\n\\t#(#datedVersion #osVersion #platformName #platformSubtype #vmPath #vmVersion #imageName #changesName #sourcesName #listBuiltinModules #listLoadedModules #getVMParameters )\\n\\t\\tdo: [:each | \\n\\t\\t\\t| value | \\n\\t\\t\\tvalue := SmalltalkImage current perform: each.\\n\\t\\t\\targs at: 'extra-' , each asString put: {value asString isoToSqueak}]! !\\n\\n!PRServerDirectory methodsFor: 'private' stamp: 'dgd 12/22/2003 20:47'!\\nurlFromServer: serverString directories: aCollection \\n\\t\\\"private - builds an url for server/directories\\\"\\n\\t| result |\\n\\tresult := String new writeStream.\\n\\t\\\"\\\"\\n\\t{serverString} , aCollection\\n\\t\\tdo: [:each | \\\"\\\"\\n\\t\\t\\tresult\\n\\t\\t\\t\\tnextPutAll: (each copyReplaceAll: ' ' with: '+')]\\n\\t\\tseparatedBy: [result nextPutAll: self slash].\\n\\t\\\"\\\"\\n\\t^ result contents! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPRServerDirectory class\\n\\tinstanceVariableNames: ''!\\n\\n!PRServerDirectory class methodsFor: 'instance creation' stamp: 'dgd 12/22/2003 20:43'!\\nfullPath: fullNameString\\n\\t\\\"answer an instance of the receiver on fullName\\\"\\n\\t| pathParts |\\n\\tpathParts := self pathParts: fullNameString.\\n\\t^ self server: pathParts first directories: pathParts allButFirst! !\\n\\n!PRServerDirectory class methodsFor: 'instance creation' stamp: 'dgd 12/22/2003 20:43'!\\npathParts: fullName \\n\\t\\\"private - parse fullName in server and directory\\\"\\n\\t| url slashPos server directory |\\n\\turl := fullName.\\n\\t(url beginsWith: 'http://')\\n\\t\\tifTrue: [url := url allButFirst: 7].\\n\\turl last = $/\\n\\t\\tifTrue: [url := url allButLast].\\n\\t\\\"\\\"\\n\\tslashPos := url indexOf: $/.\\n\\tslashPos isZero\\n\\t\\tifTrue: [^ {'http://' , url}].\\n\\t\\\"\\\"\\n\\tserver := url first: slashPos - 1.\\n\\tdirectory := url allButFirst: slashPos.\\n\\t\\\"\\\"\\n\\t^ {'http://' , server. directory}! !\\n\\n!PRServerDirectory class methodsFor: 'instance creation' stamp: 'dgd 12/22/2003 07:57'!\\nserver: serverString \\n\\t\\\"answer a new instance of the receiver on server aString\\\"\\n\\t^ self server: serverString directories: #()! !\\n\\n!PRServerDirectory class methodsFor: 'instance creation' stamp: 'dgd 12/22/2003 07:56'!\\nserver: serverString directories: aCollection \\n\\t\\\"answer a new instance of the receiver on server aString\\\"\\n\\t^ self new initializeServer: serverString directories: aCollection! !\\n\\n!PRServerDirectory class methodsFor: 'instance creation' stamp: 'dgd 12/22/2003 07:58'!\\nserver: serverString directory: directoryString \\n\\t\\\"answer a new instance of the receiver on server aString\\\"\\n\\t^ self new\\n\\t\\tinitializeServer: serverString\\n\\t\\tdirectories: (directoryString findTokens: '/')!\\n]style[(8 12 12 15 3 57 4 4 25 12 17 15 13 3 1)f3b,f3cblue;b,f3b,f3cblue;b,f3,f3c146044000,f3,f3cmagenta;,f3,f3cblue;i,f3,f3cblue;i,f3,f3c255146000b,f3! !\\nObject subclass: #PackageInfo\\n\\tinstanceVariableNames: 'packageName methodCategoryPrefix'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PackageInfo-Base'!\\n!PackageInfo commentStamp: '<historical>' prior: 0!\\nSubclass this class to create new Packages.!\\n\\n\\n!PackageInfo methodsFor: 'comparing' stamp: 'avi 10/11/2003 14:20'!\\nhash\\n\\t^ packageName hash! !\\n\\n!PackageInfo methodsFor: 'comparing' stamp: 'avi 10/11/2003 00:09'!\\n= other\\n\\t^ other species = self species and: [other packageName = self packageName]! !\\n\\n\\n!PackageInfo methodsFor: 'dependencies' stamp: 'ab 11/18/2002 01:16'!\\nexternalCallers\\n\\t^ self \\n\\t\\texternalRefsSelect: [:literal | literal isKindOf: Symbol] \\n\\t\\tthenCollect: [:l | l].! !\\n\\n!PackageInfo methodsFor: 'dependencies' stamp: 'stephaneducasse 2/4/2006 20:40'!\\nexternalClasses\\n\\t| myClasses |\\n\\tmyClasses := self classesAndMetaClasses.\\n\\t^ Array streamContents:\\n\\t\\t[:s |\\n\\t\\tProtoObject withAllSubclassesDo:\\n\\t\\t\\t[:class |\\n\\t\\t\\t(myClasses includes: class) ifFalse: [s nextPut: class]]]! !\\n\\n!PackageInfo methodsFor: 'dependencies' stamp: 'stephaneducasse 2/4/2006 20:40'!\\nexternalRefsSelect: selBlock thenCollect: colBlock\\n\\t| pkgMethods dependents refs extMethods otherClasses otherMethods classNames |\\n\\n\\tclassNames := self classes collect: [:c | c name].\\n\\textMethods := self extensionMethods collect: [:mr | mr methodSymbol].\\n\\totherClasses := self externalClasses difference: self externalSubclasses.\\n\\totherMethods := otherClasses gather: [:c | c selectors].\\n\\tpkgMethods := self methods asSet collect: [:mr | mr methodSymbol].\\n\\tpkgMethods removeAllFoundIn: otherMethods.\\n\\n\\tdependents := Set new.\\n\\totherClasses do: [:c |\\n\\t\\tc selectorsAndMethodsDo:\\n\\t\\t\\t[:sel :compiled |\\n\\t\\t\\t(extMethods includes: sel) ifFalse: \\n\\t\\t\\t\\t[refs := compiled literals select: selBlock thenCollect: colBlock.\\n\\t\\t\\t\\trefs do: [:ea |\\n\\t\\t\\t\\t\\t((classNames includes: ea) or: [pkgMethods includes: ea])\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [dependents add: (self referenceForMethod: sel ofClass: c) -> ea]]]]].\\n\\t^ dependents! !\\n\\n!PackageInfo methodsFor: 'dependencies' stamp: 'stephaneducasse 2/4/2006 20:40'!\\nexternalSubclasses\\n\\t| pkgClasses subClasses |\\n\\tpkgClasses := self classes.\\n\\tsubClasses := Set new.\\n\\tpkgClasses do: [:c | subClasses addAll: (c allSubclasses)].\\n\\t^ subClasses difference: pkgClasses\\n! !\\n\\n!PackageInfo methodsFor: 'dependencies' stamp: 'ab 11/18/2002 01:15'!\\nexternalUsers\\n\\t^ self \\n\\t\\texternalRefsSelect: [:literal | literal isVariableBinding] \\n\\t\\tthenCollect: [:l | l key]! !\\n\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'ac 5/14/2003 16:23'!\\nclasses\\n\\t^(self systemCategories gather:\\n\\t\\t[:cat |\\n\\t\\t(SystemOrganization listAtCategoryNamed: cat)\\n\\t\\t\\tcollect: [:className | Smalltalk at: className]])\\n\\t\\t\\t\\tsortBy: [:a :b | a className <= b className]! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'al 12/14/2005 18:06'!\\nclassesAndMetaClasses\\n\\t| baseClasses |\\n\\tbaseClasses := self classes.\\n\\t^baseClasses , (baseClasses collect: [:c | c classSide])! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'ab 11/13/2002 01:23'!\\ncoreMethods\\n\\t^ self classesAndMetaClasses gather: [:class | self coreMethodsForClass: class]! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'al 3/1/2006 21:51'!\\nextensionClasses\\n\\t^ self externalBehaviors reject: [:classOrTrait | (self extensionCategoriesForClass: classOrTrait) isEmpty]! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'al 3/1/2006 21:51'!\\nextensionMethods\\n\\t^ self externalBehaviors gather: [:classOrTrait | self extensionMethodsForClass: classOrTrait]! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'stephaneducasse 2/4/2006 20:40'!\\nforeignClasses\\n\\t| s |\\n\\ts := IdentitySet new.\\n\\tself foreignSystemCategories\\n\\t\\tdo: [:c | (SystemOrganization listAtCategoryNamed: c)\\n\\t\\t\\t\\tdo: [:cl | \\n\\t\\t\\t\\t\\t| cls | \\n\\t\\t\\t\\t\\tcls := Smalltalk at: cl. \\n\\t\\t\\t\\t\\ts add: cls;\\n\\t\\t\\t\\t\\t add: cls class]].\\n\\t^ s! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'ab 12/3/2002 14:34'!\\nforeignSystemCategories\\n\\t^ SystemOrganization categories\\n\\t\\treject: [:cat | self includesSystemCategory: cat] ! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'al 10/9/2005 20:00'!\\nmethods\\n\\t^ (self extensionMethods, self coreMethods) select: [:method |\\n\\t\\tmethod isValid\\n\\t\\t\\tand: [method isLocalSelector]\\n\\t\\t\\tand: [method methodSymbol isDoIt not]]! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'avi 11/10/2003 15:35'!\\noverrideMethods\\n\\t^ self extensionMethods select: [:ea | self isOvverideMethod: ea]! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'ab 11/14/2002 18:39'!\\nselectors\\n\\t^ self methods collect: [:ea | ea methodSymbol]! !\\n\\n!PackageInfo methodsFor: 'listing' stamp: 'ab 11/11/2002 21:51'!\\nsystemCategories\\n\\t^ SystemOrganization categories select: [:cat | self includesSystemCategory: cat]! !\\n\\n\\n!PackageInfo methodsFor: 'modifying' stamp: 'stephaneducasse 2/4/2006 20:40'!\\naddCoreMethod: aMethodReference\\n\\t| category |\\n\\tcategory := self baseCategoryOfMethod: aMethodReference.\\n\\taMethodReference actualClass organization\\n\\t\\tclassify: aMethodReference methodSymbol\\n\\t\\tunder: category\\n\\t\\tsuppressIfDefault: false! !\\n\\n!PackageInfo methodsFor: 'modifying' stamp: 'stephaneducasse 2/4/2006 20:40'!\\naddExtensionMethod: aMethodReference\\n\\t| category |\\n\\tcategory := self baseCategoryOfMethod: aMethodReference.\\n\\taMethodReference actualClass organization\\n\\t\\tclassify: aMethodReference methodSymbol\\n\\t\\tunder: self methodCategoryPrefix, '-', category! !\\n\\n!PackageInfo methodsFor: 'modifying' stamp: 'avi 10/11/2003 15:16'!\\naddMethod: aMethodReference\\n\\t(self includesClass: aMethodReference class)\\n\\t\\tifTrue: [self addCoreMethod: aMethodReference]\\n\\t\\tifFalse: [self addExtensionMethod: aMethodReference]! !\\n\\n!PackageInfo methodsFor: 'modifying' stamp: 'stephaneducasse 2/4/2006 20:40'!\\nbaseCategoryOfMethod: aMethodReference\\n\\t| oldCat oldPrefix tokens | \\n\\toldCat := aMethodReference category.\\n\\t({ 'as yet unclassified'. 'all' } includes: oldCat) ifTrue: [ oldCat := '' ].\\n\\ttokens := oldCat findTokens: '*-' keep: '*'.\\n\\n\\t\\\"Strip off any old prefixes\\\"\\n\\t((tokens at: 1 ifAbsent: [ '' ]) = '*') ifTrue: [\\n\\t\\t[ ((tokens at: 1 ifAbsent: [ '' ]) = '*') ]\\n\\t\\t\\twhileTrue: [ tokens removeFirst ].\\n\\t\\toldPrefix := tokens removeFirst asLowercase.\\n\\t\\t[ (tokens at: 1 ifAbsent: [ '' ]) asLowercase = oldPrefix ]\\n\\t\\t\\twhileTrue: [ tokens removeFirst ].\\n\\t].\\n\\n\\ttokens isEmpty ifTrue: [^ 'as yet unclassified'].\\n\\t^ String streamContents:\\n\\t\\t[ :s |\\n\\t\\ttokens\\n\\t\\t\\tdo: [ :tok | s nextPutAll: tok ]\\n\\t\\t\\tseparatedBy: [ s nextPut: $- ]]! !\\n\\n!PackageInfo methodsFor: 'modifying' stamp: 'al 3/1/2006 21:42'!\\nexternalBehaviors\\n\\t^self externalClasses , self externalTraits! !\\n\\n!PackageInfo methodsFor: 'modifying' stamp: 'al 3/1/2006 22:08'!\\nexternalTraits\\n\\t| behaviors |\\n\\t\\n\\t^ Array streamContents: [:s |\\n\\t\\tbehaviors := self classesAndMetaClasses.\\n\\t\\tSmalltalk allTraits do: [:trait |\\n\\t\\t\\t(behaviors includes: trait) ifFalse: [s nextPut: trait].\\n\\t\\t\\t(behaviors includes: trait classSide) ifFalse: [s nextPut: trait classSide]]].\\t\\t\\t! !\\n\\n!PackageInfo methodsFor: 'modifying' stamp: 'avi 10/11/2003 15:14'!\\nremoveMethod: aMethodReference! !\\n\\n\\n!PackageInfo methodsFor: 'naming' stamp: 'stephaneducasse 2/4/2006 20:40'!\\ncategoryName\\n\\t|category|\\n\\tcategory := self class category.\\n\\t^ (category endsWith: '-Info')\\n\\t\\tifTrue: [category copyUpToLast: $-]\\n\\t\\tifFalse: [category]! !\\n\\n!PackageInfo methodsFor: 'naming' stamp: 'ab 10/16/2002 21:22'!\\nexternalName\\n\\t^ self packageName! !\\n\\n!PackageInfo methodsFor: 'naming' stamp: 'stephaneducasse 2/4/2006 20:40'!\\nmethodCategoryPrefix\\n\\t^ methodCategoryPrefix ifNil: [methodCategoryPrefix := '*', self packageName asLowercase]! !\\n\\n!PackageInfo methodsFor: 'naming' stamp: 'stephaneducasse 2/4/2006 20:40'!\\npackageName\\n\\t^ packageName ifNil: [packageName := self categoryName]! !\\n\\n!PackageInfo methodsFor: 'naming' stamp: 'stephaneducasse 2/4/2006 20:40'!\\npackageName: aString\\n\\tpackageName := aString! !\\n\\n!PackageInfo methodsFor: 'naming' stamp: 'ab 10/28/2002 10:38'!\\nsystemCategoryPrefix\\n\\t^ self packageName! !\\n\\n\\n!PackageInfo methodsFor: 'registering' stamp: 'avi 11/12/2003 23:12'!\\nregister\\n\\tPackageOrganizer default registerPackage: self! !\\n\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'avi 3/9/2004 15:53'!\\ncategory: categoryName matches: prefix\\n\\t^ categoryName notNil and: [categoryName = prefix or: [categoryName beginsWith: prefix, '-']]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/13/2002 01:18'!\\ncoreCategoriesForClass: aClass\\n\\t^ aClass organization categories select: [:cat | (self isForeignClassExtension: cat) not]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/13/2002 01:22'!\\ncoreMethodsForClass: aClass\\n\\t^ (aClass selectors difference:\\n\\t\\t((self foreignExtensionMethodsForClass: aClass) collect: [:r | r methodSymbol]))\\n\\t\\t\\tasArray collect: [:sel | self referenceForMethod: sel ofClass: aClass]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/13/2002 01:20'!\\nextensionCategoriesForClass: aClass\\n\\t^ aClass organization categories select: [:cat | self isYourClassExtension: cat]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'avi 4/6/2004 15:16'!\\nextensionMethodsForClass: aClass\\n\\t^ (self extensionCategoriesForClass: aClass)\\n\\t\\tgather: [:cat | ((aClass organization listAtCategoryNamed: cat) ifNil: [#()])\\n\\t\\t\\t\\t\\t\\t\\tcollect: [:sel | self referenceForMethod: sel ofClass: aClass]]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'dvf 10/18/2002 23:22'!\\nextensionMethodsFromClasses: classes\\n\\t^classes\\n\\t\\tgather: [:class | self extensionMethodsForClass: class]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/13/2002 01:22'!\\nforeignExtensionCategoriesForClass: aClass\\n\\t^ aClass organization categories select: [:cat | self isForeignClassExtension: cat]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/13/2002 01:23'!\\nforeignExtensionMethodsForClass: aClass\\n\\t^ (self foreignExtensionCategoriesForClass: aClass)\\n\\t\\tgather: [:cat | (aClass organization listAtCategoryNamed: cat)\\n\\t\\t\\t\\t\\t\\t collect: [:sel | self referenceForMethod: sel ofClass: aClass]]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'dvf 7/23/2003 14:08'!\\nincludesClassNamed: aClassName\\n\\t^ self includesSystemCategory: ((SystemOrganization categoryOfElement: aClassName) ifNil: [^false])! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/13/2002 01:23'!\\nincludesClass: aClass\\n\\t^ self includesSystemCategory: aClass theNonMetaClass category! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'dvf 7/23/2003 14:06'!\\nincludesMethodCategory: categoryName ofClassNamed: aClass\\n\\t^ (self isYourClassExtension: categoryName)\\n\\t\\tor: [(self includesClassNamed: aClass)\\n\\t\\t\\t\\tand: [(self isForeignClassExtension: categoryName) not]]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'dvf 9/17/2002 00:18'!\\nincludesMethodCategory: categoryName ofClass: aClass\\n\\t^ (self isYourClassExtension: categoryName)\\n\\t\\tor: [(self includesClass: aClass)\\n\\t\\t\\t\\tand: [(self isForeignClassExtension: categoryName) not]]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/14/2002 18:06'!\\nincludesMethodReference: aMethodRef\\n\\t^ self includesMethod: aMethodRef methodSymbol ofClass: aMethodRef actualClass! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 12/5/2002 00:16'!\\nincludesMethod: aSymbol ofClass: aClass\\n\\taClass ifNil: [^ false].\\n\\t^ self\\n\\t\\tincludesMethodCategory: ((aClass organization categoryOfElement: aSymbol)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifNil: [' '])\\n\\t\\tofClass: aClass! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/13/2002 01:23'!\\nincludesSystemCategory: categoryName\\n\\t^ self category: categoryName matches: self systemCategoryPrefix! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/13/2002 01:23'!\\nisForeignClassExtension: categoryName\\n\\t^ categoryName first = $* and: [(self isYourClassExtension: categoryName) not]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'avi 11/10/2003 15:42'!\\nisOverrideMethod: aMethodReference\\n\\t^ aMethodReference category endsWith: '-override'! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'avi 3/10/2004 12:37'!\\nisYourClassExtension: categoryName\\n\\t^ categoryName notNil and: [self category: categoryName asLowercase matches: self methodCategoryPrefix]! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'dvf 10/18/2002 23:22'!\\noutsideClasses\\n\\t^ProtoObject withAllSubclasses difference: self classesAndMetaClasses! !\\n\\n!PackageInfo methodsFor: 'testing' stamp: 'ab 11/13/2002 01:25'!\\nreferenceForMethod: aSymbol ofClass: aClass\\n\\t^ MethodReference new setStandardClass: aClass methodSymbol: aSymbol! !\\n\\n\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPackageInfo class\\n\\tinstanceVariableNames: ''!\\n\\n!PackageInfo class methodsFor: 'class initialization' stamp: 'avi 2/18/2004 00:46'!\\ninitialize\\n\\tself allSubclassesDo: [:ea | ea new register]! !\\n\\n\\n!PackageInfo class methodsFor: 'compatibility' stamp: 'avi 3/9/2004 16:28'!\\ndefault\\n\\t^ self allPackages detect: [:ea | ea class = self] ifNone: [self new register]! !\\n\\n\\n!PackageInfo class methodsFor: 'packages access' stamp: 'nk 3/9/2004 10:49'!\\nallPackages\\n\\t^PackageOrganizer default packages! !\\n\\n!PackageInfo class methodsFor: 'packages access' stamp: 'avi 11/12/2003 23:00'!\\nnamed: aString\\n\\t^ PackageOrganizer default packageNamed: aString ifAbsent: [(self new packageName: aString) register]! !\\n\\n!PackageInfo class methodsFor: 'packages access' stamp: 'avi 11/11/2003 17:19'!\\nregisterPackageName: aString\\n\\t^ PackageOrganizer default registerPackageNamed: aString! !\\nObject subclass: #PackageOrganizer\\n\\tinstanceVariableNames: 'packages'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PackageInfo-Base'!\\n\\n!PackageOrganizer methodsFor: 'accessing' stamp: 'avi 11/12/2003 23:01'!\\npackageNames\\n\\t^ packages keys! !\\n\\n!PackageOrganizer methodsFor: 'accessing' stamp: 'avi 11/12/2003 23:01'!\\npackages\\n\\t^ packages values! !\\n\\n\\n!PackageOrganizer methodsFor: 'initializing' stamp: 'stephaneducasse 2/4/2006 20:40'!\\ninitialize\\n\\tpackages := Dictionary new! !\\n\\n\\n!PackageOrganizer methodsFor: 'registering' stamp: 'avi 11/12/2003 23:01'!\\nregisterPackage: aPackageInfo\\n\\tpackages at: aPackageInfo packageName put: aPackageInfo.\\n\\tself changed: #packages; changed: #packageNames.\\n! !\\n\\n!PackageOrganizer methodsFor: 'registering' stamp: 'avi 11/12/2003 21:08'!\\nregisterPackageNamed: aString\\n\\t^ self registerPackage: (PackageInfo named: aString)! !\\n\\n!PackageOrganizer methodsFor: 'registering' stamp: 'avi 11/12/2003 23:08'!\\nunregisterPackage: aPackageInfo\\n\\tpackages removeKey: aPackageInfo packageName ifAbsent: [].\\t\\n\\tself changed: #packages; changed: #packageNames.\\n! !\\n\\n!PackageOrganizer methodsFor: 'registering' stamp: 'avi 11/12/2003 21:10'!\\nunregisterPackageNamed: aString\\n\\tself unregisterPackage: (self packageNamed: aString ifAbsent: [^ self])! !\\n\\n\\n!PackageOrganizer methodsFor: 'searching' stamp: 'avi 10/11/2003 14:21'!\\nnoPackageFound\\n\\tself error: 'No package found'! !\\n\\n!PackageOrganizer methodsFor: 'searching' stamp: 'avi 11/12/2003 23:08'!\\npackageNamed: aString ifAbsent: errorBlock\\n\\t^ packages at: aString ifAbsent: errorBlock! !\\n\\n!PackageOrganizer methodsFor: 'searching' stamp: 'avi 10/11/2003 14:21'!\\npackageOfClass: aClass\\n\\t^ self packageOfClass: aClass ifNone: [self noPackageFound]! !\\n\\n!PackageOrganizer methodsFor: 'searching' stamp: 'avi 10/11/2003 14:22'!\\npackageOfClass: aClass ifNone: errorBlock\\n\\t^ self packages detect: [:ea | ea includesClass: aClass] ifNone: errorBlock! !\\n\\n!PackageOrganizer methodsFor: 'searching' stamp: 'avi 10/11/2003 14:21'!\\npackageOfMethod: aMethodReference\\n\\t^ self packageOfMethod: aMethodReference ifNone: [self noPackageFound]! !\\n\\n!PackageOrganizer methodsFor: 'searching' stamp: 'avi 10/11/2003 14:22'!\\npackageOfMethod: aMethodReference ifNone: errorBlock\\n\\t^ self packages detect: [:ea | ea includesMethodReference: aMethodReference] ifNone: errorBlock! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPackageOrganizer class\\n\\tinstanceVariableNames: 'default'!\\n\\n!PackageOrganizer class methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:40'!\\ndefault\\n\\t^ default ifNil: [default := self new]! !\\n\\n!PackageOrganizer class methodsFor: 'as yet unclassified' stamp: 'avi 10/13/2003 15:25'!\\nnew\\n\\t^ self basicNew initialize! !\\nBrowser subclass: #PackagePaneBrowser\\n\\tinstanceVariableNames: 'package packageListIndex packageList'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tools-Browser'!\\n!PackagePaneBrowser commentStamp: '<historical>' prior: 0!\\nA package browser represents a hierarchical query path through an organization of class and method information. It parses class categories into a two-level hierarchy on the first '-' character, giving \\\"packages\\\" (e.g., Magnitude, Collections, Graphics, etc.), and \\\"categories\\\" (e.g., Magnitude-General and Magnitude-Number).\\n\\nInstance Variables:\\n\\tpackage <Symbol> the \\\"category header,\\\" e.g., #Magnitudes or #Collections\\n\\tpackageListIndex <Integer> The index in the package list\\n\\tpackageList <OrderedCollection of String> the list of package names\\n!\\n\\n\\n!PackagePaneBrowser methodsFor: 'class list' stamp: 'JF 7/30/2003 12:26'!\\nclassList\\n\\t\\\"Answer an array of the class names of the selected category. Answer an \\n\\tempty array if no selection exists.\\\"\\n\\n\\t^ self hasSystemCategorySelected \\n\\t\\tifFalse:\\n\\t\\t\\t[self packageClasses]\\n\\t\\tifTrue: [systemOrganizer listAtCategoryNumber:\\n\\t\\t\\t(systemOrganizer categories indexOf: self selectedSystemCategoryName asSymbol)]! !\\n\\n!PackagePaneBrowser methodsFor: 'class list' stamp: 'JF 7/30/2003 12:36'!\\npackageClasses\\n\\t^ self categoryExistsForPackage\\n\\t\\tifFalse: [Array new]\\n\\t\\tifTrue:\\n\\t\\t\\t[systemOrganizer listAtCategoryNumber:\\n\\t\\t\\t\\t(systemOrganizer categories indexOf: self package asSymbol)]! !\\n\\n!PackagePaneBrowser methodsFor: 'class list' stamp: 'md 3/3/2006 11:04'!\\nselectedClass\\n\\t\\\"Answer the class that is currently selected. Answer nil if no selection \\n\\texists.\\\"\\n\\n\\t| name envt |\\n\\t(name := self selectedClassName) ifNil: [^ nil].\\n\\t\\\"(envt := self selectedEnvironment) ifNil: [^ nil].\\\"\\n\\tenvt:= Smalltalk.\\n\\t^ envt at: name! !\\n\\n\\n!PackagePaneBrowser methodsFor: 'dragNDrop' stamp: 'sd 11/20/2005 21:27'!\\nchangeCategoryForClass: class srcSystemCategory: srcSystemCategorySel atListMorph: dstListMorph internal: internal copy: copyFlag \\n\\t\\\"only move semantic\\\"\\n\\t| newClassCategory success |\\n\\tself flag: #stringSymbolProblem.\\n\\tsuccess := copyFlag not ifFalse: [^ false].\\n\\tnewClassCategory := self dstCategoryDstListMorph: dstListMorph internal: internal.\\n\\t(success := newClassCategory notNil & (newClassCategory ~= class category))\\n\\t\\tifTrue: \\n\\t\\t\\t[class category: newClassCategory.\\n\\t\\t\\tself changed: #classList.\\n\\t\\t\\tinternal ifFalse: [self selectClass: class]].\\n\\t^ success! !\\n\\n\\n!PackagePaneBrowser methodsFor: 'dragNDrop util' stamp: 'sd 11/20/2005 21:27'!\\ndstCategoryDstListMorph: dstListMorph internal: internal \\n\\t| dropItem |\\n\\t^ internal & (dstListMorph getListSelector == #systemCategoryList)\\n\\t\\tifTrue: [(dropItem := dstListMorph potentialDropItem) ifNotNil: [(self package , '-' , dropItem) asSymbol]]\\n\\t\\tifFalse: [self selectedSystemCategoryName]! !\\n\\n\\n!PackagePaneBrowser methodsFor: 'initialize-release' stamp: 'sw 1/13/2000 16:45'!\\ndefaultBrowserTitle\\n\\t^ 'Package Browser'! !\\n\\n!PackagePaneBrowser methodsFor: 'initialize-release' stamp: 'sd 11/20/2005 21:27'!\\nopenAsMorphEditing: editString \\n\\t\\\"Create a pluggable version of all the views for a Browser, including \\n\\tviews and controllers.\\\"\\n\\t\\\"PackagePaneBrowser openBrowser\\\"\\n\\n\\t| listHeight window |\\n\\tlistHeight := 0.4.\\n\\t(window := SystemWindow labelled: 'later') model: self.\\n\\twindow\\n\\t\\taddMorph: (PluggableListMorph\\n\\t\\t\\t\\ton: self\\n\\t\\t\\t\\tlist: #packageList\\n\\t\\t\\t\\tselected: #packageListIndex\\n\\t\\t\\t\\tchangeSelected: #packageListIndex:\\n\\t\\t\\t\\tmenu: #packageMenu:\\n\\t\\t\\t\\tkeystroke: #packageListKey:from:)\\n\\t\\tframe: (0 @ 0 extent: 0.15 @ listHeight).\\n\\twindow\\n\\t\\taddMorph: self buildMorphicSystemCatList\\n\\t\\tframe: (0.15 @ 0 extent: 0.2 @ listHeight).\\n\\tself\\n\\t\\taddClassAndSwitchesTo: window\\n\\t\\tat: (0.35 @ 0 extent: 0.25 @ listHeight)\\n\\t\\tplus: 0.\\n\\twindow\\n\\t\\taddMorph: self buildMorphicMessageCatList\\n\\t\\tframe: (0.6 @ 0 extent: 0.15 @ listHeight).\\n\\twindow\\n\\t\\taddMorph: self buildMorphicMessageList\\n\\t\\tframe: (0.75 @ 0 extent: 0.25 @ listHeight).\\n\\tself\\n\\t\\taddLowerPanesTo: window\\n\\t\\tat: (0 @ listHeight corner: 1 @ 1)\\n\\t\\twith: editString.\\n\\twindow setUpdatablePanesFrom: #(#packageList #systemCategoryList #classList #messageCategoryList #messageList ).\\n\\t^ window! !\\n\\n!PackagePaneBrowser methodsFor: 'initialize-release' stamp: 'stp 10/06/1998 22:02'!\\nsystemOrganizer: aSystemOrganizer \\n\\t\\\"Initialize the receiver as a perspective on the system organizer, \\n\\taSystemOrganizer. Typically there is only one--the system variable \\n\\tSystemOrganization.\\\"\\n\\n\\tsuper systemOrganizer: aSystemOrganizer .\\n\\tpackageListIndex := 0! !\\n\\n\\n!PackagePaneBrowser methodsFor: 'package list' stamp: 'JF 7/30/2003 12:35'!\\ncategoryExistsForPackage\\n\\t^ self hasPackageSelected\\n\\t\\tand: [(systemOrganizer categories indexOf: self package asSymbol) ~= 0]\\n! !\\n\\n!PackagePaneBrowser methodsFor: 'package list' stamp: 'JF 7/30/2003 12:24'!\\nhasPackageSelected\\n\\n\\t^ packageListIndex ~= 0! !\\n\\n!PackagePaneBrowser methodsFor: 'package list' stamp: 'sd 11/20/2005 21:27'!\\nopenEditString: aString\\n\\t\\\"Create a pluggable version of all the views for a Browser, including views and controllers.\\\"\\n\\t\\\"PackageBrowser openBrowser\\\"\\n\\n\\t| packageListView systemCategoryListView classListView messageCategoryListView\\n\\t messageListView browserCodeView topView switchView annotationPane underPane y optionalButtonsView |\\n\\n\\tself couldOpenInMorphic ifTrue: [^ self openAsMorphEditing: aString].\\n\\n\\ttopView := StandardSystemView new model: self.\\n\\ttopView borderWidth: 1. \\\"label and minSize taken care of by caller\\\"\\n\\n\\tpackageListView := PluggableListView on: self\\n\\t\\tlist: #packageList\\n\\t\\tselected: #packageListIndex\\n\\t\\tchangeSelected: #packageListIndex:\\n\\t\\tmenu: #packageMenu:.\\n\\tpackageListView window: (0 @ 0 extent: 20 @ 70).\\n\\ttopView addSubView: packageListView.\\n\\n\\tsystemCategoryListView := PluggableListView on: self\\n\\t\\tlist: #systemCategoryList\\n\\t\\tselected: #systemCategoryListIndex\\n\\t\\tchangeSelected: #systemCategoryListIndex:\\n\\t\\tmenu: #systemCategoryMenu:.\\n\\tsystemCategoryListView window: (20 @ 0 extent: 30 @ 70).\\n\\ttopView addSubView: systemCategoryListView.\\n\\n\\tclassListView := PluggableListView on: self\\n\\t\\tlist: #classList\\n\\t\\tselected: #classListIndex\\n\\t\\tchangeSelected: #classListIndex:\\n\\t\\tmenu: #classListMenu:shifted:.\\n\\tclassListView window: (0 @ 0 extent: 50 @ 62).\\n\\ttopView addSubView: classListView toRightOf: systemCategoryListView.\\n\\n\\tswitchView := self buildInstanceClassSwitchView.\\n\\tswitchView borderWidth: 1.\\n\\ttopView addSubView: switchView below: classListView.\\n\\n\\tmessageCategoryListView := PluggableListView on: self\\n\\t\\tlist: #messageCategoryList\\n\\t\\tselected: #messageCategoryListIndex\\n\\t\\tchangeSelected: #messageCategoryListIndex:\\n\\t\\tmenu: #messageCategoryMenu:.\\n\\tmessageCategoryListView window: (0 @ 0 extent: 50 @ 70).\\n\\ttopView addSubView: messageCategoryListView toRightOf: classListView.\\n\\n\\tmessageListView := PluggableListView on: self\\n\\t\\tlist: #messageList\\n\\t\\tselected: #messageListIndex\\n\\t\\tchangeSelected: #messageListIndex:\\n\\t\\tmenu: #messageListMenu:shifted:\\n\\t\\tkeystroke: #messageListKey:from:.\\n\\tmessageListView window: (0 @ 0 extent: 50 @ 70).\\n\\ttopView addSubView: messageListView toRightOf: messageCategoryListView.\\n\\n\\tself wantsAnnotationPane\\n\\t\\tifTrue:\\n\\t\\t\\t[annotationPane := PluggableTextView on: self\\n\\t\\t\\t\\ttext: #annotation accept: nil\\n\\t\\t\\t\\treadSelection: nil menu: nil.\\n\\t\\t\\tannotationPane window: (0@0 extent: 200@self optionalAnnotationHeight).\\n\\t\\t\\ttopView addSubView: annotationPane below: packageListView.\\n\\t\\t\\tunderPane := annotationPane.\\n\\t\\t\\ty := 110 - self optionalAnnotationHeight]\\n\\t\\tifFalse:\\n\\t\\t\\t[underPane := packageListView.\\n\\t\\t\\ty := 110].\\n\\n\\tself wantsOptionalButtons ifTrue:\\n\\t\\t[optionalButtonsView := self buildOptionalButtonsView.\\n\\t\\toptionalButtonsView borderWidth: 1.\\n\\t\\ttopView addSubView: optionalButtonsView below: underPane.\\n\\t\\tunderPane := optionalButtonsView.\\n\\t\\ty := y - self optionalButtonHeight].\\n\\n\\tbrowserCodeView := MvcTextEditor default on: self \\n\\t\\t\\ttext: #contents accept: #contents:notifying:\\n\\t\\t\\treadSelection: #contentsSelection menu: #codePaneMenu:shifted:.\\n\\tbrowserCodeView window: (0@0 extent: 200@y).\\n\\ttopView addSubView: browserCodeView below: underPane.\\n\\taString ifNotNil: [browserCodeView editString: aString.\\n\\t\\t\\tbrowserCodeView hasUnacceptedEdits: true].\\n\\t^ topView! !\\n\\n!PackagePaneBrowser methodsFor: 'package list' stamp: 'JF 7/30/2003 12:25'!\\npackage\\n\\t\\\"Answer the receiver's 'package'.\\\"\\n\\n\\t^ self hasPackageSelected\\n\\t\\tifFalse: [nil]\\n\\t\\tifTrue: [self packageList at: packageListIndex]\\n! !\\n\\n!PackagePaneBrowser methodsFor: 'package list' stamp: 'stp 10/05/1998 20:36'!\\npackageList\\n\\t\\\"Answer a list of the packages in the current system organization.\\\"\\n\\n\\t| str cats stream |\\n\\tstr := Set new: 100.\\n\\tstream := WriteStream on: (Array new: 100).\\n\\tsystemOrganizer categories do:\\n\\t\\t[ :categ | \\n\\t\\tcats := categ asString copyUpTo: $-.\\n\\t\\t(str includes: cats) ifFalse: \\n\\t\\t\\t[str add: cats.\\n\\t\\t\\tstream nextPut: cats]].\\n\\t^stream contents! !\\n\\n!PackagePaneBrowser methodsFor: 'package list' stamp: 'stp 10/05/1998 19:48'!\\npackageListIndex\\n\\t\\\"Answer the index of the current package selection.\\\"\\n\\n\\t^packageListIndex! !\\n\\n!PackagePaneBrowser methodsFor: 'package list' stamp: 'stp 12/01/1998 02:46'!\\npackageListIndex: anInteger \\n\\t\\\"Set anInteger to be the index of the current package selection.\\\"\\n\\n\\tpackageListIndex := anInteger.\\n\\tanInteger = 0\\n\\t\\tifFalse: [package := self packageList at: packageListIndex].\\n\\tmessageCategoryListIndex := 0.\\n\\tsystemCategoryListIndex := 0.\\n\\tmessageListIndex := 0.\\n\\tclassListIndex := 0.\\n\\tself setClassOrganizer.\\n\\tself changed: #packageSelectionChanged.\\n\\tself changed: #packageListIndex.\\t\\\"update my selection\\\"\\n\\tself changed: #systemCategoryList.\\t\\\"update the category list\\\"\\n\\tself systemCategoryListIndex: 0.\\t\\\"update category list selection\\\"\\n! !\\n\\n!PackagePaneBrowser methodsFor: 'package list' stamp: 'stp 10/06/1998 19:59'!\\npackageMenu: aMenu\\n\\t\\\"Answer a Menu of operations on class packages to be \\n\\tdisplayed when the operate menu button is pressed.\\\"\\n\\n\\t^aMenu\\n\\t\\t\\tlabels: 'find class...\\\\recent classes...\\\\reorganize\\\\update' withCRs\\n\\t\\t\\tlines: #(2)\\n\\t\\t\\tselections: #(#findClass #recent #editSystemCategories #updatePackages)! !\\n\\n!PackagePaneBrowser methodsFor: 'package list' stamp: 'nk 2/14/2004 15:09'!\\nupdatePackages\\n\\t\\\"Update the contents of the package list.\\\"\\n\\n\\tself editSelection: #none.\\n\\tself changed: #packageList.\\n\\tself changed: #package.\\n\\tself packageListIndex: 0 ! !\\n\\n\\n!PackagePaneBrowser methodsFor: 'system category list' stamp: 'JF 7/30/2003 12:23'!\\nhasSystemCategorySelected\\n\\t^ systemCategoryListIndex ~= 0! !\\n\\n!PackagePaneBrowser methodsFor: 'system category list' stamp: 'stp 01/13/2000 12:59'!\\nselectCategoryForClass: theClass\\n\\t\\\"Set the package and category lists to display the given class.\\\"\\n\\n\\t| cat |\\n\\tcat := theClass category.\\n\\tself packageListIndex: (self packageList indexOf: (cat copyUpTo: $-)).\\t\\n\\tself systemCategoryListIndex: (self systemCategoryList indexOf: \\n\\t\\t\\t(cat copyFrom: ((cat indexOf: $- ifAbsent: [0]) + 1) to: cat size)).! !\\n\\n!PackagePaneBrowser methodsFor: 'system category list' stamp: 'di 12/20/1999 20:16'!\\nselectedSystemCategoryName\\n\\t\\\"Answer the name of the selected system category or nil.\\\"\\n\\n\\tsystemCategoryListIndex = 0\\n\\t\\tifTrue: [^nil].\\n\\tpackageListIndex = 0\\n\\t\\tifTrue: [^ self systemCategoryList at: systemCategoryListIndex].\\n\\t^ self package , '-' , (self systemCategoryList at: systemCategoryListIndex)! !\\n\\n!PackagePaneBrowser methodsFor: 'system category list' stamp: 'di 12/16/1999 16:14'!\\nsystemCategoryList\\n\\t\\\"Answer the sequenceable collection containing the class categories that \\n\\tthe receiver accesses.\\\"\\n\\n\\t| prefix |\\n\\tpackageListIndex = 0 ifTrue: [^ systemOrganizer categories].\\n\\tprefix := self package, '-'.\\n\\t^ Array streamContents:\\n\\t\\t[:strm |\\n\\t\\tsystemOrganizer categories do: \\n\\t\\t\\t[ :cat | (cat beginsWith: prefix) ifTrue:\\n\\t\\t\\t\\t[strm nextPut: (cat copyFrom: prefix size + 1 to: cat size)]]]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPackagePaneBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!PackagePaneBrowser class methodsFor: 'class initialization' stamp: 'hpt 8/5/2004 20:12'!\\nregisterInAppRegistry\\n\\t\\\"Register the receiver in the SystemBrowser AppRegistry\\\"\\n\\tSystemBrowser register: self.! !\\n\\n\\n!PackagePaneBrowser class methodsFor: 'instance creation' stamp: 'sd 11/20/2005 21:28'!\\nprototypicalToolWindow\\n\\t\\\"Answer an example of myself seen in a tool window, for the benefit of parts-launching tools\\\"\\n\\n\\t| aWindow |\\n\\taWindow := self new openAsMorphEditing: nil.\\n\\taWindow setLabel: 'Package Browser'.\\n\\taWindow applyModelExtent.\\n\\t^ aWindow\\n! !\\n\\n\\n!PackagePaneBrowser class methodsFor: 'window color' stamp: 'sw 2/26/2002 14:39'!\\nwindowColorSpecification\\n\\t\\\"Answer a WindowColorSpec object that declares my preference\\\"\\n\\n\\t^ WindowColorSpec classSymbol: self name wording: 'Package Browser' brightColor: #(1.0 1.0 0.6)\\t pastelColor: #(0.976 0.976 0.835) helpMessage: 'A system browser with an extra pane at top-left for module.'! !\\n\\n\\n!PackagePaneBrowser class methodsFor: '*MorphicExtras-class initialization' stamp: 'hpt 8/5/2004 20:12'!\\ninitialize\\n\\n\\tself registerInFlapsRegistry;\\n\\t\\tregisterInAppRegistry.! !\\n\\n!PackagePaneBrowser class methodsFor: '*MorphicExtras-class initialization' stamp: 'asm 4/10/2003 13:15'!\\nregisterInFlapsRegistry\\n\\t\\\"Register the receiver in the system's flaps registry\\\"\\n\\tself environment\\n\\t\\tat: #Flaps\\n\\t\\tifPresent: [:cl | cl registerQuad: #(PackagePaneBrowser\\tprototypicalToolWindow\\t\\t'Packages'\\t\\t\\t'Package Browser: like a System Browser, except that if has extra level of categorization in the top-left pane, such that class-categories are further organized into groups called \\\"packages\\\"') \\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Tools']! !\\n\\n!PackagePaneBrowser class methodsFor: '*MorphicExtras-class initialization' stamp: 'hpt 8/5/2004 20:12'!\\nunload\\n\\t\\\"Unload the receiver from global registries\\\"\\n\\n\\tself environment at: #Flaps ifPresent: [:cl |\\n\\tcl unregisterQuadsWithReceiver: self].\\n\\tSystemBrowser unregister: self.! !\\nObject subclass: #PackageServices\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'ServiceClasses'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'PackageInfo-Base'!\\n\\n!PackageServices methodsFor: 'as yet unclassified' stamp: 'avi 10/11/2003 14:06'!\\nseeClassSide! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPackageServices class\\n\\tinstanceVariableNames: ''!\\n\\n!PackageServices class methodsFor: 'as yet unclassified' stamp: 'avi 10/11/2003 13:01'!\\nallServices\\n\\t^ ServiceClasses gather: [:ea | ea services]! !\\n\\n!PackageServices class methodsFor: 'as yet unclassified' stamp: 'stephaneducasse 2/4/2006 20:40'!\\ninitialize\\n\\tServiceClasses := Set new! !\\n\\n!PackageServices class methodsFor: 'as yet unclassified' stamp: 'avi 10/11/2003 12:59'!\\nregister: aClass\\n\\tServiceClasses add: aClass! !\\n\\n!PackageServices class methodsFor: 'as yet unclassified' stamp: 'avi 10/11/2003 12:59'!\\nunregister: aClass\\n\\tServiceClasses remove: aClass! !\\nImageMorph subclass: #PaintBoxColorPicker\\n\\tinstanceVariableNames: 'currentColor locOfCurrent'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Support'!\\n!PaintBoxColorPicker commentStamp: 'JMM 9/13/2004 07:37' prior: 0!\\nA pop-up, 32-bit color palette used as part of a PaintBoxMorph.\\n!\\n\\n\\n!PaintBoxColorPicker methodsFor: 'accessing' stamp: 'jm 4/29/1998 20:07'!\\ncurrentColor\\n\\n\\t^ currentColor\\n! !\\n\\n!PaintBoxColorPicker methodsFor: 'accessing' stamp: 'jm 4/29/1998 20:18'!\\ncurrentColor: aColor\\n\\t\\\"Force me to select the given color.\\\"\\n\\n\\tcurrentColor _ aColor.\\n\\tlocOfCurrent _ nil. \\\"remove the marker\\\"\\n! !\\n\\n\\n!PaintBoxColorPicker methodsFor: 'drawing' stamp: 'jm 4/29/1998 20:00'!\\ndrawOn: aCanvas\\n\\t\\\"Image plus circles for currently selected color.\\\"\\n\\n\\t| c |\\n\\tsuper drawOn: aCanvas.\\n\\tlocOfCurrent ifNotNil: [\\n\\t\\tc _ self ringColor.\\n\\t\\taCanvas\\n\\t\\t\\tfillOval: (Rectangle center: locOfCurrent + self topLeft extent: 9@9)\\n\\t\\t\\tcolor: Color transparent\\n\\t\\t\\tborderWidth: 1\\n\\t\\t\\tborderColor: c].\\n! !\\n\\n!PaintBoxColorPicker methodsFor: 'drawing' stamp: 'jm 4/29/1998 20:00'!\\nringColor\\n\\t\\\"Choose a color that contrasts with my current color. If that color isn't redish, return red. Otherwise, return green\\\"\\n\\n\\tcurrentColor isTransparent ifTrue: [^ Color red].\\n\\tcurrentColor red < 0.5 ifTrue: [^ Color red].\\n\\tcurrentColor red > (currentColor green + (currentColor blue * 0.5))\\n\\t\\tifTrue: [^ Color green]\\n\\t\\tifFalse: [^ Color red].\\n! !\\n\\n\\n!PaintBoxColorPicker methodsFor: 'event handling' stamp: 'ar 10/5/2000 16:01'!\\nendColorSelection: evt\\n\\t\\\"Update current color and report it to paint box.\\\"\\n\\n\\tself selectColor: evt.\\n\\t\\\"restore mouseLeave handling\\\"\\n\\tself on: #mouseLeave send: #delete to: self.\\n! !\\n\\n!PaintBoxColorPicker methodsFor: 'event handling' stamp: 'ar 10/25/2000 17:49'!\\ninitMouseHandlers\\n\\n\\tself on: #mouseDown send: #startColorSelection: to: self.\\n\\tself on: #mouseMove send: #selectColor: to: self.\\n\\tself on: #mouseUp send: #endColorSelection: to: self.\\n\\tself on: #mouseLeave send: #delete to: self.\\n! !\\n\\n!PaintBoxColorPicker methodsFor: 'event handling' stamp: 'JMM 9/13/2004 09:08'!\\nselectColor: evt \\n\\t\\\"Update the receiver from the given event. Constrain locOfCurrent's center to lie within the color selection area. If it is partially in the transparent area, snap it entirely into it vertically.\\\"\\n\\n\\t| r |\\n\\n\\tlocOfCurrent := evt cursorPoint - self topLeft.\\n\\tr := Rectangle center: locOfCurrent extent: 9 @ 9.\\n\\tlocOfCurrent := locOfCurrent \\n\\t\\t\\t\\t+ (r amountToTranslateWithin: (8 @ 11 corner: (self image width-6) @ (self image height-6))).\\n\\tlocOfCurrent x > (self image width-(12+7)) ifTrue: [locOfCurrent := (self image width - 12) @ locOfCurrent y].\\t\\\"snap into grayscale\\\"\\n\\tcurrentColor := locOfCurrent y < 19\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[locOfCurrent := locOfCurrent x @ 11.\\t\\\"snap into transparent\\\"\\n\\t\\t\\t\\t\\tColor transparent]\\n\\t\\t\\t\\tifFalse: [image colorAt: locOfCurrent].\\n\\t(owner isKindOf: PaintBoxMorph) \\n\\t\\tifTrue: [owner takeColorEvt: evt from: self].\\n\\tself changed! !\\n\\n!PaintBoxColorPicker methodsFor: 'event handling' stamp: 'jm 4/29/1998 21:21'!\\nstartColorSelection: evt\\n\\t\\\"Start color selection. Make me stay up as long as the mouse is down.\\\"\\n\\n\\tself on: #mouseLeave send: nil to: nil.\\n\\tself selectColor: evt.\\n! !\\n\\n\\n!PaintBoxColorPicker methodsFor: 'initialization' stamp: 'RAA 8/15/2000 14:57'!\\nbeStatic\\n\\n\\t\\\"an aid for Nebraska: make the color chart a static image to reduce traffic\\\"\\n\\timage isStatic ifFalse: [\\n\\t\\timage _ image as: StaticForm\\n\\t].! !\\n\\n!PaintBoxColorPicker methodsFor: 'initialization' stamp: 'jm 4/29/1998 21:24'!\\ninitialize\\n\\n\\tsuper initialize.\\n\\tcurrentColor _ Color black.\\n\\tlocOfCurrent _ nil.\\n\\tself initMouseHandlers.\\n! !\\nImageMorph subclass: #PaintBoxMorph\\n\\tinstanceVariableNames: 'action tool currentCursor thumbnail currentColor currentBrush colorMemory colorPatch stampHolder rotationTabForm scaleTabForm colorMemoryThin brushes focusMorph weakDependents recentColors'\\n\\tclassVariableNames: 'AllOffImage AllOnImage AllPressedImage ColorChart OriginalBounds Prototype RecentColors'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Support'!\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'laza 3/24/2000 17:58'!\\naction\\n\\t^ action\\t! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 13:35'!\\nactionCursor\\n\\t\\\"Return the cursor to use with this painting action/tool. Offset of the form must be set.\\\"\\n\\n\\t^self\\n\\t\\tcursorFor: action\\n\\t\\toldCursor: currentCursor\\n\\t\\tcurrentNib: self getNib\\n\\t\\tcolor: currentColor\\n! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'dgd 2/22/2003 19:03'!\\nbrush: brushButton action: aSelector nib: aMask evt: evt \\n\\t\\\"Set the current tool and action for the paintBox. \\\"\\n\\n\\tcurrentBrush \\n\\t\\tifNotNil: [currentBrush == brushButton ifFalse: [currentBrush state: #off]].\\n\\tcurrentBrush := brushButton.\\t\\\"A ThreePhaseButtonMorph\\\"\\n\\n\\t\\\"currentBrush state: #on.\\talready done\\\"\\n\\t\\\"aSelector is like brush3:. Don't save it. Can always say (currentBrush arguments at: 2)\\n\\taMask is the brush shape. Don't save it. Can always say (currentBrush arguments at: 3)\\\"\\n\\tself notifyWeakDependentsWith: { \\n\\t\\t\\t\\t#currentNib.\\n\\t\\t\\t\\tevt.\\n\\t\\t\\t\\tcurrentBrush arguments third}.\\n\\tself brushable ifFalse: [self setAction: #paint: evt: evt]\\t\\\"User now thinking of painting\\\"! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 10/19/97 11:12'!\\nbrushable\\n\\t\\\"Return true if the current tool uses a brush.\\\"\\n\\t^ (#(\\\"non-brushable\\\" eyedropper: fill: pickup: stamp:) indexOf: action) = 0! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 01:34'!\\nclear: clearButton with: clearSelector evt: evt\\n\\n\\t| ss |\\n\\t(ss _ self focusMorph) \\n\\t\\tifNotNil: [ss clearPainting: self]\\n\\t\\tifNil: [self notCurrentlyPainting].\\n\\tclearButton state: #off.! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 7/15/97 13:35'!\\ncolorable\\n\\t\\\"Return true if the current tool uses a color.\\\"\\n\\t^ (#(\\\"These use no color\\\" erase: eyedropper: \\\"fill: does\\\" pickup: stamp:) indexOf: action) = 0! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/17/2000 17:06'!\\ncurrentColor: aColor evt: evt\\n\\t\\\"Accept a color from the outside. (my colorMemoryMorph must call takeColorEvt: evt from: colorPicker instead)\\\"\\n\\n\\tcurrentColor _ aColor.\\n\\tcolorMemory currentColor: aColor.\\n\\tself notifyWeakDependentsWith: {#currentColor. evt. currentColor}.\\n\\tself showColor.\\n\\tself colorable ifFalse: [self setAction: #paint: evt: evt].\\t\\\"User now thinking of painting\\\"! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 13:37'!\\ncursorFor: anAction oldCursor: oldCursor currentNib: aNibForm color: aColor \\n\\t\\\"Return the cursor to use with this painting action/tool. Offset of the \\n\\tform must be set.\\\"\\n\\n\\t| ff width co larger c box |\\n\\n\\tanAction == #paint:\\n\\t\\tifTrue: [\\\"Make a cursor from the brush and the color\\\"\\n\\t\\t\\twidth _ aNibForm width.\\n\\t\\t\\tc _ self ringColorFor: aColor.\\n\\t\\t\\tco _ oldCursor offset - (width // 4 @ 34 - (width // 6)) min: 0 @ 0.\\n\\t\\t\\tlarger _ width negated + 10 @ 0 extent: oldCursor extent + (width @ width).\\n\\t\\t\\tff _ oldCursor copy: larger.\\n\\t\\t\\tff colors at: 1 put: Color transparent.\\n\\t\\t\\tff colors at: 2 put: Color transparent.\\n\\t\\t\\tff offset: co - (width @ width // 2).\\n\\t\\t\\tff getCanvas\\n\\t\\t\\t\\tfillOval: (Rectangle center: ff offset negated extent: width @ width)\\n\\t\\t\\t\\tcolor: Color transparent\\n\\t\\t\\t\\tborderWidth: 1\\n\\t\\t\\t\\tborderColor: c.\\n\\t\\t\\t^ ff].\\n\\tanAction == #erase:\\n\\t\\tifTrue: [\\\"Make a cursor from the cursor and the color\\\"\\n\\t\\t\\twidth _ aNibForm width.\\n\\t\\t\\tco _ oldCursor offset + (width // 2 @ 4) min: 0 @ 0.\\n\\t\\t\\tlarger _ 0 @ 0 extent: oldCursor extent + (width @ width).\\n\\t\\t\\tff _ oldCursor copy: larger.\\n\\t\\t\\tff offset: co - (width @ width // 2).\\n\\t\\t\\tff\\n\\t\\t\\t\\tfill: (box _ co negated extent: width @ width)\\n\\t\\t\\t\\tfillColor: (Color r: 0.5 g: 0.5 b: 1.0).\\n\\t\\t\\tff\\n\\t\\t\\t\\tfill: (box insetBy: 1 @ 1)\\n\\t\\t\\t\\tfillColor: Color transparent.\\n\\t\\t\\t^ ff].\\n\\t^ oldCursor! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'dgd 2/22/2003 19:03'!\\ndeleteCurrentStamp: evt \\n\\t\\\"The trash is telling us to delete the currently selected stamp\\\"\\n\\n\\t(tool arguments second) == #stamp: \\n\\t\\tifTrue: \\n\\t\\t\\t[stampHolder remove: tool.\\n\\t\\t\\tself setAction: #paint: evt: evt]\\t\\\"no use stamping with a blank stamp\\\"! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'JMM 9/13/2004 09:47'!\\neyedropper: aButton action: aSelector cursor: aCursor evt: evt \\n\\t\\\"Take total control and pick up a color!!!!\\\"\\n\\n\\t| pt feedbackColor delay |\\n\\tdelay _ Delay forMilliseconds: 10.\\n\\taButton state: #on.\\n\\ttool ifNotNil: [tool state: #off].\\n\\tcurrentCursor := aCursor.\\n\\tevt hand showTemporaryCursor: currentCursor\\n\\t\\thotSpotOffset: 6 negated @ 4 negated.\\n\\t\\\"<<<< the form was changed a bit??\\\"\\n\\tfeedbackColor := Display colorAt: Sensor cursorPoint.\\n\\tcolorMemory align: colorMemory bounds topRight\\n\\t\\twith: colorMemoryThin bounds topRight.\\n\\tself addMorphFront: colorMemory.\\n\\n\\t\\\"Full color picker\\\"\\n\\t[Sensor anyButtonPressed] whileFalse: \\n\\t\\t\\t[pt := Sensor cursorPoint.\\n\\t\\t\\t\\\"deal with the fact that 32 bit displays may have garbage in the \\n\\t\\t\\talpha bits\\\"\\n\\t\\t\\tfeedbackColor := Display depth = 32 \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[Color colorFromPixelValue: ((Display pixelValueAt: pt) bitOr: 4278190080)\\n\\t\\t\\t\\t\\t\\t\\t\\tdepth: 32]\\n\\t\\t\\t\\t\\t\\tifFalse: [Display colorAt: pt].\\n\\t\\t\\t\\\"the hand needs to be drawn\\\"\\n\\t\\t\\tevt hand position: pt.\\n\\t\\t\\tcurrentColor ~= feedbackColor ifTrue: [\\n\\t\\t\\t\\tcurrentColor _ feedbackColor.\\n\\t\\t\\t\\tself showColor ].\\n\\t\\t\\tself world displayWorldSafely.\\n\\t\\t\\tdelay wait].\\n\\n\\t\\\"Now wait for the button to be released.\\\"\\n\\t[Sensor anyButtonPressed] whileTrue:\\n\\t\\t[ pt := Sensor cursorPoint.\\n\\t\\t\\\"the hand needs to be drawn\\\"\\n\\t\\tevt hand position: pt.\\n\\t\\tself world displayWorldSafely.\\n\\t\\tdelay wait].\\n\\n\\tevt hand showTemporaryCursor: nil hotSpotOffset: 0 @ 0.\\n\\tself currentColor: feedbackColor evt: evt.\\n\\tcolorMemory delete.\\n\\ttool ifNotNil: \\n\\t\\t\\t[tool state: #on.\\n\\t\\t\\tcurrentCursor := tool arguments third].\\n\\taButton state: #off\\n! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 7/1/97 12:52'!\\ngetColor\\n\\t^ currentColor! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'dgd 2/22/2003 19:03'!\\ngetNib\\n\\t^currentBrush arguments third! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 7/1/97 13:02'!\\ngetSpecial\\n\\t^ action\\t\\t\\\"a selector like #paint:\\\"! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'dgd 2/21/2003 23:17'!\\ngrabFromScreen: evt \\n\\t\\\"Allow the user to grab a picture from the screen OUTSIDE THE PAINTING AREA and install it in a blank stamp. To get a stamp in the painting area, click on the stamp tool in a blank stamp.\\\"\\n\\n\\t\\\"scroll to blank stamp\\\"\\n\\n\\t| stampButton form |\\n\\tstampButton := stampHolder stampButtons first.\\n\\t[(stampHolder stampFormFor: stampButton) isNil] \\n\\t\\twhileFalse: [stampHolder scroll: 1].\\n\\tform := Form fromUser.\\n\\ttool state: #off.\\n\\ttool := stampHolder otherButtonFor: stampButton.\\n\\tstampHolder stampForm: form for: tool.\\t\\\"install it\\\"\\n\\tstampButton state: #on.\\n\\tstampButton doButtonAction: evt.\\n\\tevt hand showTemporaryCursor: (focusMorph getCursorFor: evt)! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'sw 8/29/2000 15:31'!\\nindicateColorUnderMouse\\n\\t\\\"Track the mouse with the special eyedropper cursor, and accept whatever color is under the mouse as the currently-chosen color; reflect that choice in the feedback box, and return that color.\\\"\\n\\n\\t| pt feedbackColor |\\n\\tpt _ Sensor cursorPoint.\\n\\t\\\"deal with the fact that 32 bit displays may have garbage in the alpha bits\\\"\\n\\tfeedbackColor _ Display depth = 32\\n\\t\\tifTrue: [ Color colorFromPixelValue: ((Display pixelValueAt: pt) bitOr: 16rFF000000) depth: 32] \\t\\tifFalse: [Display colorAt: pt].\\n\\n\\tself activeHand position: pt.\\n\\tself world displayWorldSafely.\\n\\tDisplay fill: colorPatch bounds fillColor: feedbackColor.\\n\\t^ feedbackColor\\t! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 01:48'!\\nkeep: keepButton with: keepSelector evt: evt\\n\\t\\\"Showing of the corrent palette (viewer or noPalette) is done by the block submitted to the SketchMorphEditor, see (EToyHand makeNewDrawing) and (SketchMorph editDrawingInWorld:forBackground:).\\\"\\n\\t| ss |\\n\\towner ifNil: [^ self].\\n\\tkeepButton ifNotNil: [keepButton state: #off].\\n\\t(ss _ self focusMorph) \\n\\t\\tifNotNil: [ss savePainting: self evt: evt]\\n\\t\\tifNil:\\n\\t\\t[keepSelector == #silent ifTrue: [^ self].\\n\\t\\tself notCurrentlyPainting].! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'sw 5/3/1998 18:22'!\\nnotCurrentlyPainting\\n\\tself inform: 'You are not currently painting'! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'dgd 2/22/2003 19:04'!\\npickup: actionButton action: aSelector cursor: aCursor evt: evt \\n\\t\\\"Special version for pickup: and stamp:, because of these tests\\\"\\n\\n\\t| ss picker old map stamper |\\n\\tself \\n\\t\\ttool: actionButton\\n\\t\\taction: aSelector\\n\\t\\tcursor: aCursor\\n\\t\\tevt: evt.\\n\\taSelector == #stamp: \\n\\t\\tifTrue: \\n\\t\\t\\t[(stampHolder pickupButtons includes: actionButton) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[stamper := stampHolder otherButtonFor: actionButton.\\n\\t\\t\\t\\t\\t^self \\n\\t\\t\\t\\t\\t\\tpickup: stamper\\n\\t\\t\\t\\t\\t\\taction: #stamp:\\n\\t\\t\\t\\t\\t\\tcursor: (stamper arguments third)\\n\\t\\t\\t\\t\\t\\tevt: evt].\\n\\t\\t\\t(stampHolder stampFormFor: actionButton) ifNil: \\n\\t\\t\\t\\t\\t[\\\"If not stamp there, go to pickup mode\\\"\\n\\n\\t\\t\\t\\t\\tpicker := stampHolder otherButtonFor: actionButton.\\n\\t\\t\\t\\t\\tpicker state: #on.\\n\\t\\t\\t\\t\\t^self \\n\\t\\t\\t\\t\\t\\tpickup: picker\\n\\t\\t\\t\\t\\t\\taction: #pickup:\\n\\t\\t\\t\\t\\t\\tcursor: (picker arguments third)\\n\\t\\t\\t\\t\\t\\tevt: evt]\\n\\t\\t\\t\\tifNotNil: \\n\\t\\t\\t\\t\\t[old := stampHolder stampFormFor: actionButton.\\n\\t\\t\\t\\t\\tcurrentCursor := ColorForm extent: old extent depth: 8.\\n\\t\\t\\t\\t\\told displayOn: currentCursor.\\n\\t\\t\\t\\t\\tmap := Color indexedColors copy.\\n\\t\\t\\t\\t\\tmap at: 1 put: Color transparent.\\n\\t\\t\\t\\t\\tcurrentCursor colors: map.\\n\\t\\t\\t\\t\\tcurrentCursor offset: currentCursor extent // -2.\\n\\t\\t\\t\\t\\t\\\"Emphisize the stamp button\\\"\\n\\t\\t\\t\\t\\tactionButton owner borderColor: (Color \\n\\t\\t\\t\\t\\t\\t\\t\\tr: 0.65\\n\\t\\t\\t\\t\\t\\t\\t\\tg: 0.599\\n\\t\\t\\t\\t\\t\\t\\t\\tb: 0.8)\\t\\\"layoutMorph\\\"\\t\\\"color: (Color r: 1.0 g: 0.645 b: 0.419);\\\"]].\\n\\taSelector == #pickup: \\n\\t\\tifTrue: \\n\\t\\t\\t[ss := self focusMorph.\\n\\t\\t\\tss ifNotNil: [currentCursor := aCursor]\\n\\t\\t\\t\\tifNil: \\n\\t\\t\\t\\t\\t[self notCurrentlyPainting.\\n\\t\\t\\t\\t\\tself setAction: #paint: evt: evt]]! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 7/2/97 22:13'!\\npickupForm: stampForm\\n\\t\\\"Install the new picture in this stamp\\\"\\n\\n\\t| stampButton |\\n\\tstampHolder stampForm: stampForm for: tool.\\n\\tstampButton _ action == #pickup: \\n\\t\\tifTrue: [stampHolder otherButtonFor: tool]\\n\\t\\tifFalse: [tool].\\t\\\"was a nil stampForm\\\"\\n\\tstampButton state: #on.\\n\\tstampButton doButtonAction.! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/17/2000 14:59'!\\npickupForm: stampForm evt: evt\\n\\t\\\"Install the new picture in this stamp\\\"\\n\\n\\t| stampButton |\\n\\tstampHolder stampForm: stampForm for: tool.\\n\\tstampButton _ action == #pickup: \\n\\t\\tifTrue: [stampHolder otherButtonFor: tool]\\n\\t\\tifFalse: [tool].\\t\\\"was a nil stampForm\\\"\\n\\tstampButton state: #on.\\n\\tstampButton doButtonAction: evt.! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 13:40'!\\nplainCursor\\n\\t\\\"Return the cursor to use with this painting action/tool. Offset of the form must be set.\\\"\\n\\n\\t^currentCursor\\n! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'ar 10/10/2000 16:38'!\\nplainCursor: aCursor event: anEvent\\n\\t\\\"Set the cursor to use with this painting action/tool. Offset of the form must be set.\\\"\\n\\n\\tcurrentCursor _ aCursor.\\n\\tanEvent hand showTemporaryCursor: aCursor.\\n\\tself notifyWeakDependentsWith: {#currentCursor. anEvent. currentCursor}.! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 13:30'!\\nringColor\\n\\t\\\"Choose a color that contrasts with my current color. If that color isn't redish, return red. Otherwise, return green\\\"\\n\\n\\t^self ringColorFor: currentColor\\n! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 13:29'!\\nringColorFor: aColor\\n\\t\\\"Choose a color that contrasts with my current color. If that color isn't redish, return red. Otherwise, return green\\\"\\n\\n\\taColor isTransparent ifTrue: [^ Color red].\\n\\taColor red < 0.5 ifTrue: [^ Color red].\\n\\taColor red > (aColor green + (aColor blue * 0.5))\\n\\t\\tifTrue: [^ Color green]\\n\\t\\tifFalse: [^ Color red].\\n! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 01:44'!\\nscrollStamps: actionButton action: aSelector evt: evt\\n\\t\\\"Move the stamps over\\\"\\n\\n\\taSelector == #prevStamp:\\n\\t\\tifTrue: [stampHolder scroll: -1]\\n\\t\\tifFalse: [stampHolder scroll: 1].\\n\\tactionButton state: #off.\\n\\taction == #stamp: ifTrue: [\\\"reselect the stamp and compute the cursor\\\"\\n\\t\\tself stampForm \\n\\t\\t\\tifNil: [self setAction: #paint: evt: evt]\\n\\t\\t\\tifNotNil: [tool doButtonAction: evt]].\\n\\t\\t! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 8/22/2000 11:57'!\\nsetAction: aSelector evt: evt\\n\\t\\\"Find this button and turn it on. Does not work for stamps or pickups\\\"\\n\\n\\t| button |\\n\\tbutton _ self submorphNamed: aSelector.\\n \\n\\tbutton ifNotNil: [\\n\\t\\tbutton state: #on.\\n\\t\\tbutton doButtonAction: evt].\\t\\\"select it!!\\\"! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'dgd 2/22/2003 19:04'!\\nshowColor\\n\\t\\\"Display the current color in all brushes, both on and off.\\\"\\n\\n\\t| offIndex onIndex center |\\n\\tcurrentColor ifNil: [^self].\\n\\t\\\"colorPatch color: currentColor.\\tMay delete later\\\"\\n\\t(brushes isNil or: [brushes first owner ~~ self]) \\n\\t\\tifTrue: \\n\\t\\t\\t[brushes := OrderedCollection new.\\n\\t\\t\\t#(#brush1: #brush2: #brush3: #brush4: #brush5: #brush6:) \\n\\t\\t\\t\\tdo: [:sel | brushes addLast: (self submorphNamed: sel)]].\\n\\tcenter := (brushes sixth) offImage extent // 2.\\n\\toffIndex := (brushes sixth) offImage pixelValueAt: center.\\n\\tonIndex := (brushes sixth) onImage pixelValueAt: center.\\n\\tbrushes do: \\n\\t\\t\\t[:bb | \\n\\t\\t\\tbb offImage colors at: offIndex + 1 put: currentColor.\\n\\t\\t\\tbb offImage clearColormapCache.\\n\\t\\t\\tbb onImage colors at: onIndex + 1 put: currentColor.\\n\\t\\t\\tbb onImage clearColormapCache.\\n\\t\\t\\tbb invalidRect: bb bounds].\\n\\tself invalidRect: (brushes first topLeft rect: brushes last bottomRight)! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'ar 12/19/2000 19:16'!\\nshowColorPalette: evt\\n\\n\\t| w box |\\n\\tself comeToFront.\\n\\tcolorMemory align: colorMemory bounds topRight \\n\\t\\t\\twith: colorMemoryThin bounds topRight.\\n\\t\\\"make sure color memory fits or else align with left\\\"\\n\\tw _ self world.\\n\\tbox _ self bounds: colorMemory fullBounds in: w.\\n\\tbox left < 0 ifTrue:[\\n\\t\\tcolorMemory align: colorMemory bounds topLeft\\n\\t\\t\\twith: colorMemoryThin bounds topLeft].\\n\\tself addMorphFront: colorMemory.! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 8/22/2000 11:58'!\\nstampCursorBeCursorFor: anAction\\n\\t\\\"User just chose a stamp. Take that stamp picture and make it be the cursor for the tool named.\\\"\\n\\t\\\"self stampCursorBeCursorFor: #star:.\\n\\tcurrentCursor offset: -9@-3.\\t\\t\\tHas side effect on the saved cursor.\\\"\\n\\n\\t(self submorphNamed: anAction) arguments at: 3 put: currentCursor.\\n\\t\\t\\\"Already converted to 8 bits and in the right form\\\"! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'di 5/6/1998 21:08'!\\nstampDeEmphasize\\n\\t\\\"Turn off an emphasized stamp. Was turned on in pickup:action:cursor:\\\"\\n\\n\\ttool owner class == AlignmentMorph ifTrue: [\\n\\t\\ttool \\\"actionButton\\\" owner \\\"layoutMorph\\\" color: Color transparent; \\n\\t\\t\\t\\t\\tborderColor: Color transparent].! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 7/2/97 14:02'!\\nstampForm\\n\\t\\\"Return the selected stamp\\\"\\n\\n\\t^ stampHolder stampFormFor: tool.\\n! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 7/17/97 11:47'!\\nstampHolder\\n\\n\\t^ stampHolder! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 7/17/97 11:48'!\\nstampHolder: newOne\\n\\n\\tstampHolder _ newOne! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'ar 9/23/2000 20:00'!\\ntakeColor: aColor event: evt\\n\\t\\\"Accept the given color programmatically\\\"\\n\\tcurrentColor _ aColor.\\n\\tself notifyWeakDependentsWith: {#currentColor. evt. currentColor}.\\n\\tself showColor.\\n\\tself colorable ifFalse: [self setAction: #paint: evt: evt].\\t\\\"User now thinking of painting\\\"! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'ar 9/23/2000 20:39'!\\ntakeColorEvt: evt from: colorPicker\\n\\t\\\"Accept a new color from the colorMemory. Programs use currentColor: instead. Do not do this before the picker has a chance to set its own color!!\\\"\\n\\t^self takeColor: colorPicker currentColor event: evt! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 8/21/2000 16:06'!\\ntoggleShapes\\n\\t| tab sh stamps |\\n\\t\\\"The sub panel that has the shape tools on it. Rect, line...\\\"\\n\\tstamps _ self submorphNamed: 'stamps'.\\n\\ttab _ self submorphNamed: 'shapeTab'.\\n\\t(sh _ self submorphNamed: 'shapes') visible\\n\\t\\tifTrue: [sh hide. tab top: stamps bottom-1]\\n\\t\\tifFalse: [sh comeToFront. sh top: stamps bottom-9. \\n\\t\\t\\t\\tsh show. tab top: sh bottom - tab height + 10].\\n\\tself layoutChanged.\\n! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 8/21/2000 15:57'!\\ntoggleStamps\\n\\t| tab otherTab st shapes |\\n\\t\\\"The sub panel that has the stamps in it. For saving and moving parts of an image.\\\"\\n\\tshapes _ self submorphNamed: 'shapes'.\\n\\totherTab _ self submorphNamed: 'shapeTab'.\\n\\ttab _ self submorphNamed: 'stampTab'.\\n\\t(st _ self submorphNamed: 'stamps') visible\\n\\t\\tifTrue: [st hide. st bottom: self bottom. tab top: self bottom-1.\\n\\t\\t\\t\\tshapes top: self bottom-9.\\n\\t\\t\\t\\totherTab top: (shapes visible ifTrue: [shapes bottom - otherTab height + 10] \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [self bottom-1])]\\n\\t\\tifFalse: [st top: self bottom-10. st show. tab top: st bottom-0.\\n\\t\\t\\t\\tshapes top: st bottom-9.\\n\\t\\t\\t\\totherTab top: (shapes visible ifTrue: [shapes bottom - otherTab height + 10] \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [st bottom-0])].\\n\\tself layoutChanged.! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'tk 7/1/97 12:09'!\\ntool\\n\\t^ tool! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 12:38'!\\ntool: actionButton action: aSelector cursor: aCursor evt: evt\\n\\t\\\"Set the current tool and action for the paintBox. \\\"\\n\\n\\ttool ifNotNil: [\\n\\t\\ttool == actionButton ifFalse: [\\n\\t\\t\\ttool state: #off.\\n\\t\\t\\taction == #stamp: ifTrue: [self stampDeEmphasize]]].\\n\\ttool _ actionButton.\\t\\t\\\"A ThreePhaseButtonMorph\\\"\\n\\t\\\"tool state: #on.\\talready done\\\"\\n\\taction _ aSelector.\\t\\t\\\"paint:\\\"\\n\\tcurrentCursor _ aCursor.\\n\\tself notifyWeakDependentsWith: {#action. evt. action}.\\n\\tself notifyWeakDependentsWith: {#currentCursor. evt. currentCursor}.\\n! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 01:45'!\\ntoss: cancelButton with: cancelSelector evt: evt\\n\\t\\\"Reject the painting. Showing noPalette is done by the block submitted to the SketchEditorMorph\\\"\\n\\n\\t| focus |\\n\\towner ifNil: [\\\"it happens\\\" ^ self].\\n\\t(focus _ self focusMorph) \\n\\t\\tifNotNil: [focus cancelPainting: self evt: evt]\\n\\t\\tifNil:\\n\\t\\t\\t[self delete].\\n\\tcancelButton state: #off.\\n! !\\n\\n!PaintBoxMorph methodsFor: 'actions' stamp: 'RAA 8/16/2000 11:15'!\\nundo: undoButton with: undoSelector evt: evt\\n\\t| ss |\\n\\t(ss _ self focusMorph) \\n\\t\\tifNotNil: [ss undoPainting: self evt: evt]\\n\\t\\tifNil: [self notCurrentlyPainting].\\n\\tundoButton state: #off.! !\\n\\n\\n!PaintBoxMorph methodsFor: 'copying' stamp: 'di 10/14/97 10:13'!\\nupdateReferencesUsing: aDictionary\\n\\t\\\"Fix up stampHolder which is a ScrollingToolHolder, which is not a Morph\\\"\\n\\n\\tsuper updateReferencesUsing: aDictionary.\\n\\tstampHolder updateReferencesUsing: aDictionary.\\n\\tcolorMemory updateReferencesUsing: aDictionary.! !\\n\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'RAA 8/15/2000 16:47'!\\naddWeakDependent: anObject\\n\\n\\tweakDependents ifNil: [^weakDependents _ WeakArray with: anObject].\\n\\tweakDependents _ weakDependents,{anObject} reject: [ :each | each isNil].! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'RAA 8/15/2000 14:59'!\\nbeStatic\\n\\n\\tcolorMemory ifNotNil: [colorMemory beStatic].! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'sw 5/23/2001 13:53'!\\ncreateButtons\\n\\t\\\"Create buttons one at a time and let the user place them over the background. Later can move them again by turning on AuthorModeOwner in ThreePhaseButtonMorph.\\n\\tself createButtons.\\t\\\"\\n\\n\\t| rect button nib |\\n\\t#(erase: eyedropper: fill: paint: rect: ellipse: polygon: line: star: pickup: \\\"pickup: pickup: pickup:\\\" stamp: \\\"stamp: stamp: stamp:\\\" undo: keep: toss: prevStamp: nextStamp:) do: [:sel |\\n\\t\\t(self submorphNamed: sel) ifNil:\\n\\t\\t\\t[self inform: 'Rectangle for ',sel.\\n\\t\\t\\trect _ Rectangle fromUser.\\n\\t\\t\\tbutton _ ThreePhaseButtonMorph new.\\n\\t\\t\\tbutton onImage: nil; bounds: rect.\\n\\t\\t\\tself addMorph: button.\\n\\t\\t\\tbutton actionSelector: #tool:action:cursor:evt:; arguments: (Array with: button with: sel with: nil).\\n\\t\\t\\tbutton actWhen: #buttonUp; target: self]].\\n\\t#(brush1: brush2: brush3: brush4: brush5: brush6: ) doWithIndex: [:sel :ind |\\n\\t\\t(self submorphNamed: sel) ifNil:\\n\\t\\t\\t[self inform: 'Rectangle for ',sel.\\n\\t\\t\\trect _ Rectangle fromUser.\\n\\t\\t\\tbutton _ ThreePhaseButtonMorph new.\\n\\t\\t\\tbutton onImage: nil; bounds: rect.\\n\\t\\t\\tself addMorph: button.\\n\\t\\t\\tnib _ Form dotOfSize: (#(1 2 3 6 11 26) at: ind).\\n\\t\\t\\tbutton actionSelector: #brush:action:nib:evt:; \\n\\t\\t\\t\\t\\targuments: (Array with: button with: sel with: nib).\\n\\t\\t\\tbutton actWhen: #buttonUp; target: self]].\\n\\t\\\"stamp: Stamps are held in a ScrollingToolHolder. Pickups and stamps and brushes are id-ed by the button == with item from a list.\\\"\\n\\n\\n! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'dgd 2/22/2003 19:39'!\\nfixupButtons\\n\\t| changes answer newSelector |\\n\\tchanges := Dictionary new.\\n\\tchanges\\n\\t\\tat: #brush:action:nib: put: #brush:action:nib:evt:;\\n\\t\\tat: #tool:action:cursor: put: #tool:action:cursor:evt:;\\n\\t\\tat: #pickup:action:cursor: put: #pickup:action:cursor:evt:;\\n\\t\\tat: #keep:with: put: #keep:with:evt:;\\n\\t\\tat: #undo:with: put: #undo:with:evt:;\\n\\t\\tat: #scrollStamps:action: put: #scrollStamps:action:evt:;\\n\\t\\tat: #toss:with: put: #toss:with:evt:;\\n\\t\\tat: #eyedropper:action:cursor: put: #eyedropper:action:cursor:evt:;\\n\\t\\tat: #clear:with: put: #clear:with:evt:.\\n\\tanswer := WriteStream on: String new.\\n\\tself allMorphsDo: \\n\\t\\t\\t[:each | \\n\\t\\t\\t(each isKindOf: ThreePhaseButtonMorph) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[answer nextPutAll: each actionSelector.\\n\\t\\t\\t\\t\\t(changes includesKey: each actionSelector) \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[each actionSelector: (newSelector := changes at: each actionSelector).\\n\\t\\t\\t\\t\\t\\t\\tanswer nextPutAll: ' <-- ' , newSelector].\\n\\t\\t\\t\\t\\tanswer cr]].\\n\\t^answer contents\\n\\t\\\"StringHolder new\\n\\t\\tcontents: answer contents;\\n\\t\\topenLabel: 'button fixups'\\\"! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'dgd 2/22/2003 19:03'!\\ninit3\\n\\t\\\"Just a record of how we loaded in the latest paintbox button images\\\"\\n\\n\\t| bb rect lay pic16Bit aa blt on thin |\\n\\tself loadoffImage: 'etoy_default.gif'.\\n\\tself allMorphsDo: \\n\\t\\t\\t[:button | \\n\\t\\t\\t(button isKindOf: ThreePhaseButtonMorph) \\n\\t\\t\\t\\tifTrue: [button offImage: nil]\\n\\t\\t\\t\\tifFalse: [button position: button position + (100 @ 0)]].\\n\\t(bb := self submorphNamed: #keep:) position: bb position + (100 @ 0).\\n\\t(bb := self submorphNamed: #toss:) position: bb position + (100 @ 0).\\n\\t(bb := self submorphNamed: #undo:) position: bb position + (100 @ 0).\\n\\t\\\"Transparent is (Color r: 1.0 g: 0 b: 1.0)\\\"\\n\\tself moveButtons.\\n\\tself loadOnImage: 'etoy_in.gif'.\\n\\tAllOnImage := nil.\\n\\t'save space'.\\n\\tself loadPressedImage: 'etoy_in.gif'.\\n\\tAllPressedImage := nil.\\n\\t'save space'.\\n\\tself loadCursors.\\n\\n\\t\\\"position the stamp buttons\\\"\\n\\tstampHolder stampButtons owner last delete.\\n\\tstampHolder pickupButtons last delete.\\n\\tstampHolder stampButtons: (stampHolder stampButtons copyFrom: 1 to: 3).\\n\\tstampHolder pickupButtons: (stampHolder pickupButtons copyFrom: 1 to: 3).\\n\\t\\\"| rect |\\\"\\n\\tstampHolder pickupButtons do: \\n\\t\\t\\t[:button | \\n\\t\\t\\t\\\"PopUpMenu notify: 'Rectangle for ',sel.\\\"\\n\\n\\t\\t\\trect := Rectangle fromUser.\\n\\t\\t\\tbutton bounds: rect\\t\\\"image is nil\\\"].\\n\\t\\\"| rect lay |\\\"\\n\\tstampHolder clear.\\n\\tstampHolder stampButtons do: \\n\\t\\t\\t[:button | \\n\\t\\t\\tbutton\\n\\t\\t\\t\\toffImage: nil;\\n\\t\\t\\t\\tpressedImage: nil.\\n\\t\\t\\tlay := button owner.\\n\\t\\t\\t\\\"PopUpMenu notify: 'Rectangle for ',sel.\\\"\\n\\t\\t\\trect := Rectangle fromUser.\\n\\t\\t\\tbutton image: (Form fromDisplay: (rect insetBy: 2)).\\n\\t\\t\\tlay borderWidth: 2.\\n\\t\\t\\tlay bounds: rect\\t\\\"image is nil\\\"].\\n\\t\\\"| pic16Bit blt aa on |\\\"\\n\\tpic16Bit := GIFReadWriter formFromFileNamed: 'etoy_in.gif'.\\t\\\"really 8\\\"\\n\\taa := Form extent: OriginalBounds extent depth: 8.\\n\\tblt := BitBlt current toForm: aa.\\n\\tblt\\n\\t\\tsourceForm: pic16Bit;\\n\\t\\tcombinationRule: Form over;\\n\\t\\tsourceRect: OriginalBounds;\\n\\t\\tdestOrigin: 0 @ 0;\\n\\t\\tcopyBits.\\n\\t\\\"Collect all the images for the buttons in the on state\\\"\\n\\tstampHolder pickupButtons do: \\n\\t\\t\\t[:button | \\n\\t\\t\\ton := ColorForm extent: button extent depth: 8.\\n\\t\\t\\ton colors: pic16Bit colors.\\n\\t\\t\\ton \\n\\t\\t\\t\\tcopy: (0 @ 0 extent: button extent)\\n\\t\\t\\t\\tfrom: button topLeft - self topLeft\\n\\t\\t\\t\\tin: aa\\n\\t\\t\\t\\trule: Form over.\\n\\t\\t\\tbutton\\n\\t\\t\\t\\timage: on;\\n\\t\\t\\t\\tpressedImage: on;\\n\\t\\t\\t\\toffImage: nil].\\n\\tself invalidRect: bounds.\\n\\t((self submorphNamed: #erase:) arguments third) offset: 12 @ 35.\\n\\t((self submorphNamed: #eyedropper:) arguments third) offset: 0 @ 0.\\n\\t((self submorphNamed: #fill:) arguments third) offset: 10 @ 44.\\n\\t((self submorphNamed: #paint:) arguments third) offset: 3 @ 3.\\t\\\"unused\\\"\\n\\t((self submorphNamed: #rect:) arguments third) offset: 6 @ 17.\\n\\t((self submorphNamed: #ellipse:) arguments third) offset: 5 @ 4.\\n\\t((self submorphNamed: #polygon:) arguments third) offset: 5 @ 4.\\n\\t((self submorphNamed: #line:) arguments third) offset: 5 @ 17.\\n\\t((self submorphNamed: #star:) arguments third) offset: 2 @ 5.\\n\\tthumbnail delete.\\n\\tthumbnail := nil.\\n\\t(submorphs select: [:e | e class == RectangleMorph]) first \\n\\t\\tbounds: Rectangle fromUser.\\n\\t((submorphs select: [:e | e class == RectangleMorph]) first)\\n\\t\\tborderWidth: 1;\\n\\t\\tborderColor: Color black.\\n\\t\\\"| thin |\\\"\\n\\tsubmorphs do: [:ss | ss class == ImageMorph ifTrue: [thin := ss\\t\\\"first\\\"]].\\n\\tcolorMemoryThin := thin! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'tk 8/22/2000 11:56'!\\ninit4\\n\\t\\\"Just a record of how Ted loaded in the paintbox button images, Feb 98\\\"\\n| bb im pp newImage pic24Bit picNewBit blt |\\n\\n\\\"self loadoffImage: 'roundedPalette3.bmp'.\\\"\\npic24Bit _ GIFReadWriter formFromServerFile: 'updates/137roundedPalette3.bmp'.\\npicNewBit _ Form extent: pic24Bit extent depth: 16.\\npic24Bit displayOn: picNewBit.\\nOriginalBounds _ picNewBit boundingBox.\\nAllOffImage _ Form extent: OriginalBounds extent depth: 16.\\nblt _ BitBlt current toForm: AllOffImage.\\nblt sourceForm: picNewBit; combinationRule: Form over;\\n\\t\\tsourceRect: OriginalBounds; destOrigin: 0@0; copyBits.\\n\\nAllOffImage mapColor: Color transparent to: Color black.\\nself image: AllOffImage.\\nself invalidRect: bounds.\\n\\nself submorphsDo: [:button | button position: button position + (10@10)].\\n(im _ submorphs at: 28) class == ImageMorph ifTrue: [\\n\\tim position: im position + (2@0)].\\t\\\"color picker\\\"\\n\\\"exercise it once\\\"\\n\\n(bb _ self submorphNamed: #keep:) position: bb position + (0@25).\\n(bb _ self submorphNamed: #toss:) position: bb position + (0@25).\\n(bb _ self submorphNamed: #undo:) position: bb position + (0@-25).\\n(bb _ self submorphNamed: #clear:) position: bb position + (0@-25).\\n(bb _ self submorphNamed: #undo:) position: bb position + (0@-69).\\n(bb _ self submorphNamed: #clear:) position: bb position + (0@-69).\\nself submorphsDo: [:button | \\n\\tbutton class == AlignmentMorph ifTrue: [\\n\\t\\tbutton position: button position + (0@25)].\\n\\t(button printString includesSubString: 'stamp:') ifTrue: [\\n\\t\\tbutton position: button position + (0@25)]].\\n(bb _ self submorphNamed: #prevStamp:) position: bb position + (0@25).\\n(bb _ self submorphNamed: #nextStamp:) position: bb position + (0@25).\\n\\nbb _ self submorphNamed: #keep:.\\nnewImage _ bb pressedImage copy: (0@4 corner: (bb pressedImage boundingBox extent)).\\nbb onImage: newImage. bb pressedImage: newImage. bb extent: newImage extent.\\nbb position: bb position + (4@1).\\n\\npp _ (bb _ self submorphNamed: #toss:) pressedImage.\\nnewImage _ pp copy: (0@4 corner: (bb pressedImage extent - (3@0))).\\nbb onImage: newImage. bb pressedImage: newImage. \\nbb extent: newImage extent.\\nbb position: bb position + (3@1).\\n\\npp _ (bb _ self submorphNamed: #undo:) pressedImage.\\nnewImage _ pp copy: (0@0 corner: (bb pressedImage extent - (3@5))).\\nbb onImage: newImage. bb pressedImage: newImage. \\nbb extent: newImage extent.\\nbb position: bb position + (3@-1).\\n\\npp _ (bb _ self submorphNamed: #clear:) pressedImage.\\nnewImage _ pp copy: (0@0 corner: (bb pressedImage extent - (0@5))).\\nbb onImage: newImage. bb pressedImage: newImage. \\nbb extent: newImage extent.\\nbb position: bb position + (3@-1).\\n\\npic24Bit _ GIFReadWriter formFromServerFile: 'updates/137pencil.bmp'.\\npicNewBit _ Form extent: pic24Bit extent depth: 16.\\npic24Bit displayOn: picNewBit.\\nnewImage _ picNewBit as8BitColorForm.\\nnewImage transparentColor: (Color r: 0 g: 0 b: 0).\\n(bb _ self submorphNamed: #erase:) pressedImage: newImage; onImage: newImage;\\n\\textent: newImage extent.\\n\\nbb position: bb position + (-11@-1).\\n! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'tk 7/28/2000 23:26'!\\ninitialize\\n\\tsuper initialize.\\n\\tcolorMemory ifNotNil: [colorMemory on: #mouseDown send: #takeColorEvt:from: to: self].! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'jm 6/18/1999 18:58'!\\nloadColorChooser\\n\\t\\\"Load Forms for ColorMemoryMorph.\\\"\\n\\n\\t| doc closedForm openForm |\\n\\tdoc _ Utilities objectStrmFromUpdates: 'colorPalClosed.obj'.\\n\\tclosedForm _ doc fileInObjectAndCode mapColor: Color transparent to: Color black.\\n\\tdoc _ Utilities objectStrmFromUpdates: 'colorPalOpen.obj'.\\n\\topenForm _ doc fileInObjectAndCode mapColor: Color transparent to: Color black.\\n\\n\\tcolorMemoryThin image: closedForm.\\n\\tcolorMemoryThin position: self position + (0@140).\\n\\n\\tcolorMemory delete.\\t\\\"delete old one\\\"\\n\\tcolorMemory _ PaintBoxColorPicker new image: openForm.\\n! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'sw 5/23/2001 13:54'!\\nloadCursors\\n\\t\\\"Display the form containing the cursors. Transparent is (Color r: 1.0 g: 0 b: 1.0). Grab the forms one at a time, and they are stored away.\\n\\tself loadCursors.\\t\\\"\\n\\n\\t| button transp cursor map |\\n\\ttransp _ Color r: 1.0 g: 0 b: 1.0.\\n\\tmap _ Color indexedColors copy.\\t\\\"just in case\\\"\\n\\t1 to: 256 do: [:ind | (map at: ind) = transp ifTrue: \\n\\t\\t\\t\\t[map at: ind put: Color transparent]].\\n\\n\\t#(erase: eyedropper: fill: paint: rect: ellipse: polygon: line: star: ) do: [:sel |\\n\\t\\tself inform: 'Rectangle for ',sel.\\n\\t\\tcursor _ ColorForm fromUser.\\n\\t\\tcursor colors: map.\\t\\\"share it\\\"\\n\\t\\tbutton _ self submorphNamed: sel.\\n\\t\\tbutton arguments at: 3 put: cursor].\\n! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'yo 1/13/2005 12:20'!\\nloadJapanesePaintBoxBitmaps\\n\\\"\\n\\tPaintBoxMorph new loadJapanesePaintBoxBitmaps.\\n\\\"\\n\\n\\t| formTranslator form bb |\\n\\tself position: 0@0.\\n\\tformTranslator _ NaturalLanguageFormTranslator localeID: (LocaleID isoString: 'ja').\\n\\tform _ Form fromFileNamed: 'offPaletteJapanese(children).form'.\\n\\n\\t#('keep:' 'undo:' 'clear:' 'toss:') with: #('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:extName :label |\\n\\t\\tbb _ (self submorphs detect: [:e | e externalName = extName]) bounds.\\n\\t\\tformTranslator name: label, '-off' form: (form copy: bb)\\n\\t].\\n\\n\\n\\tform _ Form fromFileNamed: 'pressedPaletteJapanese(children).form'.\\n\\t#('keep:' 'undo:' 'clear:' 'toss:') with: #('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:extName :label |\\n\\t\\tbb _ (self submorphs detect: [:e | e externalName = extName]) bounds.\\n\\t\\tformTranslator name: label, '-pressed' form: (form copy: bb)\\n\\t].\\n! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'yo 11/4/2002 21:20'!\\nloadOffForm: pic16Bit \\n\\t\\\"Prototype loadOffForm: (Smalltalk imageImports at: #offPaletteJapanese)\\\"\\n\\n\\t| blt |\\n\\tOriginalBounds _ pic16Bit boundingBox.\\n\\tAllOffImage _ Form extent: OriginalBounds extent depth: 16.\\n\\tblt _ BitBlt current toForm: AllOffImage.\\n\\tblt sourceForm: pic16Bit;\\n\\t\\t combinationRule: Form over;\\n\\t\\t sourceRect: OriginalBounds;\\n\\t\\t destOrigin: 0 @ 0;\\n\\t\\t copyBits.\\n\\tAllOffImage mapColor: Color blue to: Color transparent.\\n\\tself image: AllOffImage.\\n\\tAllOffImage _ nil.\\n\\tself invalidRect: bounds\\n! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'ar 5/28/2000 12:10'!\\nloadOnImage: fileName\\n\\t\\\"Read in and convert the image for the paintBox with the buttons\\non. A .bmp 24-bit image. For each button, cut that chunk out and save it.\\\"\\n\\t\\\"\\tself loadOnImage: 'NoSh_on.bmp'.\\n\\t\\tAllOnImage _ nil.\\t'save space'.\\t\\\"\\n\\n\\t| pic16Bit blt aa on type |\\n\\ttype _ 'gif'. \\\" gif or bmp \\\"\\ntype = 'gif' ifTrue: [\\n\\tpic16Bit \\\"really 8\\\" _ GIFReadWriter formFromFileNamed: fileName.\\n\\tpic16Bit display.\\n\\taa _ AllOnImage _ Form extent: OriginalBounds extent depth: 8.\\n\\tblt _ BitBlt current toForm: aa.\\n\\tblt sourceForm: pic16Bit; combinationRule: Form over;\\n\\t\\tsourceRect: OriginalBounds; destOrigin: 0@0; copyBits.\\n\\t].\\ntype = 'bmp' ifTrue: [\\n\\tpic16Bit _ (Form fromBMPFileNamed: fileName) asFormOfDepth: 16.\\n\\tpic16Bit display.\\n\\taa _ AllOnImage _ Form extent: OriginalBounds extent depth: 16.\\n\\tblt _ BitBlt current toForm: aa.\\n\\tblt sourceForm: pic16Bit; combinationRule: Form over;\\n\\t\\tsourceRect: OriginalBounds; destOrigin: 0@0; copyBits.\\n\\taa mapColor: Color transparent to: Color black.\\n\\t].\\n\\t\\\"Collect all the images for the buttons in the on state\\\"\\n\\tself allMorphsDo: [:button |\\n\\t\\t(button isKindOf: ThreePhaseButtonMorph) ifTrue: [\\n\\t\\t\\ttype = 'gif' ifTrue: [on _ ColorForm extent: button extent depth: 8.\\n\\t\\t\\t\\t\\t on colors: pic16Bit colors]\\n\\t\\t\\t\\tifFalse: [on _ Form extent: button extent depth: 16].\\n\\t\\t\\ton copy: (0@0 extent: button extent)\\n\\t\\t\\t\\tfrom: (button topLeft - self topLeft) in: aa rule: Form over.\\n\\t\\t\\tbutton onImage: on]].\\n\\tself invalidRect: bounds.\\n\\n\\t! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'yo 11/4/2002 21:20'!\\nloadPressedForm: pic16Bit \\n\\t\\\"Prototype loadPressedForm: (Smalltalk imageImports at: #pressedPaletteJapanese)\\\"\\n\\n\\t| blt on |\\n\\tAllPressedImage _ AllPressedImage _ Form extent: OriginalBounds extent depth: 16.\\n\\tblt _ BitBlt current toForm: AllPressedImage.\\n\\tblt sourceForm: pic16Bit;\\n\\t\\t combinationRule: Form over;\\n\\t\\t sourceRect: OriginalBounds;\\n\\t\\t destOrigin: 0 @ 0;\\n\\t\\t copyBits.\\n\\tAllPressedImage mapColor: Color black to: Color transparent.\\n\\tself\\n\\t\\tallMorphsDo: [:button | (button isKindOf: ThreePhaseButtonMorph)\\n\\t\\t\\t\\tifTrue: [on _ Form extent: button extent depth: 16.\\n\\t\\t\\t\\t\\ton\\n\\t\\t\\t\\t\\t\\tcopy: (0 @ 0 extent: button extent)\\n\\t\\t\\t\\t\\t\\tfrom: button topLeft - self topLeft\\n\\t\\t\\t\\t\\t\\tin: AllPressedImage\\n\\t\\t\\t\\t\\t\\trule: Form over.\\n\\t\\t\\t\\t\\tbutton pressedImage: on]].\\n\\tAllPressedImage _ nil.\\n\\tself invalidRect: bounds\\n! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'ar 5/28/2000 12:10'!\\nloadPressedImage: fileName\\n\\t\\\"Read in and convert the image for the paintBox with the buttons\\non. A .bmp 24-bit image. For each button, cut that chunk out and save it.\\\"\\n\\t\\\"\\tself loadPressedImage: 'NoSh_on.bmp'.\\n\\t\\tAllPressedImage _ nil.\\t'save space'.\\t\\\"\\n\\n\\t| pic16Bit blt aa on type |\\n\\ttype _ 'gif'. \\\" gif or bmp \\\"\\ntype = 'gif' ifTrue: [\\n\\tpic16Bit \\\"really 8\\\" _ GIFReadWriter formFromFileNamed: fileName.\\n\\tpic16Bit display.\\n\\taa _ AllPressedImage _ Form extent: OriginalBounds extent depth: 8.\\n\\tblt _ BitBlt current toForm: aa.\\n\\tblt sourceForm: pic16Bit; combinationRule: Form over;\\n\\t\\tsourceRect: OriginalBounds; destOrigin: 0@0; copyBits.\\n\\t].\\ntype = 'bmp' ifTrue: [\\n\\tpic16Bit _ (Form fromBMPFileNamed: fileName) asFormOfDepth: 16.\\n\\tpic16Bit display.\\n\\taa _ AllPressedImage _ Form extent: OriginalBounds extent depth: 16.\\n\\tblt _ BitBlt current toForm: aa.\\n\\tblt sourceForm: pic16Bit; combinationRule: Form over;\\n\\t\\tsourceRect: OriginalBounds; destOrigin: 0@0; copyBits.\\n\\taa mapColor: Color transparent to: Color black.\\n\\t].\\n\\t\\\"Collect all the images for the buttons in the on state\\\"\\n\\tself allMorphsDo: [:button |\\n\\t\\t(button isKindOf: ThreePhaseButtonMorph) ifTrue: [\\n\\t\\t\\ttype = 'gif' ifTrue: [on _ ColorForm extent: button extent depth: 8.\\n\\t\\t\\t\\t\\t on colors: pic16Bit colors]\\n\\t\\t\\t\\tifFalse: [on _ Form extent: button extent depth: 16].\\n\\t\\t\\ton copy: (0@0 extent: button extent)\\n\\t\\t\\t\\tfrom: (button topLeft - self topLeft) in: aa rule: Form over.\\n\\t\\t\\tbutton pressedImage: on]].\\n\\tself invalidRect: bounds.\\n\\n\\t! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'md 11/14/2003 16:52'!\\nloadoffImage: fileName\\n\\t\\\"Read in and convert the background image for the paintBox. All\\nbuttons off. A .bmp 24-bit image.\\\"\\n\\t\\\"\\tPrototype loadoffImage: 'roundedPalette3.bmp'\\t\\\"\\n\\n\\t| pic16Bit blt type getBounds |\\n\\ttype _ 'bmp'. \\\" gif or bmp \\\"\\n\\tgetBounds _ 'fromPic'.\\t\\\"fromUser = draw out rect of paintbox on image\\\"\\n\\t\\t\\\"fromOB = just read in new bits, keep same size and place as last time.\\\"\\n\\t\\t\\\"fromPic = picture is just the PaintBox, use its bounds\\\"\\ntype = 'gif' ifTrue: [\\n\\tpic16Bit \\\"really 8\\\" _ GIFReadWriter formFromFileNamed: fileName.\\n\\tgetBounds = 'fromUser' ifTrue: [\\\"Just first time, collect the bounds\\\"\\n\\t\\t\\tpic16Bit display.\\n\\t\\t\\tOriginalBounds _ Rectangle fromUser].\\n\\tgetBounds = 'fromPic' ifTrue: [OriginalBounds _ pic16Bit boundingBox].\\n\\t].\\n\\t\\t\\\"Use OriginalBounds as it was last time\\\"\\ntype = 'bmp' ifTrue: [\\n\\tpic16Bit _ (Form fromBMPFileNamed: fileName) asFormOfDepth: 16.\\n\\tgetBounds = 'fromUser' ifTrue: [\\\"Just first time, collect the bounds\\\"\\n\\t\\t\\tpic16Bit display.\\n\\t\\t\\tOriginalBounds _ Rectangle fromUser].\\n\\t\\t\\\"Use OriginalBounds as it was last time\\\"\\n\\t(getBounds = 'fromPic') ifTrue: [OriginalBounds _ pic16Bit boundingBox].\\n\\tAllOffImage _ Form extent: OriginalBounds extent depth: 16.\\n\\t].\\n\\ntype = 'gif' ifTrue: [\\n\\tAllOffImage _ ColorForm extent: OriginalBounds extent depth: 8.\\n\\tAllOffImage colors: pic16Bit colors].\\n\\n\\tblt _ BitBlt current toForm: AllOffImage.\\n\\tblt sourceForm: pic16Bit; combinationRule: Form over;\\n\\t\\tsourceRect: OriginalBounds; destOrigin: 0@0; copyBits.\\n\\ntype = 'bmp' ifTrue: [AllOffImage mapColor: Color transparent to: Color black].\\n\\tself image: AllOffImage.\\n\\tself invalidRect: bounds.\\n\\n\\t! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'sw 5/23/2001 13:54'!\\nmoveButtons\\n\\t\\\"Move buttons one at a time and let the user place them over the background. Later can move them again by turning on AuthorModeOwner in ThreePhaseButtonMorph.\\n\\tself createButtons.\\t\\\"\\n\\n\\t| rect button |\\n\\t#(erase: eyedropper: fill: paint: rect: ellipse: polygon: line: star: \\\"pickup: pickup: pickup: pickup:\\\" \\\"stamp: stamp: stamp: stamp:\\\" undo: keep: toss: prevStamp: nextStamp:) do: [:sel |\\n\\t\\t\\tself inform: 'Rectangle for ',sel.\\n\\t\\t\\trect _ Rectangle fromUser.\\n\\t\\t\\tbutton _ self submorphNamed: sel.\\n\\t\\t\\tbutton bounds: rect.\\t\\\"image is nil\\\"].\\n\\t#(brush1: brush2: brush3: brush4: brush5: brush6: ) doWithIndex: [:sel :ind |\\n\\t\\t\\tself inform: 'Rectangle for ',sel.\\n\\t\\t\\trect _ Rectangle fromUser.\\n\\t\\t\\tbutton _ self submorphNamed: sel.\\n\\t\\t\\tbutton bounds: rect.\\t\\\"image is nil\\\"].\\n\\t\\\"stamp: Stamps are held in a ScrollingToolHolder. Pickups and stamps and brushes are id-ed by the button == with item from a list.\\\"\\n\\n\\t\\\"\\n\\t\\\"\\n! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'tk 8/22/97 15:57'!\\nnoVeneer\\n\\t\\\"For a palette with a background (off) image, clear that image.\\nBut first, for each button, cut that chunk out and save it in the offImage\\npart.\\\"\\n\\t\\\"\\tself noVeneer.\\n\\t\\tAllOffImage _ nil.\\t'save space. irreversible'.\\t\\\"\\n\\n\\t| aa on |\\n\\tAllOffImage ifNil: [AllOffImage _ image].\\n\\taa _ AllOffImage.\\n\\t\\\"Collect all the images for the buttons in the on state\\\"\\n\\tself allMorphsDo: [:button |\\n\\t\\t(button isKindOf: ThreePhaseButtonMorph) ifTrue: [\\n\\t\\t\\ton _ Form extent: button extent depth: 16.\\n\\t\\t\\ton copy: (0@0 extent: button extent)\\n\\t\\t\\t\\tfrom: (button topLeft - self topLeft) in:\\naa rule: Form over.\\n\\t\\t\\tbutton offImage: on]].\\n\\tself image: (Form extent: AllOffImage extent depth: 1).\\n\\tself invalidRect: bounds.\\n\\n\\n\\t! !\\n\\n!PaintBoxMorph methodsFor: 'initialization' stamp: 'RAA 8/16/2000 11:12'!\\nnotifyWeakDependentsWith: arguments\\n\\n\\tweakDependents ifNil: [^self].\\n\\tweakDependents do: [ :each |\\n\\t\\teach ifNotNil: [\\n\\t\\t\\teach paintBoxChanged: arguments.\\n\\t\\t\\teach paintBoxChanged: {#changed. arguments second. true}.\\n\\t\\t].\\n\\t].! !\\n\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'dgd 8/30/2003 21:55'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\n\\t\\\"super addCustomMenuItems: aCustomMenu hand: aHandMorph.\\\"\\n\\t\\t\\\"don't want the ones from ImageMorph\\\"\\n\\taCustomMenu add: 'grab stamp from screen' translated action: #grabFromScreen:.\\n\\n! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'yo 1/13/2005 14:08'!\\naddGraphicLabels\\n\\t\\\"translate button labels\\\"\\n\\n\\t| formTranslator ext pos newForm |\\n\\tformTranslator _ NaturalLanguageFormTranslator localeID: (Locale current localeID).\\n\\n\\t#('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:label |\\n\\t\\t(formTranslator translate: label, '-off') ifNil: [^ false].\\n\\t\\t(formTranslator translate: label, '-pressed') ifNil: [^ false].\\n\\t].\\n\\t\\n\\t#('keep:' 'undo:' 'clear:' 'toss:') with: #('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:extName :label |\\n\\t\\t| button |\\n\\t\\tbutton _ submorphs detect: [:m | m externalName = extName] ifNone: [nil].\\n\\t\\tbutton ifNotNil: [\\n\\t\\t\\tbutton removeAllMorphs.\\n\\t\\t\\text _ button extent.\\n\\t\\t\\tpos _ button position.\\n\\t\\t\\t(newForm _ formTranslator translate: label, '-off') ifNotNil: [\\n\\t\\t\\t\\tbutton offImage: newForm.\\n\\n\\t\\t\\t].\\n\\t\\t\\t(newForm _ formTranslator translate: label, '-pressed') ifNotNil: [\\n\\t\\t\\t\\tbutton pressedImage: newForm.\\n\\t\\t\\t].\\n\\t\\t\\tbutton extent: ext.\\n\\t\\t\\tbutton position: pos.\\n\\t\\t].\\n\\t].\\n\\n\\t^ true.\\n! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'yo 1/13/2005 14:08'!\\naddLabels\\n\\n\\tPreferences useFormsInPaintBox ifFalse: [\\n\\t\\tself addTextualLabels.\\n\\t] ifTrue: [\\n\\t\\tself addGraphicLabels ifFalse: [self addTextualLabels].\\n\\t].\\n! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'yo 1/13/2005 11:06'!\\naddTextualLabels\\n\\t\\\"translate button labels\\\"\\n\\n\\t#('keep:' 'undo:' 'clear:' 'toss:') with: #('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:extName :label |\\n\\t\\t| button |\\n\\t\\tbutton _ submorphs detect: [:m | m externalName = extName] ifNone: [nil].\\n\\t\\tbutton ifNotNil: [\\n\\t\\t\\tbutton removeAllMorphs.\\n\\t\\t\\tbutton addMorph: (TextMorph new \\n\\t\\t\\t\\tcontentsWrapped: (Text string: label translated\\n\\t\\t\\t\\t\\tattributes: {\\n\\t\\t\\t\\t\\t\\tTextAlignment centered. \\n\\t\\t\\t\\t\\t\\tTextEmphasis bold.\\n\\t\\t\\t\\t\\t\\tTextFontReference toFont:\\n\\t\\t\\t\\t\\t\\t\\t(Preferences standardPaintBoxButtonFont)});\\n\\t\\t\\t\\tbounds: (button bounds translateBy: 0@3);\\n\\t\\t\\t\\tlock)]]! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'tk 10/31/97 13:38'!\\ncolorMemory\\n\\n\\t^ colorMemory! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'di 10/14/97 10:15'!\\ncolorMemory: aMorph\\n\\n\\tcolorMemory _ aMorph! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'tk 10/31/97 13:35'!\\ncolorPatch\\n\\t^ colorPatch! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'ar 3/23/2000 14:18'!\\nfocusMorph\\n\\t\\\"Note: For backward compatibility we search the world for a SketchEditorMorph if the current focus morph is nil\\\"\\n\\t^focusMorph ifNil:[focusMorph _ self world findA: SketchEditorMorph]! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'ar 3/23/2000 14:20'!\\nfocusMorph: newFocus\\n\\t\\\"Set the new focus morph\\\"\\n\\tfocusMorph ifNotNil:[focusMorph paletteDetached: self]. \\\"In case the morph is interested\\\"\\n\\tfocusMorph _ newFocus.\\n\\tfocusMorph ifNotNil:[focusMorph paletteAttached: self]. \\\"In case the morph is interested\\\"! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'tk 8/22/2000 11:57'!\\nmaxBounds\\n\\t| rr |\\n\\t\\\"fullBounds if all flop-out parts of the paintBox were showing.\\\"\\n\\n\\trr _ bounds merge: colorMemory bounds.\\n\\trr _ rr merge: (self submorphNamed: 'stamps') bounds.\\n\\trr _ rr origin corner: rr corner + (0@ (self submorphNamed: 'shapes') height \\n\\t\\t\\t\\t+ 10 \\\"what is showing of (self submorphNamed: #toggleShapes) height\\\").\\n\\t^ rr! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'tk 8/22/2000 23:48'!\\noffsetFromMaxBounds\\n\\t\\\"location of normal PaintBox within maxBounds.\\\"\\n\\n\\t^ self left - colorMemory left @ 0! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'tk 7/17/97 16:26'!\\nrotationTabForm\\n\\t^ rotationTabForm! !\\n\\n!PaintBoxMorph methodsFor: 'other' stamp: 'tk 7/17/97 16:26'!\\nscaleTabForm\\n\\t^ scaleTabForm! !\\n\\n\\n!PaintBoxMorph methodsFor: 'recent colors' stamp: 'ar 7/8/2006 20:33'!\\nfixUpColorPicker\\n\\t| chart picker |\\n\\tchart _ ColorChart ifNil:[Cursor wait showWhile:[ColorChart _ (ColorPickerMorph colorPaletteForDepth: 16 extent: 120@89)]].\\n\\tchart getCanvas frameRectangle: chart boundingBox color: Color black.\\n\\tpicker _ Form extent: (chart extent + (14@12)) depth: 16.\\n\\tpicker fillWhite.\\n\\t\\\"top\\\"\\n\\tpicker copy: (0@0 extent: picker width@6)\\n\\t\\t\\tfrom: (colorMemory image width - picker width)@0 \\n\\t\\t\\tin: colorMemory image rule: Form over.\\n\\t\\\"bottom\\\"\\n\\tpicker copy: (0@ (picker height-6) extent: picker width@6) \\n\\t\\t\\tfrom: (colorMemory image width - picker width)@(colorMemory image height - 7)\\n\\t\\t\\tin: colorMemory image rule: Form over.\\n\\t\\\"left\\\"\\n\\tpicker copy: (0@6 corner: 8@(picker height - 6))\\n\\t\\t\\tfrom: (colorMemory image boundingBox topLeft + (0@6)) \\n\\t\\t\\tin: colorMemory image rule: Form over.\\n\\t\\\"right\\\"\\n\\tpicker copy: (picker width-6@6 corner: picker width@(picker height - 6))\\n\\t\\t\\tfrom: (colorMemory image boundingBox topRight - (6@-6)) \\n\\t\\t\\tin: colorMemory image rule: Form over.\\n\\tchart displayOn: picker at: 8@6.\\n\\tpicker getCanvas frameRectangle: picker boundingBox color: Color black.\\n\\tcolorMemory image: picker.\\n! !\\n\\n!PaintBoxMorph methodsFor: 'recent colors' stamp: 'dgd 2/21/2003 23:17'!\\nfixUpRecentColors\\n\\t| inner outer border box form newImage canvas morph |\\n\\tself fixUpColorPicker.\\n\\trecentColors := WriteStream on: Array new.\\n\\tform := image.\\n\\tnewImage := Form extent: form extent + (0 @ 41) depth: form depth.\\n\\tform displayOn: newImage.\\n\\tnewImage \\n\\t\\tcopy: (0 @ (form height - 10) \\n\\t\\t\\t\\textent: form width @ (newImage height - form height + 10))\\n\\t\\tfrom: 0 @ (form height - (newImage height - form height + 10))\\n\\t\\tin: form\\n\\t\\trule: Form over.\\n\\tcanvas := newImage getCanvas.\\n\\tcanvas \\n\\t\\tline: 12 @ (form height - 10)\\n\\t\\tto: 92 @ (form height - 10)\\n\\t\\twidth: 1\\n\\t\\tcolor: Color black.\\n\\tcanvas := canvas copyOffset: 12 @ (form height - 9).\\n\\tinner := Color \\n\\t\\t\\t\\tr: 0.677\\n\\t\\t\\t\\tg: 0.71\\n\\t\\t\\t\\tb: 0.968.\\n\\touter := inner darker darker.\\n\\tborder := Color \\n\\t\\t\\t\\tr: 0.194\\n\\t\\t\\t\\tg: 0.258\\n\\t\\t\\t\\tb: 0.194.\\n\\t0 to: 1\\n\\t\\tdo: \\n\\t\\t\\t[:y | \\n\\t\\t\\t0 to: 3\\n\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t[:x | \\n\\t\\t\\t\\t\\tbox := (x * 20) @ (y * 20) extent: 20 @ 20.\\n\\t\\t\\t\\t\\tmorph := BorderedMorph new \\n\\t\\t\\t\\t\\t\\t\\t\\tbounds: ((box insetBy: 1) translateBy: canvas origin + bounds origin).\\n\\t\\t\\t\\t\\tmorph\\n\\t\\t\\t\\t\\t\\tborderWidth: 1;\\n\\t\\t\\t\\t\\t\\tborderColor: border.\\n\\t\\t\\t\\t\\tmorph color: Color white.\\n\\t\\t\\t\\t\\tmorph \\n\\t\\t\\t\\t\\t\\ton: #mouseDown\\n\\t\\t\\t\\t\\t\\tsend: #mouseDownRecent:with:\\n\\t\\t\\t\\t\\t\\tto: self.\\n\\t\\t\\t\\t\\tmorph \\n\\t\\t\\t\\t\\t\\ton: #mouseMove\\n\\t\\t\\t\\t\\t\\tsend: #mouseStillDownRecent:with:\\n\\t\\t\\t\\t\\t\\tto: self.\\n\\t\\t\\t\\t\\tmorph \\n\\t\\t\\t\\t\\t\\ton: #mouseUp\\n\\t\\t\\t\\t\\t\\tsend: #mouseUpRecent:with:\\n\\t\\t\\t\\t\\t\\tto: self.\\n\\t\\t\\t\\t\\tself addMorphFront: morph.\\n\\t\\t\\t\\t\\trecentColors nextPut: morph.\\n\\t\\t\\t\\t\\tcanvas fillRectangle: box color: Color white.\\n\\t\\t\\t\\t\\tcanvas frameRectangle: (box insetBy: 1) color: border.\\n\\t\\t\\t\\t\\tcanvas frameRectangle: box color: inner.\\n\\t\\t\\t\\t\\tbox := box insetBy: 1.\\n\\t\\t\\t\\t\\tcanvas \\n\\t\\t\\t\\t\\t\\tline: box topRight\\n\\t\\t\\t\\t\\t\\tto: box bottomRight\\n\\t\\t\\t\\t\\t\\twidth: 1\\n\\t\\t\\t\\t\\t\\tcolor: outer.\\n\\t\\t\\t\\t\\tcanvas \\n\\t\\t\\t\\t\\t\\tline: box bottomLeft\\n\\t\\t\\t\\t\\t\\tto: box bottomRight\\n\\t\\t\\t\\t\\t\\twidth: 1\\n\\t\\t\\t\\t\\t\\tcolor: outer]].\\n\\trecentColors := recentColors contents.\\n\\t(RecentColors isNil or: [RecentColors size ~= recentColors size]) \\n\\t\\tifTrue: [RecentColors := recentColors collect: [:each | each color]]\\n\\t\\tifFalse: \\n\\t\\t\\t[RecentColors \\n\\t\\t\\t\\tkeysAndValuesDo: [:idx :aColor | (recentColors at: idx) color: aColor]].\\n\\tself image: newImage.\\n\\tself toggleStamps.\\n\\tself toggleStamps! !\\n\\n!PaintBoxMorph methodsFor: 'recent colors' stamp: 'ar 9/23/2000 19:54'!\\nmouseDownRecent: evt with: aMorph\\n\\taMorph borderColor: Color white.\\n! !\\n\\n!PaintBoxMorph methodsFor: 'recent colors' stamp: 'ar 9/23/2000 20:01'!\\nmouseStillDownRecent: evt with: aMorph\\n\\t(aMorph containsPoint: evt cursorPoint)\\n\\t\\tifTrue:[aMorph borderColor: Color white]\\n\\t\\tifFalse:[aMorph borderColor: (Color r: 0.194 g: 0.258 b: 0.194)]\\n! !\\n\\n!PaintBoxMorph methodsFor: 'recent colors' stamp: 'ar 9/23/2000 19:59'!\\nmouseUpRecent: evt with: aMorph\\n\\taMorph borderColor: (Color r: 0.194 g: 0.258 b: 0.194).\\n\\t(aMorph containsPoint: evt cursorPoint) ifTrue:[\\n\\t\\tself takeColor: aMorph color event: evt.\\n\\t].! !\\n\\n!PaintBoxMorph methodsFor: 'recent colors' stamp: 'dgd 2/21/2003 23:17'!\\nrecentColor: aColor \\n\\t\\\"Remember the color as one of our recent colors\\\"\\n\\n\\t(recentColors anySatisfy: [:any | any color = aColor]) ifTrue: [^self].\\t\\\"already remembered\\\"\\n\\trecentColors size to: 2\\n\\t\\tby: -1\\n\\t\\tdo: \\n\\t\\t\\t[:i | \\n\\t\\t\\t(recentColors at: i) color: (recentColors at: i - 1) color.\\n\\t\\t\\tRecentColors at: i put: (RecentColors at: i - 1)].\\n\\t(recentColors first) color: aColor.\\n\\tRecentColors at: 1 put: aColor! !\\n\\n\\n!PaintBoxMorph methodsFor: 'user interface' stamp: 'tk 7/2/97 08:10'!\\nmouseUpBalk: evt\\n\\t\\\"A button I own got a mouseDown, but the user moved out before letting up. Prevent this for the current tool. Some tool must stay selected.\\\"\\n\\n\\ttool state: #on.\\t\\\"keep current one, even if user balked on it\\\"\\n\\tcurrentBrush ifNotNil: [currentBrush state: #on].! !\\n\\n\\n!PaintBoxMorph methodsFor: '*eToys-e-toy support' stamp: 'sw 6/30/1999 20:33'!\\nisCandidateForAutomaticViewing\\n\\t^ false! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPaintBoxMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!PaintBoxMorph class methodsFor: 'as yet unclassified' stamp: 'tk 8/21/2000 12:52'!\\nfixUpPrototype\\n\\t\\\"PaintBoxMorph fixUpPrototype\\\"\\nself error: 'who uses this?'.\\n\\tPrototype eventHandler: nil! !\\n\\n!PaintBoxMorph class methodsFor: 'as yet unclassified' stamp: 'ar 7/8/2006 20:33'!\\ninitializeColorChart\\n\\t\\\"PaintBoxMorph initializeColorChart\\\"\\n\\tColorChart _ (ColorPickerMorph colorPaletteForDepth: 32 extent: (360+10)@(180+10))! !\\n\\n!PaintBoxMorph class methodsFor: 'as yet unclassified' stamp: 'tk 10/12/97 11:01'!\\nprototype\\n\\t\\\"Later we will be a subclass of Model, and it will have a general version of this\\\"\\n\\t^ Prototype! !\\n\\n\\n!PaintBoxMorph class methodsFor: 'class initialization' stamp: 'tk 8/21/2000 12:58'!\\ninitialize\\n\\t\\\"PaintBoxMorph initialize\\\"\\n\\n\\tPrototype eventHandler: nil.\\n\\tPrototype focusMorph: nil.\\n\\tPrototype stampHolder clear. \\\"clear stamps\\\"\\n\\tPrototype delete. \\\"break link to world, if any\\\"\\n\\n\\tAllOnImage _ AllOffImage _ AllPressedImage _ nil.\\n\\tOriginalBounds _ nil.\\n\\n! !\\n\\n\\n!PaintBoxMorph class methodsFor: 'instance creation' stamp: 'bf 10/11/2004 13:37'!\\nnew\\n\\n\\t| pb button dualUse formCanvas rect |\\n\\tpb _ Prototype veryDeepCopy.\\n\\t\\t\\\"Assume that the PaintBox does not contain any scripted Players!!\\\"\\n\\tpb stampHolder normalize.\\t\\\"Get the stamps to show\\\"\\n\\t\\\"Get my own copies of the brushes so I can modify them\\\"\\n\\t#(brush1: brush2: brush3: brush4: brush5: brush6:) do: [:sel |\\n\\t\\tbutton _ pb submorphNamed: sel.\\n\\t\\tbutton offImage: button offImage deepCopy.\\n\\t\\tdualUse _ button onImage == button pressedImage.\\t\\\"sometimes shared\\\"\\n\\t\\tbutton onImage: button onImage deepCopy.\\n\\t\\tdualUse\\n\\t\\t\\tifTrue: [button pressedImage: button onImage]\\n\\t\\t\\tifFalse: [button pressedImage: button pressedImage deepCopy].\\n\\t\\t\\\"force color maps for later mapping\\\"\\n\\t\\tbutton offImage.\\n\\t\\tbutton onImage.\\n\\t\\tbutton pressedImage.\\n\\t\\tformCanvas _ button onImage getCanvas.\\n\\t\\tformCanvas _ formCanvas\\n\\t\\t\\tcopyOrigin: 0@0\\n\\t\\t\\tclipRect: (rect _ 0@0 extent: button onImage extent).\\n\\t\\t(#(brush1: brush3:) includes: sel) ifTrue: [\\n\\t\\t\\trect _ rect origin corner: rect corner - (2@2)].\\n\\t\\t(#brush2: == sel) ifTrue: [\\n\\t\\t\\trect _ rect origin corner: rect corner - (2@4)].\\n\\t\\tformCanvas frameAndFillRectangle: rect fillColor: Color transparent\\n\\t\\t\\tborderWidth: 2 borderColor: (Color r: 0.599 g: 0.8 b: 1.0).\\n\\t\\t].\\n\\tpb showColor.\\n\\tpb fixUpRecentColors.\\n\\tpb addLabels.\\n\\t^ pb! !\\n\\n\\n!PaintBoxMorph class methodsFor: 'notification' stamp: 'ar 7/8/2006 20:33'!\\nlocaleChanged\\n\\t| caption |\\n\\tcaption := ColorPickerMorph noColorCaption.\\n\\tcaption displayOn: ColorChart at: ColorChart boundingBox topCenter - (caption width // 2 @ 0)! !\\nImageMorph subclass: #PaintInvokingMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Widgets'!\\n!PaintInvokingMorph commentStamp: '<historical>' prior: 0!\\nWhen this is dropped inside some appropriate place, then painting is invoked for that place.!\\n\\n\\n!PaintInvokingMorph methodsFor: 'dropping/grabbing' stamp: 'dgd 4/3/2006 14:19'!\\njustDroppedInto: aPasteUpMorph event: anEvent\\n\\t\\\"This message is sent to a dropped morph after it has been dropped on--and been accepted by--a drop-sensitive morph\\\"\\n\\taPasteUpMorph isPartsBin ifFalse:[\\n\\t\\tself removeHalo.\\n\\t\\tself delete.\\n\\t\\t^aPasteUpMorph makeNewDrawing: anEvent].\\n\\t^super justDroppedInto: aPasteUpMorph event: anEvent! !\\n\\n!PaintInvokingMorph methodsFor: 'dropping/grabbing' stamp: 'ar 3/3/2001 20:40'!\\nwantsToBeDroppedInto: aMorph\\n\\t\\\"Only into PasteUps that are not part bins\\\"\\n\\t^aMorph isPlayfieldLike! !\\n\\n\\n!PaintInvokingMorph methodsFor: 'initialization' stamp: 'sw 7/16/1998 00:02'!\\ninitialize\\n\\tsuper initialize.\\n\\tself image: (ScriptingSystem formAtKey: 'Painting')! !\\n\\n\\n!PaintInvokingMorph methodsFor: 'parts bin' stamp: 'sw 8/12/2001 17:19'!\\ninitializeToStandAlone\\n\\tsuper initializeToStandAlone.\\n\\tself image: (ScriptingSystem formAtKey: 'Painting')! !\\n\\n\\n!PaintInvokingMorph methodsFor: '*eToys-e-toy support' stamp: 'sw 6/30/1999 20:31'!\\nisCandidateForAutomaticViewing\\n\\t^ self isPartsDonor not! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nPaintInvokingMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!PaintInvokingMorph class methodsFor: 'class initialization' stamp: 'asm 4/10/2003 13:16'!\\ninitialize\\n\\n\\tself registerInFlapsRegistry.! !\\n\\n!PaintInvokingMorph class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 10:09'!\\nregisterInFlapsRegistry\\n\\t\\\"Register the receiver in the system's flaps registry\\\"\\n\\tself environment\\n\\t\\tat: #Flaps\\n\\t\\tifPresent: [:cl | cl registerQuad: #(PaintInvokingMorph\\tnew\\t'Paint'\\t'Drop this into an area to start making a fresh painting there')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'PlugIn Supplies'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(PaintInvokingMorph\\tnew\\t'Paint'\\t'Drop this into an area to start making a fresh painting there')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Widgets'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(PaintInvokingMorph\\tnew\\t'Paint'\\t'Drop this into an area to start making a fresh painting there')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Scripting']! !\\n\\n!PaintInvokingMorph class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 12:38'!\\nunload\\n\\t\\\"Unload the receiver from global registries\\\"\\n\\n\\tself environment at: #Flaps ifPresent: [:cl |\\n\\tcl unregisterQuadsWithReceiver: self] ! !\\n\\n\\n!PaintInvokingMorph class methodsFor: 'parts bin' stamp: 'nk 8/23/2004 18:11'!\\ndescriptionForPartsBin\\n\\t^ self partName:\\t'Paint'\\n\\t\\tcategories:\\t\\t#('Basic' 'Graphics')\\n\\t\\tdocumentation:\\t'Drop this icon to start painting a new object.'! !\\n\\n\\n!PaintInvokingMorph class methodsFor: 'scripting' stamp: 'sw 5/6/2000 02:28'!\\nauthoringPrototype\\n\\t^ self new image: (ScriptingSystem formAtKey: 'Painting'); markAsPartsDonor; setBalloonText: 'drop this into any playfield or book page to make a new painting there'; yourself! !\\nCompositeStub subclass: #PanelStub\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ToolBuilder-SUnit'!\\nDisplayText subclass: #Paragraph\\n\\tinstanceVariableNames: 'clippingRectangle compositionRectangle destinationForm rule mask marginTabsLevel lines lastLine'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: 'TextConstants'\\n\\tcategory: 'ST80-Support'!\\n!Paragraph commentStamp: '<historical>' prior: 0!\\nI represent displayable text that has been decoraged with margin alignment, line leading, and tab settings.!\\n\\n\\n!Paragraph methodsFor: 'accessing'!\\nbackgroundColor\\n\\tbackColor == nil ifTrue: [^ Color white].\\n\\t^ backColor! !\\n\\n!Paragraph methodsFor: 'accessing'!\\nclippingRectangle \\n\\t\\\"Answer the rectangle, defined in absolute coordinates, whose \\n\\tintersection with the destinationForm is the area in which the characters \\n\\tare constrained to display.\\\"\\n\\n\\t^clippingRectangle! !\\n\\n!Paragraph methodsFor: 'accessing' stamp: 'di 10/5/97 15:33'!\\nclippingRectangle: clipRect \\n\\tclippingRectangle _ clipRect! !\\n\\n!Paragraph methodsFor: 'accessing'!\\ncompositionRectangle\\n\\t\\\"Answer the rectangle whose width is the dimension, modified by \\n\\tindents and tabsLevels, against which line wraparound is measured. The \\n\\theight of the compositionRectangle is reset each time recomposition is \\n\\trequired.\\\"\\n\\n\\t^compositionRectangle! !\\n\\n!Paragraph methodsFor: 'accessing'!\\ncompositionRectangle: compRectangle \\n\\t\\\"Set the rectangle whose width is the dimension, modified by indents and \\n\\ttabsLevels, against which line wraparound is measured.\\\"\\n\\n\\tcompositionRectangle _ compRectangle.\\n\\tself composeAll! !\\n\\n!Paragraph methodsFor: 'accessing'!\\ndestinationForm \\n\\t \\\"Answer the Form into which the characters are scanned.\\\"\\n\\n\\t^destinationForm! !\\n\\n!Paragraph methodsFor: 'accessing'!\\nfillColor \\n\\t\\\"Answer the Form with which each character is combined by the scanner \\n\\tbefore applying the rule for display.\\\"\\n\\n\\t^mask! !\\n\\n!Paragraph methodsFor: 'accessing'!\\nfillColor: maskForm \\n\\t\\\"Set the argument, maskForm, to be the form with which each character \\n\\tis combined by the scanner before applying the rule for display.\\\"\\n\\n\\tmask _ maskForm! !\\n\\n!Paragraph methodsFor: 'accessing'!\\nheight \\n\\t\\\"Answer the height of the composition rectangle.\\\"\\n\\n\\t^compositionRectangle height! !\\n\\n!Paragraph methodsFor: 'accessing'!\\nindentationOfLineIndex: lineIndex ifBlank: aBlock\\n\\t\\\"Answer the number of leading tabs in the line at lineIndex. If there are\\n\\t no visible characters, pass the number of tabs to aBlock and return its value.\\n\\t If the line is word-wrap overflow, back up a line and recur.\\\"\\n\\n\\t| arrayIndex first last reader leadingTabs lastSeparator cr tab ch |\\n\\tcr _ Character cr.\\n\\ttab _ Character tab.\\n\\tarrayIndex _ lineIndex.\\n\\t[first _ (lines at: arrayIndex) first.\\n\\t first > 1 and: [(text string at: first - 1) ~~ cr]] whileTrue: \\\"word wrap\\\"\\n\\t\\t[arrayIndex _ arrayIndex - 1].\\n\\tlast _ (lines at: lastLine) last.\\n\\treader _ ReadStream on: text string from: first to: last.\\n\\tleadingTabs _ 0.\\n\\t[reader atEnd not and: [(ch _ reader next) == tab]]\\n\\t\\twhileTrue: [leadingTabs _ leadingTabs + 1].\\n\\tlastSeparator _ first - 1 + leadingTabs.\\n\\t[reader atEnd not and: [ch isSeparator and: [ch ~~ cr]]]\\n\\t\\twhileTrue: [lastSeparator _ lastSeparator + 1. ch _ reader next].\\n\\tlastSeparator = last | (ch == cr)\\n\\t\\tifTrue: [^aBlock value: leadingTabs].\\n\\t^leadingTabs! !\\n\\n!Paragraph methodsFor: 'accessing'!\\nmask \\n\\t\\\"Answer the Form with which each character is combined by the scanner \\n\\tbefore applying the rule for display.\\\"\\n\\n\\t^mask! !\\n\\n!Paragraph methodsFor: 'accessing'!\\nnumberOfLines \\n\\t\\\"Answer the number of lines of text in the receiver.\\\"\\n\\n\\t^lastLine! !\\n\\n!Paragraph methodsFor: 'accessing' stamp: 'ar 5/18/2000 18:34'!\\nreplaceFrom: start to: stop with: aText displaying: displayBoolean\\n\\t\\\"Replace the receiver's text starting at position start, stopping at stop, by \\n\\tthe characters in aText. It is expected that most requirements for \\n\\tmodifications to the receiver will call this code. Certainly all cut's or \\n\\tpaste's.\\\" \\n\\n\\t| compositionScanner obsoleteLines obsoleteLastLine firstLineIndex lastLineIndex\\n\\tstartLine stopLine replacementRange visibleRectangle startIndex newLine done\\n\\tnewStop obsoleteY newY moveRectangle |\\n\\n\\ttext replaceFrom: start to: stop with: aText.\\t\\t\\\"Update the text.\\\"\\n\\tlastLine = 0 ifTrue:\\n\\t\\t[\\\"if lines have never been set up, measure them and display\\n\\t\\tall the lines falling in the visibleRectangle\\\"\\n\\t\\tself composeAll.\\n\\t\\tdisplayBoolean ifTrue: [^ self displayLines: (1 to: lastLine)]].\\n\\n\\t\\\"save -- things get pretty mashed as we go along\\\"\\n\\tobsoleteLines _ lines copy.\\n\\tobsoleteLastLine _ lastLine.\\n\\n\\t\\\"find the starting and stopping lines\\\"\\n\\tfirstLineIndex _ startLine _ self lineIndexOfCharacterIndex: start.\\n\\tstopLine _ self lineIndexOfCharacterIndex: stop.\\n\\n\\t\\\"how many characters being inserted or deleted\\n\\t\\t-- negative if aText size is < characterInterval size.\\\"\\n\\treplacementRange _ aText size - (stop - start + 1).\\n\\t\\\"Give ourselves plenty of elbow room.\\\"\\n\\tcompositionRectangle _ compositionRectangle withHeight: (textStyle lineGrid * 9999).\\n\\t\\\"build a boundingBox of the actual screen space in question -- we'll need it later\\\"\\n\\tvisibleRectangle _ (clippingRectangle intersect: compositionRectangle)\\n\\t\\t\\t\\t\\t\\t\\tintersect: destinationForm boundingBox.\\n\\tcompositionScanner _ CompositionScanner new forParagraph: self.\\t\\t\\\"Initialize a scanner.\\\"\\n\\n\\t\\\"If the starting line is not also the first line, then measuring must commence from line preceding the one in which characterInterval start appears. For example, deleting a line with only a carriage return may move characters following the deleted portion of text into the line preceding the deleted line.\\\"\\n\\tstartIndex _ (lines at: firstLineIndex) first.\\n\\tstartLine > 1\\n\\t\\tifTrue: \\t[newLine _ compositionScanner composeLine: startLine - 1\\n\\t\\t\\t\\t\\t\\tfromCharacterIndex: (lines at: startLine - 1) first\\n\\t\\t\\t\\t\\t\\tinParagraph: self.\\n\\t\\t\\t\\t(lines at: startLine - 1) = newLine\\n\\t\\t\\t\\t\\tifFalse:\\t[\\\"start in line preceding the one with the starting character\\\"\\n\\t\\t\\t\\t\\t\\t\\tstartLine _ startLine - 1.\\n\\t\\t\\t\\t\\t\\t\\tself lineAt: startLine put: newLine.\\n\\t\\t\\t\\t\\t\\t\\tstartIndex _ newLine last + 1]].\\n\\tstartIndex > text size ifTrue:\\n\\t\\t[\\\"nil lines after a deletion -- remeasure last line below\\\"\\n\\t\\tself trimLinesTo: (firstLineIndex - 1 max: 0).\\n\\t\\ttext size = 0 ifTrue:\\n\\t\\t\\t[\\\"entire text deleted -- clear visibleRectangle and return.\\\"\\n\\t\\t\\tdisplayBoolean ifTrue: [destinationForm fill: visibleRectangle rule: rule fillColor: self backgroundColor].\\n\\t\\t\\tself updateCompositionHeight.\\n\\t\\t\\t^self]].\\n\\n\\t\\\"Now we really get to it.\\\"\\n\\tdone _ false.\\n\\tlastLineIndex _ stopLine.\\n\\t[done or: [startIndex > text size]]\\n\\t\\twhileFalse: \\n\\t\\t[self lineAt: firstLineIndex put:\\n\\t\\t\\t(newLine _ compositionScanner composeLine: firstLineIndex\\n\\t\\t\\t\\t\\t\\t\\tfromCharacterIndex: startIndex inParagraph: self).\\n\\t\\t[(lastLineIndex > obsoleteLastLine\\n\\t\\t\\tor: [\\\"no more old lines to compare with?\\\"\\n\\t\\t\\t\\tnewLine last <\\n\\t\\t\\t\\t\\t(newStop _ (obsoleteLines at: lastLineIndex) last + replacementRange)])\\n\\t\\t\\t \\tor: [done]]\\n\\t\\t\\twhileFalse: \\n\\t\\t\\t[newStop = newLine last\\n\\t\\t\\t\\tifTrue:\\t[\\\"got the match\\\"\\n\\t\\t\\t\\t\\t\\t\\\"get source and dest y's for moving the unchanged lines\\\"\\n\\t\\t\\t\\t\\t\\tobsoleteY _ self topAtLineIndex: lastLineIndex + 1\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tusing: obsoleteLines and: obsoleteLastLine.\\n\\t\\t\\t\\t\\t\\tnewY _ self topAtLineIndex: firstLineIndex + 1.\\n\\t\\t\\t\\t\\t\\tstopLine _ firstLineIndex.\\n\\t\\t\\t\\t\\t\\tdone _ true.\\n\\t\\t\\t\\t\\t\\t\\t\\\"Fill in the new line vector with the old unchanged lines.\\n\\t\\t\\t\\t\\t\\t\\tUpdate their starting and stopping indices on the way.\\\"\\n\\t\\t\\t\\t\\t\\t((lastLineIndex _ lastLineIndex + 1) to: obsoleteLastLine) do:\\n\\t\\t\\t\\t\\t\\t\\t[:upDatedIndex | \\n\\t\\t\\t\\t\\t\\t\\tself lineAt: (firstLineIndex _ firstLineIndex + 1) \\n\\t\\t\\t\\t\\t\\t\\t\\tput: ((obsoleteLines at: upDatedIndex)\\n\\t\\t\\t\\t\\t\\t\\t \\t\\tslide: replacementRange)].\\n\\t\\t\\t\\t\\t\\t\\t\\\"trim off obsolete lines, if any\\\"\\n\\t\\t\\t\\t\\t\\tself trimLinesTo: firstLineIndex]\\n\\t\\t\\t\\tifFalse:\\t[lastLineIndex _ lastLineIndex + 1]].\\n\\t\\tstartIndex _ newLine last + 1.\\n\\t\\tfirstLineIndex _ firstLineIndex + 1].\\n\\n\\t\\\"Now the lines are up to date -- Whew!!. What remains is to move\\n\\tthe 'unchanged' lines and display those which have changed.\\\"\\n\\tdisplayBoolean \\\"Not much to do if not displaying\\\"\\n\\t\\tifFalse: [^ self updateCompositionHeight].\\n\\tstartIndex > text size ifTrue:\\n\\t\\t[\\\"If at the end of previous lines simply display lines from the line in\\n\\t\\twhich the first character of the replacement occured through the\\n\\t\\tend of the paragraph.\\\"\\n\\t\\tself updateCompositionHeight.\\n\\t\\tself displayLines:\\n\\t\\t\\t(startLine to: (stopLine _ firstLineIndex min: lastLine)).\\n\\t\\tdestinationForm \\\"Clear out area at the bottom\\\"\\n\\t\\t\\tfill: ((visibleRectangle left @ (self topAtLineIndex: lastLine + 1)\\n\\t\\t\\t\\t\\t\\textent: visibleRectangle extent)\\n\\t\\t\\t\\t\\tintersect: visibleRectangle)\\n\\t\\t\\trule: rule fillColor: self backgroundColor]\\n\\t\\tifFalse:\\n\\t\\t[newY ~= obsoleteY ifTrue:\\n\\t\\t\\t[\\\"Otherwise first move the unchanged lines within\\n\\t\\t\\tthe visibleRectangle with a good old bitblt.\\\"\\n\\t\\t\\tmoveRectangle _\\n\\t\\t\\t\\tvisibleRectangle left @ (obsoleteY max: visibleRectangle top)\\n\\t\\t\\t\\t\\tcorner: visibleRectangle corner.\\n\\t\\t\\tdestinationForm copyBits: moveRectangle from: destinationForm\\n\\t\\t\\t\\tat: moveRectangle origin + (0 @ (newY-obsoleteY))\\n\\t\\t\\t\\tclippingBox: visibleRectangle\\n\\t\\t\\t\\trule: Form over fillColor: nil].\\n\\n\\t\\t\\\"Then display the altered lines.\\\"\\n\\t\\tself displayLines: (startLine to: stopLine).\\n\\n\\t\\tnewY < obsoleteY\\n\\t\\t\\tifTrue:\\n\\t\\t\\t[(self topAtLineIndex: obsoleteLastLine+1 using: obsoleteLines and: obsoleteLastLine) > visibleRectangle bottom\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[\\\"A deletion may have 'pulled' previously undisplayed lines\\n\\t\\t\\t\\tinto the visibleRectangle. If so, display them.\\\"\\n\\t\\t\\t\\tself displayLines:\\n\\t\\t\\t\\t\\t((self lineIndexOfTop: visibleRectangle bottom - (obsoleteY - newY))\\n\\t\\t\\t\\t\\t\\tto: (self lineIndexOfTop: visibleRectangle bottom))].\\n\\t\\t\\t\\\"Clear out obsolete material at the bottom of the visibleRectangle.\\\"\\n\\t\\t\\tdestinationForm\\n\\t\\t\\t\\tfill: ((visibleRectangle left @ ((self bottomAtLineIndex: lastLine) + 1)\\n\\t\\t\\t\\t\\t\\textent: visibleRectangle extent)\\n\\t\\t\\t\\t\\tintersect: visibleRectangle) \\\"How about just corner: ??\\\"\\n\\t\\t\\t\\trule: rule fillColor: self backgroundColor].\\n\\n\\t\\t(newY > obsoleteY and: [obsoleteY < visibleRectangle top])\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[\\\"An insertion may have 'pushed' previously undisplayed lines\\n\\t\\t\\t\\tinto the visibleRectangle. If so, display them.\\\"\\n\\t\\t\\t\\tself displayLines:\\n\\t\\t\\t\\t\\t((self lineIndexOfTop: visibleRectangle top)\\n\\t\\t\\t\\t\\t\\tto: (self lineIndexOfTop: visibleRectangle top + (newY-obsoleteY)))].\\n\\n\\t\\tself updateCompositionHeight]! !\\n\\n!Paragraph methodsFor: 'accessing'!\\nrule \\n\\t\\\"Answer the rule according to which character display behaves. For \\n\\texample, rule may equal over, under, reverse.\\\"\\n\\n\\t^rule! !\\n\\n!Paragraph methodsFor: 'accessing'!\\nrule: ruleInteger \\n\\t\\\"Set the rule according to which character display behaves.\\\"\\n\\n\\trule _ ruleInteger! !\\n\\n!Paragraph methodsFor: 'accessing' stamp: 'sw 10/29/1999 18:11'!\\nstringAtLineNumber: aNumber\\n\\t(aNumber > lastLine or: [aNumber < 1]) ifTrue: [^ nil].\\n\\t^ (text string copyFrom: (lines at: aNumber) first to: (lines at: aNumber) last) copyWithout: Character cr! !\\n\\n!Paragraph methodsFor: 'accessing'!\\ntext: aText \\n\\t\\\"Set the argument, aText, to be the text for the receiver.\\\"\\n\\n\\ttext _ aText.\\n\\tself composeAll! !\\n\\n\\n!Paragraph methodsFor: 'alignment'!\\ncentered \\n\\t\\\"Set the alignment for the style with which the receiver displays its text \\n\\tso that text is centered in the composition rectangle.\\\"\\n\\n\\ttextStyle alignment: Centered! !\\n\\n!Paragraph methodsFor: 'alignment'!\\njustified \\n\\t\\\"Set the alignment for the style with which the receiver displays its text \\n\\tso that the characters in each of text end on an even border in the \\n\\tcomposition rectangle.\\\"\\n\\n\\ttextStyle alignment: Justified! !\\n\\n!Paragraph methodsFor: 'alignment'!\\nleftFlush \\n\\t\\\"Set the alignment for the style with which the receiver displays its text \\n\\tso that the characters in each of text begin on an even border in the \\n\\tcomposition rectangle. This is also known as ragged-right.\\\"\\n\\n\\ttextStyle alignment: LeftFlush! !\\n\\n!Paragraph methodsFor: 'alignment'!\\nrightFlush \\n\\t\\\"Set the alignment for the style with which the receiver displays its text \\n\\tso that the characters in each of text end on an even border in the \\n\\tcomposition rectangle but the beginning of each line does not. This is \\n\\talso known as ragged-left.\\\"\\n\\n\\ttextStyle alignment: RightFlush! !\\n\\n!Paragraph methodsFor: 'alignment'!\\ntoggleAlignment \\n\\t\\\"Set the alignment for the style with which the receiver displays its text \\n\\tso that it moves from centered to justified to leftFlush to rightFlush and \\n\\tback to centered again.\\\"\\n\\n\\ttextStyle alignment: textStyle alignment + 1! !\\n\\n\\n!Paragraph methodsFor: 'character location' stamp: 'ar 5/18/2000 18:33'!\\ncharacterBlockAtPoint: aPoint \\n\\t\\\"Answer a CharacterBlock for characters in the text at point aPoint. It is \\n\\tassumed that aPoint has been transformed into coordinates appropriate to \\n\\tthe receiver's destinationForm rectangle and the compositionRectangle.\\\"\\n\\n\\t^CharacterBlockScanner new characterBlockAtPoint: aPoint in: self! !\\n\\n!Paragraph methodsFor: 'character location' stamp: 'ar 5/18/2000 18:33'!\\ncharacterBlockForIndex: targetIndex \\n\\t\\\"Answer a CharacterBlock for character in the text at targetIndex. The \\n\\tcoordinates in the CharacterBlock will be appropriate to the intersection \\n\\tof the destinationForm rectangle and the compositionRectangle.\\\"\\n\\n\\t^CharacterBlockScanner new characterBlockForIndex: targetIndex in: self! !\\n\\n!Paragraph methodsFor: 'character location' stamp: 'di 10/5/1998 12:59'!\\ndefaultCharacterBlock\\n\\t^ CharacterBlock new stringIndex: 1 text: text\\n\\t\\t\\ttopLeft: compositionRectangle topLeft extent: 0 @ 0! !\\n\\n\\n!Paragraph methodsFor: 'composition' stamp: 'yo 1/23/2003 22:47'!\\ncomposeAll\\n\\t\\\"Compose a collection of characters into a collection of lines.\\\"\\n\\n\\t| startIndex stopIndex lineIndex maximumRightX compositionScanner |\\n\\tlines _ Array new: 32.\\n\\tlastLine _ 0.\\n\\tmaximumRightX _ 0.\\n\\ttext size = 0\\n\\t\\tifTrue:\\n\\t\\t\\t[compositionRectangle _ compositionRectangle withHeight: 0.\\n\\t\\t\\t^maximumRightX].\\n\\tstartIndex _ lineIndex _ 1.\\n\\tstopIndex _ text size.\\n\\tcompositionScanner _ MultiCompositionScanner new forParagraph: self.\\n\\t[startIndex > stopIndex] whileFalse: \\n\\t\\t[self lineAt: lineIndex \\n\\t\\t\\t\\tput: (compositionScanner composeLine: lineIndex \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tfromCharacterIndex: startIndex \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tinParagraph: self).\\n\\t\\t maximumRightX _ compositionScanner rightX max: maximumRightX.\\n\\t\\t startIndex _ (lines at: lineIndex) last + 1.\\n\\t\\t lineIndex _ lineIndex + 1].\\n\\tself updateCompositionHeight.\\n\\tself trimLinesTo: lineIndex - 1.\\n\\t^ maximumRightX! !\\n\\n!Paragraph methodsFor: 'composition'!\\nwrappingBox: compositionRect clippingBox: clippingRect \\n\\t\\\"Set the composition rectangle for the receiver so that the lines wrap \\n\\twithin the rectangle, compositionRect, and the display of the text is \\n\\tclipped by the rectangle, clippingRect.\\\"\\n\\n\\tself compositionRectangle: compositionRect copy\\n\\t\\t\\t\\ttext: text\\n\\t\\t\\t\\tstyle: textStyle\\n\\t\\t\\t\\toffset: offset.\\n\\tclippingRectangle _ clippingRect copy! !\\n\\n\\n!Paragraph methodsFor: 'converting' stamp: 'yo 6/23/2003 19:05'!\\nasForm\\n\\t\\\"Answer a Form made up of the bits that represent the receiver's displayable text.\\\"\\n\\t| theForm oldBackColor oldForeColor |\\n\\ttextStyle isTTCStyle ifTrue: [\\n\\t\\ttheForm _ (Form extent: compositionRectangle extent depth: 32)\\n\\t\\toffset: offset.\\n\\t] ifFalse: [\\n\\t\\ttheForm _ (ColorForm extent: compositionRectangle extent)\\n\\t\\t\\toffset: offset;\\n\\t\\t\\tcolors: (Array\\n\\t\\t\\t\\twith: (backColor == nil ifTrue: [Color transparent] ifFalse: [backColor])\\n\\t\\t\\t\\twith: (foreColor == nil ifTrue: [Color black] ifFalse: [foreColor])).\\n\\t].\\n\\toldBackColor _ backColor.\\n\\toldForeColor _ foreColor.\\n\\tbackColor _ Color white.\\n\\tforeColor _ Color black.\\n\\tself displayOn: theForm\\n\\t\\tat: 0@0\\n\\t\\tclippingBox: theForm boundingBox\\n\\t\\trule: Form over\\n\\t\\tfillColor: nil.\\n\\tbackColor _ oldBackColor.\\n\\tforeColor _ oldForeColor.\\n\\t^ theForm\\n\\n\\\"Example:\\n| p |\\np _ 'Abc' asParagraph.\\np foregroundColor: Color red backgroundColor: Color black.\\np asForm displayOn: Display at: 30@30 rule: Form over\\\"\\n! !\\n\\n!Paragraph methodsFor: 'converting'!\\nasString\\n\\t\\\"Answer the string of characters of the receiver's text.\\\"\\n\\n\\t^text string! !\\n\\n!Paragraph methodsFor: 'converting'!\\nasText\\n\\t\\\"Answer the receiver's text.\\\"\\n\\n\\t^text! !\\n\\n\\n!Paragraph methodsFor: 'display box access'!\\nboundingBox\\n\\n\\t^offset extent: compositionRectangle extent! !\\n\\n!Paragraph methodsFor: 'display box access'!\\ncomputeBoundingBox\\n\\n\\t^offset extent: compositionRectangle extent! !\\n\\n\\n!Paragraph methodsFor: 'displaying'!\\ndisplayOn: aDisplayMedium\\n\\t\\\"Because Paragraphs cache so much information, computation is avoided\\n\\tand displayAt: 0@0 is not appropriate here.\\\"\\n\\n\\tself displayOn: aDisplayMedium\\n\\t\\tat: compositionRectangle topLeft\\n\\t\\tclippingBox: clippingRectangle\\n\\t\\trule: rule\\n\\t\\tfillColor: mask! !\\n\\n!Paragraph methodsFor: 'displaying'!\\ndisplayOn: aDisplayMedium at: aPoint\\n\\t\\\"Use internal clippingRect; destination cliping is done during actual display.\\\"\\n\\n\\tself displayOn: aDisplayMedium at: aPoint\\n\\t\\tclippingBox: (clippingRectangle translateBy: aPoint - compositionRectangle topLeft)\\n\\t\\trule: rule fillColor: mask! !\\n\\n!Paragraph methodsFor: 'displaying'!\\ndisplayOn: aDisplayMedium at: aDisplayPoint clippingBox: clipRectangle rule: ruleInteger fillColor: aForm\\n\\t\\\"Default display message when aDisplayPoint is in absolute screen\\n\\tcoordinates.\\\"\\n\\n\\trule _ ruleInteger.\\n\\tmask _ aForm.\\n\\tclippingRectangle _ clipRectangle.\\n\\tcompositionRectangle _ aDisplayPoint extent: compositionRectangle extent.\\n\\t(lastLine == nil or: [lastLine < 1]) ifTrue: [self composeAll].\\n\\tself displayOn: aDisplayMedium lines: (1 to: lastLine)! !\\n\\n!Paragraph methodsFor: 'displaying'!\\ndisplayOn: aDisplayMedium transformation: displayTransformation clippingBox: clipRectangle align: alignmentPoint with: relativePoint rule: ruleInteger fillColor: aForm \\n\\n\\tself\\t\\t\\t\\t\\\"Assumes offset has been set!!!!!!!!!!\\\"\\n\\t displayOn: aDisplayMedium\\n\\t at: (offset \\n\\t\\t\\t+ (displayTransformation applyTo: relativePoint) \\n\\t\\t\\t- alignmentPoint) rounded\\n\\t clippingBox: clipRectangle\\n\\t rule: ruleInteger\\n\\t fillColor: aForm.\\n\\t! !\\n\\n\\n!Paragraph methodsFor: 'indicating'!\\nflash \\n\\t\\\"Complement twice the visible area in which the receiver displays.\\\"\\n\\n\\tDisplay flash: clippingRectangle! !\\n\\n!Paragraph methodsFor: 'indicating'!\\noutline \\n\\t\\\"Display a border around the visible area in which the receiver presents \\n\\tits text.\\\"\\n\\n\\tclippingRectangle bottom <= compositionRectangle bottom\\n\\t ifTrue: [Display \\n\\t\\t\\t\\tborder: (clippingRectangle intersect: compositionRectangle) \\n\\t\\t\\t\\twidth: 2]\\n\\t ifFalse: [Display \\n\\t\\t\\t\\tborder: (clippingRectangle intersect: destinationForm boundingBox)\\n\\t\\t\\t\\twidth: 2].\\n\\t! !\\n\\n\\n!Paragraph methodsFor: 'scrolling'!\\nscrollBy: heightToMove \\n\\t^ self scrollBy: heightToMove withSelectionFrom: nil to: nil! !\\n\\n!Paragraph methodsFor: 'scrolling' stamp: 'hmm 9/16/2000 21:30'!\\nscrollBy: heightToMove withSelectionFrom: startBlock to: stopBlock \\n\\t\\\"Translate the composition rectangle up (dy<0) by heightToMove.\\n\\tRepainting text as necessary, and selection if blocks not nil.\\n\\tReturn true unless scrolling limits have been reached.\\\"\\n\\t| max min amount |\\n\\tmax _ 0 max: \\\"cant scroll up more than dist to (top of) bottom line\\\"\\n\\t\\tcompositionRectangle bottom - textStyle lineGrid - clippingRectangle top.\\n\\tmin _ 0 min: \\\"cant scroll down more than top is above clipRect\\\"\\n\\t\\tcompositionRectangle top - clippingRectangle top.\\n\\tamount _ ((heightToMove truncateTo: textStyle lineGrid) min: max) max: min.\\n\\tamount ~= 0\\n\\t\\tifTrue: [destinationForm deferUpdatesIn: clippingRectangle while: [\\n\\t\\t\\t\\t\\tself scrollUncheckedBy: amount\\n\\t\\t\\t\\t\\t\\twithSelectionFrom: startBlock to: stopBlock].\\n\\t\\t\\t\\t^ true]\\n\\t\\tifFalse: [^ false]! !\\n\\n!Paragraph methodsFor: 'scrolling'!\\nscrollDelta\\n\\t\\\"By comparing this before and after, you know if scrolling happened\\\"\\n\\t^ clippingRectangle top - compositionRectangle top! !\\n\\n!Paragraph methodsFor: 'scrolling'!\\nscrollUncheckedBy: heightToMove withSelectionFrom: startBlock to: stopBlock \\n\\t\\\"Scroll by the given amount. Copy bits where possible, display the rest.\\n\\tIf selection blocks are not nil, then select the newly visible text as well.\\\"\\n\\t| savedClippingRectangle delta |\\n\\tdelta _ 0 @ (0 - heightToMove).\\n\\tcompositionRectangle _ compositionRectangle translateBy: delta.\\n\\tstartBlock == nil ifFalse:\\n\\t\\t[startBlock moveBy: delta.\\n\\t\\tstopBlock moveBy: delta].\\n\\tsavedClippingRectangle _ clippingRectangle.\\n\\tclippingRectangle _ clippingRectangle intersect: Display boundingBox.\\n\\theightToMove abs >= clippingRectangle height\\n\\t ifTrue: \\n\\t\\t[\\\"Entire visible region must be repainted\\\"\\n\\t\\tself displayLines: (1 to: lastLine) affectedRectangle: clippingRectangle]\\n\\t ifFalse:\\n\\t\\t[\\\"Copy bits where possible / display the rest\\\"\\n\\t\\tdestinationForm\\n\\t\\t\\tcopyBits: clippingRectangle from: destinationForm\\n\\t\\t\\tat: clippingRectangle topLeft + delta\\n\\t\\t\\tclippingBox: clippingRectangle\\n\\t\\t\\trule: Form over fillColor: nil.\\n\\t\\t\\\"Set clippingRectangle to 'vacated' area for lines 'pulled' into view.\\\"\\n\\t\\tclippingRectangle _ heightToMove < 0\\n\\t\\t\\tifTrue: \\\"On the top\\\"\\n\\t\\t\\t\\t[clippingRectangle topLeft corner: clippingRectangle topRight + delta]\\n\\t\\t\\tifFalse: \\\"At the bottom\\\"\\n\\t\\t\\t\\t[clippingRectangle bottomLeft + delta corner: clippingRectangle bottomRight].\\n\\t\\tself displayLines: (1 to: lastLine) \\\"Refresh vacated region\\\"\\n\\t\\t\\taffectedRectangle: clippingRectangle].\\n\\tstartBlock == nil ifFalse:\\n\\t\\t[self reverseFrom: startBlock to: stopBlock].\\n\\t\\\"And restore the clippingRectangle to its original value. \\\"\\n\\tclippingRectangle _ savedClippingRectangle! !\\n\\n\\n!Paragraph methodsFor: 'selecting' stamp: 'ar 5/28/2000 12:10'!\\ncaretFormForDepth: depth\\n\\t\\\"Return a caret form for the given depth.\\\"\\n\\t\\\"(Paragraph new caretFormForDepth: Display depth) displayOn: Display at: 0@0 rule: Form reverse\\\"\\n\\n\\t| box f bb map |\\n\\tbox _ CaretForm boundingBox.\\n\\tf _ Form extent: box extent depth: depth.\\n\\tmap _ (Color cachedColormapFrom: CaretForm depth to: depth) copy.\\n\\tmap at: 1 put: (Color transparent pixelValueForDepth: depth).\\n\\tmap at: 2 put: (Color quickHighLight: depth) first. \\\"pixel value for reversing\\\"\\n\\tbb _ BitBlt current toForm: f.\\n\\tbb\\n\\t\\tsourceForm: CaretForm;\\n\\t\\tsourceRect: box;\\n\\t\\tdestOrigin: 0@0;\\n\\t\\tcolorMap: map;\\n \\t\\tcombinationRule: Form over;\\n\\t\\tcopyBits.\\n\\t^ f! !\\n\\n!Paragraph methodsFor: 'selecting' stamp: 'dvf 10/1/2003 13:28'!\\nclickAt: clickPoint for: model controller: aController\\n\\t\\\"Give sensitive text a chance to fire. Display flash: (100@100 extent: 100@100).\\\"\\n\\t| startBlock action range box boxes |\\n\\taction _ false.\\n\\tstartBlock _ self characterBlockAtPoint: clickPoint.\\n\\t(text attributesAt: startBlock stringIndex forStyle: textStyle) \\n\\t\\tdo: [:att | att mayActOnClick ifTrue:\\n\\t\\t\\t\\t[range _ text rangeOf: att startingAt: startBlock stringIndex.\\n\\t\\t\\t\\tboxes _ self selectionRectsFrom: (self characterBlockForIndex: range first) \\n\\t\\t\\t\\t\\t\\t\\tto: (self characterBlockForIndex: range last+1).\\n\\t\\t\\t\\tbox _ boxes detect: [:each | each containsPoint: clickPoint]\\n\\t\\t\\t\\t\\t\\t\\tifNone: [^ action].\\n\\t\\t\\t\\tUtilities awaitMouseUpIn: box repeating: []\\n\\t\\t\\t\\t\\tifSucceed: [aController terminateAndInitializeAround:\\n\\t\\t\\t\\t\\t\\t\\t\\t[(att actOnClickFor: model in: self at: clickPoint editor: aController) ifTrue: [action _ true]]]]].\\n\\t^ action! !\\n\\n!Paragraph methodsFor: 'selecting'!\\nextendSelectionAt: beginBlock endBlock: endBlock \\n\\t\\\"Answer with an Array of two CharacterBlocks that represent the text \\n\\tselection that the user makes.\\\"\\n\\t\\n\\t(self characterBlockAtPoint: Sensor cursorPoint) <= beginBlock\\n\\t\\tifTrue: [^self mouseMovedFrom: beginBlock \\n\\t\\t\\t\\t\\tpivotBlock: endBlock\\n\\t\\t\\t\\t\\tshowingCaret: (beginBlock = endBlock)]\\n\\t\\tifFalse: [^self mouseMovedFrom: endBlock \\n\\t\\t\\t\\t\\tpivotBlock: beginBlock\\n\\t\\t\\t\\t\\tshowingCaret: (beginBlock = endBlock)]\\n! !\\n\\n!Paragraph methodsFor: 'selecting' stamp: 'th 9/19/2002 17:27'!\\nextendSelectionMark: markBlock pointBlock: pointBlock \\n\\t\\\"Answer with an Array of two CharacterBlocks that represent the text \\n\\tselection that the user makes.\\\"\\n\\ttrue \\n\\t\\tifTrue:[^self mouseMovedFrom: pointBlock\\n\\t\\t\\t\\t\\tpivotBlock: markBlock\\n\\t\\t\\t\\t\\tshowingCaret:(pointBlock = markBlock)]\\n\\t\\tifFalse:\\n\\t\\t[\\t| beginBlock endBlock |\\n\\t\\t\\tbeginBlock _ markBlock min: pointBlock.\\n\\t\\t\\tendBlock _ markBlock max: endBlock.\\n\\t\\n\\t\\t\\t(self characterBlockAtPoint: Sensor cursorPoint) <= beginBlock\\n\\t\\t\\t\\tifTrue: [^self mouseMovedFrom: beginBlock \\n\\t\\t\\t\\t\\t\\t\\tpivotBlock: endBlock\\n\\t\\t\\t\\t\\t\\t\\tshowingCaret: (beginBlock = endBlock)]\\n\\t\\t\\t\\tifFalse: [^self mouseMovedFrom: endBlock \\n\\t\\t\\t\\t\\t\\t\\tpivotBlock: beginBlock\\n\\t\\t\\t\\t\\t\\t\\tshowingCaret: (beginBlock = endBlock)]\\n\\t\\t]\\n! !\\n\\n!Paragraph methodsFor: 'selecting' stamp: 'jm 7/1/1999 12:31'!\\nhiliteRect: rect\\n\\n\\t| highlightColor |\\n\\thighlightColor _ Color quickHighLight: destinationForm depth.\\n\\trect ifNotNil: [\\n\\t\\tdestinationForm\\n\\t\\t\\tfill: rect\\n\\t\\t\\trule: Form reverse\\n\\t\\t\\tfillColor: highlightColor.\\n\\t\\t\\\"destinationForm\\n\\t\\t\\tfill: (rect translateBy: 1@1)\\n\\t\\t\\trule: Form reverse\\n\\t\\t\\tfillColor: highlightColor\\\" ].\\n! !\\n\\n!Paragraph methodsFor: 'selecting' stamp: 'jm 7/8/97 12:25'!\\nmouseMovedFrom: beginBlock pivotBlock: pivotBlock showingCaret: caretOn \\n\\t| startBlock stopBlock showingCaret |\\n\\tstopBlock _ startBlock _ beginBlock.\\n\\tshowingCaret _ caretOn.\\n\\t[Sensor redButtonPressed]\\n\\t\\twhileTrue: \\n\\t\\t\\t[stopBlock _ self characterBlockAtPoint: Sensor cursorPoint.\\n\\t\\t\\tstopBlock = startBlock\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[showingCaret\\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[showingCaret _ false.\\n\\t\\t\\t\\t\\t\\t\\tself reverseFrom: pivotBlock to: pivotBlock].\\n\\t\\t\\t((startBlock >= pivotBlock and: [stopBlock >= pivotBlock])\\n\\t\\t\\t\\tor: [startBlock <= pivotBlock and: [stopBlock <= pivotBlock]])\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[self reverseFrom: startBlock to: stopBlock.\\n\\t\\t\\t\\t\\tstartBlock _ stopBlock]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[self reverseFrom: startBlock to: pivotBlock.\\n\\t\\t\\t\\t\\tself reverseFrom: pivotBlock to: stopBlock.\\n\\t\\t\\t\\t\\tstartBlock _ stopBlock].\\n\\t\\t\\t(clippingRectangle containsRect: stopBlock) ifFalse:\\n\\t\\t\\t\\t[stopBlock top < clippingRectangle top\\n\\t\\t\\t\\tifTrue: [self scrollBy: stopBlock top - clippingRectangle top\\n\\t\\t\\t\\t\\t\\twithSelectionFrom: pivotBlock to: stopBlock]\\n\\t\\t\\t\\tifFalse: [self scrollBy: stopBlock bottom + textStyle lineGrid - clippingRectangle bottom\\n\\t\\t\\t\\t\\t\\twithSelectionFrom: pivotBlock to: stopBlock]]]].\\n\\tpivotBlock = stopBlock ifTrue:\\n\\t\\t[showingCaret ifFalse: \\\"restore caret\\\"\\n\\t\\t\\t[self reverseFrom: pivotBlock to: pivotBlock]].\\n\\t^ Array with: pivotBlock with: stopBlock! !\\n\\n!Paragraph methodsFor: 'selecting'!\\nmouseSelect\\n\\t\\\"Answer with an Array of two CharacterBlocks that represent the text \\n\\tselection that the user makes. Return quickly if the button is noticed up\\n\\tto make double-click more responsive.\\\"\\n\\n\\t| pivotBlock startBlock stopBlock origPoint stillDown |\\n\\tstillDown _ Sensor redButtonPressed.\\n\\tpivotBlock _ startBlock _ stopBlock _\\n\\t\\tself characterBlockAtPoint: (origPoint _ Sensor cursorPoint).\\n\\tstillDown _ stillDown and: [Sensor redButtonPressed].\\n\\tself reverseFrom: startBlock to: startBlock.\\n\\t[stillDown and: [Sensor cursorPoint = origPoint]] whileTrue:\\n\\t\\t[stillDown _ Sensor redButtonPressed].\\n\\t(stillDown and: [clippingRectangle containsPoint: Sensor cursorPoint])\\n\\t\\tifFalse: [^Array with: pivotBlock with: stopBlock].\\n\\t^ self mouseMovedFrom: startBlock \\n\\t\\tpivotBlock: pivotBlock\\n\\t\\tshowingCaret: true! !\\n\\n!Paragraph methodsFor: 'selecting'!\\nmouseSelect: clickPoint \\n\\t\\\"Track text selection and answer with an Array of two CharacterBlocks.\\\"\\n\\t| startBlock |\\n\\tstartBlock _ self characterBlockAtPoint: clickPoint.\\n\\tself reverseFrom: startBlock to: startBlock.\\n\\t^ self mouseMovedFrom: startBlock \\n\\t\\tpivotBlock: startBlock\\n\\t\\tshowingCaret: true! !\\n\\n!Paragraph methodsFor: 'selecting'!\\nreverseFrom: characterBlock1 to: characterBlock2 \\n\\t\\\"Reverse area between the two character blocks given as arguments.\\\"\\n\\t| visibleRectangle initialRectangle interiorRectangle finalRectangle lineNo baseline caret |\\n\\tcharacterBlock1 = characterBlock2 ifTrue:\\n\\t\\t[lineNo _ self lineIndexOfCharacterIndex: characterBlock1 stringIndex.\\n\\t\\tbaseline _ lineNo = 0 ifTrue: [textStyle baseline]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [(lines at: lineNo) baseline].\\n\\t\\tcaret _ self caretFormForDepth: Display depth.\\n\\t\\t^ caret \\\"Use a caret to indicate null selection\\\"\\n\\t\\t\\t\\tdisplayOn: destinationForm\\n\\t\\t\\t\\tat: characterBlock1 topLeft + (-3 @ baseline)\\n\\t\\t\\t\\tclippingBox: clippingRectangle\\n\\t\\t\\t\\trule: (false \\\"Display depth>8\\\" ifTrue: [9 \\\"not-reverse\\\"]\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [Form reverse])\\n\\t\\t\\t\\tfillColor: nil].\\n\\tvisibleRectangle _ \\n\\t\\t(clippingRectangle intersect: compositionRectangle)\\n\\t\\t\\t\\\"intersect: destinationForm boundingBox\\\" \\\"not necessary\\\".\\n\\tcharacterBlock1 top = characterBlock2 top\\n\\t\\tifTrue: [characterBlock1 left < characterBlock2 left\\n\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t[initialRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t(characterBlock1 topLeft corner: characterBlock2 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]\\n\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t[initialRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t(characterBlock2 topLeft corner: characterBlock1 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]]\\n\\t\\tifFalse: [characterBlock1 top < characterBlock2 top\\n\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t[initialRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t(characterBlock1 topLeft \\n\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right @ characterBlock1 bottom)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle.\\n\\t\\t\\t\\t\\t\\tcharacterBlock1 bottom = characterBlock2 top\\n\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t[finalRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock2 top \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: characterBlock2 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t\\t[interiorRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock1 bottom\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t@ characterBlock2 top)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle.\\n\\t\\t\\t\\t\\t\\t\\t\\tfinalRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock2 top \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: characterBlock2 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[initialRectangle _ \\n\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock1 top \\n\\t\\t\\t\\t\\t\\t\\tcorner: characterBlock1 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle.\\n\\t\\t\\t\\t\\tcharacterBlock1 top = characterBlock2 bottom\\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[finalRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t(characterBlock2 topLeft \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t@ characterBlock2 bottom)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]\\n\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t[interiorRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock2 bottom \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right @ characterBlock1 top)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle.\\n\\t\\t\\t\\t\\t\\t\\tfinalRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t(characterBlock2 topLeft \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t@ characterBlock2 bottom)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]]].\\n\\tself hiliteRect: initialRectangle.\\n\\tself hiliteRect: interiorRectangle.\\n\\tself hiliteRect: finalRectangle.! !\\n\\n!Paragraph methodsFor: 'selecting' stamp: 'di 12/1/97 04:43'!\\nselectionRectsFrom: characterBlock1 to: characterBlock2 \\n\\t\\\"Return an array of rectangles representing the area between the two character blocks given as arguments.\\\"\\n\\t| visibleRectangle initialRectangle interiorRectangle finalRectangle lineNo baseline |\\n\\tcharacterBlock1 = characterBlock2 ifTrue:\\n\\t\\t[lineNo _ self lineIndexOfCharacterIndex: characterBlock1 stringIndex.\\n\\t\\tbaseline _ lineNo = 0 ifTrue: [textStyle baseline]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [(lines at: lineNo) baseline].\\n\\t\\t^ Array with: (characterBlock1 topLeft extent: 1 @ baseline)].\\n\\tvisibleRectangle _ clippingRectangle intersect: compositionRectangle.\\n\\tcharacterBlock1 top = characterBlock2 top\\n\\t\\tifTrue: [characterBlock1 left < characterBlock2 left\\n\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t[initialRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t(characterBlock1 topLeft corner: characterBlock2 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]\\n\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t[initialRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t(characterBlock2 topLeft corner: characterBlock1 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]]\\n\\t\\tifFalse: [characterBlock1 top < characterBlock2 top\\n\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t[initialRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t(characterBlock1 topLeft \\n\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right @ characterBlock1 bottom)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle.\\n\\t\\t\\t\\t\\t\\tcharacterBlock1 bottom = characterBlock2 top\\n\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t[finalRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock2 top \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: characterBlock2 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t\\t[interiorRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock1 bottom\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t@ characterBlock2 top)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle.\\n\\t\\t\\t\\t\\t\\t\\t\\tfinalRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock2 top \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: characterBlock2 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[initialRectangle _ \\n\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock1 top \\n\\t\\t\\t\\t\\t\\t\\tcorner: characterBlock1 bottomLeft)\\n\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle.\\n\\t\\t\\t\\t\\tcharacterBlock1 top = characterBlock2 bottom\\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[finalRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t(characterBlock2 topLeft \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t@ characterBlock2 bottom)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]\\n\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t[interiorRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t(visibleRectangle left @ characterBlock2 bottom \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right @ characterBlock1 top)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle.\\n\\t\\t\\t\\t\\t\\t\\tfinalRectangle _ \\n\\t\\t\\t\\t\\t\\t\\t\\t(characterBlock2 topLeft \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcorner: visibleRectangle right \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t@ characterBlock2 bottom)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tintersect: visibleRectangle]]].\\n\\t^ (Array with: initialRectangle with: interiorRectangle with: finalRectangle)\\n\\t\\t\\tselect: [:rect | rect notNil]! !\\n\\n\\n!Paragraph methodsFor: 'utilities'!\\nclearVisibleRectangle \\n\\t\\\"Display the area in which the receiver presents its text so that the area \\n\\tis all one tone--in this case, all white.\\\"\\n\\n\\tdestinationForm\\n\\t fill: clippingRectangle\\n\\t rule: rule\\n\\t fillColor: self backgroundColor! !\\n\\n!Paragraph methodsFor: 'utilities'!\\ndeepCopy\\n\\t\\\"Don't want to copy the destForm (Display) or fonts in the TextStyle. 9/13/96 tk\\\"\\n\\n\\t| new |\\n\\tnew _ self copy.\\n\\tnew textStyle: textStyle copy.\\n\\tnew destinationForm: destinationForm.\\n\\tnew lines: lines copy.\\n\\tnew text: text deepCopy.\\n\\t^ new! !\\n\\n!Paragraph methodsFor: 'utilities'!\\ndestinationForm: destForm\\n\\tdestinationForm _ destForm! !\\n\\n!Paragraph methodsFor: 'utilities'!\\nfit\\n\\t\\\"Make the bounding rectangle of the receiver contain all the text without \\n\\tchanging the width of the receiver's composition rectangle.\\\"\\n\\n\\t[(self lineIndexOfTop: clippingRectangle top) = 1]\\n\\t\\twhileFalse: [self scrollBy: (0-1)*textStyle lineGrid].\\n\\tself updateCompositionHeight.\\n\\tclippingRectangle _ clippingRectangle withBottom: compositionRectangle bottom! !\\n\\n!Paragraph methodsFor: 'utilities'!\\nlines: lineArray\\n\\tlines _ lineArray! !\\n\\n!Paragraph methodsFor: 'utilities'!\\nvisibleRectangle \\n\\t\\\"May be less than the clippingRectangle if text ends part way down.\\n\\tAlso some fearful history includes Display intersection;\\n\\tit shouldn't be necessary\\\"\\n\\n\\t^ (clippingRectangle intersect: compositionRectangle)\\n\\t\\tintersect: destinationForm boundingBox! !\\n\\n\\n!Paragraph methodsFor: 'private'!\\nbottomAtLineIndex: lineIndex \\n\\t\\\"Answer the bottom y of given line.\\\"\\n\\t| y |\\n\\ty _ compositionRectangle top.\\n\\tlastLine = 0 ifTrue: [^ y + textStyle lineGrid].\\n\\t1 to: (lineIndex min: lastLine) do:\\n\\t\\t[:i | y _ y + (lines at: i) lineHeight].\\n\\t^ y\\n! !\\n\\n!Paragraph methodsFor: 'private' stamp: 'tk 9/30/96'!\\ncompositionRectangle: compositionRect text: aText style: aTextStyle offset: aPoint\\n\\n\\tcompositionRectangle _ compositionRect copy.\\n\\ttext _ aText.\\n\\ttextStyle _ aTextStyle.\\n\\trule _ DefaultRule.\\n\\tmask _ nil.\\t\\t\\\"was DefaultMask \\\"\\n\\tmarginTabsLevel _ 0.\\n\\tdestinationForm _ Display.\\n\\toffset _ aPoint.\\n\\t^self composeAll! !\\n\\n!Paragraph methodsFor: 'private'!\\ncompositionRectangleDelta\\n\\t\\\"A handy number -- mostly for scrolling.\\\"\\n\\n\\t^compositionRectangle top - clippingRectangle top! !\\n\\n!Paragraph methodsFor: 'private'!\\ndisplayLines: linesInterval \\n\\t^ self displayLines: linesInterval\\n\\t\\taffectedRectangle: self visibleRectangle! !\\n\\n!Paragraph methodsFor: 'private' stamp: 'yo 1/23/2003 22:48'!\\ndisplayLines: linesInterval affectedRectangle: affectedRectangle\\n\\t\\\"This is the first level workhorse in the display portion of the TextForm routines.\\n\\tIt checks to see which lines in the interval are actually visible, has the\\n\\tCharacterScanner display only those, clears out the areas in which display will\\n\\toccur, and clears any space remaining in the visibleRectangle following the space\\n\\toccupied by lastLine.\\\"\\n\\n\\t| lineGrid topY firstLineIndex lastLineIndex lastLineIndexBottom |\\n\\n\\t\\\"Save some time by only displaying visible lines\\\"\\n\\tfirstLineIndex _ self lineIndexOfTop: affectedRectangle top.\\n\\tfirstLineIndex < linesInterval first ifTrue: [firstLineIndex _ linesInterval first].\\n\\tlastLineIndex _ self lineIndexOfTop: affectedRectangle bottom - 1.\\n\\tlastLineIndex > linesInterval last ifTrue:\\n\\t\\t\\t[linesInterval last > lastLine\\n\\t\\t \\t\\tifTrue: [lastLineIndex _ lastLine]\\n\\t\\t \\t\\tifFalse: [lastLineIndex _ linesInterval last]].\\n\\tlastLineIndexBottom _ (self bottomAtLineIndex: lastLineIndex).\\n\\t((Rectangle \\n\\t\\torigin: affectedRectangle left @ (topY _ self topAtLineIndex: firstLineIndex) \\n\\t\\tcorner: affectedRectangle right @ lastLineIndexBottom)\\n\\t intersects: affectedRectangle)\\n\\t\\tifTrue: [ \\\" . . . (skip to clear-below if no lines displayed)\\\"\\n\\t\\t\\t\\tMultiDisplayScanner new\\n\\t\\t\\t\\t\\tdisplayLines: (firstLineIndex to: lastLineIndex)\\n\\t\\t\\t\\t\\tin: self clippedBy: affectedRectangle].\\n\\tlastLineIndex = lastLine ifTrue: \\n\\t\\t [destinationForm \\\"Clear out white space below last line\\\"\\n\\t\\t \\tfill: (affectedRectangle left @ (lastLineIndexBottom max: affectedRectangle top)\\n\\t\\t\\t\\tcorner: affectedRectangle bottomRight)\\n\\t\\t \\trule: rule fillColor: self backgroundColor]! !\\n\\n!Paragraph methodsFor: 'private'!\\ndisplayOn: aDisplayMedium lines: lineInterval\\n\\n\\t| saveDestinationForm |\\n\\tsaveDestinationForm _ destinationForm.\\n\\tdestinationForm _ aDisplayMedium.\\n\\tself displayLines: lineInterval.\\n\\tdestinationForm _ saveDestinationForm! !\\n\\n!Paragraph methodsFor: 'private'!\\nleftMarginForCompositionForLine: lineIndex \\n\\t\\\"Build the left margin for composition of a line. Depends upon\\n\\tmarginTabsLevel and the indent.\\\"\\n\\n\\t| indent |\\n\\tlineIndex = 1\\n\\t\\tifTrue: [indent _ textStyle firstIndent]\\n\\t\\tifFalse: [indent _ textStyle restIndent].\\n\\t^indent + (textStyle leftMarginTabAt: marginTabsLevel)! !\\n\\n!Paragraph methodsFor: 'private' stamp: 'ar 12/15/2001 23:29'!\\nleftMarginForDisplayForLine: lineIndex alignment: alignment\\n\\t\\\"Build the left margin for display of a line. Depends upon\\n\\tleftMarginForComposition, compositionRectangle left and the alignment.\\\"\\n\\n\\t| pad |\\n\\t(alignment = LeftFlush or: [alignment = Justified])\\n\\t\\tifTrue: \\n\\t\\t\\t[^compositionRectangle left \\n\\t\\t\\t\\t+ (self leftMarginForCompositionForLine: lineIndex)].\\n\\t\\\"When called from character location code and entire string has been cut,\\n\\tthere are no valid lines, hence following nil check.\\\"\\n\\t(lineIndex <= lines size and: [(lines at: lineIndex) notNil])\\n\\t\\tifTrue: \\n\\t\\t\\t[pad _ (lines at: lineIndex) paddingWidth]\\n\\t\\tifFalse: \\n\\t\\t\\t[pad _ \\n\\t\\t\\t\\tcompositionRectangle width - textStyle firstIndent - textStyle rightIndent].\\n\\talignment = Centered \\n\\t\\tifTrue: \\n\\t\\t\\t[^compositionRectangle left \\n\\t\\t\\t\\t+ (self leftMarginForCompositionForLine: lineIndex) + (pad // 2)].\\n\\talignment = RightFlush \\n\\t\\tifTrue:\\n\\t\\t\\t[^compositionRectangle left \\n\\t\\t\\t\\t+ (self leftMarginForCompositionForLine: lineIndex) + pad].\\n\\tself error: ['no such alignment']! !\\n\\n!Paragraph methodsFor: 'private'!\\nlineAt: indexInteger put: aTextLineInterval \\n\\t\\\"Store a line, track last, and grow lines if necessary.\\\"\\n\\tindexInteger > lastLine ifTrue: [lastLine _ indexInteger].\\n\\tlastLine > lines size ifTrue: [lines _ lines , (Array new: lines size)].\\n\\t^lines at: indexInteger put: aTextLineInterval! !\\n\\n!Paragraph methodsFor: 'private'!\\nlineIndexOfCharacterIndex: characterIndex \\n\\t\\\"Answer the line index for a given characterIndex.\\\"\\n\\n\\t1 to: lastLine do: \\n\\t\\t[:lineIndex | \\n\\t\\t(lines at: lineIndex) last >= characterIndex ifTrue: [^lineIndex]].\\n\\t^lastLine! !\\n\\n!Paragraph methodsFor: 'private'!\\nlineIndexOfTop: top \\n\\t\\\"Answer the line index at a given top y.\\\"\\n\\t| y line |\\n\\tlastLine = 0 ifTrue: [^ 1].\\n\\ty _ compositionRectangle top.\\n\\t1 to: lastLine do:\\n\\t\\t[:i | line _ lines at: i.\\n\\t\\t(y _ y + line lineHeight) > top ifTrue: [^ i]].\\n\\t^ lastLine\\n! !\\n\\n!Paragraph methodsFor: 'private'!\\nlines\\n\\n\\t^lines! !\\n\\n!Paragraph methodsFor: 'private'!\\nmoveBy: delta\\n\\tcompositionRectangle _ compositionRectangle translateBy: delta.\\n\\tclippingRectangle _ clippingRectangle translateBy: delta.\\n! !\\n\\n!Paragraph methodsFor: 'private'!\\nrightMarginForComposition\\n\\t\\\"Build the right margin for a line. Depends upon compositionRectangle\\n\\twidth, marginTabsLevel, and right indent.\\\"\\n\\n\\t^compositionRectangle width \\n\\t\\t- (textStyle rightMarginTabAt: marginTabsLevel) \\n\\t\\t- textStyle rightIndent! !\\n\\n!Paragraph methodsFor: 'private'!\\nrightMarginForDisplay \\n\\t\\\"Build the right margin for a line. Depends upon compositionRectangle\\n\\trightSide, marginTabsLevel, and right indent.\\\"\\n\\n\\t^compositionRectangle right - \\n\\t\\ttextStyle rightIndent - (textStyle rightMarginTabAt: marginTabsLevel)! !\\n\\n!Paragraph methodsFor: 'private'!\\nsetWithText: aText style: aTextStyle \\n\\t\\\"Set text and adjust bounding rectangles to fit.\\\"\\n\\n\\t| shrink compositionWidth unbounded |\\n\\tunbounded _ Rectangle origin: 0 @ 0 extent: 9999@9999.\\n\\tcompositionWidth _ self\\n\\t\\tsetWithText: aText style: aTextStyle compositionRectangle: unbounded clippingRectangle: unbounded.\\n\\tcompositionRectangle _ compositionRectangle withWidth: compositionWidth.\\n\\tclippingRectangle _ compositionRectangle copy.\\n\\tshrink _ unbounded width - compositionWidth.\\n\\t\\\"Shrink padding widths accordingly\\\"\\n\\t1 to: lastLine do:\\n\\t\\t[:i | (lines at: i) paddingWidth: (lines at: i) paddingWidth - shrink]! !\\n\\n!Paragraph methodsFor: 'private'!\\nsetWithText: aText style: aTextStyle compositionRectangle: compRect clippingRectangle: clipRect \\n\\t\\\"Set text and using supplied parameters. Answer max composition width.\\\"\\n\\n\\tclippingRectangle _ clipRect copy.\\n\\t^self\\n\\t\\tcompositionRectangle: compRect\\n\\t\\ttext: aText\\n\\t\\tstyle: aTextStyle\\n\\t\\toffset: 0 @ 0! !\\n\\n!Paragraph methodsFor: 'private'!\\nsetWithText: aText style: aTextStyle compositionRectangle: compRect clippingRectangle: clipRect foreColor: cf backColor: cb\\n\\t\\\"Set text and using supplied parameters. Answer max composition width.\\\"\\n\\n\\tclippingRectangle _ clipRect copy.\\n\\tself foregroundColor: cf backgroundColor: cb.\\n\\t^ self\\n\\t\\tcompositionRectangle: compRect\\n\\t\\ttext: aText\\n\\t\\tstyle: aTextStyle\\n\\t\\toffset: 0 @ 0! !\\n\\n!Paragraph methodsFor: 'private'!\\ntopAtLineIndex: lineIndex \\n\\t\\\"Answer the top y of given line.\\\"\\n\\t| y |\\n\\ty _ compositionRectangle top.\\n\\tlastLine = 0 ifTrue: [lineIndex > 0 ifTrue: [^ y + textStyle lineGrid]. ^ y].\\n\\t1 to: (lineIndex-1 min: lastLine) do:\\n\\t\\t[:i | y _ y + (lines at: i) lineHeight].\\n\\t^ y\\n! !\\n\\n!Paragraph methodsFor: 'private'!\\ntopAtLineIndex: lineIndex using: otherLines and: otherLastLine\\n\\t\\\"Answer the top y of given line.\\\"\\n\\t| y |\\n\\ty _ compositionRectangle top.\\n\\totherLastLine = 0 ifTrue: [^ y].\\n\\t1 to: (lineIndex-1 min: otherLastLine) do:\\n\\t\\t[:i | y _ y + (otherLines at: i) lineHeight].\\n\\t^ y\\n! !\\n\\n!Paragraph methodsFor: 'private'!\\ntrimLinesTo: lastLineInteger\\n\\n\\t(lastLineInteger + 1 to: lastLine) do: [:i | lines at: i put: nil].\\n\\t(lastLine _ lastLineInteger) < (lines size // 2) \\n\\t\\tifTrue: [lines _ lines copyFrom: 1 to: lines size - (lines size // 2)]! !\\n\\n!Paragraph methodsFor: 'private'!\\nupdateCompositionHeight\\n\\t\\\"Mainly used to insure that intersections with compositionRectangle work.\\\" \\n\\n\\tcompositionRectangle _ compositionRectangle withHeight:\\n\\t\\t(self bottomAtLineIndex: lastLine) - compositionRectangle top.\\n\\t(text size ~= 0 and: [(text at: text size) = CR])\\n\\t\\tifTrue: [compositionRectangle _ compositionRectangle withHeight:\\n\\t\\t\\t\\t\\tcompositionRectangle height + (lines at: lastLine) lineHeight]! !\\n\\n!Paragraph methodsFor: 'private' stamp: 'di 8/30/97 11:14'!\\nwithClippingRectangle: clipRect do: aBlock\\n\\t| saveClip |\\n\\tsaveClip _ clippingRectangle.\\n\\tclippingRectangle _ clipRect.\\n\\t\\taBlock value.\\n\\tclippingRectangle _ saveClip! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nParagraph class\\n\\tinstanceVariableNames: ''!\\n\\n!Paragraph class methodsFor: 'examples' stamp: 'tk 9/30/96'!\\nexample\\n\\t\\\"This simple example illustrates how to display a few lines of text on the screen at the current cursor point. \\n\\tFixed. \\\"\\n\\n\\t| para point |\\n\\tpoint _ Sensor waitButton.\\n\\tpara _ 'This is the first line of characters\\nand this is the second line.' asParagraph.\\n\\tpara displayOn: Display at: point.\\n\\n\\t\\\"Paragraph example\\\"! !\\n\\n\\n!Paragraph class methodsFor: 'instance creation'!\\nnew\\n\\t\\\"Do not allow an uninitialized view. Create with text that has no\\n\\tcharacters.\\\"\\n\\n\\t^self withText: '' asText! !\\n\\n!Paragraph class methodsFor: 'instance creation'!\\nwithText: aText \\n\\t\\\"Answer an instance of me with text set to aText and style set to the \\n\\tsystem's default text style.\\\"\\n\\n\\t^self withText: aText style: DefaultTextStyle copy! !\\n\\n!Paragraph class methodsFor: 'instance creation'!\\nwithText: aText style: aTextStyle \\n\\t\\\"Answer an instance of me with text set to aText and style set to \\n\\taTextStyle.\\\"\\n\\n\\t^super new setWithText: aText style: aTextStyle! !\\n\\n!Paragraph class methodsFor: 'instance creation'!\\nwithText: aText style: aTextStyle compositionRectangle: compRect clippingRectangle: clipRect foreColor: c1 backColor: c2\\n\\t\\\"Answer an instance of me with text set to aText and style set to \\n\\taTextStyle, composition rectangle is compRect and the clipping rectangle \\n\\tis clipRect.\\\"\\n\\t| para |\\n\\tpara _ super new.\\n\\tpara setWithText: aText\\n\\t\\tstyle: aTextStyle\\n\\t\\tcompositionRectangle: compRect\\n\\t\\tclippingRectangle: clipRect\\n\\t\\tforeColor: c1 backColor: c2.\\n\\t^para! !\\nScrollController subclass: #ParagraphEditor\\n\\tinstanceVariableNames: 'paragraph startBlock stopBlock beginTypeInBlock emphasisHere initialText selectionShowing otherInterval lastParentLocation'\\n\\tclassVariableNames: 'ChangeText CmdActions FindText Keyboard ShiftCmdActions UndoInterval UndoMessage UndoParagraph UndoSelection Undone'\\n\\tpoolDictionaries: 'TextConstants'\\n\\tcategory: 'Kernel-ST80 Remnants'!\\n!ParagraphEditor commentStamp: '<historical>' prior: 0!\\nI am a Controller for editing a Paragraph. I am a kind of ScrollController, so that more text can be created for the Paragraph than can be viewed on the screen. Editing messages are sent by issuing commands from a yellow button menu or from keys on the keyboard. My instances keep control as long as the cursor is within the view when the red or yellow mouse button is pressed; they give up control if the blue button is pressed.!\\n\\n\\n!ParagraphEditor methodsFor: 'accessing' stamp: 'tk 4/21/1998 09:55'!\\ninitialText\\n\\t^ initialText! !\\n\\n!ParagraphEditor methodsFor: 'accessing'!\\nreplace: oldInterval with: newText and: selectingBlock \\n\\t\\\"Replace the text in oldInterval with newText and execute selectingBlock to establish the new selection. Create an undoAndReselect:redoAndReselect: undoer to allow perfect undoing.\\\"\\n\\n\\t| undoInterval |\\n\\tundoInterval _ self selectionInterval.\\n\\tundoInterval = oldInterval ifFalse: [self selectInterval: oldInterval].\\n\\tUndoSelection _ self selection.\\n\\tself zapSelectionWith: newText.\\n\\tselectingBlock value.\\n\\totherInterval _ self selectionInterval.\\n\\tself undoer: #undoAndReselect:redoAndReselect: with: undoInterval with: otherInterval! !\\n\\n!ParagraphEditor methodsFor: 'accessing'!\\nreplaceSelectionWith: aText\\n\\t\\\"Remember the selection text in UndoSelection.\\n\\t Deselect, and replace the selection text by aText.\\n\\t Remember the resulting selectionInterval in UndoInterval and PriorInterval.\\n\\t Set up undo to use UndoReplace.\\\"\\n\\n\\tbeginTypeInBlock ~~ nil ifTrue: [^self zapSelectionWith: aText]. \\\"called from old code\\\"\\n\\tUndoSelection _ self selection.\\n\\tself zapSelectionWith: aText.\\n\\tself undoer: #undoReplace! !\\n\\n!ParagraphEditor methodsFor: 'accessing'!\\nsetSearch: aString\\n\\t\\\"Set the FindText and ChangeText to seek aString; except if already seeking aString, leave ChangeText alone so again will repeat last replacement.\\\"\\n\\n\\tFindText string = aString\\n\\t\\tifFalse: [FindText _ ChangeText _ aString asText]! !\\n\\n!ParagraphEditor methodsFor: 'accessing'!\\ntext\\n\\t\\\"Answer the text of the paragraph being edited.\\\"\\n\\n\\t^paragraph text! !\\n\\n!ParagraphEditor methodsFor: 'accessing' stamp: 'jm 3/18/98 20:38'!\\nuserHasEdited\\n\\t\\\"Note that the user has edited my text. Here it is just a noop so that the Character Recognizer won't fail when used with a vanilla ParagrahEditor.\\\"\\n! !\\n\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/19/2002 18:22'!\\nhasCaret\\n\\t^self markBlock = self pointBlock! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/19/2002 18:22'!\\nhasSelection\\n\\t^self hasCaret not! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/17/2002 16:13'!\\nmark\\n\\t^ self markBlock stringIndex! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 10/21/2003 15:49'!\\nmarkBlock\\n\\t^ stopBlock! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 10/21/2003 15:49'!\\nmarkBlock: aCharacterBlock\\n\\tstopBlock _ aCharacterBlock.\\n! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/18/2002 12:31'!\\nmarkIndex\\n\\t^ self markBlock stringIndex! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 10/21/2003 15:49'!\\npointBlock\\n\\t^ startBlock! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 10/21/2003 15:49'!\\npointBlock: aCharacterBlock\\n\\tstartBlock _ aCharacterBlock.\\n! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/18/2002 12:31'!\\npointIndex\\n\\t^ self pointBlock stringIndex! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'yo 7/31/2004 16:27'!\\nselection\\n\\t\\\"Answer the text in the paragraph that is currently selected.\\\"\\n\\n\\t| t |\\n\\tt _ paragraph text copyFrom: self startIndex to: self stopIndex - 1.\\n\\tt string isOctetString ifTrue: [t asOctetStringText].\\n\\t^ t.\\n! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/19/2002 18:10'!\\nselectionAsStream\\n\\t\\\"Answer a ReadStream on the text in the paragraph that is currently \\n\\tselected.\\\"\\n\\n\\t^ReadWriteStream\\n\\t\\ton: paragraph string\\n\\t\\tfrom: self startIndex\\n\\t\\tto: self stopIndex - 1! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/18/2002 16:18'!\\nselectionInterval\\n\\t\\\"Answer the interval that is currently selected.\\\"\\n\\n\\t^self startIndex to: self stopIndex - 1 ! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/17/2002 13:02'!\\nsetMark: anIndex\\n\\tself markBlock: (paragraph characterBlockForIndex: anIndex)\\n! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/17/2002 13:02'!\\nsetPoint: anIndex\\n\\tself pointBlock: (paragraph characterBlockForIndex: anIndex)\\n! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/17/2002 16:10'!\\nstartBlock\\n\\t^ self pointBlock min: self markBlock! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/17/2002 13:10'!\\nstartBlock: aCharacterBlock\\n\\tself markBlock: aCharacterBlock! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/18/2002 14:27'!\\nstartIndex\\n\\t^ self startBlock stringIndex! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/17/2002 16:14'!\\nstopBlock\\n\\t^ self pointBlock max: self markBlock! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/17/2002 13:10'!\\nstopBlock: aCharacterBlock\\n\\tself pointBlock: aCharacterBlock! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/18/2002 14:27'!\\nstopIndex\\n\\t^ self stopBlock stringIndex! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/17/2002 16:23'!\\nunselect\\n\\tself markBlock: self pointBlock copy.! !\\n\\n!ParagraphEditor methodsFor: 'accessing-selection' stamp: 'th 9/19/2002 18:12'!\\nzapSelectionWith: aText\\n\\t\\\"Deselect, and replace the selection text by aText.\\n\\t Remember the resulting selectionInterval in UndoInterval and otherInterval.\\n\\t Do not set up for undo.\\\"\\n\\n\\t| start stop |\\n\\tself deselect.\\n\\tstart _ self startIndex.\\n\\tstop _ self stopIndex.\\n\\t(aText isEmpty and: [stop > start]) ifTrue:\\n\\t\\t[\\\"If deleting, then set emphasisHere from 1st character of the deletion\\\"\\n\\t\\temphasisHere _ (paragraph text attributesAt: start forStyle: paragraph textStyle)\\n\\t\\t\\t\\t\\tselect: [:att | att mayBeExtended]].\\n\\t(start = stop and: [aText size = 0]) ifFalse:\\n\\t\\t[paragraph\\n\\t\\t\\treplaceFrom: start\\n\\t\\t\\tto: stop - 1\\n\\t\\t\\twith: aText\\n\\t\\t\\tdisplaying: true.\\n\\t\\tself computeIntervalFrom: start to: start + aText size - 1.\\n\\t\\tUndoInterval _ otherInterval _ self selectionInterval]! !\\n\\n\\n!ParagraphEditor methodsFor: 'as yet unclassified' stamp: 'dvf 7/28/2003 14:54'!\\nactivateTextActions\\n\\t(paragraph text attributesAt: startBlock stringIndex) \\n\\t\\tdo: [:att | att actOnClickFor: model in: paragraph]! !\\n\\n!ParagraphEditor methodsFor: 'as yet unclassified' stamp: 'BG 6/1/2003 09:43'!\\nofferMenuFromEsc: aStream\\n sensor keyboard. \\\" consume the character \\\"\\n self yellowButtonActivity.\\n ^true \\\"tell the caller that the character was processed \\\"! !\\n\\n!ParagraphEditor methodsFor: 'as yet unclassified' stamp: 'sbw 10/13/1999 22:40'!\\ntotalTextHeight\\n\\n\\t^paragraph boundingBox height! !\\n\\n!ParagraphEditor methodsFor: 'as yet unclassified' stamp: 'sbw 10/13/1999 22:33'!\\nvisibleHeight\\n\\n\\t^paragraph clippingRectangle height! !\\n\\n\\n!ParagraphEditor methodsFor: 'controlling'!\\ncontrolInitialize\\n\\n\\tsuper controlInitialize.\\n\\tself recomputeInterval.\\n\\tself initializeSelection.\\n\\tbeginTypeInBlock _ nil! !\\n\\n!ParagraphEditor methodsFor: 'controlling'!\\ncontrolTerminate\\n\\n\\tself closeTypeIn. \\\"Must call to establish UndoInterval\\\"\\n\\tsuper controlTerminate.\\n\\tself deselect! !\\n\\n!ParagraphEditor methodsFor: 'controlling' stamp: 'sma 3/11/2000 15:17'!\\nnormalActivity\\n\\tself processKeyboard.\\n\\tself processMouseButtons! !\\n\\n\\n!ParagraphEditor methodsFor: 'current selection'!\\ndeselect\\n\\t\\\"If the text selection is visible on the screen, reverse its highlight.\\\"\\n\\n\\tselectionShowing ifTrue: [self reverseSelection]! !\\n\\n!ParagraphEditor methodsFor: 'current selection'!\\ninitializeSelection\\n\\t\\\"Do the initial activity when starting up the receiver. For example, in the \\n\\tParagraphEditor highlight the current selection.\\\"\\n\\n\\tself select! !\\n\\n!ParagraphEditor methodsFor: 'current selection' stamp: 'th 9/20/2002 11:41'!\\nrecomputeInterval\\n\\t\\\"The same characters are selected but their coordinates may have changed.\\\"\\n\\n\\tself computeIntervalFrom: self mark to: self pointIndex - 1! !\\n\\n!ParagraphEditor methodsFor: 'current selection'!\\nrecomputeSelection\\n\\t\\\"Redetermine the selection according to the start and stop block indices; \\n\\tdo not highlight.\\\"\\n\\n\\tself deselect; recomputeInterval! !\\n\\n!ParagraphEditor methodsFor: 'current selection' stamp: 'BG 12/12/2003 12:50'!\\nreverseSelection\\n\\t\\\"Reverse the valence of the current selection highlighting.\\\"\\n\\tselectionShowing _ selectionShowing not.\\n\\tparagraph reverseFrom: self pointBlock to: self markBlock! !\\n\\n!ParagraphEditor methodsFor: 'current selection'!\\nselect\\n\\t\\\"If the text selection is visible on the screen, highlight it.\\\"\\n\\n\\tselectionShowing ifFalse: [self reverseSelection]! !\\n\\n!ParagraphEditor methodsFor: 'current selection' stamp: 'th 9/19/2002 18:47'!\\nselectAndScroll\\n\\t\\\"Scroll until the selection is in the view and then highlight it.\\\"\\n\\t| lineHeight deltaY clippingRectangle endBlock |\\n\\tself select.\\n\\tendBlock _ self stopBlock.\\n\\tlineHeight _ paragraph textStyle lineGrid.\\n\\tclippingRectangle _ paragraph clippingRectangle.\\n\\tdeltaY _ endBlock top - clippingRectangle top.\\n\\tdeltaY >= 0 \\n\\t\\tifTrue: [deltaY _ endBlock bottom - clippingRectangle bottom max: 0].\\n\\t\\t\\t\\t\\t\\t\\\"check if stopIndex below bottom of clippingRectangle\\\"\\n\\tdeltaY ~= 0 \\n\\t\\tifTrue: [self scrollBy: (deltaY abs + lineHeight - 1 truncateTo: lineHeight)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t* deltaY sign]! !\\n\\n!ParagraphEditor methodsFor: 'current selection' stamp: 'th 9/19/2002 18:48'!\\nselectAndScrollToTop\\n\\t\\\"Scroll until the selection is in the view and then highlight it.\\\"\\n\\t| lineHeight deltaY clippingRectangle |\\n\\tself select.\\n\\tlineHeight _ paragraph textStyle lineGrid.\\n\\tclippingRectangle _ paragraph clippingRectangle.\\n\\tdeltaY _ self stopBlock top - clippingRectangle top.\\n\\tdeltaY ~= 0 \\n\\t\\tifTrue: [self scrollBy: (deltaY abs + lineHeight - 1 truncateTo: lineHeight)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t* deltaY sign]! !\\n\\n\\n!ParagraphEditor methodsFor: 'displaying'!\\ndisplay\\n\\t\\\"Redisplay the paragraph.\\\"\\n\\n\\t| selectionState |\\n\\tselectionState _ selectionShowing.\\n\\tself deselect.\\n\\tparagraph foregroundColor: view foregroundColor\\n\\t\\t\\tbackgroundColor: view backgroundColor;\\n\\t\\t\\tdisplayOn: Display.\\n\\tselectionState ifTrue: [self select]! !\\n\\n!ParagraphEditor methodsFor: 'displaying'!\\nflash\\n\\t\\\"Causes the view of the paragraph to complement twice in succession.\\\"\\n\\n\\tparagraph flash! !\\n\\n\\n!ParagraphEditor methodsFor: 'do-its' stamp: 'md 2/13/2006 14:36'!\\ncompileSelectionFor: anObject in: evalContext\\n\\n\\t| methodNode method |\\n\\tmethodNode _ [Compiler new\\n\\t\\tcompileNoPattern: self selectionAsStream\\n\\t\\tin: anObject class\\n\\t\\tcontext: evalContext\\n\\t\\tnotifying: self\\n\\t\\tifFail: [^nil]]\\n\\t\\t\\ton: OutOfScopeNotification\\n\\t\\t\\tdo: [:ex | ex resume: true].\\n\\tmethod _ methodNode generate.\\n\\t^method copyWithTempNames: methodNode tempNames! !\\n\\n!ParagraphEditor methodsFor: 'do-its' stamp: 'di 5/10/1998 21:38'!\\ndoIt\\n\\t\\\"Set the context to include pool vars of the model. Then evaluate.\\\"\\n\\t^ self evaluateSelection.\\n! !\\n\\n!ParagraphEditor methodsFor: 'do-its' stamp: 'gk 3/3/2004 17:15'!\\nevaluateSelection\\n\\t\\\"Treat the current selection as an expression; evaluate it and return the result\\\"\\n\\t| result rcvr ctxt |\\n\\tself lineSelectAndEmptyCheck: [^ ''].\\n\\n\\t(model respondsTo: #doItReceiver) \\n\\t\\tifTrue: [FakeClassPool adopt: model selectedClass. \\\"Include model pool vars if any\\\"\\n\\t\\t\\t\\trcvr _ model doItReceiver.\\n\\t\\t\\t\\tctxt _ model doItContext]\\n\\t\\tifFalse: [rcvr _ ctxt _ nil].\\n\\tresult _ [\\n\\t\\trcvr class evaluatorClass new \\n\\t\\t\\tevaluate: self selectionAsStream\\n\\t\\t\\tin: ctxt\\n\\t\\t\\tto: rcvr\\n\\t\\t\\tnotifying: self\\n\\t\\t\\tifFail: [FakeClassPool adopt: nil. ^ #failedDoit]\\n\\t\\t\\tlogged: true.\\n\\t] \\n\\t\\ton: OutOfScopeNotification \\n\\t\\tdo: [ :ex | ex resume: true].\\n\\tFakeClassPool adopt: nil.\\n\\t^ result! !\\n\\n!ParagraphEditor methodsFor: 'do-its' stamp: 'acg 12/7/1999 07:53'!\\nexploreIt\\n\\t| result |\\n\\tresult _ self evaluateSelection.\\n\\t((result isKindOf: FakeClassPool) or: [result == #failedDoit])\\n\\t\\t\\tifTrue: [view flash]\\n\\t\\t\\tifFalse: [result explore].\\n! !\\n\\n!ParagraphEditor methodsFor: 'do-its' stamp: 'di 9/7/1999 11:25'!\\ninspectIt\\n\\t\\\"1/13/96 sw: minor fixup\\\"\\n\\t| result |\\n\\tresult _ self evaluateSelection.\\n\\t((result isKindOf: FakeClassPool) or: [result == #failedDoit])\\n\\t\\t\\tifTrue: [view flash]\\n\\t\\t\\tifFalse: [result inspect].\\n! !\\n\\n!ParagraphEditor methodsFor: 'do-its' stamp: 'sd 4/16/2003 11:41'!\\nobjectsReferencingIt\\n\\t\\\"Open a list inspector on all objects that reference the object that results when the current selection is evaluated. \\\"\\n\\t| result |\\n\\tself terminateAndInitializeAround: [\\n\\tresult _ self evaluateSelection.\\n\\t((result isKindOf: FakeClassPool) or: [result == #failedDoit])\\n\\t\\tifTrue: [view flash]\\n\\t\\tifFalse: [self systemNavigation\\n\\t\\t\\t\\t\\tbrowseAllObjectReferencesTo: result\\n\\t\\t\\t\\t\\texcept: #()\\n\\t\\t\\t\\t\\tifNone: [:obj | view topView flash]].\\n\\t]! !\\n\\n!ParagraphEditor methodsFor: 'do-its' stamp: 'di 5/10/1998 21:52'!\\nprintIt\\n\\t\\\"Treat the current text selection as an expression; evaluate it. Insert the \\n\\tdescription of the result of evaluation after the selection and then make \\n\\tthis description the new text selection.\\\"\\n\\t| result |\\n\\tresult _ self evaluateSelection.\\n\\t((result isKindOf: FakeClassPool) or: [result == #failedDoit])\\n\\t\\t\\tifTrue: [view flash]\\n\\t\\t\\tifFalse: [self afterSelectionInsertAndSelect: result printString]! !\\n\\n!ParagraphEditor methodsFor: 'do-its' stamp: 'ab 3/23/2005 16:49'!\\ntallyIt\\n\\n\\t^ self tallySelection! !\\n\\n!ParagraphEditor methodsFor: 'do-its' stamp: 'ab 3/23/2005 16:49'!\\ntallySelection\\n\\t\\\"Treat the current selection as an expression; evaluate it and return the time took for this evaluation\\\"\\n\\t| result rcvr ctxt cm v valueAsString |\\n\\tself lineSelectAndEmptyCheck: [^ -1].\\n\\n\\t(model respondsTo: #doItReceiver) \\n\\t\\tifTrue: [FakeClassPool adopt: model selectedClass. \\\"Include model pool vars if any\\\"\\n\\t\\t\\t\\trcvr _ model doItReceiver.\\n\\t\\t\\t\\tctxt _ model doItContext]\\n\\t\\tifFalse: [rcvr _ ctxt _ nil].\\n\\tresult _ [\\n\\t\\tcm := rcvr class evaluatorClass new \\n\\t\\t\\tcompiledMethodFor: self selectionAsStream\\n\\t\\t\\tin: ctxt\\n\\t\\t\\tto: rcvr\\n\\t\\t\\tnotifying: self\\n\\t\\t\\tifFail: [FakeClassPool adopt: nil. ^ #failedDoit]\\n\\t\\t\\tlogged: false.\\n\\t\\tTime millisecondsToRun: \\n\\t\\t\\t[v := cm valueWithReceiver: rcvr arguments: (Array with: ctxt)].\\n\\t] \\n\\t\\ton: OutOfScopeNotification \\n\\t\\tdo: [ :ex | ex resume: true].\\n\\tFakeClassPool adopt: nil.\\n\\n\\t\\\"We do not want to have large result displayed\\\"\\n\\tvalueAsString := v printString.\\n\\t(valueAsString size > 30) ifTrue: [valueAsString := (valueAsString copyFrom: 1 to: 30), '...'].\\n\\tPopUpMenu \\n\\t\\tinform: 'Time to compile and execute: ', result printString, 'ms res: ', valueAsString.\\n! !\\n\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nalign: characterStream \\n\\t\\\"Triggered by Cmd-u; cycle through alignment alternatives. 8/11/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself align.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'hpt 8/5/2004 20:21'!\\nbrowseIt: characterStream \\n\\t\\\"Triggered by Cmd-B; browse the thing represented by the current selection, if plausible. 1/18/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself browseIt.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nbrowseItHere: characterStream \\n\\t\\\"Triggered by Cmd-shift-B; browse the thing represented by the current selection, if plausible, in the receiver's own window. 3/1/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself browseItHere.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'di 9/7/1999 08:40'!\\ncancel: characterStream \\n\\t\\\"Cancel unsubmitted changes. Flushes typeahead. 1/12/96 sw\\n\\t 1/22/96 sw: put in control terminate/init\\\"\\n\\n\\tsensor keyboard.\\n\\tself terminateAndInitializeAround: [self cancel].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'dgd 4/4/2006 15:46'!\\nchangeEmphasis: characterStream \\n\\t\\\"Change the emphasis of the current selection or prepare to\\n\\taccept characters with the change in emphasis. Emphasis\\n\\tchange amounts to a font change. Keeps typeahead.\\\"\\n\\t\\n\\t| keyCode attribute oldAttributes index thisSel colors extras |\\n\\n\\t\\\"control 0..9 -> 0..9\\\"\\n\\tkeyCode := ('0123456789-=' indexOf: sensor keyboard ifAbsent: [1]) - 1.\\n\\n\\toldAttributes := paragraph text attributesAt: self pointIndex forStyle: paragraph textStyle.\\n\\tthisSel := self selection.\\n\\n\\t\\\"Decipher keyCodes for Command 0-9...\\\"\\n\\t(keyCode between: 1 and: 5) ifTrue: [\\n\\t\\tattribute := TextFontChange fontNumber: keyCode\\n\\t].\\n\\n\\tkeyCode = 6 ifTrue: [\\n\\t\\t| labels lines | \\n\\t\\tcolors := #(#black #magenta #red #yellow #green #blue #cyan #white ).\\n\\t\\textras := (self class name = #TextMorphEditor and: [(self morph isKindOf: TextMorphForEditView) not])\\n\\t\\t\\t\\t\\t\\tifTrue: [\\\"not a system window\\\" #()]\\n\\t\\t\\t\\t\\t\\tifFalse: [#('Link to comment of class' 'Link to definition of class' 'Link to hierarchy of class' 'Link to method' )].\\n\\n\\t\\tPreferences noviceMode ifTrue: [\\n\\t\\t\\tlabels := colors , #('choose color...' ).\\n\\t\\t\\tlines := #()\\n\\t\\t]\\n\\t\\tifFalse: [\\n\\t\\t\\tlabels := colors , #('choose color...' 'Do it' 'Print it' ) , extras , #('be a web URL link' 'Edit hidden info' 'Copy hidden info' ).\\n\\t\\t\\tlines := Array with: colors size + 1\\n\\t\\t].\\n\\n\\t\\t\\\"index _ (PopUpMenu labelArray: labels lines: lines) startUp. \\\"\\n\\t\\tindex := UIManager default chooseFrom: labels lines: lines.\\n\\t\\tindex = 0\\n\\t\\t\\tifTrue: [ ^ true].\\n\\t\\t\\t\\n\\t\\tindex <= colors size ifTrue: [\\n\\t\\t\\tattribute := TextColor color: (Color perform: (colors at: index))\\n\\t\\t]\\n\\t\\tifFalse: [\\n\\t\\t\\tindex := index - colors size - 1. \\\"Re-number!!!!!!\\\"\\n\\n\\t\\t\\tindex = 0 ifTrue: [\\n\\t\\t\\t\\tattribute := self chooseColor\\n\\t\\t\\t].\\n\\n\\t\\t\\tindex = 1 ifTrue: [\\n\\t\\t\\t\\tattribute := TextDoIt new.\\n\\t\\t\\t\\tthisSel := attribute analyze: self selection asString\\n\\t\\t\\t].\\n\\n\\t\\t\\tindex = 2 ifTrue: [\\n\\t\\t\\t\\tattribute := TextPrintIt new.\\n\\t\\t\\t\\tthisSel := attribute analyze: self selection asString\\n\\t\\t\\t].\\n\\n\\t\\t\\textras size = 0 & (index > 2) ifTrue: [\\n\\t\\t\\t\\tindex := index + 4 \\\"skip those\\\"\\n\\t\\t\\t].\\n\\n\\t\\t\\tindex = 3 ifTrue: [\\n\\t\\t\\t\\tattribute := TextLink new.\\n\\t\\t\\t\\tthisSel := attribute analyze: self selection asString with: 'Comment'\\n\\t\\t\\t].\\n\\n\\t\\t\\tindex = 4 ifTrue: [\\n\\t\\t\\t\\tattribute := TextLink new.\\n\\t\\t\\t\\tthisSel := attribute analyze: self selection asString with: 'Definition'\\n\\t\\t\\t].\\n\\n\\t\\t\\tindex = 5 ifTrue: [\\n\\t\\t\\t\\tattribute := TextLink new.\\n\\t\\t\\t\\tthisSel := attribute analyze: self selection asString with: 'Hierarchy'\\n\\t\\t\\t].\\n\\n\\t\\t\\tindex = 6 ifTrue: [\\n\\t\\t\\t\\tattribute := TextLink new.\\n\\t\\t\\t\\tthisSel := attribute analyze: self selection asString\\n\\t\\t\\t].\\n\\t\\t\\n\\t\\t\\tindex = 7 ifTrue: [\\n\\t\\t\\t\\tattribute := TextURL new.\\n\\t\\t\\t\\tthisSel := attribute analyze: self selection asString\\n\\t\\t\\t].\\n\\t\\t\\n\\t\\t\\tindex = 8 ifTrue: [\\n\\t\\t\\t\\t\\\"Edit hidden info\\\"\\n\\t\\t\\t\\tthisSel := self hiddenInfo. \\\"includes selection\\\"\\n\\t\\t\\t\\tattribute := TextEmphasis normal\\n\\t\\t\\t].\\n\\n\\t\\t\\tindex = 9 ifTrue: [\\n\\t\\t\\t\\t\\\"Copy hidden info\\\"\\n\\t\\t\\t\\tself copyHiddenInfo.\\n\\t\\t\\t\\t^ true\\n\\t\\t\\t].\\n\\t\\t\\n\\t\\t\\t\\\"no other action\\\"\\n\\t\\t\\tthisSel\\n\\t\\t\\t\\tifNil: [ ^ true ]\\n\\t\\t]\\n\\t].\\n\\n\\t(keyCode between: 7 and: 11) ifTrue: [\\n\\t\\tsensor leftShiftDown ifTrue: [\\n\\t\\t\\tkeyCode = 10 ifTrue: [\\n\\t\\t\\t\\tattribute := TextKern kern: -1\\n\\t\\t\\t].\\n\\t\\t\\tkeyCode = 11 ifTrue: [\\n\\t\\t\\t\\tattribute := TextKern kern: 1\\n\\t\\t\\t]\\n\\t\\t]\\n\\t\\tifFalse: [\\n\\t\\t\\tattribute := TextEmphasis perform: (#(#bold #italic #narrow #underlined #struckOut ) at: keyCode - 6).\\n\\t\\t\\toldAttributes\\n\\t\\t\\t\\t\\t\\tdo: [:att | (att dominates: attribute) ifTrue: [attribute turnOff]]\\n\\t\\t]\\n\\t].\\n\\n\\tkeyCode = 0\\n\\t\\tifTrue: [attribute := TextEmphasis normal].\\n\\n\\tbeginTypeInBlock ~~ nil ifTrue: [\\n\\t\\t\\\"only change emphasisHere while typing\\\"\\n\\t\\tself insertTypeAhead: characterStream.\\n\\t\\temphasisHere := Text addAttribute: attribute toArray: oldAttributes.\\n\\t\\t^ true\\n\\t].\\n\\n\\tself\\n\\t\\treplaceSelectionWith: (thisSel asText addAttribute: attribute).\\n\\t\\t\\n\\t^ true\\n! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'di 5/28/1998 11:58'!\\nchangeLfToCr: characterStream \\n\\t\\\"Replace all LFs by CRs.\\n\\tTriggered by Cmd-U -- useful when getting code from FTP sites\\\"\\n\\t| cr lf |\\n\\tsensor keyboard.\\t\\t\\\"flush the triggering cmd-key character\\\"\\n\\tcr _ Character cr. lf _ Character linefeed.\\n\\tself replaceSelectionWith: (Text fromString:\\n\\t\\t\\t(self selection string collect: [:c | c = lf ifTrue: [cr] ifFalse: [c]])).\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'tk 5/7/2001 09:11'!\\nchooseColor\\n\\t\\\"Make a new Text Color Attribute, let the user pick a color, and return the attribute. This is the non-Morphic version.\\\"\\n\\n\\t^ TextColor color: (Color fromUser)! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'di 9/7/1999 08:31'!\\ncompareToClipboard: characterStream \\n\\t\\\"Compare the receiver to the text on the clipboard. Flushes typeahead. 5/1/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\n\\tself terminateAndInitializeAround: [self compareToClipboard].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'tk 5/7/2001 08:47'!\\ncopyHiddenInfo\\n\\t\\\"In TextLinks, TextDoits, TextColor, and TextURLs, there is hidden\\ninfo. Copy that to the clipboard. You can paste it and see what it is.\\nUsually enclosed in <>.\\\"\\n\\n\\t^ self clipboardTextPut: self hiddenInfo asText! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\ncopySelection: characterStream \\n\\t\\\"Copy the current text selection. Flushes typeahead.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself copySelection.\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\ncut: characterStream \\n\\t\\\"Cut out the current text selection. Flushes typeahead.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself cut.\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'di 9/7/1999 08:23'!\\ndoIt: characterStream \\n\\t\\\"Called when user hits cmd-d. Select the current line, if relevant, then evaluate and execute. 2/1/96 sw.\\n\\t2/29/96 sw: don't call selectLine; it's done by doIt now\\\"\\n\\n\\tsensor keyboard.\\t\\n\\tself terminateAndInitializeAround: [self doIt].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'th 9/20/2002 11:41'!\\nduplicate: characterStream\\n\\t\\\"Paste the current selection over the prior selection, if it is non-overlapping and\\n\\t legal. Flushes typeahead. Undoer & Redoer: undoAndReselect.\\\"\\n\\n\\tsensor keyboard.\\n\\tself closeTypeIn.\\n\\t(self hasSelection and: [self isDisjointFrom: otherInterval])\\n\\t\\tifTrue: \\\"Something to duplicate\\\"\\n\\t\\t\\t[self replace: otherInterval with: self selection and:\\n\\t\\t\\t\\t[self selectAt: self pointIndex]]\\n\\t\\tifFalse:\\n\\t\\t\\t[view flash].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'th 9/19/2002 18:01'!\\nenclose: characterStream\\n\\t\\\"Insert or remove bracket characters around the current selection.\\n\\t Flushes typeahead.\\\"\\n\\n\\t| char left right startIndex stopIndex oldSelection which text |\\n\\tchar _ sensor keyboard.\\n\\tself closeTypeIn.\\n\\tstartIndex _ self startIndex.\\n\\tstopIndex _ self stopIndex.\\n\\toldSelection _ self selection.\\n\\twhich _ '([<{\\\"''' indexOf: char ifAbsent: [ ^true ].\\n\\tleft _ '([<{\\\"''' at: which.\\n\\tright _ ')]>}\\\"''' at: which.\\n\\ttext _ paragraph text.\\n\\t((startIndex > 1 and: [stopIndex <= text size])\\n\\t\\tand:\\n\\t\\t[(text at: startIndex-1) = left and: [(text at: stopIndex) = right]])\\n\\t\\tifTrue:\\n\\t\\t\\t[\\\"already enclosed; strip off brackets\\\"\\n\\t\\t\\tself selectFrom: startIndex-1 to: stopIndex.\\n\\t\\t\\tself replaceSelectionWith: oldSelection]\\n\\t\\tifFalse:\\n\\t\\t\\t[\\\"not enclosed; enclose by matching brackets\\\"\\n\\t\\t\\tself replaceSelectionWith:\\n\\t\\t\\t\\t(Text string: (String with: left), oldSelection string ,(String with: right)\\n\\t\\t\\t\\t\\temphasis: emphasisHere).\\n\\t\\t\\tself selectFrom: startIndex+1 to: stopIndex].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nexchange: characterStream\\n\\t\\\"Exchange the current and prior selections. Keeps typeahead.\\\"\\n\\n\\tsensor keyboard.\\t \\\"Flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself exchange.\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'acg 12/7/1999 07:56'!\\nexploreIt: characterStream \\n\\t\\\"Explore the selection -- invoked via cmd-shift-I. If there is no current selection, use the current line.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself terminateAndInitializeAround: [self exploreIt].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'sw 4/24/2001 12:28'!\\nfileItIn: characterStream \\n\\t\\\"File in the selection; invoked via a keyboard shortcut, -- for now, cmd-shift-G.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself terminateAndInitializeAround: [self fileItIn].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'th 9/18/2002 16:31'!\\nhiddenInfo\\n\\t\\\"In TextLinks, TextDoits, TextColor, and TextURLs, there is hidden info. Return the entire string that was used by Cmd-6 to create this text attribute. Usually enclosed in < >.\\\"\\n\\n\\t| attrList |\\n\\tattrList _ paragraph text attributesAt: (self pointIndex +\\nself markIndex)//2 forStyle: paragraph textStyle.\\n\\tattrList do: [:attr |\\n\\t\\t(attr isKindOf: TextAction) ifTrue:\\n\\t\\t\\t[^ self selection asString, '<', attr info, '>']].\\n\\t\\\"If none of the above\\\"\\n\\tattrList do: [:attr |\\n\\t\\tattr class == TextColor ifTrue:\\n\\t\\t\\t[^ self selection asString, '<', attr color printString, '>']].\\n\\t^ self selection asString, '[No hidden info]'! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nimplementorsOfIt: characterStream \\n\\t\\\"Triggered by Cmd-m; browse implementors of the selector represented by the current selection, if plausible. 2/1/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself implementorsOfIt.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'pk 9/10/2005 22:53'!\\ninOutdent: characterStream delta: delta\\n\\t\\\"Add/remove a tab at the front of every line occupied by the selection. Flushes typeahead. Derived from work by Larry Tesler back in December 1985. Now triggered by Cmd-L and Cmd-R. 2/29/96 sw\\\"\\n\\n\\t| cr realStart realStop lines startLine stopLine start stop adjustStart indentation size numLines inStream newString outStream |\\n\\t\\n\\tsensor keyboard. \\\"Flush typeahead\\\"\\n\\tcr := Character cr.\\n\\n\\t\\\"Operate on entire lines, but remember the real selection for re-highlighting later\\\"\\n\\trealStart := self startIndex.\\n\\trealStop := self stopIndex - 1.\\n\\n\\t\\\"Special case a caret on a line of its own, including weird case at end of paragraph\\\"\\n\\t(realStart > realStop and:\\n\\t\\t\\t\\t[realStart < 2 or: [(paragraph string at: realStart - 1) == cr]])\\n\\t\\tifTrue:\\n\\t\\t\\t[delta < 0\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[view flash]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[self replaceSelectionWith: Character tab asSymbol asText.\\n\\t\\t\\t\\t\\tself selectAt: realStart + 1].\\n\\t\\t\\t^ true].\\n\\n\\tlines := paragraph lines.\\n\\tstartLine := paragraph lineIndexOfCharacterIndex: realStart.\\n\\tstopLine := paragraph lineIndexOfCharacterIndex: (realStart max: realStop).\\n\\tstart := (lines at: startLine) first.\\n\\tstop := (lines at: stopLine) last.\\n\\t\\n\\t\\\"Pin the start of highlighting unless the selection starts a line\\\"\\n\\tadjustStart := realStart > start.\\n\\n\\t\\\"Find the indentation of the least-indented non-blank line; never outdent more\\\"\\n\\tindentation := (startLine to: stopLine) inject: 1000 into:\\n\\t\\t[:m :l |\\n\\t\\tm := m min: (paragraph indentationOfLineIndex: l ifBlank: [:tabs | 1000])].\\t\\t\\t\\n\\n\\tsize := stop + 1 - start.\\n\\tnumLines := stopLine + 1 - startLine.\\n\\tinStream := ReadStream on: paragraph string from: start to: stop.\\n\\n\\tnewString := WideString new: size + ((numLines * delta) max: 0).\\n\\toutStream := ReadWriteStream on: newString.\\n\\n\\t\\\"This subroutine does the actual work\\\"\\n\\tself indent: delta fromStream: inStream toStream: outStream.\\n\\n\\t\\\"Adjust the range that will be highlighted later\\\"\\n\\tadjustStart ifTrue: [realStart := (realStart + delta) max: start].\\n\\trealStop := realStop + outStream position - size.\\n\\n\\t\\\"Prepare for another iteration\\\"\\n\\tindentation := indentation + delta.\\n\\tsize := outStream position.\\n\\tinStream := outStream setFrom: 1 to: size.\\n\\n\\toutStream == nil\\n\\t\\tifTrue: \\t\\\"tried to outdent but some line(s) were already left flush\\\"\\n\\t\\t\\t[view flash]\\n\\t\\tifFalse:\\n\\t\\t\\t[self selectInvisiblyFrom: start to: stop.\\n\\t\\t\\tsize = newString size ifFalse: [newString _ outStream contents].\\n\\t\\t\\tself replaceSelectionWith: newString asText].\\n\\tself selectFrom: realStart to: realStop. \\t\\\"highlight only the original range\\\"\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nindent: characterStream\\n\\t\\\"Add a tab at the front of every line occupied by the selection. Flushes typeahead. Invoked from keyboard via cmd-shift-R. 2/29/96 sw\\\"\\n\\n\\t^ self inOutdent: characterStream delta: 1! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'di 9/7/1999 08:25'!\\ninspectIt: characterStream \\n\\t\\\"Inspect the selection -- invoked via cmd-i. If there is no current selection, use the current line. 1/17/96 sw\\n\\t 2/29/96 sw: don't call selectLine; it's done by inspectIt now\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself terminateAndInitializeAround: [self inspectIt].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'md 1/18/2006 23:42'!\\nmakeCapitalized: characterStream \\n\\t\\\"Force the current selection to be capitalized. Triggered by Cmd-Z.\\\"\\n\\t| prev |\\n\\tsensor keyboard.\\t\\t\\\"Flush the triggering cmd-key character\\\"\\n\\tprev _ $-. \\\"not a letter\\\"\\n\\tself replaceSelectionWith: (Text fromString:\\n\\t\\t\\t(self selection string collect:\\n\\t\\t\\t\\t[:c | prev _ prev isLetter ifTrue: [c asLowercase] ifFalse: [c asUppercase]])).\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'di 5/28/1998 12:00'!\\nmakeLowercase: characterStream \\n\\t\\\"Force the current selection to lowercase. Triggered by Cmd-X.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush the triggering cmd-key character\\\"\\n\\tself replaceSelectionWith: (Text fromString: (self selection string asLowercase)).\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'th 9/18/2002 16:21'!\\nmakeProjectLink: characterStream \\n\\t\\\"\\\"\\n\\n\\t| attribute oldAttributes thisSel |\\n\\t\\n\\tsensor keyboard.\\n\\toldAttributes _ paragraph text attributesAt: self pointIndex forStyle: paragraph textStyle.\\n\\tthisSel _ self selection.\\n\\n\\tattribute _ TextSqkProjectLink new. \\n\\tthisSel _ attribute analyze: self selection asString.\\n\\n\\tthisSel ifNil: [^ true].\\n\\tbeginTypeInBlock ~~ nil\\n\\t\\tifTrue: \\\"only change emphasisHere while typing\\\"\\n\\t\\t\\t[self insertTypeAhead: characterStream.\\n\\t\\t\\temphasisHere _ Text addAttribute: attribute toArray: oldAttributes.\\n\\t\\t\\t^ true].\\n\\tself replaceSelectionWith: (thisSel asText addAttribute: attribute).\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'ls 11/10/2002 12:11'!\\nmakeUppercase: characterStream \\n\\t\\\"Force the current selection to uppercase. Triggered by Cmd-Y.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush the triggering cmd-key character\\\"\\n\\tself replaceSelectionWith: (Text fromString: (self selection string asUppercase)).\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'sw 8/1/97 15:18'!\\nmethodNamesContainingIt: characterStream \\n\\t\\\"Browse methods whose selectors containing the selection in their names\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself methodNamesContainingIt.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'sw 9/9/97 16:44'!\\nmethodStringsContainingIt: characterStream \\n\\t\\\"Invoked from cmd-E -- open a browser on all methods holding string constants containing it. Flushes typeahead. \\\"\\n\\n\\tsensor keyboard.\\t\\n\\tself methodStringsContainingit.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nnoop: characterStream \\n\\t\\\"Unimplemented keyboard command; just ignore it.\\\"\\n\\n\\tsensor keyboard.\\t \\\"flush character\\\"\\n\\t^ true\\n! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'sw 1/19/2000 11:14'!\\nofferFontMenu\\n\\t\\\"Present a menu of available fonts, and if one is chosen, apply it to the current selection. \\n\\tUse only names of Fonts of this paragraph \\\"\\n\\n\\t| aList reply |\\n\\taList _ paragraph textStyle fontNamesWithPointSizes.\\n\\treply _ (SelectionMenu labelList: aList selections: aList) startUp.\\n\\treply ~~ nil ifTrue:\\n\\t\\t[self replaceSelectionWith:\\n\\t\\t\\t(Text string: self selection asString \\n\\t\\t\\t\\tattribute: (TextFontChange fontNumber: (aList indexOf: reply)))] ! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nofferFontMenu: characterStream \\n\\t\\\"The user typed the command key that requests a font change; Offer the font menu. 5/27/96 sw\\n\\t Keeps typeahead. (?? should flush?)\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself offerFontMenu.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\noutdent: characterStream\\n\\t\\\"Remove a tab from the front of every line occupied by the selection. Flushes typeahead. Invoked from keyboard via cmd-shift-L. 2/29/96 sw\\\"\\n\\n\\t^ self inOutdent: characterStream delta: -1! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\npaste: characterStream \\n\\t\\\"Replace the current text selection by the text in the shared buffer.\\n\\t Keeps typeahead.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself paste.\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'th 9/19/2002 18:48'!\\npasteInitials: characterStream \\n\\t\\\"Replace the current text selection by an authorship name/date stamp; invoked by cmd-shift-v, easy way to put an authorship stamp in the comments of an editor.\\n\\t Keeps typeahead.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself replace: self selectionInterval with: (Text fromString: Utilities changeStamp) and: [self selectAt: self stopIndex].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'di 9/7/1999 08:25'!\\nprintIt: characterStream \\n\\t\\\"Print the results of evaluting the selection -- invoked via cmd-p. If there is no current selection, use the current line. 1/17/96 sw\\n\\t 2/29/96 sw: don't call selectLine now, since it's called by doIt\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself terminateAndInitializeAround: [self printIt].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nreferencesToIt: characterStream \\n\\t\\\"Triggered by Cmd-N; browse references to the current selection\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself referencesToIt.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'di 9/7/1999 08:43'!\\nsave: characterStream\\n\\t\\\"Submit the current text. Equivalent to 'accept' 1/18/96 sw\\n\\t Keeps typeahead.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself terminateAndInitializeAround: [self accept].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nsendersOfIt: characterStream \\n\\t\\\"Triggered by Cmd-n; browse implementors of the selector represented by the current selection, if plausible. 2/1/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself sendersOfIt.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'yo 5/27/2004 13:56'!\\nsetEmphasis: emphasisSymbol\\n\\t\\\"Change the emphasis of the current selection.\\\"\\n\\n\\t| oldAttributes attribute |\\n\\toldAttributes _ paragraph text attributesAt: self selectionInterval first forStyle: paragraph textStyle.\\n\\n\\tattribute _ TextEmphasis perform: emphasisSymbol.\\n\\t(emphasisSymbol == #normal) \\n\\t\\tifFalse:\\t[oldAttributes do:\\t\\n\\t\\t\\t[:att | (att dominates: attribute) ifTrue: [attribute turnOff]]].\\n\\tself replaceSelectionWith: (self selection addAttribute: attribute)! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'th 9/18/2002 16:20'!\\nshiftEnclose: characterStream\\n\\t\\\"Insert or remove bracket characters around the current selection.\\n\\t Flushes typeahead.\\\"\\n\\n\\t| char left right startIndex stopIndex oldSelection which text |\\n\\tchar _ sensor keyboard.\\n\\tchar = $9 ifTrue: [ char _ $( ].\\n\\tchar = $, ifTrue: [ char _ $< ].\\n\\tchar = $[ ifTrue: [ char _ ${ ].\\n\\tchar = $' ifTrue: [ char _ $\\\" ].\\n\\tchar asciiValue = 27 ifTrue: [ char _ ${ ].\\t\\\"ctrl-[\\\"\\n\\n\\tself closeTypeIn.\\n\\tstartIndex _ self startIndex.\\n\\tstopIndex _ self stopIndex.\\n\\toldSelection _ self selection.\\n\\twhich _ '([<{\\\"''' indexOf: char ifAbsent: [1].\\n\\tleft _ '([<{\\\"''' at: which.\\n\\tright _ ')]>}\\\"''' at: which.\\n\\ttext _ paragraph text.\\n\\t((startIndex > 1 and: [stopIndex <= text size])\\n\\t\\tand:\\n\\t\\t[(text at: startIndex-1) = left and: [(text at: stopIndex) = right]])\\n\\t\\tifTrue:\\n\\t\\t\\t[\\\"already enclosed; strip off brackets\\\"\\n\\t\\t\\tself selectFrom: startIndex-1 to: stopIndex.\\n\\t\\t\\tself replaceSelectionWith: oldSelection]\\n\\t\\tifFalse:\\n\\t\\t\\t[\\\"not enclosed; enclose by matching brackets\\\"\\n\\t\\t\\tself replaceSelectionWith:\\n\\t\\t\\t\\t(Text string: (String with: left), oldSelection string ,(String with: right)\\n\\t\\t\\t\\t\\temphasis: emphasisHere).\\n\\t\\t\\tself selectFrom: startIndex+1 to: stopIndex].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'di 9/7/1999 08:43'!\\nspawnIt: characterStream\\n\\t\\\"Triggered by Cmd-o; spawn a new code window, if it makes sense.\\\"\\n\\n\\tsensor keyboard.\\n\\tself terminateAndInitializeAround: [self spawn].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'th 9/19/2002 18:00'!\\nswapChars: characterStream \\n\\t\\\"Triggered byCmd-Y;. Swap two characters, either those straddling the insertion point, or the two that comprise the selection. Suggested by Ted Kaehler. \\\"\\n\\n\\t| currentSelection aString chars |\\n\\tsensor keyboard.\\t\\t\\\"flush the triggering cmd-key character\\\"\\n\\t(chars _ self selection) size == 0\\n\\t\\tifTrue:\\n\\t\\t\\t[currentSelection _ self pointIndex.\\n\\t\\t\\tself selectMark: currentSelection - 1 point: currentSelection]\\n\\t\\tifFalse:\\n\\t\\t\\t[chars size == 2\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[view flash. ^ true]\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[currentSelection _ self pointIndex - 1]].\\n\\taString _ self selection string.\\n\\tself replaceSelectionWith: (Text string: aString reversed emphasis: emphasisHere).\\n\\tself selectAt: currentSelection + 1.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'editing keys' stamp: 'sw 11/2/1998 15:50'!\\ntempCommand: characterStream \\n\\t\\\"Experimental. Triggered by Cmd-t; put trial cmd-key commands here to see how they work, before hanging them on their own cmd accelerators.\\\"\\n\\tSensor keyboard.\\n\\tself experimentalCommand.\\n\\t^ true\\n\\n\\t\\\"sensor keyboard.\\n\\tself spawnWorkspace.\\n\\t^ true\\\"! !\\n\\n!ParagraphEditor methodsFor: 'editing keys'!\\nundo: characterStream \\n\\t\\\"Undo the last edit. Keeps typeahead, so undo twice is a full redo.\\\"\\n\\n\\tsensor keyboard. \\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself undo.\\n\\t^true! !\\n\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'nk 6/26/2003 22:02'!\\nexplainAnySel: symbol \\n\\t\\\"Is this any message selector?\\\"\\n\\n\\t| list reply |\\n\\tlist _ self systemNavigation allClassesImplementing: symbol.\\n\\tlist size = 0 ifTrue: [^nil].\\n\\tlist size < 12\\n\\t\\tifTrue: [reply _ ' is a message selector which is defined in these classes ' , list printString]\\n\\t\\tifFalse: [reply _ ' is a message selector which is defined in many classes'].\\n\\t^'\\\"' , symbol , reply , '.\\\"' , '\\\\' withCRs, 'SystemNavigation new browseAllImplementorsOf: #' , symbol! !\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'di 1/30/2002 21:09'!\\nexplainChar: string\\n\\t\\\"Does string start with a special character?\\\"\\n\\n\\t| char |\\n\\tchar _ string at: 1.\\n\\tchar = $. ifTrue: [^'\\\"Period marks the end of a Smalltalk statement. A period in the middle of a number means a decimal point. (The number is an instance of class Float).\\\"'].\\n\\tchar = $' ifTrue: [^'\\\"The characters between two single quotes are made into an instance of class String\\\"'].\\n\\tchar = $\\\" ifTrue: [^'\\\"Double quotes enclose a comment. Smalltalk ignores everything between double quotes.\\\"'].\\n\\tchar = $# ifTrue: [^'\\\"The characters following a hash mark are made into an instance of class Symbol. If parenthesis follow a hash mark, an instance of class Array is made. It contains literal constants.\\\"'].\\n\\t(char = $( or: [char = $)]) ifTrue: [^'\\\"Expressions enclosed in parenthesis are evaluated first\\\"'].\\n\\t(char = $[ or: [char = $]]) ifTrue: [^'\\\"The code inside square brackets is an unevaluated block of code. It becomes an instance of BlockContext and is usually passed as an argument.\\\"'].\\n\\t(char = ${ or: [char = $}]) ifTrue: [^ '\\\"A sequence of expressions separated by periods, when enclosed in curly braces, are evaluated to yield the elements of a new Array\\\"'].\\n\\t(char = $< or: [char = $>]) ifTrue: [^'\\\"<primitive: xx> means that this method is usually preformed directly by the virtual machine. If this method is primitive, its Smalltalk code is executed only when the primitive fails.\\\"'].\\n\\tchar = $^ ifTrue: [^'\\\"Uparrow means return from this method. The value returned is the expression following the ^\\\"'].\\n\\tchar = $| ifTrue: [^'\\\"Vertical bars enclose the names of the temporary variables used in this method. In a block, the vertical bar separates the argument names from the rest of the code.\\\"'].\\n\\tchar = $_ ifTrue: [^'\\\"Left arrow means assignment. The value of the expression after the left arrow is stored into the variable before it.\\\"'].\\n\\tchar = $; ifTrue: [^'\\\"Semicolon means cascading. The message after the semicolon is sent to the same object which received the message before the semicolon.\\\"'].\\n\\tchar = $: ifTrue: [^'\\\"A colon at the end of a keyword means that an argument is expected to follow. Methods which take more than one argument have selectors with more than one keyword. (One keyword, ending with a colon, appears before each argument).', '\\\\\\\\' withCRs, 'A colon before a variable name just inside a block means that the block takes an agrument. (When the block is evaluated, the argument will be assigned to the variable whose name appears after the colon).\\\"'].\\n\\tchar = $$ ifTrue: [^'\\\"The single character following a dollar sign is made into an instance of class Character\\\"'].\\n\\tchar = $- ifTrue: [^'\\\"A minus sign in front of a number means a negative number.\\\"'].\\n\\tchar = $e ifTrue: [^'\\\"An e in the middle of a number means that the exponent follows.\\\"'].\\n\\tchar = $r ifTrue: [^'\\\"An r in the middle of a bunch of digits is an instance of Integer expressed in a certain radix. The digits before the r denote the base and the digits after it express a number in that base.\\\"'].\\n\\tchar = Character space ifTrue: [^'\\\"the space Character\\\"'].\\n\\tchar = Character tab ifTrue: [^'\\\"the tab Character\\\"'].\\n\\tchar = Character cr ifTrue: [^'\\\"the carriage return Character\\\"'].\\n\\t^nil! !\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'nk 6/10/2004 07:02'!\\nexplainClass: symbol \\n\\t\\\"Is symbol a class variable or a pool variable?\\\"\\n\\t| class reply classes |\\n\\t(model respondsTo: #selectedClassOrMetaClass)\\n\\t\\tifFalse: [^ nil].\\n\\t(class _ model selectedClassOrMetaClass) ifNil: [^ nil].\\n\\t\\\"no class is selected\\\"\\n\\t(class isKindOf: Metaclass)\\n\\t\\tifTrue: [class _ class soleInstance].\\n\\tclasses _ (Array with: class)\\n\\t\\t\\t\\t, class allSuperclasses.\\n\\t\\\"class variables\\\"\\n\\treply _ classes detect: [:each | (each classVarNames detect: [:name | symbol = name]\\n\\t\\t\\t\\t\\tifNone: [])\\n\\t\\t\\t\\t\\t~~ nil]\\n\\t\\t\\t\\tifNone: [].\\n\\treply == nil ifFalse: [^ '\\\"is a class variable, defined in class ' , reply printString , '\\\"\\\\' withCRs , 'SystemNavigation new browseAllCallsOn: (' , reply printString , ' classPool associationAt: #' , symbol , ').'].\\n\\t\\\"pool variables\\\"\\n\\tclasses do: [:each | (each sharedPools\\n\\t\\t\\tdetect: [:pool | (pool includesKey: symbol)\\n\\t\\t\\t\\t\\tand: \\n\\t\\t\\t\\t\\t\\t[reply _ pool.\\n\\t\\t\\t\\t\\t\\ttrue]]\\n\\t\\t\\tifNone: [])\\n\\t\\t\\t~~ nil].\\n\\treply\\n\\t\\tifNil: [(Undeclared includesKey: symbol)\\n\\t\\t\\t\\tifTrue: [^ '\\\"is an undeclared variable.' , '\\\"\\\\' withCRs , 'SystemNavigation new browseAllCallsOn: (Undeclared associationAt: #' , symbol , ').']]\\n\\t\\tifNotNil: \\n\\t\\t\\t[classes _ WriteStream on: Array new.\\n\\t\\t\\tself systemNavigation\\n\\t\\t\\t\\tallBehaviorsDo: [:each | (each sharedPools\\n\\t\\t\\t\\t\\t\\tdetect: \\n\\t\\t\\t\\t\\t\\t\\t[:pool | \\n\\t\\t\\t\\t\\t\\t\\tpool == reply]\\n\\t\\t\\t\\t\\t\\tifNone: [])\\n\\t\\t\\t\\t\\t\\t~~ nil ifTrue: [classes nextPut: each]].\\n\\t\\t\\t\\\"Perhaps not print whole list of classes if too long. (unlikely)\\\"\\n\\t\\t\\t^ '\\\"is a pool variable from the pool ' , (Smalltalk keyAtIdentityValue: reply) asString , ', which is used by the following classes ' , classes contents printString , '\\\"\\\\' withCRs , 'SystemNavigation new browseAllCallsOn: (' , (Smalltalk keyAtIdentityValue: reply) asString , ' bindingOf: #' , symbol , ').'].\\n\\t^ nil! !\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'sw 5/3/1998 14:32'!\\nexplainCtxt: symbol \\n\\t\\\"Is symbol a context variable?\\\"\\n\\n\\t| reply classes text cls |\\n\\tsymbol = #nil ifTrue: [reply _ '\\\"is a constant. It is the only instance of class UndefinedObject. nil is the initial value of all variables.\\\"'].\\n\\tsymbol = #true ifTrue: [reply _ '\\\"is a constant. It is the only instance of class True and is the receiver of many control messages.\\\"'].\\n\\tsymbol = #false ifTrue: [reply _ '\\\"is a constant. It is the only instance of class False and is the receiver of many control messages.\\\"'].\\n\\tsymbol = #thisContext ifTrue: [reply _ '\\\"is a context variable. Its value is always the MethodContext which is executing this method.\\\"'].\\n\\t(model respondsTo: #selectedClassOrMetaClass) ifTrue: [\\n\\t\\tcls _ model selectedClassOrMetaClass].\\n\\tcls ifNil: [^ reply].\\t \\\"no class known\\\"\\n\\tsymbol = #self ifTrue: \\n\\t\\t\\t[classes _ cls withAllSubclasses.\\n\\t\\t\\tclasses size > 12\\n\\t\\t\\t\\tifTrue: [text _ cls printString , ' or a subclass']\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[classes _ classes printString.\\n\\t\\t\\t\\t\\ttext _ 'one of these classes' , (classes copyFrom: 4 to: classes size)].\\n\\t\\t\\treply _ '\\\"is the receiver of this message; an instance of ' , text , '\\\"'].\\n\\tsymbol = #super ifTrue: [reply _ '\\\"is just like self. Messages to super are looked up in the superclass (' , cls superclass printString , ')\\\"'].\\n\\t^reply! !\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'tpr 5/29/2003 20:07'!\\nexplainGlobal: symbol \\n\\t\\\"Is symbol a global variable?\\\"\\n\\t| reply classes |\\n\\treply _ Smalltalk at: symbol ifAbsent: [^nil].\\n\\t(reply class == Dictionary or:[reply isKindOf: SharedPool class])\\n\\t\\tifTrue: \\n\\t\\t\\t[classes _ Set new.\\n\\t\\t\\tself systemNavigation allBehaviorsDo: [:each | (each sharedPools detect: [:pool | pool == reply]\\n\\t\\t\\t\\t\\tifNone: [])\\n\\t\\t\\t\\t\\t~~ nil ifTrue: [classes add: each]].\\n\\t\\t\\tclasses _ classes printString.\\n\\t\\t\\t^'\\\"is a global variable. It is a pool which is used by the following classes ' , (classes allButFirst: 5) , '\\\"'].\\n\\t(reply isKindOf: Behavior)\\n\\t\\tifTrue: [^'\\\"is a global variable. ' , symbol , ' is a class in category ', reply category,\\n\\t\\t\\t'.\\\"', '\\\\' withCRs, 'Browser newOnClass: ' , symbol , '.'].\\n\\tsymbol == #Smalltalk ifTrue: [^'\\\"is a global. Smalltalk is the only instance of SystemDictionary and holds all global variables.\\\"'].\\n\\t^'\\\"is a global variable. ' , symbol , ' is ' , reply printString , '\\\"'! !\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'tpr 5/12/2004 16:22'!\\nexplainInst: string \\n\\t\\\"Is string an instance variable of this class?\\\"\\n\\t| classes cls |\\n\\n\\t(model respondsTo: #selectedClassOrMetaClass) ifTrue: [\\n\\t\\tcls _ model selectedClassOrMetaClass].\\n\\tcls ifNil: [^ nil].\\t \\\"no class known\\\"\\n\\tclasses _ (Array with: cls)\\n\\t\\t\\t\\t, cls allSuperclasses.\\n\\tclasses _ classes detect: [:each | (each instVarNames\\n\\t\\t\\tdetect: [:name | name = string] ifNone: [])\\n\\t\\t\\t~~ nil] ifNone: [^nil].\\n\\tclasses _ classes printString.\\n\\t^ '\\\"is an instance variable of the receiver; defined in class ' , classes , \\n\\t\\t'\\\"\\\\' withCRs , classes , ' systemNavigation browseAllAccessesTo: ''' , string , ''' from: ', classes, '.'! !\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'nb 5/6/2003 16:54'!\\nexplainMySel: symbol \\n\\t\\\"Is symbol the selector of this method? Is it sent by this method? If \\n\\tnot, then expalin will call (explainPartSel:) to see if it is a fragment of a \\n\\tselector sent here. If not, explain will call (explainAnySel:) to catch any \\n\\tselector. \\\"\\n\\n\\t| lits classes msg |\\n\\t(model respondsTo: #selectedMessageName) ifFalse: [^ nil].\\n\\t(msg _ model selectedMessageName) ifNil: [^nil].\\t\\\"not in a message\\\"\\n\\tclasses _ self systemNavigation allClassesImplementing: symbol.\\n\\tclasses size > 12\\n\\t\\tifTrue: [classes _ 'many classes']\\n\\t\\tifFalse: [classes _ 'these classes ' , classes printString].\\n\\tmsg = symbol\\n\\t\\tifTrue: [^ '\\\"' , symbol , ' is the selector of this very method!! It is defined in ',\\n\\t\\t\\tclasses , '. To see the other definitions, go to the message list pane, get the menu from the top of the scroll bar, and select ''implementors of...''.\\\"']\\n\\t\\tifFalse: \\n\\t\\t\\t[lits _ (model selectedClassOrMetaClass compiledMethodAt:\\n\\t\\t\\t\\tmsg) messages.\\n\\t\\t\\t(lits detect: [:each | each == symbol]\\n\\t\\t\\t\\tifNone: [])\\n\\t\\t\\t\\t== nil ifTrue: [^nil].\\n\\t\\t\\t^ '\\\"' , symbol , ' is a message selector which is defined in ', classes , '. To see the definitions, go to the message list pane, get the menu from the top of the scroll bar, and select ''implementors of...''.\\\"'].! !\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'apb 1/5/2000 16:56'!\\nexplainNumber: string \\n\\t\\\"Is string a Number?\\\"\\n\\n\\t| strm c |\\n\\t(c _ string at: 1) isDigit ifFalse: [(c = $- and: [string size > 1 and: [(string at: 2) isDigit]])\\n\\t\\t\\tifFalse: [^nil]].\\n\\tstrm _ ReadStream on: string.\\n\\tc _ Number readFrom: strm.\\n\\tstrm atEnd ifFalse: [^nil].\\n\\tc printString = string\\n\\t\\tifTrue: [^'\\\"' , string , ' is a ' , c class name , '\\\"']\\n\\t\\tifFalse: [^'\\\"' , string , ' (= ' , c printString , ') is a ' , c class name , '\\\"']! !\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'nb 5/6/2003 16:54'!\\nexplainPartSel: string \\n\\t\\\"Is this a fragment of a multiple-argument selector sent in this method?\\\"\\n\\t| lits whole reply classes s msg |\\n\\n\\t(model respondsTo: #selectedMessageName) ifFalse: [^ nil].\\n\\t(msg _ model selectedMessageName) ifNil: [^ nil]. \\\"not in a message\\\"\\n\\tstring last == $: ifFalse: [^ nil].\\n\\t\\\"Name of this method\\\"\\n\\tlits _ Array with: msg.\\n\\t(whole _ lits detect: [:each | (each keywords detect: [:frag | frag = string]\\n\\t\\t\\t\\t\\tifNone: []) ~~ nil]\\n\\t\\t\\t\\tifNone: []) ~~ nil\\n\\t\\tifTrue: [reply _ ', which is the selector of this very method!!'.\\n\\t\\t\\ts _ '. To see the other definitions, go to the message list pane, get the menu from the top of the scroll bar, and select ''implementors of...''.\\\"']\\n\\t\\tifFalse: \\n\\t\\t\\t[\\\"Selectors called from this method\\\"\\n\\t\\t\\tlits _ (model selectedClassOrMetaClass compiledMethodAt:\\n\\t\\t\\t\\tmsg) messages.\\n\\t\\t\\t(whole _ lits detect: [:each | (each keywords detect: [:frag | frag = string]\\n\\t\\t\\t\\t\\t\\t\\tifNone: []) ~~ nil]\\n\\t\\t\\t\\t\\t\\tifNone: []) ~~ nil\\n\\t\\t\\t\\tifFalse: [string = 'primitive:'\\n\\t\\t\\t\\t\\tifTrue: [^self explainChar: '<']\\n\\t\\t\\t\\t\\tifFalse: [^nil]].\\n\\t\\t\\treply _ '.'.\\n\\t\\t\\ts _ '. To see the definitions, go to the message list pane, get the menu from the top of the scroll bar, and select ''implementors of...''.\\\"'].\\n\\tclasses _ self systemNavigation allClassesImplementing: whole.\\n\\tclasses size > 12\\n\\t\\tifTrue: [classes _ 'many classes']\\n\\t\\tifFalse: [classes _ 'these classes ' , classes printString].\\n\\t^ '\\\"' , string , ' is one part of the message selector ' , whole, reply , ' It is defined in ' , classes , s! !\\n\\n!ParagraphEditor methodsFor: 'explain'!\\nexplainScan: string \\n\\t\\\"Remove beginning and trailing space, tab, cr.\\n\\t 1/15/96 sw: copied intact from BrowserCodeController\\\"\\n\\n\\t| c beg end |\\n\\tbeg _ 1.\\n\\tend _ string size.\\n\\t\\n\\t[beg = end ifTrue: [^string copyFrom: 1 to: 1].\\n\\t\\\"if all blank, tell about the first\\\"\\n\\tc _ string at: beg.\\n\\tc = Character space or: [c = Character tab or: [c = Character cr]]]\\n\\t\\twhileTrue: [beg _ beg + 1].\\n\\t\\n\\t[c _ string at: end.\\n\\tc = Character space or: [c = Character tab or: [c = Character cr]]]\\n\\t\\twhileTrue: [end _ end - 1].\\n\\t^string copyFrom: beg to: end\\t\\\"Return purely visible characters\\\"! !\\n\\n!ParagraphEditor methodsFor: 'explain' stamp: 'tk 4/1/98 14:19'!\\nexplainTemp: string \\n\\t\\\"Is string the name of a temporary variable (or block argument variable)?\\\"\\n\\n\\t| selectedClass tempNames i reply methodNode method msg |\\n\\t(model respondsTo: #selectedMessageName) ifFalse: [^ nil].\\n\\t(msg _ model selectedMessageName) ifNil: [^nil].\\t\\\"not in a message\\\"\\n\\tselectedClass _ model selectedClassOrMetaClass.\\n\\ttempNames _ selectedClass parserClass new \\n\\t\\t\\tparseArgsAndTemps: model selectedMessage notifying: nil.\\n\\tmethod _ selectedClass compiledMethodAt: msg.\\n\\t(i _ tempNames findFirst: [:each | each = string]) = 0 ifTrue: [\\n\\t\\t(method numTemps > tempNames size)\\n\\t\\t\\tifTrue: \\n\\t\\t\\t\\t[\\\"It must be an undeclared block argument temporary\\\"\\n\\t\\t\\t\\tmethodNode _ selectedClass compilerClass new\\n\\t\\t\\t\\t\\t\\t\\tparse: model selectedMessage\\n\\t\\t\\t\\t\\t\\t\\tin: selectedClass\\n\\t\\t\\t\\t\\t\\t\\tnotifying: nil.\\n\\t\\t\\t\\ttempNames _ methodNode tempNames]\\n\\t\\t\\tifFalse: [^nil]].\\n\\t(i _ tempNames findFirst: [:each | each = string]) > 0 ifTrue: [i > method numArgs\\n\\t\\t\\tifTrue: [reply _ '\\\"is a temporary variable in this method\\\"']\\n\\t\\t\\tifFalse: [reply _ '\\\"is an argument to this method\\\"']].\\n\\t^reply! !\\n\\n\\n!ParagraphEditor methodsFor: 'initialize-release'!\\nchangeParagraph: aParagraph \\n\\t\\\"Install aParagraph as the one to be edited by the receiver.\\\"\\n\\n\\tUndoParagraph == paragraph ifTrue: [UndoParagraph _ nil].\\n\\tparagraph _ aParagraph.\\n\\tself resetState! !\\n\\n!ParagraphEditor methodsFor: 'initialize-release' stamp: 'th 10/21/2003 15:49'!\\nresetState \\n\\t\\\"Establish the initial conditions for editing the paragraph: place caret \\n\\tbefore first character, set the emphasis to that of the first character,\\n\\tand save the paragraph for purposes of canceling.\\\"\\n\\n\\tstopBlock _ paragraph defaultCharacterBlock.\\n\\tself pointBlock: stopBlock copy.\\n\\tbeginTypeInBlock _ nil.\\n\\tUndoInterval _ otherInterval _ 1 to: 0.\\n\\tself setEmphasisHere.\\n\\tselectionShowing _ false.\\n\\tinitialText _ paragraph text copy! !\\n\\n!ParagraphEditor methodsFor: 'initialize-release' stamp: 'di 5/15/2000 13:51'!\\nstateArray\\n\\t^ {ChangeText.\\n\\t\\tFindText.\\n\\t\\tUndoInterval.\\n\\t\\tUndoMessage.\\n\\t\\tUndoParagraph.\\n\\t\\tUndoSelection.\\n\\t\\tUndone.\\n\\t\\tself selectionInterval.\\n\\t\\tself startOfTyping.\\n\\t\\temphasisHere}! !\\n\\n!ParagraphEditor methodsFor: 'initialize-release' stamp: 'di 10/5/1998 17:03'!\\nstateArrayPut: stateArray\\n\\t| sel |\\n\\tChangeText _ stateArray at: 1.\\n\\tFindText _ stateArray at: 2.\\n\\tUndoInterval _ stateArray at: 3.\\n\\tUndoMessage _ stateArray at: 4.\\n\\tUndoParagraph _ stateArray at: 5.\\n\\tUndoSelection _ stateArray at: 6.\\n\\tUndone _ stateArray at: 7.\\n\\tsel _ stateArray at: 8.\\n\\tself selectFrom: sel first to: sel last.\\n\\tbeginTypeInBlock _ stateArray at: 9.\\n\\temphasisHere _ stateArray at: 10.! !\\n\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'jm 5/3/1998 19:19'!\\naccept\\n\\t\\\"Save the current text of the text being edited as the current acceptable version for purposes of canceling.\\\"\\n\\n\\tinitialText _ paragraph text copy.\\n! !\\n\\n!ParagraphEditor methodsFor: 'menu messages'!\\nagain\\n\\t\\\"Text substitution. If the left shift key is down, the substitution is made \\n\\tthroughout the entire Paragraph. Otherwise, only the next possible \\n\\tsubstitution is made.\\n\\tUndoer & Redoer: #undoAgain:andReselect:typedKey:.\\\"\\n\\n\\t\\\"If last command was also 'again', use same keys as before\\\"\\n\\tself againOrSame: (UndoMessage sends: #undoAgain:andReselect:typedKey:)! !\\n\\n!ParagraphEditor methodsFor: 'menu messages'!\\nalign\\n\\t\\\"Align text according to the next greater alignment value--cycling among \\n\\tleft flush, right flush, center, justified. No effect on the undoability of the pre\\n\\tpreceding command.\\\"\\n\\n\\tparagraph toggleAlignment.\\n\\tparagraph displayOn: Display.\\n\\tself recomputeInterval! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'md 8/2/2005 20:53'!\\nbrowseClassFromIt\\n\\t\\\"Launch a browser for the class indicated by the current selection. \\n\\tIf multiple classes matching the selection exist, let the user choose among them.\\\"\\n\\t| aBrow aClass |\\n\\tself\\n\\t\\tlineSelectAndEmptyCheck: [^ self].\\n\\taClass := Utilities\\n\\t\\t\\t\\tclassFromPattern: (self selection string copyWithout: Character cr)\\n\\t\\t\\t\\twithCaption: 'choose a class to browse...'.\\n\\taClass\\n\\t\\tifNil: [^ view flash].\\n\\tself\\n\\t\\tterminateAndInitializeAround: \\n\\t\\t\\t[aBrow := SystemBrowser default new.\\n\\t\\t\\taBrow setClass: aClass selector: nil.\\n\\t\\t\\taBrow class\\n\\t\\t\\t\\topenBrowserView: (aBrow openEditString: nil) label: 'System Browser'].! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'pmm 7/6/2006 20:50'!\\nbrowseIt\\n\\t\\\"Launch a browser for the current selection, if appropriate\\\"\\n\\n\\t| aSymbol anEntry |\\n\\tself flag: #yoCharCases.\\n\\n\\tPreferences alternativeBrowseIt ifTrue: [^ self browseClassFromIt].\\n\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\t(aSymbol _ self selectedSymbol) isNil ifTrue: [^ view flash].\\n\\n\\tself terminateAndInitializeAround:\\n\\t\\t[aSymbol first isUppercase\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[anEntry _ (Smalltalk\\n\\t\\t\\t\\t\\tat: aSymbol\\n\\t\\t\\t\\t\\tifAbsent:\\n\\t\\t\\t\\t\\t\\t[ self systemNavigation browseAllImplementorsOf: aSymbol.\\n\\t\\t\\t\\t\\t\\t^ nil]).\\n\\t\\t\\t\\tanEntry isNil ifTrue: [^ view flash].\\n\\t\\t\\t\\t(anEntry isBehavior or: [ anEntry isTrait ])\\n\\t\\t\\t\\t\\tifFalse: [ anEntry := anEntry class ].\\n\\t\\t\\t\\tToolSet browse: anEntry selector: nil.\\n\\t\\t] ifFalse:[ self systemNavigation browseAllImplementorsOf: aSymbol]]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sw 1/15/98 12:57'!\\ncancel \\n\\t\\\"Restore the text of the paragraph to be the text saved since initialization \\n\\tor the last accept. Undoer & Redoer: undoAndReselect:redoAndReselect:.\\n\\tThis used to call controlTerminate and controlInitialize but this seemed illogical.\\n\\tSure enough, nobody overrode them who had cancel in the menu, and if\\n\\tanybody really cared they could override cancel.\\\"\\n\\n\\tUndoSelection _ paragraph text.\\n\\tself undoer: #undoAndReselect:redoAndReselect: with: self selectionInterval with: (1 to: 0).\\n\\tview ifNotNil: [view clearInside].\\n\\tself changeParagraph: (paragraph text: initialText).\\n\\tUndoParagraph _ paragraph.\\n\\totherInterval _ UndoInterval _ 1 to: initialText size. \\\"so undo will replace all\\\"\\n\\tparagraph displayOn: Display.\\n\\tself selectAt: 1.\\n\\tself scrollToTop\\n! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'yo 2/17/2005 17:53'!\\nchangeAlignment\\n\\t| aList reply |\\n\\taList _ #(leftFlush centered justified rightFlush).\\n\\treply _ (SelectionMenu labelList: (aList collect: [:t | t translated]) selections: aList) startUp.\\n\\treply ifNil:[^self].\\n\\tself setAlignment: reply.\\n\\tparagraph composeAll.\\n\\tself recomputeSelection.\\n\\tself mvcRedisplay.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'yo 3/14/2005 13:03'!\\nchangeEmphasis\\n\\t| aList reply |\\n\\taList _ #(normal bold italic narrow underlined struckOut).\\n\\treply _ (SelectionMenu labelList: (aList collect: [:t | t translated]) selections: aList) startUp.\\n\\treply ~~ nil ifTrue:\\n\\t\\t[self setEmphasis: reply.\\n\\t\\tparagraph composeAll.\\n\\t\\tself recomputeSelection.\\n\\t\\tself mvcRedisplay].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'fc 2/19/2004 22:09'!\\nchangeEmphasisOrAlignment\\n\\t| aList reply |\\n\\taList _ #(normal bold italic narrow underlined struckOut leftFlush centered rightFlush justified).\\n\\treply _ (SelectionMenu labelList: aList lines: #(6) selections: aList) startUp.\\n\\treply ~~ nil ifTrue:\\n\\t\\t[(#(leftFlush centered rightFlush justified) includes: reply)\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[paragraph perform: reply.\\n\\t\\t\\t\\tself recomputeInterval]\\n\\t\\t\\tifFalse:\\n\\t\\t\\t\\t[self setEmphasis: reply.\\n\\t\\t\\t\\tparagraph composeAll.\\n\\t\\t\\t\\tself recomputeSelection.\\n\\t\\t\\t\\tself mvcRedisplay]].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'md 10/22/2003 15:27'!\\nchangeStyle\\n\\t\\\"Let user change styles for the current text pane \\n\\t Moved from experimentalCommand to its own method \\\"\\n\\n\\t| aList reply style |\\n\\taList _ StrikeFont actualFamilyNames.\\n\\taList addFirst: 'DefaultTextStyle'.\\n\\treply _ (SelectionMenu labelList: aList lines: #(1) selections: aList) startUp.\\n\\treply ifNotNil:\\n\\t\\t[(style _ TextStyle named: reply) ifNil: [Beeper beep. ^ true].\\n\\t\\tparagraph textStyle: style copy.\\n\\t\\tparagraph composeAll.\\n\\t\\tself recomputeSelection.\\n\\t\\tself mvcRedisplay].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'RAA 3/15/2001 12:10'!\\nchangeStyleTo: aNewStyle\\n\\n\\tparagraph textStyle: aNewStyle.\\n\\tparagraph composeAll.\\n\\tself recomputeSelection.\\n! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sw 9/27/1999 11:54'!\\nchooseAlignment\\n\\tself changeAlignment! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sd 4/15/2003 22:40'!\\nclassCommentsContainingIt\\n\\t\\\"Open a browser class comments which contain the current selection somewhere in them.\\\"\\n\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\tself terminateAndInitializeAround: [\\n\\t\\tself systemNavigation browseClassCommentsWithString: self selection string]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'dvf 8/23/2003 11:51'!\\nclassNamesContainingIt\\n\\t\\\"Open a browser on classes whose names contain the selected string\\\"\\n\\n\\tself lineSelectAndEmptyCheck: [^self].\\n\\tself systemNavigation \\n\\t\\tbrowseClassesWithNamesContaining: self selection string\\n\\t\\tcaseSensitive: Sensor leftShiftDown! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'ar 1/15/2001 18:37'!\\nclipboardText\\n\\n\\t^ Clipboard clipboardText! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'ar 1/15/2001 18:38'!\\nclipboardText: text\\n\\n\\t^ Clipboard clipboardText: text! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'ar 1/15/2001 18:38'!\\nclipboardTextPut: text\\n\\n\\t^ Clipboard clipboardText: text! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'di 11/23/1998 15:21'!\\ncompareToClipboard\\n\\t\\\"Check to see if whether the receiver's text is the same as the text currently on the clipboard, and inform the user.\\\"\\n\\t| s1 s2 |\\n\\ts1 _ self clipboardText string.\\n\\ts2 _ paragraph text string.\\n\\ts1 = s2 ifTrue: [^ self inform: 'Exact match'].\\n\\n\\t(StringHolder new textContents:\\n\\t\\t(TextDiffBuilder buildDisplayPatchFrom: s1 to: s2))\\n\\t\\topenLabel: 'Comparison to Clipboard Text'! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sw 8/1/97 15:09'!\\ncopySelection\\n\\t\\\"Copy the current selection and store it in the paste buffer, unless a caret. Undoer & Redoer: undoCutCopy\\\"\\n\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\n\\t\\\"Simulate 'substitute: self selection' without locking the controller\\\"\\n\\tUndoSelection _ self selection.\\n\\tself undoer: #undoCutCopy: with: self clipboardText.\\n\\tUndoInterval _ self selectionInterval.\\n\\tself clipboardTextPut: UndoSelection! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sw 8/1/97 16:33'!\\ncut\\n\\t\\\"Cut out the current selection and redisplay the paragraph if necessary. Undoer & Redoer: undoCutCopy:\\\"\\n\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\n\\tself replaceSelectionWith: self nullText. \\n\\tself undoer: #undoCutCopy: with: self clipboardText.\\n\\tself clipboardTextPut: UndoSelection! !\\n\\n!ParagraphEditor methodsFor: 'menu messages'!\\nexchange\\n\\t\\\"See comment in exchangeWith:\\\"\\n\\n\\tself exchangeWith: otherInterval! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sma 5/28/2000 09:34'!\\nexperimentalCommand\\n\\t\\\"Use for experimental command-key implementation. Using this, \\n\\tyou can try things out without forever needing to reinitialize the \\n\\tParagraphEditor.\\\"\\n\\n\\tself prettyPrint.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'ls 10/10/1999\\n11:36'!\\nexplain\\n\\t\\\"Try to shed some light on what kind of entity the current selection\\nis. \\n\\tThe selection must be a single token or construct. Insert the answer\\nafter \\n\\tthe selection. Send private messages whose names begin with 'explain' \\n\\tthat return a string if they recognize the selection, else nil.\\\"\\n\\n\\t| string tiVars cgVars selectors delimitors numbers sorry reply symbol\\n|\\nCursor execute showWhile: \\n\\t\\t\\t[sorry _ '\\\"Sorry, I can''t explain that. Please select a single\\ntoken, construct, or special character.'.\\n\\t\\t\\tsorry _ sorry , (view canDiscardEdits\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [' Also, please cancel or accept.\\\"']\\n\\t\\t\\t\\t\\t\\t\\tifTrue: ['\\\"']).\\n\\t\\t\\t(string _ self selection asString) isEmpty\\n\\t\\t\\t\\tifTrue: [reply _ '']\\n\\t\\t\\t\\tifFalse: [string _ self explainScan: string.\\n\\t\\t\\t\\t\\t\\\"Remove space, tab, cr\\\"\\n\\t\\t\\t\\t\\t\\\"Temps and Instance vars need only test strings that are all\\nletters\\\"\\n\\t\\t\\t\\t\\t(string detect: [:char | (char isLetter or: [char isDigit]) not]\\n\\t\\t\\t\\t\\t\\tifNone: []) ifNil: \\n\\t\\t\\t\\t\\t\\t\\t[tiVars _ self explainTemp: string.\\n\\t\\t\\t\\t\\t\\t\\ttiVars == nil ifTrue: [tiVars _ self explainInst: string]].\\n\\t\\t\\t\\t\\t(tiVars == nil and: [model respondsTo: #explainSpecial:])\\n\\t\\t\\t\\t\\t\\tifTrue: [tiVars _ model explainSpecial: string].\\n\\t\\t\\t\\t\\ttiVars == nil\\n\\t\\t\\t\\t\\t\\tifTrue: [tiVars _ '']\\n\\t\\t\\t\\t\\t\\tifFalse: [tiVars _ tiVars , '\\\\' withCRs].\\n\\t\\t\\t\\t\\t\\\"Context, Class, Pool, and Global vars, and Selectors need \\n\\t\\t\\t\\t\\tonly test symbols\\\"\\n\\t\\t\\t\\t\\t(Symbol hasInterned: string ifTrue: [:s | symbol _ s])\\n\\t\\t\\t\\t\\t\\tifTrue: [cgVars _ self explainCtxt: symbol.\\n\\t\\t\\t\\t\\t\\t\\tcgVars == nil\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [cgVars _ self explainClass: symbol.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcgVars == nil ifTrue: [cgVars _ self explainGlobal: symbol]].\\n\\t\\t\\t\\t\\t\\t\\t\\\"See if it is a Selector (sent here or not)\\\"\\n\\t\\t\\t\\t\\t\\t\\tselectors _ self explainMySel: symbol.\\n\\t\\t\\t\\t\\t\\t\\tselectors == nil\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[selectors _ self explainPartSel: string.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tselectors == nil ifTrue: [\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tselectors _ self explainAnySel: symbol]]]\\n\\t\\t\\t\\t\\t\\tifFalse: [selectors _ self explainPartSel: string].\\n\\t\\t\\t\\t\\tcgVars == nil\\n\\t\\t\\t\\t\\t\\tifTrue: [cgVars _ '']\\n\\t\\t\\t\\t\\t\\tifFalse: [cgVars _ cgVars , '\\\\' withCRs].\\n\\t\\t\\t\\t\\tselectors == nil\\n\\t\\t\\t\\t\\t\\tifTrue: [selectors _ '']\\n\\t\\t\\t\\t\\t\\tifFalse: [selectors _ selectors , '\\\\' withCRs].\\n\\t\\t\\t\\t\\tstring size = 1\\n\\t\\t\\t\\t\\t\\tifTrue: [\\\"single special characters\\\"\\n\\t\\t\\t\\t\\t\\t\\tdelimitors _ self explainChar: string]\\n\\t\\t\\t\\t\\t\\tifFalse: [\\\"matched delimitors\\\"\\n\\t\\t\\t\\t\\t\\t\\tdelimitors _ self explainDelimitor: string].\\n\\t\\t\\t\\t\\tnumbers _ self explainNumber: string.\\n\\t\\t\\t\\t\\tnumbers == nil ifTrue: [numbers _ ''].\\n\\t\\t\\t\\t\\tdelimitors == nil ifTrue: [delimitors _ ''].\\n\\t\\t\\t\\t\\treply _ tiVars , cgVars , selectors , delimitors , numbers].\\n\\t\\t\\treply size = 0 ifTrue: [reply _ sorry].\\n\\t\\t\\tself afterSelectionInsertAndSelect: reply]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'di 9/7/1999 08:41'!\\nfileItIn\\n\\t\\\"Make a Stream on the text selection and fileIn it.\\n\\t 1/24/96 sw: moved here from FileController; this function can be useful from any text window that shows stuff in chunk format\\\"\\n\\n\\t| selection |\\n\\tselection _ self selection.\\n\\tself terminateAndInitializeAround:\\n\\t\\t[(ReadWriteStream on: selection string from: 1 to: selection size) fileIn].\\n! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'CdG 10/17/2005 20:49'!\\nfind\\n\\t\\\"Prompt the user for a string to search for, and search the receiver from the current selection onward for it. 1/26/96 sw\\\"\\n\\n\\t| reply |\\n\\treply := UIManager default request: 'Find what? ' translated initialAnswer: ''.\\n\\treply size == 0 ifTrue: [^ self].\\n\\tself setSearch: reply.\\n\\tChangeText := FindText. \\\"Implies no replacement to againOnce: method\\\"\\n\\tself againOrSame: true\\n\\t\\n! !\\n\\n!ParagraphEditor methodsFor: 'menu messages'!\\nfindAgain\\n\\t\\\"Find the text-to-find again. 1/24/96 sw\\\"\\n\\n\\tself againOrSame: true! !\\n\\n!ParagraphEditor methodsFor: 'menu messages'!\\nfit\\n\\t\\\"Make the bounding rectangle of the paragraph contain all the text while \\n\\t not changing the width of the view of the paragraph. No effect on undoability\\n\\t of the preceding command.\\\"\\n\\n\\tparagraph clearVisibleRectangle.\\n\\tparagraph fit.\\n\\tparagraph displayOn: Display; outline.\\n\\tself recomputeInterval! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sd 4/16/2003 09:42'!\\nimplementorsOfIt\\n\\t\\\"Open an implementors browser on the selected selector\\\"\\n\\n\\t| aSelector |\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\t(aSelector _ self selectedSelector) == nil ifTrue: [^ view flash].\\n\\tself terminateAndInitializeAround: [ self systemNavigation browseAllImplementorsOf: aSelector]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'th 9/19/2002 18:12'!\\nlineSelectAndEmptyCheck: returnBlock\\n\\t\\\"If the current selection is an insertion point, expand it to be the entire current line; if after that's done the selection is still empty, then evaluate the returnBlock, which will typically consist of '[^ self]' in the caller -- check senders of this method to understand this.\\\"\\n\\n\\tself selectLine. \\\"if current selection is an insertion point, then first select the entire line in which occurs before proceeding\\\"\\n\\tself hasSelection ifFalse: [self flash. ^ returnBlock value]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'dgd 11/25/2004 18:03'!\\nmakeProjectLink\\n\\t\\n\\t| attribute thisSel |\\n\\t\\n\\tthisSel := self selection.\\n\\n\\tattribute := TextSqkProjectLink new. \\n\\tthisSel := attribute analyze: self selection asString.\\n\\n\\tthisSel ifNil: [^ true].\\n\\tself replaceSelectionWith: (thisSel asText addAttribute: attribute).\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sd 4/16/2003 19:31'!\\nmethodNamesContainingIt\\n\\t\\\"Open a browser on methods names containing the selected string\\\"\\n\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\tCursor wait showWhile:\\n\\t\\t[self terminateAndInitializeAround: [self systemNavigation browseMethodsWhoseNamesContain: self selection string withBlanksTrimmed]].\\n\\tCursor normal show! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'md 9/6/2005 18:45'!\\nmethodSourceContainingIt\\n\\t\\\"Open a browser on methods which contain the current selection in their source (case-sensitive full-text search of source). Slow!!\\\"\\n\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\tself systemNavigation browseMethodsWithSourceString: self selection string! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sd 4/16/2003 19:28'!\\nmethodStringsContainingit\\n\\t\\\"Open a browser on methods which contain the current selection as part of a string constant.\\\"\\n\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\tself terminateAndInitializeAround: [self systemNavigation browseMethodsWithString: self selection string]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'di 10/2/97 11:34'!\\nmvcRedisplay\\n\\t\\\"Overridable by subclasses that do their own display\\\"\\n\\tDisplay fill: paragraph clippingRectangle \\n\\t\\t\\tfillColor: view backgroundColor.\\t\\\"very brute force\\\"\\n\\tself display! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'th 9/20/2002 11:21'!\\npaste\\n\\t\\\"Paste the text from the shared buffer over the current selection and \\n\\tredisplay if necessary. Undoer & Redoer: undoAndReselect.\\\"\\n\\n\\tself replace: self selectionInterval with: self clipboardText and:\\n\\t\\t[self selectAt: self pointIndex]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'ar 1/15/2001 18:36'!\\npasteRecent\\n\\t\\\"Paste an item chose from RecentClippings.\\\"\\n\\n\\t| clipping |\\n\\t(clipping _ Clipboard chooseRecentClipping) ifNil: [^ self].\\n\\tClipboard clipboardText: clipping.\\n\\t^ self paste! !\\n\\n!ParagraphEditor methodsFor: 'menu messages'!\\nperformMenuMessage: aSelector\\n\\t\\\"If a menu command is invoked, typeIn must be closed first, the selection\\n\\t must be unhighlighted before and rehighlighted after, and the marker\\n\\t must be updated.\\\"\\n\\n\\tself closeTypeIn.\\n\\tself deselect.\\n\\tsuper performMenuMessage: aSelector.\\n\\tself selectAndScroll.\\n\\tself updateMarker! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'rbb 2/16/2005 16:49'!\\npresentSpecialMenu\\n\\t\\\"Present a list of expressions, and if the user chooses one, evaluate it in the context of the receiver, a ParagraphEditor. Primarily for debugging, this provides a convenient way to talk to the various views, controllers, and models associated with any text pane\\\"\\n\\n\\t| reply items |\\n\\tself terminateAndInitializeAround:\\n\\t\\t[reply _ (UIManager default chooseFrom: (items _ self specialMenuItems) lines: #()).\\n\\t\\treply = 0 ifTrue: [^ self].\\n\\t\\tCompiler new evaluate: (items at: reply) in: [] to: self]\\n\\t! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sma 5/28/2000 09:40'!\\nprettyPrint\\n\\tself prettyPrint: false! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'md 7/13/2006 16:00'!\\nprettyPrint: decorated\\n\\t\\\"Reformat the contents of the receiver's view (a Browser).\\\"\\n\\n\\t| selectedClass newText |\\n\\tmodel selectedMessageCategoryName ifNil: [^ view flash].\\n\\tselectedClass _ model selectedClassOrMetaClass.\\n\\tnewText _ selectedClass prettyPrinterClass\\n\\t\\tformat: self text\\n\\t\\tin: selectedClass\\n\\t\\tnotifying: self\\n\\t\\tdecorated: decorated.\\n\\tnewText ifNotNil:\\n\\t\\t[self deselect; selectInvisiblyFrom: 1 to: paragraph text size.\\n\\t\\tself replaceSelectionWith: (newText asText makeSelectorBoldIn: selectedClass).\\n\\t\\tself selectAt: 1]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sma 5/28/2000 09:40'!\\nprettyPrintWithColor\\n\\tself prettyPrint: true! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'dew 3/7/2000 21:06'!\\nprinterSetup\\n\\t\\n\\tTextPrinter defaultTextPrinter inspect\\n! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sd 4/16/2003 11:47'!\\nreferencesToIt\\n\\t\\\"Open a references browser on the selected symbol\\\"\\n\\n\\t| aSymbol |\\n\\tself selectLine.\\n\\t((aSymbol _ self selectedSymbol) == nil or:\\n\\t\\t[(Smalltalk includesKey: aSymbol) not])\\n\\t\\t\\tifTrue: [^ view flash].\\n\\n\\tself terminateAndInitializeAround: [self systemNavigation browseAllCallsOn: (Smalltalk associationAt: self selectedSymbol)]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'CdG 10/17/2005 20:47'!\\nsaveContentsInFile\\n\\t\\\"Save the receiver's contents string to a file, prompting the user for a file-name. Suggest a reasonable file-name.\\\"\\n\\n\\t| fileName stringToSave parentWindow labelToUse suggestedName lastIndex |\\n\\tstringToSave := paragraph text string.\\n\\tstringToSave size == 0 ifTrue: [^ self inform: 'nothing to save.'].\\n\\tparentWindow := self model dependents\\n\\t\\t\\t\\t\\t\\tdetect: [:dep | dep isKindOf: SystemWindow orOf: StandardSystemView]\\n\\t\\t\\t\\t\\t\\tifNone: [nil].\\n\\tlabelToUse := parentWindow\\n\\t\\tifNil: \\t\\t['Untitled']\\n\\t\\tifNotNil: \\t[parentWindow label].\\n\\tsuggestedName := nil.\\n\\t#(('Decompressed contents of: '\\t\\t'.gz')) do: \\\"can add more here...\\\"\\n\\t\\t[:leaderTrailer |\\n\\t\\t\\t(labelToUse beginsWith: leaderTrailer first) ifTrue:\\n\\t\\t\\t\\t[suggestedName := labelToUse copyFrom: leaderTrailer first size + 1 to: labelToUse size.\\n\\t\\t\\t\\t(labelToUse endsWith: leaderTrailer last)\\n\\t\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t\\t[suggestedName := suggestedName copyFrom: 1 to: suggestedName size - leaderTrailer last size]\\n\\t\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t\\t[lastIndex := suggestedName lastIndexOf: $. ifAbsent: [0].\\n\\t\\t\\t\\t\\t\\t(lastIndex = 0 or: [lastIndex = 1]) ifFalse:\\n\\t\\t\\t\\t\\t\\t\\t[suggestedName := suggestedName copyFrom: 1 to: lastIndex - 1]]]].\\n\\n\\tsuggestedName ifNil:\\n\\t\\t[suggestedName := labelToUse, '.text'].\\n\\t\\t\\t\\n\\tfileName := UIManager default request: 'File name?' translated\\n\\t\\t\\tinitialAnswer: suggestedName.\\n\\tfileName isEmptyOrNil ifFalse:\\n\\t\\t[(FileStream newFileNamed: fileName) nextPutAll: stringToSave; close]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'bf 10/13/1999 09:09'!\\nselectedSelector\\n\\t\\\"Try to make a selector out of the current text selection\\\"\\n\\t^self selection string findSelector! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'yo 7/5/2004 16:38'!\\nselectedSymbol\\n\\t\\\"Return the currently selected symbol, or nil if none. Spaces, tabs and returns are ignored\\\"\\n\\n\\t| aString |\\n\\tself hasCaret ifTrue: [^ nil].\\n\\taString _ self selection string.\\n\\taString isOctetString ifTrue: [aString _ aString asOctetString].\\n\\taString _ aString copyWithoutAll:\\n\\t\\t{Character space. Character cr. Character tab}.\\n\\taString size == 0 ifTrue: [^ nil].\\n\\tSymbol hasInterned: aString ifTrue: [:sym | ^ sym].\\n\\n\\t^ nil! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'di 2/23/2001 09:26'!\\nselectionAsTiles\\n\\t\\\"Try to make new universal tiles from the selected text\\\"\\n\\t| selection tiles |\\n\\n\\tselection _ self selection.\\n\\tself terminateAndInitializeAround:\\n\\t\\t[self currentHand attachMorph: (tiles _ Player tilesFrom: selection).\\n\\t\\tPreferences tileTranslucentDrag\\n\\t\\t\\tifTrue: [tiles lookTranslucent]\\n\\t\\t\\tifFalse: [tiles align: tiles topLeft \\n\\t\\t\\t \\t\\t\\twith: self currentHand position + tiles cursorBaseOffset]].! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'gm 2/16/2003 20:38'!\\nsendContentsToPrinter\\n\\t| textToPrint printer parentWindow |\\n\\ttextToPrint := paragraph text.\\n\\ttextToPrint size == 0 ifTrue: [^self inform: 'nothing to print.'].\\n\\tprinter := TextPrinter defaultTextPrinter.\\n\\tparentWindow := self model dependents \\n\\t\\t\\t\\tdetect: [:dep | dep isSystemWindow]\\n\\t\\t\\t\\tifNone: [nil].\\n\\tparentWindow isNil \\n\\t\\tifTrue: [printer documentTitle: 'Untitled']\\n\\t\\tifFalse: [printer documentTitle: parentWindow label].\\n\\tprinter printText: textToPrint! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sd 4/16/2003 19:30'!\\nsendersOfIt\\n\\t\\\"Open a senders browser on the selected selector\\\"\\n\\n\\t| aSelector |\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\t(aSelector _ self selectedSelector) == nil ifTrue: [^ view flash].\\n\\tself terminateAndInitializeAround: [self systemNavigation browseAllCallsOn: aSelector]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'th 9/18/2002 17:28'!\\nsetAlignment: aSymbol\\n\\t| attr interval |\\n\\tattr _ TextAlignment perform: aSymbol.\\n\\tinterval _ self encompassLine: self selectionInterval.\\n\\tparagraph replaceFrom: interval first to: interval last with:\\n\\t\\t((paragraph text copyFrom: interval first to: interval last) addAttribute: attr) displaying: true.\\n! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'th 9/19/2002 18:27'!\\nsetSearchString\\n\\t\\\"Make the current selection, if any, be the current search string.\\\"\\n\\tself hasCaret ifTrue: [view flash. ^ self].\\n\\tself setSearch: self selection string! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'dgd 8/28/2004 13:59'!\\nspawn\\n\\t\\\"Create and schedule a message browser for the code of the model's \\n\\tselected message. Retain any edits that have not yet been accepted.\\\"\\n\\t| code |\\n\\tcode _ paragraph text string.\\n\\tself cancel.\\n\\tmodel notNil ifTrue:[model spawn: code].\\n! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'di 9/7/1999 08:44'!\\nspawnWorkspace\\n\\t| toUse |\\n\\tself selectLine.\\n\\ttoUse _ self selection asString.\\n\\ttoUse size > 0 ifFalse:\\n\\t\\t[toUse _ paragraph text string.\\n\\t\\ttoUse size > 0 ifFalse: [^ self flash]].\\n\\t\\\"NB: BrowserCodeController's version does a cancel here\\\"\\n\\tself terminateAndInitializeAround:\\n\\t\\t[Utilities openScratchWorkspaceLabeled: 'Untitled' contents: toUse]! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'sw 4/29/96'!\\nspecialMenuItems\\n\\t\\\"Refer to comment under #presentSpecialMenu. .\\n\\t : added objectsReferencingIt,\\\"\\n\\n\\t^ #(\\t'Transcript cr; show: ''testing'''\\n\\t\\t\\t'view superView model inspect'\\n\\t\\t\\t'view superView model browseObjClass'\\n\\t\\t\\t'view display'\\n\\t\\t\\t'self inspect'\\n\\t\\t\\t'view backgroundColor: Color fromUser'\\n\\t\\t\\t'view topView inspect'\\n\\t\\t\\t'self compareToClipboard'\\n\\t\\t\\t'view insideColor: Form white'\\n\\t\\t\\t'self objectsReferencingIt'\\n\\t\\t) ! !\\n\\n!ParagraphEditor methodsFor: 'menu messages' stamp: 'SqR 11/14/2000 12:15'!\\nundo\\n\\t\\\"Reset the state of the paragraph prior to the previous edit.\\n\\t If another ParagraphEditor instance did that edit, UndoInterval is invalid;\\n\\t just recover the contents of the undo-buffer at the start of the paragraph.\\\"\\n\\n\\tsensor flushKeyboard. \\\"a way to flush stuck keys\\\"\\n\\tself closeTypeIn.\\n\\n\\tUndoParagraph == paragraph ifFalse: \\\"Can't undo another paragraph's edit\\\"\\n\\t\\t[UndoMessage _ Message selector: #undoReplace.\\n\\t\\tUndoInterval _ 1 to: 0.\\n\\t\\tUndone _ true].\\n\\tUndoInterval ~= self selectionInterval ifTrue: \\\"blink the actual target\\\"\\n\\t\\t[self selectInterval: UndoInterval; deselect].\\n\\n\\t\\\"Leave a signal of which phase is in progress\\\"\\n\\tUndoParagraph _ Undone ifTrue: [#redoing] ifFalse: [#undoing].\\n\\tUndoMessage sentTo: self.\\n\\tUndoParagraph _ paragraph! !\\n\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 9/18/2002 14:37'!\\nadjustSelection: directionBlock\\n\\t\\\"Helper function for Cursor movement. Always moves point thus allowing selections to shrink. \\\"\\n\\t\\\"See also expandSelection:\\\"\\n\\t\\\"Accepts a one argument Block that computes the new postion given an old one.\\\"\\n\\t| newPosition |\\n\\tnewPosition _ directionBlock value: self pointIndex.\\n\\tself selectMark: self markIndex point: newPosition.\\n\\t^true.! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 10/28/2003 12:11'!\\nafterSelectionInsertAndSelect: aString\\n\\n\\tself insertAndSelect: aString at: self stopIndex ! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 9/17/2002 16:11'!\\ncomputeIntervalFrom: start to: stop\\n\\t\\\"Select the designated characters, inclusive. Make no visual changes.\\\"\\n\\n\\tself setMark: start.\\n\\tself setPoint: stop + 1.! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'di 5/6/1998 15:21'!\\ncorrectFrom: start to: stop with: aString\\n\\t\\\"Make a correction in the model that the user has authorised from somewhere else in the system (such as from the compilier). The user's selection is not changed, only corrected.\\\"\\n\\t| wasShowing userSelection delta loc |\\n\\taString = '#insert period' ifTrue:\\n\\t\\t[loc _ start.\\n\\t\\t[(loc _ loc-1)>0 and: [(paragraph text string at: loc) isSeparator]]\\n\\t\\t\\twhileTrue: [loc _ loc-1].\\n\\t\\t^ self correctFrom: loc+1 to: loc with: '.'].\\n\\t(wasShowing _ selectionShowing) ifTrue: [ self reverseSelection ].\\n\\tuserSelection _ self selectionInterval.\\n\\n\\tself selectInvisiblyFrom: start to: stop.\\n\\tself replaceSelectionWith: aString asText.\\n\\n\\tdelta _ aString size - (stop - start + 1).\\n\\tself selectInvisiblyFrom:\\n\\t\\tuserSelection first + (userSelection first > start ifFalse: [ 0 ] ifTrue: [ delta ])\\n\\t\\tto: userSelection last + (userSelection last > start ifFalse: [ 0 ] ifTrue: [ delta ]).\\n\\twasShowing ifTrue: [ self reverseSelection ].\\n! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 9/19/2002 17:21'!\\nencompassLine: anInterval\\n\\t\\\"Return an interval that encompasses the entire line\\\"\\n\\t| string left right |\\n\\tstring _ paragraph text string.\\n\\tleft _ (string lastIndexOf: Character cr startingAt: anInterval first - 1 ifAbsent:[0]) + 1.\\n\\tright _ (string indexOf: Character cr startingAt: anInterval last + 1 ifAbsent: [string size + 1]) - 1.\\n\\t^left to: right! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'di 12/17/1998 09:41'!\\ninsertAndSelect: aString at: anInteger\\n\\n\\tself replace: (anInteger to: anInteger - 1)\\n\\t\\twith: (Text string: (' ' , aString)\\n\\t\\t\\t\\t\\tattributes: emphasisHere)\\n\\t\\tand: [self selectAndScroll]! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'di 5/6/1998 15:25'!\\nnextTokenFrom: start direction: dir\\n\\t\\\"simple token-finder for compiler automated corrections\\\"\\n\\t| loc str |\\n\\tloc _ start + dir.\\n\\tstr _ paragraph text string.\\n\\t[(loc between: 1 and: str size) and: [(str at: loc) isSeparator]]\\n\\t\\twhileTrue: [loc _ loc + dir].\\n\\t^ loc! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'di 5/20/1998 08:31'!\\nnotify: aString at: anInteger in: aStream \\n\\t\\\"The compilation of text failed. The syntax error is noted as the argument, \\n\\taString. Insert it in the text at starting character position anInteger.\\\"\\n\\n\\tself insertAndSelect: aString at: (anInteger max: 1)! !\\n\\n!ParagraphEditor methodsFor: 'new selection'!\\nselectAt: characterIndex \\n\\t\\\"Deselect, then place the caret before the character at characterIndex.\\n\\t Be sure it is in view.\\\"\\n\\n\\tself selectFrom: characterIndex to: characterIndex - 1! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 9/18/2002 16:50'!\\nselectFrom: start to: stop\\n\\t\\\"Deselect, then select the specified characters inclusive.\\n\\t Be sure the selection is in view.\\\"\\n\\n\\t(start = self startIndex and: [stop + 1 = self stopIndex]) ifFalse:\\n\\t\\t[self deselect.\\n\\t\\tself selectInvisiblyFrom: start to: stop].\\n\\tself selectAndScroll! !\\n\\n!ParagraphEditor methodsFor: 'new selection'!\\nselectInterval: anInterval\\n\\t\\\"Deselect, then select the specified characters inclusive.\\n\\t Be sure the selection is in view.\\\"\\n\\n\\tself selectFrom: anInterval first to: anInterval last! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'di 5/9/1998 20:59'!\\nselectInvisiblyFrom: start to: stop\\n\\t\\\"Select the designated characters, inclusive. Make no visual changes.\\\"\\n\\n\\t^ self computeIntervalFrom: start to: stop! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 9/18/2002 14:17'!\\nselectInvisiblyMark: mark point: point\\n\\t\\\"Select the designated characters, inclusive. Make no visual changes.\\\"\\n\\n\\t^ self computeIntervalFrom: mark to: point! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 9/19/2002 17:17'!\\nselectLine\\n\\t\\\"Make the receiver's selection, if it currently consists of an insertion point only, encompass the current line.\\\"\\n\\tself hasSelection ifTrue:[^self].\\n\\tself selectInterval: (self encompassLine: self selectionInterval)! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 9/18/2002 14:18'!\\nselectMark: mark point: point\\n\\t\\\"Deselect, then select the specified characters inclusive.\\n\\t Be sure the selection is in view.\\\"\\n\\n\\t(mark = self markIndex and: [point + 1 = self pointIndex]) ifFalse:\\n\\t\\t[self deselect.\\n\\t\\tself selectInvisiblyMark: mark point: point].\\n\\tself selectAndScroll! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 9/19/2002 18:49'!\\nselectPrecedingIdentifier\\n\\t\\\"Invisibly select the identifier that ends at the end of the selection, if any.\\\"\\n\\n\\t| string sep stop tok |\\n\\ttok _ false.\\n\\tstring _ paragraph text string.\\n\\tstop _ self stopIndex - 1.\\n\\t[stop > 0 and: [(string at: stop) isSeparator]] whileTrue: [stop _ stop - 1].\\n\\tsep _ stop.\\n\\t[sep > 0 and: [(string at: sep) tokenish]] whileTrue: [tok _ true. sep _ sep - 1].\\n\\ttok ifTrue: [self selectInvisiblyFrom: sep + 1 to: stop]! !\\n\\n!ParagraphEditor methodsFor: 'new selection' stamp: 'th 9/18/2002 16:51'!\\nselectWord\\n\\t\\\"Select delimited text or word--the result of double-clicking.\\\"\\n\\n\\t| openDelimiter closeDelimiter direction match level leftDelimiters rightDelimiters\\n\\tstring here hereChar start stop |\\n\\tstring _ paragraph text string.\\n\\there _ self pointIndex.\\n\\t(here between: 2 and: string size)\\n\\t\\tifFalse: [\\\"if at beginning or end, select entire string\\\"\\n\\t\\t\\t^self selectFrom: 1 to: string size].\\n\\tleftDelimiters _ '([{<''\\\"\\n'.\\n\\trightDelimiters _ ')]}>''\\\"\\n'.\\n\\topenDelimiter _ string at: here - 1.\\n\\tmatch _ leftDelimiters indexOf: openDelimiter.\\n\\tmatch > 0\\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"delimiter is on left -- match to the right\\\"\\n\\t\\t\\tstart _ here.\\n\\t\\t\\tdirection _ 1.\\n\\t\\t\\there _ here - 1.\\n\\t\\t\\tcloseDelimiter _ rightDelimiters at: match]\\n\\t\\tifFalse: \\n\\t\\t\\t[openDelimiter _ string at: here.\\n\\t\\t\\tmatch _ rightDelimiters indexOf: openDelimiter.\\n\\t\\t\\tmatch > 0\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[\\\"delimiter is on right -- match to the left\\\"\\n\\t\\t\\t\\t\\tstop _ here - 1.\\n\\t\\t\\t\\t\\tdirection _ -1.\\n\\t\\t\\t\\t\\tcloseDelimiter _ leftDelimiters at: match]\\n\\t\\t\\t\\tifFalse: [\\\"no delimiters -- select a token\\\"\\n\\t\\t\\t\\t\\tdirection _ -1]].\\n\\tlevel _ 1.\\n\\t[level > 0 and: [direction > 0\\n\\t\\t\\tifTrue: [here < string size]\\n\\t\\t\\tifFalse: [here > 1]]]\\n\\t\\twhileTrue: \\n\\t\\t\\t[hereChar _ string at: (here _ here + direction).\\n\\t\\t\\tmatch = 0\\n\\t\\t\\t\\tifTrue: [\\\"token scan goes left, then right\\\"\\n\\t\\t\\t\\t\\thereChar tokenish\\n\\t\\t\\t\\t\\t\\tifTrue: [here = 1\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[start _ 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\\"go right if hit string start\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tdirection _ 1]]\\n\\t\\t\\t\\t\\t\\tifFalse: [direction < 0\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[start _ here + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\\"go right if hit non-token\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tdirection _ 1]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [level _ 0]]]\\n\\t\\t\\t\\tifFalse: [\\\"bracket match just counts nesting level\\\"\\n\\t\\t\\t\\t\\thereChar = closeDelimiter\\n\\t\\t\\t\\t\\t\\tifTrue: [level _ level - 1\\\"leaving nest\\\"]\\n\\t\\t\\t\\t\\t\\tifFalse: [hereChar = openDelimiter \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [level _ level + 1\\\"entering deeper nest\\\"]]]].\\n\\n\\tlevel > 0 ifTrue: [\\\"in case ran off string end\\\"\\there _ here + direction].\\n\\tdirection > 0\\n\\t\\tifTrue: [self selectFrom: start to: here - 1]\\n\\t\\tifFalse: [self selectFrom: here + 1 to: stop]! !\\n\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 1/21/2000 18:51'!\\ncomment\\n\\t\\\"All key actions that are neither editing nor typing actions have to\\n\\tsend closeTypeIn at first. See comment in openTypeIn closeTypeIn\\\"! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 11/18/2002 17:08'!\\ncursorDown: characterStream \\n\\n\\t\\\"Private - Move cursor from position in current line to same position in\\n\\tnext line. If next line too short, put at end. If shift key down,\\n\\tselect.\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself \\n\\t\\tmoveCursor:[:position | self\\n\\t\\t\\t\\tsameColumn: position\\n\\t\\t\\t\\tnewLine:[:line | line + 1]\\n\\t\\t\\t\\tforward: true]\\n\\t\\tforward: true\\n\\t\\tspecialBlock:[:dummy | dummy].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 10/28/2003 10:47'!\\ncursorEnd: characterStream \\n\\n\\t\\\"Private - Move cursor end of current line.\\\"\\n\\t| string |\\n\\tself closeTypeIn: characterStream.\\n\\tstring _ paragraph text string.\\n\\tself\\n\\t\\tmoveCursor:\\n\\t\\t\\t[:position | Preferences wordStyleCursorMovement\\n\\t\\t\\t\\tifTrue:[| targetLine |\\n\\t\\t\\t\\t\\ttargetLine _ paragraph lines at:(paragraph lineIndexOfCharacterIndex: position).\\n\\t\\t\\t\\t\\ttargetLine = paragraph lines last\\n\\t\\t\\t\\t\\t\\tifTrue:[targetLine last + 1]\\n\\t\\t\\t\\t\\t\\tifFalse:[targetLine last]]\\n\\t\\t\\t\\tifFalse:[\\n\\t\\t\\t\\t\\tstring\\n\\t\\t\\t\\t\\t\\tindexOf: Character cr\\n\\t\\t\\t\\t\\t\\tstartingAt: position\\n\\t\\t\\t\\t\\t\\tifAbsent:[string size + 1]]]\\n\\t\\tforward: true\\n\\t\\tspecialBlock:[:dummy | string size + 1].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 9/20/2002 12:14'!\\ncursorHome: characterStream \\n\\n\\t\\\"Private - Move cursor from position in current line to beginning of\\n\\tcurrent line. If control key is pressed put cursor at beginning of text\\\"\\n\\n\\t| string |\\n\\n\\tstring _ paragraph text string.\\n\\tself\\n\\t\\tmoveCursor: [ :position | Preferences wordStyleCursorMovement\\n\\t\\t\\t\\tifTrue:[\\n\\t\\t\\t\\t\\t(paragraph lines at:(paragraph lineIndexOfCharacterIndex: position)) first]\\n\\t\\t\\t\\tifFalse:[\\n\\t\\t\\t\\t\\t(string\\n\\t\\t\\t\\t\\t\\tlastIndexOf: Character cr\\n\\t\\t\\t\\t\\t\\tstartingAt: position - 1\\n\\t\\t\\t\\t\\t\\tifAbsent:[0]) + 1]]\\n\\t\\tforward: false\\n\\t\\tspecialBlock: [:dummy | 1].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 9/19/2002 20:07'!\\ncursorLeft: characterStream \\n\\t\\\"Private - Move cursor left one character if nothing selected, otherwise \\n\\tmove cursor to beginning of selection. If the shift key is down, start \\n\\tselecting or extending current selection. Don't allow cursor past \\n\\tbeginning of text\\\"\\n\\n\\tself closeTypeIn: characterStream.\\n\\tself\\n\\t\\tmoveCursor:[:position | position - 1 max: 1]\\n\\t\\tforward: false\\n\\t\\tspecialBlock:[:position | self previousWord: position].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 11/18/2002 17:09'!\\ncursorPageDown: characterStream \\n\\n\\tself closeTypeIn: characterStream.\\n\\tself \\n\\t\\tmoveCursor: [:position |\\n\\t\\t\\tself\\n\\t\\t\\t\\tsameColumn: position\\n\\t\\t\\t\\tnewLine:[:lineNo | lineNo + self pageHeight]\\n\\t\\t\\t\\tforward: true]\\n\\t\\tforward: true\\n\\t\\tspecialBlock:[:dummy | dummy].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 11/18/2002 17:09'!\\ncursorPageUp: characterStream \\n\\n\\tself closeTypeIn: characterStream.\\n\\tself \\n\\t\\tmoveCursor: [:position |\\n\\t\\t\\tself\\n\\t\\t\\t\\tsameColumn: position\\n\\t\\t\\t\\tnewLine:[:lineNo | lineNo - self pageHeight]\\n\\t\\t\\t\\tforward: false]\\n\\t\\tforward: false\\n\\t\\tspecialBlock:[:dummy | dummy].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 9/19/2002 20:01'!\\ncursorRight: characterStream \\n\\t\\\"Private - Move cursor right one character if nothing selected, \\n\\totherwise move cursor to end of selection. If the shift key is down, \\n\\tstart selecting characters or extending already selected characters. \\n\\tDon't allow cursor past end of text\\\"\\n\\n\\tself closeTypeIn: characterStream.\\n\\tself\\n\\t\\tmoveCursor: [:position | position + 1]\\n\\t\\tforward: true\\n\\t\\tspecialBlock:[:position | self nextWord: position].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 11/18/2002 17:15'!\\ncursorUp: characterStream \\n\\n\\\"Private - Move cursor from position in current line to same position in\\nprior line. If prior line too short, put at end\\\"\\n\\n\\tself closeTypeIn: characterStream.\\n\\tself\\n\\t\\tmoveCursor: [:position | self\\n\\t\\t\\t\\tsameColumn: position\\n\\t\\t\\t\\tnewLine:[:line | line - 1]\\n\\t\\t\\t\\tforward: false]\\n\\t\\tforward: false\\n\\t\\tspecialBlock:[:dummy | dummy].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'di 12/3/2001 21:49'!\\nescapeToDesktop: characterStream \\n\\t\\\"Pop up a morph to field keyboard input in the context of the desktop\\\"\\n\\n\\tSmalltalk isMorphic ifTrue: [ActiveWorld putUpWorldMenuFromEscapeKey].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'dvf 12/8/2001 00:46'!\\nraiseContextMenu: characterStream \\n\\t\\\"AFAIK, this is never called in morphic, because a subclass overrides it. Which is good, because a ParagraphEditor doesn't know about Morphic and thus duplicates the text-editing actions that really belong in the specific application, not the controller. So the context menu this would raise is likely to be out of date.\\\"\\n\\tself yellowButtonActivity.\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 1/21/2000 18:55'!\\nselectCurrentTypeIn: characterStream \\n\\t\\\"Select what would be replaced by an undo (e.g., the last typeIn).\\\"\\n\\n\\t| prior |\\n\\n\\tself closeTypeIn: characterStream.\\n\\tprior _ otherInterval.\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself selectInterval: UndoInterval.\\n\\totherInterval _ prior.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'sma 12/15/1999 11:46'!\\nselectWord: characterStream\\n\\tsensor keyboard.\\n\\tself closeTypeIn: characterStream.\\n\\tself selectWord.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'nonediting/nontyping keys' stamp: 'th 1/21/2000 18:55'!\\nsetSearchString: characterStream\\n\\t\\\"Establish the current selection as the current search string.\\\"\\n\\n\\t| aString |\\n\\tself closeTypeIn: characterStream.\\n\\tsensor keyboard.\\n\\tself lineSelectAndEmptyCheck: [^ true].\\n\\taString _ self selection string.\\n\\taString size == 0\\n\\t\\tifTrue:\\n\\t\\t\\t[self flash]\\n\\t\\tifFalse:\\n\\t\\t\\t[self setSearch: aString].\\n\\t^ true! !\\n\\n\\n!ParagraphEditor methodsFor: 'parenblinking' stamp: 'mir 8/3/2004 13:31'!\\nblinkParenAt: parenLocation \\n\\tself text\\n\\t\\taddAttribute: TextEmphasis bold\\n\\t\\tfrom: parenLocation\\n\\t\\tto: parenLocation.\\n\\tlastParentLocation _ parenLocation.! !\\n\\n!ParagraphEditor methodsFor: 'parenblinking' stamp: 'AB 1/7/2002 04:03'!\\nblinkPrevParen\\n\\t| openDelimiter closeDelimiter level string here hereChar |\\n\\tstring _ paragraph text string.\\n\\there _ startBlock stringIndex.\\n\\topenDelimiter _ sensor keyboardPeek.\\n\\tcloseDelimiter _ '([{' at: (')]}' indexOf: openDelimiter).\\n\\tlevel _ 1.\\n\\t[level > 0 and: [here > 2]]\\n\\t\\twhileTrue:\\n\\t\\t\\t[hereChar _ string at: (here _ here - 1).\\n\\t\\t\\thereChar = closeDelimiter\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[level _ level - 1.\\n\\t\\t\\t\\t\\tlevel = 0\\n\\t\\t\\t\\t\\t\\tifTrue: [^ self blinkParenAt: here]]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[hereChar = openDelimiter\\n\\t\\t\\t\\t\\t\\tifTrue: [level _ level + 1]]].! !\\n\\n!ParagraphEditor methodsFor: 'parenblinking' stamp: 'mir 8/3/2004 13:31'!\\nclearParens\\n\\tlastParentLocation ifNotNil:\\n\\t\\t[self text string size >= lastParentLocation ifTrue: [\\n\\t\\t\\tself text\\n\\t\\t\\t\\tremoveAttribute: TextEmphasis bold\\n\\t\\t\\t\\tfrom: lastParentLocation\\n\\t\\t\\t\\tto: lastParentLocation]]\\n! !\\n\\n!ParagraphEditor methodsFor: 'parenblinking' stamp: 'mikki 1/5/2005 14:10'!\\ndispatchOnCharacter: char with: typeAheadStream\\n\\t\\\"Carry out the action associated with this character, if any.\\n\\tType-ahead is passed so some routines can flush or use it.\\\"\\n\\n\\t| honorCommandKeys |\\n\\tself clearParens.\\n \\n\\t\\\"mikki 1/3/2005 21:31 Preference for auto-indent on return added.\\\"\\n\\tchar asciiValue = 13 ifTrue: [\\n\\t\\t^Preferences autoIndent \\n\\t\\t\\tifTrue: [\\n\\t\\t\\t\\tsensor controlKeyPressed\\n\\t\\t\\t\\t\\tifTrue: [self normalCharacter: typeAheadStream]\\n\\t\\t\\t\\t\\tifFalse: [self crWithIndent: typeAheadStream]]\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tsensor controlKeyPressed\\n\\t\\t\\t\\t\\tifTrue: [self crWithIndent: typeAheadStream]\\n\\t\\t\\t\\t\\tifFalse: [self normalCharacter: typeAheadStream]]].\\n\\n\\t((honorCommandKeys _ Preferences cmdKeysInText) and: [char = Character enter])\\n\\t\\tifTrue: [^ self dispatchOnEnterWith: typeAheadStream].\\n\\t\\t\\n\\t\\\"Special keys overwrite crtl+key combinations - at least on Windows. To resolve this\\n\\tconflict, assume that keys other than cursor keys aren't used together with Crtl.\\\" \\n\\t((self class specialShiftCmdKeys includes: char asciiValue) and: [char asciiValue < 27])\\n\\t\\tifTrue: [^ sensor controlKeyPressed\\n\\t\\t\\tifTrue: [self perform: (ShiftCmdActions at: char asciiValue + 1) with: typeAheadStream]\\n\\t\\t\\tifFalse: [self perform: (CmdActions at: char asciiValue + 1) with: typeAheadStream]].\\n\\n\\t\\\"backspace, and escape keys (ascii 8 and 27) are command keys\\\"\\n\\t((honorCommandKeys and: [sensor commandKeyPressed]) or: [self class specialShiftCmdKeys includes: char asciiValue]) ifTrue:\\n\\t\\t[^ sensor leftShiftDown\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[self perform: (ShiftCmdActions at: char asciiValue + 1) with: typeAheadStream]\\n\\t\\t\\tifFalse:\\n\\t\\t\\t\\t[self perform: (CmdActions at: char asciiValue + 1) with: typeAheadStream]].\\n\\n\\t\\\"the control key can be used to invoke shift-cmd shortcuts\\\"\\n\\t(honorCommandKeys and: [sensor controlKeyPressed])\\n\\t\\tifTrue:\\n\\t\\t\\t[^ self perform: (ShiftCmdActions at: char asciiValue + 1) with: typeAheadStream].\\n\\n\\t(')]}' includes: char)\\n\\t\\tifTrue: [self blinkPrevParen].\\n\\n\\t^ self perform: #normalCharacter: with: typeAheadStream! !\\n\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\ncomputeMarkerRegion \\n\\t\\\"Refer to the comment in ScrollController|computeMarkerRegion.\\\"\\n\\n\\tparagraph compositionRectangle height = 0\\n\\t\\tifTrue:\\t[^0@0 extent: Preferences scrollBarWidth @ scrollBar inside height]\\n\\t\\tifFalse:\\t[^0@0 extent:\\n\\t\\t\\t\\t\\tPreferences scrollBarWidth \\n\\t\\t\\t\\t\\t\\t@ ((paragraph clippingRectangle height asFloat /\\n\\t\\t\\t\\t\\t\\t\\tself scrollRectangleHeight * scrollBar inside height) rounded\\n\\t\\t\\t\\t\\t\\t\\tmin: scrollBar inside height)]! !\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\nmarkerDelta\\n\\n\\t^marker top - scrollBar top - ((paragraph clippingRectangle top -\\n\\t\\tparagraph compositionRectangle top) asFloat /\\n\\t\\t\\t(self scrollRectangleHeight max: 1) asFloat *\\n\\t\\t\\t\\tscrollBar height asFloat) rounded! !\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\nscrollAmount \\n\\t\\\"Refer to the comment in ScrollController|scrollAmount.\\\"\\n\\n\\t^sensor cursorPoint y - scrollBar top! !\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\nscrollBar\\n\\t^ scrollBar! !\\n\\n!ParagraphEditor methodsFor: 'scrolling' stamp: 'BG 12/12/2003 15:31'!\\nscrollBy: heightToMove\\n\\t\\\"Move the paragraph by heightToMove, and reset the text selection.\\\"\\n\\t^ paragraph scrollBy: heightToMove withSelectionFrom: self pointBlock to: self markBlock! !\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\nscrollRectangleHeight\\n\\n\\t^paragraph compositionRectangle height \\n\\t\\t+ paragraph lineGrid! !\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\nscrollToBottom\\n\\t\\\"Scroll so that the tail end of the text is visible in the view. 5/6/96 sw\\\"\\n\\n\\tself scrollView: (paragraph clippingRectangle bottom \\n\\t\\t- paragraph compositionRectangle bottom)! !\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\nscrollToTop\\n\\t\\\"Scroll so that the paragraph is at the top of the view.\\\"\\n\\n\\tself scrollView: (paragraph clippingRectangle top \\n\\t\\t- paragraph compositionRectangle top)! !\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\nscrollView: anInteger \\n\\t\\\"Paragraph scrolling uses opposite polarity\\\"\\n\\t^ self scrollBy: anInteger negated! !\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\nupdateMarker\\n\\t\\\"A variation of computeMarkerRegion--only redisplay the marker in the scrollbar if an actual change has occurred in the positioning of the paragraph.\\\"\\n\\tself moveMarkerTo: self computeMarkerRegion! !\\n\\n!ParagraphEditor methodsFor: 'scrolling'!\\nviewDelta \\n\\t\\\"Refer to the comment in ScrollController|viewDelta.\\\"\\n\\n\\t^paragraph clippingRectangle top \\n\\t\\t- paragraph compositionRectangle top \\n\\t\\t- ((marker top - scrollBar inside top) asFloat \\n\\t\\t\\t\\t/ scrollBar inside height asFloat * self scrollRectangleHeight asFloat)\\n\\t\\t\\troundTo: paragraph lineGrid! !\\n\\n\\n!ParagraphEditor methodsFor: 'sensor access'!\\nprocessBlueButton\\n\\t\\\"The user pressed the blue button on the mouse. Determine what action \\n\\tto take.\\\"\\n\\n\\t^self! !\\n\\n!ParagraphEditor methodsFor: 'sensor access'!\\nprocessKeyboard\\n\\t\\\"Determine whether the user pressed the keyboard. If so, read the keys.\\\"\\n\\n\\tsensor keyboardPressed ifTrue: [self readKeyboard]! !\\n\\n!ParagraphEditor methodsFor: 'sensor access'!\\nprocessMouseButtons\\n\\t\\\"Determine whether the user pressed any mouse button. For each possible \\n\\tbutton, determine what actions to take.\\\"\\n\\n\\tsensor redButtonPressed ifTrue: [self processRedButton].\\n\\tsensor yellowButtonPressed ifTrue: [self processYellowButton].\\n\\tsensor blueButtonPressed ifTrue: [self processBlueButton]! !\\n\\n!ParagraphEditor methodsFor: 'sensor access' stamp: 'th 9/19/2002 18:24'!\\nprocessRedButton\\n\\t\\\"The user pressed a red mouse button, meaning create a new text \\n\\tselection. Highlighting the selection is carried out by the paragraph \\n\\titself. Double clicking causes a selection of the area between the nearest \\n\\tenclosing delimitors.\\\"\\n\\n\\t| selectionBlocks clickPoint oldDelta oldInterval previousMarkBlock previousPointBlock |\\n\\n\\tclickPoint _ sensor cursorPoint.\\n\\t(view containsPoint: clickPoint) ifFalse: [^ self].\\n\\t(paragraph clickAt: clickPoint for: model controller: self) ifTrue: [^ self].\\n\\toldInterval _ self selectionInterval.\\n\\tpreviousMarkBlock _ self markBlock.\\n\\tpreviousPointBlock _ self pointBlock.\\n\\toldDelta _ paragraph scrollDelta.\\n\\tsensor leftShiftDown\\n\\t\\tifFalse:\\n\\t\\t\\t[self deselect.\\n\\t\\t\\tself closeTypeIn.\\n\\t\\t\\tselectionBlocks _ paragraph mouseSelect: clickPoint]\\n\\t\\tifTrue:\\n\\t\\t\\t[selectionBlocks _ paragraph extendSelectionMark: self markBlock pointBlock: self pointBlock.\\n\\t\\t\\tself closeTypeIn].\\n\\tselectionShowing _ true.\\n\\tself markBlock: (selectionBlocks at: 1).\\n\\tself pointBlock: (selectionBlocks at: 2).\\n\\t(self hasCaret\\n\\t\\tand: [previousMarkBlock = self markBlock and: [previousPointBlock = self pointBlock]])\\n\\t\\tifTrue: [self selectWord].\\n\\toldDelta ~= paragraph scrollDelta \\\"case of autoscroll\\\"\\n\\t\\t\\tifTrue: [self updateMarker].\\n\\tself setEmphasisHere.\\n\\t(self isDisjointFrom: oldInterval) ifTrue:\\n\\t\\t[otherInterval _ oldInterval]! !\\n\\n!ParagraphEditor methodsFor: 'sensor access'!\\nprocessYellowButton\\n\\t\\\"User pressed the yellow button on the mouse. Determine what actions to \\n\\ttake.\\\"\\n\\n\\tself yellowButtonActivity! !\\n\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'yo 3/16/2004 13:05'!\\nbackTo: startIndex\\n\\t\\\"During typing, backspace to startIndex. Deleted characters fall into three\\n\\t clusters, from left to right in the text: (1) preexisting characters that were\\n\\t backed over; (2) newly typed characters that were backed over (excluding\\n\\t typeahead, which never even appears); (3) preexisting characters that\\n\\t were highlighted before typing began. If typing has not yet been opened,\\n\\t open it and watch for the first and third cluster. If typing has been opened,\\n\\t watch for the first and second cluster. Save characters from the first and third\\n\\t cluster in UndoSelection. Tally characters from the first cluster in UndoMessage's parameter.\\n\\t Delete all the clusters. Do not alter Undoer or UndoInterval (except via\\n\\t openTypeIn). The code is shorter than the comment.\\\"\\n\\n\\t| saveLimit newBackovers |\\n\\tsaveLimit _ beginTypeInBlock == nil\\n\\t\\tifTrue: [self openTypeIn. UndoSelection _ self nullText. self stopIndex]\\n\\t\\tifFalse: [self startOfTyping].\\n\\tself setMark: startIndex.\\n\\tstartIndex < saveLimit ifTrue:\\n\\t\\t[newBackovers _ self startOfTyping - startIndex.\\n\\t\\tbeginTypeInBlock _ self startIndex.\\n\\t\\tUndoSelection replaceFrom: 1 to: 0 with:\\n\\t\\t\\t(paragraph text copyFrom: startIndex to: saveLimit - 1).\\n\\t\\tUndoMessage argument: (UndoMessage argument ifNil: [1]) + newBackovers].\\n\\tself zapSelectionWith: self nullText.\\n\\tself unselect! !\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'th 9/19/2002 17:40'!\\ncloseTypeIn\\n\\t\\\"See comment in openTypeIn. It is important to call closeTypeIn before executing\\n\\t any non-typing key, making a new selection, etc. It is called automatically for\\n\\t menu commands.\\n\\t Typing commands can call 'closeTypeIn: aCharacterStream' instead of this to\\n\\t save typeahead. Undoer & Redoer: undoAndReselect:redoAndReselect:.\\\"\\n\\n\\t| begin stop |\\n\\tbeginTypeInBlock == nil ifFalse:\\n\\t\\t[(UndoMessage sends: #noUndoer) ifTrue: \\\"should always be true, but just in case...\\\"\\n\\t\\t\\t[begin _ self startOfTyping.\\n\\t\\t\\tstop _ self stopIndex.\\n\\t\\t\\tself undoer: #undoAndReselect:redoAndReselect:\\n\\t\\t\\t\\twith: (begin + UndoMessage argument to: begin + UndoSelection size - 1)\\n\\t\\t\\t\\twith: (stop to: stop - 1).\\n\\t\\t\\tUndoInterval _ begin to: stop - 1].\\n\\t\\tbeginTypeInBlock _ nil]! !\\n\\n!ParagraphEditor methodsFor: 'typing support'!\\ncloseTypeIn: characterStream\\n\\t\\\"Call instead of closeTypeIn when you want typeahead to be inserted before the\\n\\t control character is executed, e.g., from Ctrl-V.\\\"\\n\\n\\tself insertTypeAhead: characterStream.\\n\\tself closeTypeIn! !\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'di 9/7/1999 11:26'!\\ndispatchOnEnterWith: typeAheadStream\\n\\t\\\"Enter key hit. Treat is as an 'accept', viz a synonym for cmd-s. If cmd key is down, treat is as a synonym for print-it. \\\"\\n\\n\\tsensor keyboard. \\\"consume enter key\\\"\\n\\tself terminateAndInitializeAround: [\\n\\tsensor commandKeyPressed\\n\\t\\tifTrue:\\n\\t\\t\\t[self printIt.]\\n\\t\\tifFalse: \\n\\t\\t\\t[self closeTypeIn: typeAheadStream.\\n\\t\\t\\tself accept].\\n\\t].\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'di 6/14/1998 13:08'!\\ndoneTyping\\n\\tbeginTypeInBlock _ nil! !\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'th 9/17/2002 16:23'!\\ninsertTypeAhead: typeAhead\\n\\ttypeAhead position = 0 ifFalse:\\n\\t\\t[self zapSelectionWith: (Text string: typeAhead contents emphasis: emphasisHere).\\n\\t\\ttypeAhead reset.\\n\\t\\tself unselect]! !\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'th 9/18/2002 16:48'!\\nopenTypeIn\\n\\t\\\"Set up UndoSelection to null text (to be added to by readKeyboard and backTo:),\\n\\t beginTypeInBlock to keep track of the leftmost backspace, and UndoParameter to tally\\n\\t how many deleted characters were backspaced over rather than 'cut'.\\n\\t You can't undo typing until after closeTypeIn.\\\"\\n\\n\\tbeginTypeInBlock == nil ifTrue:\\n\\t\\t[UndoSelection _ self nullText.\\n\\t\\tself undoer: #noUndoer with: 0.\\n\\t\\tbeginTypeInBlock _ self startIndex]! !\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'th 9/19/2002 18:26'!\\nreadKeyboard\\n\\t\\\"Key struck on the keyboard. Find out which one and, if special, carry \\n\\tout the associated special action. Otherwise, add the character to the \\n\\tstream of characters. Undoer & Redoer: see closeTypeIn.\\\"\\n\\n\\t| typeAhead char |\\n\\ttypeAhead _ WriteStream on: (String new: 128).\\n\\t[sensor keyboardPressed] whileTrue: \\n\\t\\t[self deselect.\\n\\t\\t [sensor keyboardPressed] whileTrue: \\n\\t\\t\\t[char _ sensor keyboardPeek.\\n\\t\\t\\t(self dispatchOnCharacter: char with: typeAhead) ifTrue:\\n\\t\\t\\t\\t[self doneTyping.\\n\\t\\t\\t\\tself setEmphasisHere.\\n\\t\\t\\t\\t^self selectAndScroll; updateMarker].\\n\\t\\t\\tself openTypeIn].\\n\\t\\tself hasSelection ifTrue: \\\"save highlighted characters\\\"\\n\\t\\t\\t[UndoSelection _ self selection]. \\n\\t\\tself zapSelectionWith: \\n\\t\\t\\t(Text string: typeAhead contents emphasis: emphasisHere).\\n\\t\\ttypeAhead reset.\\n\\t\\tself unselect.\\n\\t\\tsensor keyboardPressed ifFalse: \\n\\t\\t\\t[self selectAndScroll.\\n\\t\\t\\tsensor keyboardPressed\\n\\t\\t\\t\\tifFalse: [self updateMarker]]]! !\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'th 9/18/2002 16:49'!\\nsetEmphasisHere\\n\\n\\temphasisHere _ (paragraph text attributesAt: (self pointIndex - 1 max: 1) forStyle: paragraph textStyle)\\n\\t\\t\\t\\t\\tselect: [:att | att mayBeExtended]! !\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'th 9/17/2002 16:23'!\\nsimulatedKeystroke: char\\n\\t\\\"Accept char as if it were struck on the keyboard. This version does not yet deal with command keys, and achieves update in the receiver's typically inactive window via the sledge-hammer of uncache-bits.\\\"\\n\\n\\tself deselect.\\n\\tself openTypeIn.\\n\\tself markBlock = self pointBlock ifFalse: [UndoSelection _ self selection].\\n\\tself zapSelectionWith:\\n\\t\\t(Text string: char asString emphasis: emphasisHere).\\n\\tself userHasEdited.\\n\\tself unselect.\\n\\tself selectAndScroll.\\n\\tself updateMarker.\\n\\tview ifNotNil:\\n\\t\\t[view topView uncacheBits\\n\\t\\t\\\"in mvc, this makes sure the recognized character shows up in the pane right now; in morphic, a different mechanism is used for the same effect -- see TextMorphEditor method #recognizeCharactersWhileMouseIn:\\\"]\\n! !\\n\\n!ParagraphEditor methodsFor: 'typing support' stamp: 'di 10/6/1998 08:45'!\\nstartOfTyping\\n\\t\\\"Compatibility during change from characterBlock to integer\\\"\\n\\tbeginTypeInBlock == nil ifTrue: [^ nil].\\n\\tbeginTypeInBlock isNumber ifTrue: [^ beginTypeInBlock].\\n\\t\\\"Last line for compatibility during change from CharacterBlock to Integer.\\\"\\n\\t^ beginTypeInBlock stringIndex\\n\\t! !\\n\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys' stamp: 'th 9/20/2002 11:22'!\\nargAdvance: characterStream\\n\\t\\\"Invoked by Ctrl-a. Useful after Ctrl-q.\\n\\t Search forward from the end of the selection for a colon followed by\\n\\t\\ta space. Place the caret after the space. If none are found, place the\\n\\t\\tcaret at the end of the text. Does not affect the undoability of the \\n\\t \\tprevious command.\\\"\\n\\n\\t| start |\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tstart _ paragraph text findString: ': ' startingAt: self stopIndex.\\n\\tstart = 0 ifTrue: [start _ paragraph text size + 1].\\n\\tself selectAt: start + 2.\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys' stamp: 'th 10/21/2003 15:46'!\\nbackWord: characterStream \\n\\t\\\"If the selection is not a caret, delete it and leave it in the backspace buffer.\\n\\t Else if there is typeahead, delete it.\\n\\t Else, delete the word before the caret.\\\"\\n\\n\\t| startIndex |\\n\\tsensor keyboard.\\n\\tcharacterStream isEmpty\\n\\t\\tifTrue:\\n\\t\\t\\t[self hasCaret\\n\\t\\t\\t\\tifTrue: \\\"a caret, delete at least one character\\\"\\n\\t\\t\\t\\t\\t[startIndex _ 1 max: self markIndex - 1.\\n\\t\\t\\t\\t\\t[startIndex > 1 and:\\n\\t\\t\\t\\t\\t\\t[(paragraph text at: startIndex - 1) asCharacter tokenish]]\\n\\t\\t\\t\\t\\t\\twhileTrue:\\n\\t\\t\\t\\t\\t\\t\\t[startIndex _ startIndex - 1]]\\n\\t\\t\\t\\tifFalse: \\\"a non-caret, just delete it\\\"\\n\\t\\t\\t\\t\\t[startIndex _ self markIndex].\\n\\t\\t\\tself backTo: startIndex]\\n\\t\\tifFalse:\\n\\t\\t\\t[characterStream reset].\\n\\t^false! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys' stamp: 'th 9/19/2002 18:23'!\\nbackspace: characterStream \\n\\t\\\"Backspace over the last character.\\\"\\n\\n\\t| startIndex |\\n\\tsensor leftShiftDown ifTrue: [^ self backWord: characterStream].\\n\\tcharacterStream isEmpty\\n\\t\\tifTrue:\\n\\t\\t\\t[startIndex _ self markIndex +\\n\\t\\t\\t\\t(self hasCaret ifTrue: [0] ifFalse: [1]).\\n\\t\\t\\t[sensor keyboardPressed and:\\n\\t\\t\\t [sensor keyboardPeek asciiValue = 8]] whileTrue: [\\n\\t\\t\\t\\t\\\"process multiple backspaces\\\"\\n\\t\\t\\t\\tsensor keyboard.\\n\\t\\t\\t\\tstartIndex _ 1 max: startIndex - 1.\\n\\t\\t\\t].\\n\\t\\t\\tself backTo: startIndex]\\n\\t\\tifFalse:\\n\\t\\t\\t[sensor keyboard.\\n\\t\\t\\tcharacterStream skip: -1].\\n\\t^false! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\nchangeStyle: characterStream \\n\\t\\\"Put up the style-change menu\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself changeStyle.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys' stamp: 'th 9/20/2002 11:25'!\\ncrWithIndent: characterStream \\n\\t\\\"Replace the current text selection with CR followed by as many tabs\\n\\tas on the current line (+/- bracket count) -- initiated by Shift-Return.\\\"\\n\\t| char s i tabCount |\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\ts _ paragraph string.\\n\\ti _ self stopIndex.\\n\\ttabCount _ 0.\\n\\t[(i _ i-1) > 0 and: [(char _ s at: i) ~= Character cr]]\\n\\t\\twhileTrue: \\\"Count tabs and brackets (but not a leading bracket)\\\"\\n\\t\\t[(char = Character tab and: [i < s size and: [(s at: i+1) ~= $[ ]]) ifTrue: [tabCount _ tabCount + 1].\\n\\t\\tchar = $[ ifTrue: [tabCount _ tabCount + 1].\\n\\t\\tchar = $] ifTrue: [tabCount _ tabCount - 1]].\\n\\tcharacterStream crtab: tabCount. \\\"Now inject CR with tabCount tabs\\\"\\n\\t^ false! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys' stamp: 'sw 4/30/2001 21:20'!\\ncursorTopHome: characterStream \\n\\t\\\"Put cursor at beginning of text -- invoked from cmd-H shortcut, useful for keyboards that have no home key.\\\"\\n\\t\\n\\tsensor keyboard.\\n\\tself selectAt: 1.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\ndisplayIfFalse: characterStream \\n\\t\\\"Replace the current text selection with the text 'ifFalse:'--initiated by \\n\\tctrl-f.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tcharacterStream nextPutAll: 'ifFalse:'.\\n\\t^false! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\ndisplayIfTrue: characterStream \\n\\t\\\"Replace the current text selection with the text 'ifTrue:'--initiated by \\n\\tctrl-t.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tcharacterStream nextPutAll: 'ifTrue:'.\\n\\t^false! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\ndoAgainMany: characterStream \\n\\t\\\"Do the previous thing again repeatedly. 1/26/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself againOrSame: (UndoMessage sends: #undoAgain:andReselect:typedKey:) many: true.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\ndoAgainOnce: characterStream \\n\\t\\\"Do the previous thing again once. 1/26/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself again.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\nfind: characterStream\\n\\t\\\"Prompt the user for what to find, then find it, searching from the current selection onward. 1/24/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself find.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\nfindAgain: characterStream \\n\\t\\\"Find the desired text again. 1/24/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself findAgain.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys' stamp: 'th 9/18/2002 11:39'!\\nforwardDelete: characterStream\\n\\t\\\"Delete forward over the next character.\\n\\t Make Undo work on the whole type-in, not just the one char.\\n\\twod 11/3/1998: If there was a selection use #zapSelectionWith: rather than #backspace: which was 'one off' in deleting the selection. Handling of things like undo or typeIn area were not fully considered.\\\"\\n\\t| startIndex usel upara uinterval ind stopIndex |\\n\\tstartIndex _ self mark.\\n\\tstartIndex > paragraph text size ifTrue:\\n\\t\\t[sensor keyboard.\\n\\t\\t^ false].\\n\\tself hasSelection ifTrue:\\n\\t\\t[\\\"there was a selection\\\"\\n\\t\\tsensor keyboard.\\n\\t\\tself zapSelectionWith: self nullText.\\n\\t\\t^ false].\\n\\t\\\"Null selection - do the delete forward\\\"\\n\\tbeginTypeInBlock == nil\\t\\\"no previous typing. openTypeIn\\\"\\n\\t\\tifTrue: [self openTypeIn. UndoSelection _ self nullText].\\n\\tuinterval _ UndoInterval deepCopy.\\n\\tupara _ UndoParagraph deepCopy.\\n\\tstopIndex := startIndex.\\n\\t(sensor keyboard asciiValue = 127 and: [sensor leftShiftDown])\\n\\t\\tifTrue: [stopIndex := (self nextWord: stopIndex) - 1].\\n\\tself selectFrom: startIndex to: stopIndex.\\n\\tself replaceSelectionWith: self nullText.\\n\\tself selectFrom: startIndex to: startIndex-1.\\n\\tUndoParagraph _ upara. UndoInterval _ uinterval.\\n\\tUndoMessage selector == #noUndoer ifTrue: [\\n\\t\\t(UndoSelection isText) ifTrue: [\\n\\t\\t\\tusel _ UndoSelection.\\n\\t\\t\\tind _ startIndex. \\\"UndoInterval startIndex\\\"\\n\\t\\t\\tusel replaceFrom: usel size + 1 to: usel size with:\\n\\t\\t\\t\\t(UndoParagraph text copyFrom: ind to: ind).\\n\\t\\t\\tUndoParagraph text replaceFrom: ind to: ind with:\\nself nullText]].\\n\\t^false! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\nnormalCharacter: characterStream \\n\\t\\\"A nonspecial character is to be added to the stream of characters.\\\"\\n\\n\\tcharacterStream nextPut: sensor keyboard.\\n\\t^false! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys' stamp: 'th 9/19/2002 18:25'!\\nquerySymbol: characterStream\\n\\t\\\"Invoked by Ctrl-q to query the Symbol table and display alternate symbols.\\n\\t See comment in completeSymbol:lastOffering: for details.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\t\\\"keep typeahead\\\"\\n\\tself hasCaret\\n\\t\\tifTrue: \\\"Ctrl-q typed when a caret\\\"\\n\\t\\t\\t[self perform: #completeSymbol:lastOffering: withArguments:\\n\\t\\t\\t\\t((UndoParagraph == paragraph and: [UndoMessage sends: #undoQuery:lastOffering:])\\n\\t\\t\\t\\t\\tifTrue: [UndoMessage arguments] \\\"repeated Ctrl-q\\\"\\n\\t\\t\\t\\t\\tifFalse: [Array with: nil with: nil])] \\\"initial Ctrl-q\\\"\\n\\t\\tifFalse: \\\"Ctrl-q typed when statements were highlighted\\\"\\n\\t\\t\\t[view flash].\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\nsearch: characterStream\\n\\t\\\"Invoked by Ctrl-S. Same as 'again', but always uses the existing FindText\\n\\t and ChangeText regardless of the last edit.\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself againOrSame: true. \\\"true means use same keys\\\"\\n\\t^true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys' stamp: 'sw 8/29/2000 14:58'!\\nselectAll\\n\\t\\\"Make the selection be all the characters of the receiver\\\"\\n\\n\\tself selectFrom: 1 to: paragraph text string size! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys'!\\nselectAll: characterStream \\n\\t\\\"select everything, invoked by cmd-a. 1/17/96 sw\\\"\\n\\n\\tsensor keyboard.\\t\\t\\\"flush character\\\"\\n\\tself closeTypeIn: characterStream.\\n\\tself selectFrom: 1 to: paragraph text string size.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'typing/selecting keys' stamp: 'th 9/19/2002 17:34'!\\nsimulatedBackspace\\n\\t\\\"Backspace over the last character, derived from hand-char recognition. 2/5/96 sw\\\"\\n\\n\\t| startIndex |\\n\\tstartIndex _ self markIndex + (self hasSelection ifTrue: [1] ifFalse: [0]).\\n\\n\\tstartIndex _ 1 max: startIndex - 1.\\n\\tself backTo: startIndex.\\n\\t^ false! !\\n\\n\\n!ParagraphEditor methodsFor: 'undo support'!\\nisDoing\\n\\t\\\"Call from a doer/undoer/redoer any time to see which it is.\\\"\\n\\n\\t^(self isUndoing | self isRedoing) not! !\\n\\n!ParagraphEditor methodsFor: 'undo support'!\\nisRedoing\\n\\t\\\"Call from a doer/undoer/redoer any time to see which it is.\\\"\\n\\n\\t^UndoParagraph == #redoing! !\\n\\n!ParagraphEditor methodsFor: 'undo support'!\\nisUndoing\\n\\t\\\"Call from a doer/undoer/redoer any time to see which it is.\\\"\\n\\n\\t^UndoParagraph == #undoing! !\\n\\n!ParagraphEditor methodsFor: 'undo support'!\\nnoUndoer\\n\\t\\\"The Undoer to use when the command can not be undone. Checked for\\n\\t specially by readKeyboard.\\\"\\n\\n\\tUndoMessage _ Message selector: #noUndoer! !\\n\\n!ParagraphEditor methodsFor: 'undo support'!\\nundoMessage: aMessage forRedo: aBoolean\\n\\t\\\"Call this from an undoer/redoer to set up UndoMessage as the\\n\\t corresponding redoer/undoer. Also set up UndoParagraph, as well\\n\\t as the state variable Undone. It is assumed that UndoInterval has been\\n\\t established (generally by zapSelectionWith:) and that UndoSelection has been\\n\\t saved (generally by replaceSelectionWith: or replace:With:and:).\\\"\\n\\n\\tself isDoing ifTrue: [UndoParagraph _ paragraph].\\n\\tUndoMessage _ aMessage.\\n\\tUndone _ aBoolean! !\\n\\n!ParagraphEditor methodsFor: 'undo support'!\\nundoer: aSelector\\n\\t\\\"See comment in undoMessage:. Use this version when aSelector has no arguments, and you are doing or redoing and want to prepare for undoing.\\\"\\n\\n\\tself undoMessage: (Message selector: aSelector) forRedo: false! !\\n\\n!ParagraphEditor methodsFor: 'undo support'!\\nundoer: aSelector with: arg1\\n\\t\\\"See comment in undoMessage:. Use this version when aSelector has one argument, and you are doing or redoing and want to prepare for undoing.\\\"\\n\\n\\tself undoMessage: (Message selector: aSelector argument: arg1) forRedo: false! !\\n\\n!ParagraphEditor methodsFor: 'undo support'!\\nundoer: aSelector with: arg1 with: arg2\\n\\t\\\"See comment in undoMessage:. Use this version when aSelector has two arguments, and you are doing or redoing and want to prepare for undoing.\\\"\\n\\n\\tself undoMessage: (Message selector: aSelector arguments: (Array with: arg1 with: arg2)) forRedo: false! !\\n\\n!ParagraphEditor methodsFor: 'undo support'!\\nundoer: aSelector with: arg1 with: arg2 with: arg3\\n\\t\\\"See comment in undoMessage:. Use this version when aSelector has three arguments, and you are doing or redoing and want to prepare for undoing.\\\"\\n\\n\\tself undoMessage: (Message selector: aSelector arguments: (Array with: arg1 with: arg2 with: arg3)) forRedo: false! !\\n\\n\\n!ParagraphEditor methodsFor: 'undoers'!\\nundoAgain: indices andReselect: home typedKey: wasTypedKey\\n\\t\\\"The last command was again. Undo it. Redoer: itself.\\\"\\n\\n\\t| findSize substText index subject |\\n\\t(self isRedoing & wasTypedKey) ifTrue: \\\"redelete search key\\\"\\n\\t\\t[self selectInterval: home.\\n\\t\\tself zapSelectionWith: self nullText].\\n\\n\\tfindSize _ (self isRedoing ifTrue: [FindText] ifFalse: [ChangeText]) size.\\n\\tsubstText _ self isUndoing ifTrue: [FindText] ifFalse: [ChangeText].\\n\\t(self isUndoing ifTrue: [indices size to: 1 by: -1] ifFalse: [1 to: indices size]) do:\\n\\t\\t[:i |\\n\\t\\tindex _ indices at: i.\\n\\t\\t(subject _ index to: index + findSize - 1) = self selectionInterval ifFalse:\\n\\t\\t\\t[self selectInterval: subject].\\n\\t\\tFindText == ChangeText ifFalse: [self zapSelectionWith: substText]].\\n\\n\\tself isUndoing\\n\\t\\tifTrue: \\\"restore selection to where it was when 'again' was invoked\\\"\\n\\t\\t\\t[wasTypedKey\\n\\t\\t\\t\\tifTrue: \\\"search started by typing key at a caret; restore it\\\"\\n\\t\\t\\t\\t\\t[self selectAt: home first.\\n\\t\\t\\t\\t\\tself zapSelectionWith: FindText.\\n\\t\\t\\t\\t\\tself selectAt: home last + 1]\\n\\t\\t\\t\\tifFalse: [self selectInterval: home]].\\n\\n\\tself undoMessage: UndoMessage forRedo: self isUndoing! !\\n\\n!ParagraphEditor methodsFor: 'undoers'!\\nundoAndReselect: undoHighlight redoAndReselect: redoHighlight\\n\\t\\\"Undo typing, cancel, paste, and other operations that are like replaces\\n\\t but the selection is not the whole restored text after undo, redo, or both.\\n\\t undoHighlight is selected after this phase and redoHighlight after the next phase.\\n\\tRedoer: itself.\\\"\\n\\n\\tself replace: self selectionInterval with: UndoSelection and:\\n\\t\\t[self selectInterval: undoHighlight].\\n\\tself undoMessage: (UndoMessage argument: redoHighlight) forRedo: self isUndoing\\n! !\\n\\n!ParagraphEditor methodsFor: 'undoers'!\\nundoCutCopy: oldPasteBuffer\\n\\t\\\"Undo of a cut, copy, or any edit that changed CurrentSelection. Be sure\\n\\t undo-copy does not lock the model. Redoer: itself, so never isRedoing.\\\"\\n\\n\\t| recentCut |\\n\\trecentCut _ self clipboardText.\\t\\n\\tUndoSelection size = UndoInterval size\\n\\t\\tifFalse: [self replaceSelectionWith: UndoSelection].\\n\\tself clipboardTextPut: oldPasteBuffer.\\n\\tself undoer: #undoCutCopy: with: recentCut! !\\n\\n!ParagraphEditor methodsFor: 'undoers' stamp: 'th 9/19/2002 18:46'!\\nundoQuery: hintText lastOffering: selectorOrNil\\n\\t\\\"Undo ctrl-q. selectorOrNil (if not nil) is the previously offered selector.\\n\\t hintText is the original hint. Redoer: completeSymbol.\\\"\\n\\n\\tself zapSelectionWith: UndoSelection.\\n\\tself undoMessage: (Message selector: #completeSymbol:lastOffering: arguments: UndoMessage arguments) forRedo: true.\\n\\tself selectAt: self stopIndex! !\\n\\n!ParagraphEditor methodsFor: 'undoers'!\\nundoReplace\\n\\t\\\"Undo of any command that replaced a selection by other text that it left\\n\\t highlighted, and that is undone and redone by simple reversal of the\\n\\t operation. This is the most common Undoer; call replaceSelectionWith:\\n\\t to get this setup. Redoer: itself, so never isRedoing.\\\"\\n\\n\\tself replaceSelectionWith: UndoSelection! !\\n\\n\\n!ParagraphEditor methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nbrowseChangeSetsWithSelector\\n\\t\\\"Determine which, if any, change sets have at least one change for the selected selector, independent of class\\\"\\n\\n\\t| aSelector |\\n\\tself lineSelectAndEmptyCheck: [^ self].\\n\\t(aSelector := self selectedSelector) == nil ifTrue: [^ view flash].\\n\\tself terminateAndInitializeAround: [ChangeSorter browseChangeSetsWithSelector: aSelector]! !\\n\\n!ParagraphEditor methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nbrowseItHere\\n\\t\\\"Retarget the receiver's window to look at the selected class, if appropriate. 3/1/96 sw\\\"\\n\\t| aSymbol foundClass b |\\n\\t(((b := model) isKindOf: Browser) and: [b couldBrowseAnyClass])\\n\\t\\tifFalse: [^ view flash].\\n\\tmodel okToChange ifFalse: [^ view flash].\\n\\tself selectionInterval isEmpty ifTrue: [self selectWord].\\n\\t(aSymbol := self selectedSymbol) isNil ifTrue: [^ view flash].\\n\\n\\tself terminateAndInitializeAround:\\n\\t\\t[foundClass := (Smalltalk at: aSymbol ifAbsent: [nil]).\\n\\t\\t\\tfoundClass isNil ifTrue: [^ view flash].\\n\\t\\t\\t(foundClass isKindOf: Class)\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[model systemCategoryListIndex: \\n\\t\\t\\t\\t\\t\\t(model systemCategoryList indexOf: foundClass category).\\n\\t\\tmodel classListIndex: (model classList indexOf: foundClass name)]]! !\\n\\n!ParagraphEditor methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\ndebugIt\\n\\n\\t| method receiver context |\\n\\t(model respondsTo: #doItReceiver) \\n\\t\\tifTrue: \\n\\t\\t\\t[FakeClassPool adopt: model selectedClass.\\n\\t\\t\\treceiver := model doItReceiver.\\n\\t\\t\\tcontext := model doItContext]\\n\\t\\tifFalse:\\n\\t\\t\\t[receiver := context := nil].\\n\\tself lineSelectAndEmptyCheck: [^self].\\n\\tmethod := self compileSelectionFor: receiver in: context.\\n\\tmethod notNil ifTrue:\\n\\t\\t[self debug: method receiver: receiver in: context].\\n\\tFakeClassPool adopt: nil! !\\n\\n!ParagraphEditor methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\ndebug: aCompiledMethod receiver: anObject in: evalContext\\n\\n\\t| selector guineaPig debugger context |\\n\\tselector := evalContext isNil ifTrue: [#DoIt] ifFalse: [#DoItIn:].\\n\\tanObject class addSelectorSilently: selector withMethod: aCompiledMethod.\\n\\tguineaPig := evalContext isNil\\n\\t\\tifTrue: [[anObject DoIt] newProcess]\\n\\t\\tifFalse: [[anObject DoItIn: evalContext] newProcess].\\n\\tcontext := guineaPig suspendedContext.\\n\\tdebugger := Debugger new\\n\\t\\tprocess: guineaPig\\n\\t\\tcontroller: ((Smalltalk isMorphic not and: [ScheduledControllers inActiveControllerProcess])\\n\\t\\t\\t\\tifTrue: [ScheduledControllers activeController]\\n\\t\\t\\t\\tifFalse: [nil])\\n\\t\\tcontext: context\\n\\t\\tisolationHead: nil.\\n\\tdebugger openFullNoSuspendLabel: 'Debug it'.\\n\\t[debugger interruptedContext method == aCompiledMethod]\\n\\t\\twhileFalse: [debugger send].\\n\\tanObject class basicRemoveSelector: selector! !\\n\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'th 9/19/2002 18:48'!\\nagainOnce: indices\\n\\t\\\"Find the next occurrence of FindText. If none, answer false.\\n\\tAppend the start index of the occurrence to the stream indices, and, if\\n\\tChangeText is not the same object as FindText, replace the occurrence by it.\\n\\tNote that the search is case-sensitive for replacements, otherwise not.\\\"\\n\\n\\t| where |\\n\\twhere _ paragraph text findString: FindText startingAt: self stopIndex\\n\\t\\t\\t\\tcaseSensitive: ((ChangeText ~~ FindText) or: [Preferences caseSensitiveFinds]).\\n\\twhere = 0 ifTrue: [^ false].\\n\\tself deselect; selectInvisiblyFrom: where to: where + FindText size - 1.\\n\\tChangeText ~~ FindText ifTrue: [self zapSelectionWith: ChangeText].\\n\\tindices nextPut: where.\\n\\tself selectAndScroll.\\n\\t^ true! !\\n\\n!ParagraphEditor methodsFor: 'private'!\\nagainOrSame: useOldKeys\\n\\t\\\"Subroutine of search: and again. If useOldKeys, use same FindText and ChangeText as before.\\n\\t 1/26/96 sw: real worked moved to againOrSame:many:\\\"\\n\\n\\t^ self againOrSame: useOldKeys many: sensor leftShiftDown! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'th 9/18/2002 16:53'!\\nagainOrSame: useOldKeys many: many\\n\\t\\\"Subroutine of search: and again. If useOldKeys, use same FindText and ChangeText as before. If many is true, do it repeatedly. Created 1/26/96 sw by adding the many argument to #againOrSame.\\\"\\n\\n\\t| home indices wasTypedKey |\\n\\n\\thome _ self selectionInterval. \\\"what was selected when 'again' was invoked\\\"\\n\\n\\t\\\"If new keys are to be picked...\\\"\\n\\tuseOldKeys ifFalse: \\\"Choose as FindText...\\\"\\n\\t\\t[FindText _ UndoSelection. \\\"... the last thing replaced.\\\"\\n\\t\\t\\\"If the last command was in another paragraph, ChangeText is set...\\\"\\n\\t\\tparagraph == UndoParagraph ifTrue: \\\"... else set it now as follows.\\\"\\n\\t\\t\\t[UndoInterval ~= home ifTrue: [self selectInterval: UndoInterval]. \\\"blink\\\"\\n\\t\\t\\tChangeText _ ((UndoMessage sends: #undoCutCopy:) and: [self hasSelection])\\n\\t\\t\\t\\tifTrue: [FindText] \\\"== objects signal no model-locking by 'undo copy'\\\"\\n\\t\\t\\t\\tifFalse: [self selection]]]. \\\"otherwise, change text is last-replaced text\\\"\\n\\n\\t(wasTypedKey _ FindText size = 0)\\n\\t\\tifTrue: \\\"just inserted at a caret\\\"\\n\\t\\t\\t[home _ self selectionInterval.\\n\\t\\t\\tself replaceSelectionWith: self nullText. \\\"delete search key...\\\"\\n\\t\\t\\tFindText _ ChangeText] \\\"... and search for it, without replacing\\\"\\n\\t\\tifFalse: \\\"Show where the search will start\\\"\\n\\t\\t\\t[home last = self selectionInterval last ifFalse:\\n\\t\\t\\t\\t[self selectInterval: home]].\\n\\n\\t\\\"Find and Change, recording start indices in the array\\\"\\n\\tindices _ WriteStream on: (Array new: 20). \\\"an array to store change locs\\\"\\n\\t[(self againOnce: indices) & many] whileTrue. \\\"<-- this does the work\\\"\\n\\tindices isEmpty ifTrue: \\\"none found\\\"\\n\\t\\t[self flash.\\n\\t\\twasTypedKey ifFalse: [^self]].\\n\\n\\t(many | wasTypedKey) ifFalse: \\\"after undo, select this replacement\\\"\\n\\t\\t[home _ self startIndex to:\\n\\t\\t\\tself startIndex + UndoSelection size - 1].\\n\\n\\tself undoer: #undoAgain:andReselect:typedKey: with: indices contents with: home with: wasTypedKey! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'th 9/19/2002 18:16'!\\ncompleteSymbol: hintText lastOffering: selectorOrNil\\n\\t\\\"Invoked by Ctrl-q when there is only a caret.\\n\\t\\tDo selector-completion, i.e., try to replace the preceding identifier by a\\n\\t\\tselector that begins with those characters & has as many keywords as possible.\\n\\t \\tLeave two spaces after each colon (only one after the last) as space for\\n\\t\\targuments. Put the caret after the space after the first keyword. If the\\n\\t\\tuser types Ctrl-q again immediately, choose a different selector.\\n\\t Undoer: #undoQuery:lastOffering:; Redoer: itself.\\n\\tIf redoing, just redisplay the last offering, selector[OrNil].\\\"\\n\\n\\t| firstTime input prior caret newStart sym kwds outStream |\\n\\tfirstTime _ self isRedoing\\n\\t\\tifTrue: [prior _ sym _ selectorOrNil. true]\\n\\t\\tifFalse: [hintText isNil].\\n\\tfirstTime\\n\\t\\tifTrue: \\\"Initial Ctrl-q (or redo)\\\"\\t\\t\\t\\t\\t\\n\\t\\t\\t[caret _ self startIndex.\\n\\t\\t\\tself selectPrecedingIdentifier.\\n\\t\\t\\tinput _ self selection]\\n\\t\\tifFalse: \\\"Repeated Ctrl-q\\\"\\n\\t\\t\\t[caret _ UndoInterval first + hintText size.\\n\\t\\t\\tself selectInvisiblyFrom: UndoInterval first to: UndoInterval last.\\n\\t\\t\\tinput _ hintText.\\n\\t\\t\\tprior _ selectorOrNil].\\n\\t(input size ~= 0 and: [sym ~~ nil or:\\n\\t\\t\\t[(sym _ Symbol thatStarts: input string skipping: prior) ~~ nil]])\\n\\t\\tifTrue: \\\"found something to offer\\\"\\n\\t\\t\\t[newStart _ self startIndex.\\n\\t\\t\\toutStream _ WriteStream on: (String new: 2 * sym size).\\n\\t\\t\\t1 to: (kwds _ sym keywords) size do:\\n\\t\\t\\t\\t[:i |\\n\\t\\t\\t\\toutStream nextPutAll: (kwds at: i).\\n\\t\\t\\t\\ti = 1 ifTrue: [caret _ newStart + outStream contents size + 1].\\n\\t\\t\\t\\toutStream nextPutAll:\\n\\t\\t\\t\\t\\t(i < kwds size ifTrue: [' '] ifFalse: [' '])].\\n\\t\\t\\tUndoSelection _ input.\\n\\t\\t\\tself deselect; zapSelectionWith: outStream contents asText.\\n\\t\\t\\tself undoer: #undoQuery:lastOffering: with: input with: sym]\\n\\t\\tifFalse: \\\"no more matches\\\"\\n\\t\\t\\t[firstTime ifFalse: \\\"restore original text & set up for a redo\\\"\\n\\t\\t\\t\\t[UndoSelection _ self selection.\\n\\t\\t\\t\\tself deselect; zapSelectionWith: input.\\n\\t\\t\\t\\tself undoer: #completeSymbol:lastOffering: with: input with: prior.\\n\\t\\t\\t\\tUndone _ true].\\n\\t\\t\\tview flash].\\n\\tself selectAt: caret! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'th 9/18/2002 16:49'!\\nexchangeWith: prior\\n\\t\\\"If the prior selection is non-overlapping and legal, exchange the text of\\n\\t it with the current selection and leave the currently selected text selected\\n\\t in the location of the prior selection (or leave a caret after a non-caret if it was\\n\\t exchanged with a caret). If both selections are carets, flash & do nothing.\\n\\t Don't affect the paste buffer. Undoer: itself; Redoer: Undoer.\\\"\\n\\n\\t| start stop before selection priorSelection delta altInterval |\\n\\tstart _ self startIndex.\\n\\tstop _ self stopIndex - 1.\\n\\t((prior first <= prior last) | (start <= stop) \\\"Something to exchange\\\" and:\\n\\t\\t\\t[self isDisjointFrom: prior])\\n\\t\\tifTrue:\\n\\t\\t\\t[before _ prior last < start.\\n\\t\\t\\tselection _ self selection.\\n\\t\\t\\tpriorSelection _ paragraph text copyFrom: prior first to: prior last.\\n\\n\\t\\t\\tdelta _ before ifTrue: [0] ifFalse: [priorSelection size - selection size].\\n\\t\\t\\tself zapSelectionWith: priorSelection.\\n\\t\\t\\tself selectFrom: prior first + delta to: prior last + delta.\\n\\n\\t\\t\\tdelta _ before ifTrue: [stop - prior last] ifFalse: [start - prior first].\\n\\t\\t\\tself zapSelectionWith: selection.\\n\\t\\t\\taltInterval _ prior first + delta to: prior last + delta.\\n\\t\\t\\tself undoer: #exchangeWith: with: altInterval.\\n\\t\\t\\t\\\"If one was a caret, make it otherInterval & leave the caret after the other\\\"\\n\\t\\t\\tprior first > prior last ifTrue: [self selectAt: UndoInterval last + 1].\\n\\t\\t\\totherInterval _ start > stop\\n\\t\\t\\t\\tifTrue: [self selectAt: altInterval last + 1. UndoInterval]\\n\\t\\t\\t\\tifFalse: [altInterval]]\\n\\t\\tifFalse:\\n\\t\\t\\t[view flash]! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'raok 11/15/2001 14:01'!\\nexplainDelimitor: string\\n\\t\\\"Is string enclosed in delimitors?\\\"\\n\\n\\t| str |\\n\\t(string at: 1) isLetter ifTrue: [^nil]. \\\"only special chars\\\"\\n\\t(string first = string last) ifTrue:\\n\\t\\t\\t[^ self explainChar: (String with: string first)]\\n\\t\\tifFalse:\\n\\t\\t\\t[(string first = $( and: [string last = $)]) ifTrue:\\n\\t\\t\\t\\t[^ self explainChar: (String with: string first)].\\n\\t\\t\\t(string first = $[ and: [string last = $]]) ifTrue:\\n\\t\\t\\t\\t[^ self explainChar: (String with: string first)].\\n\\t\\t\\t(string first = ${ and: [string last = $}]) ifTrue:\\n\\t\\t\\t\\t[^ self explainChar: (String with: string first)].\\n\\t\\t\\t(string first = $< and: [string last = $>]) ifTrue:\\n\\t\\t\\t\\t[^ self explainChar: (String with: string first)].\\n\\t\\t\\t(string first = $# and: [string last = $)]) ifTrue:\\n\\t\\t\\t\\t[^'\\\"An instance of class Array. The Numbers, Characters, or Symbols between the parenthesis are the elements of the Array.\\\"'].\\n\\t\\t\\tstring first = $# ifTrue:\\n\\t\\t\\t\\t[^'\\\"An instance of class Symbol.\\\"'].\\n\\t\\t\\t(string first = $$ and: [string size = 2]) ifTrue:\\n\\t\\t\\t\\t[^'\\\"An instance of class Character. This one is the character ', (String with: string last), '.\\\"'].\\n\\t\\t\\t(string first = $:) ifTrue:\\n\\t\\t\\t\\t[str _ string allButFirst.\\n\\t\\t\\t\\t(self explainTemp: str) ~~ nil ifTrue:\\n\\t\\t\\t\\t\\t[^'\\\"An argument to this block will be bound to the temporary variable ',\\n\\t\\t\\t\\t\\t\\tstr, '.\\\"']]].\\n\\t^ nil! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'tk 7/14/2000 12:15'!\\ngetPluggableYellowButtonMenu: shiftKeyState\\n\\t| customMenu |\\n\\t^ ((view ~~ nil) and: [(customMenu _ view getMenu: shiftKeyState) notNil])\\n\\t\\tifTrue: [customMenu]\\n\\t\\tifFalse:\\n\\t\\t\\t[shiftKeyState\\n\\t\\t\\t\\tifTrue: [self class shiftedYellowButtonMenu]\\n\\t\\t\\t\\tifFalse: [self class yellowButtonMenu]]! !\\n\\n!ParagraphEditor methodsFor: 'private'!\\nindent: delta fromStream: inStream toStream: outStream\\n\\t\\\"Append the contents of inStream to outStream, adding or deleting delta or -delta\\n\\t tabs at the beginning, and after every CR except a final CR. Do not add tabs\\n\\t to totally empty lines, and be sure nothing but tabs are removed from lines.\\\"\\n\\n\\t| ch skip cr tab prev atEnd |\\n\\tcr _ Character cr.\\n\\ttab _ Character tab.\\n\\tdelta > 0\\n\\t\\tifTrue: \\\"shift right\\\"\\n\\t\\t\\t[prev _ cr.\\n\\t\\t\\t [ch _ (atEnd _ inStream atEnd) ifTrue: [cr] ifFalse: [inStream next].\\n\\t\\t\\t (prev == cr and: [ch ~~ cr]) ifTrue:\\n\\t\\t\\t\\t[delta timesRepeat: [outStream nextPut: tab]].\\n\\t\\t\\t atEnd]\\n\\t\\t\\t\\twhileFalse:\\n\\t\\t\\t\\t\\t[outStream nextPut: ch.\\n\\t\\t\\t\\t\\tprev _ ch]]\\n\\t\\tifFalse: \\\"shift left\\\"\\n\\t\\t\\t[skip _ delta. \\\"a negative number\\\"\\n\\t\\t\\t [inStream atEnd] whileFalse:\\n\\t\\t\\t\\t[((ch _ inStream next) == tab and: [skip < 0]) ifFalse:\\n\\t\\t\\t\\t\\t[outStream nextPut: ch].\\n\\t\\t\\t\\tskip _ ch == cr ifTrue: [delta] ifFalse: [skip + 1]]]! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'cmm 4/9/2004 14:00'!\\nisDisjointFrom: anInterval\\n\\t\\\"Answer true if anInterval is a caret not touching or within the current\\n\\t interval, or if anInterval is a non-caret that does not overlap the current\\n\\t selection.\\\"\\n\\n\\t| fudge |\\n\\tfudge _ anInterval size = 0 ifTrue: [1] ifFalse: [0].\\n\\t^(anInterval last + fudge < self startIndex or:\\n\\t\\t\\t[anInterval first - fudge >= self stopIndex])\\n! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'th 11/24/2002 17:13'!\\nlines\\n\\t\\\"Other than my member paragraph i compute lines based on logical\\n\\tline breaks, not optical (which may change due to line wrapping of the editor)\\\"\\n\\t| lines string index lineIndex stringSize |\\n\\tstring _ paragraph text string.\\n\\t\\\"Empty strings have no lines at all. Think of something.\\\"\\n\\tstring isEmpty ifTrue:[^{#(1 0 0)}].\\n\\tstringSize _ string size.\\n\\tlines _ OrderedCollection new: (string size // 15).\\n\\tindex _ 0.\\n\\tlineIndex _ 0.\\n\\tstring linesDo:[:line |\\n\\t\\tlines addLast: (Array\\n\\t\\t\\twith: (index _ index + 1)\\n\\t\\t\\twith: (lineIndex _ lineIndex + 1)\\n\\t\\t\\twith: (index _ index + line size min: stringSize))].\\n\\t\\\"Special workaround for last line empty.\\\"\\n\\tstring last == Character cr\\n\\t\\\"lines last last < stringSize\\\" ifTrue:[lines addLast:{stringSize +1. lineIndex+1. stringSize}].\\n\\t^lines! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'th 9/19/2002 19:57'!\\nmoveCursor: directionBlock forward: forward specialBlock: specialBlock\\n\\t\\\"Private - Move cursor.\\n\\tdirectionBlock is a one argument Block that computes the new Position from a given one.\\n\\tspecialBlock is a one argumentBlock that computes the new position from a given one under the alternate semantics.\\n\\tNote that directionBlock always is evaluated first.\\\"\\n\\t| shift indices newPosition |\\n\\tshift _ sensor leftShiftDown.\\n\\tindices _ self setIndices: shift forward: forward.\\n\\tnewPosition _ directionBlock value: (indices at: #moving).\\n\\t(sensor commandKeyPressed or:[sensor controlKeyPressed])\\n\\t\\tifTrue: [newPosition _ specialBlock value: newPosition].\\n\\tsensor keyboard.\\n\\tshift\\n\\t\\tifTrue: [self selectMark: (indices at: #fixed) point: newPosition - 1]\\n\\t\\tifFalse: [self selectAt: newPosition]! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'sma 12/15/1999 11:32'!\\nnextWord: position\\n\\t| string index |\\n\\tstring _ paragraph text string.\\n\\tindex _ position.\\n\\t[(index between: 1 and: string size) and: [(string at: index) isAlphaNumeric]]\\n\\t\\twhileTrue: [index _ index + 1].\\n\\t[(index between: 1 and: string size) and: [(string at: index) isAlphaNumeric not]]\\n\\t\\twhileTrue: [index _ index + 1].\\n\\t^ index! !\\n\\n!ParagraphEditor methodsFor: 'private'!\\nnullText\\n\\n\\t^Text string: '' emphasis: emphasisHere! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'th 9/20/2002 11:09'!\\npageHeight\\n\\t| howManyLines visibleHeight totalHeight ratio |\\n\\thowManyLines _ paragraph numberOfLines.\\n\\tvisibleHeight _ self visibleHeight.\\n\\ttotalHeight _ self totalTextHeight.\\n\\tratio _ visibleHeight / totalHeight.\\n\\t^(ratio * howManyLines) rounded - 2! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'sma 12/15/1999 11:33'!\\npreviousWord: position\\n\\t| string index |\\n\\tstring _ paragraph text string.\\n\\tindex _ position.\\n\\t[(index between: 1 and: string size) and: [(string at: index) isAlphaNumeric not]]\\n\\t\\twhileTrue: [index _ index - 1].\\n\\t[(index between: 1 and: string size) and: [(string at: index) isAlphaNumeric]]\\n\\t\\twhileTrue: [index _ index - 1].\\n\\t^ index + 1! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'BG 4/29/2004 11:19'!\\nsameColumn: start newLine: lineBlock forward: isForward\\n\\t\\\"Private - Compute the index in my text\\n\\twith the line number derived from lineBlock,\\\"\\n\\t\\\" a one argument block accepting the old line number.\\n\\tThe position inside the line will be preserved as good as possible\\\"\\n\\t\\\"The boolean isForward is used in the border case to determine if\\n\\twe should move to the beginning or the end of the line.\\\"\\n\\t| wordStyle column currentLine offsetAtTargetLine targetEOL lines numberOfLines currentLineNumber targetLineNumber |\\n\\twordStyle _ Preferences wordStyleCursorMovement.\\n\\twordStyle\\n\\t\\tifTrue: [\\n\\t\\t\\tlines _ paragraph lines.\\n\\t\\t\\tnumberOfLines := paragraph numberOfLines.\\n\\t\\t\\tcurrentLineNumber _ paragraph lineIndexOfCharacterIndex: start.\\n\\t\\t\\tcurrentLine _ lines at: currentLineNumber]\\n\\t\\tifFalse: [\\n\\t\\t\\tlines _ self lines.\\n\\t\\t\\tnumberOfLines := lines size.\\n\\t\\t\\tcurrentLine _ lines\\n\\t\\t\\t\\tdetect:[:lineInterval | lineInterval last >= start]\\n\\t\\t\\t\\tifNone:[lines last].\\n\\t\\t\\tcurrentLineNumber _ currentLine second].\\n\\tcolumn _ start - currentLine first.\\n\\ttargetLineNumber _ ((lineBlock value: currentLineNumber) max: 1) min: numberOfLines.\\n\\toffsetAtTargetLine _ (lines at: targetLineNumber) first.\\n\\ttargetEOL _ (lines at: targetLineNumber) last + (targetLineNumber == numberOfLines ifTrue:[1]ifFalse:[0]).\\n\\ttargetLineNumber == currentLineNumber\\n\\t\\\"No movement or movement failed. Move to beginning or end of line.\\\"\\n\\t\\tifTrue:[^isForward\\n\\t\\t\\tifTrue:[targetEOL]\\n\\t\\t\\tifFalse:[offsetAtTargetLine]].\\n\\t^offsetAtTargetLine + column min: targetEOL.! !\\n\\n!ParagraphEditor methodsFor: 'private' stamp: 'md 2/22/2006 21:17'!\\nsetIndices: shiftPressed forward: forward\\n\\t\\\"Little helper method that sets the moving and fixed indices according to some flags.\\\"\\n\\t| indices |\\n\\tindices _ Dictionary new.\\n\\tshiftPressed ifTrue: [\\n\\t\\t\\tindices at: #moving put: self pointIndex.\\n\\t\\t\\tindices at: #fixed put: self markIndex\\n\\t\\t] ifFalse: [\\n\\t\\t\\tforward\\n\\t\\t\\t\\tifTrue:[\\n\\t\\t\\t\\t\\tindices at: #moving put: self stopIndex.\\n\\t\\t\\t\\t\\tindices at: #fixed put: self startIndex.\\n\\t\\t\\t\\t] ifFalse: [\\n\\t\\t\\t\\t\\tindices at: #moving put: self startIndex.\\n\\t\\t\\t\\t\\tindices at: #fixed put: self stopIndex.\\n\\t\\t\\t\\t]\\n\\t\\t].\\n\\t^indices! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nParagraphEditor class\\n\\tinstanceVariableNames: ''!\\n\\n!ParagraphEditor class methodsFor: 'class initialization' stamp: 'sw 5/27/2000 00:03'!\\nabandonChangeText\\n\\t\\\"Call this to get out of the maddening situation in which the system keeps aggressively trying to do a replacement that you no longer wish to make, every time you make choose a new method in a list.\\\"\\n\\tChangeText _ FindText\\n\\n\\t\\\"ParagraphEditor abandonChangeText\\\"\\n! !\\n\\n!ParagraphEditor class methodsFor: 'class initialization' stamp: 'dgd 10/1/2004 11:00'!\\ninitialize\\n\\t\\\"Initialize the keyboard shortcut maps and the shared buffers \\n\\tfor copying text across views and managing again and undo. \\n\\tMarked this method changed to trigger reinit\\\"\\n\\t\\\"ParagraphEditor initialize\\\"\\n\\tUndoSelection := FindText := ChangeText := Text new.\\n\\tUndoMessage := Message selector: #halt.\\n\\tself initializeCmdKeyShortcuts.\\n\\tself initializeShiftCmdKeyShortcuts.! !\\n\\n!ParagraphEditor class methodsFor: 'class initialization' stamp: 'dgd 4/4/2006 16:07'!\\nshiftedYellowButtonMenu\\n\\t\\\"Answer the menu to be presented when the yellow button is pressed while the shift key is down\\\"\\n\\n\\t^ MenuMorph fromArray: {\\n\\t\\t{'explain' translated.\\t\\t\\t\\t\\t\\t#explain}.\\n\\t\\t{'pretty print' translated.\\t\\t\\t\\t\\t#prettyPrint}.\\n\\t\\t{'pretty print with color' translated.\\t\\t#prettyPrintWithColor}.\\n\\t\\t{'file it in (G)' translated.\\t\\t\\t\\t\\t#fileItIn}.\\n\\t\\t{'tiles from it' translated.\\t\\t\\t\\t\\t#selectionAsTiles}.\\n\\t\\t{'spawn (o)' translated.\\t\\t\\t\\t\\t\\t#spawn}.\\n\\t\\t#-.\\n\\t\\t{'browse it (b)' translated.\\t\\t\\t\\t\\t#browseIt}.\\n\\t\\t{'senders of it (n)' translated.\\t\\t\\t\\t#sendersOfIt}.\\n\\t\\t{'implementors of it (m)' translated.\\t\\t#implementorsOfIt}.\\n\\t\\t{'references to it (N)' translated.\\t\\t\\t#referencesToIt}.\\n\\t\\t#-.\\n\\t\\t{'selectors containing it (W)' translated.\\t#methodNamesContainingIt}.\\n\\t\\t{'method strings with it (E)' translated.\\t#methodStringsContainingit}.\\n\\t\\t{'method source with it' translated.\\t\\t#methodSourceContainingIt}.\\n\\t\\t{'class names containing it' translated.\\t#classNamesContainingIt}.\\n\\t\\t{'class comments with it' translated.\\t\\t#classCommentsContainingIt}.\\n\\t\\t{'change sets with it' translated.\\t\\t\\t#browseChangeSetsWithSelector}.\\n\\t\\t#-.\\n\\t\\t{'save contents to file...' translated.\\t\\t#saveContentsInFile}.\\n\\t\\t{'send contents to printer' translated.\\t#sendContentsToPrinter}.\\n\\t\\t{'printer setup' translated.\\t\\t\\t\\t\\t#printerSetup}.\\n\\t\\t#-.\\n\\t\\t{'special menu...' translated.\\t\\t\\t\\t#presentSpecialMenu}.\\n\\t\\t{'more...' translated.\\t\\t\\t\\t\\t\\t#yellowButtonActivity}.\\n\\t}\\n! !\\n\\n!ParagraphEditor class methodsFor: 'class initialization' stamp: 'dgd 9/1/2005 12:35'!\\nyellowButtonExpertMenu\\n\\n\\t^ MenuMorph fromArray: {\\n\\t\\t\\t{'set font... (k)' translated.\\t\\t\\t\\t#offerFontMenu}.\\n\\t\\t\\t{'set style... (K)' translated.\\t\\t\\t\\t#changeStyle}.\\n\\t\\t\\t{'set alignment... (u)' translated.\\t\\t#chooseAlignment}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'make project link (P)' translated.\\t#makeProjectLink}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'find...(f)' translated.\\t\\t\\t\\t\\t#find}.\\n\\t\\t\\t{'find again (g)' translated.\\t\\t\\t\\t#findAgain}.\\n\\t\\t\\t{'set search string (h)' translated.\\t\\t#setSearchString}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'do again (j)' translated.\\t\\t\\t\\t#again}.\\n\\t\\t\\t{'undo (z)' translated.\\t\\t\\t\\t\\t#undo}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'copy (c)' translated.\\t\\t\\t\\t\\t#copySelection}.\\n\\t\\t\\t{'cut (x)' translated.\\t\\t\\t\\t\\t\\t#cut}.\\n\\t\\t\\t{'paste (v)' translated.\\t\\t\\t\\t\\t#paste}.\\n\\t\\t\\t{'paste...' translated.\\t\\t\\t\\t\\t#pasteRecent}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'do it (d)' translated.\\t\\t\\t\\t\\t#doIt}.\\n\\t\\t\\t{'print it (p)' translated.\\t\\t\\t\\t#printIt}.\\n\\t\\t\\t{'inspect it (i)' translated.\\t\\t\\t\\t#inspectIt}.\\n\\t\\t\\t{'explore it (I)' translated.\\t\\t\\t\\t#exploreIt}.\\n\\t\\t\\t{'debug it' translated.\\t\\t\\t\\t\\t#debugIt}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'accept (s)' translated.\\t\\t\\t\\t\\t#accept}.\\n\\t\\t\\t{'cancel (l)' translated.\\t\\t\\t\\t\\t#cancel}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'show bytecodes' translated.\\t\\t\\t#showBytecodes}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'copy html' translated.\\t\\t\\t\\t\\t#copyHtml}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'more...' translated.\\t\\t\\t\\t\\t#shiftedTextPaneMenuRequest}.\\n\\t\\t}.\\n! !\\n\\n!ParagraphEditor class methodsFor: 'class initialization' stamp: 'dgd 10/1/2004 10:59'!\\nyellowButtonMenu\\n\\n\\t^ Preferences noviceMode\\n\\t\\t\\tifTrue: [self yellowButtonNoviceMenu]\\n\\t\\t\\tifFalse: [self yellowButtonExpertMenu]\\n! !\\n\\n!ParagraphEditor class methodsFor: 'class initialization' stamp: 'dgd 11/25/2004 17:33'!\\nyellowButtonNoviceMenu\\n\\n\\t^ MenuMorph fromArray: {\\n\\t\\t\\t{'set font... (k)' translated.\\t\\t\\t\\t#offerFontMenu}.\\n\\t\\t\\t{'set style... (K)' translated.\\t\\t\\t\\t#changeStyle}.\\n\\t\\t\\t{'set alignment... (u)' translated.\\t\\t#chooseAlignment}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'make project link (P)' translated.\\t#makeProjectLink}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'find...(f)' translated.\\t\\t\\t\\t\\t#find}.\\n\\t\\t\\t{'find again (g)' translated.\\t\\t\\t\\t#findAgain}.\\n\\t\\t\\t{'set search string (h)' translated.\\t\\t#setSearchString}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'do again (j)' translated.\\t\\t\\t\\t#again}.\\n\\t\\t\\t{'undo (z)' translated.\\t\\t\\t\\t\\t#undo}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'copy (c)' translated.\\t\\t\\t\\t\\t#copySelection}.\\n\\t\\t\\t{'cut (x)' translated.\\t\\t\\t\\t\\t\\t#cut}.\\n\\t\\t\\t{'paste (v)' translated.\\t\\t\\t\\t\\t#paste}.\\n\\t\\t\\t{'paste...' translated.\\t\\t\\t\\t\\t#pasteRecent}.\\n\\t\\t\\t#-.\\n\\t\\t\\t{'accept (s)' translated.\\t\\t\\t\\t\\t#accept}.\\n\\t\\t\\t{'cancel (l)' translated.\\t\\t\\t\\t\\t#cancel}.\\n\\t\\t}.\\n! !\\n\\n\\n!ParagraphEditor class methodsFor: 'instance creation' stamp: 'nk 9/3/2004 14:10'!\\nnew\\n\\t\\\"Answer a new instance of me with a null Paragraph to be edited.\\\"\\n\\n\\t| aParagraphEditor |\\n\\taParagraphEditor _ super new.\\n\\taParagraphEditor changeParagraph: '' asParagraph.\\n\\t^aParagraphEditor! !\\n\\n!ParagraphEditor class methodsFor: 'instance creation'!\\nnewParagraph: aParagraph \\n\\t\\\"Answer an instance of me with aParagraph as the text to be edited.\\\"\\n\\n\\t| aParagraphEditor |\\n\\taParagraphEditor _ super new.\\n\\taParagraphEditor initialize.\\n\\taParagraphEditor changeParagraph: aParagraph.\\n\\t^aParagraphEditor! !\\n\\n\\n!ParagraphEditor class methodsFor: 'keyboard shortcut tables' stamp: 'dgd 4/4/2006 16:04'!\\ninitializeCmdKeyShortcuts\\n\\t\\\"Initialize the (unshifted) command-key (or alt-key) shortcut table.\\\"\\n\\n\\t\\\"NOTE: if you don't know what your keyboard generates, use Sensor kbdTest\\\"\\n\\n\\t\\\"ParagraphEditor initialize\\\"\\n\\n\\t| cmdMap |\\n\\n\\tcmdMap := Array new: 256 withAll: #noop:.\\t\\\"use temp in case of a crash\\\"\\n\\n\\tcmdMap at: 1 + 1 put: #cursorHome:.\\t\\t\\t\\\"home key\\\"\\n\\tcmdMap at: 4 + 1 put: #cursorEnd:.\\t\\t\\t\\t\\\"end key\\\"\\n\\tcmdMap at: 8 + 1 put: #backspace:.\\t\\t\\t\\t\\\"ctrl-H or delete key\\\"\\n\\tcmdMap at: 11 + 1 put: #cursorPageUp:.\\t\\t\\\"page up key\\\"\\n\\tcmdMap at: 12 + 1 put: #cursorPageDown:.\\t\\\"page down key\\\"\\n\\tcmdMap at: 13 + 1 put: #crWithIndent:.\\t\\t\\t\\\"cmd-Return\\\"\\n\\tcmdMap at: 27 + 1 put: #offerMenuFromEsc:.\\t\\\"escape key\\\"\\n\\tcmdMap at: 28 + 1 put: #cursorLeft:.\\t\\t\\t\\\"left arrow key\\\"\\n\\tcmdMap at: 29 + 1 put: #cursorRight:.\\t\\t\\t\\\"right arrow key\\\"\\n\\tcmdMap at: 30 + 1 put: #cursorUp:.\\t\\t\\t\\t\\\"up arrow key\\\"\\n\\tcmdMap at: 31 + 1 put: #cursorDown:.\\t\\t\\t\\\"down arrow key\\\"\\n\\tcmdMap at: 32 + 1 put: #selectWord:.\\t\\t\\t\\\"space bar key\\\"\\n\\tcmdMap at: 127 + 1 put: #forwardDelete:.\\t\\t\\\"del key\\\"\\n\\n\\t'0123456789-=' \\n\\t\\tdo: [:char | cmdMap at: char asciiValue + 1 put: #changeEmphasis:].\\n\\n\\t'([{''\\\"<' do: [:char | cmdMap at: char asciiValue + 1 put: #enclose:].\\n\\n\\tcmdMap at: $, asciiValue + 1 put: #shiftEnclose:.\\n\\n\\t\\\"triplet = {character. comment selector. novice appropiated}\\\"\\n\\t#(\\n\\t\\t($a\\t\\t#selectAll:\\t\\t\\t\\ttrue)\\n\\t\\t($b\\t\\t#browseIt:\\t\\t\\t\\tfalse)\\n\\t\\t($c\\t\\t#copySelection:\\t\\t\\ttrue)\\n\\t\\t($d\\t\\t#doIt:\\t\\t\\t\\t\\t\\tfalse)\\n\\t\\t($e\\t\\t#exchange:\\t\\t\\t\\ttrue)\\n\\t\\t($f\\t\\t#find:\\t\\t\\t\\t\\t\\ttrue)\\n\\t\\t($g\\t\\t#findAgain:\\t\\t\\t\\ttrue)\\n\\t\\t($h\\t\\t#setSearchString:\\t\\ttrue)\\n\\t\\t($i\\t\\t#inspectIt:\\t\\t\\t\\tfalse)\\n\\t\\t($j\\t\\t#doAgainOnce:\\t\\t\\ttrue)\\n\\t\\t($k\\t\\t#offerFontMenu:\\t\\ttrue)\\n\\t\\t($l\\t\\t#cancel:\\t\\t\\t\\t\\ttrue)\\n\\t\\t($m\\t#implementorsOfIt:\\t\\tfalse)\\n\\t\\t($n\\t\\t#sendersOfIt:\\t\\t\\tfalse)\\n\\t\\t($o\\t\\t#spawnIt:\\t\\t\\t\\tfalse)\\n\\t\\t($p\\t\\t#printIt:\\t\\t\\t\\t\\tfalse)\\n\\t\\t($q\\t\\t#querySymbol:\\t\\t\\tfalse)\\n\\t\\t($s\\t\\t#save:\\t\\t\\t\\t\\ttrue)\\n\\t\\t($t\\t\\t#tempCommand:\\t\\tfalse)\\n\\t\\t($u\\t\\t#align:\\t\\t\\t\\t\\ttrue)\\n\\t\\t($v\\t\\t#paste:\\t\\t\\t\\t\\ttrue)\\n\\t\\t($w\\t#backWord:\\t\\t\\t\\ttrue)\\n\\t\\t($x\\t\\t#cut:\\t\\t\\t\\t\\t\\ttrue)\\n\\t\\t($y\\t\\t#swapChars:\\t\\t\\t\\ttrue)\\n\\t\\t($z\\t\\t#undo:\\t\\t\\t\\t\\ttrue)\\n\\t)\\n\\t\\tselect:[:triplet | Preferences noviceMode not or:[triplet third]]\\n\\t\\tthenDo:[:triplet | cmdMap at: triplet first asciiValue + 1 put: triplet second].\\n\\n\\tCmdActions := cmdMap.\\n! !\\n\\n!ParagraphEditor class methodsFor: 'keyboard shortcut tables' stamp: 'dgd 10/4/2004 13:53'!\\ninitializeShiftCmdKeyShortcuts \\n\\t\\\"Initialize the shift-command-key (or control-key) shortcut table.\\\"\\n\\t\\\"NOTE: if you don't know what your keyboard generates, use Sensor kbdTest\\\"\\n\\t\\\"wod 11/3/1998: Fix setting of cmdMap for shifted keys to actually use the \\n\\tcapitalized versions of the letters.\\n\\tTPR 2/18/99: add the plain ascii values back in for those VMs that don't return the shifted values.\\\"\\n\\n\\t| cmdMap |\\n\\n\\t\\\"shift-command and control shortcuts\\\"\\n\\tcmdMap _ Array new: 256 withAll: #noop:. \\\"use temp in case of a crash\\\"\\n\\n\\tcmdMap at: ( 1 + 1) put: #cursorHome:.\\t\\t\\t\\t\\\"home key\\\"\\n\\tcmdMap at: ( 4 + 1) put: #cursorEnd:.\\t\\t\\t\\t\\\"end key\\\"\\n\\tcmdMap at: ( 8 + 1) put: #forwardDelete:.\\t\\t\\t\\\"ctrl-H or delete key\\\"\\n\\tcmdMap at: (11 + 1) put: #cursorPageUp:.\\t\\t\\t\\\"page up key\\\"\\n\\tcmdMap at: (12 + 1) put: #cursorPageDown:.\\t\\t\\\"page down key\\\"\\n\\tcmdMap at: (13 + 1) put: #crWithIndent:.\\t\\t\\t\\\"ctrl-Return\\\"\\n\\tcmdMap at: (27 + 1) put: #offerMenuFromEsc:.\\t\\\"escape key\\\"\\n\\tcmdMap at: (28 + 1) put: #cursorLeft:.\\t\\t\\t\\t\\\"left arrow key\\\"\\n\\tcmdMap at: (29 + 1) put: #cursorRight:.\\t\\t\\t\\t\\\"right arrow key\\\"\\n\\tcmdMap at: (30 + 1) put: #cursorUp:.\\t\\t\\t\\t\\\"up arrow key\\\"\\n\\tcmdMap at: (31 + 1) put: #cursorDown:.\\t\\t\\t\\\"down arrow key\\\"\\n\\tcmdMap at: (32 + 1) put: #selectWord:.\\t\\t\\t\\t\\\"space bar key\\\"\\n\\tcmdMap at: (45 + 1) put: #changeEmphasis:.\\t\\t\\\"cmd-sh-minus\\\"\\n\\tcmdMap at: (61 + 1) put: #changeEmphasis:.\\t\\t\\\"cmd-sh-plus\\\"\\n\\tcmdMap at: (127 + 1) put: #forwardDelete:.\\t\\t\\\"del key\\\"\\n\\n\\t\\\"Note: Command key overrides shift key, so, for example, cmd-shift-9 produces $9 not $(\\\"\\n\\t'9[,''' do: [ :char | cmdMap at: (char asciiValue + 1) put: #shiftEnclose: ].\\t\\\"({< and double-quote\\\"\\n\\t\\\"Note: Must use cmd-9 or ctrl-9 to get '()' since cmd-shift-9 is a Mac FKey command.\\\"\\n\\n\\t\\\"NB: sw 12/9/2001 commented out the idiosyncratic line just below, which was grabbing shift-esc in the text editor and hence which argued with the wish to have shift-esc be a universal gesture for escaping the local context and calling up the desktop menu.\\\" \\n\\t\\\"cmdMap at: (27 + 1) put: #shiftEnclose:.\\\" \\t\\\"ctrl-[\\\"\\n\\n\\t\\\"'\\\"\\\"''(' do: [ :char | cmdMap at: (char asciiValue + 1) put: #enclose:].\\\"\\n\\n\\t\\\"triplet = {character. comment selector. novice appropiated}\\\"\\n\\t#(\\n\\t\\t($a\\t\\targAdvance:\\t\\t\\t\\t\\t\\tfalse)\\n\\t\\t($b\\t\\tbrowseItHere:\\t\\t\\t\\t\\tfalse)\\n\\t\\t($c\\t\\tcompareToClipboard:\\t\\t\\tfalse)\\n\\t\\t($d\\t\\tduplicate:\\t\\t\\t\\t\\t\\t\\ttrue)\\n\\t\\t($e\\t\\tmethodStringsContainingIt:\\tfalse)\\n\\t\\t($f\\t\\tdisplayIfFalse:\\t\\t\\t\\t\\tfalse)\\n\\t\\t($g\\t\\tfileItIn:\\t\\t\\t\\t\\t\\t\\tfalse)\\n\\t\\t($h\\t\\tcursorTopHome:\\t\\t\\t\\t\\ttrue)\\n\\t\\t($i\\t\\texploreIt:\\t\\t\\t\\t\\t\\t\\tfalse)\\n\\t\\t($j\\t\\tdoAgainMany:\\t\\t\\t\\t\\ttrue)\\n\\t\\t($k\\t\\tchangeStyle:\\t\\t\\t\\t\\t\\ttrue)\\n\\t\\t($l\\t\\toutdent:\\t\\t\\t\\t\\t\\t\\ttrue)\\n\\t\\t($m\\tselectCurrentTypeIn:\\t\\t\\ttrue)\\n\\t\\t($n\\t\\treferencesToIt:\\t\\t\\t\\t\\tfalse)\\n\\t\\t($p\\t\\tmakeProjectLink:\\t\\t\\t\\ttrue)\\n\\t\\t($r\\t\\tindent:\\t\\t\\t\\t\\t\\t\\ttrue)\\n\\t\\t($s\\t\\tsearch:\\t\\t\\t\\t\\t\\t\\ttrue)\\n\\t\\t($t\\t\\tdisplayIfTrue:\\t\\t\\t\\t\\tfalse)\\n\\t\\t($u\\t\\tchangeLfToCr:\\t\\t\\t\\t\\tfalse)\\n\\t\\t($v\\t\\tpasteInitials:\\t\\t\\t\\t\\t\\tfalse)\\n\\t\\t($w\\tmethodNamesContainingIt:\\tfalse)\\n\\t\\t($x\\t\\tmakeLowercase:\\t\\t\\t\\t\\ttrue)\\n\\t\\t($y\\t\\tmakeUppercase:\\t\\t\\t\\t\\ttrue)\\n\\t\\t($z\\t\\tmakeCapitalized:\\t\\t\\t\\ttrue)\\n\\t)\\n\\t\\tselect:[:triplet | Preferences noviceMode not or:[triplet third]]\\n\\t\\tthenDo:[:triplet |\\n\\t\\t\\tcmdMap at: (triplet first asciiValue + 1) put: triplet second.\\t\\t\\\"plain keys\\\"\\n\\t\\t\\tcmdMap at: (triplet first asciiValue - 32 + 1) put: triplet second.\\t\\t\\\"shifted keys\\\"\\n\\t\\t\\tcmdMap at: (triplet first asciiValue - 96 + 1) put: triplet second.\\t\\t\\\"ctrl keys\\\"\\n\\t\\t].\\n\\n\\tShiftCmdActions _ cmdMap! !\\n\\n!ParagraphEditor class methodsFor: 'keyboard shortcut tables' stamp: 'sps 7/24/2003 17:25'!\\nmultiRedoOverride\\n\\\"Call this to set meta-r to perform the multilevel redo (or tweak the code below to have it bound to some other key sequence).\\\"\\n\\n\\\"\\nParagraphEditor multiRedoOverride.\\n\\\"\\n\\tCmdActions at: $r asciiValue + 1 put: #multiRedo: \\n! !\\n\\n!ParagraphEditor class methodsFor: 'keyboard shortcut tables' stamp: 'sbw 10/8/1999 21:42'!\\nspecialShiftCmdKeys\\n\\n\\\"Private - return array of key codes that represent single keys acting\\nas if shift-command were also being pressed\\\"\\n\\n^#(\\n\\t1\\t\\\"home\\\"\\n\\t3\\t\\\"enter\\\"\\n\\t4\\t\\\"end\\\"\\n\\t8\\t\\\"backspace\\\"\\n\\t11\\t\\\"page up\\\"\\n\\t12\\t\\\"page down\\\"\\n\\t27\\t\\\"escape\\\"\\n\\t28\\t\\\"left arrow\\\"\\n\\t29\\t\\\"right arrow\\\"\\n\\t30\\t\\\"up arrow\\\"\\n\\t31\\t\\\"down arrow\\\"\\n\\t127\\t\\\"delete\\\"\\n\\t)! !\\nTileMorph subclass: #ParameterTile\\n\\tinstanceVariableNames: 'scriptEditor'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting Tiles'!\\n!ParameterTile commentStamp: '<historical>' prior: 0!\\nRepresents a parameter in a user-defined script in \\\"classic\\\" tile-scripting. The type of a script's parameter is declared in the ScriptEditor for the script, and a parameter tile gets its type from the script. But because the user can change the parameter type *after* having created parameter tiles, we can later have type mismatches. Which however we at least deal with reasonably cleverly.!\\n\\n\\n!ParameterTile methodsFor: 'access' stamp: 'sw 3/15/2005 21:45'!\\nisBoolean \\n\\t\\\"Answer whether the receiver's type is inherently boolean\\\"\\n\\n\\t^ self scriptEditor typeForParameter == #Boolean! !\\n\\n!ParameterTile methodsFor: 'access' stamp: 'sw 3/15/2005 22:36'!\\nrowOfRightTypeFor: aLayoutMorph forActor: aPlayer\\n\\t\\\"Answer a phrase of the right type for the putative container\\\"\\n\\n\\t| aTemporaryViewer aPhrase |\\n\\taLayoutMorph demandsBoolean ifTrue:\\n\\t\\t[aTemporaryViewer _ CategoryViewer new invisiblySetPlayer: aPlayer.\\n\\t\\taPhrase _ aTemporaryViewer booleanPhraseFromPhrase: self.\\n\\t\\taPhrase justGrabbedFromViewer: false.\\n\\t\\t^ aPhrase].\\n\\t^ self! !\\n\\n!ParameterTile methodsFor: 'access' stamp: 'sw 1/18/2004 22:12'!\\nscriptEditor\\n\\t\\\"Answer the receiver's script editor. The slightly strange code here is in order to contend with the unusual situation where a parameter tile obtained from one script editor is later dropped into a different script editor. As long as the parameter tile is *in* a script editor, that containing scriptEditor is the one; if it is *not*, then we use the last known one\\\"\\n\\n\\t| aScriptEditor |\\n\\t^ (aScriptEditor _ self outermostMorphThat: [:m | m isKindOf: ScriptEditorMorph])\\n\\t\\tifNotNil:\\n\\t\\t\\t[scriptEditor _ aScriptEditor]\\n\\t\\tifNil:\\n\\t\\t\\t[scriptEditor]! !\\n\\n\\n!ParameterTile methodsFor: 'accessing' stamp: 'sw 7/18/2002 02:45'!\\nresultType\\n\\t\\\"Answer the result type of the receiver\\\"\\n\\n\\t^ self scriptEditor typeForParameter! !\\n\\n\\n!ParameterTile methodsFor: 'code generation' stamp: 'yo 12/20/2003 02:49'!\\nstoreCodeOn: aStream indent: tabCount\\n\\t\\\"Store code on the stream\\\"\\n \\n\\t| myTypeString |\\n\\tmyTypeString _ self resultType.\\n\\t(self scriptEditor hasParameter and: [self scriptEditor typeForParameter = myTypeString])\\n\\t\\tifTrue:\\n\\t\\t\\t[aStream nextPutAll: 'parameter']\\n\\t\\tifFalse:\\n\\t\\t\\t[\\\"This script no longer bears a parameter, yet there's an orphaned Parameter tile in it\\\"\\n\\t\\t\\taStream nextPutAll: '(self defaultValueOfType: #', myTypeString, ')']! !\\n\\n\\n!ParameterTile methodsFor: 'initialization' stamp: 'yo 3/14/2005 08:01'!\\nforScriptEditor: aScriptEditor\\n\\t\\\"Make the receiver be associated with the given script editor\\\"\\n\\n\\tscriptEditor _ aScriptEditor.\\n\\tself line1: aScriptEditor typeForParameter translated.! !\\n\\n!ParameterTile methodsFor: 'initialization' stamp: 'dgd 3/7/2003 15:45'!\\ninitialize\\n\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\\"\\\"\\n\\tself typeColor: Color red! !\\n\\n\\n!ParameterTile methodsFor: 'miscellaneous' stamp: 'sw 3/15/2005 21:55'!\\nassociatedPlayer\\n\\t\\\"Answer the player with which the receiver is associated\\\"\\n\\n\\t^ self scriptEditor playerScripted! !\\n\\n!ParameterTile methodsFor: 'miscellaneous' stamp: 'sw 3/15/2005 22:37'!\\nbooleanComparatorPhrase\\n\\t\\\"Answer a boolean-valued phrase derived from a retriever (e.g. 'car's heading'); this is in order to assure that tiles laid down in a TEST area will indeed produce a boolean result\\\"\\n\\n\\t| outerPhrase rel retrieverType |\\n\\tretrieverType _ self resultType.\\n\\n\\trel _ (Vocabulary vocabularyForType: retrieverType) comparatorForSampleBoolean.\\n\\touterPhrase _ PhraseTileMorph new setOperator: rel type: #Boolean rcvrType: retrieverType argType: retrieverType.\\n\\touterPhrase firstSubmorph addMorph: self.\\n\\touterPhrase submorphs last addMorph: (ScriptingSystem tileForArgType: retrieverType).\\n\\n\\touterPhrase submorphs second submorphs last setBalloonText: (ScriptingSystem helpStringForOperator: rel). \\n\\t^ outerPhrase! !\\n\\n!ParameterTile methodsFor: 'miscellaneous' stamp: 'sw 3/15/2005 22:41'!\\ntileRows\\n\\t\\\"Answer a list of tile rows -- in this case exactly one row -- representing the receiver.\\\"\\n\\n\\t^ Array with: (Array with: self)! !\\n\\n\\n!ParameterTile methodsFor: 'type' stamp: 'sw 7/22/2002 17:48'!\\nassureTypeStillValid\\n\\t\\\"Consider the possibility that the parameter type of my surrounding method has changed and that hence I no longer represent a possible value for the parameter of the script. If this condition obtains, then banish me in favor of a default literal tile of the correct type\\\"\\n\\n\\t(self ownerThatIsA: TilePadMorph) ifNotNilDo:\\n\\t\\t[:aPad | aPad type = self scriptEditor typeForParameter ifFalse:\\n\\t\\t\\t[aPad setToBearDefaultLiteral]]! !\\nObject subclass: #ParseNode\\n\\tinstanceVariableNames: 'comment pc'\\n\\tclassVariableNames: 'Bfp BtpLong CodeBases CodeLimits DblExtDoAll Dup EndMethod EndRemote Jmp JmpLimit JmpLong LdFalse LdInstLong LdInstType LdLitIndType LdLitType LdMinus1 LdNil LdSelf LdSuper LdTempType LdThisContext LdTrue LoadLong LongLongDoAll NodeFalse NodeNil NodeSelf NodeSuper NodeThisContext NodeTrue Pop Send SendLimit SendLong SendLong2 SendPlus SendType ShortStoP StdLiterals StdSelectors StdVariables Store StorePop'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Compiler-ParseNodes'!\\n!ParseNode commentStamp: '<historical>' prior: 0!\\nThis superclass of most compiler/decompiler classes declares common class variables, default messages, and the code emitters for jumps. Some of the class variables are initialized here; the rest are initialized in class VariableNode.!\\n\\n\\n!ParseNode methodsFor: 'code generation'!\\nemitBranchOn:\\ncondition dist: dist pop: stack on: strm\\n\\tstack pop: 1.\\n\\tdist = 0 ifTrue: [^ strm nextPut: Pop].\\n\\tcondition\\n\\t\\tifTrue: [self emitLong: dist code: BtpLong on: strm]\\n\\t\\tifFalse: [self emitShortOrLong: dist code: Bfp on: strm]! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nemitForEffect: stack on: strm\\n\\n\\tself emitForValue: stack on: strm.\\n\\tstrm nextPut: Pop.\\n\\tstack pop: 1! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nemitForReturn: stack on: strm\\n\\n\\tself emitForValue: stack on: strm.\\n\\tstrm nextPut: EndMethod! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nemitJump: dist on: strm\\n\\n\\tdist = 0 ifFalse: [self emitShortOrLong: dist code: Jmp on: strm]! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nemitLong: dist code: longCode on: aStream \\n\\t\\\"Force a two-byte jump.\\\"\\n\\t| code distance |\\n\\tcode _ longCode.\\n\\tdistance _ dist.\\n\\tdistance < 0\\n\\t\\tifTrue: \\n\\t\\t\\t[distance _ distance + 1024.\\n\\t\\t\\tcode _ code - 4]\\n\\t\\tifFalse: \\n\\t\\t\\t[distance > 1023 ifTrue: [distance _ -1]].\\n\\tdistance < 0\\n\\t\\tifTrue: \\n\\t\\t\\t[self error: 'A block compiles more than 1K bytes of code']\\n\\t\\tifFalse: \\n\\t\\t\\t[aStream nextPut: distance // 256 + code.\\n\\t\\t\\taStream nextPut: distance \\\\\\\\ 256]! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nemitShortOrLong: dist code: shortCode on: strm\\n\\t(1 <= dist and: [dist <= JmpLimit])\\n\\t\\tifTrue: [strm nextPut: shortCode + dist - 1]\\n\\t\\tifFalse: [self emitLong: dist code: shortCode + (JmpLong-Jmp) on: strm]! !\\n\\n!ParseNode methodsFor: 'code generation' stamp: 'nk 7/10/2004 10:04'!\\npc\\n\\t\\\"Used by encoder source mapping.\\\"\\n\\n\\t^pc ifNil: [ 0 ]\\n! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nsizeBranchOn: condition dist: dist\\n\\tdist = 0 ifTrue: [^1].\\n\\t^ condition\\n\\t\\tifTrue: [2] \\\"Branch on true is always 2 bytes\\\"\\n\\t\\tifFalse: [self sizeShortOrLong: dist]! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nsizeForEffect: encoder\\n\\n\\t^(self sizeForValue: encoder) + 1! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nsizeForReturn: encoder\\n\\n\\t^(self sizeForValue: encoder) + 1! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nsizeJump: dist\\n\\n\\tdist = 0 ifTrue: [^0].\\n\\t^self sizeShortOrLong: dist! !\\n\\n!ParseNode methodsFor: 'code generation'!\\nsizeShortOrLong: dist\\n\\n\\t(1 <= dist and: [dist <= JmpLimit])\\n\\t\\tifTrue: [^1].\\n\\t^2! !\\n\\n\\n!ParseNode methodsFor: 'comment'!\\ncomment\\n\\n\\t^comment! !\\n\\n!ParseNode methodsFor: 'comment'!\\ncomment: newComment\\n\\n\\tcomment _ newComment! !\\n\\n\\n!ParseNode methodsFor: 'converting'!\\nasReturnNode\\n\\n\\t^ReturnNode new expr: self! !\\n\\n\\n!ParseNode methodsFor: 'encoding'!\\nencodeSelector: selector\\n\\n\\t^nil! !\\n\\n\\n!ParseNode methodsFor: 'printing' stamp: 'tk 10/16/2000 13:57'!\\nnodePrintOn: aStrm indent: nn\\n\\t| var aaStrm myLine |\\n\\t\\\"Show just the sub nodes and the code.\\\"\\n\\n\\t(aaStrm _ aStrm) ifNil: [aaStrm _ WriteStream on: (String new: 500)].\\n\\tnn timesRepeat: [aaStrm tab].\\n\\taaStrm nextPutAll: self class name; space.\\n\\tmyLine _ self printString copyWithout: Character cr.\\n\\tmyLine _ myLine copyFrom: 1 to: (myLine size min: 70).\\n\\taaStrm nextPutAll: myLine; cr.\\n\\t1 to: self class instSize do: [:ii | \\n\\t\\tvar _ self instVarAt: ii.\\n\\t\\t(var respondsTo: #asReturnNode) ifTrue: [var nodePrintOn: aaStrm indent: nn+1]].\\n\\t1 to: self class instSize do: [:ii | \\n\\t\\tvar _ self instVarAt: ii.\\n\\t\\t(var isKindOf: SequenceableCollection) ifTrue: [\\n\\t\\t\\t\\tvar do: [:aNode | \\n\\t\\t\\t\\t\\t(aNode respondsTo: #asReturnNode) ifTrue: [\\n\\t\\t\\t\\t\\t\\taNode nodePrintOn: aaStrm indent: nn+1]]]].\\n\\t^ aaStrm\\n! !\\n\\n!ParseNode methodsFor: 'printing' stamp: 'ab 7/13/2004 13:46'!\\nprintCommentOn: aStream indent: indent \\n\\t| thisComment |\\n\\tself comment == nil ifTrue: [^ self].\\n\\taStream withStyleFor: #comment\\n\\t\\tdo: [1 to: self comment size do: \\n\\t\\t\\t\\t[:index | \\n\\t\\t\\t\\tindex > 1 ifTrue: [aStream crtab: indent].\\n\\t\\t\\t\\taStream nextPut: $\\\".\\n\\t\\t\\t\\tthisComment _ self comment at: index.\\n\\t\\t\\t\\tself printSingleComment: thisComment\\n\\t\\t\\t\\t\\ton: aStream\\n\\t\\t\\t\\t\\tindent: indent.\\n\\t\\t\\t\\taStream nextPut: $\\\"]].\\n\\tself comment: nil! !\\n\\n!ParseNode methodsFor: 'printing' stamp: 'md 8/15/2005 11:02'!\\nprintOn: aStream \\n\\t\\\"Refer to the comment in Object|printOn:.\\\"\\n\\n\\taStream nextPutAll: '{'.\\n\\taStream nextPutAll: ((ColoredCodeStream contents: [:strm | self printOn: strm indent: 0])\\n\\t\\t\\t\\t\\t\\t\\tasString).\\n\\taStream nextPutAll: '}'! !\\n\\n!ParseNode methodsFor: 'printing'!\\nprintOn: aStream indent: anInteger \\n\\t\\\"If control gets here, avoid recursion loop.\\\"\\n\\n\\tsuper printOn: aStream! !\\n\\n!ParseNode methodsFor: 'printing'!\\nprintOn: aStream indent: level precedence: p\\n\\n\\tself printOn: aStream indent: level! !\\n\\n!ParseNode methodsFor: 'printing' stamp: 'ms 8/1/2006 16:47'!\\nshortPrintOn: aStream \\n\\tself printOn: aStream indent: 0! !\\n\\n\\n!ParseNode methodsFor: 'testing'!\\nassignmentCheck: encoder at: location\\n\\t\\\"For messageNodes masquerading as variables for the debugger.\\n\\tFor now we let this through - ie we allow stores ev\\n\\tinto args. Should check against numArgs, though.\\\"\\n\\t^ -1! !\\n\\n!ParseNode methodsFor: 'testing'!\\ncanBeSpecialArgument\\n\\t\\\"Can I be an argument of (e.g.) ifTrue:?\\\"\\n\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing'!\\ncanCascade\\n\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisArg\\n\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisComplex\\n\\t\\\"Used for pretty printing to determine whether to start a new line\\\"\\n\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisConstantNumber \\\"Overridden in LiteralNode\\\"\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing' stamp: 'md 1/20/2006 16:22'!\\nisDoIt\\n\\t\\\"polymorphic with RBNodes; called by debugger\\\"\\n\\n\\t^ false! !\\n\\n!ParseNode methodsFor: 'testing' stamp: 'ls 1/29/2004 21:11'!\\nisJust: node\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing' stamp: 'di 4/5/2000 11:14'!\\nisLiteral\\n\\n\\t^ false! !\\n\\n!ParseNode methodsFor: 'testing' stamp: 'md 7/27/2006 19:14'!\\nisMessage\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisMessage: selSymbol receiver: rcvrPred arguments: argsPred\\n\\t\\\"See comment in MessageNode.\\\"\\n\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisReturnSelf\\n\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisReturningIf\\n\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing' stamp: 'tk 8/2/1999 18:39'!\\nisSelfPseudoVariable\\t\\n\\t\\\"Overridden in VariableNode.\\\"\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisSpecialConstant\\n\\t^ false! !\\n\\n!ParseNode methodsFor: 'testing' stamp: 'di 10/12/1999 15:28'!\\nisTemp\\n\\t^ false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisUndefTemp\\n\\t^ false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisUnusedTemp\\n\\t^ false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nisVariableReference\\n\\n\\t^false! !\\n\\n!ParseNode methodsFor: 'testing'!\\nnowHasDef \\\"Ignored in all but VariableNode\\\"! !\\n\\n!ParseNode methodsFor: 'testing'!\\nnowHasRef \\\"Ignored in all but VariableNode\\\"! !\\n\\n!ParseNode methodsFor: 'testing'!\\ntoDoIncrement: ignored\\n\\t\\\"Only meant for Messages or Assignments - else return nil\\\"\\n\\t^ nil! !\\n\\n\\n!ParseNode methodsFor: '*eToys-tiles' stamp: 'ab 7/13/2004 13:47'!\\naddCommentToMorph: aMorph\\n\\t| row |\\n\\t(self comment isNil or: [self comment isEmpty]) ifTrue: [^ self].\\n\\trow _ aMorph addTextRow:\\n\\t\\t(String streamContents: [:strm | self printCommentOn: strm indent: 1]).\\n\\trow firstSubmorph color: (SyntaxMorph translateColor: #comment).\\n\\trow parseNode: (self as: CommentNode).\\n! !\\n\\n!ParseNode methodsFor: '*eToys-tiles' stamp: 'RAA 8/24/1999 12:24'!\\nasMorphicSyntaxIn: parent\\n\\n\\t| morph |\\n\\t\\\"Default for missing implementations\\\"\\n\\n\\tmorph _ parent addColumn: #error on: self.\\n\\tmorph addTextRow: self class printString.\\n\\t^morph\\n\\t\\n\\n! !\\n\\n!ParseNode methodsFor: '*eToys-tiles' stamp: 'RAA 8/24/1999 13:06'!\\ncurrentValueIn: aContext\\n\\n\\t^nil! !\\n\\n!ParseNode methodsFor: '*eToys-tiles' stamp: 'RAA 8/24/1999 18:18'!\\nexplanation\\n\\n\\t^self class printString! !\\n\\n\\n!ParseNode methodsFor: 'private' stamp: 'ls 1/29/2004 21:17'!\\nifNilReceiver\\n\\t\\\"assuming this object is the receiver of an ifNil:, what object is being asked about?\\\"\\n\\t^self! !\\n\\n!ParseNode methodsFor: 'private' stamp: 'sma 5/28/2000 10:47'!\\nnextWordFrom: aStream setCharacter: aBlock\\n\\t| outStream char |\\n\\toutStream _ WriteStream on: (String new: 16).\\n\\t[(aStream peekFor: Character space) \\n\\t\\tor: [aStream peekFor: Character tab]] whileTrue.\\n\\t[aStream atEnd\\n\\t\\tor:\\n\\t\\t\\t[char _ aStream next.\\n\\t\\t\\tchar = Character cr or: [char = Character space]]]\\n\\t\\twhileFalse: [outStream nextPut: char].\\n\\taBlock value: char.\\n\\t^ outStream contents! !\\n\\n!ParseNode methodsFor: 'private' stamp: 'nk 7/11/2004 13:39'!\\nprintSingleComment: aString on: aStream indent: indent \\n\\t\\\"Print the comment string, assuming it has been indented indent tabs.\\n\\tBreak the string at word breaks, given the widths in the default\\n\\tfont, at 450 points.\\\"\\n\\n\\t| readStream word position lineBreak font wordWidth tabWidth spaceWidth lastChar |\\n\\treadStream _ ReadStream on: aString.\\n\\tfont _ TextStyle default defaultFont.\\n\\ttabWidth _ TextConstants at: #DefaultTab.\\n\\tspaceWidth _ font widthOf: Character space.\\n\\tposition _ indent * tabWidth.\\n\\tlineBreak _ 450.\\n\\t[readStream atEnd]\\n\\t\\twhileFalse: \\n\\t\\t\\t[word _ self nextWordFrom: readStream setCharacter: [:lc | lastChar _ lc].\\n\\t\\t\\twordWidth _ word inject: 0 into: [:width :char | width + (font widthOf: char)].\\n\\t\\t\\tposition _ position + wordWidth.\\n\\t\\t\\tposition > lineBreak\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[aStream skip: -1; crtab: indent.\\n\\t\\t\\t\\t\\tposition _ indent * tabWidth + wordWidth + spaceWidth.\\n\\t\\t\\t\\t\\tlastChar = Character cr\\n\\t\\t\\t\\t\\t\\tifTrue: [[readStream peekFor: Character tab] whileTrue].\\n\\t\\t\\t\\t\\tword isEmpty ifFalse: [aStream nextPutAll: word; space]]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[aStream nextPutAll: word.\\n\\t\\t\\t\\t\\treadStream atEnd\\n\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t[position _ position + spaceWidth.\\n\\t\\t\\t\\t\\t\\t\\taStream space].\\n\\t\\t\\t\\t\\tlastChar = Character cr\\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[aStream skip: -1; crtab: indent.\\n\\t\\t\\t\\t\\t\\t\\tposition _ indent * tabWidth.\\n\\t\\t\\t\\t\\t\\t\\t[readStream peekFor: Character tab] whileTrue]]]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nParseNode class\\n\\tinstanceVariableNames: ''!\\n\\n!ParseNode class methodsFor: 'class initialization' stamp: 'ajh 8/12/2002 11:10'!\\nblockReturnCode\\n\\n\\t^ EndRemote! !\\n\\n!ParseNode class methodsFor: 'class initialization'!\\ninitialize\\n\\t\\\"ParseNode initialize. VariableNode initialize\\\"\\n\\tLdInstType _ 1.\\n\\tLdTempType _ 2.\\n\\tLdLitType _ 3.\\n\\tLdLitIndType _ 4.\\n\\tSendType _ 5.\\n\\tCodeBases _ #(0 16 32 64 208 ).\\n\\tCodeLimits _ #(16 16 32 32 16 ).\\n\\tLdSelf _ 112.\\n\\tLdTrue _ 113.\\n\\tLdFalse _ 114.\\n\\tLdNil _ 115.\\n\\tLdMinus1 _ 116.\\n\\tLoadLong _ 128.\\n\\tStore _ 129.\\n\\tStorePop _ 130.\\n\\tShortStoP _ 96.\\n\\tSendLong _ 131.\\n\\tDblExtDoAll _ 132.\\n\\tSendLong2 _ 134.\\n\\tLdSuper _ 133.\\n\\tPop _ 135.\\n\\tDup _ 136.\\n\\tLdThisContext _ 137.\\n\\tEndMethod _ 124.\\n\\tEndRemote _ 125.\\n\\tJmp _ 144.\\n\\tBfp _ 152.\\n\\tJmpLimit _ 8.\\n\\tJmpLong _ 164. \\\"code for jmp 0\\\"\\n\\tBtpLong _ 168.\\n\\tSendPlus _ 176.\\n\\tSend _ 208.\\n\\tSendLimit _ 16! !\\n\\n!ParseNode class methodsFor: 'class initialization' stamp: 'ajh 8/6/2002 12:04'!\\npopCode\\n\\n\\t^ Pop! !\\nObject subclass: #ParseStack\\n\\tinstanceVariableNames: 'position length'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Compiler-Support'!\\n!ParseStack commentStamp: '<historical>' prior: 0!\\nI keep track of the current and high position of the stack that will be needed by code being compiled.!\\n\\n\\n!ParseStack methodsFor: 'accessing'!\\npop: n\\n\\n\\t(position _ position - n) < 0 \\n\\t\\tifTrue: [self error: 'Parse stack underflow']! !\\n\\n!ParseStack methodsFor: 'accessing'!\\npush: n\\n\\n\\t(position _ position + n) > length \\n\\t\\tifTrue: [length _ position]! !\\n\\n!ParseStack methodsFor: 'accessing'!\\nsize\\n\\n\\t^length! !\\n\\n\\n!ParseStack methodsFor: 'initialize-release'!\\ninit\\n\\n\\tlength _ position _ 0! !\\n\\n\\n!ParseStack methodsFor: 'printing'!\\nprintOn: aStream\\n\\t\\n\\tsuper printOn: aStream.\\n\\taStream nextPutAll: ' at '; print: position; nextPutAll: ' of '; print: length! !\\n\\n\\n!ParseStack methodsFor: 'results'!\\nposition\\n\\n\\t^position! !\\nScanner subclass: #Parser\\n\\tinstanceVariableNames: 'here hereType hereMark hereEnd prevMark prevEnd encoder requestor parseNode failBlock requestorOffset tempsMark doitFlag properties category'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Compiler-Kernel'!\\n!Parser commentStamp: '<historical>' prior: 0!\\nI parse Smalltalk syntax and create a MethodNode that is the root of the parse tree. I look one token ahead.!\\n\\n\\n!Parser methodsFor: 'error correction' stamp: 'rbb 2/18/2005 11:01'!\\ncorrectSelector: proposedKeyword wordIntervals: spots exprInterval: expInt ifAbort: abortAction\\n\\t\\\"Correct the proposedKeyword to some selector symbol, correcting the original text if such action is indicated. abortAction is invoked if the proposedKeyword couldn't be converted into a valid selector. Spots is an ordered collection of intervals within the test stream of the for each of the keyword parts.\\\"\\n\\n\\t| alternatives aStream choice correctSelector userSelection lines firstLine |\\n\\t\\\"If we can't ask the user, assume that the keyword will be defined later\\\"\\n\\tself interactive ifFalse: [ ^ proposedKeyword asSymbol ].\\n\\n\\tuserSelection _ requestor selectionInterval.\\n\\trequestor selectFrom: spots first first to: spots last last.\\n\\trequestor select.\\n\\talternatives _ Symbol possibleSelectorsFor: proposedKeyword.\\n\\tself flag: #toBeFixed.\\n\\t\\\"alternatives addAll: (MultiSymbol possibleSelectorsFor: proposedKeyword).\\\"\\n\\n\\taStream _ WriteStream on: (String new: 200).\\n\\taStream nextPutAll: (proposedKeyword contractTo: 35); cr.\\n\\tfirstLine _ 1.\\n \\talternatives do:\\n\\t\\t[:sel | aStream nextPutAll: (sel contractTo: 35); nextPut: Character cr].\\n\\taStream nextPutAll: 'cancel'.\\n\\tlines _ Array with: firstLine with: (alternatives size + firstLine).\\n\\t\\n\\tchoice _ (UIManager default \\n\\t\\t\\tchooseFrom: (aStream contents substrings)\\n\\t\\t\\tlines: lines\\n\\t\\t\\ttitle: 'Unknown selector, please\\\\confirm, correct, or cancel' withCRs).\\n\\n\\t(choice = 0) | (choice > (lines at: 2))\\n\\t\\tifTrue: [ ^ abortAction value ].\\n\\n\\trequestor deselect.\\n\\trequestor selectInvisiblyFrom: userSelection first to: userSelection last.\\n\\n\\tchoice = 1 ifTrue: [ ^ proposedKeyword asSymbol ].\\n\\tcorrectSelector _ alternatives at: choice - 1.\\n\\tself substituteSelector: correctSelector keywords wordIntervals: spots.\\n\\t((proposedKeyword last ~= $:) and: [correctSelector last == $:]) ifTrue: [\\n\\t\\t^ abortAction value].\\n\\t^ correctSelector.\\n! !\\n\\n!Parser methodsFor: 'error correction' stamp: 'rbb 2/18/2005 09:01'!\\ncorrectVariable: proposedVariable interval: spot\\n\\t\\\"Correct the proposedVariable to a known variable, or declare it as a new\\n\\tvariable if such action is requested. We support declaring lowercase\\n\\tvariables as temps or inst-vars, and uppercase variables as Globals or \\n\\tClassVars, depending on whether the context is nil (class=UndefinedObject).\\n\\tSpot is the interval within the test stream of the variable.\\n\\trr 3/4/2004 10:26 : adds the option to define a new class. \\\"\\n\\n\\t| tempIvar labels actions lines alternatives binding userSelection choice action |\\n\\n\\t\\\"Check if this is an i-var, that has been corrected already (ugly)\\\"\\n\\t(encoder classEncoding allInstVarNames includes: proposedVariable) ifTrue: [\\n\\t\\t^LiteralVariableNode new \\n\\t\\t\\tname: proposedVariable index: (encoder classEncoding allInstVarNames indexOf: proposedVariable) - 1 type: 1;\\n\\t\\t\\tyourself ].\\n\\n\\t\\\"If we can't ask the user for correction, make it undeclared\\\"\\n\\tself interactive \\n\\t\\tifFalse: [ ^encoder undeclared: proposedVariable ].\\n\\n\\t\\\"First check to see if the requestor knows anything about the variable\\\"\\n\\ttempIvar _ proposedVariable first canBeNonGlobalVarInitial.\\n\\t(tempIvar and: [ (binding _ requestor bindingOf: proposedVariable) notNil ])\\n\\t\\tifTrue: [ ^encoder global: binding name: proposedVariable ].\\n\\tuserSelection _ requestor selectionInterval.\\n\\trequestor selectFrom: spot first to: spot last.\\n\\trequestor select.\\n\\n\\t\\\"Build the menu with alternatives\\\"\\n\\tlabels _ OrderedCollection new. actions _ OrderedCollection new. lines _ OrderedCollection new.\\n\\talternatives _ encoder possibleVariablesFor: proposedVariable.\\n\\ttempIvar \\n\\t\\tifTrue: [ \\n\\t\\t\\tlabels add: 'declare temp'. \\n\\t\\t\\tactions add: [ self declareTempAndPaste: proposedVariable ].\\n\\t\\t\\tlabels add: 'declare instance'.\\n\\t\\t\\tactions add: [ self declareInstVar: proposedVariable ] ]\\n\\t\\tifFalse: [ \\n\\t\\t\\tlabels add: 'define new class'.\\n\\t\\t\\tactions add: [self defineClass: proposedVariable].\\n\\t\\t\\tlabels add: 'declare global'.\\n\\t\\t\\tactions add: [ self declareGlobal: proposedVariable ].\\n\\t\\t\\tencoder classEncoding == UndefinedObject ifFalse: [ \\n\\t\\t\\t\\tlabels add: 'declare class variable'.\\n\\t\\t\\t\\tactions add: [ self declareClassVar: proposedVariable ] ] ].\\n\\tlines add: labels size.\\n\\talternatives do: [ :each | \\n\\t\\tlabels add: each.\\n\\t\\tactions add: [ \\n\\t\\t\\tself substituteWord: each wordInterval: spot offset: 0.\\n\\t\\t\\tencoder encodeVariable: each ] fixTemps ].\\n\\tlines add: labels size.\\n\\tlabels add: 'cancel'.\\n\\n\\t\\\"Display the pop-up menu\\\"\\n\\tchoice _ (UIManager default chooseFrom: labels asArray lines: lines asArray\\n\\t\\ttitle: 'Unknown variable: ', proposedVariable, ' please correct, or cancel:').\\n\\taction _ actions at: choice ifAbsent: [ ^self fail ].\\n\\n\\t\\\"Execute the selected action\\\"\\n\\trequestor deselect.\\n\\trequestor selectInvisiblyFrom: userSelection first to: userSelection last.\\n\\t^action value! !\\n\\n!Parser methodsFor: 'error correction'!\\ndeclareClassVar: name\\n\\t| sym class |\\n\\tsym _ name asSymbol.\\n\\tclass _ encoder classEncoding.\\n\\tclass _ class theNonMetaClass.\\t\\t\\\"not the metaclass\\\"\\n\\tclass addClassVarName: name.\\n\\t^ encoder global: (class classPool associationAt: sym)\\n\\t\\t\\tname: sym! !\\n\\n!Parser methodsFor: 'error correction'!\\ndeclareGlobal: name\\n\\t| sym |\\n\\tsym _ name asSymbol.\\n\\tSmalltalk at: sym put: nil.\\n\\t^ encoder global: (Smalltalk associationAt: sym) name: sym! !\\n\\n!Parser methodsFor: 'error correction' stamp: 'rr 3/6/2004 16:07'!\\ndeclareInstVar: name\\n\\t\\\" rr 3/6/2004 16:06 : adds the line to correctly compute the index. uncommented the option in \\n\\tthe caller.\\\"\\n\\t| index |\\n\\tencoder classEncoding addInstVarName: name.\\n\\tindex _ encoder classEncoding instVarNames indexOf: name.\\n\\tencoder classEncoding allSuperclassesDo: [:cls | index := index + cls instVarNames size].\\n\\t^LiteralVariableNode new\\n\\t\\tname: name index: index - 1 type: 1;\\n\\t\\tyourself\\n\\t\\t! !\\n\\n!Parser methodsFor: 'error correction' stamp: 'RAA 6/5/2001 11:57'!\\ndeclareTempAndPaste: name\\n\\t| insertion delta theTextString characterBeforeMark |\\n\\n\\ttheTextString _ requestor text string.\\n\\tcharacterBeforeMark _ theTextString at: tempsMark-1 ifAbsent: [$ ].\\n\\t(theTextString at: tempsMark) = $| ifTrue: [\\n \\t\\t\\\"Paste it before the second vertical bar\\\"\\n\\t\\tinsertion _ name, ' '.\\n\\t\\tcharacterBeforeMark isSeparator ifFalse: [\\finsertion _ ' ', insertion].\\n\\t\\tdelta _ 0.\\n\\t] ifFalse: [\\n\\t\\t\\\"No bars - insert some with CR, tab\\\"\\n\\t\\tinsertion _ '| ' , name , ' |',String cr.\\n\\t\\tdelta _ 2.\\t\\\"the bar and CR\\\"\\n\\t\\tcharacterBeforeMark = Character tab ifTrue: [\\n\\t\\t\\tinsertion _ insertion , String tab.\\n\\t\\t\\tdelta _ delta + 1.\\t\\\"the tab\\\"\\n\\t\\t].\\n\\t].\\n\\ttempsMark _ tempsMark +\\n\\t\\t(self substituteWord: insertion\\n\\t\\t\\twordInterval: (tempsMark to: tempsMark-1)\\n\\t\\t\\toffset: 0) - delta.\\n\\t^ encoder bindAndJuggle: name! !\\n\\n!Parser methodsFor: 'error correction' stamp: 'DF 4/28/2006 14:31'!\\ndefineClass: className \\n\\t\\\"prompts the user to define a new class, \\n\\tasks for it's category, and lets the users edit further \\n\\tthe definition\\\"\\n\\t| sym cat def d2 |\\n\\tsym := className asSymbol.\\n\\tcat := UIManager default request: 'Enter class category : ' initialAnswer: self encoder classEncoding theNonMetaClass category.\\n\\tcat\\n\\t\\tifEmpty: [cat := 'Unknown'].\\n\\tdef := 'Object subclass: #' , sym , '\\n\\t\\tinstanceVariableNames: '''' \\n\\t\\tclassVariableNames: ''''\\n\\t\\tpoolDictionaries: ''''\\n\\t\\tcategory: ''' , cat , ''''.\\n\\td2 := UIManager default request: 'Edit class definition : ' initialAnswer: def.\\n\\td2\\n\\t\\tifEmpty: [d2 := def].\\n\\tCompiler evaluate: d2.\\n\\t^ encoder\\n\\t\\tglobal: (Smalltalk associationAt: sym)\\n\\t\\tname: sym! !\\n\\n!Parser methodsFor: 'error correction' stamp: 'rbb 2/18/2005 09:10'!\\nqueryUndefined\\n\\t| varStart varName | \\n\\tvarName _ parseNode key.\\n\\tvarStart _ self endOfLastToken + requestorOffset - varName size + 1.\\n\\trequestor selectFrom: varStart to: varStart + varName size - 1; select.\\n\\t((UIManager default \\n\\t\\tchooseFrom: #('yes' 'no') \\n\\t\\ttitle: ((varName , ' appears to be\\\\undefined at this point.Proceed anyway?') \\n\\t\\t\\t\\twithCRs asText makeBoldFrom: 1 to: varName size))\\n\\t\\t= 1) ifFalse: [^ self fail]! !\\n\\n!Parser methodsFor: 'error correction' stamp: 'rbb 2/18/2005 09:08'!\\nremoveUnusedTemps\\n\\t\\\"Scan for unused temp names, and prompt the user about the prospect of removing each one found\\\"\\n\\n\\t| str end start madeChanges | \\n\\tmadeChanges _ false.\\n\\tstr _ requestor text string.\\n\\t((tempsMark between: 1 and: str size)\\n\\t\\tand: [(str at: tempsMark) = $|]) ifFalse: [^ self].\\n\\tencoder unusedTempNames do:\\n\\t\\t[:temp |\\n\\t\\t((UIManager default \\n\\t\\t\\t\\tchooseFrom: #('yes' 'no') \\n\\t\\t\\t\\ttitle: ((temp , ' appears to be\\\\unused in this method.\\\\OK to remove it?') \\n\\t\\t\\t\\t\\t\\twithCRs asText makeBoldFrom: 1 to: temp size)) = 1)\\n\\t\\tifTrue:\\n\\t\\t[(encoder encodeVariable: temp) isUndefTemp\\n\\t\\t\\tifTrue:\\n\\t\\t\\t[end _ tempsMark.\\n\\t\\t\\t[\\\"Beginning at right temp marker...\\\"\\n\\t\\t\\tstart _ end - temp size + 1.\\n\\t\\t\\tend < temp size or: [temp = (str copyFrom: start to: end)\\n\\t\\t\\t\\t\\tand: [(str at: start-1) isAlphaNumeric not & (str at: end+1) isAlphaNumeric not]]]\\n\\t\\t\\twhileFalse:\\n\\t\\t\\t\\t[\\\"Search left for the unused temp\\\"\\n\\t\\t\\t\\tend _ requestor nextTokenFrom: end direction: -1].\\n\\t\\t\\tend < temp size ifFalse:\\n\\t\\t\\t\\t[(str at: start-1) = $ ifTrue: [start _ start-1].\\n\\t\\t\\t\\trequestor correctFrom: start to: end with: ''.\\n\\t\\t\\t\\tstr _ str copyReplaceFrom: start to: end with: ''. \\n\\t\\t\\t\\tmadeChanges _ true.\\n\\t\\t\\t\\ttempsMark _ tempsMark - (end-start+1)]]\\n\\t\\t\\tifFalse:\\n\\t\\t\\t[self inform:\\n'You''ll first have to remove the\\nstatement where it''s stored into']]].\\n\\tmadeChanges ifTrue: [ParserRemovedUnusedTemps signal]! !\\n\\n!Parser methodsFor: 'error correction'!\\nsubstituteSelector: selectorParts wordIntervals: spots\\n\\t\\\"Substitute the correctSelector into the (presuamed interactive) receiver.\\\"\\n\\t| offset |\\n\\toffset _ 0.\\n\\tselectorParts with: spots do:\\n\\t\\t[ :word :interval |\\n\\t\\toffset _ self substituteWord: word wordInterval: interval offset: offset ]\\n! !\\n\\n!Parser methodsFor: 'error correction'!\\nsubstituteWord: correctWord wordInterval: spot offset: o\\n\\t\\\"Substitute the correctSelector into the (presuamed interactive) receiver.\\\"\\n\\n\\trequestor correctFrom: (spot first + o)\\n\\t\\t\\t\\t\\tto: (spot last + o)\\n\\t\\t\\t\\t\\twith: correctWord.\\n\\n\\trequestorOffset _ requestorOffset + correctWord size - spot size.\\n\\t^ o + correctWord size - spot size! !\\n\\n\\n!Parser methodsFor: 'error handling' stamp: 'hmm 7/18/2001 21:45'!\\nexpected: aString \\n\\t\\\"Notify a problem at token 'here'.\\\"\\n\\n\\ttokenType == #doIt ifTrue: [hereMark _ hereMark + 1].\\n\\thereType == #doIt ifTrue: [hereMark _ hereMark + 1].\\n\\t^ self notify: aString , ' expected' at: hereMark + requestorOffset! !\\n\\n!Parser methodsFor: 'error handling'!\\nfail\\n\\n\\t| exitBlock |\\n\\tencoder == nil\\n\\t\\tifFalse: [encoder release. encoder _ nil]. \\\"break cycle\\\"\\n\\texitBlock _ failBlock.\\n\\tfailBlock _ nil.\\n\\t^exitBlock value! !\\n\\n!Parser methodsFor: 'error handling' stamp: 'stephaneducassse 11/5/2005 16:39'!\\ninteractive\\n\\t\\\"this version of the method is necessary to load code from MC else the interactive mode is one. \\n\\tThis method is really bad since it links the compiler package with the Tools\\n\\tone. The solution would be to have a real SyntaxError exception belonging to the \\n\\tcompiler package and not a subclass of StringHolder - sd Nov 2005\\\"\\n\\t\\\"the code submitted by PlusTools is ideally the one that should be used\\n\\tinteractive\\n\\n\\t ^requestor ~~ nil \\\"\\n\\t\\n\\t^ (requestor == nil or: [requestor isKindOf: SyntaxError]) not! !\\n\\n!Parser methodsFor: 'error handling'!\\nnotify: aString \\n\\t\\\"Notify problem at token before 'here'.\\\"\\n\\n\\t^self notify: aString at: prevMark + requestorOffset! !\\n\\n!Parser methodsFor: 'error handling' stamp: 'KLC 11/28/2005 18:01'!\\nnotify: string at: location\\n\\trequestor isNil\\n\\t\\tifTrue: [(encoder == self or: [encoder isNil]) ifTrue: [^ self fail \\\"failure setting up syntax error\\\"].\\n\\t\\t\\t\\tSyntaxErrorNotification\\n\\t\\t\\t\\t\\tinClass: encoder classEncoding\\n\\t\\t\\t\\t\\tcategory: encoder classEncoding category\\n\\t\\t\\t\\t\\twithCode: \\n\\t\\t\\t\\t\\t\\t(source contents\\n\\t\\t\\t\\t\\t\\t\\tcopyReplaceFrom: location\\n\\t\\t\\t\\t\\t\\t\\tto: location - 1\\n\\t\\t\\t\\t\\t\\t\\twith: string , ' ->')\\n\\t\\t\\t\\t\\tdoitFlag: doitFlag]\\n\\t\\tifFalse: [requestor\\n\\t\\t\\t\\t\\tnotify: string , ' ->'\\n\\t\\t\\t\\t\\tat: location\\n\\t\\t\\t\\t\\tin: source].\\n\\t^self fail! !\\n\\n!Parser methodsFor: 'error handling' stamp: 'di 2/9/1999 15:43'!\\noffEnd: aString \\n\\t\\\"Notify a problem beyond 'here' (in lookAhead token). Don't be offEnded!!\\\"\\n\\n\\trequestorOffset == nil\\n\\t\\tifTrue: [^ self notify: aString at: mark]\\n\\t\\tifFalse: [^ self notify: aString at: mark + requestorOffset]\\n! !\\n\\n\\n!Parser methodsFor: 'expression types'!\\nargumentName\\n\\n\\thereType == #word\\n\\t\\tifFalse: [^self expected: 'Argument name'].\\n\\t^self advance! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'hmm 7/16/2001 18:47'!\\nassignment: varNode\\n\\t\\\" var '_' expression => AssignmentNode.\\\"\\n\\t| loc start |\\n\\t(loc _ varNode assignmentCheck: encoder at: prevMark + requestorOffset) >= 0\\n\\t\\tifTrue: [^self notify: 'Cannot store into' at: loc].\\n\\tstart _ self startOfNextToken.\\n\\tvarNode nowHasDef.\\n\\tself advance.\\n\\tself expression ifFalse: [^self expected: 'Expression'].\\n\\tparseNode _ AssignmentNode new\\n\\t\\t\\t\\tvariable: varNode\\n\\t\\t\\t\\tvalue: parseNode\\n\\t\\t\\t\\tfrom: encoder\\n\\t\\t\\t\\tsourceRange: (start to: self endOfLastToken).\\n\\t^true! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'hmm 7/17/2001 21:03'!\\nblockExpression\\n\\t\\\"[ ({:var} |) (| {temps} |) (statements) ] => BlockNode.\\\"\\n\\n\\t| variableNodes temporaryBlockVariables start |\\n\\n\\tvariableNodes _ OrderedCollection new.\\n\\tstart _ prevMark + requestorOffset.\\n\\t\\\"Gather parameters.\\\"\\n\\t[self match: #colon] whileTrue: [variableNodes addLast: (encoder autoBind: self argumentName)].\\n\\t(variableNodes size > 0 & (hereType ~~ #rightBracket) and: [(self match: #verticalBar) not]) ifTrue: [^self expected: 'Vertical bar'].\\n\\n\\ttemporaryBlockVariables _ self temporaryBlockVariables.\\n\\tself statements: variableNodes innerBlock: true.\\n\\tparseNode temporaries: temporaryBlockVariables.\\n\\n\\t(self match: #rightBracket) ifFalse: [^self expected: 'Period or right bracket'].\\n\\n\\tencoder noteSourceRange: (self endOfLastToken to: self endOfLastToken) forNode: parseNode.\\n\\n\\t\\\"The scope of the parameters and temporary block variables is no longer active.\\\"\\n\\ttemporaryBlockVariables do: [:variable | variable scope: -1].\\n\\tvariableNodes do: [:variable | variable scope: -1]! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'di 3/8/2000 09:36'!\\nbraceExpression\\n\\t\\\" { elements } => BraceNode.\\\"\\n\\n\\t| elements locations loc more |\\n\\telements _ OrderedCollection new.\\n\\tlocations _ OrderedCollection new.\\n\\tself advance.\\n\\tmore _ hereType ~~ #rightBrace.\\n\\t[more]\\n\\t\\twhileTrue: \\n\\t\\t\\t[loc _ hereMark + requestorOffset.\\n\\t\\t\\tself expression\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[elements addLast: parseNode.\\n\\t\\t\\t\\t\\tlocations addLast: loc]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[^self expected: 'Variable or expression'].\\n\\t\\t\\t(self match: #period)\\n\\t\\t\\t\\tifTrue: [more _ hereType ~~ #rightBrace]\\n\\t\\t\\t\\tifFalse: [more _ false]].\\n\\tparseNode _ BraceNode new elements: elements sourceLocations: locations.\\n\\t(self match: #rightBrace)\\n\\t\\tifFalse: [^self expected: 'Period or right brace'].\\n\\t^true! !\\n\\n!Parser methodsFor: 'expression types'!\\ncascade\\n\\t\\\" {; message} => CascadeNode.\\\"\\n\\n\\t| rcvr msgs |\\n\\tparseNode canCascade\\n\\t\\tifFalse: [^self expected: 'Cascading not'].\\n\\trcvr _ parseNode cascadeReceiver.\\n\\tmsgs _ OrderedCollection with: parseNode.\\n\\t[self match: #semicolon]\\n\\t\\twhileTrue: \\n\\t\\t\\t[parseNode _ rcvr.\\n\\t\\t\\t(self messagePart: 3 repeat: false)\\n\\t\\t\\t\\tifFalse: [^self expected: 'Cascade'].\\n\\t\\t\\tparseNode canCascade\\n\\t\\t\\t\\tifFalse: [^self expected: '<- No special messages'].\\n\\t\\t\\tparseNode cascadeReceiver.\\n\\t\\t\\tmsgs addLast: parseNode].\\n\\tparseNode _ CascadeNode new receiver: rcvr messages: msgs! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'di 11/19/1999 07:43'!\\nexpression\\n\\n\\t(hereType == #word and: [tokenType == #leftArrow])\\n\\t\\tifTrue: [^ self assignment: self variable].\\n\\thereType == #leftBrace\\n\\t\\tifTrue: [self braceExpression]\\n\\t\\tifFalse: [self primaryExpression ifFalse: [^ false]].\\n\\t(self messagePart: 3 repeat: true)\\n\\t\\tifTrue: [hereType == #semicolon ifTrue: [self cascade]].\\n\\t^ true! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'di 4/5/2000 08:27'!\\nkeylessMessagePartTest: level repeat: repeat\\n! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'yo 8/30/2002 14:41'!\\nmessagePart: level repeat: repeat\\n\\n\\t| start receiver selector args precedence words keywordStart |\\n\\t[receiver _ parseNode.\\n\\t(hereType == #keyword and: [level >= 3])\\n\\t\\tifTrue: \\n\\t\\t\\t[start _ self startOfNextToken.\\n\\t\\t\\tselector _ WriteStream on: (String new: 32).\\n\\t\\t\\targs _ OrderedCollection new.\\n\\t\\t\\twords _ OrderedCollection new.\\n\\t\\t\\t[hereType == #keyword]\\n\\t\\t\\t\\twhileTrue: \\n\\t\\t\\t\\t\\t[keywordStart _ self startOfNextToken + requestorOffset.\\n\\t\\t\\t\\t\\tselector nextPutAll: self advance.\\n\\t\\t\\t\\t\\twords addLast: (keywordStart to: self endOfLastToken + requestorOffset).\\n\\t\\t\\t\\t\\tself primaryExpression ifFalse: [^self expected: 'Argument'].\\n\\t\\t\\t\\t\\tself messagePart: 2 repeat: true.\\n\\t\\t\\t\\t\\targs addLast: parseNode].\\n\\t\\t\\t(Symbol hasInterned: selector contents ifTrue: [ :sym | selector _ sym])\\n\\t\\t\\t\\tifFalse: [ selector _ self correctSelector: selector contents\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\twordIntervals: words\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\texprInterval: (start to: self endOfLastToken)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifAbort: [ ^ self fail ] ].\\n\\t\\t\\tprecedence _ 3]\\n\\t\\tifFalse: [((hereType == #binary or: [hereType == #verticalBar])\\n\\t\\t\\t\\tand: [level >= 2])\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[start _ self startOfNextToken.\\n\\t\\t\\t\\t\\tselector _ self advance asOctetString asSymbol.\\n\\t\\t\\t\\t\\tself primaryExpression ifFalse: [^self expected: 'Argument'].\\n\\t\\t\\t\\t\\tself messagePart: 1 repeat: true.\\n\\t\\t\\t\\t\\targs _ Array with: parseNode.\\n\\t\\t\\t\\t\\tprecedence _ 2]\\n\\t\\t\\t\\tifFalse: [hereType == #word\\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[start _ self startOfNextToken.\\n\\t\\t\\t\\t\\t\\t\\tselector _ self advance.\\n\\t\\t\\t\\t\\t\\t\\targs _ #().\\n\\t\\t\\t\\t\\t\\t\\twords _ OrderedCollection with: (start + requestorOffset to: self endOfLastToken + requestorOffset).\\n\\t\\t\\t\\t\\t\\t\\t(Symbol hasInterned: selector ifTrue: [ :sym | selector _ sym])\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [ selector _ self correctSelector: selector\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\twordIntervals: words\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\texprInterval: (start to: self endOfLastToken)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifAbort: [ ^ self fail ] ].\\n\\t\\t\\t\\t\\t\\t\\tprecedence _ 1]\\n\\t\\t\\t\\t\\t\\tifFalse: [^args notNil]]].\\n\\tparseNode _ MessageNode new\\n\\t\\t\\t\\treceiver: receiver\\n\\t\\t\\t\\tselector: selector\\n\\t\\t\\t\\targuments: args\\n\\t\\t\\t\\tprecedence: precedence\\n\\t\\t\\t\\tfrom: encoder\\n\\t\\t\\t\\tsourceRange: (start to: self endOfLastToken).\\n\\trepeat]\\n\\t\\twhileTrue: [].\\n\\t^true! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'lr 7/3/2006 14:37'!\\nmethod: doit context: ctxt encoder: encoderToUse\\n\\t\\\" pattern [ | temporaries ] block => MethodNode.\\\"\\n\\n\\t| sap blk prim temps messageComment methodNode |\\n\\tencoder _ encoderToUse.\\n\\tsap _ self pattern: doit inContext: ctxt.\\n\\t\\\"sap={selector, arguments, precedence}\\\"\\n\\t(sap at: 2) do: [:argNode | argNode isArg: true].\\n\\tdoit ifFalse: [ self pragmaSequence ].\\n\\ttemps _ self temporariesIn: (sap at: 1)..\\n\\tmessageComment _ currentComment.\\n\\tcurrentComment _ nil.\\n\\tdoit ifFalse: [ self pragmaSequence ].\\n\\tprim := self pragmaPrimitives.\\n\\tself statements: #() innerBlock: doit.\\n\\tblk _ parseNode.\\n\\tdoit ifTrue: [blk returnLast]\\n\\t\\tifFalse: [blk returnSelfIfNoOther].\\n\\thereType == #doIt ifFalse: [^self expected: 'Nothing more'].\\n\\tself interactive ifTrue: [self removeUnusedTemps].\\n\\tmethodNode _ self newMethodNode comment: messageComment.\\n\\t^ methodNode\\n\\t\\tselector: (sap at: 1)\\n\\t\\targuments: (sap at: 2)\\n\\t\\tprecedence: (sap at: 3)\\n\\t\\ttemporaries: temps\\n\\t\\tblock: blk\\n\\t\\tencoder: encoder\\n\\t\\tprimitive: prim\\n\\t\\tproperties: properties! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'di 5/30/2000 21:59'!\\nnewMethodNode\\n\\n\\t^ MethodNode new! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'ar 1/2/2002 14:31'!\\npattern: fromDoit inContext: ctxt \\n\\t\\\" unarySelector | binarySelector arg | keyword arg {keyword arg} => \\n\\t{selector, arguments, precedence}.\\\"\\n\\t| args selector |\\n\\tdoitFlag _ fromDoit.\\n\\tfromDoit ifTrue:\\n\\t\\t\\t[ctxt == nil\\n\\t\\t\\t\\tifTrue: [^ {#DoIt. {}. 1}]\\n\\t\\t\\t\\tifFalse: [^ {#DoItIn:. {encoder encodeVariable: 'homeContext'}. 3}]].\\n\\n\\thereType == #word ifTrue: [^ {self advance asSymbol. {}. 1}].\\n\\n\\t(hereType == #binary or: [hereType == #verticalBar])\\n\\t\\tifTrue: \\n\\t\\t\\t[selector _ self advance asSymbol.\\n\\t\\t\\targs _ Array with: (encoder bindArg: self argumentName).\\n\\t\\t\\t^ {selector. args. 2}].\\n\\n\\thereType == #keyword\\n\\t\\tifTrue: \\n\\t\\t\\t[selector _ WriteStream on: (String new: 32).\\n\\t\\t\\targs _ OrderedCollection new.\\n\\t\\t\\t[hereType == #keyword] whileTrue:[\\n\\t\\t\\t\\tselector nextPutAll: self advance.\\n\\t\\t\\t\\targs addLast: (encoder bindArg: self argumentName).\\n\\t\\t\\t].\\n\\t\\t\\t^ {selector contents asSymbol. args. 3}].\\n\\n\\t^ self expected: 'Message pattern'! !\\n\\n!Parser methodsFor: 'expression types'!\\nprimaryExpression \\n\\thereType == #word \\n\\t\\tifTrue: \\n\\t\\t\\t[parseNode _ self variable.\\n\\t\\t\\t(parseNode isUndefTemp and: [self interactive])\\n\\t\\t\\t\\tifTrue: [self queryUndefined].\\n\\t\\t\\tparseNode nowHasRef.\\n\\t\\t\\t^ true].\\n\\thereType == #leftBracket\\n\\t\\tifTrue: \\n\\t\\t\\t[self advance.\\n\\t\\t\\tself blockExpression.\\n\\t\\t\\t^true].\\n\\thereType == #leftBrace\\n\\t\\tifTrue: \\n\\t\\t\\t[self braceExpression.\\n\\t\\t\\t^true].\\n\\thereType == #leftParenthesis\\n\\t\\tifTrue: \\n\\t\\t\\t[self advance.\\n\\t\\t\\tself expression ifFalse: [^self expected: 'expression'].\\n\\t\\t\\t(self match: #rightParenthesis)\\n\\t\\t\\t\\tifFalse: [^self expected: 'right parenthesis'].\\n\\t\\t\\t^true].\\n\\t(hereType == #string or: [hereType == #number or: [hereType == #literal]])\\n\\t\\tifTrue: \\n\\t\\t\\t[parseNode _ encoder encodeLiteral: self advance.\\n\\t\\t\\t^true].\\n\\t(here == #- and: [tokenType == #number])\\n\\t\\tifTrue: \\n\\t\\t\\t[self advance.\\n\\t\\t\\tparseNode _ encoder encodeLiteral: self advance negated.\\n\\t\\t\\t^true].\\n\\t^false! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'di 6/7/2000 08:45'!\\nstatements: argNodes innerBlock: inner\\n\\n\\t| stmts returns start more blockComment |\\n\\tstmts _ OrderedCollection new.\\n\\t\\\"give initial comment to block, since others trail statements\\\"\\n\\tblockComment _ currentComment.\\n\\tcurrentComment _ nil.\\n\\treturns _ false.\\n\\tmore _ hereType ~~ #rightBracket.\\n\\t[more]\\n\\t\\twhileTrue: \\n\\t\\t[start _ self startOfNextToken.\\n\\t\\t(returns _ self matchReturn)\\n\\t\\t\\tifTrue: \\n\\t\\t\\t\\t[self expression\\n\\t\\t\\t\\t\\tifFalse: [^self expected: 'Expression to return'].\\n\\t\\t\\t\\tself addComment.\\n\\t\\t\\t\\tstmts addLast: (parseNode isReturningIf\\n\\t\\t\\t\\t\\tifTrue: [parseNode]\\n\\t\\t\\t\\t\\tifFalse: [ReturnNode new\\n\\t\\t\\t\\t\\t\\t\\texpr: parseNode\\n\\t\\t\\t\\t\\t\\t\\tencoder: encoder\\n\\t\\t\\t\\t\\t\\t\\tsourceRange: (start to: self endOfLastToken)])]\\n\\t\\t\\tifFalse: \\n\\t\\t\\t\\t[self expression\\n\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t[self addComment.\\n\\t\\t\\t\\t\\t\\tstmts addLast: parseNode]\\n\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t[self addComment.\\n\\t\\t\\t\\t\\t\\tstmts size = 0\\n\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t[stmts addLast: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t(encoder encodeVariable:\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t(inner ifTrue: ['nil'] ifFalse: ['self']))]]].\\n\\t\\treturns \\n\\t\\t\\tifTrue: \\n\\t\\t\\t\\t[self match: #period.\\n\\t\\t\\t\\t(hereType == #rightBracket or: [hereType == #doIt])\\n\\t\\t\\t\\t\\tifFalse: [^self expected: 'End of block']].\\n\\t\\tmore _ returns not and: [self match: #period]].\\n\\tparseNode _ BlockNode new\\n\\t\\t\\t\\targuments: argNodes\\n\\t\\t\\t\\tstatements: stmts\\n\\t\\t\\t\\treturns: returns\\n\\t\\t\\t\\tfrom: encoder.\\n\\tparseNode comment: blockComment.\\n\\t^ true! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'ar 1/4/2002 00:23'!\\ntemporaries\\n\\t\\\" [ '|' (variable)* '|' ]\\\"\\n\\t| vars theActualText |\\n\\t(self match: #verticalBar) ifFalse: \\n\\t\\t[\\\"no temps\\\"\\n\\t\\tdoitFlag ifTrue: [self interactive\\n\\t\\t\\t\\tifFalse: [tempsMark _ 1]\\n\\t\\t\\t\\tifTrue: [tempsMark _ requestor selectionInterval first].\\n\\t\\t\\t^ #()].\\n\\t\\ttempsMark _ (prevEnd ifNil: [0]) + 1.\\n\\t\\ttempsMark _ hereMark\\t\\\"formerly --> prevMark + prevToken\\\".\\n\\n\\t\\ttempsMark > 0 ifTrue:\\n\\t\\t\\t[theActualText _ source contents.\\n\\t\\t\\t[tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]]\\n\\t\\t\\t\\twhileTrue: [tempsMark _ tempsMark + 1]].\\n\\t\\t\\t^ #()].\\n\\tvars _ OrderedCollection new.\\n\\t[hereType == #word]\\n\\t\\twhileTrue: [vars addLast: (encoder bindTemp: self advance)].\\n\\t(self match: #verticalBar) ifTrue: \\n\\t\\t[tempsMark _ prevMark.\\n\\t\\t^ vars].\\n\\t^ self expected: 'Vertical bar'\\n! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'mir 1/17/2004 12:27'!\\ntemporariesIn: methodSelector\\n\\t\\\" [ '|' (variable)* '|' ]\\\"\\n\\t| vars theActualText |\\n\\t(self match: #verticalBar) ifFalse: \\n\\t\\t[\\\"no temps\\\"\\n\\t\\tdoitFlag ifTrue: [requestor\\n\\t\\t\\t\\tifNil: [tempsMark _ 1]\\n\\t\\t\\t\\tifNotNil: [tempsMark _ requestor selectionInterval first].\\n\\t\\t\\t^ #()].\\n\\t\\ttempsMark _ (prevEnd ifNil: [0]) + 1.\\n\\t\\ttempsMark _ hereMark\\t\\\"formerly --> prevMark + prevToken\\\".\\n\\n\\t\\ttempsMark > 0 ifTrue:\\n\\t\\t\\t[theActualText _ source contents.\\n\\t\\t\\t[tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]]\\n\\t\\t\\t\\twhileTrue: [tempsMark _ tempsMark + 1]].\\n\\t\\t\\t^ #()].\\n\\tvars _ OrderedCollection new.\\n\\t[hereType == #word]\\n\\t\\twhileTrue: [vars addLast: (encoder bindTemp: self advance in: methodSelector)].\\n\\t(self match: #verticalBar) ifTrue: \\n\\t\\t[tempsMark _ prevMark.\\n\\t\\t^ vars].\\n\\t^ self expected: 'Vertical bar'! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'crl 2/26/1999 12:22'!\\ntemporaryBlockVariables\\n\\t\\\"Scan and answer temporary block variables.\\\"\\n\\n\\t| variables |\\n\\n\\t(self match: #verticalBar) ifFalse: [\\n\\t\\t\\\"There are't any temporary variables.\\\"\\n\\t\\t^#()].\\n\\n\\tvariables _ OrderedCollection new.\\n\\t[hereType == #word] whileTrue: [variables addLast: (encoder bindBlockTemp: self advance)].\\n\\t(self match: #verticalBar) ifTrue: [^variables].\\n\\t^self expected: 'Vertical bar'! !\\n\\n!Parser methodsFor: 'expression types' stamp: 'di 12/4/1999 21:04'!\\nvariable\\n\\n\\t| varName varStart varEnd |\\n\\tvarStart _ self startOfNextToken + requestorOffset.\\n\\tvarName _ self advance.\\n\\tvarEnd _ self endOfLastToken + requestorOffset.\\n\\t^ encoder encodeVariable: varName\\n\\t\\tsourceRange: (varStart to: varEnd)\\n\\t\\tifUnknown: [self correctVariable: varName interval: (varStart to: varEnd)]! !\\n\\n\\n!Parser methodsFor: 'pragmas' stamp: 'lr 2/6/2006 20:50'!\\naddPragma: aPragma\\n\\tself properties addPragma: aPragma.! !\\n\\n!Parser methodsFor: 'pragmas' stamp: 'lr 2/6/2006 21:02'!\\npragmaLiteral\\n\\t\\\"Read a pragma literal.\\\"\\n\\n\\t(hereType == #string or: [ hereType == #literal or: [ hereType == #number ] ])\\n\\t\\tifTrue: [ ^ self advance ].\\n\\t(here == $# and: [ tokenType == #word ])\\n\\t\\tifTrue: [ ^ self advance ].\\n\\t(here == #- and: [ tokenType == #number ])\\n\\t\\tifTrue: [ ^ (self advance; advance) negated ].\\n\\t(here = 'true' or: [ here = 'false' or: [ here = 'nil' or: [ Smalltalk hasClassNamed: here ] ] ])\\n\\t\\tifTrue: [ ^ Compiler evaluate: self advance ].\\n\\t^ self expected: 'Literal constant'.! !\\n\\n!Parser methodsFor: 'pragmas' stamp: 'lr 2/6/2006 20:23'!\\npragmaPrimitives\\n\\t| primitives |\\n\\tprimitives := self properties pragmas select: [ :each | \\n\\t\\t#( primitive: primitive:module: ) \\n\\t\\t\\tincludes: each keyword ].\\n\\tprimitives isEmpty \\n\\t\\tifTrue: [ ^ 0 ].\\n\\tprimitives size = 1 \\n\\t\\tifFalse: [ ^ self notify: 'Ambigous primitives' ].\\n\\t^ primitives first message sendTo: self.! !\\n\\n!Parser methodsFor: 'pragmas' stamp: 'lr 2/6/2006 20:23'!\\npragmaSequence\\n\\t\\\"Parse a sequence of method pragmas.\\\"\\n\\t\\n\\t[ true ] whileTrue: [\\n\\t\\t(self matchToken: #<)\\n\\t\\t\\tifFalse: [ ^ self ].\\n\\t\\tself pragmaStatement.\\n\\t\\t(self matchToken: \";\n r = \"{7689049, 2109470}\";\n s = 1;\n },\n {\n l = \"instance or #class> <selector name>), and with a string to be produced as part of the error msg if any of the methods affected is reached\\\"\\n\\n\\t| aClass sel keywords codeString |\\n\\ttripletList do:\\n\\t\\t[:triplet | \\n\\t\\t\\t(aClass _ (Smalltalk at: triplet first ifAbsent: [nil])) notNil ifTrue:\\n\\t\\t\\t\\t[triplet second == #class ifTrue:\\n\\t\\t\\t\\t\\t[aClass _ aClass class].\\n\\t\\t\\t\\tsel _ triplet third.\\n\\t\\t\\t\\tkeywords _ sel keywords.\\n\\t\\t\\t\\t(keywords size == 1 and: [keywords first asSymbol isKeyword not])\\n\\t\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t\\t[codeString _ keywords first asString]\\n\\t\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t\\t[codeString _ ''.\\n\\t\\t\\t\\t\\t\\tkeywords withIndexDo:\\n\\t\\t\\t\\t\\t\\t\\t[:kwd :index |\\n\\t\\t\\t\\t\\t\\t\\t\\tcodeString _ codeString, ' ', (keywords at: index), ' ',\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t'arg', index printString]].\\n\\t\\t\\t\\tcodeString _ codeString, '\\n\\tself codeStrippedOut: ', (messageString surroundedBySingleQuotes).\\n\\n\\t\\t\\t\\taClass compile: codeString classified: 'stripped']]! !\\n\\n\\n!SmalltalkImage methodsFor: 'vm parameters' stamp: 'sd 6/27/2003 23:27'!\\nextraVMMemory\\n\\t\\\"Answer the current setting of the 'extraVMMemory' VM parameter. See the comment in extraVMMemory: for details.\\\"\\n\\n\\t^ self vmParameterAt: 23\\n! !\\n\\n!SmalltalkImage methodsFor: 'vm parameters' stamp: 'sd 6/27/2003 23:27'!\\nextraVMMemory: extraBytesToReserve\\n\\t\\\"Request that the given amount of extra memory be reserved for use by the virtual machine to leave extra C heap space available for things like plugins, network and file buffers, and so on. This request is stored when the image is saved and honored when the image is next started up. Answer the previous value of this parameter.\\\"\\n\\n\\textraBytesToReserve < 0\\n\\t\\tifTrue: [self error: 'VM memory reservation must be non-negative'].\\n\\t^ self vmParameterAt: 23 put: extraBytesToReserve\\n! !\\n\\n!SmalltalkImage methodsFor: 'vm parameters' stamp: 'sd 6/27/2003 23:47'!\\ngetVMParameters\\t\\n\\t\\\"Answer an Array containing the current values of the VM's internal\\n\\tparameter/metric registers. Each value is stored in the array at the\\n\\tindex corresponding to its VM register. (See #vmParameterAt: and\\n\\t#vmParameterAt:put:.)\\\"\\n\\t\\\"SmalltalkImage current getVMParameters\\\"\\n\\t\\n\\t<primitive: 254>\\n\\tself primitiveFailed! !\\n\\n!SmalltalkImage methodsFor: 'vm parameters' stamp: 'tpr 4/27/2005 11:03'!\\nvmParameterAt: parameterIndex\\n\\t\\\"parameterIndex is a positive integer corresponding to one of the VM's internal\\n\\tparameter/metric registers. Answer with the current value of that register.\\n\\tFail if parameterIndex has no corresponding register.\\n\\tVM parameters are numbered as follows:\\n\\t\\t1\\tend of old-space (0-based, read-only)\\n\\t\\t2\\tend of young-space (read-only)\\n\\t\\t3\\tend of memory (read-only)\\n\\t\\t4\\tallocationCount (read-only)\\n\\t\\t5\\tallocations between GCs (read-write)\\n\\t\\t6\\tsurvivor count tenuring threshold (read-write)\\n\\t\\t7\\tfull GCs since startup (read-only)\\n\\t\\t8\\ttotal milliseconds in full GCs since startup (read-only)\\n\\t\\t9\\tincremental GCs since startup (read-only)\\n\\t\\t10\\ttotal milliseconds in incremental GCs since startup (read-only)\\n\\t\\t11\\ttenures of surving objects since startup (read-only)\\n\\t\\t12-20 specific to the translating VM\\n\\t\\t21\\troot table size (read-only)\\n\\t\\t22\\troot table overflows since startup (read-only)\\n\\t\\t23\\tbytes of extra memory to reserve for VM buffers, plugins, etc.\\n\\n\\t\\t24\\tmemory threshold above which shrinking object memory (rw)\\n\\t\\t25\\tmemory headroom when growing object memory (rw)\\n\\t\\t26 interruptChecksEveryNms - force an ioProcessEvents every N milliseconds, in case the image is not calling getNextEvent often (rw)\\n\\t\\t27\\tnumber of times mark loop iterated for current IGC/FGC (read-only) includes ALL marking\\n\\t\\t28\\tnumber of times sweep loop iterated for current IGC/FGC (read-only)\\n\\t\\t29\\tnumber of times make forward loop iterated for current IGC/FGC (read-only)\\n\\t\\t30\\tnumber of times compact move loop iterated for current IGC/FGC (read-only)\\n\\t\\t31\\tnumber of grow memory requests (read-only)\\n\\t\\t32\\tnumber of shrink memory requests (read-only)\\n\\t\\t33\\tnumber of root table entries used for current IGC/FGC (read-only)\\n\\t\\t34\\tnumber of allocations done before current IGC/FGC (read-only)\\n\\t\\t35\\tnumber of survivor objects after current IGC/FGC (read-only)\\n\\t\\t36 millisecond clock when current IGC/FGC completed (read-only)\\n\\t\\t37 number of marked objects for Roots of the world, not including Root Table entries for current IGC/FGC (read-only)\\n\\t\\t38 milliseconds taken by current IGC (read-only)\\n\\t\\t39 Number of finalization signals for Weak Objects pending when current IGC/FGC completed (read-only)\\n\\t\\t40 VM word size - 4 or 8 (read-only)\\\"\\n\\n\\t<primitive: 254>\\n\\tself primitiveFailed! !\\n\\n!SmalltalkImage methodsFor: 'vm parameters' stamp: 'sd 6/27/2003 23:27'!\\nvmParameterAt: parameterIndex put: newValue\\n\\t\\\"parameterIndex is a positive integer corresponding to one of the VM's internal\\n\\tparameter/metric registers. Store newValue (a positive integer) into that\\n\\tregister and answer with the previous value that was stored there.\\n\\tFail if newValue is out of range, if parameterIndex has no corresponding\\n\\tregister, or if the corresponding register is read-only.\\\"\\n\\n\\t<primitive: 254>\\n\\tself primitiveFailed! !\\n\\n\\n!SmalltalkImage methodsFor: 'vm profiling' stamp: 'sd 9/24/2003 11:54'!\\nclearProfile\\n\\t\\\"Clear the profile database.\\\"\\n\\n\\t<primitive: 250>\\n! !\\n\\n!SmalltalkImage methodsFor: 'vm profiling' stamp: 'sd 9/24/2003 11:54'!\\ndumpProfile\\n\\t\\\"Dump the profile database to a file.\\\"\\n\\n\\t<primitive: 251>\\n! !\\n\\n!SmalltalkImage methodsFor: 'vm profiling' stamp: 'sd 9/24/2003 11:54'!\\nprofile: aBlock\\n\\t\\\"Make a virtual machine profile of the given block.\\\"\\n\\t\\\"Note: Profiling support is provided so that VM implementors\\n\\t can better understand and improve the efficiency of the virtual\\n\\t machine. To use it, you must be running a version of the\\n\\t virtual machine compiled with profiling enabled (which\\n\\t makes it much slower than normal even when not profiling).\\n\\t You will also need the CodeWarrior profile reader application.\\\"\\n\\n\\tself stopProfiling.\\n\\tself clearProfile.\\n\\tself startProfiling.\\n\\taBlock value.\\n\\tself stopProfiling.\\n\\tself dumpProfile.! !\\n\\n!SmalltalkImage methodsFor: 'vm profiling' stamp: 'sd 9/24/2003 11:55'!\\nstartProfiling\\n\\t\\\"Start profiling the virtual machine.\\\"\\n\\n\\t<primitive: 252>\\n! !\\n\\n!SmalltalkImage methodsFor: 'vm profiling' stamp: 'sd 9/24/2003 11:55'!\\nstopProfiling\\n\\t\\\"Stop profiling the virtual machine.\\\"\\n\\n\\t<primitive: 253>\\n! !\\n\\n\\n!SmalltalkImage methodsFor: 'vm statistics' stamp: 'sd 7/2/2003 21:45'!\\ntextMarkerForShortReport\\n\\n\\t^ 'Since last view\\t'! !\\n\\n!SmalltalkImage methodsFor: 'vm statistics' stamp: 'sd 9/30/2003 13:53'!\\nvmStatisticsReportString\\n\\t\\\"StringHolderView open: (StringHolder new contents:\\n\\t\\tSmalltalkImage current vmStatisticsReportString) label: 'VM Statistics'\\\"\\n\\n\\t| params oldSpaceEnd youngSpaceEnd memoryEnd fullGCs fullGCTime incrGCs incrGCTime tenureCount mcMisses mcHits icHits upTime sendCount tms tmSize upTime2 fullGCs2 fullGCTime2 incrGCs2 incrGCTime2 tenureCount2 str |\\n\\tparams _ self getVMParameters.\\n\\toldSpaceEnd\\t\\t\\t_ params at: 1.\\n\\tyoungSpaceEnd\\t\\t_ params at: 2.\\n\\tmemoryEnd\\t\\t\\t_ params at: 3.\\n\\tfullGCs\\t\\t\\t\\t_ params at: 7.\\n\\tfullGCTime\\t\\t\\t_ params at: 8.\\n\\tincrGCs\\t\\t\\t\\t_ params at: 9.\\n\\tincrGCTime\\t\\t\\t_ params at: 10.\\n\\ttenureCount\\t\\t\\t_ params at: 11.\\n\\tmcMisses\\t\\t\\t_ params at: 15.\\n\\tmcHits\\t\\t\\t\\t_ params at: 16.\\n\\ticHits\\t\\t\\t\\t_ params at: 17.\\n\\tupTime _ Time millisecondClockValue.\\n\\tsendCount _ mcMisses + mcHits + icHits.\\n\\ttms _ TranslatedMethod allSubInstances.\\n\\ttmSize _ tms inject: 0 into: [:sum :tm | sum + (tm size * 4)].\\n\\n\\tstr _ WriteStream on: (String new: 1000).\\n\\tstr\\tnextPutAll: 'uptime\\t\\t\\t';\\n\\t\\tprint: (upTime / 1000 / 60 // 60); nextPut: $h;\\n\\t\\tprint: (upTime / 1000 / 60 \\\\\\\\ 60) asInteger; nextPut: $m;\\n\\t\\tprint: (upTime / 1000 \\\\\\\\ 60) asInteger; nextPut: $s; cr.\\n\\n\\tstr\\tnextPutAll: 'memory\\t\\t\\t';\\n\\t\\tnextPutAll: memoryEnd asStringWithCommas; nextPutAll: ' bytes'; cr.\\n\\tstr\\tnextPutAll:\\t'\\told\\t\\t\\t';\\n\\t\\tnextPutAll: oldSpaceEnd asStringWithCommas; nextPutAll: ' bytes (';\\n\\t\\tprint: ((oldSpaceEnd / memoryEnd * 100) roundTo: 0.1); nextPutAll: '%)'; cr.\\n\\tstr\\tnextPutAll: '\\tyoung\\t\\t';\\n\\t\\tnextPutAll: (youngSpaceEnd - oldSpaceEnd) asStringWithCommas; nextPutAll: ' bytes (';\\n\\t\\tprint: ((youngSpaceEnd - oldSpaceEnd / memoryEnd * 100) roundTo: 0.1); nextPutAll: '%)'; cr.\\n\\tstr\\tnextPutAll: '\\tused\\t\\t';\\n\\t\\tnextPutAll: youngSpaceEnd asStringWithCommas; nextPutAll: ' bytes (';\\n\\t\\tprint: ((youngSpaceEnd / memoryEnd * 100) roundTo: 0.1); nextPutAll: '%)'; cr.\\n\\tstr\\tnextPutAll: '\\tfree\\t\\t';\\n\\t\\tnextPutAll: (memoryEnd - youngSpaceEnd) asStringWithCommas; nextPutAll: ' bytes (';\\n\\t\\tprint: ((memoryEnd - youngSpaceEnd / memoryEnd * 100) roundTo: 0.1); nextPutAll: '%)'; cr.\\n\\n\\tstr\\tnextPutAll: 'GCs\\t\\t\\t\\t';\\n\\t\\tnextPutAll: (fullGCs + incrGCs) asStringWithCommas.\\n\\tfullGCs + incrGCs > 0 ifTrue: [\\n\\t\\tstr\\n\\t\\t\\tnextPutAll: ' ('; \\n\\t\\t\\tprint: ((upTime / (fullGCs + incrGCs)) roundTo: 1); \\n\\t\\t\\tnextPutAll: 'ms between GCs)'\\n\\t].\\n\\tstr cr.\\n\\tstr\\tnextPutAll: '\\tfull\\t\\t\\t';\\n\\t\\tprint: fullGCs; nextPutAll: ' totalling '; nextPutAll: fullGCTime asStringWithCommas; nextPutAll: 'ms (';\\n\\t\\tprint: ((fullGCTime / upTime * 100) roundTo: 1.0);\\n\\t\\tnextPutAll: '% uptime)'.\\n\\tfullGCs = 0 ifFalse:\\n\\t\\t[str\\tnextPutAll: ', avg '; print: ((fullGCTime / fullGCs) roundTo: 1.0); nextPutAll: 'ms'].\\n\\tstr\\tcr.\\n\\tstr\\tnextPutAll: '\\tincr\\t\\t';\\n\\t\\tprint: incrGCs; nextPutAll: ' totalling '; nextPutAll: incrGCTime asStringWithCommas; nextPutAll: 'ms (';\\n\\t\\tprint: ((incrGCTime / upTime * 100) roundTo: 1.0);\\n\\t\\tnextPutAll: '% uptime), avg '; print: ((incrGCTime / incrGCs) roundTo: 1.0); nextPutAll: 'ms'; cr.\\n\\tstr\\tnextPutAll: '\\ttenures\\t\\t';\\n\\t\\tnextPutAll: tenureCount asStringWithCommas.\\n\\ttenureCount = 0 ifFalse:\\n\\t\\t[str nextPutAll: ' (avg '; print: (incrGCs / tenureCount) asInteger; nextPutAll: ' GCs/tenure)'].\\n\\tstr\\tcr.\\n\\nLastStats ifNil: [LastStats _ Array new: 6]\\nifNotNil: [\\n\\tupTime2 _ upTime - (LastStats at: 1).\\n\\tfullGCs2 _ fullGCs - (LastStats at: 2).\\n\\tfullGCTime2 _ fullGCTime - (LastStats at: 3).\\n\\tincrGCs2 _ incrGCs - (LastStats at: 4).\\n\\tincrGCTime2 _ incrGCTime - (LastStats at: 5).\\n\\ttenureCount2 _ tenureCount - (LastStats at: 6).\\n\\n\\tstr\\tnextPutAll: self textMarkerForShortReport ;\\n\\t\\tnextPutAll: (fullGCs2 + incrGCs2) asStringWithCommas.\\n\\tfullGCs2 + incrGCs2 > 0 ifTrue: [\\n\\t\\tstr\\n\\t\\t\\tnextPutAll: ' ('; \\n\\t\\t\\tprint: ((upTime2 / (fullGCs2 + incrGCs2)) roundTo: 1); \\n\\t\\t\\tnextPutAll: 'ms between GCs)'.\\n\\t].\\n\\tstr cr.\\n\\tstr\\tnextPutAll: '\\tuptime\\t\\t'; print: ((upTime2 / 1000.0) roundTo: 0.1); nextPutAll: 's'; cr.\\n\\tstr\\tnextPutAll: '\\tfull\\t\\t\\t';\\n\\t\\tprint: fullGCs2; nextPutAll: ' totalling '; nextPutAll: fullGCTime2 asStringWithCommas; nextPutAll: 'ms (';\\n\\t\\tprint: ((fullGCTime2 / upTime2 * 100) roundTo: 1.0);\\n\\t\\tnextPutAll: '% uptime)'.\\n\\tfullGCs2 = 0 ifFalse:\\n\\t\\t[str\\tnextPutAll: ', avg '; print: ((fullGCTime2 / fullGCs2) roundTo: 1.0); nextPutAll: 'ms'].\\n\\tstr\\tcr.\\n\\tstr\\tnextPutAll: '\\tincr\\t\\t';\\n\\t\\tprint: incrGCs2; nextPutAll: ' totalling '; nextPutAll: incrGCTime2 asStringWithCommas; nextPutAll: 'ms (';\\n\\t\\tprint: ((incrGCTime2 / upTime2 * 100) roundTo: 1.0);\\n\\t\\tnextPutAll: '% uptime), avg '.\\n\\tincrGCs2 > 0 ifTrue: [\\n\\t\\t str print: ((incrGCTime2 / incrGCs2) roundTo: 1.0); nextPutAll: 'ms'\\n\\t].\\n\\tstr cr.\\n\\tstr\\tnextPutAll: '\\ttenures\\t\\t';\\n\\t\\tnextPutAll: tenureCount2 asStringWithCommas.\\n\\ttenureCount2 = 0 ifFalse:\\n\\t\\t[str nextPutAll: ' (avg '; print: (incrGCs2 / tenureCount2) asInteger; nextPutAll: ' GCs/tenure)'].\\n\\tstr\\tcr.\\n].\\n\\tLastStats at: 1 put: upTime.\\n\\tLastStats at: 2 put: fullGCs.\\n\\tLastStats at: 3 put: fullGCTime.\\n\\tLastStats at: 4 put: incrGCs.\\n\\tLastStats at: 5 put: incrGCTime.\\n\\tLastStats at: 6 put: tenureCount.\\n\\n\\tsendCount > 0 ifTrue: [\\n\\t\\tstr\\tnextPutAll: 'sends\\t\\t\\t';\\n\\t\\t\\tnextPutAll: sendCount asStringWithCommas; cr.\\n\\t\\tstr\\tnextPutAll: '\\tfull\\t\\t\\t';\\n\\t\\t\\tnextPutAll: mcMisses asStringWithCommas;\\n\\t\\t\\tnextPutAll: ' ('; print: ((mcMisses / sendCount * 100) roundTo: 0.1); nextPutAll: '%)'; cr.\\n\\t\\tstr\\tnextPutAll: '\\tm-cache\\t';\\n\\t\\t\\tnextPutAll: mcHits asStringWithCommas;\\n\\t\\t\\tnextPutAll: ' ('; print: ((mcHits / sendCount * 100) roundTo: 0.1); nextPutAll: '%)'; cr.\\n\\t\\tstr\\tnextPutAll: '\\ti-cache\\t\\t';\\n\\t\\t\\tnextPutAll: icHits asStringWithCommas;\\n\\t\\t\\tnextPutAll: ' ('; print: ((icHits / sendCount * 100) roundTo: 0.1); nextPutAll: '%)'; cr].\\n\\n\\ticHits > 0 ifTrue: [\\n\\t\\tstr\\tnextPutAll: 'methods\\t\\t\\t';\\n\\t\\t\\tnextPutAll: tms size asStringWithCommas; nextPutAll: ' translated'; cr.\\n\\t\\tstr\\tnextPutAll: '\\tsize\\t\\t\\t';\\n\\t\\t\\tnextPutAll: tmSize asStringWithCommas; nextPutAll: ' bytes, avg ';\\n\\t\\t\\tprint: ((tmSize / tms size) roundTo: 0.1); nextPutAll: ' bytes/method'; cr.\\n\\t\\tstr\\tnextPutAll: '\\tmemory\\t\\t';\\n\\t\\t\\tprint: ((tmSize / youngSpaceEnd * 100) roundTo: 0.1); nextPutAll: '% of used, ';\\n\\t\\t\\tprint: ((tmSize / memoryEnd * 100) roundTo: 0.1); nextPutAll: '% of available'; cr].\\n\\n\\t^ str contents\\n! !\\n\\n!SmalltalkImage methodsFor: 'vm statistics' stamp: 'sd 9/30/2003 13:54'!\\nvmStatisticsShortString\\n\\t\\\"Convenience item for access to recent statistics only\\\"\\n\\t\\\"StringHolderView open: (StringHolder new contents: SmalltalkImage current vmStatisticsShortString)\\n\\t\\tlabel: 'VM Recent Statistics'\\\"\\n\\n\\t^ (ReadStream on: self vmStatisticsReportString) upToAll: 'Since'; upTo: Character cr; upToEnd\\n! !\\n\\n\\n!SmalltalkImage methodsFor: 'private source file' stamp: 'sd 9/24/2003 12:42'!\\nsourceFileVersionString: aString\\n\\n\\tSourceFileVersionString := aString! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSmalltalkImage class\\n\\tinstanceVariableNames: 'current'!\\n\\n!SmalltalkImage class methodsFor: 'class initialization' stamp: 'yo 2/18/2004 18:26'!\\ninitialize\\n\\\"\\n\\tself initialize\\n\\\"\\n\\tSmalltalk addToStartUpList: SmalltalkImage.\\n\\tSmalltalkImage startUp.\\n! !\\n\\n!SmalltalkImage class methodsFor: 'class initialization' stamp: 'yo 2/18/2004 18:25'!\\nstartUp\\n\\n\\tEndianCache _ nil.\\n! !\\n\\n\\n!SmalltalkImage class methodsFor: 'instance creation' stamp: 'sd 9/30/2003 14:28'!\\ncurrent\\n\\t\\\"Note that this could be implemented differently to avoid the test\\\"\\n\\n\\tcurrent isNil\\n\\t\\tifTrue: [current := self basicNew].\\n\\t^ current! !\\n\\n!SmalltalkImage class methodsFor: 'instance creation' stamp: 'sd 9/30/2003 13:39'!\\nnew\\n\\n\\tself error: 'Use current'.! !\\nReferenceStream subclass: #SmartRefStream\\n\\tinstanceVariableNames: 'structures steady reshaped renamed renamedConv superclasses progressBar objCount classInstVars'\\n\\tclassVariableNames: 'ScannedObject'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Object Storage'!\\n!SmartRefStream commentStamp: '<historical>' prior: 0!\\nOrdinary ReferenceStreams assume that the names and order of instance variables is exactly the same when an object file is written and read. \\n\\tSmartRefStream allows object files to be read even after instance variables have changed or the entire class has been renamed.\\n\\nWhen an object file is written, no one knows how the classes will change in the future. Therefore, all conversion must be done when the file is read. The key is to store enough information in the file about the names of the instance variables of all outgoing classes. \\n\\nSmartRefStream works best with only one tree of objects per file. You can nextPut: more than once, but each object tree gets its own class structure description, which is big. \\n\\nConversion of old objects is done by a method in each class called (convertToCurrentVersion: varDict refStream: smartRefStrm). At fileOut time, ChangeSet>>checkForConversionMethods creates a prototype of this method (if Preference #conversionMethodsAtFileOut is true). The programmer must edit this method to (1) test if the incoming object needs conversion, (2) put non-nil values into any new inst vars that need them, and (3) save the data of any inst vars that are being deleted. \\n\\nDetermining which old version is represented by the incoming object can be done in several ways: noticing that a current inst var is nil when it should have data, noticing that there is an older inst var name in the variable dictionary (varDict), checking kinds of objects in one or more inst vars, or retrieving the classVersion of the incoming object from the ref stream. \\n\\nIf a class is renamed, a method goes into SmartRefStream telling the new name. The conversion method of the new class must be prepared to accept instances of the old class also. If no inst var names have changed, the conversion method does nothing.\\n\\nAn example: \\n\\tSuppose we change the representation of class Rectangle from ('origin' 'corner') to ('origin' 'extent'). Suppose lots of Rectangle instances are already out on files (in .pr project files, especially). \\n\\tThe programmer changes the class definition, modifies all the methods, and filesOut. A series of dialogs appear, asking if instances Rectangle might be in an object file, if 'extent' needs to be non-nil (yes), and if the info in 'corner' needs to be preserved (yes). This method appears:\\n\\nRectangle >> convertToCurrentVersion: varDict refStream: smartRefStrm\\n\\t\\\"These variables are automatically stored into the new instance: #('origin').\\n\\tTest for this particular conversion. Get values using expressions like (varDict at: 'foo').\\\"\\n\\n\\t\\\"New variables: #('extent'). If a non-nil value is needed, please assign it.\\\"\\n\\t\\\"These are going away #('corner'). Possibly store their info in some other variable?\\\"\\n\\t\\\"Move your code above the ^ super... Delete extra comments.\\\"\\n\\t^ super convertToCurrentVersion: varDict refStream: smartRefStrm\\n\\nThe programmer modifies it to be:\\n\\nRectangle >> convertToCurrentVersion: varDict refStream: smartRefStrm\\n\\n(varDict includesKey: 'extent') ifFalse: [\\\"old version!!\\\"\\n\\t\\\"Create the new extent, and preserve the info from the old corner\\\"\\n\\textent _ (varDict at: 'corner') - origin.\\n\\t].\\n^ super convertToCurrentVersion: varDict refStream: smartRefStrm\\n\\n\\tThis conversion method stays in the system and is ready to convert the old format of Rectangle whenever one is encountered in an object file. Note that the subclasses of Rectangle, (B3DViewport, CharacterBlock, and Quadrangle) do not need conversion methods. Their instances will be converted by the code in Rectangle. \\n\\n\\tFiles written by SmartRefStream are in standard fileout format. You can mix raw objects with code to be filed in. The file starts out in the normal fileOut format. Definitions of new classes on the front.\\n\\nstructures \\tDictionary of (#Rectangle -> #(<classVersionInteger> 'origin' 'corner')). Inst \\n\\t\\t\\t\\tvar names are strings.\\nsteady \\t\\tSet of Classes who have the same structure now as on the incoming file.\\n\\t\\t\\t\\tIncludes classes with same inst vars except for new ones added on the end.\\nreshaped \\tDictionary of Classes who have a different structure now from the incoming file. \\n\\t\\t\\t\\tIncludes those with same inst vars but new version number.\\n\\t\\t\\t\\t(old class name -> method selector to fill in data for version to version)\\nrenamed\\tDictionary of Classes who have a different name. Make an instance of the new\\n\\t\\t\\tclass, and send it the conversion call.\\n\\t\\t\\t\\t(old class name symbol -> new class name). \\nrenamedConv\\tDictionary of conversion selector for Classes who have a different name.\\n\\t\\t\\t\\t(old class name symbol -> conversion selector). \\ntopCall\\t\\tTells if next or nextPut: are working on the top object in the tree. \\n\\t\\t\\tnil if outside, the top object if deep inside.\\n\\nSee DataStream.typeIDFor: for where the tangle of objects is clipped, so the whole system will not be written on the file.\\n\\nNo object that is written on the file is ever a class. All class definitions are filed in. A class may be stored inside an ImageSegment that itself is stored in a SmartRefStream.\\n\\nUniClasses are classes for the instance specific behavior of just one instance. Subclasses of Player are an example. When a UniClass is read in, and a class of the same name already exists, the incoming one is renamed. ObjectScanner converts the filed-in code.\\n\\nValues in instance variables of UniClasses are stored in the array that tells the class structure. It is the fourth of the four top level objects. #(version (class-structure) the-object ((#Player25 scripts slotInfo costumeDictionary) (#Player26 scripts slotInfo costumeDictionary))).\\n\\nThere is a separate subclass for doing veryDeepCopy (in memory). Currently, any object for which objectToStoreOnDataStream return an object other than self, does this: The new object (a DiskProxy) is traced. When it comes time to go through the fields of the old object, they are not found as keys in references (DiskProxies are there instead). So the old field value is left in the new object. That is OK for StrikeFont, Class, MetaClass, DisplayScreen. But the DiskProxies are evaluated, which takes a lot of time.\\n\\nSome metaclasses are put into the structures table. This is for when a block has a receiver that is a class. See checkFatalReshape:.\\n\\nImageSegments:\\n\\tA ReferenceStream is used to enumerate objects to put inside an ImageSegment. If an instance of a UniClass is seen, the class is put in also.\\n\\tA SmartRefStream is used to store the ImageSegment. Roots are nil, and the segment is a wordArray. We are encoding the outPointers. Structures contains all classes from both places. Must filter out UniClasses for some things, and do include them for putting source code at end of file. Do not write any class inst vars in file.\\n\\n--Ted Kaehler and Bob Arning.\\n!\\n\\n\\n!SmartRefStream methodsFor: 'accessing' stamp: 'tk 5/19/1999 15:47'!\\nstructures: anObject\\n\\tstructures _ anObject! !\\n\\n!SmartRefStream methodsFor: 'accessing' stamp: 'tk 5/19/1999 15:47'!\\nsuperclasses: anObject\\n\\tsuperclasses _ anObject! !\\n\\n\\n!SmartRefStream methodsFor: 'class changed shape' stamp: 'tk 1/7/97'!\\ncatalogValues: instVarList size: varsOnDisk\\n\\t\\\"Create a dictionary of (name -> value) for the inst vars of this reshaped object. Indexed vars as (1 -> val) etc. \\\"\\n\\n\\t| dict sz |\\n\\tdict _ Dictionary new.\\n\\t2 to: instVarList size do: [:ind |\\n\\t\\tdict at: (instVarList at: ind) put: self next].\\n\\tsz _ varsOnDisk - (instVarList size - 1).\\n\\t1 to: sz do: [:ii | \\n\\t\\tdict at: ii put: self next].\\n\\t\\\"Total number read MUST be equal to varsOnDisk!!\\\"\\n\\tsz > 0 ifTrue: [dict at: #SizeOfVariablePart put: sz].\\n\\t^ dict! !\\n\\n!SmartRefStream methodsFor: 'class changed shape' stamp: 'ar 9/27/2005 22:41'!\\nconversionMethodsFor: classList\\n\\t| oldStruct newStruct list |\\n\\t\\\"Each of these needs a conversion method. Hard part is the comment in it. Return a MessageSet.\\\"\\n\\n\\tlist _ OrderedCollection new.\\n\\tclassList do: [:cls |\\n\\t\\toldStruct _ structures at: cls name ifAbsent: [#()].\\n\\t\\tnewStruct _ (Array with: cls classVersion), (cls allInstVarNames).\\n\\t\\tself writeConversionMethodIn: cls fromInstVars: oldStruct to: newStruct \\n\\t\\t\\t\\trenamedFrom: nil.\\n\\t\\tlist add: cls name, ' convertToCurrentVersion:refStream:'.\\n\\t\\t].\\n\\n\\t^list.! !\\n\\n!SmartRefStream methodsFor: 'class changed shape' stamp: 'tk 5/26/97'!\\nstoreInstVarsIn: anObject from: dict\\n\\t\\\"For instance variables with the same names, store them in the new instance. Values in variable-length part also. This is NOT the normal inst var transfer!! See Object.readDataFrom:size:. This is for when inst var names have changed and some additional conversion is needed. Here we handle the unchanged vars. \\\"\\n\\n\\t(anObject class allInstVarNames) doWithIndex: [:varName :index |\\n\\t\\t(dict includesKey: varName) ifTrue: [\\n\\t\\t\\tanObject instVarAt: index put: (dict at: varName)]].\\n\\t\\\"variable part\\\"\\n\\t(dict includesKey: #SizeOfVariablePart) ifFalse: [^ anObject].\\n\\t1 to: (dict at: #SizeOfVariablePart) do: [:index | \\n\\t\\tanObject basicAt: index put: (dict at: index)].\\n\\t^ anObject! !\\n\\n!SmartRefStream methodsFor: 'class changed shape' stamp: 'tk 6/8/2001 09:57'!\\nwriteClassRename: newName was: oldName\\n\\t\\\"Write a method that tells which modern class to map instances to.\\\"\\n\\t| oldVer sel code |\\n\\n\\toldVer _ self versionSymbol: (structures at: oldName).\\n\\tsel _ oldName asString.\\n\\tsel at: 1 put: (sel at: 1) asLowercase.\\n\\tsel _ sel, oldVer.\\t\\\"i.e. #rectangleoc4\\\"\\n\\n\\tcode _ WriteStream on: (String new: 500).\\n\\tcode nextPutAll: sel; cr.\\n\\tcode cr; tab; nextPutAll: '^ ', newName.\\t\\\"Return new class\\\"\\n\\n\\tself class compile: code contents classified: 'conversion'.\\n\\n! !\\n\\n!SmartRefStream methodsFor: 'class changed shape' stamp: 'CdG 10/17/2005 21:01'!\\nwriteClassRenameMethod: sel was: oldName fromInstVars: oldList\\n\\t\\\"The class coming is unknown. Ask the user for the existing class it maps to. If got one, write a method, and restart the obj fileIn. If none, write a dummy method and get the user to complete it later. \\\"\\n\\n| tell choice newName answ code |\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\ntell := 'Reading an instance of ', oldName, '.\\nWhich modern class should it translate to?'.\\nansw := (UIManager default \\n\\t\\tchooseFrom: #('Let me type the name now' 'Let me think about it'\\n'Let me find a conversion file on the disk') \\n\\t\\ttitle: tell). \\n\\nansw = 1 ifTrue: [\\n\\ttell := 'Name of the modern class {1} should translate to:' translated format: {oldName}.\\n\\tchoice := UIManager default request: tell.\\t\\t\\\"class name\\\"\\n\\t(choice size = 0) \\n\\t\\tifTrue: [answ := 'conversion method needed']\\n\\t\\tifFalse: [newName := choice.\\n\\t\\t\\tansw := Smalltalk at: newName asSymbol \\n\\t\\t\\t\\tifAbsent: ['conversion method needed'].\\n\\t\\t\\tansw isString ifFalse: [renamed at: oldName asSymbol put: answ name]]].\\n(answ = 3) | (answ = 0) ifTrue: [self close.\\n\\t\\t^ 'conversion method needed'].\\nansw = 2 ifTrue: [answ := 'conversion method needed'].\\nansw = 'conversion method needed' ifTrue: [\\n\\t\\tself close. \\n\\t\\tnewName := 'PutNewClassHere'].\\n\\ncode := WriteStream on: (String new: 500).\\ncode nextPutAll: sel; cr.\\ncode cr; tab; nextPutAll: '^ ', newName.\\t\\\"Return new class\\\"\\n\\nself class compile: code contents classified: 'conversion'.\\n\\nnewName = 'PutNewClassHere' ifTrue: [\\n\\tself inform: 'Please complete the following method and \\nthen read-in the object file again.'.\\n\\tSystemNavigation default browseAllImplementorsOf: sel asSymbol]. \\n\\n\\t\\\"The class version number only needs to change under one specific circumstance. That is when the first letters of the instance variables have stayed the same, but their meaning has changed. A conversion method is needed, but this system does not know it. \\n\\tIf this is true for class Foo, define classVersion in Foo class. \\n\\tBeware of previous object fileouts already written after the change in meaning, but before bumping the version number. They have the old (wrong) version number, say 2. If this is true, your method must be able to test the data and successfully read files that say version 2 but are really 3.\\\"\\n\\n\\t^ answ! !\\n\\n!SmartRefStream methodsFor: 'class changed shape' stamp: 'tk 6/7/2001 13:02'!\\nwriteConversionMethod: sel class: newClass was: oldName fromInstVars: oldList to: newList\\n\\t\\\"The method convertToCurrentVersion:refStream: was not found in newClass. Write a default conversion method for the author to modify.\\\"\\n\\n\\t| code newOthers oldOthers copied |\\n\\n\\tcode _ WriteStream on: (String new: 500).\\n\\tcode nextPutAll: 'convertToCurrentVersion: varDict refStream: smartRefStrm'; cr; tab.\\n\\tnewOthers _ newList asOrderedCollection \\\"copy\\\".\\n\\toldOthers _ oldList asOrderedCollection \\\"copy\\\".\\n\\tcopied _ OrderedCollection new.\\n\\tnewList do: [:instVar |\\n\\t\\t(oldList includes: instVar) ifTrue: [\\n\\t\\t\\tinstVar isInteger ifFalse: [copied add: instVar].\\n\\t\\t\\tnewOthers remove: instVar.\\n\\t\\t\\toldOthers remove: instVar]].\\n\\tcode nextPutAll: '\\\"These variables are automatically stored into the new instance '.\\n\\tcode nextPutAll: copied asArray printString; nextPut: $. .\\n\\tcode cr; tab; nextPutAll: 'This method is for additional changes.'; \\n\\t\\tnextPutAll: ' Use statements like (foo _ varDict at: ''foo'').\\\"'; cr; cr; tab.\\n\\t(newOthers size = 0) & (oldOthers size = 0) ifTrue: [^ self].\\n\\t\\t\\\"Instance variables are the same. Only the order changed. No conversion needed.\\\"\\n\\t(newOthers size > 0) ifTrue: [code nextPutAll: '\\\"New variables: ', newOthers asArray printString, ' If a non-nil value is needed, please assign it.\\\"\\\\' withCRs].\\n\\t(oldOthers size > 0) ifTrue: [code nextPutAll: '\\t\\\"These are going away ', oldOthers asArray printString, '. Possibly store their info in some other variable?\\\"'].\\n\\n\\tcode cr; tab.\\n\\tcode nextPutAll: '^ super convertToCurrentVersion: varDict refStream: smartRefStrm'.\\n\\tnewClass compile: code contents classified: 'object fileIn'.\\n\\n\\n\\t\\\"If you write a conversion method beware that the class may need a version number change. This only happens when two conversion methods in the same class have the same selector name. (A) The inst var lists of the new and old versions intials as some older set of new and old inst var lists. or (B) Twice in a row, the class needs a conversion method, but the inst vars stay the same the whole time. (For an internal format change.)\\n\\tIf either is the case, fileouts already written with the old (wrong) version number, say 2. Your method must be able to read files that say version 2 but are really 3, until you expunge the erroneous version 2 files from the universe.\\\"\\n\\n ! !\\n\\n!SmartRefStream methodsFor: 'class changed shape' stamp: 'nk 7/29/2004 10:10'!\\nwriteConversionMethodIn: newClass fromInstVars: oldList to: newList renamedFrom: oldName\\n\\t\\\"The method convertToCurrentVersion:refStream: was not found in newClass. Write a default conversion method for the author to modify. If method exists, append new info into the end.\\\"\\n\\n\\t| code newOthers oldOthers copied newCode |\\n\\n\\tnewOthers _ newList asOrderedCollection \\\"copy\\\".\\n\\toldOthers _ oldList asOrderedCollection \\\"copy\\\".\\n\\tcopied _ OrderedCollection new.\\n\\tnewList do: [:instVar |\\n\\t\\t(oldList includes: instVar) ifTrue: [\\n\\t\\t\\tinstVar isInteger ifFalse: [copied add: instVar].\\n\\t\\t\\tnewOthers remove: instVar.\\n\\t\\t\\toldOthers remove: instVar]].\\n\\tcode _ WriteStream on: (String new: 500).\\n\\tcode cr; cr; tab; nextPutAll: '\\\"From ', SystemVersion current version, ' [', SmalltalkImage current lastUpdateString;\\n\\t\\t\\tnextPutAll: '] on ', Date today printString, '\\\"'; cr.\\n\\tcode tab; nextPutAll: '\\\"These variables are automatically stored into the new instance: '.\\n\\tcode nextPutAll: copied asArray printString; nextPut: $.; cr.\\n\\tcode tab; nextPutAll: 'Test for this particular conversion.'; \\n\\t\\tnextPutAll: ' Get values using expressions like (varDict at: ''foo'').\\\"'; cr; cr.\\n\\t(newOthers size = 0) & (oldOthers size = 0) & (oldName == nil) ifTrue: [^ self].\\n\\t\\t\\\"Instance variables are the same. Only the order changed. No conversion needed.\\\"\\n\\t(newOthers size > 0) ifTrue: [\\n\\t\\tcode tab; nextPutAll: '\\\"New variables: ', newOthers asArray printString, \\n\\t\\t\\t'. If a non-nil value is needed, please assign it.\\\"'; cr].\\n\\t(oldOthers size > 0) ifTrue: [\\n\\t\\tcode tab; nextPutAll: '\\\"These are going away ', oldOthers asArray printString, \\n\\t\\t\\t'. Possibly store their info in some other variable?\\\"'; cr].\\n\\toldName ifNotNil: [\\n\\t\\tcode tab; nextPutAll: '\\\"Test for instances of class ', oldName, '.'; cr.\\n\\t\\tcode tab; nextPutAll: 'Instance vars with the same name have been moved here.\\\"'; cr.\\n\\t\\t].\\n\\tcode tab; nextPutAll: '\\\"Move your code above the ^ super... Delete extra comments.\\\"'; cr. \\n\\n\\t(newClass includesSelector: #convertToCurrentVersion:refStream:) \\n\\t\\tifTrue: [\\\"append to old methods\\\"\\n\\t\\t\\tnewCode _ (newClass sourceCodeAt: #convertToCurrentVersion:refStream:),\\n\\t\\t\\t\\tcode contents]\\n\\t\\tifFalse: [\\\"new method\\\"\\n\\t\\t\\tnewCode _ 'convertToCurrentVersion: varDict refStream: smartRefStrm',\\n\\t\\t\\t\\tcode contents, \\n\\t\\t\\t\\t'\\t^ super convertToCurrentVersion: varDict refStream: smartRefStrm'].\\n\\tnewClass compile: newCode classified: 'object fileIn'.\\n\\n\\n\\t\\\"If you write a conversion method beware that the class may need a version number change. This only happens when two conversion methods in the same class have the same selector name. (A) The inst var lists of the new and old versions intials as some older set of new and old inst var lists. or (B) Twice in a row, the class needs a conversion method, but the inst vars stay the same the whole time. (For an internal format change.)\\n\\tIf either is the case, fileouts already written with the old (wrong) version number, say 2. Your method must be able to read files that say version 2 but are really 3, until you expunge the erroneous version 2 files from the universe.\\\"\\n\\n ! !\\n\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'ar 4/10/2005 15:44'!\\nabstractStringx0\\n\\n\\t^ String! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'ar 7/29/2005 18:41'!\\nalansTextPlusMorphbosfcebbmsopssrsggshtt0\\n\\n\\t^ TextPlusMorph! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'jm 5/21/1998 06:44'!\\nbookPageMorphbosfcepcbbfgcc0\\n\\t\\\"BookPageMorph->PasteUpMorph. For reading in old BookMorphs.\\\"\\n\\n\\t^ PasteUpMorph\\n! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'di 5/22/1998 15:03'!\\nclippingMorphbosfcep0\\n\\t^ PasteUpMorph! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'jm 5/21/1998 06:44'!\\nclippingMorphbosfcepc0\\n\\t\\\"ClippingMorph->PasteUpMorph. For reading in old BookMorphs.\\\"\\n\\n\\t^ PasteUpMorph! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'tk 11/3/2000 18:47'!\\ndropShadowMorphbosfces0\\n\\n\\t^ Morph ! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'jm 11/13/97 10:32'!\\ngradientFillbosfcepbbfgcc0\\n\\t^ GradientFillMorph! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'di 5/21/1998 19:24'!\\nlayoutMorphbosfcepbbochvimol0\\n\\t^ AlignmentMorph! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'tk 5/12/1998 16:18'!\\nlayoutMorphbosfcepcbbochvimol0\\n\\t^ AlignmentMorph! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'ar 10/26/2000 01:55'!\\nmorphicEventtcbks0\\n\\t^ MorphicEvent! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'ar 10/26/2000 00:48'!\\nmorphicSoundEventtcbkss0\\n\\t^ MorphicUnknownEvent! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'ar 4/12/2005 17:38'!\\nmultiStringx0\\n\\n\\t^ WideString! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'ar 4/12/2005 17:38'!\\nmultiSymbolx0\\n\\n\\t^ WideSymbol! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'ar 7/8/2001 17:11'!\\nmyMorphbosfce0\\n\\n\\treshaped at: #MyMorph put: #convertbosfce0:bosfce0:.\\n\\t\\t\\\"Be sure to define that conversion method in class Morph\\\"\\n\\t^ Morph! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'RAA 10/26/2000 09:43'!\\nnewMorphicEventts0\\n\\n\\t^ MorphicEvent! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'mir 7/12/2002 18:03'!\\nscrollControllermvslrrsmsms0\\n\\n\\t^ MouseMenuController! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'tk 1/14/1999 13:16'!\\ntransparentColorrcc0\\n\\t^ TranslucentColor! !\\n\\n!SmartRefStream methodsFor: 'conversion' stamp: 'di 8/16/2000 16:37'!\\nworldMorphbosfcebbfgccpmcpbttloiairfidcuwhavcdsll0\\n\\t^ 'PutNewClassHere' \\\" <-- Replace this by a class name (no string quotes)\\\"! !\\n\\n\\n!SmartRefStream methodsFor: 'import image segment' stamp: 'tk\\n\\n11/26/2004 05:53'!\\napplyConversionMethodsTo: objectIn className: className varMap: varMap\\n\\n\\t\\\"Modify the object's instance vars to have the proper values\\n\\nfor its new shape. Mostly, fill in defaut values of new inst vars.\\n\\nCan substitute an object of a different class. (Beware: if\\n\\nsubstituted, varMap will not be correct when the new object is asked\\n\\nto convert.)\\\"\\n\\n\\t| anObject prevObject |\\n\\n\\n\\n\\tself flag: #bobconv.\\n\\n\\n\\n\\tanObject _ objectIn.\\n\\n\\t[\\n\\n\\t\\tprevObject _ anObject.\\n\\n\\t\\tanObject _ anObject convertToCurrentVersion: varMap\\n\\nrefStream: self.\\n\\n\\t\\tprevObject == anObject\\n\\n\\t] whileFalse.\\n\\n\\t^anObject\\n\\n! !\\n\\n!SmartRefStream methodsFor: 'import image segment' stamp: 'RAA 12/20/2000 11:08'!\\ncheckFatalReshape: setOfClasses\\n\\t| suspects oldInstVars newInstVars bad className |\\n\\t\\\"Inform the user if any of these classes were reshaped. A block has a method from the old system whose receiver is of this class. The method's inst var references might be wrong. OK if inst vars were only added.\\\"\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\tsetOfClasses isEmpty ifTrue: [^ self].\\n\\tsuspects _ OrderedCollection new.\\n\\tsetOfClasses do: [:aClass |\\n\\t\\tclassName _ renamed keyAtValue: aClass name ifAbsent: [aClass name].\\n\\t\\toldInstVars _ (structures at: className ifAbsent: [#(0)]) allButFirst.\\t\\t\\\"should be there\\\"\\n\\t\\tnewInstVars _ aClass allInstVarNames.\\n\\t\\toldInstVars size > newInstVars size ifTrue: [bad _ true].\\n\\t\\toldInstVars size = newInstVars size ifTrue: [\\n\\t\\t\\tbad _ oldInstVars ~= newInstVars].\\n\\t\\toldInstVars size < newInstVars size ifTrue: [\\n\\t\\t\\tbad _ oldInstVars ~= (newInstVars copyFrom: 1 to: oldInstVars size)].\\n\\t\\tbad ifTrue: [suspects add: aClass]].\\n\\n\\tsuspects isEmpty ifFalse: [\\n\\t\\tself inform: ('Imported foreign methods will run on instances of:\\\\',\\n\\t\\t\\tsuspects asArray printString, \\n\\t\\t\\t'\\\\whose shape has changed. Errors may occur.') withCRs].! !\\n\\n!SmartRefStream methodsFor: 'import image segment' stamp: 'RAA 12/20/2000 11:06'!\\nconvert1: misShapenInst to: goodClass allVarMaps: allVarMaps\\n\\t\\\"Go through the normal instance conversion process and return a modern object.\\\"\\n\\n\\t| className oldInstVars anObject varMap |\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\tgoodClass isVariable ifTrue: [\\n\\t\\tgoodClass error: 'shape change for variable class not implemented yet'\\n\\t].\\n\\t(misShapenInst class name beginsWith: 'Fake37') ifFalse: [self error: 'why mapping?'].\\n\\tclassName _ (misShapenInst class name allButFirst: 6) asSymbol.\\n\\toldInstVars _ structures at: className.\\n\\tanObject _ goodClass basicNew.\\n\\n\\tvarMap _ Dictionary new.\\t\\\"later, indexed vars as (1 -> val) etc.\\\"\\n\\t2 to: oldInstVars size do: [:ind |\\n\\t\\tvarMap at: (oldInstVars at: ind) put: (misShapenInst instVarAt: ind-1)].\\n\\tvarMap at: #ClassName put: className.\\t\\\"original\\\"\\n\\tvarMap at: #NewClassName put: goodClass name.\\t\\\"new\\\"\\n\\tself storeInstVarsIn: anObject from: varMap. \\t\\\"ones with the same names\\\"\\n\\tallVarMaps at: misShapenInst put: varMap.\\n\\t^ anObject\\n! !\\n\\n!SmartRefStream methodsFor: 'import image segment' stamp: 'RAA 12/20/2000 17:15'!\\nconvert2: partiallyCorrectInst allVarMaps: allVarMaps\\n\\t\\\"Go through the normal instance conversion process and return a modern object.\\\"\\n\\n\\t| className varMap |\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\tvarMap _ allVarMaps at: partiallyCorrectInst.\\n\\tclassName _ varMap at: #ClassName.\\t\\\"original\\\"\\n\\t^self applyConversionMethodsTo: partiallyCorrectInst className: className varMap: varMap.\\n\\n! !\\n\\n!SmartRefStream methodsFor: 'import image segment' stamp: 'ar 4/12/2005 18:06'!\\nmapClass: newClass origName: originalName\\n\\t\\\"See if instances changed shape. If so, make a fake class for the old shape and return it. Remember the original class name.\\\"\\n\\n\\t| newName oldInstVars fakeClass |\\n\\tnewClass isMeta ifTrue: [^ newClass].\\n\\tnewName _ newClass name.\\n\\t(steady includes: newClass) & (newName == originalName) ifTrue: [^ newClass].\\n\\t\\t\\\"instances in the segment have the right shape\\\"\\n\\toldInstVars _ structures at: originalName ifAbsent: [\\n\\t\\t\\tself error: 'class is not in structures list'].\\t\\\"Missing in object file\\\"\\n\\n\\t\\\"Allow mapping from old to new string names\\\"\\n\\t(newName == #ByteString and:[originalName == #String]) ifTrue:[^newClass].\\n\\t(newName == #WideString and:[originalName == #MultiString]) ifTrue:[^newClass].\\n\\t(newName == #WideSymbol and:[originalName == #MultiSymbol]) ifTrue:[^newClass].\\n\\n\\tfakeClass _ Object subclass: ('Fake37', originalName) asSymbol\\n\\t\\tinstanceVariableNames: oldInstVars allButFirst\\n\\t\\tclassVariableNames: ''\\n\\t\\tpoolDictionaries: ''\\n\\t\\tcategory: 'Obsolete'.\\n\\tChangeSet current removeClassChanges: fakeClass name.\\t\\\"reduce clutter\\\"\\n\\t^ fakeClass\\n! !\\n\\n!SmartRefStream methodsFor: 'import image segment' stamp: 'RAA 12/20/2000 11:09'!\\nreshapedClassesIn: outPointers\\n\\t\\\"Look for classes in the outPointer array that have changed shape. Make a fake class for the old shape. Return a dictionary mapping Fake classes to Real classes. Substitute fake classes for real ones in outPointers.\\\"\\n\\n\\t| mapFakeClassesToReal fakeCls originalName |\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\n\\tmapFakeClassesToReal _ IdentityDictionary new.\\n\\toutPointers withIndexDo: [:outp :ind | \\n\\t\\toutp isBehavior ifTrue: [\\n\\t\\t\\toriginalName _ renamedConv at: ind ifAbsent: [outp name].\\n\\t\\t\\t\\t\\\"in DiskProxy>>comeFullyUpOnReload: we saved the name at the index\\\"\\n\\t\\t\\tfakeCls _ self mapClass: outp origName: originalName.\\n\\t\\t\\tfakeCls == outp ifFalse: [\\n\\t\\t\\t\\tmapFakeClassesToReal at: fakeCls put: outp.\\n\\t\\t\\t\\toutPointers at: ind put: fakeCls]]].\\n\\t^ mapFakeClassesToReal! !\\n\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 3/15/98 20:28'!\\nappendClassDefns\\n\\t\\\"Make this a fileOut format file. For each UniClass mentioned, prepend its source code to the file. Class name conflicts during reading will be resolved then. Assume instVarInfo: has already been done.\\\"\\n\\nbyteStream ascii.\\nbyteStream position = 0 ifTrue: [\\n\\tbyteStream setFileTypeToObject.\\n\\t\\t\\\"Type and Creator not to be text, so can attach correctly to an email msg\\\"\\n\\tbyteStream header; timeStamp].\\n\\nbyteStream cr; nextPutAll: '!!ObjectScanner new initialize!!'; cr; cr.\\nself uniClasesDo: [:class | class\\n\\t\\tclass sharedPools size > 0 ifTrue: \\\"This never happens\\\"\\n\\t\\t\\t[class shouldFileOutPools\\n\\t\\t\\t\\tifTrue: [class fileOutSharedPoolsOn: self]].\\n\\t\\tclass fileOutOn: byteStream moveSource: false toFile: 0].\\t\\n\\t\\t\\\"UniClasses are filed out normally, no special format.\\\"\\n\\n\\tbyteStream trailer.\\t\\\"Does nothing for normal files. \\n\\t\\tHTML streams will have trouble with object data\\\"\\n\\n\\t\\\"Append the object's raw data\\\"\\n\\tbyteStream cr; cr; nextPutAll: '!!self smartRefStream!!'.\\n\\tbyteStream binary.\\t\\t\\\"get ready for objects\\\"\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 6/19/2000 21:22'!\\ncheckCrLf\\n\\t| save isCrLf cc prev loneLf |\\n\\t\\\"Watch for a file that has had all of its Cr's converted to CrLf's. Some unpacking programs like Stuffit 5.0 do this by default!!\\\"\\n\\n\\tsave _ byteStream position.\\n\\tisCrLf _ false. loneLf _ false.\\n\\tcc _ 0.\\n\\t350 timesRepeat: [\\n\\t\\tprev _ cc.\\n\\t\\t(cc _ byteStream next) = 16r0A \\\"Lf\\\" ifTrue: [\\n\\t\\t\\tprev = 16r0D \\\"Cr\\\" ifTrue: [isCrLf _ true] ifFalse: [loneLf _ true]].\\n\\t\\t].\\n\\tisCrLf & (loneLf not) ifTrue: [\\n\\t\\tself inform: 'Carriage Returns in this file were converted to CrLfs \\nby an evil unpacking utility. Please set the preferences in \\nStuffIt Expander to \\\"do not convert file formats\\\"'].\\n\\tbyteStream position: save.\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'mir 9/12/2002 10:59'!\\ninitKnownRenames\\n\\trenamed\\n\\t\\tat: #FlasherMorph put: #Flasher;\\n\\t\\tyourself! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'ar 4/10/2005 19:27'!\\ninitShapeDicts\\n\\t\\\"Initialize me. \\\"\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\t\\\"These must stay constant. When structures read in, then things can change.\\\"\\n\\tsteady _ {Array. Dictionary. Association. ByteString. SmallInteger} asSet.\\n\\n\\trenamed ifNil: [\\n\\t\\trenamed _ Dictionary new. \\\"(old class name symbol -> new class name)\\\"\\n\\t\\trenamedConv _ Dictionary new \\\"(oldClassNameSymbol -> conversionSelectorInNewClass)\\\"\\n\\t].\\n\\tself initKnownRenames! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 3/7/2001 18:17'!\\ninstVarInfo: anObject\\n\\t\\\"Return the object to write on the outgoing file that contains the structure of each class we are about to write out. Must be an Array whose first element is 'class structure'. Its second element is a Dictionary of pairs of the form #Rectangle -> #(<classVersion> 'origin' 'corner'). \\\"\\n\\n\\t\\\"Make a pass through the objects, not writing, but recording the classes. Construct a database of their inst vars and any version info (classVersion).\\\"\\n\\n\\t| dummy refs cls newSupers |\\n\\tstructures _ Dictionary new.\\n\\tsuperclasses _ Dictionary new.\\n\\tdummy _ ReferenceStream on: (DummyStream on: nil).\\n\\t\\t\\\"Write to a fake Stream, not a file\\\"\\n\\t\\\"Collect all objects\\\"\\n\\tdummy rootObject: anObject.\\t\\\"inform him about the root\\\"\\n\\tdummy nextPut: anObject.\\n\\trefs _ dummy references.\\n\\tobjCount _ refs size.\\t\\t\\\"for progress bar\\\"\\n\\t\\t\\\"Note that Dictionary must not change its implementation!! If it does, how do we read this reading information?\\\"\\n\\t(refs includesKey: #AnImageSegment) \\n\\t\\tifFalse: [\\n\\t\\t\\tself uniClassInstVarsRefs: dummy.\\t\\\"catalog the extra objects in UniClass inst vars\\\"\\n\\t\\t\\trefs keysDo: [:each | \\n\\t\\t\\t\\tcls _ each class.\\n\\t\\t\\t\\t\\\"cls isObsolete ifTrue: [self error: 'Trying to write ', cls name].\\\"\\n\\t\\t\\t\\t(cls class ~~ Metaclass) & (cls isObsolete not) ifTrue: [\\n\\t\\t\\t\\t\\tstructures at: cls name put: false]]]\\n\\t\\tifTrue: [self recordImageSegment: refs].\\n\\t\\\"Save work by only computing inst vars once for each class\\\"\\n\\tnewSupers _ Set new.\\n\\tstructures at: #Point put: false.\\t\\\"writeRectangle: does not put out class pointer\\\"\\n\\tstructures at: #Rectangle put: false.\\n\\tstructures at: #LargePositiveInteger put: false.\\t\\\"used in slow case of WordArray\\\"\\n\\tstructures keysDo: [:nm | \\n\\t\\tcls _ (nm endsWith: ' class') \\n\\t\\t\\tifFalse: [Smalltalk at: nm]\\n\\t\\t\\tifTrue: [(Smalltalk at: nm substrings first asSymbol) class].\\n\\t\\tcls allSuperclasses do: [:aSuper |\\n\\t\\t\\tstructures at: aSuper name ifAbsent: [newSupers add: aSuper name]]].\\n\\t\\t\\t\\\"Don't modify structures during iteration\\\"\\n\\tnewSupers do: [:nm | structures at: nm put: 3].\\t\\\"Get all superclasses into list\\\"\\n\\tstructures keysDo: [:nm | \\\"Nothing added to classes during loop\\\"\\n\\t\\tcls _ (nm endsWith: ' class') \\n\\t\\t\\tifFalse: [Smalltalk at: nm]\\n\\t\\t\\tifTrue: [(Smalltalk at: nm substrings first asSymbol) class].\\n\\t\\tstructures at: nm put: \\n\\t\\t\\t((Array with: cls classVersion), (cls allInstVarNames)).\\n\\t\\tsuperclasses at: nm ifAbsent: [\\n\\t\\t\\t\\tsuperclasses at: nm put: cls superclass name]].\\n\\t(refs includesKey: #AnImageSegment) \\n\\t\\tifTrue: [classInstVars _ #()]\\n\\t\\tifFalse: [self saveClassInstVars].\\t\\\"of UniClassses\\\"\\n\\t^ (Array with: 'class structure' with: structures with: 'superclasses' with: superclasses)! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'ar 4/10/2005 18:52'!\\nmapClass: incoming\\n\\t\\\"See if the old class named nm exists. If so, return it. If not, map it to a new class, and save the mapping in renamed. \\\"\\n\\n\\t| cls oldVer sel nm |\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\n\\tnm _ renamed at: incoming ifAbsent: [incoming].\\t\\\"allow pre-mapping around collisions\\\"\\n\\t(nm endsWith: ' class') \\n\\t\\tifFalse: [cls _ Smalltalk at: nm ifAbsent: [nil].\\n\\t\\t\\tcls ifNotNil: [^ cls]] \\t\\\"Known class. It will know how to translate the instance.\\\"\\n\\t\\tifTrue: [cls _ Smalltalk at: nm substrings first asSymbol ifAbsent: [nil].\\n\\t\\t\\tcls ifNotNil: [^ cls class]]. \\t\\\"Known class. It will know how to translate the instance.\\\"\\n\\toldVer _ self versionSymbol: (structures at: nm).\\n\\tsel _ nm asString.\\n\\tsel at: 1 put: (sel at: 1) asLowercase.\\n\\tsel _ sel, oldVer.\\t\\\"i.e. #rectangleoc4\\\"\\n\\tSymbol hasInterned: sel ifTrue: [:symb | \\n\\t\\t(self class canUnderstand: sel asSymbol) ifTrue: [\\n\\t\\t\\treshaped ifNil: [reshaped _ Dictionary new].\\n\\t\\t\\tcls _ self perform: sel asSymbol]].\\t\\\"This class will take responsibility\\\"\\n\\tcls ifNil: [cls _ self writeClassRenameMethod: sel was: nm\\n\\t\\t\\t\\t\\tfromInstVars: (structures at: nm).\\n\\t\\t\\t cls isString ifTrue: [cls _ nil]].\\n\\tcls ifNotNil: [renamed at: nm put: cls name].\\n\\t^ cls\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 5/26/1998 15:09'!\\nmoreObjects\\n\\t\\\"Return true if there appears to be another object following this one on the file.\\\"\\n\\n\\t| byte |\\n\\tbyteStream atEnd ifTrue: [^ false].\\t\\\"off end of file\\\"\\n\\t(byte _ byteStream peek) ifNil: [^ false].\\t\\\"off end of file\\\"\\n\\tbyte = 33 \\\"$!! asciiValue\\\" ifTrue: [^ false].\\n\\tbyte = 0 ifTrue: [^ false].\\n\\t^ byte <= RefTypes size\\t\\t\\\"between 1 and 16\\\"! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 6/19/2000 17:06'!\\nnext\\n\\t\\\"Really write three objects: (version, class structure, object). But only when called from the outside. \\\"\\n\\n\\t| version ss object |\\n\\t^ topCall == nil \\n\\t\\tifTrue: \\n\\t\\t\\t[topCall _ #marked.\\n\\t\\t\\tversion _ super next.\\n\\t\\t\\tversion class == SmallInteger ifFalse: [^ version].\\t\\n\\t\\t\\t\\t\\\"version number, else just a regular object, not in our format, \\\"\\n\\t\\t\\tself checkCrLf.\\n\\t\\t\\tss _ super next.\\n\\t\\t\\tss class == Array ifFalse: [^ ss]. \\\"just a regular object\\\"\\n\\t\\t\\t(ss at: 1) = 'class structure' ifFalse: [^ ss].\\n\\t\\t\\tstructures _ ss at: 2.\\n\\t\\t\\tsuperclasses _ (ss size > 3 and: [(ss at: 3) = 'superclasses']) \\n\\t\\t\\t\\tifTrue: [ss at: 4]\\t\\t\\\"class name -> superclass name\\\"\\n\\t\\t\\t\\tifFalse: [Dictionary new].\\n\\t\\t\\t(self verifyStructure = 'conversion method needed') ifTrue: [^ nil].\\n\\t\\t\\tobject _ super next.\\t\\\"all the action here\\\"\\n\\t\\t\\tself restoreClassInstVars.\\t\\t\\\"for UniClasses. version 4\\\"\\n\\n\\t\\t\\ttopCall _ nil.\\t\\\"reset it\\\"\\n\\t\\t\\tobject]\\n\\t\\tifFalse:\\n\\t\\t\\t[super next]\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 3/5/2002 09:52'!\\nnextAndClose\\n\\t\\\"Speedy way to grab one object. Only use when we are inside an object binary file. If used for the start of a SmartRefStream mixed code-and-object file, tell the user and then do the right thing.\\\"\\n\\n\\t| obj |\\n\\tbyteStream peek = ReferenceStream versionCode \\\"4\\\" ifFalse: [\\n\\t\\t\\\"OK it is a fileIn afterall...\\\"\\n\\t\\tself inform: 'Should be using fileInObjectAndCode'.\\n\\t\\tbyteStream ascii.\\n\\t\\tbyteStream fileIn.\\n\\t\\tobj _ SmartRefStream scannedObject.\\n\\t\\tSmartRefStream scannedObject: nil.\\n\\t\\t^ obj].\\n\\n\\tobj _ self next.\\n\\tself close.\\n\\t^ obj! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'md 2/24/2006 19:52'!\\nnextPut: anObject\\n\\t\\\"Really write three objects: (version, class structure, object). But only when called from the outside. If any instance-specific classes are present, prepend their source code. byteStream will be in fileOut format.\\n\\tYou can see an analysis of which objects are written out by doing: \\n\\t(SmartRefStream statsOfSubObjects: anObject)\\n\\t(SmartRefStream tallyOfSubObjects: anObject)\\n\\t(SmartRefStream subObjects: anObject ofClass: aClass)\\\"\\n\\n| info |\\ntopCall == nil \\n\\tifTrue:\\n\\t\\t[topCall _ anObject.\\n\\t\\t'Please wait while objects are counted' \\n\\t\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\t\\tfrom: 0 to: 10\\n\\t\\t\\tduring: [:bar | info _ self instVarInfo: anObject].\\n\\t\\tself appendClassDefns.\\t\\\"For instance-specific classes\\\"\\n\\t\\t'Writing an object file' displayProgressAt: Sensor cursorPoint\\n\\t\\t\\tfrom: 0 to: objCount*4\\t\\\"estimate\\\"\\n\\t\\t\\tduring: [:bar |\\n\\t\\t\\t\\tobjCount _ 0.\\n\\t\\t\\t\\tprogressBar _ bar.\\n\\t\\t\\t\\tself setStream: byteStream reading: false.\\n\\t\\t\\t\\t\\t\\\"set basePos, but keep any class renames\\\"\\n\\t\\t\\t\\tsuper nextPut: ReferenceStream versionCode.\\n\\t\\t\\t\\tsuper nextPut: info.\\n\\t\\t\\t\\tsuper nextPut: anObject.\\t\\t\\\"<- the real writing\\\"\\n\\t\\t\\t\\tclassInstVars size > 0 ifTrue: [super nextPut: classInstVars]].\\n\\t\\t\\t\\t\\t\\\"Note: the terminator, $!!, is not doubled inside object data\\\"\\n\\t\\t\\\"references is an IDict of every object that got written\\\"\\n\\t\\tbyteStream ascii.\\n\\t\\tbyteStream nextPutAll: '!!'; cr; cr.\\n\\t\\tbyteStream padToEndWith: $ .\\t\\\"really want to truncate file, but can't\\\"\\n\\t\\ttopCall _ progressBar _ nil]\\t\\\"reset it\\\"\\n\\tifFalse:\\n\\t\\t[super nextPut: anObject.\\n\\t\\tprogressBar ifNotNil: [progressBar value: (objCount _ objCount + 1)]].\\n\\t\\t\\\"return the argument - added by kwl\\\"\\n\\t^ anObject\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 6/23/1998 11:00'!\\nnextPutObjOnly: anObject\\n\\t\\\"Really write three objects: (version, class structure, object). But only when called from the outside. Not in fileOut format. No class definitions will be written for instance-specific classes. Error if find one. (Use nextPut: instead)\\\"\\n\\n\\t| info |\\n\\ttopCall == nil \\n\\t\\tifTrue:\\n\\t\\t\\t[topCall _ anObject.\\n\\t\\t\\tsuper nextPut: ReferenceStream versionCode.\\n\\t\\t\\t'Please wait while objects are counted' displayProgressAt: Sensor cursorPoint\\n\\t\\t\\t\\tfrom: 0 to: 10\\n\\t\\t\\t\\tduring: [:bar |\\n\\t\\t\\t\\t\\tinfo _ self instVarInfo: anObject].\\n\\t\\t\\tself uniClasesDo: [:cls | cls error: 'Class defn not written out. Proceed?'].\\n\\t\\t\\t'Writing an object file' displayProgressAt: Sensor cursorPoint\\n\\t\\t\\t\\tfrom: 0 to: objCount*4\\t\\\"estimate\\\"\\n\\t\\t\\t\\tduring: [:bar |\\n\\t\\t\\t\\t\\tobjCount _ 0.\\n\\t\\t\\t\\t\\tprogressBar _ bar.\\n\\t\\t\\t\\t\\tsuper nextPut: info.\\n\\t\\t\\t\\t\\tsuper nextPut: anObject.\\t\\\"<- the real writing\\\"\\n\\t\\t\\t\\t\\t\\\"Class inst vars not written here!!\\\"].\\n\\t\\t\\t\\\"references is an IDict of every object that got written\\n\\t\\t\\t(in case you want to take statistics)\\\"\\n\\t\\t\\t\\\"Transcript cr; show: structures keys printString.\\\"\\t\\t\\\"debug\\\"\\n\\t\\t\\ttopCall _ progressBar _ nil]\\t\\\"reset it\\\"\\n\\t\\tifFalse:\\n\\t\\t\\t[super nextPut: anObject.\\n\\t\\t\\tprogressBar ifNotNil: [progressBar value: (objCount _ objCount + 1)]].! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 6/23/1998 11:13'!\\nnoHeader\\n\\t\\\"Signal that we've already dealt with the version and structure array, and are now reading objects.\\\"\\n\\n\\ttopCall _ #marked.\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 11/3/2000 17:59'!\\nreadInstance\\n\\t\\\"Read the contents of an arbitrary instance.\\n\\t ASSUMES: readDataFrom:size: sends me beginReference: after it\\n\\t instantiates the new object but before reading nested objects.\\n\\t NOTE: We must restore the current reference position after\\n\\t recursive calls to next.\\nThree cases for files from older versions of the system:\\n1) Class has not changed shape, read it straight.\\n2) Class has changed instance variables (or needs fixup). Call a particular method to do it.\\n3) There is a new class instead. Find it, call a particular method to read.\\n\\tAll classes used to construct the structures dictionary *itself* need to be in 'steady' and they must not change!! See setStream:\\\"\\n\\t| instSize className refPosn |\\n\\n\\tinstSize _ (byteStream nextNumber: 4) - 1.\\n\\trefPosn _ self getCurrentReference.\\n\\tclassName _ self next asSymbol.\\n\\t^ self readInstanceSize: instSize clsname: className refPosn: refPosn\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'yo 1/21/2006 19:27'!\\nreadInstanceSize: instSize clsname: className refPosn: refPosn\\n\\t\\\"The common code to read the contents of an arbitrary instance.\\n\\t ASSUMES: readDataFrom:size: sends me beginReference: after it\\n\\t instantiates the new object but before reading nested objects.\\n\\t NOTE: We must restore the current reference position after\\n\\t recursive calls to next.\\nThree cases for files from older versions of the system:\\n1) Class has not changed shape, read it straight.\\n2) Class has changed instance variables (or needs fixup). Call a particular method to do it.\\n3) There is a new class instead. Find it, call a particular method to read.\\n\\tAll classes used to construct the structures dictionary *itself* need to be in 'steady' and they must not change!! See setStream:\\\"\\n\\t| anObject newName newClass dict oldInstVars isMultiSymbol |\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\tself setCurrentReference: refPosn. \\\"remember pos before readDataFrom:size:\\\"\\n\\tnewName _ renamed at: className ifAbsent: [className].\\n\\tisMultiSymbol _ newName = #MultiSymbol or: [newName = #WideSymbol].\\n\\t\\\"isMultiSymbol ifTrue: [self halt].\\\"\\n\\tnewClass _ Smalltalk at: newName asSymbol.\\n\\t(steady includes: newClass) & (newName == className) ifTrue: [\\n\\t \\tanObject _ newClass isVariable \\\"Create it here\\\"\\n\\t\\t\\tifFalse: [newClass basicNew]\\n\\t\\t\\tifTrue: [newClass basicNew: instSize - (newClass instSize)].\\n\\n\\t\\tanObject _ anObject readDataFrom: self size: instSize.\\n\\t\\tself setCurrentReference: refPosn. \\\"before returning to next\\\"\\n\\t\\tisMultiSymbol ifTrue: [^ Symbol intern: anObject asString].\\n\\t\\t^ anObject].\\n\\toldInstVars _ structures at: className ifAbsent: [\\n\\t\\t\\tself error: 'class is not in structures list'].\\t\\\"Missing in object file\\\"\\n\\tanObject _ newClass createFrom: self size: instSize version: oldInstVars.\\n\\t\\t\\\"only create the instance\\\"\\n\\tself beginReference: anObject.\\n\\tdict _ self catalogValues: oldInstVars size: instSize.\\n\\t\\t\\\"indexed vars as (1 -> val) etc.\\\"\\n\\tdict at: #ClassName put: className.\\t\\\"so conversion method can know it\\\"\\n\\n\\t\\\"Give each superclass a chance to make its changes\\\"\\n\\tself storeInstVarsIn: anObject from: dict.\\t\\\"ones with the same names\\\"\\n\\n\\tanObject _ self applyConversionMethodsTo: anObject className: className varMap: dict.\\n\\n\\tself setCurrentReference: refPosn. \\\"before returning to next\\\"\\n\\tisMultiSymbol ifTrue: [^ Symbol intern: anObject asString].\\n\\t^ anObject! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 11/3/2000 18:04'!\\nreadShortInst\\n\\t\\\"Instance has just one byte of size. Class symbol is encoded in two bytes of file position. See readInstance.\\\"\\n\\t| instSize className refPosn |\\n\\n\\tinstSize _ (byteStream next) - 1.\\t\\\"one byte of size\\\"\\n\\trefPosn _ self getCurrentReference.\\n\\tclassName _ self readShortRef.\\t\\\"class symbol in two bytes of file pos\\\"\\n\\t^ self readInstanceSize: instSize clsname: className refPosn: refPosn\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'ar 7/25/2005 21:30'!\\nreadWordLike\\n\\t| refPosn newClass anObject className |\\n\\t\\\"Can be used by any class that is bits and not bytes (WordArray, Bitmap, SoundBuffer, etc).\\\"\\n\\n\\trefPosn _ self getCurrentReference.\\n\\tclassName _ self next asSymbol.\\n\\tclassName _ renamed at: className ifAbsent: [className].\\n\\tnewClass _ Smalltalk at: className.\\n\\tanObject _ newClass newFromStream: byteStream.\\n\\t\\\"Size is number of long words.\\\"\\n\\tself setCurrentReference: refPosn. \\\"before returning to next\\\"\\n\\t^ anObject\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 10/10/2000 13:36'!\\nrecordImageSegment: refs\\n\\t\\\"Besides the objects being written out, record the structure of instances inside the image segment we are writing out.\\\"\\n\\n\\t| cls list |\\n\\t\\\"Do not record Player class inst vars. They are in the segement.\\\"\\n\\trefs keysDo: [:each | \\n\\t\\tcls _ each class.\\n\\t\\tcls isObsolete ifTrue: [self error: 'Trying to write ', cls name].\\n\\t\\tcls class == Metaclass \\n\\t\\t\\tifFalse: [structures at: cls name put: false.\\n\\t\\t\\t\\t(each isKindOf: ImageSegment) ifTrue: [\\n\\t\\t\\t\\t\\teach outPointers do: [:out |\\n\\t\\t\\t\\t\\t\\t(out isKindOf: Class) ifTrue: [\\n\\t\\t\\t\\t\\t\\t\\tstructures at: out theNonMetaClass name put: false].\\n\\t\\t\\t\\t\\t\\tout class == DiskProxy ifTrue: [\\n\\t\\t\\t\\t\\t\\t\\tout simpleGlobalOrNil ifNotNil: [\\n\\t\\t\\t\\t\\t\\t\\t\\t(out simpleGlobalOrNil isKindOf: Class) ifTrue: [\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tstructures at: out simpleGlobalOrNil name put: false]]]].\\n\\t\\t\\t\\t\\t\\\"each arrayOfRoots do: [:rr | (rr isKindOf: Class) ifTrue: [\\n\\t\\t\\t\\t\\t\\t\\tstructures at: rr theNonMetaClass name put: false]].\\\"\\n\\t\\t\\t\\t\\t \\t\\\"all classes in roots are local to seg\\\"]]].\\n\\tlist _ refs at: #BlockReceiverClasses ifAbsent: [^ self].\\n\\tlist do: [:meta | structures at: meta name put: false].\\n\\t\\t\\\"Just the metaclasses whose instances are block receivers. Otherwise metaclasses are not allowed.\\\"! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'RAA 12/20/2000 11:08'!\\nrenamed\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\n\\t^ renamed! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'RAA 12/20/2000 11:10'!\\nrenamedConv\\n\\tself flag: #bobconv.\\t\\n\\n\\n\\t^ renamedConv! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'RAA 12/22/2000 15:14'!\\nrestoreClassInstVars\\n\\t\\\"Install the values of the class instance variables of UniClasses\\n(i.e. scripts slotInfo). classInstVars is ((#Player25 scripts slotInfo)\\n...). Thank you Mark Wai for the bug fix.\\\"\\n\\n\\t| normal aName newName newCls trans rList start |\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\n\\tself moreObjects ifFalse: [^ self]. \\t\\\"are no UniClasses with class inst vars\\\"\\n\\tclassInstVars _ super next.\\t\\\"Array of arrays\\\"\\n\\tnormal _ Object class instSize.\\t\\\"might give trouble if Player class superclass changes size\\\"\\n\\t(structures at: #Player ifAbsent: [#()]) = #(0 'dependents' 'costume') ifTrue:\\n\\t\\t[trans _ 1].\\t\\\"now (0 costume costumes). Do the conversion of Player class\\n\\t\\t\\tinst vars in Update 509.\\\"\\n\\tclassInstVars do: [:list |\\n\\t\\taName _ (list at: 1) asSymbol.\\n\\t\\trList _ list.\\n\\t\\tnewName _ renamed at: aName ifAbsent: [aName].\\n\\t\\tnewCls _ Smalltalk at: newName\\n\\t\\t\\t\\tifAbsent: [self error: 'UniClass definition missing'].\\n\\t\\t(\\\"old conversion\\\" trans == 1 and: [newCls inheritsFrom: Player]) ifTrue: [\\n\\t\\t\\t\\\"remove costumeDictionary from Player class inst vars\\\"\\n\\t\\t\\trList _ rList asOrderedCollection.\\n\\t\\t\\trList removeAt: 4].\\t\\\"costumeDictionary's value\\\"\\n\\t\\tstart _ list second = 'Update to read classPool' ifTrue: [4] ifFalse: [2].\\n\\t\\tnewCls class instSize = (normal + (rList size) - start + 1) ifFalse:\\n\\t\\t\\t[self error: 'UniClass superclass class has changed size'].\\n\\t\\t\\t\\\"Need to install a conversion method mechanism\\\"\\n\\t\\tstart = 4 ifTrue: [newCls instVarAt: normal - 1 \\\"classPool\\\" put: (list at: 3)].\\n\\t\\tstart to: rList size do: [:ii |\\n\\t\\t\\tnewCls instVarAt: normal + ii - start + 1 put: (rList at: ii)]].\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 3/6/2000 18:17'!\\nsaveClassInstVars\\n\\t\\\"Install the values of the instance variables of UniClasses.\\nclassInstVars is an array of arrays (#Player3 (Player3 class's inst var\\nscripts) (Player3 class's inst var slotInfo) ...) \\\"\\n\\n\\t| normal mySize list clsPoolIndex |\\n\\tclassInstVars _ OrderedCollection new: 100.\\n\\tnormal _ Object class instSize.\\n\\tclsPoolIndex _ Object class allInstVarNames indexOf: 'classPool'.\\n\\tself uniClasesDo: [:aUniClass |\\n\\t\\tlist _ OrderedCollection new.\\n\\t\\tmySize _ aUniClass class instSize.\\n\\t\\tmySize = normal ifFalse:\\n\\t\\t\\t[list add: aUniClass name.\\t\\\"a symbol\\\"\\n\\t\\t\\tlist add: 'Update to read classPool'.\\t\\\"new\\nconvention for saving the classPool\\\"\\n\\t\\t\\tlist add: (aUniClass instVarAt: clsPoolIndex)\\n\\\"classPool\\\".\\n\\t\\t\\t\\t\\t\\t\\\"write actual value of nil\\ninstead of Dictionary()\\\"\\n\\t\\t\\tnormal + 1 to: mySize do: [:ii |\\n\\t\\t\\t\\tlist addLast: (aUniClass instVarAt: ii)].\\n\\t\\t\\tclassInstVars add: list asArray]].\\n\\tclassInstVars _ classInstVars asArray.\\n\\t! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 8/18/1998 09:02'!\\nscanFrom: aByteStream\\n\\t\\\"During a code fileIn, we need to read in an object, and stash it in ScannedObject. \\\"\\n\\n\\tself setStream: aByteStream reading: true.\\n\\tScannedObject _ self next.\\n\\tbyteStream ascii.\\n\\tbyteStream next == $!! ifFalse: [\\n\\t\\tbyteStream close.\\n\\t\\tself error: 'Object did not end correctly']. \\n\\t\\\"caller will close the byteStream\\\"\\n\\t\\\"HandMorph.readMorphFile will retrieve the ScannedObject\\\"! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'RAA 12/20/2000 16:57'!\\nsetStream: aStream\\n\\t\\\"Initialize me. \\\"\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\tsuper setStream: aStream.\\n\\tself initShapeDicts.\\n\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'RAA 12/20/2000 16:57'!\\nsetStream: aStream reading: isReading\\n\\t\\\"Initialize me. \\\"\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\tsuper setStream: aStream reading: isReading.\\n\\tisReading ifFalse: [^ false].\\n\\tself initShapeDicts.\\n\\n! !\\n\\n!SmartRefStream methodsFor: 'read write'!\\nstructures\\n\\t^ structures! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 9/28/97 11:17'!\\nsuperclasses\\n\\t^superclasses! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 3/6/2000 17:15'!\\nuniClasesDo: aBlock\\n\\t\\\"Examine structures and execute the block with each instance-specific class\\\"\\n\\n\\t| cls |\\n\\tstructures keysDo: [:clsName | \\n\\t\\t(clsName endsWith: ' class') ifFalse: [\\n\\t\\t\\t(cls _ Smalltalk at: clsName) isSystemDefined ifFalse: [\\n\\t\\t\\t\\t\\taBlock value: cls]]]! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 1/18/2001 15:54'!\\nuniClassInstVarsRefs: dummy\\n\\t\\\"If some of the objects seen so far are instances UniClasses, check the UniClasses for extra class inst vars, and send them to the steam also. The new objects get added to (dummy references), where they will be noticed by the caller. They will wind up in the structures array and will be written on the disk by class.\\n\\tReturn all classes seen.\\\" \\n| uniClasses normal more aUniClass mySize allClasses |\\n\\n\\\"Note: Any classes used in the structure of classInstVars must be written out also!!\\\"\\nuniClasses _ Set new.\\nallClasses _ IdentitySet new.\\nnormal _ Object class instSize.\\nmore _ true.\\n[more] whileTrue: [\\n\\tmore _ false.\\n\\tdummy references keysDo: [:each | \\\"any faster way to do this?\\\"\\n\\t\\t(aUniClass _ each class) isSystemDefined ifFalse: [\\n\\t\\t\\t(uniClasses includes: aUniClass name) ifFalse: [\\n\\t\\t\\t\\tmySize _ aUniClass class instSize.\\n\\t\\t\\t\\tnormal+1 to: mySize do: [:ii | \\n\\t\\t\\t\\t\\tmore _ true.\\n\\t\\t\\t\\t\\tdummy nextPut: (aUniClass instVarAt: ii)].\\n\\t\\t\\t\\tuniClasses add: aUniClass name]].\\n\\t\\teach class class isMeta ifFalse: [\\\"it is a class\\\" allClasses add: each]]].\\n\\\"References dictionary is modified as the loop proceeds, but we will catch any we missed on the next cycle.\\\"\\n\\n^ allClasses! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'ar 4/10/2005 18:52'!\\nverifyStructure\\n\\t\\\"Compare the incoming inst var name lists with the existing classes. Prepare tables that will help to restructure those who need it (renamed, reshaped, steady). If all superclasses are recorded in the file, only compare inst vars of this class, not of superclasses. They will get their turn. \\\"\\n\\n\\n\\t| newClass newList oldList converting |\\n\\n\\tself flag: #bobconv.\\t\\n\\n\\tconverting _ OrderedCollection new.\\n\\tstructures keysDo: [:nm \\\"an old className (symbol)\\\" |\\n\\t\\t\\\"For missing classes, there needs to be a method in SmartRefStream like \\n\\t\\t\\t#rectangleoc2 that returns the new class.\\\"\\n\\t\\tnewClass _ self mapClass: nm.\\t \\\"does (renamed at: nm put: newClass name)\\\"\\n\\t\\tnewClass isString ifTrue: [^ newClass]. \\\"error, fileIn needed\\\"\\n\\t\\tnewList _ (Array with: newClass classVersion), (newClass allInstVarNames).\\n\\t\\toldList _ structures at: nm.\\n\\t\\tnewList = oldList \\n\\t\\t\\tifTrue: [steady add: newClass] \\\"read it in as written\\\"\\n\\t\\t\\tifFalse: [converting add: newClass name]\\n\\t].\\n\\tfalse & converting isEmpty not ifTrue: [\\\"debug\\\" \\n\\t\\t\\tself inform: 'These classes are being converted from existing methods:\\\\' withCRs,\\n\\t\\t\\t\\tconverting asArray printString].\\n! !\\n\\n!SmartRefStream methodsFor: 'read write' stamp: 'tk 1/7/97'!\\nversionSymbol: instVarList\\n\\t\\\"Create the symbolic code (like a version number) for this class in some older version. First initials of all the inst vars, followed by the class version number. Returns a string, caller makes it into a compound selector. \\\"\\n\\n\\t| str |\\n\\tstr _ instVarList size = 1 ifFalse: [''] ifTrue: ['x'].\\t\\t\\\"at least one letter\\\"\\n\\t2 to: instVarList size do: [:ind |\\n\\t\\tstr _ str, (instVarList at: ind) first asString].\\n\\tstr _ str, instVarList first printString.\\t\\\"the number\\\"\\n\\t^ str\\n\\n\\\" | list | list _ (Array with: Paragraph classVersion), (Paragraph alistInstVarNames).\\n(SmartRefStream on: (DummyStream on: nil)) versionSymbol: list\\n\\\"! !\\n\\n\\n!SmartRefStream methodsFor: '*starSqueak-*starSqueak' stamp: 'RAA 5/16/2001 18:35'!\\nstarLogoAntColonybosfcedppplppppttwssdlgrstta0\\n\\n\\t^ StarSqueakAntColony! !\\n\\n!SmartRefStream methodsFor: '*starSqueak-*starSqueak' stamp: 'RAA 5/16/2001 18:31'!\\nstarLogoMorphbosfcedppplppppttwssdlgrstt0\\n\\n\\t^ StarSqueakMorph! !\\n\\n!SmartRefStream methodsFor: '*starSqueak-*starSqueak' stamp: 'RAA 5/16/2001 18:32'!\\nstarLogoTreesbosfcedppplppppttwssdlgrsttdt0\\n\\n\\t^ StarSqueakTrees! !\\n\\n!SmartRefStream methodsFor: '*starSqueak-*starSqueak' stamp: 'RAA 5/16/2001 18:32'!\\nstarLogoTurtlewwxywwhcpn0\\n\\n\\t^ StarSqueakTurtle! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSmartRefStream class\\n\\tinstanceVariableNames: ''!\\n\\n!SmartRefStream class methodsFor: 'accessing' stamp: 'tk 5/20/97'!\\nscannedObject\\n\\t\\\"The most recently read in object. Watch out for read-in that is interrupted and resumed. May want to make this a dictionary? \\\"\\n\\n\\t^ ScannedObject! !\\n\\n!SmartRefStream class methodsFor: 'accessing' stamp: 'tk 5/20/97'!\\nscannedObject: objOrNil\\n\\t\\\"Used to free up the last object stashed here. \\\"\\n\\n\\tScannedObject _ objOrNil! !\\n\\n!SmartRefStream class methodsFor: 'accessing' stamp: 'tk 3/11/98 09:45'!\\nsubObjects: anObject ofClass: aClass\\n\\t\\\"Return a collection of all instances of aClass that would be written out with anObject. Does not actually write on the disk. Inspect the result and ask for 'references to this object'.\\\"\\n\\n\\t| dummy coll |\\n\\tdummy _ ReferenceStream on: (DummyStream on: nil).\\n\\t\\t\\\"Write to a fake Stream, not a file\\\"\\n\\t\\\"Collect all objects\\\"\\n\\tdummy rootObject: anObject.\\t\\\"inform him about the root\\\"\\n\\tdummy nextPut: anObject.\\n\\tcoll _ OrderedCollection new.\\n\\tdummy references keysDo: [:each |\\n\\t\\teach class == aClass ifTrue: [coll add: each]].\\n\\t^ coll! !\\n\\n\\n!SmartRefStream class methodsFor: 'initialize-release' stamp: 'dvf 8/23/2003 12:18'!\\ncleanUpCategories\\n\\t| list valid removed newList newVers |\\n\\t\\\"Look for all conversion methods that can't be used any longer. Delete them.\\\"\\n\\t\\\" SmartRefStream cleanUpCategories \\\"\\n\\n\\t\\\"Two part selectors that begin with convert and end with a digit.\\\"\\n\\t\\\"convertasossfe0: varDict asossfeu0: smartRefStrm\\\"\\n\\tlist _ Symbol selectorsContaining: 'convert'.\\n\\tlist _ list select: [:symb | (symb beginsWith: 'convert') & (symb allButLast last isDigit)\\n\\t\\t\\t\\tifTrue: [(symb numArgs = 2)]\\n\\t\\t\\t\\tifFalse: [false]].\\n\\tvalid _ 0. removed _ 0.\\n\\tlist do: [:symb |\\n\\t\\t(self systemNavigation allClassesImplementing: symb) do: [:newClass |\\n\\t\\t\\tnewList _ (Array with: newClass classVersion), (newClass allInstVarNames).\\n\\t\\t\\tnewVers _ self new versionSymbol: newList.\\n\\t\\t\\t(symb endsWith: (':',newVers,':')) \\n\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\t\\\"method is useless because can't convert to current shape\\\"\\n\\t\\t\\t\\t\\tnewClass removeSelector: symb.\\t\\\"get rid of it\\\"\\n\\t\\t\\t\\t\\tremoved _ removed + 1]\\n\\t\\t\\t\\tifTrue: [valid _ valid + 1]]].\\n\\tTranscript cr; show: 'Removed: '; print: removed; \\n\\t\\tshow: '\\t\\tKept: '; print: valid; show: ' '.! !\\n\\n\\n!SmartRefStream class methodsFor: 'i/o' stamp: 'RAA 7/9/2000 05:48'!\\nobjectFromStreamedRepresentation: someBytes\\n\\n\\t| file |\\n\\n\\tfile _ RWBinaryOrTextStream with: someBytes.\\n\\tfile reset.\\n\\t^file fileInObjectAndCode! !\\n\\n!SmartRefStream class methodsFor: 'i/o' stamp: 'tk 12/9/97 21:31'!\\nread: aByteStream withClasses: structureArray\\n\\t\\\"Read an object off the stream, but first check structureArray against the current system.\\\"\\n\\n\\t| me |\\n\\tme _ self on: aByteStream.\\n\\tme noHeader.\\n\\tme structures: (structureArray at: 2).\\n\\tme superclasses: (structureArray at: 4).\\n\\t(me verifyStructure = 'conversion method needed') ifTrue: [^ nil].\\n\\t^ super next\\n! !\\n\\n!SmartRefStream class methodsFor: 'i/o' stamp: 'tk 5/20/97'!\\nscanFrom: aByteStream\\n\\t\\\"During a code fileIn, we need to read in an object, and stash it in ScannedObject. \\\"\\n\\n\\t| me |\\n\\tme _ self on: aByteStream.\\n\\tScannedObject _ me next.\\n\\taByteStream ascii.\\n\\taByteStream next == $!! ifFalse: [\\n\\t\\taByteStream close.\\n\\t\\tself error: 'Object did not end correctly']. \\n\\t\\\"caller will close the byteStream\\\"\\n\\t\\\"HandMorph.readMorphFile will retrieve the ScannedObject\\\"! !\\n\\n\\n!SmartRefStream class methodsFor: 'utilities' stamp: 'tk 5/4/1998 17:34'!\\nstatsOfSubObjects: anObject\\n\\t\\\"Open a window with statistics on what objects would be written out with anObject. Does not actually write on the disk. Stats in the form:\\n\\tScriptEditorMorph 51\\n\\t\\tSortedCollection (21->LayoutMorph 15->SimpleButtonMorph 9->Array 4->CompoundTileMorph 2->StringMorph )\\\"\\n\\n\\t| dummy printOut |\\n\\tdummy _ ReferenceStream on: (DummyStream on: nil).\\n\\t\\t\\\"Write to a fake Stream, not a file\\\"\\n\\t\\\"Collect all objects\\\"\\n\\tdummy rootObject: anObject.\\t\\\"inform him about the root\\\"\\n\\tdummy nextPut: anObject.\\n\\t\\\"(dummy references) is the raw data\\\"\\n\\tprintOut _ dummy statisticsOfRefs.\\n\\t(StringHolder new contents: printOut) \\n\\t\\topenLabel: 'ReferenceStream statistics'.! !\\n\\n!SmartRefStream class methodsFor: 'utilities' stamp: 'RAA 7/9/2000 05:35'!\\nstreamedRepresentationOf: anObject\\n\\n\\t| file |\\n\\tfile _ (RWBinaryOrTextStream on: (ByteArray new: 5000)).\\n\\tfile binary.\\n\\t(self on: file) nextPut: anObject.\\n\\tfile close.\\n\\t^file contents! !\\n\\n!SmartRefStream class methodsFor: 'utilities' stamp: 'tk 5/4/1998 17:34'!\\ntallyOfSubObjects: anObject\\n\\t\\\"Open a window with statistics on what objects would be written out with anObject. Does not actually write on the disk. Stats are simply the number of instances of each class:\\n\\t1450->Point 835->Rectangle 549->Array 300->String\\\"\\n\\n\\t| dummy bag |\\n\\tdummy _ ReferenceStream on: (DummyStream on: nil).\\n\\t\\t\\\"Write to a fake Stream, not a file\\\"\\n\\t\\\"Collect all objects\\\"\\n\\tdummy rootObject: anObject.\\t\\\"inform him about the root\\\"\\n\\tdummy nextPut: anObject.\\n\\tbag _ Bag new.\\n\\tdummy references keysDo: [:key | bag add: key class name].\\n\\t\\\"(bag sortedCounts) is the SortedCollection\\\"\\n\\t(StringHolder new contents: bag sortedCounts printString) \\n\\t\\topenLabel: 'ReferenceStream statistics'.! !\\nObject subclass: #Socket\\n\\tinstanceVariableNames: 'semaphore socketHandle readSemaphore writeSemaphore primitiveOnlySupportsOneSemaphore'\\n\\tclassVariableNames: 'Connected DeadServer InvalidSocket OtherEndClosed Registry RegistryThreshold TCPSocketType ThisEndClosed UDPSocketType Unconnected WaitingForConnection'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Kernel'!\\n!Socket commentStamp: 'gk 12/13/2005 00:43' prior: 0!\\nA Socket represents a network connection point. Current sockets are designed to support the TCP/IP and UDP protocols. Sockets are the lowest level of networking object in Squeak and are not normally used directly. SocketStream is a higher level object wrapping a Socket in a stream like protocol.\\n\\nProtocolClient and subclasses are in turn wrappers around a SocketStream to provide support for specific network protocols such as POP, NNTP, HTTP, and FTP.!\\n\\n\\n!Socket methodsFor: 'accessing' stamp: 'ar 4/30/1999 04:25'!\\naddress\\n\\t\\\"Shortcut\\\"\\n\\t^self localAddress! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'MU 11/26/2003 16:53'!\\nlocalAddress\\n\\tself isWaitingForConnection\\n\\t\\tifFalse: [[self waitForConnectionFor: Socket standardTimeout]\\n\\t\\t\\t\\ton: ConnectionTimedOut\\n\\t\\t\\t\\tdo: [:ex | ^ ByteArray new: 4]].\\n\\t^ self primSocketLocalAddress: socketHandle! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'MU 11/26/2003 16:53'!\\nlocalPort\\n\\tself isWaitingForConnection\\n\\t\\tifFalse: [[self waitForConnectionFor: Socket standardTimeout]\\n\\t\\t\\t\\ton: ConnectionTimedOut\\n\\t\\t\\t\\tdo: [:ex | ^ 0]].\\n\\t^ self primSocketLocalPort: socketHandle! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'jm 3/13/98 12:11'!\\npeerName\\n\\t\\\"Return the name of the host I'm connected to, or nil if its name isn't known to the domain name server or the request times out.\\\"\\n\\t\\\"Note: Slow. Calls the domain name server, taking up to 20 seconds to time out. Even when sucessful, delays of up to 13 seconds have been observed during periods of high network load.\\\" \\n\\n\\t^ NetNameResolver\\n\\t\\tnameForAddress: self remoteAddress\\n\\t\\ttimeout: 20\\n! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'ar 4/30/1999 04:25'!\\nport\\n\\t\\\"Shortcut\\\"\\n\\t^self localPort! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'JMM 6/5/2000 10:12'!\\nprimitiveOnlySupportsOneSemaphore\\n\\t^primitiveOnlySupportsOneSemaphore! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'JMM 5/22/2000 22:49'!\\nreadSemaphore\\n\\tprimitiveOnlySupportsOneSemaphore ifTrue: [^semaphore].\\n\\t^readSemaphore! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'jm 9/17/97 14:34'!\\nremoteAddress\\n\\n\\t^ self primSocketRemoteAddress: socketHandle\\n! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'jm 9/17/97 14:34'!\\nremotePort\\n\\n\\t^ self primSocketRemotePort: socketHandle\\n! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'JMM 5/9/2000 15:32'!\\nsemaphore\\n\\t^semaphore! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'ar 7/16/1999 17:22'!\\nsocketHandle\\n\\t^socketHandle! !\\n\\n!Socket methodsFor: 'accessing' stamp: 'JMM 5/22/2000 22:49'!\\nwriteSemaphore\\n\\tprimitiveOnlySupportsOneSemaphore ifTrue: [^semaphore].\\n\\t^writeSemaphore! !\\n\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'bolot 7/16/1999 14:36'!\\naccept\\n\\t\\\"Accept a connection from the receiver socket.\\n\\tReturn a new socket that is connected to the client\\\"\\n\\t^Socket acceptFrom: self.! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'jm 9/11/97 20:29'!\\nclose\\n\\t\\\"Close this connection gracefully. For TCP, this sends a close request, but the stream remains open until the other side also closes it.\\\"\\n\\n\\tself primSocketCloseConnection: socketHandle. \\\"close this end\\\"\\n! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'jm 11/4/97 07:15'!\\ncloseAndDestroy\\n\\t\\\"First, try to close this connection gracefully. If the close attempt fails or times out, abort the connection. In either case, destroy the socket. Do nothing if the socket has already been destroyed (i.e., if its socketHandle is nil).\\\"\\n\\n\\tself closeAndDestroy: 20.\\n\\n! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'gk 12/13/2005 00:05'!\\ncloseAndDestroy: timeoutSeconds\\n\\t\\\"First, try to close this connection gracefully. If the close attempt fails or times out, abort the connection. In either case, destroy the socket. Do nothing if the socket has already been destroyed (i.e., if its socketHandle is nil).\\\"\\n\\n\\tsocketHandle = nil\\n\\t\\tifFalse: [\\n\\t\\t\\tself isConnected ifTrue: [\\n\\t\\t\\t\\tself close. \\\"close this end\\\"\\n\\t\\t\\t\\t(self waitForDisconnectionFor: timeoutSeconds)\\n\\t\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\t\\t\\\"The other end didn't close so we just abort the connection\\\"\\n\\t\\t\\t\\t\\t\\tself primSocketAbortConnection: socketHandle]].\\n\\t\\t\\tself destroy].\\n! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'mir 5/9/2003 18:13'!\\nconnectNonBlockingTo: hostAddress port: port\\n\\t\\\"Initiate a connection to the given port at the given host address. This operation will return immediately; follow it with waitForConnectionUntil: to wait until the connection is established.\\\"\\n\\n\\t| status |\\n\\tself initializeNetwork.\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t(status == Unconnected)\\n\\t\\tifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected before opening a new connection'].\\n\\n\\tself primSocket: socketHandle connectTo: hostAddress port: port.\\n! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'mir 5/15/2003 18:29'!\\nconnectTo: hostAddress port: port\\n\\t\\\"Initiate a connection to the given port at the given host address.\\n\\tWaits until the connection is established or time outs.\\\"\\n\\n\\tself connectTo: hostAddress port: port waitForConnectionFor: Socket standardTimeout! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'mu 8/14/2003 15:15'!\\nconnectTo: hostAddress port: port waitForConnectionFor: timeout \\n\\t\\\"Initiate a connection to the given port at the given host \\n\\taddress. Waits until the connection is established or time outs.\\\"\\n\\tself connectNonBlockingTo: hostAddress port: port.\\n\\tself\\n\\t\\twaitForConnectionFor: timeout\\n\\t\\tifTimedOut: [ConnectionTimedOut signal: 'Cannot connect to '\\n\\t\\t\\t\\t\\t, (NetNameResolver stringFromAddress: hostAddress) , ':' , port asString]! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'mir 5/8/2003 16:03'!\\nconnectToHostNamed: hostName port: portNumber\\n\\t| serverIP |\\n\\tserverIP _ NetNameResolver addressForName: hostName timeout: 20.\\n\\t^self connectTo: serverIP port: portNumber\\n! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'jm 3/10/98 11:56'!\\ndisconnect\\n\\t\\\"Break this connection, no matter what state it is in. Data that has been sent but not received will be lost.\\\"\\n\\n\\tself primSocketAbortConnection: socketHandle.\\n! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'mir 2/22/2002 16:25'!\\nlistenOn: port\\n\\t\\\"Listen for a connection on the given port. This operation will return immediately; follow it with waitForConnectionUntil: to wait until a connection is established.\\\"\\n\\n\\t| status |\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t(status == Unconnected)\\n\\t\\tifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected before listening for a new connection'].\\n\\n\\tself primSocket: socketHandle listenOn: port.\\n! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'mir 2/22/2002 16:25'!\\nlistenOn: portNumber backlogSize: backlog\\n\\t\\\"Listen for a connection on the given port.\\n\\tIf this method succeeds, #accept may be used to establish a new connection\\\"\\n\\t| status |\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t(status == Unconnected)\\n\\t\\tifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected before listening for a new connection'].\\n\\tself primSocket: socketHandle listenOn: portNumber backlogSize: backlog.\\n! !\\n\\n!Socket methodsFor: 'connection open/close' stamp: 'ikp 9/1/2003 20:32'!\\nlistenOn: portNumber backlogSize: backlog interface: ifAddr\\n\\t\\\"Listen for a connection on the given port.\\n\\tIf this method succeeds, #accept may be used to establish a new connection\\\"\\n\\t| status |\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t(status == Unconnected)\\n\\t\\tifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected before listening for a new connection'].\\n\\tself primSocket: socketHandle listenOn: portNumber backlogSize: backlog interface: ifAddr.\\n! !\\n\\n\\n!Socket methodsFor: 'datagrams' stamp: 'JMM 6/7/2000 14:58'!\\nreceiveDataInto: aStringOrByteArray fromHost: hostAddress port: portNumber\\n\\t| datagram |\\n\\t\\\"Receive a UDP packet from the given hostAddress/portNumber, storing the data in the given buffer, and return the number of bytes received. Note the given buffer may be only partially filled by the received data.\\\"\\n\\n\\tprimitiveOnlySupportsOneSemaphore ifTrue:\\n\\t\\t[self setPeer: hostAddress port: portNumber.\\n\\t\\t^self receiveDataInto: aStringOrByteArray].\\n\\t[true] whileTrue: \\n\\t\\t[datagram _ self receiveUDPDataInto: aStringOrByteArray.\\n\\t\\t((datagram at: 2) = hostAddress and: [(datagram at: 3) = portNumber]) \\n\\t\\t\\tifTrue: [^datagram at: 1]\\n\\t\\t\\tifFalse: [^0]]! !\\n\\n!Socket methodsFor: 'datagrams' stamp: 'JMM 6/3/2000 21:54'!\\nreceiveUDPDataInto: aStringOrByteArray\\n\\t\\\"Receive UDP data into the given buffer and return the number of bytes received. Note the given buffer may be only partially filled by the received data. What is returned is an array, the first element is the bytes read, the second the sending bytearray address, the third the senders port, the fourth, true if more of the datagram awaits reading\\\"\\n\\n\\t^ self primSocket: socketHandle\\n\\t\\treceiveUDPDataInto: aStringOrByteArray\\n\\t\\tstartingAt: 1\\n\\t\\tcount: aStringOrByteArray size\\n! !\\n\\n!Socket methodsFor: 'datagrams' stamp: 'JMM 5/25/2000 00:05'!\\nsendData: aStringOrByteArray toHost: hostAddress port: portNumber\\n\\t\\\"Send a UDP packet containing the given data to the specified host/port.\\\"\\n\\n\\tprimitiveOnlySupportsOneSemaphore ifTrue:\\n\\t\\t[self setPeer: hostAddress port: portNumber.\\n\\t\\t^self sendData: aStringOrByteArray].\\n\\t^self sendUDPData: aStringOrByteArray toHost: hostAddress port: portNumber! !\\n\\n!Socket methodsFor: 'datagrams' stamp: 'mir 5/15/2003 18:34'!\\nsendUDPData: aStringOrByteArray toHost: hostAddress port: portNumber\\n\\t\\\"Send a UDP packet containing the given data to the specified host/port.\\\"\\n\\t| bytesToSend bytesSent count |\\n\\n\\tbytesToSend _ aStringOrByteArray size.\\n\\tbytesSent _ 0.\\n\\t[bytesSent < bytesToSend] whileTrue: [\\n\\t\\t(self waitForSendDoneFor: 20)\\n\\t\\t\\tifFalse: [ConnectionTimedOut signal: 'send data timeout; data not sent'].\\n\\t\\tcount _ self primSocket: socketHandle\\n\\t\\t\\tsendUDPData: aStringOrByteArray\\n\\t\\t\\ttoHost: hostAddress\\n\\t\\t\\tport: portNumber\\n\\t\\t\\tstartIndex: bytesSent + 1\\n\\t\\t\\tcount: bytesToSend - bytesSent.\\n\\t\\tbytesSent _ bytesSent + count].\\n\\n\\t^ bytesSent\\n! !\\n\\n!Socket methodsFor: 'datagrams' stamp: 'ar 4/30/1999 04:29'!\\nsetPeer: hostAddress port: port\\n\\t\\\"Set the default send/recv address.\\\"\\n\\n\\tself primSocket: socketHandle connectTo: hostAddress port: port.\\n! !\\n\\n!Socket methodsFor: 'datagrams' stamp: 'ar 4/30/1999 04:29'!\\nsetPort: port\\n\\t\\\"Associate a local port number with a UDP socket. Not applicable to TCP sockets.\\\"\\n\\n\\tself primSocket: socketHandle setPort: port.\\n! !\\n\\n\\n!Socket methodsFor: 'finalization' stamp: 'JMM 5/22/2000 22:52'!\\nfinalize\\n\\tself primSocketDestroyGently: socketHandle.\\n\\tSmalltalk unregisterExternalObject: semaphore.\\n\\tSmalltalk unregisterExternalObject: readSemaphore.\\n\\tSmalltalk unregisterExternalObject: writeSemaphore.\\n! !\\n\\n\\n!Socket methodsFor: 'initialize-destroy' stamp: 'JMM 5/22/2000 22:47'!\\nacceptFrom: aSocket\\n\\t\\\"Initialize a new socket handle from an accept call\\\"\\n\\t| semaIndex readSemaIndex writeSemaIndex |\\n\\n\\tprimitiveOnlySupportsOneSemaphore _ false.\\n\\tsemaphore _ Semaphore new.\\n\\treadSemaphore _ Semaphore new.\\n\\twriteSemaphore _ Semaphore new.\\n\\tsemaIndex _ Smalltalk registerExternalObject: semaphore.\\n\\treadSemaIndex _ Smalltalk registerExternalObject: readSemaphore.\\n\\twriteSemaIndex _ Smalltalk registerExternalObject: writeSemaphore.\\n\\tsocketHandle _ self primAcceptFrom: aSocket socketHandle\\n\\t\\t\\t\\t\\t\\treceiveBufferSize: 8000\\n\\t\\t\\t\\t\\t\\tsendBufSize: 8000\\n\\t\\t\\t\\t\\t\\tsemaIndex: semaIndex\\n\\t\\t\\t\\t\\t\\treadSemaIndex: readSemaIndex\\n\\t\\t\\t\\t\\t\\twriteSemaIndex: writeSemaIndex.\\n\\tsocketHandle = nil ifTrue: [ \\\"socket creation failed\\\"\\n\\t\\tSmalltalk unregisterExternalObject: semaphore.\\n\\t\\tSmalltalk unregisterExternalObject: readSemaphore.\\n\\t\\tSmalltalk unregisterExternalObject: writeSemaphore.\\n\\t\\treadSemaphore _ writeSemaphore _ semaphore _ nil\\n\\t] ifFalse:[self register].\\n! !\\n\\n!Socket methodsFor: 'initialize-destroy' stamp: 'JMM 5/22/2000 22:54'!\\ndestroy\\n\\t\\\"Destroy this socket. Its connection, if any, is aborted and its resources are freed. Do nothing if the socket has already been destroyed (i.e., if its socketHandle is nil).\\\"\\n\\n\\tsocketHandle = nil ifFalse: \\n\\t\\t[self isValid ifTrue: [self primSocketDestroy: socketHandle].\\n\\t\\tSmalltalk unregisterExternalObject: semaphore.\\n\\t\\tSmalltalk unregisterExternalObject: readSemaphore.\\n\\t\\tSmalltalk unregisterExternalObject: writeSemaphore.\\n\\t\\tsocketHandle _ nil.\\n\\t\\treadSemaphore _ writeSemaphore _ semaphore _ nil.\\n\\t\\tself unregister].\\n! !\\n\\n!Socket methodsFor: 'initialize-destroy' stamp: 'JMM 5/22/2000 23:04'!\\ninitialize: socketType\\n\\t\\\"Initialize a new socket handle. If socket creation fails, socketHandle will be set to nil.\\\"\\n\\t| semaIndex readSemaIndex writeSemaIndex |\\n\\n\\tprimitiveOnlySupportsOneSemaphore _ false.\\n\\tsemaphore _ Semaphore new.\\n\\treadSemaphore _ Semaphore new.\\n\\twriteSemaphore _ Semaphore new.\\n\\tsemaIndex _ Smalltalk registerExternalObject: semaphore.\\n\\treadSemaIndex _ Smalltalk registerExternalObject: readSemaphore.\\n\\twriteSemaIndex _ Smalltalk registerExternalObject: writeSemaphore.\\n\\tsocketHandle _\\n\\t\\tself primSocketCreateNetwork: 0\\n\\t\\t\\ttype: socketType\\n\\t\\t\\treceiveBufferSize: 8000\\n\\t\\t\\tsendBufSize: 8000\\n\\t\\t\\tsemaIndex: semaIndex\\n\\t\\t\\treadSemaIndex: readSemaIndex\\n\\t\\t\\twriteSemaIndex: writeSemaIndex.\\n\\n\\tsocketHandle = nil ifTrue: [ \\\"socket creation failed\\\"\\n\\t\\tSmalltalk unregisterExternalObject: semaphore.\\n\\t\\tSmalltalk unregisterExternalObject: readSemaphore.\\n\\t\\tSmalltalk unregisterExternalObject: writeSemaphore.\\n\\t\\treadSemaphore _ writeSemaphore _ semaphore _ nil\\n\\t] ifFalse:[self register].\\n! !\\n\\n!Socket methodsFor: 'initialize-destroy' stamp: 'mir 2/22/2002 15:48'!\\ninitializeNetwork\\n\\tself class initializeNetwork! !\\n\\n\\n!Socket methodsFor: 'other' stamp: 'mir 2/22/2002 16:25'!\\ngetOption: aName \\n\\t\\\"Get options on this socket, see Unix man pages for values for \\n\\tsockets, IP, TCP, UDP. IE SO_KEEPALIVE\\n\\treturns an array, element one is an status number (0 ok, -1 read only option)\\n\\telement two is the resulting of the requested option\\\"\\n\\n\\t(socketHandle == nil or: [self isValid not])\\n\\t\\tifTrue: [InvalidSocketStatusException signal: 'Socket status must valid before getting an option'].\\n\\t^self primSocket: socketHandle getOption: aName\\n\\n\\\"| foo options |\\nSocket initializeNetwork.\\nfoo _ Socket newTCP.\\nfoo connectTo: (NetNameResolver addressFromString: '192.168.1.1') port: 80.\\nfoo waitForConnectionUntil: (Socket standardDeadline).\\n\\noptions _ {\\n'SO_DEBUG'. 'SO_REUSEADDR'. 'SO_REUSEPORT'. 'SO_DONTROUTE'.\\n'SO_BROADCAST'. 'SO_SNDBUF'. 'SO_RCVBUF'. 'SO_KEEPALIVE'.\\n'SO_OOBINLINE'. 'SO_PRIORITY'. 'SO_LINGER'. 'SO_RCVLOWAT'.\\n'SO_SNDLOWAT'. 'IP_TTL'. 'IP_HDRINCL'. 'IP_RCVOPTS'.\\n'IP_RCVDSTADDR'. 'IP_MULTICAST_IF'. 'IP_MULTICAST_TTL'.\\n'IP_MULTICAST_LOOP'. 'UDP_CHECKSUM'. 'TCP_MAXSEG'.\\n'TCP_NODELAY'. 'TCP_ABORT_THRESHOLD'. 'TCP_CONN_NOTIFY_THRESHOLD'. \\n'TCP_CONN_ABORT_THRESHOLD'. 'TCP_NOTIFY_THRESHOLD'.\\n'TCP_URGENT_PTR_TYPE'}.\\n\\n1 to: options size do: [:i | | fum |\\n\\tfum _foo getOption: (options at: i).\\n\\tTranscript show: (options at: i),fum printString;cr].\\n\\nfoo _ Socket newUDP.\\nfoo setPeer: (NetNameResolver addressFromString: '192.168.1.9') port: 7.\\nfoo waitForConnectionUntil: (Socket standardDeadline).\\n\\n1 to: options size do: [:i | | fum |\\n\\tfum _foo getOption: (options at: i).\\n\\tTranscript show: (options at: i),fum printString;cr].\\n\\\"! !\\n\\n!Socket methodsFor: 'other' stamp: 'mir 2/22/2002 16:30'!\\nsetOption: aName value: aValue \\n\\t| value |\\n\\t\\\"setup options on this socket, see Unix man pages for values for \\n\\tsockets, IP, TCP, UDP. IE SO_KEEPALIVE\\n\\treturns an array, element one is the error number\\n\\telement two is the resulting of the negotiated value.\\n\\tSee getOption for list of keys\\\"\\n\\n\\t(socketHandle == nil or: [self isValid not])\\n\\t\\tifTrue: [InvalidSocketStatusException signal: 'Socket status must valid before setting an option'].\\n\\tvalue _ aValue asString.\\n\\taValue == true ifTrue: [value _ '1'].\\n\\taValue == false ifTrue: [value _ '0'].\\n\\t^ self primSocket: socketHandle setOption: aName value: value! !\\n\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimAcceptFrom: aHandle receiveBufferSize: rcvBufSize sendBufSize: sndBufSize semaIndex: semaIndex\\n\\t\\\"Create and return a new socket handle based on accepting the connection from the given listening socket\\\"\\n\\t<primitive: 'primitiveSocketAccept' module: 'SocketPlugin'>\\n\\t^self primitiveFailed! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'JMM 5/22/2000 22:55'!\\nprimAcceptFrom: aHandle receiveBufferSize: rcvBufSize sendBufSize: sndBufSize semaIndex: semaIndex readSemaIndex: aReadSema writeSemaIndex: aWriteSema\\n\\t\\\"Create and return a new socket handle based on accepting the connection from the given listening socket\\\"\\n\\t<primitive: 'primitiveSocketAccept3Semaphores' module: 'SocketPlugin'>\\n\\tprimitiveOnlySupportsOneSemaphore _ true.\\n\\t^self primAcceptFrom: aHandle receiveBufferSize: rcvBufSize sendBufSize: sndBufSize semaIndex: semaIndex ! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID connectTo: hostAddress port: port\\n\\t\\\"Attempt to establish a connection to the given port of the given host. This is an asynchronous call; query the socket status to discover if and when the connection is actually completed.\\\"\\n\\n\\t<primitive: 'primitiveSocketConnectToPort' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'JMM 5/25/2000 21:48'!\\nprimSocket: socketID getOption: aString \\n\\t\\\"Get some option information on this socket. Refer to the UNIX \\n\\tman pages for valid SO, TCP, IP, UDP options. In case of doubt\\n\\trefer to the source code.\\n\\tTCP_NODELAY, SO_KEEPALIVE are valid options for example\\n\\treturns an array containing the error code and the option value\\\"\\n\\n\\t<primitive: 'primitiveSocketGetOptions' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID listenOn: port\\n\\t\\\"Listen for a connection on the given port. This is an asynchronous call; query the socket status to discover if and when the connection is actually completed.\\\"\\n\\n\\t<primitive: 'primitiveSocketListenWithOrWithoutBacklog' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: aHandle listenOn: portNumber backlogSize: backlog\\n\\t\\\"Primitive. Set up the socket to listen on the given port.\\n\\tWill be used in conjunction with #accept only.\\\"\\n\\t<primitive: 'primitiveSocketListenWithOrWithoutBacklog' module: 'SocketPlugin'>\\n\\tself destroy. \\\"Accept not supported so clean up\\\"! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ikp 9/1/2003 20:33'!\\nprimSocket: aHandle listenOn: portNumber backlogSize: backlog interface: ifAddr\\n\\t\\\"Primitive. Set up the socket to listen on the given port.\\n\\tWill be used in conjunction with #accept only.\\\"\\n\\t<primitive: 'primitiveSocketListenOnPortBacklogInterface' module: 'SocketPlugin'>\\n\\tself destroy. \\\"Accept not supported so clean up\\\"! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID receiveDataInto: aStringOrByteArray startingAt: startIndex count: count\\n\\t\\\"Receive data from the given socket into the given array starting at the given index. Return the number of bytes read or zero if no data is available.\\\"\\n\\n\\t<primitive: 'primitiveSocketReceiveDataBufCount' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'JMM 5/24/2000 17:19'!\\nprimSocket: socketID receiveUDPDataInto: aStringOrByteArray startingAt: startIndex count: count\\n\\t\\\"Receive data from the given socket into the given array starting at the given index. \\n\\tReturn an Array containing the amount read, the host address byte array, the host port, and the more flag\\\"\\n\\n\\t<primitive: 'primitiveSocketReceiveUDPDataBufCount' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID sendData: aStringOrByteArray startIndex: startIndex count: count\\n\\t\\\"Send data to the remote host through the given socket starting with the given byte index of the given byte array. The data sent is 'pushed' immediately. Return the number of bytes of data actually sent; any remaining data should be re-submitted for sending after the current send operation has completed.\\\"\\n\\t\\\"Note: In general, it many take several sendData calls to transmit a large data array since the data is sent in send-buffer-sized chunks. The size of the send buffer is determined when the socket is created.\\\"\\n\\n\\t<primitive: 'primitiveSocketSendDataBufCount' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'JMM 5/25/2000 00:08'!\\nprimSocket: socketID sendUDPData: aStringOrByteArray toHost: hostAddress port: portNumber startIndex: startIndex count: count\\n\\t\\\"Send data to the remote host through the given socket starting with the given byte index of the given byte array. The data sent is 'pushed' immediately. Return the number of bytes of data actually sent; any remaining data should be re-submitted for sending after the current send operation has completed.\\\"\\n\\t\\\"Note: In general, it many take several sendData calls to transmit a large data array since the data is sent in send-buffer-sized chunks. The size of the send buffer is determined when the socket is created.\\\"\\n\\n\\t<primitive: 'primitiveSocketSendUDPDataBufCount' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 7/18/2000 11:42'!\\nprimSocket: socketID setOption: aString value: aStringValue\\n\\t\\\"Set some option information on this socket. Refer to the UNIX \\n\\tman pages for valid SO, TCP, IP, UDP options. In case of doubt\\n\\trefer to the source code.\\n\\tTCP_NODELAY, SO_KEEPALIVE are valid options for example\\n\\treturns an array containing the error code and the negotiated value\\\"\\n\\n\\t<primitive: 'primitiveSocketSetOptions' module: 'SocketPlugin'>\\n\\t^nil! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocket: socketID setPort: port\\n\\t\\\"Set the local port associated with a UDP socket.\\n\\tNote: this primitive is overloaded. The primitive will not fail on a TCP socket, but\\n\\tthe effects will not be what was desired. Best solution would be to split Socket into\\n\\ttwo subclasses, TCPSocket and UDPSocket.\\\"\\n\\n\\t<primitive: 'primitiveSocketListenWithOrWithoutBacklog' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketAbortConnection: socketID\\n\\t\\\"Terminate the connection on the given port immediately without going through the normal close sequence. This is an asynchronous call; query the socket status to discover if and when the connection is actually terminated.\\\"\\n\\n\\t<primitive: 'primitiveSocketAbortConnection' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketCloseConnection: socketID\\n\\t\\\"Close the connection on the given port. The remote end is informed that this end has closed and will do no further sends. This is an asynchronous call; query the socket status to discover if and when the connection is actually closed.\\\"\\n\\n\\t<primitive: 'primitiveSocketCloseConnection' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketConnectionStatus: socketID\\n\\t\\\"Return an integer reflecting the connection status of this socket. For a list of possible values, see the comment in the 'initialize' method of this class. If the primitive fails, return a status indicating that the socket handle is no longer valid, perhaps because the Squeak image was saved and restored since the socket was created. (Sockets do not survive snapshots.)\\\"\\n\\n\\t<primitive: 'primitiveSocketConnectionStatus' module: 'SocketPlugin'>\\n\\t^ InvalidSocket\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketCreateNetwork: netType type: socketType receiveBufferSize: rcvBufSize sendBufSize: sendBufSize semaIndex: semaIndex\\n\\t\\\"Return a new socket handle for a socket of the given type and buffer sizes. Return nil if socket creation fails.\\n\\tThe netType parameter is platform dependent and can be used to encode both the protocol type (IP, Xerox XNS, etc.) and/or the physical network interface to use if this host is connected to multiple networks. A zero netType means to use IP protocols and the primary (or only) network interface.\\n\\tThe socketType parameter specifies:\\n\\t\\t0\\treliable stream socket (TCP if the protocol is IP)\\n\\t\\t1\\tunreliable datagram socket (UDP if the protocol is IP)\\n\\tThe buffer size parameters allow performance to be tuned to the application. For example, a larger receive buffer should be used when the application expects to be receiving large amounts of data, especially from a host that is far away. These values are considered requests only; the underlying implementation will ensure that the buffer sizes actually used are within allowable bounds. Note that memory may be limited, so an application that keeps many sockets open should use smaller buffer sizes. Note the macintosh implementation ignores this buffer size. Also see setOption to get/set socket buffer sizes which allows you to set/get the current buffer sizes for reading and writing.\\n \\tIf semaIndex is > 0, it is taken to be the index of a Semaphore in the external objects array to be associated with this socket. This semaphore will be signalled when the socket status changes, such as when data arrives or a send completes. All processes waiting on the semaphore will be awoken for each such event; each process must then query the socket state to figure out if the conditions they are waiting for have been met. For example, a process waiting to send some data can see if the last send has completed.\\\"\\n\\n\\t<primitive: 'primitiveSocketCreate' module: 'SocketPlugin'>\\n\\t^ nil \\\"socket creation failed\\\"\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'JMM 5/22/2000 22:48'!\\nprimSocketCreateNetwork: netType type: socketType receiveBufferSize: rcvBufSize sendBufSize: sendBufSize semaIndex: semaIndex readSemaIndex: aReadSema writeSemaIndex: aWriteSema\\n\\t\\\"See comment in primSocketCreateNetwork: with one semaIndex. However you should know that some implementations\\n\\tignore the buffer size and this interface supports three semaphores, one for open/close/listen and the other two for\\n\\treading and writing\\\"\\n\\n\\t<primitive: 'primitiveSocketCreate3Semaphores' module: 'SocketPlugin'>\\n\\tprimitiveOnlySupportsOneSemaphore _ true.\\n\\t^ self primSocketCreateNetwork: netType\\n\\t\\t\\ttype: socketType\\n\\t\\t\\treceiveBufferSize: rcvBufSize\\n\\t\\t\\tsendBufSize: sendBufSize\\n\\t\\t\\tsemaIndex: semaIndex! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketDestroy: socketID\\n\\t\\\"Release the resources associated with this socket. If a connection is open, it is aborted.\\\"\\n\\n\\t<primitive: 'primitiveSocketDestroy' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketDestroyGently: socketID\\n\\t\\\"Release the resources associated with this socket. If a connection is open, it is aborted.\\n\\tDo not fail if the receiver is already closed.\\\"\\n\\n\\t<primitive: 'primitiveSocketDestroy' module: 'SocketPlugin'>\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketError: socketID\\n\\t\\\"Return an integer encoding the most recent error on this socket. Zero means no error.\\\"\\n\\n\\t<primitive: 'primitiveSocketError' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketLocalAddress: socketID\\n\\t\\\"Return the local host address for this socket.\\\"\\n\\n\\t<primitive: 'primitiveSocketLocalAddress' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketLocalPort: socketID\\n\\t\\\"Return the local port for this socket, or zero if no port has yet been assigned.\\\"\\n\\n\\t<primitive: 'primitiveSocketLocalPort' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketReceiveDataAvailable: socketID\\n\\t\\\"Return true if data may be available for reading from the current socket.\\\"\\n\\n\\t<primitive: 'primitiveSocketReceiveDataAvailable' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketRemoteAddress: socketID\\n\\t\\\"Return the remote host address for this socket, or zero if no connection has been made.\\\"\\n\\n\\t<primitive: 'primitiveSocketRemoteAddress' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketRemotePort: socketID\\n\\t\\\"Return the remote port for this socket, or zero if no connection has been made.\\\"\\n\\n\\t<primitive: 'primitiveSocketRemotePort' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!Socket methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSocketSendDone: socketID\\n\\t\\\"Return true if there is no send in progress on the current socket.\\\"\\n\\n\\t<primitive: 'primitiveSocketSendDone' module: 'SocketPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n\\n!Socket methodsFor: 'printing' stamp: 'jm 11/23/1998 11:57'!\\nprintOn: aStream\\n\\n\\tsuper printOn: aStream.\\n\\taStream nextPutAll: '[', self statusString, ']'.\\n! !\\n\\n\\n!Socket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:52'!\\ndataAvailable\\n\\t\\\"Return true if this socket has unread received data.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ self primSocketReceiveDataAvailable: socketHandle\\n! !\\n\\n!Socket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:52'!\\nisConnected\\n\\t\\\"Return true if this socket is connected.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == Connected\\n! !\\n\\n!Socket methodsFor: 'queries' stamp: 'JMM 5/5/2000 12:15'!\\nisOtherEndClosed\\n\\t\\\"Return true if this socket had the other end closed.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == OtherEndClosed\\n! !\\n\\n!Socket methodsFor: 'queries' stamp: 'JMM 5/5/2000 12:17'!\\nisThisEndClosed\\n\\t\\\"Return true if this socket had the this end closed.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == ThisEndClosed\\n! !\\n\\n!Socket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:54'!\\nisUnconnected\\n\\t\\\"Return true if this socket's state is Unconnected.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == Unconnected\\n! !\\n\\n!Socket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:54'!\\nisUnconnectedOrInvalid\\n\\t\\\"Return true if this socket is completely disconnected or is invalid.\\\"\\n\\n\\t| status |\\n\\tsocketHandle == nil ifTrue: [^ true].\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t^ (status = Unconnected) | (status = InvalidSocket)\\n! !\\n\\n!Socket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:51'!\\nisValid\\n\\t\\\"Return true if this socket contains a valid, non-nil socket handle.\\\"\\n\\n\\t| status |\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t^ status ~= InvalidSocket\\n! !\\n\\n!Socket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:54'!\\nisWaitingForConnection\\n\\t\\\"Return true if this socket is waiting for a connection.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ (self primSocketConnectionStatus: socketHandle) == WaitingForConnection\\n! !\\n\\n!Socket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:54'!\\nsendDone\\n\\t\\\"Return true if the most recent send operation on this socket has completed.\\\"\\n\\n\\tsocketHandle == nil ifTrue: [^ false].\\n\\t^ self primSocketSendDone: socketHandle\\n! !\\n\\n!Socket methodsFor: 'queries' stamp: 'JMM 5/8/2000 23:24'!\\nsocketError\\n\\t^self primSocketError: socketHandle! !\\n\\n!Socket methodsFor: 'queries' stamp: 'jm 2/25/1999 13:56'!\\nstatusString\\n\\t\\\"Return a string describing the status of this socket.\\\"\\n\\n\\t| status |\\n\\tsocketHandle == nil ifTrue: [^ 'destroyed'].\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\tstatus = InvalidSocket ifTrue: [^ 'invalidSocketHandle'].\\n\\tstatus = Unconnected ifTrue: [^ 'unconnected'].\\n\\tstatus = WaitingForConnection ifTrue: [^ 'waitingForConnection'].\\n\\tstatus = Connected ifTrue: [^ 'connected'].\\n\\tstatus = OtherEndClosed ifTrue: [^ 'otherEndClosedButNotThisEnd'].\\n\\tstatus = ThisEndClosed ifTrue: [^ 'thisEndClosedButNotOtherEnd'].\\n\\t^ 'unknown socket status'\\n! !\\n\\n\\n!Socket methodsFor: 'receiving' stamp: 'gk 12/14/2005 10:02'!\\ndiscardReceivedData\\n\\t\\\"Discard any data received up until now, and return the number of bytes discarded.\\\"\\n\\n\\t| buf totalBytesDiscarded |\\n\\tbuf _ String new: 10000.\\n\\ttotalBytesDiscarded _ 0.\\n\\t[self isConnected] whileTrue: [\\n\\t\\ttotalBytesDiscarded _\\n\\t\\t\\ttotalBytesDiscarded + (self receiveDataInto: buf)].\\n\\t^ totalBytesDiscarded\\n! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mir 5/15/2003 13:52'!\\nreceiveAvailableData\\n\\t\\\"Receive all available data (if any). Do not wait.\\\"\\n \\n\\t| buffer bytesRead |\\n\\tbuffer _ String new: 2000.\\n\\tbytesRead _ self receiveAvailableDataInto: buffer.\\n\\t^buffer copyFrom: 1 to: bytesRead! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'yo 10/10/2005 18:47'!\\nreceiveAvailableDataIntoBuffer: buffer\\n\\t\\\"Receive all available data (if any). Do not wait.\\\"\\n \\n\\t| bytesRead |\\n\\tbytesRead _ self receiveAvailableDataInto: buffer.\\n\\t^buffer copyFrom: 1 to: bytesRead! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mir 5/15/2003 13:52'!\\nreceiveAvailableDataInto: buffer\\n\\t\\\"Receive all available data into the given buffer and return the number of bytes received.\\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tDo not wait for data.\\\"\\n\\n\\t^self receiveAvailableDataInto: buffer startingAt: 1! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mu 8/9/2003 18:04'!\\nreceiveAvailableDataInto: buffer startingAt: startIndex\\n\\t\\\"Receive all available data into the given buffer and return the number of bytes received.\\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tDo not wait for data.\\\"\\n\\n\\t| bufferPos bytesRead |\\n\\tbufferPos := startIndex.\\n\\t[self dataAvailable\\n\\t\\tand: [bufferPos-1 < buffer size]] \\n\\t\\twhileTrue: [\\n\\t\\t\\tbytesRead := self receiveSomeDataInto: buffer startingAt: bufferPos.\\n\\t\\t\\tbufferPos := bufferPos + bytesRead].\\n\\t^bufferPos - startIndex! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mir 5/15/2003 16:05'!\\nreceiveData\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWaits for data once.\\n\\tEither returns data or signals a time out or connection close.\\\"\\n\\n\\t| buffer bytesRead |\\n\\tbuffer _ String new: 2000.\\n\\tbytesRead _ self receiveDataInto: buffer.\\n\\t^buffer copyFrom: 1 to: bytesRead! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mir 5/15/2003 16:05'!\\nreceiveDataInto: aStringOrByteArray\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWaits for data once.\\n\\tEither returns data or signals a time out or connection close.\\\"\\n\\n\\t^self receiveDataInto: aStringOrByteArray startingAt: 1! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'svp 9/23/2003 00:12'!\\nreceiveDataInto: aStringOrByteArray startingAt: aNumber\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWaits for data once. The answer may be zero (indicating that no data was \\n\\tavailable before the socket closed).\\\"\\n\\n\\t| bytesRead closed |\\n\\tbytesRead := 0.\\n\\tclosed := false.\\n\\t[closed not and: [bytesRead == 0]]\\n\\t\\twhileTrue: [\\n\\t\\t\\tself waitForDataIfClosed: [closed := true].\\n\\t\\t\\tbytesRead := self primSocket: socketHandle\\n\\t\\t\\t\\treceiveDataInto: aStringOrByteArray\\n\\t\\t\\t\\tstartingAt: aNumber\\n\\t\\t\\t\\tcount: aStringOrByteArray size-aNumber+1].\\n\\t^bytesRead\\n! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'gk 2/9/2005 12:33'!\\nreceiveDataSignallingClosedInto: aStringOrByteArray startingAt: aNumber\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWaits for data until something is read or the socket is closed, upon which\\n\\twe signal.\\\"\\n\\n\\t| bytesRead |\\n\\tbytesRead := 0.\\n\\t[bytesRead == 0]\\n\\t\\twhileTrue: [\\n\\t\\t\\tself waitForData.\\n\\t\\t\\tbytesRead := self primSocket: socketHandle\\n\\t\\t\\t\\treceiveDataInto: aStringOrByteArray\\n\\t\\t\\t\\tstartingAt: aNumber\\n\\t\\t\\t\\tcount: aStringOrByteArray size-aNumber+1].\\n\\t^bytesRead\\n! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'gk 2/9/2005 12:24'!\\nreceiveDataSignallingTimeout: timeout into: aStringOrByteArray startingAt: aNumber\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWait for data once for the specified nr of seconds. This method will\\n\\tthrow exceptions on timeout or the socket closing.\\\"\\n\\n\\tself waitForDataFor: timeout.\\n\\t^self primSocket: socketHandle\\n\\t\\treceiveDataInto: aStringOrByteArray\\n\\t\\tstartingAt: aNumber\\n\\t\\tcount: aStringOrByteArray size-aNumber+1\\n! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'svp 9/23/2003 00:03'!\\nreceiveDataTimeout: timeout\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWaits for data once.\\\"\\n\\n\\t| buffer bytesRead |\\n\\tbuffer _ String new: 2000.\\n\\tbytesRead _ self receiveDataTimeout: timeout into: buffer.\\n\\t^buffer copyFrom: 1 to: bytesRead! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'svp 9/23/2003 00:01'!\\nreceiveDataTimeout: timeout into: aStringOrByteArray \\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWaits for data once.\\\"\\n\\n\\t^self receiveDataTimeout: timeout into: aStringOrByteArray startingAt: 1! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'svp 9/22/2003 23:58'!\\nreceiveDataTimeout: timeout into: aStringOrByteArray startingAt: aNumber\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWait for data once for the specified nr of seconds. The answer may be \\n\\tzero (indicating that there was no data available within the given timeout).\\\"\\n\\n\\tself waitForDataFor: timeout ifClosed: [] ifTimedOut: [].\\n\\t^self primSocket: socketHandle\\n\\t\\treceiveDataInto: aStringOrByteArray\\n\\t\\tstartingAt: aNumber\\n\\t\\tcount: aStringOrByteArray size-aNumber+1\\n! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mir 5/15/2003 16:18'!\\nreceiveDataWithTimeout\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWaits for data once.\\n\\tEither returns data or signals a time out or connection close.\\\"\\n\\n\\t| buffer bytesRead |\\n\\tbuffer _ String new: 2000.\\n\\tbytesRead _ self receiveDataWithTimeoutInto: buffer.\\n\\t^buffer copyFrom: 1 to: bytesRead! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mir 5/15/2003 16:18'!\\nreceiveDataWithTimeoutInto: aStringOrByteArray\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWaits for data once.\\n\\tEither returns data or signals a time out or connection close.\\\"\\n\\n\\t^self receiveDataWithTimeoutInto: aStringOrByteArray startingAt: 1! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'svp 9/23/2003 00:01'!\\nreceiveDataWithTimeoutInto: aStringOrByteArray startingAt: aNumber\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. \\n\\tNote the given buffer may be only partially filled by the received data.\\n\\tWaits for data once.\\\"\\n\\n\\t^self receiveDataTimeout: Socket standardTimeout into: aStringOrByteArray startingAt: aNumber \\n! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mir 5/15/2003 13:46'!\\nreceiveSomeData\\n\\t\\\"Receive currently available data (if any). Do not wait.\\\"\\n \\n\\t| buffer bytesRead |\\n\\tbuffer _ String new: 2000.\\n\\tbytesRead _ self receiveSomeDataInto: buffer.\\n\\t^buffer copyFrom: 1 to: bytesRead! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mir 5/15/2003 13:46'!\\nreceiveSomeDataInto: aStringOrByteArray\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. Note the given buffer may be only partially filled by the received data.\\\"\\n\\n\\t^self receiveSomeDataInto: aStringOrByteArray startingAt: 1! !\\n\\n!Socket methodsFor: 'receiving' stamp: 'mir 5/15/2003 13:46'!\\nreceiveSomeDataInto: aStringOrByteArray startingAt: aNumber\\n\\t\\\"Receive data into the given buffer and return the number of bytes received. Note the given buffer may be only partially filled by the received data.\\\"\\n\\n\\t^ self primSocket: socketHandle\\n\\t\\treceiveDataInto: aStringOrByteArray\\n\\t\\tstartingAt: aNumber\\n\\t\\tcount: aStringOrByteArray size-aNumber+1\\n! !\\n\\n\\n!Socket methodsFor: 'registry' stamp: 'ar 3/21/98 17:40'!\\nregister\\n\\t^self class register: self! !\\n\\n!Socket methodsFor: 'registry' stamp: 'ar 3/21/98 17:41'!\\nunregister\\n\\t^self class unregister: self! !\\n\\n\\n!Socket methodsFor: 'sending' stamp: 'mir 5/15/2003 18:33'!\\nsendData: aStringOrByteArray\\n\\t\\\"Send all of the data in the given array, even if it requires multiple calls to send it all. Return the number of bytes sent.\\\"\\n\\n\\t\\\"An experimental version use on slow lines: Longer timeout and smaller writes to try to avoid spurious timeouts.\\\"\\n\\n\\t| bytesSent bytesToSend count |\\n\\tbytesToSend _ aStringOrByteArray size.\\n\\tbytesSent _ 0.\\n\\t[bytesSent < bytesToSend] whileTrue: [\\n\\t\\t(self waitForSendDoneFor: 60)\\n\\t\\t\\tifFalse: [ConnectionTimedOut signal: 'send data timeout; data not sent'].\\n\\t\\tcount _ self primSocket: socketHandle\\n\\t\\t\\tsendData: aStringOrByteArray\\n\\t\\t\\tstartIndex: bytesSent + 1\\n\\t\\t\\tcount: (bytesToSend - bytesSent min: 5000).\\n\\t\\tbytesSent _ bytesSent + count].\\n\\n\\t^ bytesSent\\n! !\\n\\n!Socket methodsFor: 'sending' stamp: 'ar 7/20/1999 17:23'!\\nsendData: buffer count: n\\n\\t\\\"Send the amount of data from the given buffer\\\"\\n\\t| sent |\\n\\tsent _ 0.\\n\\t[sent < n] whileTrue:[\\n\\t\\tsent _ sent + (self sendSomeData: buffer startIndex: sent+1 count: (n-sent))].! !\\n\\n!Socket methodsFor: 'sending' stamp: 'ls 1/5/1999 15:05'!\\nsendSomeData: aStringOrByteArray\\n\\t\\\"Send as much of the given data as possible and answer the number of bytes actually sent.\\\"\\n\\t\\\"Note: This operation may have to be repeated multiple times to send a large amount of data.\\\"\\n\\n\\t^ self\\n\\t\\tsendSomeData: aStringOrByteArray\\n\\t\\tstartIndex: 1\\n\\t\\tcount: aStringOrByteArray size! !\\n\\n!Socket methodsFor: 'sending' stamp: 'ls 3/3/1999 18:59'!\\nsendSomeData: aStringOrByteArray startIndex: startIndex\\n\\t\\\"Send as much of the given data as possible starting at the given index. Answer the number of bytes actually sent.\\\"\\n\\t\\\"Note: This operation may have to be repeated multiple times to send a large amount of data.\\\"\\n\\n\\t^ self\\n\\t\\tsendSomeData: aStringOrByteArray\\n\\t\\tstartIndex: startIndex\\n\\t\\tcount: (aStringOrByteArray size - startIndex + 1)! !\\n\\n!Socket methodsFor: 'sending' stamp: 'mir 5/15/2003 18:34'!\\nsendSomeData: aStringOrByteArray startIndex: startIndex count: count\\n\\t\\\"Send up to count bytes of the given data starting at the given index. Answer the number of bytes actually sent.\\\"\\n\\t\\\"Note: This operation may have to be repeated multiple times to send a large amount of data.\\\"\\n\\n\\t| bytesSent |\\n\\t(self waitForSendDoneFor: 20)\\n\\t\\tifTrue: [\\n\\t\\t\\tbytesSent _ self primSocket: socketHandle\\n\\t\\t\\t\\tsendData: aStringOrByteArray\\n\\t\\t\\t\\tstartIndex: startIndex\\n\\t\\t\\t\\tcount: count]\\n\\t\\tifFalse: [ConnectionTimedOut signal: 'send data timeout; data not sent'].\\n\\t^ bytesSent\\n! !\\n\\n!Socket methodsFor: 'sending' stamp: 'mir 2/19/2002 18:33'!\\nsendStreamContents: stream\\n\\t\\\"Send the data in the stream. Close the stream.\\n\\tUsefull for directly sending contents of a file without reading into memory first.\\\"\\n\\n\\tself sendStreamContents: stream checkBlock: [true]! !\\n\\n!Socket methodsFor: 'sending' stamp: 'mir 2/19/2002 18:31'!\\nsendStreamContents: stream checkBlock: checkBlock\\n\\t\\\"Send the data in the stream. Close the stream after you are done. After each block of data evaluate checkBlock and abort if it returns false.\\n\\tUsefull for directly sending contents of a file without reading into memory first.\\\"\\n\\n\\t| chunkSize buffer |\\n\\tchunkSize _ 5000.\\n\\tbuffer _ ByteArray new: chunkSize.\\n\\tstream binary.\\n\\t[[stream atEnd and: [checkBlock value]]\\n\\t\\twhileFalse: [\\n\\t\\t\\tbuffer _ stream next: chunkSize into: buffer.\\n\\t\\t\\tself sendData: buffer]]\\n\\t\\tensure: [stream close]! !\\n\\n\\n!Socket methodsFor: 'waiting' stamp: 'mu 8/9/2003 15:17'!\\nwaitForAcceptFor: timeout\\n\\t\\\"Wait and accept an incoming connection. Return nil if it falis\\\"\\n\\t[self waitForConnectionFor: timeout] on: ConnectionTimedOut do: [:ex | ^nil].\\n\\t^self isConnected\\n\\t\\tifTrue:[self accept]\\n\\t\\t! !\\n\\n!Socket methodsFor: 'waiting' stamp: 'svp 7/27/2003 00:23'!\\nwaitForAcceptFor: timeout ifTimedOut: timeoutBlock\\n\\t\\\"Wait and accept an incoming connection\\\"\\n\\tself waitForConnectionFor: timeout ifTimedOut: [^timeoutBlock value].\\n\\t^self accept! !\\n\\n!Socket methodsFor: 'waiting' stamp: 'mu 8/19/2003 02:57'!\\nwaitForConnectionFor: timeout\\n\\t\\\"Wait up until the given deadline for a connection to be established. Return true if it is established by the deadline, false if not.\\\"\\n\\n\\t^self \\n\\t\\twaitForConnectionFor: timeout \\n\\t\\tifTimedOut: [ConnectionTimedOut signal: 'Failed to connect in ', timeout asString, ' seconds']\\n! !\\n\\n!Socket methodsFor: 'waiting' stamp: 'gk 12/15/2005 01:09'!\\nwaitForConnectionFor: timeout ifTimedOut: timeoutBlock\\n\\t\\\"Wait up until the given deadline for a connection to be established. Return true if it is established by the deadline, false if not.\\\"\\n\\n\\t| status deadline |\\n\\tdeadline := Socket deadlineSecs: timeout.\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\t[(status = WaitingForConnection) and: [Time millisecondClockValue < deadline]]\\n\\t\\twhileTrue: [\\n\\t\\t\\tsemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue).\\n\\t\\t\\tstatus _ self primSocketConnectionStatus: socketHandle].\\n\\n\\tstatus = Connected ifFalse: [^timeoutBlock value]\\n! !\\n\\n!Socket methodsFor: 'waiting' stamp: 'svp 9/23/2003 00:09'!\\nwaitForData\\n\\t\\\"Wait for data to arrive. This method will block until\\n\\tdata is available or the socket is closed. If the socket is closed\\n\\ta ConnectionClosed exception will be signaled.\\\"\\n\\n\\t^self waitForDataIfClosed:\\n\\t\\t[ConnectionClosed signal: 'Connection close while waiting for data.']! !\\n\\n!Socket methodsFor: 'waiting' stamp: 'svp 7/27/2003 00:18'!\\nwaitForDataFor: timeout\\n\\t\\\"Wait for the given nr of seconds for data to arrive.\\n\\tSignal a time out or connection close exception if either happens before data becomes available.\\\"\\n\\n\\t^self\\n\\t\\twaitForDataFor: timeout\\n\\t\\tifClosed: [ConnectionClosed signal: 'Connection closed while waiting for data.']\\n\\t\\tifTimedOut: [ConnectionTimedOut signal: 'Data receive timed out.']\\n! !\\n\\n!Socket methodsFor: 'waiting' stamp: 'svp 7/27/2003 00:16'!\\nwaitForDataFor: timeout ifClosed: closedBlock ifTimedOut: timedOutBlock\\n\\t\\\"Wait for the given nr of seconds for data to arrive.\\\"\\n\\n\\t| deadline |\\n\\tdeadline := Socket deadlineSecs: timeout.\\n\\n\\t[Time millisecondClockValue < deadline]\\n\\t\\twhileTrue: [\\n\\t\\t\\t(self primSocketReceiveDataAvailable: socketHandle)\\n\\t\\t\\t\\tifTrue: [^self].\\n\\t\\t\\tself isConnected\\n\\t\\t\\t\\tifFalse: [^closedBlock value].\\n\\t\\t\\tself readSemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue)].\\n\\n\\t(self primSocketReceiveDataAvailable: socketHandle)\\n\\t\\tifFalse: [\\n\\t\\t\\tself isConnected\\n\\t\\t\\t\\tifTrue: [^timedOutBlock value]\\n\\t\\t\\t\\tifFalse: [^closedBlock value]]! !\\n\\n!Socket methodsFor: 'waiting' stamp: 'svp 9/23/2003 00:08'!\\nwaitForDataIfClosed: closedBlock\\n\\t\\\"Wait indefinitely for data to arrive. This method will block until\\n\\tdata is available or the socket is closed.\\\"\\n\\n\\t[true]\\n\\t\\twhileTrue: [\\n\\t\\t\\t(self primSocketReceiveDataAvailable: socketHandle)\\n\\t\\t\\t\\tifTrue: [^self].\\n\\t\\t\\tself isConnected\\n\\t\\t\\t\\tifFalse: [^closedBlock value].\\n\\t\\t\\tself readSemaphore wait].\\n! !\\n\\n!Socket methodsFor: 'waiting' stamp: 'gk 12/14/2005 09:59'!\\nwaitForDisconnectionFor: timeout\\n\\t\\\"Wait for the given nr of seconds for the connection to be broken.\\n\\tReturn true if it is broken by the deadline, false if not.\\n\\tThe client should know the connection is really going to be closed\\n\\t(e.g., because he has called 'close' to send a close request to the other end)\\n\\tbefore calling this method.\\\"\\n\\n\\t| status deadline |\\n\\tstatus _ self primSocketConnectionStatus: socketHandle.\\n\\tdeadline := Socket deadlineSecs: timeout.\\n\\t[((status == Connected) or: [(status == ThisEndClosed)]) and:\\n\\t [Time millisecondClockValue < deadline]] whileTrue: [\\n\\t\\tself discardReceivedData.\\n\\t\\tself readSemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue).\\n\\t\\tstatus _ self primSocketConnectionStatus: socketHandle].\\n\\n\\t^ status ~= Connected\\n! !\\n\\n!Socket methodsFor: 'waiting' stamp: 'mir 5/15/2003 18:33'!\\nwaitForSendDoneFor: timeout\\n\\t\\\"Wait up until the given deadline for the current send operation to complete. Return true if it completes by the deadline, false if not.\\\"\\n\\n\\t| sendDone deadline |\\n\\tdeadline := Socket deadlineSecs: timeout.\\n\\t[self isConnected & (sendDone _ self primSocketSendDone: socketHandle) not\\n\\t\\t\\t\\\"Connection end and final data can happen fast, so test in this order\\\"\\n\\t\\tand: [Time millisecondClockValue < deadline]] whileTrue: [\\n\\t\\t\\tself writeSemaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue)].\\n\\n\\t^ sendDone! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSocket class\\n\\tinstanceVariableNames: ''!\\n\\n!Socket class methodsFor: 'class initialization' stamp: 'ar 12/12/2001 19:12'!\\ninitialize\\n\\t\\\"Socket initialize\\\"\\n\\n\\t\\\"Socket Types\\\"\\n\\tTCPSocketType _ 0.\\n\\tUDPSocketType _ 1.\\n\\n\\t\\\"Socket Status Values\\\"\\n\\tInvalidSocket _ -1.\\n\\tUnconnected _ 0.\\n\\tWaitingForConnection _ 1.\\n\\tConnected _ 2.\\n\\tOtherEndClosed _ 3.\\n\\tThisEndClosed _ 4.\\n\\n\\tRegistryThreshold _ 100. \\\"# of sockets\\\"! !\\n\\n\\n!Socket class methodsFor: 'instance creation' stamp: 'ls 9/24/1999 09:45'!\\nacceptFrom: aSocket\\n\\t^[ super new acceptFrom: aSocket ]\\n\\t\\trepeatWithGCIf: [ :sock | sock isValid not ]! !\\n\\n!Socket class methodsFor: 'instance creation' stamp: 'ar 4/30/1999 04:15'!\\ncreateIfFail: failBlock\\n\\t\\\"Attempt to create a new socket. If successful, return the new socket. Otherwise, return the result of evaluating the given block. Socket creation can fail if the network isn't available or if there are not sufficient resources available to create another socket.\\\"\\n\\t\\\"Note: The default creates a TCP socket\\\"\\n\\t^self tcpCreateIfFail: failBlock! !\\n\\n!Socket class methodsFor: 'instance creation' stamp: 'ar 4/30/1999 04:13'!\\nnew\\n\\t\\\"Return a new, unconnected Socket. Note that since socket creation may fail, it is safer to use the method createIfFail: to handle such failures gracefully; this method is primarily for backward compatibility and may be disallowed in a future release.\\\"\\n\\t\\\"Note: The default creates a TCP socket - this is also backward compatibility.\\\"\\n\\t^self newTCP! !\\n\\n!Socket class methodsFor: 'instance creation' stamp: 'mir 2/22/2002 15:48'!\\nnewTCP\\n\\t\\\"Create a socket and initialise it for TCP\\\"\\n\\tself initializeNetwork.\\n\\t^[ super new initialize: TCPSocketType ]\\n\\t\\trepeatWithGCIf: [ :socket | socket isValid not ]! !\\n\\n!Socket class methodsFor: 'instance creation' stamp: 'mir 2/22/2002 15:49'!\\nnewUDP\\n\\t\\\"Create a socket and initialise it for UDP\\\"\\n\\tself initializeNetwork.\\n\\t^[ super new initialize: UDPSocketType ]\\n\\t\\trepeatWithGCIf: [ :socket | socket isValid not ]! !\\n\\n!Socket class methodsFor: 'instance creation' stamp: 'mir 2/22/2002 15:49'!\\ntcpCreateIfFail: failBlock\\n\\t\\\"Attempt to create a new socket. If successful, return the new socket. Otherwise, return the result of evaluating the given block. Socket creation can fail if the network isn't available or if there are not sufficient resources available to create another socket.\\\"\\n\\n\\t| sock |\\n\\tself initializeNetwork.\\n\\tsock _ super new initialize: TCPSocketType.\\n\\tsock isValid ifFalse: [^ failBlock value].\\n\\t^ sock\\n! !\\n\\n!Socket class methodsFor: 'instance creation' stamp: 'mir 2/22/2002 15:49'!\\nudpCreateIfFail: failBlock\\n\\t\\\"Attempt to create a new socket. If successful, return the new socket. Otherwise, return the result of evaluating the given block. Socket creation can fail if the network isn't available or if there are not sufficient resources available to create another socket.\\\"\\n\\n\\t| sock |\\n\\tself initializeNetwork.\\n\\tsock _ super new initialize: UDPSocketType.\\n\\tsock isValid ifFalse: [^ failBlock value].\\n\\t^ sock\\n! !\\n\\n\\n!Socket class methodsFor: 'network initialization' stamp: 'mir 2/22/2002 15:01'!\\ninitializeNetwork\\n\\t\\\"Initialize the network drivers and the NetNameResolver. Do nothing if the network is already initialized.\\\"\\n\\t\\\"Note: The network must be re-initialized every time Squeak starts up, so applications that persist across snapshots should be prepared to re-initialize the network as needed. Such applications should call 'Socket initializeNetwork' before every network transaction. \\\"\\n\\n\\tNetNameResolver initializeNetwork! !\\n\\n!Socket class methodsFor: 'network initialization' stamp: 'mir 2/22/2002 14:59'!\\nprimInitializeNetwork: resolverSemaIndex\\n\\t\\\"Initialize the network drivers on platforms that need it, such as the Macintosh, and return nil if network initialization failed or the reciever if it succeeds. Since mobile computers may not always be connected to a network, this method should NOT be called automatically at startup time; rather, it should be called when first starting a networking application. It is a noop if the network driver has already been initialized. If non-zero, resolverSemaIndex is the index of a VM semaphore to be associated with the network name resolver. This semaphore will be signalled when the resolver status changes, such as when a name lookup query is completed.\\\"\\n\\t\\\"Note: some platforms (e.g., Mac) only allow only one name lookup query at a time, so a manager process should be used to serialize resolver lookup requests.\\\"\\n\\n\\t<primitive: 'primitiveInitializeNetwork' module: 'SocketPlugin'>\\n\\t^ nil \\\"return nil if primitive fails\\\"\\n! !\\n\\n\\n!Socket class methodsFor: 'registry' stamp: 'ar 10/7/1998 14:40'!\\nregister: anObject\\n\\tWeakArray isFinalizationSupported ifFalse:[^anObject].\\n\\tself registry add: anObject! !\\n\\n!Socket class methodsFor: 'registry' stamp: 'ar 10/7/1998 14:40'!\\nregistry\\n\\tWeakArray isFinalizationSupported ifFalse:[^nil].\\n\\t^Registry isNil\\n\\t\\tifTrue:[Registry := WeakRegistry new]\\n\\t\\tifFalse:[Registry].! !\\n\\n!Socket class methodsFor: 'registry' stamp: 'ar 12/12/2001 19:12'!\\nregistryThreshold\\n\\t\\\"Return the registry threshold above which socket creation may fail due to too many already open sockets. If the threshold is reached, a full GC will be issued if the creation of a socket fails.\\\"\\n\\t^RegistryThreshold! !\\n\\n!Socket class methodsFor: 'registry' stamp: 'ar 12/12/2001 19:12'!\\nregistryThreshold: aNumber\\n\\t\\\"Return the registry threshold above which socket creation may fail due to too many already open sockets. If the threshold is reached, a full GC will be issued if the creation of a socket fails.\\\"\\n\\tRegistryThreshold _ aNumber! !\\n\\n!Socket class methodsFor: 'registry' stamp: 'ar 10/7/1998 15:22'!\\nunregister: anObject\\n\\tWeakArray isFinalizationSupported ifFalse:[^anObject].\\n\\tself registry remove: anObject ifAbsent:[]! !\\n\\n\\n!Socket class methodsFor: 'utilities' stamp: 'tk 4/9/98 15:54'!\\ndeadServer\\n\\n\\t^ DeadServer! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'tk 4/9/98 15:56'!\\ndeadServer: aStringOrNil\\n\\t\\\"Keep the machine name of the most recently encoutered non-responding machine. Next time the user can move it to the last in a list of servers to try.\\\"\\n\\n\\tDeadServer _ aStringOrNil! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'mir 5/15/2003 18:28'!\\ndeadlineSecs: secs\\n\\t\\\"Return a deadline time the given number of seconds from now.\\\"\\n\\n\\t^ Time millisecondClockValue + (secs * 1000) truncated\\n! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'jm 1/14/1999 12:13'!\\nnameForWellKnownTCPPort: portNum\\n\\t\\\"Answer the name for the given well-known TCP port number. Answer a string containing the port number if it isn't well-known.\\\"\\n\\n\\t| portList entry |\\n\\tportList _ #(\\n\\t\\t(7 'echo') (9 'discard') (13 'time') (19 'characterGenerator')\\n\\t\\t(21 'ftp') (23 'telnet') (25 'smtp')\\n\\t\\t(80 'http') (110 'pop3') (119 'nntp')).\\n\\tentry _ portList detect: [:pair | pair first = portNum] ifNone: [^ 'port-', portNum printString].\\n\\t^ entry last\\n! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'mir 5/15/2003 18:30'!\\nping: hostName\\n\\t\\\"Ping the given host. Useful for checking network connectivity. The host must be running a TCP echo server.\\\"\\n\\t\\\"Socket ping: 'squeak.cs.uiuc.edu'\\\"\\n\\n\\t| tcpPort sock serverAddr startTime echoTime |\\n\\ttcpPort _ 7. \\\"7 = echo port, 13 = time port, 19 = character generator port\\\"\\n\\n\\tserverAddr _ NetNameResolver addressForName: hostName timeout: 10.\\n\\tserverAddr = nil ifTrue: [\\n\\t\\t^ self inform: 'Could not find an address for ', hostName].\\n\\n\\tsock _ Socket new.\\n\\tsock connectNonBlockingTo: serverAddr port: tcpPort.\\n\\t[sock waitForConnectionFor: 10]\\n\\t\\ton: ConnectionTimedOut\\n\\t\\tdo: [:ex |\\n\\t\\t\\t(self confirm: 'Continue to wait for connection to ', hostName, '?')\\n\\t\\t\\t\\tifTrue: [ex retry]\\n\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\tsock destroy.\\n\\t\\t\\t\\t\\t^ self]].\\n\\n\\tsock sendData: 'echo!!'.\\n\\tstartTime _ Time millisecondClockValue.\\n\\t[sock waitForDataFor: 15]\\n\\t\\ton: ConnectionTimedOut\\n\\t\\tdo: [:ex | (self confirm: 'Packet sent but no echo yet; keep waiting?')\\n\\t\\t\\tifTrue: [ex retry]].\\n\\techoTime _ Time millisecondClockValue - startTime.\\n\\n\\tsock destroy.\\n\\tself inform: hostName, ' responded in ', echoTime printString, ' milliseconds'.\\n! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'mir 2/22/2002 15:49'!\\npingPorts: portList on: hostName timeOutSecs: timeOutSecs\\n\\t\\\"Attempt to connect to each of the given sockets on the given host. Wait at most timeOutSecs for the connections to be established. Answer an array of strings indicating the available ports.\\\"\\n\\t\\\"Socket pingPorts: #(7 13 19 21 23 25 80 110 119) on: 'squeak.cs.uiuc.edu' timeOutSecs: 15\\\"\\n\\n\\t| serverAddr sockets sock deadline done unconnectedCount connectedCount waitingCount result |\\n\\tserverAddr _ NetNameResolver addressForName: hostName timeout: 10.\\n\\tserverAddr = nil ifTrue: [\\n\\t\\tself inform: 'Could not find an address for ', hostName.\\n\\t\\t^ #()].\\n\\n\\tsockets _ portList collect: [:portNum |\\n\\t\\tsock _ Socket new.\\n\\t\\tsock connectTo: serverAddr port: portNum].\\n\\n\\tdeadline _ self deadlineSecs: timeOutSecs.\\n\\tdone _ false.\\n\\t[done] whileFalse: [\\n\\t\\tunconnectedCount _ 0.\\n\\t\\tconnectedCount _ 0.\\n\\t\\twaitingCount _ 0.\\n\\t\\tsockets do: [:s |\\n\\t\\t\\ts isUnconnectedOrInvalid\\n\\t\\t\\t\\tifTrue: [unconnectedCount _ unconnectedCount + 1]\\n\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\ts isConnected ifTrue: [connectedCount _ connectedCount + 1].\\n\\t\\t\\t\\t\\ts isWaitingForConnection ifTrue: [waitingCount _ waitingCount + 1]]].\\n\\t\\twaitingCount = 0 ifTrue: [done _ true].\\n\\t\\tconnectedCount = sockets size ifTrue: [done _ true].\\n\\t\\tTime millisecondClockValue > deadline ifTrue: [done _ true]].\\n\\n\\tresult _ (sockets select: [:s | s isConnected])\\n\\t\\tcollect: [:s | self nameForWellKnownTCPPort: s remotePort].\\n\\tsockets do: [:s | s destroy].\\n\\t^ result\\n! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'jm 1/14/1999 17:25'!\\npingPortsOn: hostName\\n\\t\\\"Attempt to connect to a set of well-known sockets on the given host, and answer the names of the available ports.\\\"\\n\\t\\\"Socket pingPortsOn: 'www.disney.com'\\\"\\n\\n\\t^ Socket\\n\\t\\tpingPorts: #(7 13 19 21 23 25 80 110 119)\\n\\t\\ton: hostName\\n\\t\\ttimeOutSecs: 20\\n! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'mir 5/15/2003 16:17'!\\nstandardDeadline\\n\\t\\\"Return a default deadline time some seconds into the future.\\\"\\n\\n\\t^ self deadlineSecs: self standardTimeout\\n! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'mir 5/15/2003 16:16'!\\nstandardTimeout\\n\\n\\t^45\\n! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'ar 4/30/1999 04:21'!\\nwildcardAddress\\n\\t\\\"Answer a don't-care address for use with UDP sockets.\\\"\\n\\n\\t^ByteArray new: 4\\t\\t\\\"0.0.0.0\\\"! !\\n\\n!Socket class methodsFor: 'utilities' stamp: 'ar 4/30/1999 04:21'!\\nwildcardPort\\n\\t\\\"Answer a don't-care port for use with UDP sockets. (The system will allocate an\\n\\tunused port number to the socket.)\\\"\\n\\n\\t^0! !\\n\\n\\n!Socket class methodsFor: 'tests' stamp: 'gk 12/15/2005 01:18'!\\nloopbackTest\\n\\t\\\"Send data from one socket to another on the local machine.\\n\\tTests most of the socket primitives.\\\"\\n\\n\\t\\\"100 timesRepeat: [Socket loopbackTest]\\\"\\n\\n\\t| sock1 sock2 bytesToSend sendBuf receiveBuf done bytesSent bytesReceived t extraBytes packetsSent packetsRead |\\n\\tTranscript\\n\\t\\tcr;\\n\\t\\tshow: 'starting loopback test';\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: '---------- Connecting ----------';\\n\\t\\tcr.\\n\\tself initializeNetwork.\\n\\tsock1 := self new.\\n\\tsock2 := self new.\\n\\tsock1 listenOn: 54321.\\n\\tsock2 connectTo: NetNameResolver localHostAddress port: 54321.\\n\\tsock1 waitForConnectionFor: self standardTimeout.\\n\\tsock2 waitForConnectionFor: self standardTimeout.\\n\\tsock1 isConnected ifFalse: [self error: 'sock1 not connected'].\\n\\tsock2 isConnected ifFalse: [self error: 'sock2 not connected'].\\n\\tTranscript\\n\\t\\tshow: 'connection established';\\n\\t\\tcr.\\n\\tbytesToSend := 5000000.\\n\\tsendBuf := String new: 5000 withAll: $x.\\n\\treceiveBuf := String new: 50000.\\n\\tdone := false.\\n\\tpacketsSent := packetsRead := bytesSent := bytesReceived := 0.\\n\\tt := Time millisecondsToRun: \\n\\t\\t\\t\\t\\t[[done] whileFalse: \\n\\t\\t\\t\\t\\t\\t\\t[(sock1 sendDone and: [bytesSent < bytesToSend]) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsSent := packetsSent + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesSent := bytesSent + (sock1 sendSomeData: sendBuf)].\\n\\t\\t\\t\\t\\t\\t\\tsock2 dataAvailable \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[packetsRead := packetsRead + 1.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbytesReceived := bytesReceived + (sock2 receiveDataInto: receiveBuf)].\\n\\t\\t\\t\\t\\t\\t\\tdone := bytesSent >= bytesToSend and: [bytesReceived = bytesSent]]].\\n\\tTranscript\\n\\t\\tshow: 'closing connection';\\n\\t\\tcr.\\n\\tsock1 waitForSendDoneFor: self standardTimeout.\\n\\tsock1 close.\\n\\tsock2 waitForDisconnectionFor: self standardTimeout.\\n\\textraBytes := sock2 discardReceivedData.\\n\\textraBytes > 0 \\n\\t\\tifTrue: \\n\\t\\t\\t[Transcript\\n\\t\\t\\t\\tshow: ' *** received ' , extraBytes size printString , ' extra bytes ***';\\n\\t\\t\\t\\tcr].\\n\\tsock2 close.\\n\\tsock1 waitForDisconnectionFor: self standardTimeout.\\n\\tsock1 isUnconnectedOrInvalid ifFalse: [self error: 'sock1 not closed'].\\n\\tsock2 isUnconnectedOrInvalid ifFalse: [self error: 'sock2 not closed'].\\n\\tTranscript\\n\\t\\tshow: '---------- Connection Closed ----------';\\n\\t\\tcr.\\n\\tsock1 destroy.\\n\\tsock2 destroy.\\n\\tTranscript\\n\\t\\tshow: 'loopback test done; time = ' , t printString;\\n\\t\\tcr.\\n\\tTranscript\\n\\t\\tshow: (bytesToSend asFloat / t roundTo: 0.01) printString \\n\\t\\t\\t\\t\\t, '* 1000 bytes/sec';\\n\\t\\tcr.\\n\\tTranscript endEntry! !\\n\\n!Socket class methodsFor: 'tests' stamp: 'gk 12/15/2005 01:03'!\\nnewAcceptCheck\\n\\t\\\"Check if the platform has support for the BSD style accept().\\\"\\n\\n\\t\\\"Socket newAcceptCheck\\\"\\n\\t\\n\\t| socket |\\n\\tself initializeNetwork.\\n\\tsocket _ self newTCP.\\n\\tsocket listenOn: 44444 backlogSize: 4.\\n\\tsocket isValid ifTrue: [\\n\\t\\tself inform: 'Everything looks OK for the BSD style accept()'\\n\\t] ifFalse: [\\n\\t\\tself inform: 'It appears that you DO NOT have support for the BSD style accept()'].\\n\\tsocket destroy! !\\n\\n!Socket class methodsFor: 'tests' stamp: 'gk 12/15/2005 01:10'!\\nsendTest\\n\\t\\\"Send data to the 'discard' socket of the given host.\\n\\tTests the speed of one-way data transfers across the\\n\\tnetwork to the given host. Note that most hosts\\n\\tdo not run a discard server.\\\"\\n\\n\\t\\\"Socket sendTest\\\"\\n\\n\\t| sock bytesToSend sendBuf bytesSent t serverName serverAddr |\\n\\tTranscript cr; show: 'starting send test'; cr.\\n\\tself initializeNetwork.\\n\\tserverName := UIManager default request: 'What is the destination server?' initialAnswer: 'create.ucsb.edu'.\\n\\tserverAddr := NetNameResolver addressForName: serverName timeout: 10.\\n\\tserverAddr = nil \\n\\t\\tifTrue: [^self inform: 'Could not find an address for ' , serverName].\\n\\tsock := self new.\\n\\tTranscript show: '---------- Connecting ----------';cr.\\n\\tsock connectTo: serverAddr port: 9.\\n\\tsock isConnected ifFalse: [\\n\\t\\tsock destroy.\\n\\t\\t^self inform: 'could not connect'].\\n\\tTranscript show: 'connection established; sending data'; cr.\\n\\tbytesToSend := 1000000.\\n\\tsendBuf := String new: 64 * 1024 withAll: $x.\\n\\tbytesSent := 0.\\n\\tt := Time millisecondsToRun: \\n\\t\\t\\t\\t\\t[[bytesSent < bytesToSend] whileTrue: \\n\\t\\t\\t\\t\\t\\t\\t[sock sendDone \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [bytesSent := bytesSent + (sock sendSomeData: sendBuf)]]].\\n\\tsock waitForSendDoneFor: self standardTimeout.\\n\\tsock destroy.\\n\\tTranscript show: '---------- Connection Closed ----------'; cr;\\n\\t\\tshow: 'send test done; time = ' , t printString; cr;\\n\\t\\tshow: (bytesToSend asFloat / t roundTo: 0.01) printString, ' * 1000 bytes/sec';cr;endEntry! !\\nObject subclass: #SocketStream\\n\\tinstanceVariableNames: 'recentlyRead socket inBuffer outBuffer inNextToWrite outNextToWrite lastRead timeout autoFlush bufferSize binary shouldSignal'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Kernel'!\\n!SocketStream commentStamp: 'md 7/14/2006 16:32' prior: 0!\\nSocketStream is a wrapper for class Socket making it easy to write networking code by giving the programmer a stream-like protocol. A Socket is a two way communication link with two logically separate channels - input and output. The Socket class is the lowest level in Squeak for network communication and using it directly can be difficult and bug prone.\\n\\nA SocketStream can be in binary or ascii mode, ascii is the default which means you are transmitting and receiving Strings. Most Internet protocols are in clear text ascii, like for example HTTP. Another setting is what timeout you want to use - default is the standardTimeout from Socket. More settings can be found in the method category 'configuration'.\\n\\nSimplest example of connecting, sending/receiving and closing:\\n\\n| stream result |\\nstream := SocketStream openConnectionToHostNamed: 'www.squeak.org' port: 80.\\n[[stream nextPutAll: 'GET / HTTP/1.0'; crlf; crlf; flush.\\nresult := stream upToEnd. \\\"Give us all data until the socket is closed.\\\"\\nTranscript show: result; cr.]\\n\\tensure: [stream close]]\\n\\t\\ton: ConnectionTimedOut\\n\\t\\tdo: [:ex | Transcript show: ex asString;cr. ex resume]\\n\\nThere are two important things to note above:\\n\\t- The methods in category \\\"stream in\\\" can signal two exceptions (unless turned off with #shouldSignal:):\\n\\t\\tConnectionClosed and ConnectionTimedOut\\n\\t- We close the stream using #ensure:, that is to make sure it isn't left opened.\\n\\t- We use #on:do: to catch any signal. In this case we do not need to catch ConnectionClosed since #upToEnd does that for us intrinsically.\\n\\n----------------\\nSocketStream (below called SS) is a reimplementation of 'Old'-SocketStream (below called OSS) - the class that originates from the original Comanche implementation but now is included in standard Squeak. SS has the same protocol as OSS and is meant to replace it. SS is faster, more flexible, is better documented and adds a few features:\\n\\n1. #shouldSignal:, which decides if SS should signal low level Socket exceptions (true) or if it should swallow them like original OSS did. Default is true. The only reason I added this is for backwards compatibility - not signalling causes problems - see bug 4 below.\\n\\n2. #nextAllInBuffer, #nextInBuffer:, #skip:, #receiveData:, #nextPutAllFlush: and #recentlyRead are new additions to the public protocol.\\n\\n\\nIt also fixes various bugs:\\n\\n1. #isDataAvailable could theoretically answer false, when there actually is some in the buffer in OSS. If #receiveDataIfAvailable reads the last byte then the following \\\"socket dataAvailable\\\" would answer false. So the last byte would be sitting in the inStream missed.\\n\\n2. #upToAll: in OSS has several problems, for example - #positionOfSubCollection:ifAbsent: which was introduced answers one position too low. This was compensated in upToAll:, but only in the pushBack: call, not the actual result being returned which was cut short 1 byte. Amusingly this makes KomHttpServer not use \\\"Keep-Alive\\\" since the last $e in 'Alive' was cut short. :)\\n\\n3. SS doesn't inherit from PositionableStream since that just breaks various inherited messages, like for example #skip:. OSS should IMHO be changed to inherit from Object - or of course, replaced in full with SS. :)\\n\\n4. Since SocketStream by default signals closes and timeouts the SocketStreamTest now passes. The reason for SocketStream to fail is that while it does timeout on a low level (#SocketStream>>receiveData doesn't hang forever) - the callers of #receiveData sometimes loop - like in #next:, and thus eliminates the timeout. SS warns about some methods (in their method comments) not honouring timeouts if shouldSignal is false, I really don't know what they should do in that case:\\n\\t#next:, #upTo:, #upToAll: and #upToEnd (and #receiveData:)\\n\\n\\nThe primary reason for the SS implementation is optimal performance. The main differences in implementation with the old OSS are:\\n\\n1. SS uses two buffers directly (inBuffer and outBuffer) with pointers marking start and stop within the buffer. OSS instead uses two regular streams, a ReadStream and a WriteStream. Using internal buffers makes it possible to avoid copying and reallocation in various ways, it also makes SS be able to have specialized growing/buffer moving behaviour.\\n\\n2. #upTo:, #upToAll: and #peekForAll: uses selectged String messages that in turn uses fast primitives for searching. OSS used other messages that fell back on byte per byte reading.\\n\\n3. #receiveData in OSS creates a temporary buffer stream for each call!! During a long read operation, like say #upToAll: (which for example is used when uploading files using HTTP POST forms), this is devastating - especially since the default size is only 2000 bytes - and leads to a very high number of low level read operations on the Socket, typically 100 times more calls than with OSS. The buffer in OSS is held in an instvar (not recreated for each call), is larger from the start and above all - grows dynamically by doubling. OSS can also avoid a grow/reallocation by doing a \\\"move down\\\" if data has been read from the SS as it comes in and through that making room in the lower part of the inBuffer. The net result is that upToAll: for large files is about 10 times faster.\\n\\n4. The implementation of upTo: and upToAll: tries to avoid doing unnecessary find operations in the buffer and is greedy by default, which means it favors reading more data - if available - before searching for the stop sequence. If we had #findString:startingAt:stoppingAt: this wouldn't have to be greedy and we wouldn't be needlessly scanning dead buffer area. VM hackers? Also, while you are at it - make it work for ByteArrays too. :)\\n\\n\\nSS can not be run unbuffered, since that seems unneeded. The option to autoFlush is still available, with it set to true SocketStream (just like OSS) will flush on its own on each nextPut:/nextPutAll:, otherwise flushing it will have to be done manually but is done on close.\\n\\nThe first performance tests shows that, as noted above, receiving large amounts of data using #upToAll: is greatly improved - factor of 10. Serving HTTP with small payloads seemed at first not be faster at all - but this is due to the high overhead of Socket connect/close and other things. Increasing payloads show a difference and especially with keep alive on - where the new SS roughly doubles the throughput!!!\\n\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/9/2005 22:37'!\\nascii\\n\\t\\\"Tell the SocketStream to send data\\n\\tas Strings instead of ByteArrays.\\n\\tThis is default.\\\"\\n\\n\\tbinary := false.\\n\\tself resetBuffers! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/9/2005 22:26'!\\nautoFlush\\n\\t\\\"If autoFlush is enabled data will be sent through\\n\\tthe socket (flushed) when the bufferSize is reached\\n\\tor the SocketStream is closed. Otherwise the user\\n\\twill have to send #flush manually.\\n\\tClose will always flush. Default is false.\\\"\\n\\n\\t^autoFlush! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/9/2005 22:27'!\\nautoFlush: aBoolean\\n\\t\\\"If autoFlush is enabled data will be sent through\\n\\tthe socket (flushed) when the bufferSize is reached\\n\\tor the SocketStream is closed. Otherwise the user\\n\\twill have to send #flush manually.\\n\\tClose will always flush. Default is false.\\\"\\n\\n\\tautoFlush := aBoolean! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/9/2005 22:37'!\\nbinary\\n\\t\\\"Tell the SocketStream to send data\\n\\tas ByteArrays instead of Strings.\\n\\tDefault is ascii.\\\"\\n\\n\\tbinary := true.\\n\\tself resetBuffers! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/9/2005 22:28'!\\nbufferSize\\n\\t\\\"Default buffer size is 4kb.\\n\\tincreased from earlier 2000 bytes.\\\"\\n\\t\\n\\t^bufferSize! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/9/2005 22:28'!\\nbufferSize: anInt\\n\\t\\\"Default buffer size is 4kb.\\n\\tincreased from earlier 2000 bytes.\\\"\\n\\n\\tbufferSize := anInt! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/10/2005 17:58'!\\ninBufferSize\\n\\t\\\"Answers the current size of data in the inBuffer.\\\"\\n\\n\\t^inNextToWrite - lastRead - 1! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/10/2005 17:59'!\\nnoTimeout\\n\\t\\\"Do not use timeout.\\\"\\n\\n\\ttimeout := 0! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/10/2005 17:59'!\\noutBufferSize\\n\\t\\\"Answers the current size of data in the outBuffer.\\\"\\n\\n\\t^outNextToWrite - 1! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/10/2005 18:00'!\\nshouldSignal\\n\\t\\\"If shouldSignal is enabled the Socket Exceptions\\n\\tConnectionClosed and ConnectionTimedOut\\n\\twill not be swallowed. Default is true.\\n\\tFor more info, see #shouldSignal:\\\"\\n\\n\\t^shouldSignal! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/10/2005 18:03'!\\nshouldSignal: aBoolean\\n\\t\\\"If shouldSignal is enabled the Socket Exceptions\\n\\tConnectionClosed and ConnectionTimedOut will not be swallowed.\\n\\tDefault is true. And please - don't set it to false - it is better to\\n\\tuse an exception handler (see below) and several methods\\n\\tin this class will not honour timeouts (says so in their method comments).\\n\\tAlso, it is quite hard to understand what for example #upToEnd\\n\\tshould return to indicate a timeout.\\n\\t\\n\\tWrap your use of SocketStream with a handler like:\\n\\t\\n\\t[stuff _ mySocketStream next: 10]\\n\\t\\ton: ConnectionClosed, ConnectionTimedOut\\n\\t\\tdo: [:ex |\\n\\t\\t\\tTranscript show: 'Oops!! Did not get my ten bytes!!;cr]\\n\\t\\\"\\n\\n\\tshouldSignal := aBoolean! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/3/2005 20:35'!\\nsocket\\n\\t^socket! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/3/2005 20:35'!\\nsocket: aSocket\\n\\tsocket _ aSocket! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/7/2005 08:41'!\\ntimeout\\n\\t\\\"Lazily initialized unless it has been set explicitly.\\\"\\n\\n\\ttimeout ifNil: [timeout := Socket standardTimeout].\\n\\t^timeout! !\\n\\n!SocketStream methodsFor: 'configuration' stamp: 'gk 2/3/2005 20:35'!\\ntimeout: seconds\\n\\ttimeout := seconds! !\\n\\n\\n!SocketStream methodsFor: 'control' stamp: 'gk 2/24/2005 11:55'!\\nclose\\n\\t\\\"Flush any data still not sent\\n\\tand take care of the socket.\\\"\\n\\n\\tself flush.\\n\\tsocket closeAndDestroy: 30! !\\n\\n!SocketStream methodsFor: 'control' stamp: 'gk 9/9/2005 09:33'!\\nflush\\n\\t\\\"If the other end is connected and we have something\\n\\tto send, then we send it and reset the outBuffer.\\\"\\n\\n\\t((outNextToWrite > 1) and: [socket isOtherEndClosed not])\\n\\t\\tifTrue: [\\n\\t\\t\\t[socket sendData: outBuffer count: outNextToWrite - 1]\\n\\t\\t\\t\\ton: ConnectionTimedOut\\n\\t\\t\\t\\tdo: [:ex | shouldSignal ifFalse: [\\\"swallow\\\"]].\\n\\t\\t\\toutNextToWrite _ 1]! !\\n\\n!SocketStream methodsFor: 'control' stamp: 'gk 4/14/2005 09:49'!\\nreceiveData: nBytes\\n\\t\\\"Keep reading the socket until we have nBytes\\n\\tin the inBuffer or we reach the end. This method\\n\\tdoes not return data, but can be used to make sure\\n\\tdata has been read into the buffer from the Socket\\n\\tbefore actually reading it from the FastSocketStream.\\n\\tMainly used internally. We could also adjust the buffer\\n\\tto the expected amount of data and avoiding several\\n\\tincremental grow operations.\\n\\n\\tNOTE: This method doesn't honor timeouts if shouldSignal\\n\\tis false!! And frankly, I am not sure how to handle that\\n\\tcase or if I care - I think we should always signal.\\\"\\n\\n\\t[self atEnd not and: [nBytes > self inBufferSize]]\\n\\t\\twhileTrue: [self receiveData]! !\\n\\n!SocketStream methodsFor: 'control' stamp: 'gk 2/9/2005 23:08'!\\nrecentlyRead\\n\\t\\\"Return the number of bytes read\\n\\tduring the last socket operation.\\\"\\n\\t\\n\\t^recentlyRead! !\\n\\n\\n!SocketStream methodsFor: 'initialize-release' stamp: 'gk 2/25/2005 14:20'!\\ninitialize\\n\\tautoFlush _ true.\\n\\tshouldSignal _ true.\\n\\trecentlyRead _ 0.\\n\\tbufferSize _ 4096.\\n\\tself ascii! !\\n\\n\\n!SocketStream methodsFor: 'printing' stamp: 'gk 2/25/2005 14:19'!\\ndebug\\n\\t\\\"Display debug info.\\\"\\n\\n\\t| data |\\n\\tdata _ self inBufferSize.\\n\\t^String streamContents: [:s |\\n\\t\\ts\\n\\t\\t\\tnextPutAll: 'Buffer size: ', inBuffer size asString;cr;\\n\\t\\t\\tnextPutAll: 'InBuffer data size: ', data asString; cr;\\n\\t\\t\\tnextPutAll: 'In data (20):', (inBuffer copyFrom: lastRead + 1 to: lastRead + (data min: 20)); cr;\\n\\t\\t\\tnextPutAll: 'OutBuffer data size: ', (outNextToWrite - 1) asString; cr;\\n\\t\\t\\tnextPutAll: 'Out data (20):', (outBuffer copyFrom: 1 to: ((outNextToWrite - 1) min: 20)); cr]! !\\n\\n!SocketStream methodsFor: 'printing' stamp: 'md 7/14/2006 12:28'!\\nprint: anObject\\n\\tanObject printOn: self! !\\n\\n!SocketStream methodsFor: 'printing' stamp: 'gk 2/10/2005 11:44'!\\nprintOn: aStream\\n\\t\\\"Display buffer sizes.\\\"\\n\\n\\taStream nextPutAll: self class name.\\n\\tinBuffer ifNotNil: [\\n\\t\\taStream nextPutAll: '[inbuf:',\\n\\t\\t(inBuffer size / 1024) rounded asString, 'kb/outbuf:',\\n\\t\\t(outBuffer size / 1024) rounded asString, 'kb]']! !\\n\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/7/2005 13:33'!\\nnext\\n\\t\\\"Return next byte, if inBuffer is empty\\n\\twe recieve some more data and try again.\\\"\\n\\n\\tself atEnd ifTrue: [^nil].\\n\\tself isInBufferEmpty ifTrue:\\n\\t\\t[self receiveData.\\n\\t\\tself atEnd ifTrue: [^nil]].\\n\\tlastRead _ lastRead + 1.\\n\\t^inBuffer at: lastRead! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/7/2005 21:26'!\\nnextAllInBuffer\\n\\t\\\"Return all data currently in the inBuffer,\\\"\\n\\n\\t^self nextInBuffer: inNextToWrite - lastRead - 1! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/7/2005 12:51'!\\nnextInBuffer: anInteger\\n\\t\\\"Answer anInteger bytes of data at most,\\n\\tbut only from the inBuffer.\\\"\\n\\n\\t| start amount |\\n\\tamount _ anInteger min: (inNextToWrite - lastRead - 1).\\n\\tstart _ lastRead + 1.\\n\\tlastRead _ lastRead + amount.\\n\\t^inBuffer copyFrom: start to: lastRead! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/15/2005 14:17'!\\nnext: anInteger\\n\\t\\\"Answer anInteger bytes of data.\\n\\n\\tNOTE: This method doesn't honor timeouts if shouldSignal is false!!\\\"\\n\\n\\t| start |\\n\\tself receiveData: anInteger.\\n\\tstart _ lastRead + 1.\\n\\tlastRead _ (lastRead + anInteger) min: inNextToWrite - 1.\\n\\t^inBuffer copyFrom: start to: lastRead! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/7/2005 13:47'!\\nnextAvailable\\n\\t\\\"Answer all the data currently available,\\n\\tin buffer or in socket.\\\"\\n\\n\\tself isInBufferEmpty ifFalse: [^self nextAllInBuffer].\\n\\tself isDataAvailable ifTrue: [self receiveData].\\n\\t^self nextAllInBuffer! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/7/2005 13:02'!\\nnextAvailable: howMany\\n\\t\\\"Answer all the data currently available,\\n\\tin buffer or in socket - but limited to <howMany>.\\\"\\n\\n\\tself isInBufferEmpty ifFalse: [^self nextInBuffer: howMany].\\n\\tself isDataAvailable ifTrue: [self receiveData].\\n\\t^self nextInBuffer: howMany! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/3/2005 20:35'!\\nnextLine\\n\\t^self nextLineCrLf! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/24/2005 12:01'!\\nnextLineCrLf\\n\\t^self upToAll: String crlf! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/15/2005 14:16'!\\nnextLineLf\\n\\t| nextLine |\\n\\tnextLine := self upToAll: String lf.\\n\\t^nextLine! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/15/2005 14:09'!\\npeek\\n\\t\\\"Return next byte, if inBuffer is empty\\n\\twe recieve some more data and try again.\\n\\tDo not consume the byte.\\\"\\n\\n\\tself atEnd ifTrue: [^nil].\\n\\tself isInBufferEmpty ifTrue:\\n\\t\\t[self receiveData.\\n\\t\\tself atEnd ifTrue: [^nil]].\\n\\t^inBuffer at: lastRead! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/7/2005 14:04'!\\npeekFor: aCharacterOrByte\\n\\t\\\"Read and return next character or byte\\n\\tif it is equal to the argument.\\n\\tOtherwise return false.\\\"\\n\\n\\t| nextObject |\\n\\tself atEnd ifTrue: [^false].\\n\\tself isInBufferEmpty ifTrue: \\n\\t\\t[self receiveData.\\n\\t\\tself atEnd ifTrue: [^false]].\\n\\tnextObject _ inBuffer at: lastRead.\\n\\tnextObject = aCharacterOrByte ifTrue: [\\n\\t\\tlastRead _ lastRead + 1.\\n\\t\\t^true].\\n\\t^false\\n! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/15/2005 14:16'!\\npeekForAll: aString\\n\\t\\\"Answer whether or not the next string of characters in the receiver\\n\\tmatches aString. If a match is made, advance over that string in the receiver and\\n\\tanswer true. If no match, then leave the receiver alone and answer false.\\n\\tWe use findString:startingAt: to avoid copying.\\n\\n\\tNOTE: This method doesn't honor timeouts if shouldSignal is false!!\\\"\\n\\n\\t| sz start |\\n\\tsz _ aString size.\\n\\tself receiveData: sz.\\n\\t(inNextToWrite - lastRead - 1) < sz ifTrue: [^false].\\n\\tstart _ lastRead + 1.\\n\\t(inBuffer findString: aString startingAt: start) = start\\n\\t\\tifFalse: [^false].\\n\\tlastRead _ lastRead + sz.\\n\\t^true! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/15/2005 14:16'!\\npeek: anInteger\\n\\t\\\"Answer anInteger bytes of data.\\n\\tDo not consume data.\\n\\n\\tNOTE: This method doesn't honor timeouts if shouldSignal is false!!\\\"\\n\\n\\t| start |\\n\\tself receiveData: anInteger.\\n\\tstart _ lastRead + 1.\\n\\t^inBuffer copyFrom: start to: ((lastRead + anInteger) min: inNextToWrite - 1).! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/15/2005 14:15'!\\nskip: anInteger\\n\\t\\\"Skip a number of bytes.\\n\\tThis is faster than #next: since it does not\\n\\thave to copy and return a new String or ByteArray.\\n\\n\\tNOTE: This method doesn't honor timeouts if shouldSignal is false!!\\\"\\n\\n\\tself receiveData: anInteger.\\n\\tlastRead _ (lastRead + anInteger) min: inNextToWrite - 1! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 9/9/2005 02:57'!\\nupTo: aCharacterOrByte\\n\\t\\\"Return data up to, but not including given character or byte.\\n\\t\\n\\tNOTE: Does not honour timeouts if shouldSignal is false!!\\n\\t\\n\\tThis method looks a bit complicated, and this is mainly because there is no fast search method\\n\\tin String that takes a stoppingAt: argument. This means we need to ignore getting hits in the\\n\\tdead buffer area above inNextToWrite.\\n\\tAnother measure is that this implementation is greedy and will load data into the buffer\\n\\tuntil there is nothing more available, or it has loaded 100kb - and not until then we search the buffer.\\n\\n\\tA totally non greedy variant would search on every loop.\\\"\\n\\n\\t| index result lastRecentlyRead searchedSoFar |\\n\\tsearchedSoFar _ 0.\\n\\tlastRecentlyRead _ 0.\\n\\tindex _ 0.\\n\\t[self atEnd not and: [\\n\\t\\t((lastRecentlyRead = 0 and: [self isInBufferEmpty not]) or: [self inBufferSize > 100000]) ifTrue: [\\n\\t\\t\\t\\\"Data begins at lastRead + 1, we add searchedSoFar as offset.\\\"\\n\\t\\t\\tindex _ inBuffer indexOf: aCharacterOrByte startingAt: lastRead + searchedSoFar + 1.\\n\\t\\t\\tsearchedSoFar _ self inBufferSize.\\n\\t\\t\\t(index > 0 and: [(index + 1) > inNextToWrite]) ifTrue: [\\n\\t\\t\\t\\t\\\"Oops, hit in dead buffer area.\\n\\t\\t\\t\\tThis is probably due to old data, so we ignore it.\\n\\t\\t\\t\\tNo point in cleaning the dead area to avoid hits - it will still search it.\\\"\\n\\t\\t\\t\\tindex _ 0]].\\n\\t\\tindex = 0]]\\n\\t\\t\\t\\twhileTrue: [\\n\\t\\t\\t\\t\\trecentlyRead = 0\\n\\t\\t\\t\\t\\t\\tifTrue: [\\\"blocking call for now, we don't want to poll\\\"\\n\\t\\t\\t\\t\\t\\t\\tself receiveData]\\n\\t\\t\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\t\\t\\tself receiveAvailableData].\\n\\t\\t\\t\\t\\tlastRecentlyRead _ recentlyRead].\\n\\tindex > 0\\n\\t\\tifTrue: [\\\"found it\\\"\\n\\t\\t\\tresult _ self nextInBuffer: index - lastRead - 1.\\n\\t\\t\\tself skip: 1.\\n\\t\\t\\t^ result]\\n\\t\\tifFalse: [\\\"atEnd\\\"\\n\\t\\t\\t^ self nextAllInBuffer]! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 9/9/2005 02:55'!\\nupToAll: aStringOrByteArray\\n\\t\\\"Answer a subcollection from the current access position to the occurrence (if any, but not\\n\\tinclusive) of aStringOrByteArray. If aCollection is not in the stream, answer the entire rest of\\n\\tthe stream.\\n\\t\\n\\tNOTE: Does not honour timeouts if shouldSignal is false!!\\n\\t\\n\\tThis method looks a bit complicated, and this is mainly because there is no fast search method\\n\\tin String that takes a stoppingAt: argument. This means we need to ignore getting hits in the\\n\\tdead buffer area above inNextToWrite.\\n\\tAnother measure is that this implementation is greedy and will load data into the buffer\\n\\tuntil there is nothing more available, or it has loaded 100kb - and not until then we search the buffer.\\n\\n\\tA totally non greedy variant would search on every loop.\\\"\\n\\n\\t| index sz result lastRecentlyRead searchedSoFar |\\n\\tsz _ aStringOrByteArray size.\\n\\tsearchedSoFar _ 0.\\n\\tlastRecentlyRead _ 0.\\n\\tindex _ 0.\\n\\t[self atEnd not and: [\\n\\t\\t((lastRecentlyRead = 0 and: [self isInBufferEmpty not]) or: [self inBufferSize > 100000]) ifTrue: [\\n\\t\\t\\t\\\"Data begins at lastRead + 1, we add searchedSoFar as offset and backs up sz - 1\\n\\t\\t\\tso that we can catch any borderline hits.\\\"\\n\\t\\t\\tindex _ inBuffer indexOfSubCollection: aStringOrByteArray\\n\\t\\t\\t\\t\\t\\tstartingAt: lastRead + searchedSoFar - sz + 2.\\n\\t\\t\\tsearchedSoFar _ self inBufferSize.\\n\\t\\t\\t(index > 0 and: [(index + sz) > inNextToWrite]) ifTrue: [\\n\\t\\t\\t\\t\\\"Oops, hit partially or completely in dead buffer area.\\n\\t\\t\\t\\tThis is probably due to old data, so we ignore it.\\n\\t\\t\\t\\tNo point in cleaning the dead area to avoid hits - it will still search it.\\\"\\n\\t\\t\\t\\tindex _ 0]].\\n\\t\\tindex = 0]]\\n\\t\\t\\t\\twhileTrue: [\\n\\t\\t\\t\\t\\trecentlyRead = 0\\n\\t\\t\\t\\t\\t\\tifTrue: [\\\"blocking call for now, we don't want to poll\\\"\\n\\t\\t\\t\\t\\t\\t\\tself receiveData]\\n\\t\\t\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\t\\t\\tself receiveAvailableData].\\n\\t\\t\\t\\t\\tlastRecentlyRead _ recentlyRead].\\n\\tindex > 0\\n\\t\\tifTrue: [\\\"found it\\\"\\n\\t\\t\\tresult _ self nextInBuffer: index - lastRead - 1.\\n\\t\\t\\tself skip: sz.\\n\\t\\t\\t^ result]\\n\\t\\tifFalse: [\\\"atEnd\\\"\\n\\t\\t\\t^ self nextAllInBuffer]! !\\n\\n!SocketStream methodsFor: 'stream in' stamp: 'gk 2/15/2005 14:14'!\\nupToEnd\\n\\t\\\"Answer all data coming in on the socket until the socket\\n\\tis closed by the other end, or we get a timeout.\\n\\tThis means this method catches ConnectionClosed by itself.\\n\\t\\n\\tNOTE: Does not honour timeouts if shouldSignal is false!!\\\"\\n\\n\\t[[self atEnd] whileFalse: [self receiveData]]\\n\\t\\ton: ConnectionClosed\\n\\t\\tdo: [:ex | \\\"swallow it\\\"]. \\n\\t^self nextAllInBuffer! !\\n\\n\\n!SocketStream methodsFor: 'stream out' stamp: 'gk 2/3/2005 20:35'!\\ncr\\n\\tself nextPutAll: String cr! !\\n\\n!SocketStream methodsFor: 'stream out' stamp: 'gk 2/3/2005 20:35'!\\ncrlf\\n\\tself nextPutAll: String crlf! !\\n\\n!SocketStream methodsFor: 'stream out' stamp: 'gk 2/10/2005 11:14'!\\nnextPutAllFlush: aCollection\\n\\t\\\"Put a String or a ByteArray onto the stream.\\n\\tYou can use this if you have very large data - it avoids\\n\\tcopying into the buffer (and avoids buffer growing)\\n\\tand also flushes any other pending data first.\\\"\\n\\n\\t| toPut |\\n\\ttoPut _ binary ifTrue: [aCollection asByteArray] ifFalse: [aCollection asString].\\n\\tself flush. \\\"first flush pending stuff, then directly send\\\"\\n\\tsocket isOtherEndClosed ifFalse: [\\n\\t\\t[socket sendData: toPut count: toPut size]\\n\\t\\t\\ton: ConnectionTimedOut\\n\\t\\t\\tdo: [:ex | shouldSignal ifFalse: [\\\"swallow\\\"]]]! !\\n\\n!SocketStream methodsFor: 'stream out' stamp: 'md 2/24/2006 19:51'!\\nnextPut: char\\n\\t\\\"Put a single Character or byte onto the stream.\\\"\\n\\n\\t| toPut |\\n\\ttoPut _ binary ifTrue: [char asInteger] ifFalse: [char asCharacter].\\n\\tself adjustOutBuffer: 1.\\n\\toutBuffer at: outNextToWrite put: toPut.\\n\\toutNextToWrite _ outNextToWrite + 1.\\n\\tself checkFlush.\\n\\t\\\"return the argument - added by kwl\\\"\\n\\t^ char! !\\n\\n!SocketStream methodsFor: 'stream out' stamp: 'gk 2/7/2005 22:51'!\\nnextPutAll: aCollection\\n\\t\\\"Put a String or a ByteArray onto the stream.\\n\\tCurrently a large collection will allocate a large buffer.\\\"\\n\\n\\t| toPut |\\n\\ttoPut _ binary ifTrue: [aCollection asByteArray] ifFalse: [aCollection asString].\\n\\tself adjustOutBuffer: toPut size.\\n\\toutBuffer replaceFrom: outNextToWrite to: outNextToWrite + toPut size - 1 with: toPut startingAt: 1.\\n\\toutNextToWrite _ outNextToWrite + toPut size.\\n\\tself checkFlush! !\\n\\n!SocketStream methodsFor: 'stream out' stamp: 'gk 9/9/2005 09:32'!\\nsendCommand: aString\\n\\t\\\"Sends a String ending it with CR LF and then flush\\n\\tcausing it to block until sent.\\\"\\n\\n\\tself nextPutAll: aString, String crlf; flush! !\\n\\n!SocketStream methodsFor: 'stream out' stamp: 'gk 2/3/2005 20:35'!\\nspace\\n\\tself nextPut: Character space! !\\n\\n\\n!SocketStream methodsFor: 'testing' stamp: 'gk 2/25/2005 14:23'!\\natEnd\\n\\t\\\"There is nothing more to read when\\n\\tthere is no more data in our inBuffer, the socket\\n\\tis disconnected and there is none available on the socket.\\n\\tNote that we need to check isConnected before isDataAvailable,\\n\\totherwise data may sneak in in the meantime. But we check the\\n\\tbuffer first, because it is faster.\\\"\\n\\n\\tself isInBufferEmpty ifFalse: [^false].\\n\\t^self isConnected not\\n\\t\\tand: [self isDataAvailable not]! !\\n\\n!SocketStream methodsFor: 'testing' stamp: 'gk 2/3/2005 20:35'!\\nisBinary\\n\\t^binary! !\\n\\n!SocketStream methodsFor: 'testing' stamp: 'gk 2/7/2005 12:24'!\\nisConnected\\n\\t\\\"The stream is connected if the socket is.\\\"\\n\\n\\t^socket isConnected! !\\n\\n!SocketStream methodsFor: 'testing' stamp: 'gk 2/24/2005 12:23'!\\nisDataAvailable\\n\\t\\\"It the inbuffer is empty, we check the socket for data.\\n\\tIf it claims to have data available to read, we try to read\\n\\tsome once and recursively call this method again.\\n\\tIf something really was available it is now in the inBuffer.\\n\\tThis is because there has been spurious\\n\\tdataAvailable when there really is no data to get.\\\"\\n \\n\\tself isInBufferEmpty ifFalse: [^true].\\n\\t^socket dataAvailable\\n\\t\\tifFalse: [false]\\n\\t\\tifTrue: [self receiveDataIfAvailable; isDataAvailable]! !\\n\\n!SocketStream methodsFor: 'testing' stamp: 'gk 2/7/2005 13:02'!\\nisEmpty\\n\\t\\\"Test if there are more data to read.\U0005\\\"\\n\\n\\t^self isInBufferEmpty and: [self isDataAvailable not]! !\\n\\n!SocketStream methodsFor: 'testing' stamp: 'gk 2/7/2005 13:02'!\\nisInBufferEmpty\\n\\t\\\"Any data in the buffer?\\\"\\n \\n\\t^lastRead + 1 = inNextToWrite! !\\n\\n!SocketStream methodsFor: 'testing' stamp: 'gk 2/7/2005 08:59'!\\nisOtherEndConnected\\n\\t^socket isOtherEndClosed not! !\\n\\n!SocketStream methodsFor: 'testing' stamp: 'gk 2/3/2005 20:35'!\\nshouldTimeout\\n\\t^self timeout > 0! !\\n\\n\\n!SocketStream methodsFor: 'private' stamp: 'gk 2/9/2005 22:44'!\\nadjustInBuffer: bytesRead\\n\\t\\\"Adjust markers and possibly grow inBuffer or move data down.\\n\\tCurrently grows through doubling when less than 1024 bytes are left.\\n\\tNever shrinks. Returns the position in the buffer where any new\\n\\tdata can be found.\\\"\\n\\n\\t| old |\\n\\tbytesRead = 0 ifTrue: [^inNextToWrite].\\n\\told _ inNextToWrite.\\n\\tinNextToWrite _ inNextToWrite + bytesRead.\\n\\t(inBuffer size - inNextToWrite) < 1024\\n\\t\\tifTrue: [\\n\\t\\t\\t\\\"Hit the roof, move data down (if enough has been read) or do we grow?\\\"\\n\\t\\t\\t(lastRead > 512)\\n\\t\\t\\t\\tifTrue: [^old - self moveInBufferDown]\\n\\t\\t\\t\\tifFalse: [self growInBuffer]].\\n\\t^old! !\\n\\n!SocketStream methodsFor: 'private' stamp: 'gk 2/9/2005 22:42'!\\nadjustOutBuffer: bytesToWrite\\n\\t\\\"Possibly grow outBuffer to accommodate the new data.\\n\\tCurrently grows through doubling when less\\n\\tthan 1024 bytes are left. If bytesToWrite is even\\n\\tlarger we double that instead. Never shrinks.\\\"\\n\\n\\t(outBuffer size - outNextToWrite - bytesToWrite) < 1024 ifTrue: [\\n\\t\\toutBuffer _ (self streamBuffer: ((outBuffer size max: bytesToWrite) * 2))\\n\\t\\t\\t\\t\\t\\treplaceFrom: 1 to: outBuffer size with: outBuffer startingAt: 1]! !\\n\\n!SocketStream methodsFor: 'private' stamp: 'gk 2/7/2005 13:09'!\\ncheckFlush\\n\\t\\\"If autoFlush is true we flush if\\n\\twe have reached the bufferSize\\n\\tof data in the outBuffer.\\\"\\n\\n\\t(autoFlush and: [outNextToWrite > bufferSize])\\n\\t\\tifTrue: [self flush]! !\\n\\n!SocketStream methodsFor: 'private' stamp: 'gk 2/7/2005 23:05'!\\ngrowInBuffer\\n\\t\\\"Grows through doubling.\\\"\\n\\n\\tself resizeInBuffer: inBuffer size * 2! !\\n\\n!SocketStream methodsFor: 'private' stamp: 'gk 2/8/2005 22:15'!\\nmoveInBufferDown\\n\\t\\\"Move down contents of inBuffer to the start.\\n\\tReturn distance moved.\\\"\\n\\n\\t| sz distanceMoved |\\n\\tsz _ inNextToWrite - lastRead - 1.\\n\\tinBuffer replaceFrom: 1 to: sz with: inBuffer startingAt: lastRead + 1.\\n\\tdistanceMoved _ lastRead.\\n\\tlastRead _ 0.\\n\\tinNextToWrite _ sz + 1.\\n\\t^distanceMoved\\n! !\\n\\n!SocketStream methodsFor: 'private' stamp: 'gk 2/9/2005 22:36'!\\nresetBuffers\\n\\t\\\"Recreate the buffers with default start sizes.\\\"\\n\\n\\tinBuffer _ self streamBuffer: bufferSize.\\n\\tlastRead _ 0.\\n\\tinNextToWrite _ 1.\\n\\toutBuffer _ self streamBuffer: bufferSize.\\n\\toutNextToWrite _ 1! !\\n\\n!SocketStream methodsFor: 'private' stamp: 'gk 9/9/2005 02:29'!\\nresizeInBuffer: newSize\\n\\t\\\"Resize the inBuffer by recreating it.\\n\\tThis also has the effect of getting rid of\\n\\tdead data above inNextToWrite.\\n\\t<newSize> must >= inBuffer size!!\\\"\\n\\n\\tinBuffer _ (self streamBuffer: newSize)\\n\\t\\t\\t\\t\\treplaceFrom: 1 to: inNextToWrite - 1 with: inBuffer startingAt: 1! !\\n\\n!SocketStream methodsFor: 'private' stamp: 'gk 2/9/2005 22:35'!\\nstreamBuffer: size\\n\\t\\\"Create a buffer of the correct class and given size.\\\"\\n\\n\\t^(self isBinary\\n\\t\\tifTrue: [ByteArray]\\n\\t\\tifFalse: [String]) new: size! !\\n\\n\\n!SocketStream methodsFor: 'private-socket' stamp: 'gk 2/25/2005 14:20'!\\nreceiveAvailableData\\n\\t\\\"Receive available data (as much as fits in the inBuffer)\\n\\tbut not waiting for more to arrive.\\n\\tReturn the position in the buffer where the\\n\\tnew data starts, regardless if anything\\n\\twas read, see #adjustInBuffer.\\\"\\n\\t\\n\\trecentlyRead _ socket receiveAvailableDataInto: inBuffer startingAt: inNextToWrite.\\n\\t^self adjustInBuffer: recentlyRead! !\\n\\n!SocketStream methodsFor: 'private-socket' stamp: 'gk 2/25/2005 14:20'!\\nreceiveData\\n\\t\\\"Receive data with timeout if it has been set.\\n\\tIf shouldSignal is false we use the Socket methods\\n\\tthat swallow those Exceptions, if it is true the\\n\\tcaller will have to handle those Exceptions.\\n\\tReturn the position in the buffer where the\\n\\tnew data starts, regardless if anything\\n\\twas read, see #adjustInBuffer.\\\"\\n\\t\\n\\trecentlyRead := shouldSignal ifTrue: [\\n\\t\\tself shouldTimeout ifTrue: [\\n\\t\\t\\t\\tsocket receiveDataSignallingTimeout: timeout\\n\\t\\t\\t\\t\\tinto: inBuffer startingAt: inNextToWrite]\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tsocket receiveDataSignallingClosedInto: inBuffer\\n\\t\\t\\t\\t\\tstartingAt: inNextToWrite]]\\n\\t\\t\\t\\tifFalse: [\\n\\t\\tself shouldTimeout ifTrue: [\\n\\t\\t\\t\\\"This case is tricky, if it times out and is swallowed\\n\\t\\t\\thow does other methods calling this method repeatedly\\n\\t\\t\\tget to know that? And what should they do?\\\"\\n\\t\\t\\t\\tsocket receiveDataTimeout: timeout\\n\\t\\t\\t\\t\\tinto: inBuffer startingAt: inNextToWrite]\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tsocket receiveDataInto: inBuffer\\n\\t\\t\\t\\t\\tstartingAt: inNextToWrite]].\\n\\t^self adjustInBuffer: recentlyRead! !\\n\\n!SocketStream methodsFor: 'private-socket' stamp: 'gk 2/9/2005 22:53'!\\nreceiveDataIfAvailable\\n\\t\\\"Only used to check that there really is data to read\\n\\tfrom the socket after it signals dataAvailable.\\n\\tIt has been known to signal true and then still\\n\\tnot have anything to read. See also isDataAvailable.\\n\\tReturn the position in the buffer where the\\n\\tnew data starts, regardless if anything\\n\\twas read, see #adjustInBuffer.\\\"\\n\\n\\trecentlyRead _ socket receiveSomeDataInto: inBuffer startingAt: inNextToWrite.\\n\\t^self adjustInBuffer: recentlyRead! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSocketStream class\\n\\tinstanceVariableNames: ''!\\n\\n!SocketStream class methodsFor: 'example' stamp: 'md 8/14/2005 18:25'!\\nfinger: userName\\n\\t\\\"SocketStream finger: 'stp'\\\"\\n\\n\\t| addr s |\\n\\taddr _ NetNameResolver promptUserForHostAddress.\\n\\ts _ SocketStream openConnectionToHost: addr port: 79. \\\"finger port number\\\"\\n\\tTranscript show: '---------- Connecting ----------'; cr.\\n\\ts sendCommand: userName.\\n\\tTranscript show: s getLine.\\n\\ts close.\\n\\tTranscript show: '---------- Connection Closed ----------'; cr; endEntry.\\n! !\\n\\n\\n!SocketStream class methodsFor: 'instance creation' stamp: 'gk 2/3/2005 22:19'!\\non: socket\\n\\t\\\"Create a socket stream on a connected server socket.\\\"\\n\\n\\t^self basicNew initialize socket: socket! !\\n\\n!SocketStream class methodsFor: 'instance creation' stamp: 'gk 2/3/2005 20:35'!\\nopenConnectionToHost: hostIP port: portNumber\\n\\t| socket |\\n\\tsocket _ Socket new.\\n\\tsocket connectTo: hostIP port: portNumber.\\n\\t^self on: socket! !\\n\\n!SocketStream class methodsFor: 'instance creation' stamp: 'gk 2/3/2005 20:35'!\\nopenConnectionToHostNamed: hostName port: portNumber\\n\\t| hostIP |\\n\\thostIP _ NetNameResolver addressForName: hostName timeout: 20.\\n\\t^self openConnectionToHost: hostIP port: portNumber! !\\nSocket subclass: #SocksSocket\\n\\tinstanceVariableNames: 'vers method socksIP socksPort dstPort dstIP dstName'\\n\\tclassVariableNames: 'DefaultSocksVersion'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-Kernel'!\\n!SocksSocket commentStamp: '<historical>' prior: 0!\\nThis class implements the socks 4 and partially socks 5 connection protocol.\\nFor backward compatibility the socks protocol is disabled by default, so subclasses still work.\\nFor further documentation check out:\\n\\nSocks4: http://spiderman.socks.nec.com/protocol/socks4.protocol\\n\\nSocks5: http://spiderman.socks.nec.com/rfc/rfc1928.txt!\\n\\n\\n!SocksSocket methodsFor: 'connection open/close' stamp: 'mir 2/22/2002 15:49'!\\nconnectTo: hostAddress port: port\\n\\tself initializeNetwork.\\n\\tself shouldUseSocks\\n\\t\\tifFalse: [^super connectTo: hostAddress port: port].\\n\\tsuper connectTo: socksIP port: socksPort.\\n\\tself waitForConnectionUntil: Socket standardDeadline.\\n\\tdstIP _ hostAddress.\\n\\tdstPort _ port.\\n\\tvers == 4\\n\\t\\tifTrue: [self connectSocks4]\\n\\t\\tifFalse: [self connectSocks5]\\n\\t! !\\n\\n!SocksSocket methodsFor: 'connection open/close' stamp: 'mir 3/6/2000 15:17'!\\nconnectToHostNamed: hostName port: port\\n\\tsuper connectTo: socksIP port: socksPort.\\n\\tself waitForConnectionUntil: Socket standardDeadline.\\n\\tdstName _ hostName.\\n\\tdstPort _ port.\\n\\tvers == 4\\n\\t\\tifTrue: [self connectSocks4]\\n\\t\\tifFalse: [self connectSocks5]\\n\\t! !\\n\\n\\n!SocksSocket methodsFor: 'initialize' stamp: 'mir 9/26/2000 00:05'!\\nsocks4\\n\\tvers _ 4.\\n\\tmethod _ nil.\\n\\tsocksIP _ self class defaultSocksHostAddress.\\n\\tsocksPort _ self class defaultSocksPort! !\\n\\n!SocksSocket methodsFor: 'initialize' stamp: 'mir 9/26/2000 00:05'!\\nsocks5\\n\\tvers _ 5.\\n\\tmethod _ self class noAutorizationMethod.\\n\\tsocksIP _ self class defaultSocksHostAddress.\\n\\tsocksPort _ self class defaultSocksPort! !\\n\\n\\n!SocksSocket methodsFor: 'methods' stamp: 'mir 3/6/2000 13:24'!\\nnoAutorizationMethod\\n\\t^0! !\\n\\n\\n!SocksSocket methodsFor: 'socks4' stamp: 'mir 3/6/2000 15:07'!\\nconnectSocks4\\n\\tself\\n\\t\\tsendSocks4ConnectionRequestUserId: '';\\n\\t\\twaitForSocks4ConnectionReply.\\n! !\\n\\n!SocksSocket methodsFor: 'socks4' stamp: 'mir 2/22/2002 15:49'!\\nsendSocks4ConnectionRequestUserId: userId\\n\\t\\\"The client connects to the SOCKS server and sends a CONNECT request when\\nit wants to establish a connection to an application server. The client\\nincludes in the request packet the IP address and the port number of the\\ndestination host, and userid, in the following format.\\n\\n\\t+----+----+----+----+----+----+----+----+----+----+....+----+\\n\\t| VN | CD | DSTPORT | DSTIP | USERID |NULL|\\n\\t+----+----+----+----+----+----+----+----+----+----+....+----+\\n\\t 1 1 2 4 variable 1\\n\\t\\\"\\n\\n\\t| requestString |\\n\\trequestString _ WriteStream on: ByteArray new.\\n\\tdstIP\\n\\t\\tifNil: [dstIP _ NetNameResolver addressForName: dstName].\\n\\trequestString\\n\\t\\tnextPut: 4;\\n\\t\\tnextPut: self connectCommandCode;\\n\\t\\tnextWordPut: dstPort;\\n\\t\\tnextPutAll: self dstIP;\\n\\t\\tnextPutAll: userId asByteArray;\\n\\t\\tnextPut: 0.\\n\\tself sendData: requestString contents! !\\n\\n!SocksSocket methodsFor: 'socks4' stamp: 'mir 3/6/2000 15:11'!\\nwaitForSocks4ConnectionReply\\n\\n\\t| response |\\n\\tresponse _ self waitForReply: 8 for: self defaultTimeOutDuration.\\n\\n\\t(response at: 2) = self requestGrantedCode\\n\\t\\tifFalse: [^self socksError: 'Connection failed: ' , (response at: 2) printString].! !\\n\\n\\n!SocksSocket methodsFor: 'socks5' stamp: 'mir 3/6/2000 17:42'!\\nconnectSocks5\\n\\tself\\n\\t\\tsocks5MethodSelection;\\n\\t\\tsendSocks5ConnectionRequest;\\n\\t\\tsocks5RequestReply\\n! !\\n\\n!SocksSocket methodsFor: 'socks5' stamp: 'mir 3/6/2000 17:29'!\\nhostIP6Code\\n\\t^4! !\\n\\n!SocksSocket methodsFor: 'socks5' stamp: 'mir 3/6/2000 15:20'!\\nhostIPCode\\n\\t^1! !\\n\\n!SocksSocket methodsFor: 'socks5' stamp: 'mir 3/6/2000 15:15'!\\nqualifiedHostNameCode\\n\\t^3! !\\n\\n!SocksSocket methodsFor: 'socks5' stamp: 'mir 3/6/2000 17:25'!\\nsendSocks5ConnectionRequest\\n\\t\\\"Once the method-dependent subnegotiation has completed, the client\\n sends the request details.\\\"\\n\\n\\t| requestString |\\n\\trequestString _ WriteStream on: ByteArray new.\\n\\trequestString\\n\\t\\tnextPut: 5;\\n\\t\\tnextPut: self connectCommandCode;\\n\\t\\tnextPut: 0. \\\"Reserved slot\\\"\\n\\tdstName isNil\\n\\t\\tifTrue: [\\n\\t\\t\\trequestString\\n\\t\\t\\t\\tnextPutAll: self hostIPCode;\\n\\t\\t\\t\\tnextPutAll: dstIP]\\n\\t\\tifFalse: [\\n\\t\\t\\trequestString\\n\\t\\t\\t\\tnextPut: self qualifiedHostNameCode;\\n\\t\\t\\t\\tnextPut: dstName size;\\n\\t\\t\\t\\tnextPutAll: dstName asByteArray].\\n\\trequestString nextWordPut: dstPort.\\n\\tself sendData: requestString contents! !\\n\\n!SocksSocket methodsFor: 'socks5' stamp: 'mir 3/6/2000 17:35'!\\nskipQualifiedHostName\\n\\n\\t| startTime response bytesRead |\\n\\tstartTime _ Time millisecondClockValue.\\n\\tresponse _ ByteArray new: 1.\\n\\n\\t[(bytesRead _ self receiveDataInto: response) < 1\\n\\t\\tand: [(Time millisecondClockValue - startTime) < self defaultTimeOutDuration]] whileTrue.\\n\\n\\tbytesRead < 1\\n\\t\\tifTrue: [self socksError: 'Time out reading data'].\\n\\n\\tself waitForReply: (response at: 1) + 2 for: self defaultTimeOutDuration! !\\n\\n!SocksSocket methodsFor: 'socks5' stamp: 'mir 3/6/2000 15:16'!\\nsocks5MethodSelection\\n\\t\\\"The client connects to the server, and sends a version\\n identifier/method selection message.\\n\\tThe server selects from one of the methods given in METHODS, and\\n sends a METHOD selection message.\\\"\\n\\n\\t| requestString response |\\n\\trequestString _ WriteStream on: ByteArray new.\\n\\trequestString\\n\\t\\tnextPut: 5;\\n\\t\\tnextPut: 1;\\n\\t\\tnextPut: 0.\\n\\tself sendData: requestString contents.\\n\\n\\tresponse _ self waitForReply: 2 for: self defaultTimeOutDuration.\\n\\t(response at: 2) == 16rFF\\n\\t\\tifTrue: [self socksError: 'No acceptable methods.']\\n\\t\\tifFalse: [method _ response at: 2]! !\\n\\n!SocksSocket methodsFor: 'socks5' stamp: 'mir 3/6/2000 17:28'!\\nsocks5RequestReply\\n\\n\\t| response |\\n\\tresponse _ self waitForReply: 4 for: self defaultTimeOutDuration.\\n\\t\\\"Skip rest for now.\\\"\\n\\t(response at: 4) = self hostIPCode\\n\\t\\tifTrue: [self waitForReply: 6 for: self defaultTimeOutDuration].\\n\\t(response at: 4) = self qualifiedHostNameCode\\n\\t\\tifTrue: [self skipQualifiedHostName].\\n\\t(response at: 4) = self hostIP6Code\\n\\t\\tifTrue: [self waitForReply: 18 for: self defaultTimeOutDuration].\\n\\t(response at: 2) ~= 0\\n\\t\\tifTrue: [^self socksError: 'Connection failed: ', (response at: 2) printString].\\n! !\\n\\n\\n!SocksSocket methodsFor: 'private' stamp: 'mir 3/6/2000 13:34'!\\nconnectCommandCode\\n\\t^1! !\\n\\n!SocksSocket methodsFor: 'private' stamp: 'mir 3/6/2000 15:07'!\\ndefaultTimeOutDuration\\n\\t^20000! !\\n\\n!SocksSocket methodsFor: 'private' stamp: 'mir 3/6/2000 15:29'!\\ndstIP\\n\\t^dstIP! !\\n\\n!SocksSocket methodsFor: 'private' stamp: 'mir 2/22/2002 16:23'!\\ndstPort\\n\\t^dstPort! !\\n\\n!SocksSocket methodsFor: 'private' stamp: 'mir 3/6/2000 14:03'!\\nrequestGrantedCode\\n\\t^90! !\\n\\n!SocksSocket methodsFor: 'private' stamp: 'mir 9/26/2000 11:23'!\\nshouldUseSocks\\n\\t^vers notNil! !\\n\\n!SocksSocket methodsFor: 'private' stamp: 'mir 3/6/2000 15:11'!\\nsocksError: errorString\\n\\tself close; destroy.\\n\\tself error: errorString! !\\n\\n!SocksSocket methodsFor: 'private' stamp: 'len 12/14/2002 11:39'!\\nwaitForReply: replySize for: timeOutDuration\\n\\t| startTime response delay bytesRead |\\n\\tstartTime _ Time millisecondClockValue.\\n\\tresponse _ ByteArray new: replySize.\\n\\tbytesRead _ 0.\\n\\tdelay _ Delay forMilliseconds: 500.\\n\\t[bytesRead < replySize\\n\\t\\tand: [(Time millisecondClockValue - startTime) < timeOutDuration]] whileTrue: [\\n\\t\\tbytesRead _ bytesRead + (self receiveDataInto: response).\\n\\t\\tdelay wait.\\n\\t\\tTranscript show: '.'].\\n\\tbytesRead < replySize\\n\\t\\tifTrue: [self close; destroy.\\n\\t\\t\\t\\t^ (ConnectionRefused host: self dstIP port: self dstPort) signal].\\n\\t^response! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSocksSocket class\\n\\tinstanceVariableNames: ''!\\n\\n!SocksSocket class methodsFor: 'accessing' stamp: 'nk 7/6/2003 07:30'!\\ndefaultSocksHostAddress\\n\\n\\t^NetNameResolver addressForName: HTTPSocket httpProxyServer! !\\n\\n!SocksSocket class methodsFor: 'accessing' stamp: 'nk 7/6/2003 07:30'!\\ndefaultSocksPort\\n\\t^HTTPSocket httpProxyPort! !\\n\\n!SocksSocket class methodsFor: 'accessing' stamp: 'mir 9/26/2000 00:06'!\\ndefaultSocksVersion\\n\\t\\\"nil means no socks\\\"\\n\\t^DefaultSocksVersion! !\\n\\n!SocksSocket class methodsFor: 'accessing' stamp: 'mir 9/26/2000 00:07'!\\ndefaultSocksVersion: anInteger\\n\\t\\\"nil means no socks\\\"\\n\\tDefaultSocksVersion _ anInteger! !\\nFillStyle subclass: #SolidFillStyle\\n\\tinstanceVariableNames: 'color pixelValue32'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Balloon-Fills'!\\n!SolidFillStyle commentStamp: '<historical>' prior: 0!\\nSolidFillStyle is a fill which represents a color for the BalloonEngine.\\n\\nInstance variables:\\n\\tcolor\\t<Color>\\tThe color to use.\\n\\tpixelValue32 <Integer>\\tThe cached pixel value to use.!\\n\\n\\n!SolidFillStyle methodsFor: 'accessing' stamp: 'ar 1/14/1999 15:24'!\\ncolor: aColor\\n\\tcolor := aColor.\\n\\tpixelValue32 := aColor scaledPixelValue32! !\\n\\n!SolidFillStyle methodsFor: 'accessing' stamp: 'ar 11/9/1998 03:29'!\\ndisplay\\n\\t^color display! !\\n\\n!SolidFillStyle methodsFor: 'accessing' stamp: 'ar 1/14/1999 15:25'!\\nscaledPixelValue32\\n\\t\\\"Return the alpha scaled pixel value for depth 32\\\"\\n\\t^pixelValue32! !\\n\\n\\n!SolidFillStyle methodsFor: 'converting' stamp: 'ar 11/9/1998 13:55'!\\nasColor\\n\\t^color! !\\n\\n\\n!SolidFillStyle methodsFor: 'printing' stamp: 'ar 11/17/1998 00:29'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream nextPut:$(; print: color; nextPut:$).! !\\n\\n\\n!SolidFillStyle methodsFor: 'testing' stamp: 'ar 11/8/1998 18:34'!\\nisSolidFill\\n\\t^true! !\\n\\n!SolidFillStyle methodsFor: 'testing' stamp: 'ar 9/2/1999 14:30'!\\nisTranslucent\\n\\t^color isTranslucent! !\\n\\n!SolidFillStyle methodsFor: 'testing' stamp: 'ar 10/26/2000 19:25'!\\nisTransparent\\n\\t^color isTransparent! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSolidFillStyle class\\n\\tinstanceVariableNames: ''!\\n\\n!SolidFillStyle class methodsFor: 'instance creation' stamp: 'ar 11/8/1998 18:31'!\\ncolor: aColor\\n\\t^self new color: aColor! !\\nImageMorph subclass: #Sonogram\\n\\tinstanceVariableNames: 'lastX scrollDelta columnForm minVal maxVal pixValMap'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n!Sonogram commentStamp: '<historical>' prior: 0!\\nSonograms are imageMorphs that will repeatedly plot arrays of values as black on white columns moving to the right in time and scrolling left as necessary.!\\n\\n\\n!Sonogram methodsFor: 'all' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nextent: extent minVal: min maxVal: max scrollDelta: d\\n\\tminVal := min.\\n\\tmaxVal := max.\\n\\tscrollDelta := d.\\n\\tself extent: extent.\\n\\n\\\" try following with scrolldelta = 1, 20, 200\\n\\t| s data |\\n\\ts := Sonogram new extent: 200@50\\n\\t\\t\\t\\tminVal: 0.0 maxVal: 1.0 scrollDelta: 20.\\n\\tWorld addMorph: s.\\n\\tdata := (1 to: 133) collect: [:i | 0.0].\\n\\t1 to: 300 do:\\n\\t\\t[:i | data at: (i\\\\\\\\133)+1 put: 1.0.\\n\\t\\ts plotColumn: data.\\n\\t\\tdata at: (i\\\\\\\\133)+1 put: 0.0.\\n\\t\\tWorld doOneCycleNow].\\n\\ts delete\\t\\n\\\"! !\\n\\n!Sonogram methodsFor: 'all' stamp: 'jdl 3/28/2003 09:30'!\\nplotColumn: dataArray \\n\\t| chm1 i normVal r |\\n\\tcolumnForm unhibernate.\\n\\tchm1 := columnForm height - 1.\\n\\t0 to: chm1\\n\\t\\tdo: \\n\\t\\t\\t[:y | \\n\\t\\t\\ti := y * (dataArray size - 1) // chm1 + 1.\\n\\t\\t\\tnormVal := ((dataArray at: i) - minVal) / (maxVal - minVal).\\n\\t\\t\\tnormVal := normVal max: 0.0.\\n\\t\\t\\tnormVal := normVal min: 1.0.\\n\\t\\t\\tcolumnForm bits at: chm1 - y + 1\\n\\t\\t\\t\\tput: (pixValMap at: (normVal * 255.0) truncated + 1)].\\n\\t(lastX := lastX + 1) > (image width - 1) ifTrue: [self scroll].\\n\\timage \\n\\t\\tcopy: (r := lastX @ 0 extent: 1 @ image height)\\n\\t\\tfrom: (32 // image depth - 1) @ 0\\n\\t\\tin: columnForm\\n\\t\\trule: Form over.\\n\\t\\\"self changed.\\\"\\n\\tself invalidRect: (r translateBy: self position)! !\\n\\n!Sonogram methodsFor: 'all' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nscroll\\n\\timage copy: (scrollDelta@0 extent: (image width-scrollDelta)@image height)\\n\\t\\t\\tfrom: image to: 0@0 rule: Form over.\\n\\tlastX := lastX - scrollDelta.\\n\\tself changed! !\\n\\n\\n!Sonogram methodsFor: 'geometry' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nextent: newExtent\\n\\tsuper image: (Form extent: newExtent depth: Display depth).\\n\\tlastX := -1.\\n\\tcolumnForm := Form extent: (32//image depth)@(image height) depth: image depth.\\n\\tpixValMap := ((1 to: 256) collect:\\n\\t\\t\\t[:i | columnForm pixelValueFor: (Color gray: (256-i)/255.0)])\\n\\t\\tas: Bitmap.\\n! !\\nOrderedCollection subclass: #SortedCollection\\n\\tinstanceVariableNames: 'sortBlock'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Collections-Sequenceable'!\\n!SortedCollection commentStamp: '<historical>' prior: 0!\\nI represent a collection of objects ordered by some property of the objects themselves. The ordering is specified in a BlockContext.!\\n\\n\\n!SortedCollection methodsFor: 'accessing' stamp: 'sma 4/28/2000 17:47'!\\nat: anInteger put: anObject\\n\\tself shouldNotImplement! !\\n\\n!SortedCollection methodsFor: 'accessing' stamp: 'tk 3/28/1999 22:55'!\\nmedian\\n\\t\\\"Return the middle element, or as close as we can get.\\\"\\n\\n\\t^ self at: self size + 1 // 2! !\\n\\n!SortedCollection methodsFor: 'accessing'!\\nsortBlock\\n\\t\\\"Answer the blockContext which is the criterion for sorting elements of \\n\\tthe receiver.\\\"\\n\\n\\t^sortBlock! !\\n\\n!SortedCollection methodsFor: 'accessing' stamp: 'stp 12/05/1999 07:09'!\\nsortBlock: aBlock \\n\\t\\\"Make the argument, aBlock, be the criterion for ordering elements of the \\n\\treceiver.\\\"\\n\\n\\taBlock\\n\\t\\tifNotNil: [sortBlock := aBlock fixTemps]\\n\\t\\tifNil: [sortBlock := aBlock].\\n\\t\\\"The sortBlock must copy its home context, so as to avoid circularities!!\\\"\\n\\t\\\"Therefore sortBlocks with side effects may not work right\\\"\\n\\tself size > 0 ifTrue: [self reSort]! !\\n\\n\\n!SortedCollection methodsFor: 'adding' stamp: 'go 4/27/2000 13:19'!\\nadd: newObject\\n\\t^ super insert: newObject before: (self indexForInserting: newObject)! !\\n\\n!SortedCollection methodsFor: 'adding' stamp: 'sma 4/28/2000 18:35'!\\naddAll: aCollection\\n\\taCollection size > (self size // 3)\\n\\t\\tifTrue:\\n\\t\\t\\t[aCollection do: [:each | self addLast: each].\\n\\t\\t\\tself reSort]\\n\\t\\tifFalse: [aCollection do: [:each | self add: each]].\\n\\t^ aCollection! !\\n\\n!SortedCollection methodsFor: 'adding' stamp: 'go 4/26/2000 17:26'!\\naddFirst: newObject\\n\\tself shouldNotImplement! !\\n\\n!SortedCollection methodsFor: 'adding' stamp: 'MPH 10/23/2000 13:31'!\\ncopyEmpty\\n\\t\\\"Answer a copy of the receiver without any of the receiver's elements.\\\"\\n\\n\\t^self species sortBlock: sortBlock! !\\n\\n\\n!SortedCollection methodsFor: 'comparing'!\\n= aSortedCollection\\n\\t\\\"Answer true if my and aSortedCollection's species are the same,\\n\\tand if our blocks are the same, and if our elements are the same.\\\"\\n\\n\\tself species = aSortedCollection species ifFalse: [^ false].\\n\\tsortBlock = aSortedCollection sortBlock\\n\\t\\tifTrue: [^ super = aSortedCollection]\\n\\t\\tifFalse: [^ false]! !\\n\\n\\n!SortedCollection methodsFor: 'copying'!\\ncopy\\n\\n\\t| newCollection |\\n\\tnewCollection _ self species sortBlock: sortBlock.\\n\\tnewCollection addAll: self.\\n\\t^newCollection! !\\n\\n\\n!SortedCollection methodsFor: 'enumerating' stamp: 'sma 2/5/2000 15:22'!\\ncollect: aBlock \\n\\t\\\"Evaluate aBlock with each of my elements as the argument. Collect the \\n\\tresulting values into an OrderedCollection. Answer the new collection. \\n\\tOverride the superclass in order to produce an OrderedCollection instead\\n\\tof a SortedCollection.\\\"\\n\\n\\t| newCollection | \\n\\tnewCollection _ OrderedCollection new: self size.\\n\\tself do: [:each | newCollection addLast: (aBlock value: each)].\\n\\t^ newCollection! !\\n\\n\\n!SortedCollection methodsFor: 'topological sort' stamp: 'hg 1/2/2002 13:34'!\\nsortTopologically\\n\\t\\\"Plenty of room for increased efficiency in this one.\\\"\\n\\n\\t| remaining result pick |\\n\\tremaining _ self asOrderedCollection.\\n\\tresult _ OrderedCollection new.\\n\\t[remaining isEmpty] whileFalse: [\\n\\t\\tpick _ remaining select: [:item |\\n\\t\\t\\tremaining allSatisfy: [:anotherItem |\\n\\t\\t\\t\\titem == anotherItem or: [self should: item precede: anotherItem]]].\\n\\t\\tpick isEmpty ifTrue: [self error: 'bad topological ordering'].\\n\\t\\tresult addAll: pick.\\n\\t\\tremaining removeAll: pick].\\n\\t^self copySameFrom: result! !\\n\\n\\n!SortedCollection methodsFor: 'private' stamp: 'stp 04/23/1999 05:36'!\\nindexForInserting: newObject\\n\\n\\t| index low high |\\n\\tlow _ firstIndex.\\n\\thigh _ lastIndex.\\n\\tsortBlock isNil\\n\\t\\tifTrue: [[index _ high + low // 2. low > high]\\n\\t\\t\\twhileFalse: \\n\\t\\t\\t\\t[((array at: index) <= newObject)\\n\\t\\t\\t\\t\\tifTrue: [low _ index + 1]\\n\\t\\t\\t\\t\\tifFalse: [high _ index - 1]]]\\n\\t\\tifFalse: [[index _ high + low // 2. low > high]\\n\\t\\t\\twhileFalse: \\n\\t\\t\\t\\t[(sortBlock value: (array at: index) value: newObject)\\n\\t\\t\\t\\t\\tifTrue: [low _ index + 1]\\n\\t\\t\\t\\t\\tifFalse: [high _ index - 1]]].\\n\\t^low! !\\n\\n!SortedCollection methodsFor: 'private' stamp: 'go 4/26/2000 17:17'!\\ninsert: anObject before: spot\\n\\tself shouldNotImplement! !\\n\\n!SortedCollection methodsFor: 'private' stamp: 'sma 4/28/2000 17:46'!\\nreSort\\n\\tself sort: firstIndex to: lastIndex! !\\n\\n!SortedCollection methodsFor: 'private' stamp: 'hg 12/17/2001 19:30'!\\nshould: a precede: b\\n\\n\\t^sortBlock ifNil: [a <= b] ifNotNil: [sortBlock value: a value: b]\\n! !\\n\\n!SortedCollection methodsFor: 'private' stamp: 'hg 12/17/2001 20:22'!\\nsort: i to: j \\n\\t\\\"Sort elements i through j of self to be nondescending according to\\n\\tsortBlock.\\\"\\n\\n\\t| di dij dj tt ij k l n |\\n\\t\\\"The prefix d means the data at that index.\\\"\\n\\t(n _ j + 1 - i) <= 1 ifTrue: [^self].\\t\\\"Nothing to sort.\\\" \\n\\t \\\"Sort di,dj.\\\"\\n\\tdi _ array at: i.\\n\\tdj _ array at: j.\\n\\t(self should: di precede: dj)\\n\\t\\tifFalse: \\n\\t\\t\\t[array swap: i with: j.\\n\\t\\t\\t tt _ di.\\n\\t\\t\\t di _ dj.\\n\\t\\t\\t dj _ tt].\\n\\tn > 2\\n\\t\\tifTrue: \\\"More than two elements.\\\"\\n\\t\\t\\t[ij _ (i + j) // 2. \\\"ij is the midpoint of i and j.\\\"\\n\\t\\t\\t dij _ array at: ij. \\\"Sort di,dij,dj. Make dij be their median.\\\"\\n\\t\\t\\t (self should: di precede: dij)\\n\\t\\t\\t ifTrue: \\n\\t\\t\\t\\t[(self should: dij precede: dj)\\n\\t\\t\\t\\t ifFalse: \\n\\t\\t\\t\\t\\t[array swap: j with: ij.\\n\\t\\t\\t\\t\\t dij _ dj]]\\n\\t\\t\\t ifFalse:\\n\\t\\t\\t\\t[array swap: i with: ij.\\n\\t\\t\\t\\t dij _ di].\\n\\t\\t\\tn > 3\\n\\t\\t\\t ifTrue: \\\"More than three elements.\\\"\\n\\t\\t\\t\\t[\\\"Find k>i and l<j such that dk,dij,dl are in reverse order.\\n\\t\\t\\t\\tSwap k and l. Repeat this procedure until k and l pass each other.\\\"\\n\\t\\t\\t\\t k _ i.\\n\\t\\t\\t\\t l _ j.\\n\\t\\t\\t\\t [[l _ l - 1. k <= l and: [self should: dij precede: (array at: l)]]\\n\\t\\t\\t\\t whileTrue. \\\"i.e. while dl succeeds dij\\\"\\n\\t\\t\\t\\t [k _ k + 1. k <= l and: [self should: (array at: k) precede: dij]]\\n\\t\\t\\t\\t whileTrue. \\\"i.e. while dij succeeds dk\\\"\\n\\t\\t\\t\\t k <= l]\\n\\t\\t\\t\\t whileTrue:\\n\\t\\t\\t\\t\\t[array swap: k with: l]. \\n\\t\\\"Now l<k (either 1 or 2 less), and di through dl are all less than or equal to dk\\n\\tthrough dj. Sort those two segments.\\\"\\n\\t\\t\\t\\tself sort: i to: l.\\n\\t\\t\\t\\tself sort: k to: j]]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSortedCollection class\\n\\tinstanceVariableNames: ''!\\n\\n!SortedCollection class methodsFor: 'instance creation' stamp: 'stp 04/23/1999 05:34'!\\nnew: anInteger \\n\\t\\\"The default sorting function is a <= comparison on elements.\\\"\\n\\n\\t^(super new: anInteger) \\\"sortBlock: [:x :y | x <= y]\\\" \\t\\t\\\"nil sortBlock OK\\\"! !\\n\\n!SortedCollection class methodsFor: 'instance creation'!\\nsortBlock: aBlock \\n\\t\\\"Answer an instance of me such that its elements are sorted according to \\n\\tthe criterion specified in aBlock.\\\"\\n\\n\\t^(super new: 10) sortBlock: aBlock! !\\nTestCase subclass: #SortedCollectionTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'CollectionsTests-Unordered'!\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:27'!\\ntestAdd\\n\\t\\\"self run: #testAdd\\\"\\n\\t\\\"self debug: #testAdd\\\"\\n\\t\\n\\t| collection |\\n\\tcollection := #(10 9 8 7 5 4 4 2) asSortedCollection.\\n\\tself assert: collection first = 2.\\n\\tself assert: collection last = 10.\\n\\tself assert: (collection size = 8).\\n\\tcollection add:1.\\n\\tself assert: (collection size = 9).\\n\\tcollection add: 6.\\n\\tself assert: ((collection at: 5) = 5).\\n\\tself assert: (collection size = 10).\\n\\tcollection add: 3.\\n\\t! !\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:30'!\\ntestAddAll\\n\\t\\\"self run: #testAddAll\\\"\\n\\t\\\"self debug: #testAddAll\\\"\\n\\t\\n\\t| sorted2 sorted|\\n\\tsorted2 := SortedCollection new.\\n\\tsorted2 add: 'brochet'; add:'truitelle'.\\n\\tsorted := SortedCollection new.\\n\\tsorted addAll: sorted2.\\n\\tself assert: (sorted hasEqualElements: sorted2).\\n\\t ! !\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:32'!\\ntestAddAll2\\n\\t\\\"self run: #testAddAll2\\\"\\n\\t\\\"self debug: #testAddAll2\\\"\\n\\t\\n\\t| sorted2 sorted|\\n\\tsorted2 := SortedCollection new.\\n\\tsorted2 add: 'brochet'; add:'truitelle'.\\n\\tsorted := SortedCollection new.\\n\\tsorted add: 'perche'.\\n\\tsorted addAll: sorted2.\\n\\tself assert: (sorted size = (sorted2 size + 1)).\\n\\tsorted2 do: \\n\\t\\t\\t[ :each | self assert: (sorted includes: each)]\\n\\t ! !\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:33'!\\ntestCollect\\n\\t\\\"self run: #testCollect\\\"\\n\\t\\n\\t|result aSortedCollection|\\n\\taSortedCollection := SortedCollection new.\\n\\tresult := OrderedCollection new.\\n\\tresult add:true ; add: true ; add: true ;add: false ; add: false.\\n\\taSortedCollection := (1 to: 5) asSortedCollection.\\n\\tself assert: (result = (aSortedCollection collect: [:each | each < 4])).\\n\\t! !\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:39'!\\ntestCopy\\n\\t\\\"self run: #testCopy\\\"\\n\\t\\\"self debug: #testCopy\\\"\\n\\t\\n\\t|aSortedCollection copySorted|\\n\\taSortedCollection := SortedCollection new.\\n\\taSortedCollection sortBlock: [:a :b | a < b].\\n\\taSortedCollection add: 'truite' ; add: 'brochet'.\\n\\tself assert: aSortedCollection first = 'brochet'.\\n\\t\\n\\tcopySorted := aSortedCollection copy.\\n\\t\\n\\tself assert: (copySorted hasEqualElements: aSortedCollection).\\n\\tself assert: (copySorted species = aSortedCollection species).\\n\\tself assert: (copySorted sortBlock = aSortedCollection sortBlock).\\n\\tself assert: copySorted first = 'brochet'.! !\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:30'!\\ntestCreation\\n\\t\\\"self run: #testCreation\\\"\\n\\t\\\"self debug: #testCreation\\\"\\n\\t\\n\\t| collection |\\n\\tcollection := #(10 9 3 6 1 8 7 5 4 2) asSortedCollection.\\n\\tself assert: collection = (1 to: 10) asSortedCollection.\\n\\t! !\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:42'!\\ntestEquals\\n\\t\\\"self run: #testEquals\\\"\\n\\t\\\"self debug: #testEquals\\\"\\n\\t\\n\\t|aSortedCollection|\\n\\taSortedCollection := SortedCollection new.\\n\\taSortedCollection add:'truite' ; add: 'brochet'.\\n\\tself assert: aSortedCollection copy = aSortedCollection.! !\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:43'!\\ntestMedian\\n\\t\\\"self run: #testMedian\\\"\\n\\t\\\"self debug: #testMedian\\\"\\n\\t\\n\\t|aSortedCollection|\\n\\taSortedCollection := (1 to: 10) asSortedCollection.\\n\\tself assert: aSortedCollection median=5.\\n\\t\\n\\taSortedCollection := SortedCollection new.\\n\\taSortedCollection add:'truite' ; add:'porcinet' ; add:'carpe'.\\n\\tself assert: (aSortedCollection median = 'porcinet').\\n\\t! !\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:46'!\\ntestShouldPrecede\\n\\t\\\"self run: #testShouldPrecede\\\"\\n\\t\\n\\t|aSortedCollection|\\n\\taSortedCollection := SortedCollection new.\\n\\tself assert: (aSortedCollection should: 'za' precede: 'zb').\\n\\tself assert: (aSortedCollection isEmpty).\\n\\tself assert: (aSortedCollection should: 1 precede: 2).\\n\\t\\n\\taSortedCollection sortBlock: [:a :b | a > b].\\n\\taSortedCollection reSort.\\n\\tself assert: (aSortedCollection should: 'zb' precede: 'za').\\n\\tself assert: (aSortedCollection isEmpty).\\n\\tself assert: (aSortedCollection should: 2 precede: 1).\\n\\t\\t! !\\n\\n!SortedCollectionTest methodsFor: 'basic' stamp: 'DM 3/16/2006 11:38'!\\ntestSortBlock\\n\\t\\\"self run: #testSortBlock\\\"\\n\\t\\\"self debug: #testSortBlock\\\"\\n\\t\\n\\t|aSortedCollection|\\n\\taSortedCollection := SortedCollection new.\\n\\taSortedCollection sortBlock: [:a :b | a < b].\\n\\taSortedCollection add: 'truite' ; add: 'brochet' ; add: 'tortue'.\\n\\tself assert: aSortedCollection first = 'brochet'.\\n\\t\\n\\taSortedCollection := SortedCollection new.\\n\\taSortedCollection sortBlock: [:a :b | a >b].\\n\\taSortedCollection add: 'truite' ; add: 'brochet' ; add: 'tortue'.\\n\\tself assert: aSortedCollection first = 'truite'.\\n\\t\\n\\t\\n\\t! !\\nBorderedMorph subclass: #SorterTokenMorph\\n\\tinstanceVariableNames: 'morphRepresented'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Palettes'!\\n\\n!SorterTokenMorph methodsFor: 'as yet unclassified' stamp: 'sw 12/1/1998 12:38'!\\nfitContents\\n\\tsubmorphs size == 1 ifTrue: [self bounds: (submorphs first bounds insetBy: (-1 @ -1))]! !\\n\\n!SorterTokenMorph methodsFor: 'as yet unclassified' stamp: 'dgd 2/21/2003 23:16'!\\nforMorph: aMorph \\n\\t| it |\\n\\tmorphRepresented := aMorph.\\n\\taMorph submorphs notEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[self addMorphBack: (it := aMorph submorphs first veryDeepCopy).\\n\\t\\t\\tit position: self position + (1 @ 1).\\n\\t\\t\\tit lock].\\n\\tself fitContents! !\\n\\n\\n!SorterTokenMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:35'!\\ndefaultBorderColor\\n\\t\\\"answer the default border color/fill style for the receiver\\\"\\n\\t^ Color blue! !\\n\\n!SorterTokenMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:40'!\\ndefaultBorderWidth\\n\\t\\\"answer the default border width for the receiver\\\"\\n\\t^ 1! !\\n\\n!SorterTokenMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:31'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color transparent! !\\n\\n\\n!SorterTokenMorph methodsFor: 'thumbnail' stamp: 'sw 12/1/1998 12:27'!\\nmorphRepresented\\n\\t^ morphRepresented! !\\nArrayedCollection variableWordSubclass: #SoundBuffer\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'SineTable'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n!SoundBuffer commentStamp: '<historical>' prior: 0!\\nSoundBuffers store 16 bit unsigned quantities. !\\n\\n\\n!SoundBuffer methodsFor: 'accessing' stamp: 'tk 3/13/2000 14:46'!\\nbytesPerElement\\n\\t\\\"Number of bytes in each item. This multiplied by (self size)*8 gives the number of bits stored.\\\"\\n\\t^ 2! !\\n\\n!SoundBuffer methodsFor: 'accessing' stamp: 'jm 9/17/97 13:00'!\\nmonoSampleCount\\n\\t\\\"Return the number of monaural 16-bit samples that fit into this SoundBuffer.\\\"\\n\\n\\t^ super size * 2\\n! !\\n\\n!SoundBuffer methodsFor: 'accessing' stamp: 'jm 9/17/97 13:28'!\\nsize\\n\\t\\\"Return the number of 16-bit sound samples that fit in this sound buffer. To avoid confusion, it is better to get the size of SoundBuffer using monoSampleCount or stereoSampleCount.\\\"\\n\\n\\t^ self monoSampleCount\\n! !\\n\\n!SoundBuffer methodsFor: 'accessing' stamp: 'jm 9/17/97 13:01'!\\nstereoSampleCount\\n\\t\\\"Return the number of stereo slices that fit into this SoundBuffer. A stereo 'slice' consists of two 16-bit samples, one for each channel.\\\"\\n\\n\\t^ super size\\n! !\\n\\n\\n!SoundBuffer methodsFor: 'as yet unclassified' stamp: 'RAA 7/11/2000 11:31'!\\nwriteOnGZIPByteStream: aStream \\n\\t\\n\\taStream nextPutAllWordArray: self! !\\n\\n\\n!SoundBuffer methodsFor: 'objects from disk' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nrestoreEndianness\\n\\t\\\"This word object was just read in from a stream. It was stored in Big Endian (Mac) format. Swap each pair of bytes (16-bit word), if the current machine is Little Endian.\\n\\tWhy is this the right thing to do? We are using memory as a byteStream. High and low bytes are reversed in each 16-bit word, but the stream of words ascends through memory. Different from a Bitmap.\\\"\\n\\n\\t| hack blt |\\n\\tSmalltalkImage current isLittleEndian ifTrue: [\\n\\t\\t\\\"The implementation is a hack, but fast for large ranges\\\"\\n\\t\\thack := Form new hackBits: self.\\n\\t\\tblt := (BitBlt toForm: hack) sourceForm: hack.\\n\\t\\tblt combinationRule: Form reverse. \\\"XOR\\\"\\n\\t\\tblt sourceY: 0; destY: 0; height: self size; width: 1.\\n\\t\\tblt sourceX: 0; destX: 1; copyBits. \\\"Exchange bytes 0 and 1\\\"\\n\\t\\tblt sourceX: 1; destX: 0; copyBits.\\n\\t\\tblt sourceX: 0; destX: 1; copyBits.\\n\\t\\tblt sourceX: 2; destX: 3; copyBits. \\\"Exchange bytes 2 and 3\\\"\\n\\t\\tblt sourceX: 3; destX: 2; copyBits.\\n\\t\\tblt sourceX: 2; destX: 3; copyBits].\\n\\n! !\\n\\n!SoundBuffer methodsFor: 'objects from disk' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nreverseEndianness\\n\\t\\\"Swap the bytes of each 16-bit word, using a fast BitBlt hack.\\\"\\n\\n\\t| hack blt |\\n\\thack := Form new hackBits: self.\\n\\tblt := (BitBlt toForm: hack) sourceForm: hack.\\n\\tblt combinationRule: Form reverse. \\\"XOR\\\"\\n\\tblt sourceY: 0; destY: 0; height: self size; width: 1.\\n\\tblt sourceX: 0; destX: 1; copyBits. \\\"Exchange bytes 0 and 1\\\"\\n\\tblt sourceX: 1; destX: 0; copyBits.\\n\\tblt sourceX: 0; destX: 1; copyBits.\\n\\tblt sourceX: 2; destX: 3; copyBits. \\\"Exchange bytes 2 and 3\\\"\\n\\tblt sourceX: 3; destX: 2; copyBits.\\n\\tblt sourceX: 2; destX: 3; copyBits.\\n! !\\n\\n\\n!SoundBuffer methodsFor: 'primitives' stamp: 'jm 9/17/97 13:03'!\\nat: index\\n\\t\\\"Return the 16-bit integer value at the given index of the receiver.\\\"\\n\\n\\t<primitive: 143>\\n\\tindex isInteger ifTrue: [self errorSubscriptBounds: index].\\n\\tindex isNumber ifTrue: [^ self at: index truncated].\\n\\tself errorNonIntegerIndex.\\n! !\\n\\n!SoundBuffer methodsFor: 'primitives' stamp: 'jm 9/17/97 13:03'!\\nat: index put: value\\n\\t\\\"Store the given 16-bit integer at the given index in the receiver.\\\"\\n\\n\\t<primitive: 144>\\n\\tindex isInteger\\n\\t\\tifTrue: [\\n\\t\\t\\t(index >= 1 and: [index <= self size])\\n\\t\\t\\t\\tifTrue: [self errorImproperStore]\\n\\t\\t\\t\\tifFalse: [self errorSubscriptBounds: index]].\\n\\tindex isNumber ifTrue: [^ self at: index truncated put: value].\\n\\tself errorNonIntegerIndex.\\n! !\\n\\n!SoundBuffer methodsFor: 'primitives' stamp: 'jm 9/2/97 16:07'!\\nprimFill: aPositiveInteger\\n\\t\\\"Fill the receiver, an indexable bytes or words object, with the given positive integer. The range of possible fill values is [0..255] for byte arrays and [0..(2^32 - 1)] for word arrays.\\\"\\n\\t\\\"Note: Since 16-bit word arrays are not built into the virtual machine, this primitive fills by 32-bit words.\\\"\\n\\n\\t<primitive: 145>\\n\\tself errorImproperStore.\\n! !\\n\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nasByteArray\\n\\t\\\"Answer a ByteArray containing my sample data serialized in most-significant byte first order.\\\"\\n\\n\\t| sampleCount bytes dst s |\\n\\tsampleCount := self monoSampleCount.\\n\\tbytes := ByteArray new: 2 * sampleCount.\\n\\tdst := 0.\\n\\t1 to: sampleCount do: [:src |\\n\\t\\ts := self at: src.\\n\\t\\tbytes at: (dst := dst + 1) put: ((s bitShift: -8) bitAnd: 255).\\n\\t\\tbytes at: (dst := dst + 1) put: (s bitAnd: 255)].\\n\\t^ bytes\\n\\n\\t! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\naverageEvery: nSamples from: anotherBuffer upTo: inCount\\n\\n\\t| fromIndex sum |\\n\\n\\tfromIndex := 1.\\n\\t1 to: inCount // nSamples do: [ :i |\\n\\t\\tsum := 0.\\n\\t\\tnSamples timesRepeat: [\\n\\t\\t\\tsum := sum + (anotherBuffer at: fromIndex).\\n\\t\\t\\tfromIndex := fromIndex + 1.\\n\\t\\t].\\n\\t\\tself at: i put: sum // nSamples.\\n\\t].\\n! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ndownSampledLowPassFiltering: doFiltering\\n\\t\\\"Answer a new SoundBuffer half the size of the receiver consisting of every other sample. If doFiltering is true, a simple low-pass filter is applied to avoid aliasing of high frequencies. Assume that receiver is monophonic.\\\"\\n\\t\\\"Details: The simple low-pass filter in the current implementation could be improved, at some additional cost.\\\"\\n\\n\\t| n resultBuf j |\\n\\tn := self monoSampleCount.\\n\\tresultBuf := SoundBuffer newMonoSampleCount: n // 2.\\n\\tj := 0.\\n\\tdoFiltering\\n\\t\\tifTrue: [\\n\\t\\t\\t1 to: n by: 2 do: [:i |\\n\\t\\t\\t\\tresultBuf at: (j := j + 1) put:\\n\\t\\t\\t\\t\\t(((self at: i) + (self at: i + 1)) bitShift: -1)]]\\n\\t\\tifFalse: [\\n\\t\\t\\t1 to: n by: 2 do: [:i |\\n\\t\\t\\t\\tresultBuf at: (j := j + 1) put: (self at: i)]].\\n\\n\\t^ resultBuf! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nextractLeftChannel\\n\\t\\\"Answer a new SoundBuffer half the size of the receiver consisting of only the left channel of the receiver, which is assumed to contain stereo sound data.\\\"\\n\\n\\t| n resultBuf j |\\n\\tn := self monoSampleCount.\\n\\tresultBuf := SoundBuffer newMonoSampleCount: n // 2.\\n\\tj := 0.\\n\\t1 to: n by: 2 do: [:i | resultBuf at: (j := j + 1) put: (self at: i)].\\n\\t^ resultBuf! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nextractRightChannel\\n\\t\\\"Answer a new SoundBuffer half the size of the receiver consisting of only the right channel of the receiver, which is assumed to contain stereo sound data.\\\"\\n\\n\\t| n resultBuf j |\\n\\tn := self monoSampleCount.\\n\\tresultBuf := SoundBuffer newMonoSampleCount: n // 2.\\n\\tj := 0.\\n\\t2 to: n by: 2 do: [:i | resultBuf at: (j := j + 1) put: (self at: i)].\\n\\t^ resultBuf! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'jhm 10/15/97 15:13'!\\nindexOfFirstSampleOver: threshold\\n\\t\\\"Return the index of the first sample whose absolute value is over the given threshold value. Return an index one greater than my size if no sample is over the threshold.\\\"\\n\\n\\t1 to: self size do: [:i |\\n\\t\\t(self at: i) abs > threshold ifTrue: [^ i]].\\n\\t^ self size + 1! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'jhm 10/15/97 15:13'!\\nindexOfLastSampleOver: threshold\\n\\t\\\"Return the index of the last sample whose absolute value is over the given threshold value. Return zero if no sample is over the threshold.\\\"\\n\\n\\tself size to: 1 by: -1 do: [:i |\\n\\t\\t(self at: i) abs > threshold ifTrue: [^ i]].\\n\\t^ 0\\n! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nlowPassFiltered\\n\\t\\\"Answer a simple low-pass filtered copy of this buffer. Assume it is monophonic.\\\"\\n\\n\\t| sz out last this |\\n\\tsz := self monoSampleCount.\\n\\tout := self clone.\\n\\tlast := self at: 1.\\n\\t2 to: sz do: [:i |\\n\\t\\tthis := self at: i.\\n\\t\\tout at: i put: (this + last) // 2.\\n\\t\\tlast := this].\\n\\t^ out\\n! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nmergeStereo\\n\\t\\\"Answer a new SoundBuffer half the size of the receiver that mixes the left and right stereo channels of the receiver, which is assumed to contain stereo sound data.\\\"\\n\\n\\t| n resultBuf j |\\n\\tn := self monoSampleCount.\\n\\tresultBuf := SoundBuffer newMonoSampleCount: n // 2.\\n\\tj := 0.\\n\\t1 to: n by: 2 do: [:i | resultBuf at: (j := j + 1) put: (((self at: i) + (self at: i + 1)) // 2)].\\n\\t^ resultBuf\\n! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nnormalized: percentOfFullVolume\\n\\t\\\"Increase my amplitudes so that the highest peak is the given percent of full volume. For example 's normalized: 50' would normalize to half of full volume.\\\"\\n\\n\\t| peak s mult |\\n\\tpeak := 0.\\n\\t1 to: self size do: [:i |\\n\\t\\ts := (self at: i) abs.\\n\\t\\ts > peak ifTrue: [peak := s]].\\n\\tmult := (32767.0 * percentOfFullVolume) / (100.0 * peak).\\n\\t1 to: self size do: [:i | self at: i put: (mult * (self at: i)) asInteger].\\n! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsaveAsAIFFFileSamplingRate: rate on: aBinaryStream\\n\\t\\\"Store this mono sound buffer in AIFF file format with the given sampling rate on the given stream.\\\"\\n\\n\\t| sampleCount s swapBytes |\\n\\tsampleCount := self monoSampleCount.\\n\\taBinaryStream nextPutAll: 'FORM' asByteArray.\\n\\taBinaryStream nextInt32Put: (2 * sampleCount) + ((7 * 4) + 18).\\n\\taBinaryStream nextPutAll: 'AIFF' asByteArray.\\n\\taBinaryStream nextPutAll: 'COMM' asByteArray.\\n\\taBinaryStream nextInt32Put: 18.\\n\\taBinaryStream nextNumber: 2 put: 1. \\\"channels\\\"\\n\\taBinaryStream nextInt32Put: sampleCount.\\n\\taBinaryStream nextNumber: 2 put: 16. \\\"bits/sample\\\"\\n\\tself storeExtendedFloat: rate on: aBinaryStream.\\n\\taBinaryStream nextPutAll: 'SSND' asByteArray.\\n\\taBinaryStream nextInt32Put: (2 * sampleCount) + 8.\\n\\taBinaryStream nextInt32Put: 0.\\n\\taBinaryStream nextInt32Put: 0.\\n\\n\\t(aBinaryStream isKindOf: StandardFileStream) ifTrue: [\\n\\t\\t\\\"optimization: write sound buffer directly to file\\\"\\n\\t\\tswapBytes := SmalltalkImage current isLittleEndian.\\n\\t\\tswapBytes ifTrue: [self reverseEndianness]. \\\"make big endian\\\"\\n\\t\\taBinaryStream next: (self size // 2) putAll: self startingAt: 1. \\\"size in words\\\"\\n\\t\\tswapBytes ifTrue: [self reverseEndianness]. \\\"revert to little endian\\\"\\n\\t\\t^ self].\\n\\n\\t1 to: sampleCount do: [:i |\\n\\t\\ts := self at: i.\\n\\t\\taBinaryStream nextPut: ((s bitShift: -8) bitAnd: 16rFF).\\n\\t\\taBinaryStream nextPut: (s bitAnd: 16rFF)].\\n! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsplitStereo\\n\\t\\\"Answer an array of two SoundBuffers half the size of the receiver consisting of the left and right channels of the receiver (which is assumed to contain stereo sound data).\\\"\\n\\n\\t| n leftBuf rightBuf leftIndex rightIndex |\\n\\tn := self monoSampleCount.\\n\\tleftBuf := SoundBuffer newMonoSampleCount: n // 2.\\n\\trightBuf := SoundBuffer newMonoSampleCount: n // 2.\\n\\tleftIndex := rightIndex := 0.\\n\\t1 to: n by: 2 do: [:i |\\n\\t\\tleftBuf at: (leftIndex := leftIndex + 1) put: (self at: i).\\n\\t\\trightBuf at: (rightIndex := rightIndex + 1) put: (self at: i + 1)].\\n\\t^ Array with: leftBuf with: rightBuf\\n! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstoreExtendedFloat: aNumber on: aBinaryStream\\n\\t\\\"Store an Apple extended-precision 80-bit floating point number on the given stream.\\\"\\n\\t\\\"Details: I could not find the specification for this format, so constants were determined empirically based on assumption of 1-bit sign, 15-bit exponent, 64-bit mantissa. This format does not seem to have an implicit one before the mantissa as some float formats do.\\\"\\n\\n\\t| n isNeg exp mantissa |\\n\\tn := aNumber asFloat.\\n\\tisNeg := false.\\n\\tn < 0.0 ifTrue: [\\n\\t\\tn := 0.0 - n.\\n\\t\\tisNeg := true].\\n\\texp := (n log: 2.0) ceiling.\\n\\tmantissa := (n * (2 raisedTo: 64 - exp)) truncated.\\n\\texp := exp + 16r4000 - 2. \\\"not sure why the -2 is needed...\\\"\\n\\tisNeg ifTrue: [exp := exp bitOr: 16r8000]. \\\"set sign bit\\\"\\n\\taBinaryStream nextPut: ((exp bitShift: -8) bitAnd: 16rFF).\\n\\taBinaryStream nextPut: (exp bitAnd: 16rFF).\\n\\t8 to: 1 by: -1 do: [:i | aBinaryStream nextPut: (mantissa digitAt: i)].! !\\n\\n!SoundBuffer methodsFor: 'utilities' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ntrimmedThreshold: threshold\\n\\n\\t| start end |\\n\\tstart := self indexOfFirstSampleOver: threshold.\\n\\tend := self indexOfLastSampleOver: threshold.\\n\\tstart > end ifTrue: [^ SoundBuffer new].\\n\\tstart := (start - 200) max: 1.\\n\\tend := (end + 200) min: self size.\\n\\t^ self copyFrom: start to: end\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSoundBuffer class\\n\\tinstanceVariableNames: ''!\\n\\n!SoundBuffer class methodsFor: 'class initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitialize\\n\\t\\\"Build a sine wave table.\\\"\\n\\t\\\"SoundBuffer initialize\\\"\\n\\n\\t| tableSize radiansPerStep peak |\\n\\ttableSize := 4000.\\n\\tSineTable := self newMonoSampleCount: tableSize.\\n\\tradiansPerStep := (2.0 * Float pi) / tableSize asFloat.\\n\\tpeak := ((1 bitShift: 15) - 1) asFloat. \\\"range is +/- (2^15 - 1)\\\"\\n\\t1 to: tableSize do: [:i |\\n\\t\\tSineTable at: i put: (peak * (radiansPerStep * (i - 1)) sin) rounded].\\n! !\\n\\n!SoundBuffer class methodsFor: 'class initialization' stamp: 'ads 7/31/2003 11:13'!\\nsineTable\\n\\t\\\"Answer a SoundBuffer containing one complete cycle of a sine wave.\\\"\\n\\n\\t^ SineTable\\n! !\\n\\n\\n!SoundBuffer class methodsFor: 'instance creation' stamp: 'RAA 12/30/2000 18:20'!\\naverageEvery: nSamples from: anotherBuffer upTo: inCount\\n\\n\\t^(self newMonoSampleCount: inCount // nSamples)\\n\\t\\taverageEvery: nSamples \\n\\t\\tfrom: anotherBuffer \\n\\t\\tupTo: inCount! !\\n\\n!SoundBuffer class methodsFor: 'instance creation' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nfromArray: anArray\\n\\t\\\"Return a new SoundBuffer whose contents are copied from the given Array or ByteArray.\\\"\\n\\n\\t| new |\\n\\tnew := SoundBuffer newMonoSampleCount: anArray size.\\n\\t1 to: anArray size do: [:i | new at: i put: (anArray at: i)].\\n\\t^ new\\n! !\\n\\n!SoundBuffer class methodsFor: 'instance creation' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nfromByteArray: aByteArray\\n\\t\\\"Convert the given ByteArray (stored with the most significant byte first) into 16-bit sample buffer.\\\"\\n\\n\\t| n buf src w |\\n\\tn := aByteArray size // 2.\\n\\tbuf := SoundBuffer newMonoSampleCount: n.\\n\\tsrc := 1.\\n\\t1 to: n do: [:i |\\n\\t\\tw := ((aByteArray at: src) bitShift: 8) + (aByteArray at: src + 1).\\n\\t\\tw > 32767 ifTrue: [w := w - 65536].\\n\\t\\tbuf at: i put: w.\\n\\t\\tsrc := src + 2].\\n\\t^ buf\\n! !\\n\\n!SoundBuffer class methodsFor: 'instance creation' stamp: 'jm 9/17/97 13:25'!\\nnew: anInteger\\n\\t\\\"See the comment in newMonoSampleCount:. To avoid confusion, it is best to create new instances using newMonoSampleCount: or newStereoSampleCount:.\\\"\\n\\n\\t^ self newMonoSampleCount: anInteger\\n! !\\n\\n!SoundBuffer class methodsFor: 'instance creation' stamp: 'jm 9/17/97 12:44'!\\nnewMonoSampleCount: anInteger\\n\\t\\\"Return a SoundBuffer large enough to hold the given number of monaural samples (i.e., 16-bit words).\\\"\\n\\t\\\"Details: The size is rounded up to an even number, since the underlying representation is in terms of 32-bit words.\\\"\\n\\n\\t^ self basicNew: (anInteger + 1) // 2\\n! !\\n\\n!SoundBuffer class methodsFor: 'instance creation' stamp: 'jm 9/17/97 12:52'!\\nnewStereoSampleCount: anInteger\\n\\t\\\"Return a SoundBuffer large enough to hold the given number of stereo slices. A stereo 'slice' consists of two 16-bit samples, one for each channel.\\\"\\n\\n\\t^ self basicNew: anInteger\\n! !\\n\\n\\n!SoundBuffer class methodsFor: 'objects from disk' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstartUp\\n\\t\\\"Check if the word order has changed from the last save.\\\"\\n\\n\\t| la |\\n\\tla := ShortIntegerArray classPool at: #LastSaveOrder.\\n\\t((la at: 2) = 42 and: [(la at: 1) = 13]) \\n\\t\\tifTrue: [^self swapHalves]. \\\"Reverse the two 16-bit halves.\\\"\\n\\t\\t\\t\\t\\\"Another reversal happened automatically which reversed the bytes.\\\"\\n! !\\n\\n!SoundBuffer class methodsFor: 'objects from disk' stamp: 'nk 2/22/2005 15:29'!\\nstartUpFrom: anImageSegment \\n\\t\\\"In this case, do we need to swap word halves when reading this segment?\\\"\\n\\n\\t^SmalltalkImage current endianness ~~ anImageSegment endianness \\n\\t\\tifTrue: [Message selector: #swapHalves\\t\\\"will be run on each instance\\\"]\\n\\t\\tifFalse: [nil]! !\\nObject subclass: #SoundCodec\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n!SoundCodec commentStamp: '<historical>' prior: 0!\\nI am an abstract class that describes the protocol for sound codecs. Each codec (the name stems from \\\"COder/DECoder\\\") describes a particular algorithm for compressing and decompressing sound data. Most sound codecs are called 'lossy' because they lose information; the decompressed sound data is not exactly the same as the original data.\\n!\\n\\n\\n!SoundCodec methodsFor: 'compress/decompress' stamp: 'jm 2/2/1999 16:01'!\\ncompressAndDecompress: aSound\\n\\t\\\"Compress and decompress the given sound. Useful for testing.\\\"\\n\\t\\\"(MuLawCodec new compressAndDecompress: (SampledSound soundNamed: 'camera')) play\\\"\\n\\n\\t^ (self compressSound: aSound) asSound\\n! !\\n\\n!SoundCodec methodsFor: 'compress/decompress' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncompressSound: aSound\\n\\t\\\"Compress the entirety of the given sound with this codec. Answer a CompressedSoundData.\\\"\\n\\n\\t| compressed channels |\\n\\tcompressed := CompressedSoundData new\\n\\t\\tcodecName: self class name;\\n\\t\\tsoundClassName: aSound class name.\\n\\t(aSound isKindOf: SampledSound) ifTrue: [\\n\\t\\tchannels := Array new: 1.\\n\\t\\tchannels at: 1 put: (self encodeSoundBuffer: aSound samples).\\n\\t\\tcompressed\\n\\t\\t\\tchannels: channels;\\n\\t\\t\\tsamplingRate: aSound originalSamplingRate;\\n\\t\\t\\tfirstSample: 1;\\n\\t\\t\\tloopEnd: aSound samples size;\\n\\t\\t\\tloopLength: 0.0;\\n\\t\\t\\tperceivedPitch: 100.0;\\n\\t\\t\\tgain: aSound loudness.\\n\\t\\t^ compressed].\\n\\t(aSound isKindOf: LoopedSampledSound) ifTrue: [\\n\\t\\taSound isStereo\\n\\t\\t\\tifTrue: [\\n\\t\\t\\t\\tchannels := Array new: 2.\\n\\t\\t\\t\\tchannels at: 1 put: (self encodeSoundBuffer: aSound leftSamples).\\n\\t\\t\\t\\tchannels at: 2 put: (self encodeSoundBuffer: aSound rightSamples)]\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tchannels := Array new: 1.\\n\\t\\t\\t\\tchannels at: 1 put: (self encodeSoundBuffer: aSound leftSamples)].\\n\\t\\tcompressed\\n\\t\\t\\tchannels: channels;\\n\\t\\t\\tsamplingRate: aSound originalSamplingRate;\\n\\t\\t\\tfirstSample: aSound firstSample;\\n\\t\\t\\tloopEnd: aSound loopEnd;\\n\\t\\t\\tloopLength: aSound loopLength;\\n\\t\\t\\tperceivedPitch: aSound perceivedPitch;\\n\\t\\t\\tgain: aSound gain.\\n\\t\\t^ compressed].\\n\\tself error: 'you can only compress sampled sounds'.\\n! !\\n\\n!SoundCodec methodsFor: 'compress/decompress' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncompressSound: aSound atRate: desiredSampleRate\\n\\t\\\"Compress the entirety of the given sound with this codec. Answer a CompressedSoundData.\\\"\\n\\n\\t| compressed channels samples newRate ratio buffer |\\n\\n\\tcompressed := CompressedSoundData new\\n\\t\\tcodecName: self class name;\\n\\t\\tsoundClassName: aSound class name.\\n\\t(aSound isKindOf: SampledSound) ifTrue: [\\n\\t\\t(desiredSampleRate isNil or: \\n\\t\\t\\t\\t[(ratio := aSound originalSamplingRate // desiredSampleRate) <= 1]) ifTrue: [\\n\\t\\t\\tsamples := aSound samples.\\n\\t\\t\\tnewRate := aSound originalSamplingRate.\\n\\t\\t] ifFalse: [\\n\\t\\t\\tbuffer := aSound samples.\\n\\t\\t\\tsamples := SoundBuffer \\n\\t\\t\\t\\taverageEvery: ratio \\n\\t\\t\\t\\tfrom: buffer \\n\\t\\t\\t\\tupTo: buffer monoSampleCount.\\n\\t\\t\\tnewRate := aSound originalSamplingRate / ratio.\\n\\t\\t].\\n\\n\\t\\tchannels := Array new: 1.\\n\\t\\tchannels at: 1 put: (self encodeSoundBuffer: samples).\\n\\t\\tcompressed\\n\\t\\t\\tchannels: channels;\\n\\t\\t\\tsamplingRate: newRate;\\n\\t\\t\\tfirstSample: 1;\\n\\t\\t\\tloopEnd: samples size;\\n\\t\\t\\tloopLength: 0.0;\\n\\t\\t\\tperceivedPitch: 100.0;\\n\\t\\t\\tgain: aSound loudness.\\n\\t\\t^ compressed].\\n\\t(aSound isKindOf: LoopedSampledSound) ifTrue: [\\n\\t\\taSound isStereo\\n\\t\\t\\tifTrue: [\\n\\t\\t\\t\\tchannels := Array new: 2.\\n\\t\\t\\t\\tchannels at: 1 put: (self encodeSoundBuffer: aSound leftSamples).\\n\\t\\t\\t\\tchannels at: 2 put: (self encodeSoundBuffer: aSound rightSamples)]\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tchannels := Array new: 1.\\n\\t\\t\\t\\tchannels at: 1 put: (self encodeSoundBuffer: aSound leftSamples)].\\n\\t\\tcompressed\\n\\t\\t\\tchannels: channels;\\n\\t\\t\\tsamplingRate: aSound originalSamplingRate;\\n\\t\\t\\tfirstSample: aSound firstSample;\\n\\t\\t\\tloopEnd: aSound loopEnd;\\n\\t\\t\\tloopLength: aSound loopLength;\\n\\t\\t\\tperceivedPitch: aSound perceivedPitch;\\n\\t\\t\\tgain: aSound gain.\\n\\t\\t^ compressed].\\n\\tself error: 'you can only compress sampled sounds'.\\n! !\\n\\n!SoundCodec methodsFor: 'compress/decompress' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ndecompressSound: aCompressedSound\\n\\t\\\"Decompress the entirety of the given compressed sound with this codec and answer the resulting sound.\\\"\\n\\n\\t| channels sound |\\n\\tchannels := aCompressedSound channels\\n\\t\\tcollect: [:compressed | self decodeCompressedData: compressed].\\n\\t'SampledSound' = aCompressedSound soundClassName ifTrue: [\\n\\t\\tsound := SampledSound\\n\\t\\t\\tsamples: channels first\\n\\t\\t\\tsamplingRate: (aCompressedSound samplingRate).\\n\\t\\tsound loudness: aCompressedSound gain.\\n\\t\\t^ sound].\\n\\t'LoopedSampledSound' = aCompressedSound soundClassName ifTrue: [\\n\\t\\taCompressedSound loopLength = 0\\n\\t\\t\\tifTrue: [\\n\\t\\t\\t\\tsound := LoopedSampledSound\\n\\t\\t\\t\\t\\tunloopedSamples: channels first\\n\\t\\t\\t\\t\\tpitch: aCompressedSound perceivedPitch\\n\\t\\t\\t\\t\\tsamplingRate: aCompressedSound samplingRate]\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tsound := LoopedSampledSound\\n\\t\\t\\t\\t\\tsamples: channels first\\n\\t\\t\\t\\t\\tloopEnd: aCompressedSound loopEnd\\n\\t\\t\\t\\t\\tloopLength: aCompressedSound loopLength\\n\\t\\t\\t\\t\\tpitch: aCompressedSound perceivedPitch\\n\\t\\t\\t\\t\\tsamplingRate: aCompressedSound samplingRate].\\n\\t\\tchannels size > 1 ifTrue: [sound rightSamples: channels last].\\n\\t\\tsound\\n\\t\\t\\tfirstSample: aCompressedSound firstSample;\\n\\t\\t\\tgain: aCompressedSound gain.\\n\\t\\tsound\\n\\t\\t\\tsetPitch: 100.0\\n\\t\\t\\tdur: (channels first size / aCompressedSound samplingRate)\\n\\t\\t\\tloudness: 1.0.\\n\\t\\t^ sound].\\n\\tself error: 'unknown sound class'.\\n! !\\n\\n\\n!SoundCodec methodsFor: 'subclass responsibilities' stamp: 'di 2/8/1999 14:23'!\\nbytesPerEncodedFrame\\n\\t\\\"Answer the number of bytes required to hold one frame of compressed sound data. Answer zero if this codec produces encoded frames of variable size.\\\"\\n\\n\\tself subclassResponsibility.\\n! !\\n\\n!SoundCodec methodsFor: 'subclass responsibilities' stamp: 'jm 2/2/1999 15:38'!\\ndecodeFrames: frameCount from: srcByteArray at: srcIndex into: dstSoundBuffer at: dstIndex\\n\\t\\\"Decode the given number of monophonic frames starting at the given index in the given ByteArray of compressed sound data and storing the decoded samples into the given SoundBuffer starting at the given destination index. Answer a pair containing the number of bytes of compressed data consumed and the number of decompressed samples produced.\\\"\\n\\t\\\"Note: Assume that the sender has ensured that the given number of frames will not exhaust either the source or destination buffers.\\\"\\n\\n\\tself subclassResponsibility.\\n! !\\n\\n!SoundCodec methodsFor: 'subclass responsibilities' stamp: 'jm 2/2/1999 15:39'!\\nencodeFrames: frameCount from: srcSoundBuffer at: srcIndex into: dstByteArray at: dstIndex\\n\\t\\\"Encode the given number of frames starting at the given index in the given monophonic SoundBuffer and storing the encoded sound data into the given ByteArray starting at the given destination index. Encode only as many complete frames as will fit into the destination. Answer a pair containing the number of samples consumed and the number of bytes of compressed data produced.\\\"\\n\\t\\\"Note: Assume that the sender has ensured that the given number of frames will not exhaust either the source or destination buffers.\\\"\\n\\n\\tself subclassResponsibility.\\n! !\\n\\n!SoundCodec methodsFor: 'subclass responsibilities' stamp: 'jm 2/4/1999 11:30'!\\nreset\\n\\t\\\"Reset my encoding and decoding state. Optional. This default implementation does nothing.\\\"\\n! !\\n\\n!SoundCodec methodsFor: 'subclass responsibilities' stamp: 'jm 2/2/1999 15:45'!\\nsamplesPerFrame\\n\\t\\\"Answer the number of sound samples per compression frame.\\\"\\n\\n\\tself subclassResponsibility.\\n! !\\n\\n\\n!SoundCodec methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ndecodeCompressedData: aByteArray\\n\\t\\\"Decode the entirety of the given encoded data buffer with this codec. Answer a monophonic SoundBuffer containing the uncompressed samples.\\\"\\n\\n\\t| frameCount result increments |\\n\\tframeCount := self frameCount: aByteArray.\\n\\tresult := SoundBuffer newMonoSampleCount: frameCount * self samplesPerFrame.\\n\\tself reset.\\n\\tincrements := self decodeFrames: frameCount from: aByteArray at: 1 into: result at: 1.\\n\\t((increments first = aByteArray size) and: [increments last = result size]) ifFalse: [\\n\\t\\tself error: 'implementation problem; increment sizes should match buffer sizes'].\\n\\t^ result\\n! !\\n\\n!SoundCodec methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nencodeSoundBuffer: aSoundBuffer\\n\\t\\\"Encode the entirety of the given monophonic SoundBuffer with this codec. Answer a ByteArray containing the compressed sound data.\\\"\\n\\n\\t| codeFrameSize frameSize fullFrameCount lastFrameSamples result increments finalFrame i lastIncs |\\n\\tframeSize := self samplesPerFrame.\\n\\tfullFrameCount := aSoundBuffer monoSampleCount // frameSize.\\n\\tlastFrameSamples := aSoundBuffer monoSampleCount - (fullFrameCount * frameSize).\\n\\tcodeFrameSize := self bytesPerEncodedFrame.\\n\\tcodeFrameSize = 0 ifTrue:\\n\\t\\t[\\\"Allow room for 1 byte per sample for variable-length compression\\\"\\n\\t\\tcodeFrameSize := frameSize].\\n\\tlastFrameSamples > 0\\n\\t\\tifTrue: [result := ByteArray new: (fullFrameCount + 1) * codeFrameSize]\\n\\t\\tifFalse: [result := ByteArray new: fullFrameCount * codeFrameSize].\\n\\tself reset.\\n\\tincrements := self encodeFrames: fullFrameCount from: aSoundBuffer at: 1 into: result at: 1.\\n\\tlastFrameSamples > 0 ifTrue: [\\n\\t\\tfinalFrame := SoundBuffer newMonoSampleCount: frameSize.\\n\\t\\ti := fullFrameCount * frameSize.\\n\\t\\t1 to: lastFrameSamples do: [:j |\\n\\t\\t\\tfinalFrame at: j put: (aSoundBuffer at: (i := i + 1))].\\n\\t\\tlastIncs := self encodeFrames: 1 from: finalFrame at: 1 into: result at: 1 + increments second.\\n\\t\\tincrements := Array with: increments first + lastIncs first\\n\\t\\t\\t\\t\\t\\t\\twith: increments second + lastIncs second].\\n\\tincrements second < result size\\n\\t\\tifTrue: [^ result copyFrom: 1 to: increments second]\\n\\t\\tifFalse: [^ result]\\n! !\\n\\n!SoundCodec methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nframeCount: aByteArray\\n\\t\\\"Compute the frame count for this byteArray. This default computation will have to be overridden by codecs with variable frame sizes.\\\"\\n\\n\\t| codeFrameSize |\\n\\tcodeFrameSize := self bytesPerEncodedFrame.\\n\\t(aByteArray size \\\\\\\\ codeFrameSize) = 0 ifFalse:\\n\\t\\t[self error: 'encoded buffer is not an even multiple of the encoded frame size'].\\n\\t^ aByteArray size // codeFrameSize! !\\nAlignmentMorph subclass: #SoundDemoMorph\\n\\tinstanceVariableNames: 'soundColumn'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SoundInterface'!\\n\\n!SoundDemoMorph methodsFor: 'as yet unclassified' stamp: 'tk 2/19/2001 17:49'!\\nmakeControls\\n\\n\\t| bb r cc |\\n\\tcc _ Color black.\\n\\tr _ AlignmentMorph newRow.\\n\\tr color: cc; borderWidth: 0; layoutInset: 0.\\n\\tr hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5@5.\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tr addMorphBack: (bb label: 'V1';\\t\\t\\tactionSelector: #playV1).\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tr addMorphBack: (bb label: 'V2';\\t\\t\\tactionSelector: #playV2).\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tr addMorphBack: (bb label: 'V3';\\t\\t\\tactionSelector: #playV3).\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tr addMorphBack: (bb label: 'All';\\t\\t\\tactionSelector: #playAll).\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tr addMorphBack: (bb label: 'Stop';\\t\\tactionSelector: #stopSound).\\n\\t^ r\\n! !\\n\\n!SoundDemoMorph methodsFor: 'as yet unclassified' stamp: 'dgd 2/22/2003 13:34'!\\nplayAll\\n\\t| snd |\\n\\tsoundColumn submorphs isEmpty\\n\\t\\tifTrue: [^ self].\\n\\tself setTimbreFromTile: soundColumn submorphs first.\\n\\tsnd _ SampledSound bachFugueVoice1On: SampledSound new.\\n\\tsoundColumn submorphs size >= 2\\n\\t\\tifTrue: [\\\"\\\"self setTimbreFromTile: soundColumn submorphs second.\\n\\t\\t\\tsnd _ snd\\n\\t\\t\\t\\t\\t\\t+ (AbstractSound bachFugueVoice2On: SampledSound new)].\\n\\tsoundColumn submorphs size >= 3\\n\\t\\tifTrue: [\\\"\\\"self setTimbreFromTile: soundColumn submorphs third.\\n\\t\\t\\tsnd _ snd\\n\\t\\t\\t\\t\\t\\t+ (AbstractSound bachFugueVoice3On: SampledSound new)].\\n\\tsnd play! !\\n\\n!SoundDemoMorph methodsFor: 'as yet unclassified' stamp: 'dgd 2/22/2003 13:35'!\\nplayV1\\n\\tsoundColumn submorphs isEmpty\\n\\t\\tifTrue: [^ self].\\n\\tself\\n\\t\\tsetTimbreFromTile: (soundColumn submorphs first).\\n\\t(SampledSound bachFugueVoice1On: SampledSound new) play! !\\n\\n!SoundDemoMorph methodsFor: 'as yet unclassified' stamp: 'dgd 2/22/2003 13:35'!\\nplayV2\\n\\tsoundColumn submorphs size < 2\\n\\t\\tifTrue: [^ self].\\n\\tself\\n\\t\\tsetTimbreFromTile: (soundColumn submorphs second).\\n\\t(SampledSound bachFugueVoice2On: SampledSound new) playSilentlyUntil: 4.8;\\n\\t\\t resumePlaying! !\\n\\n!SoundDemoMorph methodsFor: 'as yet unclassified' stamp: 'dgd 2/22/2003 13:35'!\\nplayV3\\n\\tsoundColumn submorphs size < 3\\n\\t\\tifTrue: [^ self].\\n\\tself\\n\\t\\tsetTimbreFromTile: (soundColumn submorphs third).\\n\\t(AbstractSound bachFugueVoice3On: SampledSound new) playSilentlyUntil: 14.4;\\n\\t\\t resumePlaying! !\\n\\n!SoundDemoMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:09'!\\nsetTimbreFromTile: aSoundTile\\n\\n\\tSampledSound defaultSampleTable: aSoundTile sound samples.\\n\\tSampledSound nominalSamplePitch: 400.\\n! !\\n\\n!SoundDemoMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:09'!\\nstopSound\\n\\n\\tSoundPlayer shutDown.\\n! !\\n\\n\\n!SoundDemoMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:40'!\\ndefaultBorderWidth\\n\\t\\\"answer the default border width for the receiver\\\"\\n\\t^ 2! !\\n\\n!SoundDemoMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:31'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color lightGray! !\\n\\n!SoundDemoMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 21:04'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\tself listDirection: #topToBottom;\\n\\t\\t wrapCentering: #center;\\n\\t\\t cellPositioning: #topCenter;\\n\\t\\t hResizing: #spaceFill;\\n\\t\\t vResizing: #spaceFill;\\n\\t\\t layoutInset: 3;\\n\\t\\t addMorph: self makeControls;\\n\\tinitializeSoundColumn.\\n\\tself extent: 118 @ 150! !\\n\\n!SoundDemoMorph methodsFor: 'initialization' stamp: 'jam 3/9/2003 17:52'!\\ninitializeSoundColumn\\n\\\"initialize the receiver's soundColumn\\\"\\n\\tsoundColumn _ AlignmentMorph newColumn.\\n\\tsoundColumn enableDragNDrop.\\n\\tself addMorphBack: soundColumn! !\\nAbstractMediaEventMorph subclass: #SoundEventMorph\\n\\tinstanceVariableNames: 'sound'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SoundInterface'!\\n\\n!SoundEventMorph methodsFor: 'as yet unclassified' stamp: 'RAA 12/7/2000 13:01'!\\nsound: aSound\\n\\n\\tsound _ aSound.\\n\\tself setBalloonText: 'a sound of duration ',(sound duration roundTo: 0.1) printString,' seconds'.! !\\n\\n\\n!SoundEventMorph methodsFor: 'caching' stamp: 'RAA 12/8/2000 09:52'!\\nreleaseCachedState\\n\\n\\tsuper releaseCachedState.\\n\\tsound _ sound compressWith: GSMCodec.\\n! !\\n\\n\\n!SoundEventMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:31'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color lightGreen! !\\n\\n!SoundEventMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 21:39'!\\ninitialize\\n\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\\"\\\"\\n\\tself height: 10! !\\n\\n\\n!SoundEventMorph methodsFor: 'piano rolls' stamp: 'RAA 12/7/2000 12:36'!\\naddMorphsTo: morphList pianoRoll: pianoRoll eventTime: t betweenTime: leftTime and: rightTime\\n\\n\\t| startX lengthInTicks endX |\\n\\n\\tstartTimeInScore > rightTime ifTrue: [^ self]. \\n\\tlengthInTicks _ pianoRoll scorePlayer ticksForMSecs: sound duration * 1000.0.\\n\\tstartTimeInScore + lengthInTicks < leftTime ifTrue: [^ self].\\n\\tstartX _ pianoRoll xForTime: startTimeInScore.\\n\\tendX _ pianoRoll xForTime: startTimeInScore + lengthInTicks.\\n\\tmorphList add: \\n\\t\\t(self left: startX; width: endX - startX).\\n\\n! !\\n\\n!SoundEventMorph methodsFor: 'piano rolls' stamp: 'RAA 12/7/2000 12:29'!\\nencounteredAtTime: ticks inScorePlayer: scorePlayer atIndex: index inEventTrack: track secsPerTick: secsPerTick\\n\\n\\t\\\"hack... since we are called from within the SoundPlayer loop, the Semaphore will\\n\\tblock attempts to play directly from here\\\"\\n\\tWorldState addDeferredUIMessage: [sound play].! !\\n\\n!SoundEventMorph methodsFor: 'piano rolls' stamp: 'RAA 12/9/2000 18:48'!\\njustDroppedIntoPianoRoll: newOwner event: evt\\n\\t\\n\\t| startX lengthInTicks endX |\\n\\n\\tsuper justDroppedIntoPianoRoll: newOwner event: evt.\\n\\n\\tstartTimeInScore _ newOwner timeForX: self left.\\n\\tlengthInTicks _ newOwner scorePlayer ticksForMSecs: sound duration * 1000.0.\\n\\tendTimeInScore _ startTimeInScore + lengthInTicks.\\n\\n\\tendTimeInScore > newOwner scorePlayer durationInTicks ifTrue:\\n\\t\\t[newOwner scorePlayer updateDuration].\\n\\n\\tstartX _ newOwner xForTime: startTimeInScore.\\n\\tendX _ newOwner xForTime: endTimeInScore.\\n\\tself width: endX - startX.\\n\\n! !\\nSoundRecorder subclass: #SoundInputStream\\n\\tinstanceVariableNames: 'bufferSize mutex'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n!SoundInputStream commentStamp: '<historical>' prior: 0!\\nThis subclass of SoundRecorder supports real-time processing of incoming sound data. The sound input process queues raw sound buffers, allowing them to be read and processed by the client as they become available. A semaphore is used to synchronize between the record process and the client process. Since sound data is buffered, the client process may lag behind the input process without losing data.\\n!\\n\\n\\n!SoundInputStream methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nbufferCount\\n\\t\\\"Answer the number of sound buffers that have been queued.\\\"\\n\\n\\t| n |\\n\\tmutex ifNil: [^ 0]. \\\"not recording\\\"\\n\\tmutex critical: [n := recordedBuffers size].\\n\\t^ n\\n! !\\n\\n!SoundInputStream methodsFor: 'accessing' stamp: 'jm 9/6/1999 10:36'!\\nbufferSize\\n\\n\\t^ bufferSize\\n! !\\n\\n!SoundInputStream methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nbufferSize: aNumber\\n\\t\\\"Set the sound buffer size. Buffers of this size will be queued for the client to process.\\\"\\n\\n\\tbufferSize := aNumber truncated.\\n! !\\n\\n!SoundInputStream methodsFor: 'accessing' stamp: 'jm 9/8/1999 15:23'!\\nisRecording\\n\\t\\\"Answer true if the sound input process is running.\\\"\\n\\n\\t^ recordProcess ~~ nil\\n! !\\n\\n!SoundInputStream methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nnextBufferOrNil\\n\\t\\\"Answer the next input buffer or nil if no buffer is available.\\\"\\n\\n\\t| result |\\n\\tmutex ifNil: [^ nil]. \\\"not recording\\\"\\n\\tmutex critical: [\\n\\t\\trecordedBuffers size > 0\\n\\t\\t\\tifTrue: [result := recordedBuffers removeFirst]\\n\\t\\t\\tifFalse: [result := nil]].\\n\\t^ result\\n! !\\n\\n\\n!SoundInputStream methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitialize\\n\\n\\tsuper initialize.\\n\\tbufferSize := 1024.\\n\\tmutex := nil.\\n! !\\n\\n\\n!SoundInputStream methodsFor: 'recording controls' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstartRecording\\n\\t\\\"Start the sound input process.\\\"\\n\\n\\trecordProcess ifNotNil: [self stopRecording].\\n\\trecordedBuffers := OrderedCollection new: 100.\\n\\tmutex := Semaphore forMutualExclusion.\\n\\tsuper startRecording.\\n\\tpaused := false.\\n! !\\n\\n!SoundInputStream methodsFor: 'recording controls' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstopRecording\\n\\t\\\"Turn off the sound input process and close the driver.\\\"\\n\\n\\tsuper stopRecording.\\n\\trecordedBuffers := nil.\\n\\tmutex := nil.\\n! !\\n\\n\\n!SoundInputStream methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nallocateBuffer\\n\\t\\\"Allocate a new buffer and reset nextIndex. This message is sent by the sound input process.\\\"\\n\\n\\tcurrentBuffer := SoundBuffer newMonoSampleCount: bufferSize.\\n\\tnextIndex := 1.\\n! !\\n\\n!SoundInputStream methodsFor: 'private' stamp: 'jm 9/8/1999 15:24'!\\nemitBuffer: buffer\\n\\t\\\"Queue a buffer for later processing. This message is sent by the sound input process.\\\"\\n\\n\\tmutex critical: [recordedBuffers addLast: buffer].\\n! !\\nRectangleMorph subclass: #SoundLoopMorph\\n\\tinstanceVariableNames: 'samplesUntilNextControl seqSound cursor controlIndex'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SoundInterface'!\\n\\n!SoundLoopMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:21'!\\naddCursorMorph\\n\\tself addMorph:\\n\\t\\t(cursor _ (RectangleMorph\\n\\t\\t\\t\\tnewBounds: (self innerBounds topLeft extent: 1@self innerBounds height)\\n\\t\\t\\t\\tcolor: Color red)\\n\\t\\t\\t\\t\\t\\tborderWidth: 0)! !\\n\\n!SoundLoopMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:11'!\\nallowSubmorphExtraction\\n\\n\\t^ true! !\\n\\n!SoundLoopMorph methodsFor: 'as yet unclassified' stamp: 'jm 1/5/98 17:31'!\\nbuildSound\\n\\t\\\"Build a compound sound for the next iteration of the loop.\\\"\\n\\n\\t| mixer soundMorphs startTime pan |\\n\\tmixer _ MixedSound new.\\n\\tmixer add: (RestSound dur: (self width - (2 * borderWidth)) / 128.0).\\n\\tsoundMorphs _ self submorphs select: [:m | m respondsTo: #sound].\\n\\tsoundMorphs do: [:m |\\n\\t\\tstartTime _ (m position x - (self left + borderWidth)) / 128.0.\\n\\t\\tpan _ (m position y - (self top + borderWidth)) asFloat / (self height - (2 * borderWidth) - m height).\\n\\t\\tmixer add: ((RestSound dur: startTime), m sound copy) pan: pan].\\n\\t^ mixer\\n! !\\n\\n!SoundLoopMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:11'!\\nplay\\n\\t\\\"Play this sound to the sound ouput port in real time.\\\"\\n\\n\\tself reset.\\n\\tSoundPlayer playSound: self.\\n! !\\n\\n\\n!SoundLoopMorph methodsFor: 'dropping/grabbing' stamp: 'jm 11/14/97 11:11'!\\nwantsDroppedMorph: aMorph event: evt\\n\\n\\t^ aMorph respondsTo: #sound\\n! !\\n\\n\\n!SoundLoopMorph methodsFor: 'geometry' stamp: 'jm 11/14/97 11:21'!\\nextent: newExtent\\n\\tsuper extent: (newExtent truncateTo: 128@128) + (self borderWidth*2)! !\\n\\n\\n!SoundLoopMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:40'!\\ndefaultBorderWidth\\n\\t\\\"answer the default border width for the receiver\\\"\\n\\t^ 1! !\\n\\n!SoundLoopMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 15:07'!\\ndefaultBounds\\n\\\"answer the default bounds for the receiver\\\"\\n\\t^ 0 @ 0 corner: 128 @ 128 + (self defaultBorderWidth * 2)! !\\n\\n!SoundLoopMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:31'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color lightBlue! !\\n\\n!SoundLoopMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 20:50'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\t\\n\\tcontrolIndex _ 0.\\n\\tself addCursorMorph! !\\n\\n\\n!SoundLoopMorph methodsFor: 'playing' stamp: 'jm 11/14/97 11:21'!\\ncontrolRate\\n\\t\\\"Answer the number of control changes per second.\\\"\\n\\n\\t^ 32\\n! !\\n\\n!SoundLoopMorph methodsFor: 'playing' stamp: 'jm 11/14/97 11:21'!\\ndoControl\\n\\n\\tseqSound doControl.\\n\\tcontrolIndex _ controlIndex + 1.\\n\\tcontrolIndex >= (self controlRate * (self innerBounds width // 128))\\n\\t\\tifTrue: [controlIndex _ 0].\\n! !\\n\\n!SoundLoopMorph methodsFor: 'playing' stamp: 'jm 1/5/98 13:40'!\\nmixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol\\n\\t\\\"Repeatedly play my sounds.\\\"\\n\\n\\t| i count samplesNeeded |\\n\\ti _ startIndex.\\n\\tsamplesNeeded _ n.\\n\\t[samplesNeeded > 0] whileTrue: [\\n\\t\\tcount _ seqSound samplesRemaining min: samplesNeeded.\\n\\t\\tcount = 0 ifTrue: [\\n\\t\\t\\tself reset.\\n\\t\\t\\tcount _ seqSound samplesRemaining min: samplesNeeded.\\n\\t\\t\\tcount = 0 ifTrue: [^ self]]. \\\"zero length sound\\\"\\n\\t\\tseqSound mixSampleCount: count into: aSoundBuffer startingAt: i leftVol: leftVol rightVol: rightVol.\\n\\t\\ti _ i + count.\\n\\t\\tsamplesNeeded _ samplesNeeded - count].\\n! !\\n\\n!SoundLoopMorph methodsFor: 'playing' stamp: 'jm 1/26/98 22:05'!\\nplaySampleCount: n into: aSoundBuffer startingAt: startIndex\\n\\t\\\"Mixes the next count samples of this sound into the given buffer starting at the given index, updating the receiver's control parameters at periodic intervals.\\\"\\n\\n\\t| fullVol samplesBetweenControlUpdates pastEnd i remainingSamples count |\\n\\tfullVol _ AbstractSound scaleFactor.\\n\\tsamplesBetweenControlUpdates _ self samplingRate // self controlRate.\\n\\tpastEnd _ startIndex + n. \\\"index just index of after last sample\\\"\\n\\ti _ startIndex.\\n\\t[i < pastEnd] whileTrue: [\\n\\t\\tremainingSamples _ self samplesRemaining.\\n\\t\\tremainingSamples <= 0 ifTrue: [^ self].\\n\\t\\tcount _ pastEnd - i.\\n\\t\\tsamplesUntilNextControl < count ifTrue: [count _ samplesUntilNextControl].\\n\\t\\tremainingSamples < count ifTrue: [count _ remainingSamples].\\n\\t\\tself mixSampleCount: count into: aSoundBuffer startingAt: i leftVol: fullVol rightVol: fullVol.\\n\\t\\tsamplesUntilNextControl _ samplesUntilNextControl - count.\\n\\t\\tsamplesUntilNextControl <= 0 ifTrue: [\\n\\t\\t\\tself doControl.\\n\\t\\t\\tsamplesUntilNextControl _ samplesBetweenControlUpdates].\\n\\t\\ti _ i + count].\\n! !\\n\\n!SoundLoopMorph methodsFor: 'playing' stamp: 'jm 11/14/97 11:21'!\\npositionCursor\\n\\t| x |\\n\\tx _ controlIndex * 128 // self controlRate.\\n\\tcursor position: self innerBounds topLeft + (x@0)\\n! !\\n\\n!SoundLoopMorph methodsFor: 'playing' stamp: 'jm 11/14/97 11:21'!\\nreset\\n\\t\\\"Reset my internal state for a replay.\\\"\\n\\n\\tseqSound _ self buildSound reset.\\n\\tsamplesUntilNextControl _ (self samplingRate // self controlRate).\\n\\tcontrolIndex _ 0.\\n\\tself positionCursor! !\\n\\n!SoundLoopMorph methodsFor: 'playing' stamp: 'jm 11/14/97 11:11'!\\nsamplesRemaining\\n\\n\\t^ 1000000\\n! !\\n\\n!SoundLoopMorph methodsFor: 'playing' stamp: 'jm 11/14/97 11:11'!\\nsamplingRate\\n\\t\\\"Answer the sampling rate in samples per second.\\\"\\n\\n\\t^ SoundPlayer samplingRate! !\\n\\n\\n!SoundLoopMorph methodsFor: 'stepping and presenter' stamp: 'jm 11/14/97 11:21'!\\nstep\\n\\tself positionCursor! !\\n\\n!SoundLoopMorph methodsFor: 'stepping and presenter' stamp: 'jm 11/14/97 11:11'!\\nstop\\n\\t\\\"Stop playing this sound.\\\"\\n\\n\\tSoundPlayer pauseSound: self.\\n! !\\n\\n\\n!SoundLoopMorph methodsFor: 'testing' stamp: 'jm 11/14/97 11:21'!\\nstepTime\\n\\n\\t^ 50\\n! !\\nImageMorph subclass: #SoundMorph\\n\\tinstanceVariableNames: 'sound'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SoundInterface'!\\n!SoundMorph commentStamp: '<historical>' prior: 0!\\nNote: as of December 2000, this does not work. SoundMorph>>buildImage requires the sound to implement #volumeEnvelopeScaledTo: and as yet, no one does.!\\n\\n\\n!SoundMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:21'!\\nbuildImage\\n\\t| scale env h imageColor |\\n\\towner ifNil: [scale _ 128@128] \\\"Default is 128 pix/second, 128 pix fullscale\\\"\\n\\t\\tifNotNil: [scale _ owner soundScale].\\n\\tenv _ sound volumeEnvelopeScaledTo: scale.\\n\\tself image: (ColorForm extent: env size @ env max).\\n\\t1 to: image width do:\\n\\t\\t[:x | h _ env at: x.\\n\\t\\timage fillBlack: ((x-1)@(image height-h//2) extent: 1@h)].\\n\\timageColor _ #(black red orange green blue) atPin:\\n\\t\\t\\t\\t\\t\\t(sound pitch / 110.0) rounded highBit.\\n\\timage colors: (Array with: Color transparent with: (Color perform: imageColor)).\\n! !\\n\\n!SoundMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:08'!\\nreset\\n\\tsound reset! !\\n\\n!SoundMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:08'!\\nsound\\n\\t^ sound! !\\n\\n!SoundMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:08'!\\nsound: aSound\\n\\tsound _ aSound copy.\\n\\tsound reset.\\n\\tself buildImage! !\\n\\n\\n!SoundMorph methodsFor: 'dropping/grabbing' stamp: 'ar 10/5/2000 20:05'!\\njustDroppedInto: aMorph event: anEvent\\n\\t| relPosition |\\n\\trelPosition _ self position - aMorph innerBounds topLeft.\\n\\trelPosition _ (relPosition x roundTo: 8) @ relPosition y.\\n\\tself position: aMorph innerBounds topLeft + relPosition.\\n\\tsound copy play.\\n\\t^super justDroppedInto: aMorph event: anEvent! !\\n\\n\\n!SoundMorph methodsFor: 'initialization' stamp: 'jm 12/17/97 22:43'!\\ninitialize\\n\\n\\tsuper initialize.\\n\\tself sound: (FMSound pitch: 880.0 dur: 0.2 loudness: 0.8).\\n! !\\nObject subclass: #SoundPlayer\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'ActiveSounds Buffer BufferIndex BufferMSecs LastBuffer PlayerProcess PlayerSemaphore ReadyForBuffer ReverbState SamplingRate SoundJustStarted SoundSupported Stereo UseReadySemaphore UseReverb'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSoundPlayer class\\n\\tinstanceVariableNames: ''!\\n\\n!SoundPlayer class methodsFor: 'accessing' stamp: 'jm 8/13/1998 15:00'!\\nbufferMSecs\\n\\n\\t^ BufferMSecs\\n! !\\n\\n!SoundPlayer class methodsFor: 'accessing' stamp: 'jm 1/27/98 09:28'!\\nreverbState\\n\\n\\t^ ReverbState! !\\n\\n!SoundPlayer class methodsFor: 'accessing'!\\nsamplingRate\\n\\n\\t^ SamplingRate! !\\n\\n!SoundPlayer class methodsFor: 'accessing' stamp: 'JMM 11/6/2000 10:16'!\\nsetVolumeLeft: aLeftVolume volumeRight: aRightVolume\\n\\t\\\"Set sound pass in float 0.0-1.0 for left and right channel, with possible 2.0 or higher to overdrive sound channel \\\"\\n\\tself primSoundSetVolumeLeft: aLeftVolume volumeRight: aRightVolume! !\\n\\n!SoundPlayer class methodsFor: 'accessing' stamp: 'JMM 11/6/2000 10:17'!\\nsoundVolume\\n\\t\\\"Return sound as array of doubles left then right channel, range is 0.0 to 1.0 but may be overdriven\\\"\\n\\t^self primSoundGetVolume! !\\n\\n!SoundPlayer class methodsFor: 'accessing'!\\nstereo\\n\\n\\t^ Stereo\\n! !\\n\\n\\n!SoundPlayer class methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitialize\\n\\t\\\"SoundPlayer initialize; shutDown; startUp\\\"\\n\\t\\\"Details: BufferMSecs represents a tradeoff between latency and quality. If BufferMSecs is too low, the sound will not play smoothly, especially during long-running primitives such as large BitBlts. If BufferMSecs is too high, there will be a long time lag between when a sound buffer is submitted to be played and when that sound is actually heard. BufferMSecs is typically in the range 50-200.\\\"\\n\\n\\tSamplingRate := 22050.\\n\\tBufferMSecs := 120.\\n\\tStereo := true.\\n\\tUseReverb ifNil: [UseReverb := true].\\n! !\\n\\n!SoundPlayer class methodsFor: 'initialization' stamp: 'ar 1/24/2002 18:40'!\\nuseLastBuffer\\n\\t^LastBuffer notNil! !\\n\\n!SoundPlayer class methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nuseLastBuffer: aBool\\n\\tBuffer ifNil:[^self].\\n\\taBool \\n\\t\\tifTrue:[LastBuffer := SoundBuffer basicNew: Buffer basicSize]\\n\\t\\tifFalse:[LastBuffer := nil]\\t! !\\n\\n!SoundPlayer class methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nuseShortBuffer\\n\\t\\\"Experimental support for real-time MIDI input. This only works on platforms whose hardware allows very short buffer sizes. It has been tested on a Macintosh Powerbook G3.\\\"\\n\\t\\\"SoundPlayer useShortBuffer\\\"\\n\\n\\tself shutDown.\\n\\tBufferMSecs := 15.\\n\\tSoundPlayer\\n\\t\\tstartPlayerProcessBufferSize: (BufferMSecs * SamplingRate) // 1000\\n\\t\\trate: SamplingRate\\n\\t\\tstereo: Stereo.\\n! !\\n\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'jm 1/29/98 18:56'!\\nisReverbOn\\n\\n\\t^ ReverbState ~~ nil\\n! !\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'ar 1/24/2002 18:41'!\\nlastPlayBuffer\\n\\t^LastBuffer! !\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'stephaneducasse 2/4/2006 20:41'!\\noldStylePlayLoop\\n\\t\\\"This version of the play loop is used if the VM does not yet support sound primitives that signal a semaphore when a sound buffer becomes available.\\\"\\n\\n\\t| bytesPerSlice count |\\n\\tbytesPerSlice := Stereo ifTrue: [4] ifFalse: [2].\\n\\t[true] whileTrue: [\\n\\t\\t[(count := self primSoundAvailableBytes // bytesPerSlice) > 100]\\n\\t\\t\\twhileFalse: [(Delay forMilliseconds: 1) wait].\\n\\n\\t\\tcount := count min: Buffer stereoSampleCount.\\n\\t\\tPlayerSemaphore critical: [\\n\\t\\t\\tActiveSounds := ActiveSounds select: [:snd | snd samplesRemaining > 0].\\n\\t\\t\\tActiveSounds do: [:snd |\\n\\t\\t\\t\\tsnd ~~ SoundJustStarted ifTrue: [\\n\\t\\t\\t\\t\\tsnd playSampleCount: count into: Buffer startingAt: 1]].\\n\\t\\t\\tReverbState == nil ifFalse: [\\n\\t\\t\\t\\tReverbState applyReverbTo: Buffer startingAt: 1 count: count].\\n\\t\\t\\tself primSoundPlaySamples: count from: Buffer startingAt: 1.\\n\\t\\t\\tBuffer primFill: 0.\\n\\t\\t\\tSoundJustStarted := nil]].\\n! !\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nplayLoop\\n\\t\\\"The sound player process loop.\\\"\\n\\n\\t| bytesPerSlice count willStop mayStop |\\n\\tmayStop := Preferences soundStopWhenDone.\\n\\tbytesPerSlice := Stereo ifTrue: [4] ifFalse: [2].\\n\\t[true] whileTrue: [\\n\\t\\t[(count := self primSoundAvailableBytes // bytesPerSlice) > 100]\\n\\t\\t\\twhileFalse: [ReadyForBuffer wait].\\n\\n\\t\\tcount := count min: Buffer stereoSampleCount.\\n\\t\\tPlayerSemaphore critical: [\\n\\t\\t\\tActiveSounds := ActiveSounds select: [:snd | snd samplesRemaining > 0].\\n\\t\\t\\tActiveSounds do: [:snd |\\n\\t\\t\\t\\tsnd ~~ SoundJustStarted ifTrue: [\\n\\t\\t\\t\\t\\tsnd playSampleCount: count into: Buffer startingAt: 1]].\\n\\t\\t\\tReverbState == nil ifFalse: [\\n\\t\\t\\t\\tReverbState applyReverbTo: Buffer startingAt: 1 count: count].\\n\\t\\t\\tself primSoundPlaySamples: count from: Buffer startingAt: 1.\\n\\t\\t\\twillStop := mayStop and:[\\n\\t\\t\\t\\t\\t\\t(ActiveSounds size = 0) and:[\\n\\t\\t\\t\\t\\t\\t\\tself isAllSilence: Buffer size: count]].\\n\\t\\t\\tLastBuffer ifNotNil:[\\n\\t\\t\\t\\tLastBuffer replaceFrom: 1 to: LastBuffer size with: Buffer startingAt: 1.\\n\\t\\t\\t].\\n\\t\\t\\twillStop\\n\\t\\t\\t\\tifTrue:[self shutDown. PlayerProcess := nil]\\n\\t\\t\\t\\tifFalse:[Buffer primFill: 0].\\n\\t\\t\\tSoundJustStarted := nil].\\n\\t\\twillStop ifTrue:[^self].\\n\\t].\\n! !\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'nk 2/16/2001 13:26'!\\nplayerProcess\\n\\t^PlayerProcess! !\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'ar 2/4/2001 18:01'!\\nstartPlayerProcessBufferSize: bufferSize rate: samplesPerSecond stereo: stereoFlag\\n\\t\\\"Start the sound player process. Terminate the old process, if any.\\\"\\n\\t\\\"SoundPlayer startPlayerProcessBufferSize: 1000 rate: 11025 stereo: false\\\"\\n\\t^self startPlayerProcessBufferSize: bufferSize \\n\\t\\t\\trate: samplesPerSecond \\n\\t\\t\\tstereo: stereoFlag \\n\\t\\t\\tsound: nil! !\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstartPlayerProcessBufferSize: bufferSize rate: samplesPerSecond stereo: stereoFlag sound: aSound\\n\\t\\\"Start the sound player process. Terminate the old process, if any.\\\"\\n\\t\\\"SoundPlayer startPlayerProcessBufferSize: 1000 rate: 11025 stereo: false\\\"\\n\\n\\tself stopPlayerProcess.\\n\\taSound\\n\\t\\tifNil:[ActiveSounds := OrderedCollection new]\\n\\t\\tifNotNil:[ActiveSounds := OrderedCollection with: aSound].\\n\\tBuffer := SoundBuffer newStereoSampleCount: (bufferSize // 4) * 4.\\n\\tLastBuffer ifNotNil:[LastBuffer := SoundBuffer basicNew: Buffer basicSize].\\n\\tPlayerSemaphore := Semaphore forMutualExclusion.\\n\\tSamplingRate := samplesPerSecond.\\n\\tStereo := stereoFlag.\\n\\tReadyForBuffer := Semaphore new.\\n\\tSoundSupported := true. \\\"Assume so\\\"\\n\\tUseReadySemaphore := true. \\\"set to false if ready semaphore not supported by VM\\\"\\n\\tself primSoundStartBufferSize: Buffer stereoSampleCount\\n\\t\\trate: samplesPerSecond\\n\\t\\tstereo: Stereo\\n\\t\\tsemaIndex: (Smalltalk registerExternalObject: ReadyForBuffer).\\n\\t\\\"Check if sound start prim was successful\\\"\\n\\tSoundSupported ifFalse:[^self].\\n\\tUseReadySemaphore\\n\\t\\tifTrue: [PlayerProcess := [SoundPlayer playLoop] newProcess]\\n\\t\\tifFalse: [PlayerProcess := [SoundPlayer oldStylePlayLoop] newProcess].\\n\\tUseReverb ifTrue: [self startReverb].\\n\\n\\tPlayerProcess priority: Processor userInterruptPriority.\\n\\tPlayerProcess resume.! !\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstartReverb\\n\\t\\\"Start a delay-line style reverb with the given tap delays and gains. Tap delays are given in samples and should be prime integers; the following comment gives an expression that generates primes.\\\"\\n\\t\\\"Integer primesUpTo: 22050\\\"\\n\\n\\tUseReverb := true.\\n\\tReverbState := ReverbSound new\\n\\t\\ttapDelays: #(1601 7919) gains: #(0.12 0.07).\\n! !\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstopPlayerProcess\\n\\t\\\"Stop the sound player process.\\\"\\n\\t\\\"SoundPlayer stopPlayerProcess\\\"\\n\\n\\t(PlayerProcess == nil or:[PlayerProcess == Processor activeProcess]) \\n\\t\\tifFalse:[PlayerProcess terminate].\\n\\tPlayerProcess := nil.\\n\\tself primSoundStop.\\n\\tActiveSounds := OrderedCollection new.\\n\\tBuffer := nil.\\n\\tPlayerSemaphore := Semaphore forMutualExclusion.\\n\\tReadyForBuffer ifNotNil:\\n\\t\\t[Smalltalk unregisterExternalObject: ReadyForBuffer].\\n\\tReadyForBuffer := nil.\\n! !\\n\\n!SoundPlayer class methodsFor: 'player process' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstopReverb\\n\\n\\tUseReverb := false.\\n\\tReverbState := nil.\\n! !\\n\\n\\n!SoundPlayer class methodsFor: 'playing' stamp: 'ar 2/1/2001 15:20'!\\ncanStartPlayer\\n\\t\\\"Some platforms do no support simultaneous record and play. If this is one of those platforms, return false if there is a running SoundRecorder.\\\"\\n\\n\\tPreferences canRecordWhilePlaying ifTrue: [^ true].\\n\\tSoundRecorder anyActive ifTrue:[^false].\\n\\t^ true\\n! !\\n\\n!SoundPlayer class methodsFor: 'playing' stamp: 'di 8/5/1998 23:08'!\\nisPlaying: aSound\\n\\t^ ActiveSounds includes: aSound! !\\n\\n!SoundPlayer class methodsFor: 'playing' stamp: 'jm 8/23/97 20:38'!\\npauseSound: aSound\\n\\t\\\"Stop playing the given sound. Playing can be resumed from this point later.\\\"\\n\\n\\tPlayerSemaphore critical: [\\n\\t\\tActiveSounds remove: aSound ifAbsent: []].\\n! !\\n\\n!SoundPlayer class methodsFor: 'playing' stamp: 'ar 2/19/2001 01:28'!\\nplaySound: aSound\\n\\t\\\"Reset and start playing the given sound from its beginning.\\\"\\n\\n\\taSound reset.\\n\\taSound samplesRemaining = 0 ifTrue:[^self].\\n\\tself resumePlaying: aSound.\\n! !\\n\\n!SoundPlayer class methodsFor: 'playing' stamp: 'jm 9/8/1998 17:54'!\\nresumePlaying: aSound\\n\\t\\\"Start playing the given sound without resetting it; it will resume playing from where it last stopped.\\\"\\n\\t\\\"Implementation detail: On virtual machines that don't support the quickstart primitive, you may need to edit this method to pass false to resumePlaying:quickStart:.\\\"\\n\\n\\tself resumePlaying: aSound quickStart: true.\\n! !\\n\\n!SoundPlayer class methodsFor: 'playing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nresumePlaying: aSound quickStart: quickStart\\n\\t\\\"Start playing the given sound without resetting it; it will resume playing from where it last stopped. If quickStart is true, then try to start playing the given sound immediately.\\\"\\n\\n\\t| doQuickStart |\\n\\tPreferences soundsEnabled ifFalse: [^ self].\\n\\tdoQuickStart := quickStart.\\n\\tPreferences soundQuickStart ifFalse: [doQuickStart := false].\\n\\tPlayerProcess == nil ifTrue: [\\n\\t\\tself canStartPlayer ifFalse: [^ self].\\n\\t\\t^self startUpWithSound: aSound].\\n\\n\\tPlayerSemaphore critical: [\\n\\t\\t(ActiveSounds includes: aSound)\\n\\t\\t\\tifTrue: [doQuickStart := false]\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tdoQuickStart ifFalse: [ActiveSounds add: aSound]]].\\n\\n\\t\\\"quick-start the given sound, unless the sound player has just started\\\"\\n\\tdoQuickStart ifTrue: [self startPlayingImmediately: aSound].\\n! !\\n\\n!SoundPlayer class methodsFor: 'playing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstopPlayingAll\\n\\t\\\"Stop playing all sounds.\\\"\\n\\n\\tPlayerSemaphore critical: [\\n\\t\\tActiveSounds := ActiveSounds species new].\\n! !\\n\\n!SoundPlayer class methodsFor: 'playing' stamp: 'jm 9/13/97 19:49'!\\nwaitUntilDonePlaying: aSound\\n\\t\\\"Wait until the given sound is no longer playing.\\\"\\n\\n\\t[PlayerSemaphore critical: [ActiveSounds includes: aSound]]\\n\\t\\twhileTrue: [(Delay forMilliseconds: 100) wait].\\n! !\\n\\n\\n!SoundPlayer class methodsFor: 'primitive test' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nboinkPitch: p dur: d loudness: l waveTable: waveTable pan: pan\\n\\t\\\"Play a decaying note on the given stream using the given wave table. Used for testing only.\\\"\\n\\n\\t| decay tableSize amplitude increment cycles i |\\n\\tdecay := 0.96.\\n\\ttableSize := waveTable size.\\n\\tamplitude := l asInteger min: 1000.\\n\\tincrement := ((p asFloat * tableSize asFloat) / SamplingRate asFloat) asInteger.\\n\\tincrement := (increment max: 1) min: (tableSize // 2).\\n\\tcycles := (d * SamplingRate asFloat) asInteger.\\n\\n\\ti := 1.\\n\\t1 to: cycles do: [:cycle |\\n\\t\\t(cycle \\\\\\\\ 100) = 0\\n\\t\\t\\tifTrue: [amplitude := (decay * amplitude asFloat) asInteger].\\n\\t\\ti := (((i - 1) + increment) \\\\\\\\ tableSize) + 1.\\n\\t\\tself playTestSample: (amplitude * (waveTable at: i)) // 1000 pan: pan].\\n! !\\n\\n!SoundPlayer class methodsFor: 'primitive test' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nboinkScale\\n\\t\\\"Tests the sound output primitives by playing a scale.\\\"\\n\\t\\\"SoundPlayer boinkScale\\\"\\n\\n\\t| sineTable pan |\\n\\tself shutDown.\\n\\tSamplingRate := 11025.\\n\\tStereo := true.\\n\\tsineTable := self sineTable: 1000.\\n\\tBuffer := SoundBuffer newStereoSampleCount: 1000.\\n\\tBufferIndex := 1.\\n\\tself primSoundStartBufferSize: Buffer stereoSampleCount\\n\\t\\trate: SamplingRate\\n\\t\\tstereo: Stereo.\\n\\tpan := 0.\\n\\t#(261.626 293.665 329.628 349.229 391.996 440.001 493.884 523.252) do: [:p |\\n\\t\\tself boinkPitch: p dur: 0.3 loudness: 300 waveTable: sineTable pan: pan.\\n\\t\\tpan := pan + 125].\\n\\n\\tself boinkPitch: 261.626 dur: 1.0 loudness: 300 waveTable: sineTable pan: 500.\\n\\tself primSoundStop.\\n\\tself shutDown.\\n\\tSoundPlayer initialize. \\\"reset sampling rate, buffer size, and stereo flag\\\"\\n! !\\n\\n!SoundPlayer class methodsFor: 'primitive test' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nplayTestSample: s pan: pan\\n\\t\\\"Append the given sample in the range [-32767..32767] to the output buffer, playing the output buffer when it is full. Used for testing only.\\\"\\n\\n\\t| sample leftSample |\\n\\tBufferIndex >= Buffer size\\n\\t\\tifTrue: [\\n\\t\\t\\t\\\"current buffer is full; play it\\\"\\n\\t\\t\\t[self primSoundAvailableBytes > 0]\\n\\t\\t\\t\\twhileFalse. \\\"wait for space to be available\\\"\\n\\t\\t\\tself primSoundPlaySamples: Buffer stereoSampleCount from: Buffer startingAt: 1.\\n\\t\\t\\tBuffer primFill: 0.\\n\\t\\t\\tBufferIndex := 1].\\n\\n\\tsample := s.\\n\\tsample > 32767 ifTrue: [ sample := 32767 ]. \\n\\tsample < -32767 ifTrue: [ sample := -32767 ].\\n\\n\\tStereo\\n\\t\\tifTrue: [\\n\\t\\t\\tleftSample := (sample * pan) // 1000.\\n\\t\\t\\tBuffer at: BufferIndex\\t\\tput: sample - leftSample.\\n\\t\\t\\tBuffer at: BufferIndex + 1\\tput: leftSample]\\n\\t\\tifFalse: [\\n\\t\\t\\tBuffer at: BufferIndex + 1 put: sample].\\n\\tBufferIndex := BufferIndex + 2.\\n! !\\n\\n!SoundPlayer class methodsFor: 'primitive test' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsineTable: size\\n\\t\\\"Compute a sine table of the given size. Used for testing only.\\\"\\n\\n\\t| radiansPerStep table |\\n\\ttable := Array new: size.\\n\\tradiansPerStep := (2.0 * Float pi) / table size asFloat.\\n\\t1 to: table size do: [:i |\\n\\t\\ttable at: i put:\\n\\t\\t\\t(32767.0 * (radiansPerStep * i) sin) asInteger].\\n\\n\\t^ table\\n! !\\n\\n\\n!SoundPlayer class methodsFor: 'snapshotting' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nshutDown\\n\\t\\\"Stop player process, for example before snapshotting.\\\"\\n\\n\\tself stopPlayerProcess.\\n\\tReverbState := nil.\\n! !\\n\\n!SoundPlayer class methodsFor: 'snapshotting' stamp: 'jm 7/11/97 12:17'!\\nstartUp\\n\\t\\\"Start up the player process.\\\"\\n\\n\\tSoundPlayer initialize.\\n\\tSoundPlayer\\n\\t\\tstartPlayerProcessBufferSize: (BufferMSecs * SamplingRate) // 1000\\n\\t\\trate: SamplingRate\\n\\t\\tstereo: Stereo.\\n! !\\n\\n!SoundPlayer class methodsFor: 'snapshotting' stamp: 'ar 2/4/2001 17:59'!\\nstartUpWithSound: aSound\\n\\t\\\"Start up the player process.\\\"\\n\\n\\tSoundPlayer initialize.\\n\\tSoundPlayer\\n\\t\\tstartPlayerProcessBufferSize: (BufferMSecs * SamplingRate) // 1000\\n\\t\\trate: SamplingRate\\n\\t\\tstereo: Stereo\\n\\t\\tsound: aSound.\\n! !\\n\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nisAllSilence: buffer size: count\\n\\t\\\"return true if the buffer is all silence after reverb has ended\\\"\\n\\t| value |\\n\\tvalue := buffer at: 1.\\n\\t2 to: count do:[:i| (buffer at: i) = value ifFalse:[^false]].\\n\\t^true! !\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'ar 2/2/2001 15:09'!\\nprimSoundAvailableBytes\\n\\t\\\"Return the number of bytes of available space in the sound output buffer.\\\"\\n\\t\\\"Note: Squeak always uses buffers containing 4-bytes per sample (2 channels at 2 bytes per channel) regardless of the state of the Stereo flag.\\\"\\n\\n\\t<primitive: 'primitiveSoundAvailableSpace' module: 'SoundPlugin'>\\n\\t^ self primitiveFailed\\n! !\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'JMM 11/6/2000 10:17'!\\nprimSoundGetVolume\\n\\t\\\"Return sound as array of doubles left then right channel, range is 0.0 to 1.0 but may be overdriven\\\"\\n\\t<primitive: 'primitiveSoundGetVolume' module: 'SoundPlugin'>\\n\\t^Array with: 1.0 with: 1.0! !\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'ar 2/2/2001 15:09'!\\nprimSoundInsertSamples: count from: aSoundBuffer samplesOfLeadTime: anInteger\\n\\t\\\"Mix the given number of sample frames from the given sound buffer into the queue of samples that has already been submitted to the sound driver. This primitive is used to start a sound playing with minimum latency, even if large sound output buffers are being used to ensure smooth sound output. Returns the number of samples consumed, or zero if the primitive is not implemented or fails.\\\"\\n\\n\\t<primitive: 'primitiveSoundInsertSamples' module: 'SoundPlugin'>\\n\\t^ 0\\n! !\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'ar 2/2/2001 15:09'!\\nprimSoundPlaySamples: count from: aSampleBuffer startingAt: index\\n\\t\\\"Copy count bytes into the current sound output buffer from the given sample buffer starting at the given index.\\\"\\n\\n\\t<primitive: 'primitiveSoundPlaySamples' module: 'SoundPlugin'>\\n\\t^ self primitiveFailed\\n! !\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'JMM 11/6/2000 10:14'!\\nprimSoundSetVolumeLeft: aLeftVolume volumeRight: aRightVolume\\n\\t\\\"Set sound pass in float 0.0-1.0 for left and right channel, with possible 2.0 or higher to overdrive sound channel \\\"\\n\\t<primitive: 'primitiveSoundSetLeftVolume' module: 'SoundPlugin'>\\n! !\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nprimSoundStartBufferSize: bufferSize rate: samplesPerSecond stereo: stereoFlag\\n\\t\\\"Start double-buffered sound output with the given buffer size and sampling rate. This version has been superceded by primitive 171 (primSoundStartBufferSize:rate:stereo:semaIndex:).\\\"\\n\\t\\\"ar 12/5/1998 Turn off the sound if not supported\\\"\\n\\t<primitive: 'primitiveSoundStart' module: 'SoundPlugin'>\\n\\tSoundSupported := false.! !\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nprimSoundStartBufferSize: bufferSize rate: samplesPerSecond stereo: stereoFlag semaIndex: anInteger\\n\\t\\\"Start double-buffered sound output with the given buffer size and sampling rate. If the given semaphore index is > 0, it is taken to be the index of a Semaphore in the external objects array to be signalled when the sound driver is ready to accept another buffer of samples.\\\"\\n\\t\\\"Details: If this primitive fails, this method tries to use the older version instead.\\\"\\n\\n\\t<primitive: 'primitiveSoundStartWithSemaphore' module: 'SoundPlugin'>\\n\\tUseReadySemaphore := false.\\n\\tself primSoundStartBufferSize: bufferSize rate: samplesPerSecond stereo: stereoFlag.\\n! !\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'tpr 2/2/2001 19:46'!\\nprimSoundStop\\n\\t\\\"Stop double-buffered sound output. Must not raise an error because it is used inside error handling and at system shutdown\\\"\\n\\n\\t<primitive: 'primitiveSoundStop' module: 'SoundPlugin'>! !\\n\\n!SoundPlayer class methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstartPlayingImmediately: aSound\\n\\t\\\"Private!! Start playing the given sound as soon as possible by mixing it into the sound output buffers of the underlying sound driver.\\\"\\n\\n\\t| totalSamples buf n leftover src rest |\\n\\t\\\"first, fill a double-size buffer with samples\\\"\\n\\t\\\"Note: The code below assumes that totalSamples contains two\\n\\t buffers worth of samples, and the insertSamples primitive is\\n\\t expected to consume at least one buffer's worth of these\\n\\t samples. The remaining samples are guaranteed to fit into\\n\\t a single buffer.\\\"\\n\\ttotalSamples := Buffer stereoSampleCount * 2. \\\"two buffer's worth\\\"\\n\\tbuf := SoundBuffer newStereoSampleCount: totalSamples.\\n\\taSound playSampleCount: totalSamples into: buf startingAt: 1.\\n\\tReverbState == nil ifFalse: [\\n\\t\\tReverbState applyReverbTo: buf startingAt: 1 count: totalSamples].\\n\\n\\tPlayerSemaphore critical: [\\n\\t\\t\\\"insert as many samples as possible into the sound driver's buffers\\\"\\n\\t\\tn := self primSoundInsertSamples: totalSamples\\n\\t\\t\\tfrom: buf\\n\\t\\t\\tsamplesOfLeadTime: 1024.\\n\\t\\tn > 0 ifTrue:[\\n\\t\\t\\tleftover := totalSamples - n.\\n\\n\\t\\t\\t\\\"copy the remainder of buf into Buffer\\\"\\n\\t\\t\\t\\\"Note: the following loop iterates over 16-bit words, not two-word stereo slices\\\"\\n\\t\\t\\t\\\"assert: 0 < leftover <= Buffer stereoSampleCount\\\"\\n\\t\\t\\tsrc := 2 * n.\\n\\t\\t\\t1 to: 2 * leftover do:\\n\\t\\t\\t\\t[:dst | Buffer at: dst put: (buf at: (src := src + 1))].\\n\\n\\t\\t\\t\\\"generate enough additional samples to finish filling Buffer\\\"\\n\\t\\t\\trest := Buffer stereoSampleCount - leftover.\\n\\t\\t\\taSound playSampleCount: rest into: Buffer startingAt: leftover + 1.\\n\\t\\t\\tReverbState == nil ifFalse: [\\n\\t\\t\\t\\tReverbState applyReverbTo: Buffer startingAt: leftover + 1 count: rest].\\n\\n\\t\\t\\t\\\"record the fact that this sound has already been played into Buffer so that we don't process it again this time around\\\"\\n\\t\\t\\tSoundJustStarted := aSound.\\n\\t\\t] ifFalse:[\\n\\t\\t\\t\\\"quick start failed; reset the sound so we start over\\\"\\n\\t\\t\\taSound reset.\\n\\t\\t].\\n\\t\\tActiveSounds add: aSound].\\n! !\\nStringReadoutTile subclass: #SoundReadoutTile\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting Tiles'!\\n!SoundReadoutTile commentStamp: 'sw 11/24/2003 15:25' prior: 0!\\nA tile comprising a readout for a sound-valued instance variable in a Viewer. It sports up/down arrows, and a click on the sound name results in a pop-up menu, offering the user the opportunity to choose a new one.!\\n\\n\\n!SoundReadoutTile methodsFor: 'arrows' stamp: 'sw 1/28/2005 00:57'!\\narrowAction: delta\\n\\t\\\"Do what is appropriate when an arrow on the tile is pressed; delta will be +1 or -1\\\"\\n\\n\\t| soundChoices index |\\n\\tsoundChoices _ self soundChoices.\\n\\tindex _ soundChoices indexOf: literal.\\n\\tself literal: (soundChoices atWrap: (index + delta)).\\n\\tself playSoundNamed: literal! !\\n\\n!SoundReadoutTile methodsFor: 'arrows' stamp: 'sw 11/24/2003 14:54'!\\nhandlerForMouseDown: anEvent\\n\\n\\t\\\"Return the (prospective) handler for a mouse down event. The handler is temporarily installed and can be used for morphs further down the hierarchy to negotiate whether the inner or the outer morph should finally handle the event\\\"\\n\\n\\n\\n\\t^ ((self findA: UpdatingStringMorph) bounds containsPoint: anEvent cursorPoint)\\n\\n\\t\\tifTrue:\\n\\n\\t\\t\\t[self]\\n\\n\\t\\tifFalse:\\n\\n\\t\\t\\t[super handlerForMouseDown: anEvent]! !\\n\\n!SoundReadoutTile methodsFor: 'arrows' stamp: 'sw 1/28/2005 00:56'!\\nmouseDown: evt\\n\\t\\\"Handle a mouse down event\\\"\\n\\n\\t| aPoint index isUp soundChoices adjustment |\\n\\tupArrow ifNotNil: [((isUp _ upArrow containsPoint: (aPoint _ evt cursorPoint)) or: [downArrow containsPoint: aPoint])\\n\\t\\tifTrue:\\n\\t\\t\\t[soundChoices _ self soundChoices.\\n\\t\\t\\tindex _ soundChoices indexOf: literal ifAbsent: [1].\\n\\t\\t\\tindex > 0 ifTrue:\\n\\t\\t\\t\\t[adjustment _ isUp ifTrue: [1] ifFalse: [-1].\\n\\t\\t\\t\\tself literal: (soundChoices atWrap: (index + adjustment))].\\n\\t\\t\\tself playSoundNamed: literal.\\n\\t\\t\\t^ self]].\\n\\tself soundNameFromUser ifNotNilDo:\\n\\t\\t[:aSoundName |\\n\\t\\t\\tself literal: aSoundName.\\n\\t\\t\\tself playSoundNamed: literal]! !\\n\\n!SoundReadoutTile methodsFor: 'arrows' stamp: 'yo 2/11/2005 16:12'!\\nsetLiteral: aLiteral\\n\\n\\tsuper setLiteral: aLiteral.\\n\\n\\t(self findA: UpdatingStringMorph) useSymbolFormat; lock! !\\n\\n!SoundReadoutTile methodsFor: 'arrows' stamp: 'yo 2/11/2005 16:08'!\\nsoundNameFromUser\\n\\t\\\"Obtain a sound from the user. Exclude the items designated as being discouraged, except that if the current selection is one of those, show it anyway\\\"\\n\\n\\t| choices |\\n\\tchoices _ self soundChoices.\\n\\t^ (SelectionMenu labels: (choices collect: [:t | t translated]) selections: self soundChoices) startUpWithCaption: 'Sounds' translated! !\\n\\n\\n!SoundReadoutTile methodsFor: 'literal' stamp: 'sw 1/28/2005 00:57'!\\nsetLiteralTo: anObject width: w\\n\\t\\\"Set the literal and width of the tile as indicated\\\"\\n\\n\\t| soundChoices index |\\n\\tsoundChoices _ self soundChoices.\\n\\tindex _ soundChoices indexOf: anObject.\\n\\tself setLiteral: (soundChoices atWrap: index)! !\\n\\n\\n!SoundReadoutTile methodsFor: 'private' stamp: 'yo 2/11/2005 16:13'!\\nupdateLiteralLabel\\n\\n\\t\\\"Update the wording emblazoned on the tile, if needed\\\"\\n\\n\\n\\n\\tsuper updateLiteralLabel.\\n\\n\\t(self findA: UpdatingStringMorph) useSymbolFormat; lock! !\\nObject subclass: #SoundRecorder\\n\\tinstanceVariableNames: 'stereo samplingRate recordLevel recordedBuffers recordedSound recordProcess bufferAvailableSema paused meteringBuffer meterLevel soundPlaying currentBuffer nextIndex codec desiredSampleRate'\\n\\tclassVariableNames: 'CanRecordWhilePlaying RecorderActive'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n\\n!SoundRecorder methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncodec: aSoundCodec\\n\\n\\tcodec := aSoundCodec! !\\n\\n!SoundRecorder methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ndesiredSampleRate: newRate\\n\\n\\t\\\"use of this method indicates a strong desire for the specified rate, even if\\n\\tthe OS/hardware are not cooperative\\\"\\n\\n\\tdesiredSampleRate := samplingRate := newRate \\\"Best are 44100 22050 11025\\\"\\n! !\\n\\n!SoundRecorder methodsFor: 'accessing' stamp: 'jj 10/20/97 15:30'!\\nisActive\\n\\t\\\"Return true if I have a recordProcess running.\\\"\\n\\n\\t^ recordProcess ~~ nil\\n! !\\n\\n!SoundRecorder methodsFor: 'accessing' stamp: 'jm 9/2/97 16:16'!\\nisPaused\\n\\t\\\"Return true if recording is paused.\\\"\\n\\n\\t^ paused\\n! !\\n\\n!SoundRecorder methodsFor: 'accessing' stamp: 'jm 9/18/97 19:19'!\\nmeterLevel\\n\\t\\\"Return the meter level, an integer in the range [0..100] where zero is silence and 100 represents the maximum signal level possible without clipping.\\\"\\n\\n\\t^ (100 * meterLevel) // 32768\\n! !\\n\\n!SoundRecorder methodsFor: 'accessing' stamp: 'jm 7/4/1998 15:03'!\\nrecordLevel\\n\\n\\t^ recordLevel\\n! !\\n\\n!SoundRecorder methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nrecordLevel: level\\n\\t\\\"Set the desired recording level to the given value in the range 0.0 to 1.0, where 0.0 is the lowest recording level and 1.0 is the maximum. Do nothing if the sound input hardware does not support changing the recording level.\\\"\\n\\t\\\"Details: On the Macintosh, the lowest possible record level attenuates the input signal, but does not silence it entirely.\\\" \\n\\n\\trecordLevel := (level asFloat min: 1.0) max: 0.0.\\n\\trecordProcess ifNotNil: [\\n\\t\\tself primSetRecordLevel: (1000.0 * recordLevel) asInteger].\\n! !\\n\\n!SoundRecorder methodsFor: 'accessing' stamp: 'jm 12/15/97 14:28'!\\nsamplingRate\\n\\n\\t^ samplingRate\\n! !\\n\\n!SoundRecorder methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsamplingRate: newRate\\n\\n\\tsamplingRate := newRate \\\"Best are 44100 22050 11025\\\"\\n! !\\n\\n\\n!SoundRecorder methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitialize\\n\\t\\\"SoundRecorder new\\\"\\n\\n\\tstereo := false.\\n\\tsamplingRate := 11025.\\n\\trecordLevel := 0.5.\\n\\tself initializeRecordingState.\\n! !\\n\\n!SoundRecorder methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitializeRecordingState\\n\\n\\trecordProcess := nil.\\n\\tbufferAvailableSema := nil.\\n\\tpaused := true.\\n\\tmeteringBuffer := nil.\\n\\tmeterLevel := 0.\\n\\tsoundPlaying := nil.\\n\\tcurrentBuffer := nil.\\n\\tnextIndex := 1.\\n! !\\n\\n\\n!SoundRecorder methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimGetActualRecordingSampleRate\\n\\t\\\"Return the actual sample rate being used for recording. This primitive fails unless sound recording is currently in progress.\\\"\\n\\n\\t<primitive: 'primitiveSoundGetRecordingSampleRate' module: 'SoundPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!SoundRecorder methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimRecordSamplesInto: aWordArray startingAt: index\\n\\t\\\"Record a sequence of 16-bit sound samples into the given array starting at the given sample index. Return the number of samples recorded, which may be zero if no samples are currently available.\\\"\\n\\n\\t<primitive: 'primitiveSoundRecordSamples' module: 'SoundPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!SoundRecorder methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSetRecordLevel: anInteger\\n\\t\\\"Set the desired recording level to the given value in the range 0-1000, where 0 is the lowest recording level and 1000 is the maximum. Do nothing if the sound input hardware does not support changing the recording level.\\\"\\n\\n\\t<primitive: 'primitiveSoundSetRecordLevel' module: 'SoundPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!SoundRecorder methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimStartRecordingDesiredSampleRate: samplesPerSec stereo: stereoFlag semaIndex: anInteger\\n\\t\\\"Start sound recording with the given stereo setting. Use a sampling rate as close to the desired rate as the underlying platform will support. If the given semaphore index is > 0, it is taken to be the index of a Semaphore in the external objects array to be signalled every time a recording buffer is filled.\\\"\\n\\n\\t<primitive: 'primitiveSoundStartRecording' module: 'SoundPlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!SoundRecorder methodsFor: 'primitives' stamp: 'tpr 2/15/2001 17:13'!\\nprimStopRecording\\n\\t\\\"Stop sound recording. Does nothing if recording is not currently in progress. Do not fail if plugin is not available\\\"\\n\\n\\t<primitive: 'primitiveSoundStopRecording' module: 'SoundPlugin'>! !\\n\\n\\n!SoundRecorder methodsFor: 'recording controls' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nclearRecordedSound\\n\\t\\\"Clear the sound recorded thus far. Go into pause mode if currently recording.\\\"\\n\\n\\tpaused := true.\\n\\trecordedSound := SequentialSound new.\\n\\tself allocateBuffer.\\n! !\\n\\n!SoundRecorder methodsFor: 'recording controls' stamp: 'sw 6/10/2003 12:34'!\\nhasRecordedSound\\n\\n\\t\\\"Answer whether the receiver currently has any recorded sound\\\"\\n\\n\\n\\n\\t^ self recordedSound notNil! !\\n\\n!SoundRecorder methodsFor: 'recording controls' stamp: 'stephaneducasse 2/4/2006 20:41'!\\npause\\n\\t\\\"Go into pause mode. The record level continues to be updated, but no sound is recorded.\\\"\\n\\n\\tpaused := true.\\n\\t((currentBuffer ~~ nil) and: [nextIndex > 1])\\n\\t\\tifTrue: [self emitPartialBuffer.\\n\\t\\t\\t\\tself allocateBuffer].\\n\\n\\tsoundPlaying ifNotNil: [\\n\\t\\tsoundPlaying pause.\\n\\t\\tsoundPlaying := nil].\\n\\t\\\"Note: there can be problems if canRecordWhilePlaying is true. Recorders which only pause will inhibit other recorders from recording. I chose to make #stopPlaying unconditional in a subclass. The same might be appropriate here at the expense of making recorders resumable\\\"\\n\\n\\tPreferences canRecordWhilePlaying ifFalse: [self stopRecording].\\n! !\\n\\n!SoundRecorder methodsFor: 'recording controls' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nplayback\\n\\t\\\"Playback the sound that has been recorded.\\\"\\n\\n\\tself pause.\\n\\tsoundPlaying := self recordedSound.\\n\\tsoundPlaying play.\\n! !\\n\\n!SoundRecorder methodsFor: 'recording controls' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nresumeRecording\\n\\t\\\"Continue recording from the point at which it was last paused.\\\"\\n\\n\\tself flag: #bob.\\n\\t\\\"Note: If canRecordWhilePlaying is true, then recordings may never get started (at least by this method). One possibility, used in a subclass, is to make the #startPlaying unconditional. Another would be to use #startPlaying instead of #resumePlaying in appropriate cases\\\"\\n\\n\\tPreferences canRecordWhilePlaying ifFalse: [self startRecording].\\n\\tpaused := false.\\n! !\\n\\n!SoundRecorder methodsFor: 'recording controls' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstartRecording\\n\\t\\\"Turn of the sound input driver and start the recording process. Initially, recording is paused.\\\"\\n\\n\\t| semaIndex |\\n\\trecordLevel ifNil: [recordLevel := 0.5]. \\\"lazy initialization\\\"\\n\\tPreferences canRecordWhilePlaying ifFalse: [SoundPlayer shutDown].\\n\\trecordProcess ifNotNil: [self stopRecording].\\n\\tpaused := true.\\n\\tmeteringBuffer := SoundBuffer newMonoSampleCount: 1024.\\n\\tmeterLevel := 0.\\n\\tself allocateBuffer.\\n\\tbufferAvailableSema := Semaphore new.\\n\\tsemaIndex := Smalltalk registerExternalObject: bufferAvailableSema.\\n\\tself primStartRecordingDesiredSampleRate: samplingRate asInteger\\n\\t\\tstereo: stereo\\n\\t\\tsemaIndex: semaIndex.\\n\\tRecorderActive := true.\\n\\tsamplingRate := self primGetActualRecordingSampleRate.\\n\\tself primSetRecordLevel: (1000.0 * recordLevel) asInteger.\\n\\trecordProcess := [self recordLoop] newProcess.\\n\\trecordProcess priority: Processor userInterruptPriority.\\n\\trecordProcess resume.\\n! !\\n\\n!SoundRecorder methodsFor: 'recording controls' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstopRecording\\n\\t\\\"Stop the recording process and turn of the sound input driver.\\\"\\n\\n\\trecordProcess ifNotNil: [recordProcess terminate].\\n\\trecordProcess := nil.\\n\\tself primStopRecording.\\n\\tRecorderActive := false.\\n\\tSmalltalk unregisterExternalObject: bufferAvailableSema.\\n\\t((currentBuffer ~~ nil) and: [nextIndex > 1])\\n\\t\\tifTrue: [self emitPartialBuffer].\\n\\tself initializeRecordingState.\\n! !\\n\\n!SoundRecorder methodsFor: 'recording controls' stamp: 'sw 3/3/2004 19:49'!\\nverifyExistenceOfRecordedSound\\n\\n\\t\\\"If the receiver has a recorded sound, answer true; if not, put up an informer and answer false\\\"\\n\\n\\n\\n\\t^ self recordedSound\\n\\n\\t\\tifNotNil:\\n\\n\\t\\t\\t[true]\\n\\n\\t\\tifNil:\\n\\n\\t\\t\\t[self inform: 'please record a sound first' translated.\\n\\n\\t\\t\\tfalse]! !\\n\\n\\n!SoundRecorder methodsFor: 'results' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncondensedSamples\\n\\t\\\"Return a single SoundBuffer that is the contatenation of all my recorded buffers.\\\"\\n\\n\\t| sz newBuf i |\\n\\trecordedBuffers := recordedSound sounds collect: [:snd | snd samples].\\n\\trecordedBuffers isEmpty ifTrue: [^ SoundBuffer new: 0].\\n\\trecordedBuffers size = 1 ifTrue: [^ recordedBuffers first copy].\\n\\tsz := recordedBuffers inject: 0 into: [:tot :buff | tot + buff size].\\n\\tnewBuf := SoundBuffer newMonoSampleCount: sz.\\n\\ti := 1.\\n\\trecordedBuffers do: [:b |\\n\\t\\t1 to: b size do: [:j |\\n\\t\\t\\tnewBuf at: i put: (b at: j).\\n\\t\\t\\ti := i + 1]].\\n\\trecordedBuffers := nil.\\n\\t^ newBuf\\n! !\\n\\n!SoundRecorder methodsFor: 'results' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncondensedStereoSound\\n\\t\\\"Decompose my buffers into left and right channels and return a mixed sound consisting of the those two channels. This may be take a while, since the data must be copied into new buffers.\\\"\\n\\n\\t| sz leftBuf rightBuf leftI rightI left |\\n\\tsz := recordedBuffers inject: 0 into: [:tot :buff | tot + buff size].\\n\\tleftBuf := SoundBuffer newMonoSampleCount: (sz + 1) // 2.\\n\\trightBuf := SoundBuffer newMonoSampleCount: (sz + 1) // 2.\\n\\tleftI := rightI := 1.\\n\\tleft := true.\\n\\trecordedBuffers do: [:b |\\n\\t\\t1 to: b size do: [:j |\\n\\t\\t\\tleft\\n\\t\\t\\t\\tifTrue: [leftBuf at: leftI put: (b at: j). leftI := leftI + 1. left := false]\\n\\f\\t\\t\\t\\tifFalse: [rightBuf at: rightI put: (b at: j). rightI := rightI + 1. left := true]]].\\n\\t^ MixedSound new\\n\\t\\tadd: (SampledSound new setSamples: leftBuf samplingRate: samplingRate) pan: 0.0;\\n\\t\\tadd: (SampledSound new setSamples: rightBuf samplingRate: samplingRate) pan: 1.0\\n! !\\n\\n!SoundRecorder methodsFor: 'results' stamp: 'di 2/17/1999 11:07'!\\nrecordedSound\\n\\t\\\"Return the sound that was recorded.\\\"\\n\\n\\t^ recordedSound\\n! !\\n\\n!SoundRecorder methodsFor: 'results' stamp: 'di 2/17/1999 21:24'!\\nsoundSegments\\n\\n\\t^ self segmentsAbove: 1000 normalizedVolume: 80.0\\n! !\\n\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncopyFrom: startPlace to: endPlace normalize: nFactor dcOffset: dcOffset\\n\\t\\\"Return a new SoundBuffer containing the samples in the given range.\\\"\\n\\n\\t| startBufIndex startSampleIndex endBufIndex endSampleIndex\\n\\t count resultBuf j buf firstInBuf n |\\n\\tstartBufIndex := startPlace at: 1.\\n\\tstartSampleIndex := startPlace at: 2.\\n\\tendBufIndex := endPlace at: 1.\\n\\tendSampleIndex := endPlace at: 2.\\n\\n\\tstartBufIndex = endBufIndex\\n\\t\\tifTrue: [count := endSampleIndex + 1 - startSampleIndex]\\n\\t\\tifFalse: [\\n\\t\\t\\tcount := ((recordedBuffers at: startBufIndex) size + 1 - startSampleIndex). \\\"first buffer\\\"\\n\\t\\t\\tcount := count + endSampleIndex. \\\"last buffer\\\"\\n\\t\\t\\tstartBufIndex + 1 to: endBufIndex - 1 do:\\n\\t\\t\\t\\t[:i | count := count + (recordedBuffers at: i) size]]. \\\"middle buffers\\\"\\n\\tresultBuf := SoundBuffer newMonoSampleCount: count.\\n\\n\\tj := 1. \\\"next destination index in resultBuf\\\"\\n\\tstartBufIndex to: endBufIndex do: [:i |\\n\\t\\tbuf := recordedBuffers at: i.\\n\\t\\tfirstInBuf := 1.\\n\\t \\tn := buf size.\\n\\t\\ti = startBufIndex ifTrue: [\\n\\t\\t\\tn := (recordedBuffers at: startBufIndex) size + 1 - startSampleIndex.\\n\\t\\t\\tfirstInBuf := startSampleIndex].\\n\\t\\ti = endBufIndex ifTrue: [\\n\\t\\t\\ti = startBufIndex\\n\\t\\t\\t\\tifTrue: [n := endSampleIndex + 1 - startSampleIndex]\\n\\t\\t\\t\\tifFalse: [n := endSampleIndex]].\\n\\t\\tself copyTo: resultBuf from: j to: (j + n - 1)\\n\\t\\t\\tfrom: buf startingAt: firstInBuf\\n\\t\\t\\tnormalize: nFactor dcOffset: dcOffset.\\n\\t\\tj := j + n].\\n\\t^ resultBuf\\n! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncopyTo: resultBuf from: startIndex to: endIndex from: buf startingAt: firstInBuf normalize: nFactor dcOffset: dcOffset\\n\\t\\\"Copy samples from buf to resultBuf removing the DC offset and normalizing their volume in the process.\\\"\\n\\n\\t| indexOffset |\\n\\tindexOffset := firstInBuf - startIndex.\\n\\tstartIndex to: endIndex do: [:i |\\n\\t\\tresultBuf at: i put: (((buf at: (i + indexOffset)) - dcOffset) * nFactor) // 1000].\\n! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'di 2/16/1999 22:11'!\\nendPlace\\n\\n\\t^ Array with: recordedBuffers size with: recordedBuffers last size! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nfirstSampleOverThreshold: threshold dcOffset: dcOffset startingAt: startPlace\\n\\t\\\"Beginning at startPlace, this routine will return the first place at which a sample exceeds the given threshold.\\\"\\n\\n\\t| buf s iStart jStart nThreshold |\\n\\tnThreshold := threshold negated.\\n\\tiStart := startPlace first.\\n\\tjStart := startPlace second.\\n\\tiStart to: recordedBuffers size do:\\n\\t\\t[:i | buf := recordedBuffers at: i.\\n\\t\\tjStart to: buf size do:\\n\\t\\t\\t[:j | s := (buf at: j) - dcOffset.\\n\\t\\t\\t(s < nThreshold or: [s > threshold]) ifTrue:\\n\\t\\t\\t\\t[\\\"found a sample over threshold\\\"\\n\\t\\t\\t\\t^ Array with: i with: j]].\\n\\t\\tjStart := 1].\\n\\t^ self endPlace! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nnormalizeFactorFor: percentOfMaxVolume min: min max: max dcOffset: dcOffset\\n\\t\\\"Return a normalization factor for the range of sample values and DC offset. A normalization factor is a fixed-point number that will be divided by 1000 after multiplication with each sample value.\\\"\\n\\n\\t| peak factor |\\n\\tpeak := (max - dcOffset) max: (min - dcOffset) negated.\\n\\tpeak = 0 ifTrue: [^ 1000].\\n\\tfactor := (32767.0 * percentOfMaxVolume) / (100.0 * peak).\\n\\t^ (factor * 1000.0) asInteger\\n! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nplace: startPlace plus: nSamples\\n\\t\\\"Return the place that is nSamples (may be negative) beyond thisPlace.\\\"\\n\\n\\t| i j remaining buf |\\n\\ti := startPlace first.\\n\\tj := startPlace second.\\n\\tnSamples >= 0\\n\\tifTrue: [remaining := nSamples.\\n\\t\\t\\t[buf := recordedBuffers at: i.\\n\\t\\t\\t(j + remaining) <= buf size ifTrue: [^ Array with: i with: j + remaining].\\n\\t\\t\\ti < recordedBuffers size]\\n\\t\\t\\t\\twhileTrue: [remaining := remaining - (buf size - j + 1).\\n\\t\\t\\t\\t\\t\\t\\ti := i+1. j := 1].\\n\\t\\t\\t^ self endPlace]\\n\\tifFalse: [remaining := nSamples negated.\\n\\t\\t\\t[buf := recordedBuffers at: i.\\n\\t\\t\\t(j - remaining) >= 1 ifTrue: [^ Array with: i with: j - remaining].\\n\\t\\t\\ti > 1]\\n\\t\\t\\t\\twhileTrue: [remaining := remaining - j.\\n\\t\\t\\t\\t\\t\\t\\ti := i-1. j := (recordedBuffers at: i) size].\\n\\t\\t\\t^ #(1 1)]! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nscanForEndThreshold: threshold dcOffset: dcOffset minLull: lull startingAt: startPlace\\n\\t\\\"Beginning at startPlace, this routine will find the last sound that exceeds threshold, such that if you look lull samples later you will not find another sound over threshold within the following block of lull samples.\\n\\tReturn the place that is lull samples beyond to that last sound.\\n\\tIf no end of sound is found, return endPlace.\\\"\\n\\n\\t| buf s iStart jStart nThreshold n |\\n\\tnThreshold := threshold negated.\\n\\tiStart := startPlace first.\\n\\tjStart := startPlace second.\\n\\tn := 0.\\n\\tiStart to: recordedBuffers size do:\\n\\t\\t[:i | buf := recordedBuffers at: i.\\n\\t\\tjStart to: buf size do:\\n\\t\\t\\t[:j | s := (buf at: j) - dcOffset.\\n\\t\\t\\t(s < nThreshold or: [s > threshold])\\n\\t\\t\\t\\tifTrue: [\\\"found a sample over threshold\\\"\\n\\t\\t\\t\\t\\t\\tn := 0]\\n\\t\\t\\t\\tifFalse: [\\\"still not over threshold\\\"\\n\\t\\t\\t\\t\\t\\tn := n + 1.\\n\\t\\t\\t\\t\\t\\tn >= lull ifTrue: [^ Array with: i with: j]]].\\n\\t\\tjStart := 1].\\n\\t^ self endPlace! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nscanForStartThreshold: threshold dcOffset: dcOffset minDur: duration startingAt: startPlace\\n\\t\\\"Beginning at startPlace, this routine will find the first sound that exceeds threshold, such that if you look duration samples later you will find another sound over threshold within the following block of duration samples.\\n\\tReturn the place that is duration samples prior to that first sound.\\n\\tIf no sound is found, return endPlace.\\\"\\n\\n\\t| soundPlace lookPlace nextSoundPlace thirdPlace |\\n\\tsoundPlace := self firstSampleOverThreshold: threshold dcOffset: dcOffset\\n\\t\\t\\t\\t\\tstartingAt: startPlace.\\n\\t[soundPlace = self endPlace ifTrue: [^ soundPlace].\\n\\t\\\"Found a sound -- look duration later\\\"\\n\\tlookPlace := self place: soundPlace plus: duration.\\n\\tnextSoundPlace := self firstSampleOverThreshold: threshold dcOffset: dcOffset\\n\\t\\t\\t\\t\\tstartingAt: lookPlace.\\n\\tthirdPlace := self place: lookPlace plus: duration.\\n\\tnextSoundPlace first < thirdPlace first\\n\\t\\tor: [nextSoundPlace first = thirdPlace first\\n\\t\\t\\tand: [nextSoundPlace second < thirdPlace second]]]\\n\\t\\twhileFalse: [soundPlace := nextSoundPlace].\\n\\n\\t\\\"Yes, there is sound in the next interval as well\\\"\\n\\t^ self place: soundPlace plus: 0-duration\\n! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsegmentsAbove: threshold normalizedVolume: percentOfMaxVolume\\n\\t\\\"Break the current recording up into a sequence of sound segments separated by silences.\\\"\\n\\n\\t| max min sum totalSamples bufSize s dcOffset firstPlace endPlace resultBuf nFactor lastPlace segments gapSize minDur minLull soundSize restSize |\\n\\tstereo ifTrue: [self error: 'stereo trimming is not yet supported'].\\n\\tpaused ifFalse: [self error: 'must stop recording before trimming'].\\n\\t(recordedSound == nil or: [recordedSound sounds isEmpty]) ifTrue:[^ self].\\n\\t\\\"Reconstruct buffers so old trimming code will work\\\"\\n\\trecordedBuffers := recordedSound sounds collect: [:snd | snd samples].\\n\\tsoundSize := restSize := 0.\\n\\n\\tmax := min := sum := totalSamples := 0.\\n\\trecordedBuffers do: [:buf |\\n\\t\\tbufSize := buf size.\\n\\t\\ttotalSamples := totalSamples + buf size.\\n\\t\\t1 to: bufSize do: [:i |\\n\\t\\t\\ts := buf at: i.\\n\\t\\t\\ts > max ifTrue: [max := s].\\n\\t\\t\\ts < min ifTrue: [min := s].\\n\\t\\t\\tsum := sum + s]].\\n\\tdcOffset := sum // totalSamples.\\n\\n\\tminDur := (samplingRate/20.0) asInteger. \\\" 1/20 second \\\"\\n\\tminLull := (samplingRate/4.0) asInteger. \\\" 1/2 second \\\"\\n\\tsegments := SequentialSound new.\\n\\tendPlace := self endPlace.\\n\\tlastPlace := #(1 1).\\n\\t[firstPlace := self scanForStartThreshold: threshold\\n\\t\\t\\t\\t\\t\\tdcOffset: dcOffset\\n\\t\\t\\t\\t\\t\\tminDur: minDur\\n\\t\\t\\t\\t\\t\\tstartingAt: lastPlace.\\n\\tfirstPlace = endPlace]\\n\\t\\twhileFalse:\\n\\t\\t[firstPlace = lastPlace ifFalse:\\n\\t\\t\\t[\\\"Add a silence equal to the gap size\\\"\\n\\t\\t\\t\\\"Wasteful but simple way to get gap size...\\\"\\n\\t\\t\\tgapSize := (self copyFrom: lastPlace to: firstPlace\\n\\t\\t\\t\\t\\t\\tnormalize: 1000 dcOffset: dcOffset) size - 2.\\n\\t\\t\\t\\\"... -2 makes up for overlap of one sample on either end\\\"\\n\\t\\t\\tsegments add: (RestSound dur: gapSize asFloat / samplingRate).\\n\\t\\t\\trestSize := restSize + gapSize.\\n\\\"Transcript cr; print: firstPlace; space; print: lastPlace; space; print: gapSize; space; show: 'gap'.\\\"\\n\\t\\t\\t].\\n\\t\\tlastPlace := self scanForEndThreshold: threshold\\n\\t\\t\\t\\t\\t\\tdcOffset: dcOffset\\n\\t\\t\\t\\t\\t\\tminLull: minLull + minDur\\n\\t\\t\\t\\t\\t\\tstartingAt: firstPlace.\\n\\t\\t\\\"Allow room for lead time of next sound\\\"\\n\\t\\tlastPlace := self place: lastPlace plus: minDur negated.\\n\\t\\tnFactor := self normalizeFactorFor: percentOfMaxVolume\\n\\t\\t\\t\\t\\t\\tmin: min max: max dcOffset: dcOffset.\\n\\t\\tresultBuf := self copyFrom: firstPlace to: lastPlace\\n\\t\\t\\t\\t\\t\\tnormalize: nFactor dcOffset: dcOffset.\\n\\t\\tsoundSize := soundSize + resultBuf size.\\n\\\"Transcript cr; print: firstPlace; space; print: lastPlace; space; print: resultBuf size; space; show: 'sound'.\\\"\\n\\t\\tsegments add: (codec == nil\\n\\t\\t\\tifTrue: [SampledSound new setSamples: resultBuf samplingRate: samplingRate]\\n\\t\\t\\tifFalse: [codec compressSound: (SampledSound new setSamples: resultBuf samplingRate: samplingRate)])].\\n\\n\\t\\\"Final gap for consistency\\\"\\n\\tgapSize := (self copyFrom: lastPlace to: self endPlace\\n\\t\\t\\t\\tnormalize: 1000 dcOffset: dcOffset) size - 1.\\n\\tsegments add: (RestSound dur: gapSize asFloat / samplingRate).\\n\\trestSize := restSize + gapSize.\\n\\tself inform: ((soundSize+restSize/samplingRate) roundTo: 0.1) printString , ' secs reduced to ' , ((soundSize/samplingRate) roundTo: 0.1) printString.\\n\\trecordedBuffers := nil.\\n\\t^ segments! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsuppressSilence\\n\\n\\trecordedSound := self soundSegments! !\\n\\n!SoundRecorder methodsFor: 'trimming' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ntrim: threshold normalizedVolume: percentOfMaxVolume\\n\\t\\\"Remove the leading and trailing parts of this recording that are below the given threshold. Remove any DC offset and scale the recording so that its peaks are the given percent of the maximum volume.\\\"\\n\\n\\t| max min sum totalSamples bufSize s dcOffset startPlace endPlace resultBuf nFactor |\\n\\tstereo ifTrue: [self error: 'stereo trimming is not yet supported'].\\n\\tpaused ifFalse: [self error: 'must stop recording before trimming'].\\n\\trecordedBuffers := recordedSound sounds collect: [:snd | snd samples].\\n\\trecordedBuffers isEmpty ifTrue: [^ self].\\n\\n\\tmax := min := sum := totalSamples := 0.\\n\\trecordedBuffers do: [:buf |\\n\\t\\tbufSize := buf size.\\n\\t\\ttotalSamples := totalSamples + buf size.\\n\\t\\t1 to: bufSize do: [:i |\\n\\t\\t\\ts := buf at: i.\\n\\t\\t\\ts > max ifTrue: [max := s].\\n\\t\\t\\ts < min ifTrue: [min := s].\\n\\t\\t\\tsum := sum + s]].\\n\\tdcOffset := sum // totalSamples.\\n\\n\\t\\\"a place is an array of <buffer index><index of sample in buffer>\\\"\\n\\tstartPlace := self scanForStartThreshold: threshold\\n\\t\\t\\t\\t\\tdcOffset: dcOffset\\n\\t\\t\\t\\t\\tminDur: (samplingRate/60.0) asInteger \\\"at least 1/60th of a second\\\"\\n\\t\\t\\t\\t\\tstartingAt: #(1 1).\\n\\tstartPlace = self endPlace ifTrue:\\n\\t\\t[\\\"no samples above threshold\\\"\\n\\t\\trecordedBuffers := nil. ^ self].\\n\\n\\tendPlace := self scanForEndThreshold: threshold\\n\\t\\t\\t\\t\\tdcOffset: dcOffset\\n\\t\\t\\t\\t\\tminLull: (samplingRate/5) asInteger\\n\\t\\t\\t\\t\\tstartingAt: startPlace.\\n\\tnFactor := self normalizeFactorFor: percentOfMaxVolume min: min max: max dcOffset: dcOffset.\\n\\tresultBuf := self copyFrom: startPlace to: endPlace normalize: nFactor dcOffset: dcOffset.\\n\\trecordedSound := SampledSound new setSamples: resultBuf samplingRate: samplingRate.\\n\\trecordedBuffers := nil\\n! !\\n\\n\\n!SoundRecorder methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nallocateBuffer\\n\\t\\\"Allocate a new buffer and reset nextIndex.\\\"\\n\\n\\t| bufferTime |\\n\\tbufferTime := stereo \\\"Buffer time = 1/2 second\\\"\\n\\t\\tifTrue: [self samplingRate asInteger]\\n\\t\\tifFalse: [self samplingRate asInteger // 2].\\n\\tcurrentBuffer := SoundBuffer newMonoSampleCount:\\n\\t\\t\\\"Multiple of samplesPerFrame that is approx. bufferTime long\\\"\\n\\t\\t(bufferTime truncateTo: self samplesPerFrame).\\n\\tnextIndex := 1.\\n! !\\n\\n!SoundRecorder methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nemitBuffer: buffer\\n\\n\\t| sound ratio resultBuf |\\n\\n\\t\\\"since some sound recording devices cannot (or will not) record below a certain sample rate,\\n\\ttrim the samples down if the user really wanted fewer samples\\\"\\n\\n\\t(desiredSampleRate isNil or: [(ratio := samplingRate // desiredSampleRate) <= 1]) ifTrue: [\\n\\t\\tsound := SampledSound new setSamples: buffer samplingRate: samplingRate.\\n\\t] ifFalse: [\\n\\t\\tresultBuf := SoundBuffer \\n\\t\\t\\taverageEvery: ratio \\n\\t\\t\\tfrom: buffer \\n\\t\\t\\tupTo: buffer monoSampleCount.\\n\\t\\tsound := SampledSound new setSamples: resultBuf samplingRate: samplingRate / ratio.\\n\\t].\\n\\n\\trecordedSound add: (codec ifNil: [sound] ifNotNil: [codec compressSound: sound])! !\\n\\n!SoundRecorder methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nemitPartialBuffer\\n\\t| s |\\n\\ts := self samplesPerFrame.\\n\\tself emitBuffer: (currentBuffer copyFrom: 1 to: ((nextIndex-1) +( s-1) truncateTo: s))! !\\n\\n!SoundRecorder methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nmeterFrom: start count: count in: buffer\\n\\t\\\"Update the meter level with the maximum signal level in the given range of the given buffer.\\\"\\n\\n\\t| last max sample |\\n\\tcount = 0 ifTrue: [^ self]. \\\"no new samples\\\"\\n\\tlast := start + count - 1.\\n\\tmax := 0.\\n\\tstart to: last do: [:i |\\n\\t\\tsample := buffer at: i.\\n\\t\\tsample < 0 ifTrue: [sample := sample negated].\\n\\t\\tsample > max ifTrue: [max := sample]].\\n\\tmeterLevel := max.\\n! !\\n\\n!SoundRecorder methodsFor: 'private' stamp: 'dgd 4/4/2006 16:15'!\\nrecordLoop\\n\\t\\\"Record process loop that records samples.\\\"\\n\\n\\t| n sampleCount |\\n\\n\\tn := 0.\\n\\t[true] whileTrue: [\\n\\t\\tn = 0 ifTrue: [bufferAvailableSema wait].\\n\\t\\tpaused\\n\\t\\t\\tifTrue: [\\n\\t\\t\\t\\tn := self primRecordSamplesInto: meteringBuffer startingAt: 1.\\n\\t\\t\\t\\tself meterFrom: 1 count: n in: meteringBuffer]\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tn := self primRecordSamplesInto: currentBuffer startingAt: nextIndex.\\n\\t\\t\\t\\tself meterFrom: nextIndex count: n in: currentBuffer.\\n\\t\\t\\t\\tnextIndex := nextIndex + n.\\n\\t\\t\\t\\tstereo\\n\\t\\t\\t\\t\\tifTrue: [sampleCount := currentBuffer stereoSampleCount]\\n\\t\\t\\t\\t\\tifFalse: [sampleCount := currentBuffer monoSampleCount].\\n\\t\\t\\t\\tnextIndex > sampleCount\\n\\t\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\t\\tself emitBuffer: currentBuffer.\\n\\t\\t\\t\\t\\t\\tself allocateBuffer]].\\n\\n\\t\\t\\\"workaround for OSS emulation on top on ALSA (on Linux environments)\\\"\\n\\t\\t(Delay forMilliseconds: 20) wait.\\n\\t].\\n! !\\n\\n!SoundRecorder methodsFor: 'private' stamp: 'di 2/17/1999 10:39'!\\nsamplesPerFrame\\n\\t\\\"Can be overridden to quantize buffer size for, eg, fixed-frame codecs\\\"\\n\\n\\tcodec == nil\\n\\t\\tifTrue: [^ 1]\\n\\t\\tifFalse: [^ codec samplesPerFrame]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSoundRecorder class\\n\\tinstanceVariableNames: ''!\\n\\n!SoundRecorder class methodsFor: 'accessing' stamp: 'ar 2/1/2001 15:20'!\\nanyActive\\n\\t\\\"Return true if any sound recorder is actively recording\\\"\\n\\t^RecorderActive == true! !\\n\\n!SoundRecorder class methodsFor: 'accessing' stamp: 'RAA 8/7/2000 19:23'!\\ncanRecordWhilePlaying\\n\\t\\\"Return true if this platform supports simultaneous sound recording and playback.\\\"\\n\\n\\t^Preferences canRecordWhilePlaying.\\t\\t\\\"now in preferences\\\"\\n! !\\n\\n\\n!SoundRecorder class methodsFor: 'class initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitialize\\n\\t\\\"SoundRecorder initialize\\\"\\n\\t\\\"Details: Some computers cannot record and playback sound at the same time. If CanRecordWhilePlaying is false, then the SoundRecorder alternates between recording and playing. If it is true, sounds can be playing during recording.\\\"\\n\\n\\tCanRecordWhilePlaying := #ignoredNowInPreferences.\\n! !\\nRectangleMorph subclass: #SoundSequencerMorph\\n\\tinstanceVariableNames: 'controlPanel'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SoundInterface'!\\n\\n!SoundSequencerMorph methodsFor: 'as yet unclassified' stamp: 'tk 2/19/2001 18:14'!\\nmakeControlPanel\\n\\t| bb cc |\\n\\tcc _ Color black.\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tcontrolPanel _ AlignmentMorph newRow.\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tcontrolPanel color: bb color; borderWidth: 0; layoutInset: 0.\\n\\tcontrolPanel hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5@5.\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tcontrolPanel addMorphBack: (bb label: 'reset';\\tactionSelector: #reset).\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tcontrolPanel addMorphBack: (bb label: 'stop';\\t\\tactionSelector: #stop).\\n\\tbb _ SimpleButtonMorph new target: self; borderColor: cc.\\n\\tcontrolPanel addMorphBack: (bb label: 'play';\\tactionSelector: #play).\\n! !\\n\\n!SoundSequencerMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:08'!\\nplay\\n\\tself submorphsDo: [:m | m == controlPanel ifFalse: [m play]]! !\\n\\n!SoundSequencerMorph methodsFor: 'as yet unclassified' stamp: 'jm 11/14/97 11:08'!\\nreset\\n\\tself submorphsDo: [:m | m == controlPanel ifFalse: [m reset]]! !\\n\\n\\n!SoundSequencerMorph methodsFor: 'initialization' stamp: 'jm 11/14/97 11:21'!\\ninitialize\\n\\tsuper initialize.\\n\\tself extent: 550@350.\\n\\tself makeControlPanel.\\n\\tself addMorph: controlPanel.\\n\\tself addMorph: ((SoundLoopMorph newBounds: (10@40 extent: 128@128)) extent: 128@128).\\n\\tself addMorph: ((SoundLoopMorph newBounds: (10@200 extent: 512@128)) extent: 512@128).! !\\n\\n\\n!SoundSequencerMorph methodsFor: 'stepping and presenter' stamp: 'jm 11/14/97 11:21'!\\nstop\\n\\tself submorphsDo: [:m | m == controlPanel ifFalse: [m stop]].\\n\\tSoundPlayer shutDown! !\\nAppRegistry subclass: #SoundService\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Applications'!\\n!SoundService commentStamp: 'gk 2/24/2004 23:14' prior: 0!\\nThis is the AppRegistry class for the sound system.\\n\\nA sound system offers a small protocol for playing sounds and making beeps and works like a facade towards the rest of Squeak. A sound system is registered in this registry and can be accessed by \\\"SoundService default\\\". This way we decouple the sound system from the rest of Squeak and make it pluggable. It also is a perfect spot to check for the Preference class>>soundsEnabled.!\\n\\nTileMorph subclass: #SoundTile\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting Tiles'!\\n!SoundTile commentStamp: 'sw 1/28/2005 01:42' prior: 0!\\nA scripting tile representing a 'sound' constant. Sounds are represented by their names, which are strings; the actual sounds live in SampleSound's SoundLibrary.!\\n\\n\\n!SoundTile methodsFor: 'access' stamp: 'gk 2/23/2004 21:08'!\\nsound\\n\\n\\t^ SoundService default soundNamed: literal\\n! !\\n\\n\\n!SoundTile methodsFor: 'accessing' stamp: 'sw 9/27/2001 17:28'!\\nresultType\\n\\t\\\"Answer the result type of the receiver\\\"\\n\\n\\t^ #Sound! !\\n\\n\\n!SoundTile methodsFor: 'event handling' stamp: 'sw 1/28/2005 01:49'!\\noptions\\n\\t\\\"Answer the options of the tile for an arrow\\\"\\n\\n\\t| soundChoices |\\n\\tsoundChoices _ self soundChoices.\\n\\t^ {soundChoices. soundChoices}! !\\n\\n!SoundTile methodsFor: 'event handling' stamp: 'tak 12/5/2004 02:09'!\\nvalue: anObject \\n\\tsuper value: anObject.\\n\\tself playSoundNamed: anObject! !\\n\\n!SoundTile methodsFor: 'event handling' stamp: 'sw 11/3/97 02:11'!\\nwantsKeyboardFocusFor: aSubmorph\\n\\t^ false! !\\n\\n\\n!SoundTile methodsFor: 'initialization' stamp: 'yo 7/22/2005 15:51'!\\ninitialize\\n\\t\\\"Initialize the state of the receiver. Pick the croak sound\\n\\tif available, otherwise any sound.\\\"\\n\\t\\n\\t| soundChoices startingSoundName |\\n\\tsuper initialize.\\n\\tsoundChoices _ self soundChoices.\\n\\tstartingSoundName _ (soundChoices includes: 'croak')\\n\\t\\t\\t\\t\\t\\t\\tifTrue: ['croak']\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [[soundChoices anyOne] ifError: ['silence']].\\n\\tself addArrows; setLiteral: startingSoundName.\\n\\tself labelMorph useSymbolFormat! !\\n\\n!SoundTile methodsFor: 'initialization' stamp: 'yo 4/6/2005 16:34'!\\nsetLiteral: anObject\\n\\n\\tsuper setLiteral: anObject.\\n\\tself labelMorph useSymbolFormat\\n! !\\n\\n\\n!SoundTile methodsFor: 'mouse handling' stamp: 'sw 11/24/2003 14:44'!\\nhandlerForMouseDown: anEvent\\n\\n\\t\\\"Return the (prospective) handler for a mouse down event. The handler is temporarily installed and can be used for morphs further down the hierarchy to negotiate whether the inner or the outer morph should finally handle the event\\\"\\n\\n\\n\\n\\t^ ((self findA: UpdatingStringMorph) bounds containsPoint: anEvent cursorPoint)\\n\\n\\t\\tifTrue:\\n\\n\\t\\t\\t[self]\\n\\n\\t\\tifFalse:\\n\\n\\t\\t\\t[super handlerForMouseDown: anEvent]! !\\nDataType subclass: #SoundType\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Protocols-Type Vocabularies'!\\n\\n!SoundType methodsFor: 'initial value' stamp: 'sw 9/27/2001 17:29'!\\ninitialValueForASlotFor: aPlayer\\n\\t\\\"Answer the value to give initially to a newly created slot of the given type in the given player\\\"\\n\\n\\t^ 'croak'! !\\n\\n\\n!SoundType methodsFor: 'initialization' stamp: 'sw 9/27/2001 17:24'!\\ninitialize\\n\\t\\\"Initialize the receiver (automatically called when instances are created via 'new')\\\"\\n\\n\\tsuper initialize.\\n\\tself vocabularyName: #Sound! !\\n\\n\\n!SoundType methodsFor: '*eToys-color' stamp: 'sw 9/27/2001 17:21'!\\ntypeColor\\n\\t\\\"Answer the color for tiles to be associated with objects of this type\\\"\\n\\n\\t^ self subduedColorFromTriplet: #(1.0 0.06 0.84)\\t! !\\n\\n\\n!SoundType methodsFor: '*eToys-tiles' stamp: 'sw 9/27/2001 17:30'!\\ndefaultArgumentTile\\n\\t\\\"Answer a tile to represent the type\\\"\\n\\n\\t^ SoundTile new typeColor: self typeColor! !\\n\\n!SoundType methodsFor: '*eToys-tiles' stamp: 'sw 9/27/2001 17:37'!\\nnewReadoutTile\\n\\t\\\"Answer a tile that can serve as a readout for data of this type\\\"\\n\\n\\t^ SoundReadoutTile new typeColor: Color lightGray lighter! !\\n\\n!SoundType methodsFor: '*eToys-tiles' stamp: 'sw 9/27/2001 17:33'!\\nsetFormatForDisplayer: aDisplayer\\n\\t\\\"Set up the displayer to have the right format characteristics\\\"\\n\\n\\taDisplayer useStringFormat\\n\\t! !\\nSequenceableCollection subclass: #SourceFileArray\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Files-System'!\\n!SourceFileArray commentStamp: '<historical>' prior: 0!\\nThis class is an abstract superclass for source code access mechanisms. It defines the messages that need to be understood by those subclasses that store and retrieve source chunks on files, over the network or in databases.\\nThe first concrete subclass, StandardSourceFileArray, supports access to the traditional sources and changes files. Other subclasses might implement multiple source files for different applications, or access to a network source server.!\\n]style[(254 23 184)f1,f1LStandardSourceFileArray Comment;,f1!\\n\\n\\n!SourceFileArray methodsFor: 'accessing' stamp: 'hmm 4/26/2000 21:42'!\\nat: index\\n\\tself subclassResponsibility! !\\n\\n!SourceFileArray methodsFor: 'accessing' stamp: 'hmm 4/26/2000 21:43'!\\nat: index put: aFileStream\\n\\tself subclassResponsibility! !\\n\\n!SourceFileArray methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:32'!\\ncollect: aBlock\\n\\t| copy |\\n\\tcopy := self species new: self size.\\n\\t1 to: self size do:[:i| copy at: i put: (aBlock value: (self at: i))].\\n\\t^copy! !\\n\\n!SourceFileArray methodsFor: 'accessing' stamp: 'hmm 4/26/2000 21:43'!\\nsize\\n\\tself subclassResponsibility! !\\n\\n\\n!SourceFileArray methodsFor: 'sourcePointer conversion' stamp: 'hmm 4/25/2000 22:00'!\\nfileIndexFromSourcePointer: anInteger\\n\\t\\\"Return the index of a source file corresponding to the given source pointer.\\\"\\n\\tself subclassResponsibility! !\\n\\n!SourceFileArray methodsFor: 'sourcePointer conversion' stamp: 'hmm 4/25/2000 22:00'!\\nfilePositionFromSourcePointer: anInteger\\n\\t\\\"Return the position within a source file for the given source pointer.\\\"\\n\\tself subclassResponsibility! !\\n\\n!SourceFileArray methodsFor: 'sourcePointer conversion' stamp: 'hmm 4/25/2000 22:01'!\\nsourcePointerFromFileIndex: index andPosition: position\\n\\t\\\"Return a sourcePointer encoding the given file index and position\\\"\\n\\tself subclassResponsibility! !\\nObject subclass: #SpaceTally\\n\\tinstanceVariableNames: 'results'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Tools'!\\n!SpaceTally commentStamp: 'sd 6/20/2003 22:31' prior: 0!\\nI'm responsible to help getting information about system space usage. The information I compute is represented by a spaceTallyItem\\n\\ntry something like: \\n\\n((SpaceTally new spaceTally: (Array with: TextMorph with: Point)) \\n\\tasSortedCollection: [:a :b | a spaceForInstances > b spaceForInstances]) \\n\\nSpaceTally new systemWideSpaceTally\\n\\n\\nThis class has been created from a part of SystemDictionary. It still deserves a nice\\nclean, such as using object instead of array having 4 slots.\\n\\nsd-20 June 2003!\\n\\n\\n!SpaceTally methodsFor: 'accessing' stamp: 'sd 6/20/2003 22:31'!\\nresults\\n\\n\\t^ results! !\\n\\n\\n!SpaceTally methodsFor: 'class analysis' stamp: 'efc 7/6/2004 00:30'!\\ncomputeSpaceUsage\\n\\n\\t| entry c instanceCount |\\n\\t1 to: results size do: [:i |\\n\\t\\tentry := results at: i.\\n\\t\\tc := self class environment at: entry analyzedClassName.\\n\\t\\tinstanceCount _ c instanceCount.\\n\\t\\tentry codeSize: c spaceUsed.\\n\\t\\tentry instanceCount: instanceCount.\\n\\t\\tentry spaceForInstances: (self spaceForInstancesOf: c withInstanceCount: instanceCount).\\n\\t\\tSmalltalk garbageCollectMost].\\n\\t\\n! !\\n\\n!SpaceTally methodsFor: 'class analysis' stamp: 'sd 6/20/2003 22:54'!\\npreAllocateResultsFor: classes\\n\\n\\tresults := OrderedCollection new: classes size.\\n\\tclasses do: [:cl | results add: (SpaceTallyItem analyzedClassName: cl name)].\\n\\tresults _ results asArray.\\n! !\\n\\n!SpaceTally methodsFor: 'class analysis' stamp: 'sd 6/20/2003 22:24'!\\nspaceTally: classes\\n\\t\\\"Answer a collection of SpaceTallyItems representing the memory space (in bytes) consumed \\tby the code and instances of each class in the system. Note that code sizes do not currently \\treport memory consumed by class variables. \\\"\\n\\n\\t\\\"((SpaceTally new spaceTally: (Array with: TextMorph with: Point)) asSortedCollection: [:a :b | a spaceForInstances > b spaceForInstances]) asArray\\\"\\n\\n\\tself preAllocateResultsFor: classes.\\n\\tSmalltalk garbageCollect.\\n\\tself computeSpaceUsage.\\n\\t^ results\\n! !\\n\\n!SpaceTally methodsFor: 'class analysis' stamp: 'efc 7/6/2004 00:25'!\\nsystemWideSpaceTally\\n\\t\\\"Answer a collection of SpaceTallyItems representing the memory space (in bytes) consumed \\tby the code and instances of each class in the system. Note that code sizes do not currently \\treport memory consumed by class variables. \\\"\\n\\n\\t\\\"(SpaceTally new systemWideSpaceTally asSortedCollection: [:a :b | a spaceForInstances > b spaceForInstances]) asArray\\\"\\n\\n\\t^self spaceTally: Smalltalk allClasses.\\n\\n! !\\n\\n\\n!SpaceTally methodsFor: 'fileOut' stamp: 'sd 6/20/2003 22:39'!\\ncompareTallyIn: beforeFileName to: afterFileName\\n\\t\\\"SpaceTally new compareTallyIn: 'tally' to: 'tally2'\\\"\\n\\n\\t| answer s beforeDict a afterDict allKeys before after diff |\\n\\tbeforeDict _ Dictionary new.\\n\\ts _ FileDirectory default fileNamed: beforeFileName.\\n\\t[s atEnd] whileFalse: [\\n\\t\\ta _ Array readFrom: s nextLine.\\n\\t\\tbeforeDict at: a first put: a allButFirst.\\n\\t].\\n\\ts close.\\n\\tafterDict _ Dictionary new.\\n\\ts _ FileDirectory default fileNamed: afterFileName.\\n\\t[s atEnd] whileFalse: [\\n\\t\\ta _ Array readFrom: s nextLine.\\n\\t\\tafterDict at: a first put: a allButFirst.\\n\\t].\\n\\ts close.\\n\\tanswer _ WriteStream on: String new.\\n\\tallKeys _ (Set new addAll: beforeDict keys; addAll: afterDict keys; yourself) asSortedCollection.\\n\\tallKeys do: [ :each |\\n\\t\\tbefore _ beforeDict at: each ifAbsent: [#(0 0 0)].\\n\\t\\tafter _ afterDict at: each ifAbsent: [#(0 0 0)].\\n\\t\\tdiff _ before with: after collect: [ :vBefore :vAfter | vAfter - vBefore].\\n\\t\\tdiff = #(0 0 0) ifFalse: [\\n\\t\\t\\tanswer nextPutAll: each,' ',diff printString; cr.\\n\\t\\t].\\n\\t].\\n\\tStringHolder new contents: answer contents; openLabel: 'space diffs'.\\n\\t\\n\\n\\n! !\\n\\n!SpaceTally methodsFor: 'fileOut' stamp: 'sd 6/20/2003 23:04'!\\nprintSpaceAnalysis\\t\\n\\t\\\"SpaceTally new printSpaceAnalysis\\\"\\n\\n\\t^ self printSpaceAnalysis: 0 on: 'STspace.text'! !\\n\\n!SpaceTally methodsFor: 'fileOut' stamp: 'sd 6/20/2003 23:03'!\\nprintSpaceAnalysis: threshold on: fileName\\n\\t\\\"SpaceTally new printSpaceAnalysis: 1000 on: 'STspace.text1'\\\"\\n\\n\\t\\\"sd-This method should be rewrote to be more coherent within the rest of the class \\n\\tie using preAllocate and spaceForInstanceOf:\\\"\\n\\n\\t\\\"If threshold > 0, then only those classes with more than that number\\n\\tof instances will be shown, and they will be sorted by total instance space.\\n\\tIf threshold = 0, then all classes will appear, sorted by name.\\\"\\n\\n\\t| f codeSpace instCount instSpace totalCodeSpace totalInstCount totalInstSpace eltSize n totalPercent percent |\\n\\tSmalltalk garbageCollect.\\n\\ttotalCodeSpace _ totalInstCount _ totalInstSpace _ n _ 0.\\n\\tresults _ OrderedCollection new: Smalltalk classNames size.\\n'Taking statistics...'\\n\\tdisplayProgressAt: Sensor cursorPoint\\n\\tfrom: 0 to: Smalltalk classNames size\\n\\tduring: [:bar |\\n\\tSmalltalk allClassesDo:\\n\\t\\t[:cl | codeSpace _ cl spaceUsed.\\n\\t\\tbar value: (n _ n+1).\\n\\t\\tSmalltalk garbageCollectMost.\\n\\t\\tinstCount _ cl instanceCount.\\n\\t\\tinstSpace _ (cl indexIfCompact > 0 ifTrue: [4] ifFalse: [8])*instCount. \\\"Object headers\\\"\\n\\t\\tcl isVariable\\n\\t\\t\\tifTrue: [eltSize _ cl isBytes ifTrue: [1] ifFalse: [4].\\n\\t\\t\\t\\t\\tcl allInstancesDo: [:x | instSpace _ instSpace + (x basicSize*eltSize)]]\\n\\t\\t\\tifFalse: [instSpace _ instSpace + (cl instSize*instCount*4)].\\n\\t\\tresults add: (SpaceTallyItem analyzedClassName: cl name codeSize: codeSpace instanceCount: instCount spaceForInstances: instSpace).\\n\\t\\ttotalCodeSpace _ totalCodeSpace + codeSpace.\\n\\t\\ttotalInstCount _ totalInstCount + instCount.\\n\\t\\ttotalInstSpace _ totalInstSpace + instSpace]].\\n\\ttotalPercent _ 0.0.\\n\\n\\tf _ FileStream newFileNamed: fileName.\\n\\tf timeStamp.\\n\\tf nextPutAll: ('Class' padded: #right to: 30 with: $ );\\n\\t\\t\\tnextPutAll: ('code space' padded: #left to: 12 with: $ );\\n\\t\\t\\tnextPutAll: ('# instances' padded: #left to: 12 with: $ );\\n\\t\\t\\tnextPutAll: ('inst space' padded: #left to: 12 with: $ );\\n\\t\\t\\tnextPutAll: ('percent' padded: #left to: 8 with: $ ); cr.\\n\\n\\tthreshold > 0 ifTrue:\\n\\t\\t[\\\"If inst count threshold > 0, then sort by space\\\"\\n\\t\\tresults _ (results select: [:s | s instanceCount >= threshold or: [s spaceForInstances > (totalInstSpace // 500)]])\\n\\t\\t\\t\\tasSortedCollection: [:s :s2 | s spaceForInstances > s2 spaceForInstances]].\\n\\n\\tresults do:\\n\\t\\t[:s | f nextPutAll: (s analyzedClassName padded: #right to: 30 with: $ );\\n\\t\\t\\tnextPutAll: (s codeSize printString padded: #left to: 12 with: $ );\\n\\t\\t\\tnextPutAll: (s instanceCount printString padded: #left to: 12 with: $ );\\n\\t\\t\\tnextPutAll: (s spaceForInstances printString padded: #left to: 14 with: $ ).\\n\\t\\tpercent _ s spaceForInstances*100.0/totalInstSpace roundTo: 0.1.\\n\\t\\ttotalPercent _ totalPercent + percent.\\n\\t\\tpercent >= 0.1 ifTrue:\\n\\t\\t\\t[f nextPutAll: (percent printString padded: #left to: 8 with: $ )].\\n\\t\\tf cr].\\n\\n\\tf cr; nextPutAll: ('Total' padded: #right to: 30 with: $ );\\n\\t\\tnextPutAll: (totalCodeSpace printString padded: #left to: 12 with: $ );\\n\\t\\tnextPutAll: (totalInstCount printString padded: #left to: 12 with: $ );\\n\\t\\tnextPutAll: (totalInstSpace printString padded: #left to: 14 with: $ );\\n\\t\\tnextPutAll: ((totalPercent roundTo: 0.1) printString padded: #left to: 8 with: $ ).\\n\\tf close! !\\n\\n!SpaceTally methodsFor: 'fileOut' stamp: 'sd 6/20/2003 23:07'!\\nprintSpaceDifferenceFrom: fileName1 to: fileName2\\n\\t\\\"For differential results, run printSpaceAnalysis twice with different fileNames,\\n\\tthen run this method...\\n\\t\\tSpaceTally new printSpaceAnalysis: 0 on: 'STspace.text1'.\\n\\t\\t\\t--- do something that uses space here ---\\n\\t\\tSpaceTally new printSpaceAnalysis: 0 on: 'STspace.text2'.\\n\\t\\tSpaceTally new printSpaceDifferenceFrom: 'STspace.text1' to: 'STspace.text2'\\n\\\"\\n\\t| f coll1 coll2 item |\\n\\tf _ FileStream readOnlyFileNamed: fileName1.\\n\\tcoll1 _ OrderedCollection new.\\n\\t[f atEnd] whileFalse: [coll1 add: (f upTo: Character cr)].\\n\\tf close.\\n\\tf _ FileStream readOnlyFileNamed: fileName2.\\n\\tcoll2 _ OrderedCollection new.\\n\\t[f atEnd] whileFalse:\\n\\t\\t[item _ (f upTo: Character cr).\\n\\t\\t((coll1 includes: item) and: [(item endsWith: 'percent') not])\\n\\t\\t\\tifTrue: [coll1 remove: item]\\n\\t\\t\\tifFalse: [coll2 add: item]].\\n\\tf close.\\n\\t(StringHolder new contents: (String streamContents: \\n\\t\\t\\t[:s | \\n\\t\\t\\ts nextPutAll: fileName1; cr.\\n\\t\\t\\tcoll1 do: [:x | s nextPutAll: x; cr].\\n\\t\\t\\ts cr; cr.\\n\\t\\t\\ts nextPutAll: fileName2; cr.\\n\\t\\t\\tcoll2 do: [:x | s nextPutAll: x; cr]]))\\n\\t\\topenLabel: 'Differential Space Analysis'.\\n! !\\n\\n!SpaceTally methodsFor: 'fileOut' stamp: 'sd 6/20/2003 22:59'!\\nsaveTo: aFileName\\n\\t\\\"| st |\\n\\tst := SpaceTally new.\\n\\tst spaceTally: (Array with: TextMorph with: Point).\\n\\tst saveTo: 'spaceTally2'\\\"\\n\\t| s |\\n\\t(FileDirectory default fileExists: aFileName) ifTrue: [\\n\\t\\tFileDirectory default deleteFileNamed: aFileName].\\n\\ts _ FileDirectory default fileNamed: aFileName.\\n\\tresults do: [:each | s nextPutAll: each analyzedClassName asString ; \\n\\t\\t\\t\\t\\t\\tnextPutAll: ' '; nextPutAll: each codeSize printString; \\n\\t\\t\\t\\t\\t\\tnextPutAll: ' '; nextPutAll: each instanceCount printString; \\n\\t\\t\\t\\t\\t\\tnextPutAll: ' '; nextPutAll: each spaceForInstances printString; cr].\\n\\ts close! !\\n\\n\\n!SpaceTally methodsFor: 'instance size' stamp: 'efc 7/6/2004 00:30'!\\nspaceForInstancesOf: aClass withInstanceCount: instCount\\n\\t\\\"Answer the number of bytes consumed by all instances of the given class, including their object headers.\\\"\\n\\n\\t| isCompact instVarBytes bytesPerElement contentBytes headerBytes total |\\n\\tinstCount = 0 ifTrue: [^ 0].\\n\\tisCompact _ aClass indexIfCompact > 0.\\n\\tinstVarBytes _ aClass instSize * 4.\\n\\taClass isVariable\\n\\t\\tifTrue: [\\n\\t\\t\\tbytesPerElement _ aClass isBytes ifTrue: [1] ifFalse: [4].\\n\\t\\t\\ttotal _ 0.\\n\\t\\t\\taClass allInstancesDo: [:inst |\\n\\t\\t\\t\\tcontentBytes _ instVarBytes + (inst size * bytesPerElement).\\n\\t\\t\\t\\theaderBytes _\\n\\t\\t\\t\\t\\tcontentBytes > 255\\n\\t\\t\\t\\t\\t\\tifTrue: [12]\\n\\t\\t\\t\\t\\t\\tifFalse: [isCompact ifTrue: [4] ifFalse: [8]].\\n\\t\\t\\t\\ttotal _ total + headerBytes + contentBytes].\\n\\t\\t\\t^ total]\\n\\t\\tifFalse: [\\n\\t\\t\\theaderBytes _\\n\\t\\t\\t\\tinstVarBytes > 255\\n\\t\\t\\t\\t\\tifTrue: [12]\\n\\t\\t\\t\\t\\tifFalse: [isCompact ifTrue: [4] ifFalse: [8]].\\n\\t\\t\\t^ instCount * (headerBytes + instVarBytes)].\\n! !\\nObject subclass: #SpaceTallyItem\\n\\tinstanceVariableNames: 'analyzedClassName codeSize instanceCount spaceForInstances'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Tools'!\\n!SpaceTallyItem commentStamp: 'sd 6/20/2003 22:02' prior: 0!\\nI'm represent an entry in the spaceTally.!\\n\\n\\n!SpaceTallyItem methodsFor: 'accessing' stamp: 'sd 6/20/2003 22:59'!\\nanalyzedClassName\\n\\n\\t^ analyzedClassName! !\\n\\n!SpaceTallyItem methodsFor: 'accessing' stamp: 'sd 6/20/2003 22:59'!\\nanalyzedClassName: aClassName\\n\\n\\tanalyzedClassName := aClassName! !\\n\\n!SpaceTallyItem methodsFor: 'accessing' stamp: 'sd 6/20/2003 22:08'!\\ncodeSize\\n\\n\\t^ codeSize! !\\n\\n!SpaceTallyItem methodsFor: 'accessing' stamp: 'sd 6/20/2003 22:09'!\\ncodeSize: aNumber\\n\\n\\tcodeSize := aNumber! !\\n\\n!SpaceTallyItem methodsFor: 'accessing' stamp: 'sd 6/20/2003 22:09'!\\ninstanceCount\\n\\n\\t^ instanceCount! !\\n\\n!SpaceTallyItem methodsFor: 'accessing' stamp: 'sd 6/20/2003 22:09'!\\ninstanceCount: aNumber\\n\\n\\tinstanceCount := aNumber! !\\n\\n!SpaceTallyItem methodsFor: 'accessing' stamp: 'sd 6/20/2003 22:10'!\\nspaceForInstances\\n\\n\\t^ spaceForInstances! !\\n\\n!SpaceTallyItem methodsFor: 'accessing' stamp: 'sd 6/20/2003 22:10'!\\nspaceForInstances: aNumber\\n\\n\\tspaceForInstances := aNumber! !\\n\\n\\n!SpaceTallyItem methodsFor: 'printing' stamp: 'sd 6/20/2003 22:52'!\\nprintOn: aStream\\n\\n\\tanalyzedClassName isNil\\n\\t\\tifFalse: [aStream nextPutAll: analyzedClassName asString]. \\n\\taStream nextPutAll: ' ('.\\n\\tcodeSize isNil\\n\\t\\tifFalse: [aStream nextPutAll: 'code size: ' ; nextPutAll: codeSize asString]. \\n\\tinstanceCount isNil\\n\\t\\tifFalse: [aStream nextPutAll: ' instance count: ' ; nextPutAll: instanceCount asString]. \\n\\tspaceForInstances isNil\\n\\t\\tifFalse: [aStream nextPutAll: ' space for instances: ' ; nextPutAll: spaceForInstances asString]. \\n\\taStream nextPut: $).\\n\\t! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSpaceTallyItem class\\n\\tinstanceVariableNames: ''!\\n\\n!SpaceTallyItem class methodsFor: 'instance creation' stamp: 'sd 6/20/2003 22:54'!\\nanalyzedClassName: aClassName\\n\\n\\t^ self new\\n\\t\\tanalyzedClassName: aClassName ; yourself\\n\\t\\t! !\\n\\n!SpaceTallyItem class methodsFor: 'instance creation' stamp: 'sd 6/20/2003 22:54'!\\nanalyzedClassName: aClassName codeSize: codeSize instanceCount: instanceCount spaceForInstances: spaceForInstances\\n\\n\\t^ self new\\n\\t\\tanalyzedClassName: aClassName ;\\n\\t\\tcodeSize: codeSize ;\\n\\t\\tinstanceCount: instanceCount ;\\n\\t\\tspaceForInstances: spaceForInstances ; yourself! !\\nArrayedCollection variableSubclass: #SparseLargeTable\\n\\tinstanceVariableNames: 'base size chunkSize defaultValue'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Collections-Arrayed'!\\n!SparseLargeTable commentStamp: '<historical>' prior: 0!\\nDerivated from Stephan Pair's LargeArray, but to hold a sparse table, in which most of the entries are the same default value, it uses some tricks.!\\n\\n\\n!SparseLargeTable methodsFor: 'accessing' stamp: 'yo 12/1/2003 15:58'!\\narrayClass\\n\\n\\t^(self basicAt: 1) class\\n! !\\n\\n!SparseLargeTable methodsFor: 'accessing' stamp: 'yo 12/1/2003 15:58'!\\nat: index\\n\\n\\tself pvtCheckIndex: index.\\n\\t^self noCheckAt: index.\\n! !\\n\\n!SparseLargeTable methodsFor: 'accessing' stamp: 'yo 12/1/2003 15:58'!\\nat: index put: value\\n\\t\\n\\tself pvtCheckIndex: index.\\n\\t^self noCheckAt: index put: value\\n! !\\n\\n!SparseLargeTable methodsFor: 'accessing' stamp: 'yo 12/1/2003 17:56'!\\nbase\\n\\n\\t^ base.\\n! !\\n\\n!SparseLargeTable methodsFor: 'accessing' stamp: 'yo 12/1/2003 15:58'!\\nchunkSize\\n\\n\\t^chunkSize\\n! !\\n\\n!SparseLargeTable methodsFor: 'accessing' stamp: 'tak 12/21/2004 16:59'!\\nnoCheckAt: index\\n\\t| chunkIndex t |\\n\\n\\tchunkIndex := index - base // chunkSize + 1.\\n\\t(chunkIndex > self basicSize or: [chunkIndex < 1]) ifTrue: [^ defaultValue].\\n\\tt _ self basicAt: chunkIndex.\\n\\tt ifNil: [^ defaultValue].\\n\\t^ t at: (index - base + 1 - (chunkIndex - 1 * chunkSize))\\n! !\\n\\n!SparseLargeTable methodsFor: 'accessing' stamp: 'yo 12/1/2003 19:18'!\\nnoCheckAt: index put: value\\n\\t| chunkIndex t |\\n\\n\\tchunkIndex := index - base // chunkSize + 1.\\n\\tchunkIndex > self basicSize ifTrue: [^ value].\\n\\tt _ self basicAt: chunkIndex.\\n\\tt ifNil: [^ value].\\n\\t^ t at: (index - base + 1 - (chunkIndex - 1 * chunkSize)) put: value\\n! !\\n\\n!SparseLargeTable methodsFor: 'accessing' stamp: 'yo 12/1/2003 15:58'!\\nsize\\n\\n\\t^size\\n! !\\n\\n!SparseLargeTable methodsFor: 'accessing' stamp: 'yo 12/1/2003 22:34'!\\nzapDefaultOnlyEntries\\n\\n\\t| lastIndex newInst |\\n\\t1 to: self basicSize do: [:i |\\n\\t\\t(self allDefaultValueSubtableAt: i) ifTrue: [self basicAt: i put: nil].\\n\\t].\\n\\n\\tlastIndex _ self findLastNonNilSubTable.\\n\\tlastIndex = 0 ifTrue: [^ self].\\n\\t\\n\\tnewInst _ self class new: lastIndex*chunkSize chunkSize: chunkSize arrayClass: (self basicAt: lastIndex) class base: base defaultValue: defaultValue.\\n\\tnewInst privateSize: self size.\\n\\tbase to: newInst size do: [:i | newInst at: i put: (self at: i)].\\n\\t1 to: newInst basicSize do: [:i |\\n\\t\\t(newInst allDefaultValueSubtableAt: i) ifTrue: [newInst basicAt: i put: nil].\\n\\t].\\n\\n\\tself becomeForward: newInst.\\n\\t^ newInst.\\n! !\\n\\n\\n!SparseLargeTable methodsFor: 'initialization' stamp: 'yo 12/1/2003 16:58'!\\ninitChunkSize: aChunkSize size: aSize arrayClass: aClass base: b defaultValue: d\\n\\n\\t| lastChunkSize |\\n\\tchunkSize := aChunkSize.\\n\\tsize := aSize.\\n\\tbase _ b.\\n\\tdefaultValue _ d.\\n\\t1 to: (self basicSize - 1) do: [ :in | self basicAt: in put: (aClass new: chunkSize withAll: defaultValue) ].\\n\\tlastChunkSize := size \\\\\\\\ chunkSize.\\n\\tlastChunkSize = 0 ifTrue: [lastChunkSize := chunkSize].\\n\\tsize = 0 \\n\\t\\tifTrue: [self basicAt: 1 put: (aClass new: 0)]\\n\\t\\tifFalse: [self basicAt: self basicSize put: (aClass new: lastChunkSize withAll: defaultValue)].\\n! !\\n\\n\\n!SparseLargeTable methodsFor: 'printing' stamp: 'yo 12/1/2003 17:06'!\\nprintElementsOn: aStream\\n\\t| element |\\n\\taStream nextPut: $(.\\n\\tbase to: size do: [:index | element _ self at: index. aStream print: element; space].\\n\\tself isEmpty ifFalse: [aStream skip: -1].\\n\\taStream nextPut: $)\\n! !\\n\\n!SparseLargeTable methodsFor: 'printing' stamp: 'yo 12/1/2003 15:58'!\\nprintOn: aStream\\n\\n\\t(#(String) includes: self arrayClass name) \\n\\t\\tifTrue: [^self storeOn: aStream].\\n\\t^super printOn: aStream\\n! !\\n\\n!SparseLargeTable methodsFor: 'printing' stamp: 'yo 12/1/2003 15:59'!\\nstoreOn: aStream\\n\\n\\t| x |\\n\\t(#(String) includes: self arrayClass name) ifTrue: \\n\\t\\t[aStream nextPut: $'.\\n\\t\\t1 to: self size do:\\n\\t\\t\\t[:i |\\n\\t\\t\\taStream nextPut: (x _ self at: i).\\n\\t\\t\\tx == $' ifTrue: [aStream nextPut: x]].\\n\\t\\taStream nextPutAll: ''' asLargeArrayChunkSize: '.\\n\\t\\taStream nextPutAll: self chunkSize asString.\\n\\t\\t^self].\\n\\t^super storeOn: aStream\\n! !\\n\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 18:58'!\\nallDefaultValueSubtableAt: index\\n\\n\\t| t |\\n\\tt _ self basicAt: index.\\n\\tt ifNil: [^ true].\\n\\tt do: [:e |\\n\\t\\te ~= defaultValue ifTrue: [^ false].\\n\\t].\\n\\t^ true.\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 17:10'!\\nanalyzeSpaceSaving\\n\\n\\t| total elems tablesTotal nonNilTables |\\n\\ttotal _ size - base + 1.\\n\\telems _ 0.\\n\\tbase to: size do: [:i | (self at: i) ~= defaultValue ifTrue: [elems _ elems + 1]].\\n\\ttablesTotal _ self basicSize.\\n\\tnonNilTables _ 0.\\n\\t1 to: self basicSize do: [:i | (self basicAt: i) ifNotNil: [nonNilTables _ nonNilTables + 1]].\\n\\n\\t^ String streamContents: [:strm |\\n\\t\\tstrm nextPutAll: 'total: '.\\n\\t\\tstrm nextPutAll: total printString.\\n\\t\\tstrm nextPutAll: ' elements: '.\\n\\t\\tstrm nextPutAll: elems printString.\\n\\t\\tstrm nextPutAll: ' tables: '.\\n\\t\\tstrm nextPutAll: tablesTotal printString.\\n\\t\\tstrm nextPutAll: ' non-nil: '.\\n\\t\\tstrm nextPutAll: nonNilTables printString.\\n\\t].\\n\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'nk 8/31/2004 08:34'!\\ncopyEmpty\\n\\t\\\"Answer a copy of the receiver that contains no elements.\\\"\\n\\t^self speciesNew: 0\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 22:34'!\\nfindLastNonNilSubTable\\n\\n\\t(self basicAt: self basicSize) ifNotNil: [^ self basicSize].\\n\\n\\tself basicSize - 1 to: 1 by: -1 do: [:lastIndex |\\n\\t\\t(self basicAt: lastIndex) ifNotNil: [^ lastIndex].\\n\\t].\\n\\t^ 0.\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 19:19'!\\nprivateSize: s\\n\\n\\tsize _ s.\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 17:34'!\\npvtCheckIndex: index \\n\\n\\tindex isInteger ifFalse: [self errorNonIntegerIndex].\\n\\tindex < 1 ifTrue: [self errorSubscriptBounds: index].\\n\\tindex > size ifTrue: [self errorSubscriptBounds: index].\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 15:59'!\\nsimilarInstance\\n\\n\\t^self class\\n\\t\\tnew: self size \\n\\t\\tchunkSize: self chunkSize \\n\\t\\tarrayClass: self arrayClass\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 15:59'!\\nsimilarInstance: newSize\\n\\n\\t^self class\\n\\t\\tnew: newSize \\n\\t\\tchunkSize: self chunkSize \\n\\t\\tarrayClass: self arrayClass\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 15:59'!\\nsimilarSpeciesInstance\\n\\n\\t^self similarInstance\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 16:00'!\\nsimilarSpeciesInstance: newSize\\n\\n\\t^self similarInstance: newSize\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 16:00'!\\nspeciesNew\\n\\n\\t^self species\\n\\t\\tnew: self size \\n\\t\\tchunkSize: self chunkSize \\n\\t\\tarrayClass: self arrayClass\\n! !\\n\\n!SparseLargeTable methodsFor: 'private' stamp: 'yo 12/1/2003 16:00'!\\nspeciesNew: newSize\\n\\n\\t^self species\\n\\t\\tnew: newSize \\n\\t\\tchunkSize: self chunkSize \\n\\t\\tarrayClass: self arrayClass\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSparseLargeTable class\\n\\tinstanceVariableNames: ''!\\n\\n!SparseLargeTable class methodsFor: 'accessing' stamp: 'yo 12/1/2003 15:54'!\\ndefaultChunkSize\\n\\n\\t^100! !\\n\\n!SparseLargeTable class methodsFor: 'accessing' stamp: 'yo 12/1/2003 15:54'!\\ndefaultChunkSizeForFiles\\n\\n\\t^8000! !\\n\\n\\n!SparseLargeTable class methodsFor: 'instance creation' stamp: 'yo 12/1/2003 16:06'!\\nnew: size\\n\\n\\t^self new: size chunkSize: self defaultChunkSize\\n! !\\n\\n!SparseLargeTable class methodsFor: 'instance creation' stamp: 'yo 12/1/2003 16:07'!\\nnew: size chunkSize: chunkSize\\n\\n\\t^self new: size chunkSize: chunkSize arrayClass: Array\\n! !\\n\\n!SparseLargeTable class methodsFor: 'instance creation' stamp: 'yo 12/1/2003 16:08'!\\nnew: size chunkSize: chunkSize arrayClass: aClass\\n\\n\\t^self new: size chunkSize: chunkSize arrayClass: Array base: 1.\\n! !\\n\\n!SparseLargeTable class methodsFor: 'instance creation' stamp: 'yo 12/1/2003 16:37'!\\nnew: size chunkSize: chunkSize arrayClass: aClass base: b\\n\\n\\t^self new: size chunkSize: chunkSize arrayClass: Array base: 1 defaultValue: nil.\\n! !\\n\\n!SparseLargeTable class methodsFor: 'instance creation' stamp: 'yo 12/1/2003 16:37'!\\nnew: size chunkSize: chunkSize arrayClass: aClass base: b defaultValue: d\\n\\n\\t| basicSize |\\n\\t(basicSize := ((size - 1) // chunkSize) + 1) = 0\\n\\t\\tifTrue: [basicSize := 1].\\n\\t^(self basicNew: basicSize)\\n\\t\\tinitChunkSize: chunkSize size: size arrayClass: aClass base: b defaultValue: d;\\n\\t\\tyourself\\n! !\\nObject subclass: #SparseXTable\\n\\tinstanceVariableNames: 'tables xTables'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-Display'!\\n\\n!SparseXTable methodsFor: 'as yet unclassified' stamp: 'yo 7/30/2003 17:38'!\\ntableFor: code\\n\\n\\t| div t table |\\n\\tdiv _ code // 65536.\\n\\tt _ xTables at: div ifAbsent: [table _ Array new: 65536 withAll: 0. xTables at: div put: table. table].\\n\\t^ t.\\n! !\\nObject subclass: #Speaker\\n\\tinstanceVariableNames: 'pitch range loudness speed transcriber voice visitors'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Speech-TTS'!\\n\\n!Speaker methodsFor: 'accessing' stamp: 'len 12/8/1999 16:33'!\\nloudness\\n\\t^ loudness! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nloudness: aNumber\\n\\tloudness := aNumber! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'len 12/13/1999 03:02'!\\nphonemes\\n\\t\\\"Answer the phoneme set of the receiver.\\\"\\n\\t^ self transcriber phonemes! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'len 12/12/1999 23:18'!\\npitch\\n\\t\\\"Answer the average pitch.\\\"\\n\\t^ pitch! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\npitch: aNumber\\n\\t\\\"Set the average pitch.\\\"\\n\\tpitch := aNumber! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'len 12/12/1999 23:18'!\\nrange\\n\\t\\\"Answer the pitch range (variation).\\\"\\n\\t^ range! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nrange: aNumber\\n\\t\\\"Set the pitch range (variation).\\\"\\n\\trange := aNumber! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'len 12/8/1999 16:33'!\\nspeed\\n\\t^ speed! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nspeed: aNumber\\n\\tspeed := aNumber! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'len 12/8/1999 16:31'!\\ntranscriber\\n\\t^ transcriber! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\ntranscriber: aPhoneticTranscriber\\n\\ttranscriber := aPhoneticTranscriber! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'len 12/12/1999 23:02'!\\nvisitors\\n\\t^ visitors! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nvisitors: aCollection\\n\\tvisitors := aCollection! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'len 12/8/1999 16:32'!\\nvoice\\n\\t^ voice! !\\n\\n!Speaker methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nvoice: aVoice\\n\\tvoice := aVoice! !\\n\\n\\n!Speaker methodsFor: 'editing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nedit\\n\\t| answer buttons |\\n\\tanswer := (self findAVoice: KlattVoice) editor.\\n\\tbuttons := AlignmentMorph new listDirection: #leftToRight; color: answer color.\\n\\tbuttons\\n\\t\\taddMorphFront: (SimpleButtonMorph new target: self; actWhen: #buttonDown; actionSelector: #newHead; labelString: 'new head');\\n\\t\\taddMorphFront: (SimpleButtonMorph new target: self; actWhen: #buttonDown; actionSelector: #saySomething; labelString: 'test').\\n\\tanswer\\n\\t\\taddSliderForParameter: #speed target: self min: 0.1 max: 2.0 description: 'Speed';\\n\\t\\taddSliderForParameter: #loudness target: self min: 0.0 max: 1.0 description: 'Loudness';\\n\\t\\taddSliderForParameter: #range target: self min: 0.0 max: 1.0 description: 'Pitch Range';\\n\\t\\taddSliderForParameter: #pitch target: self min: 20.0 max: 800.0 description: 'Pitch';\\n\\t\\taddMorphFront: buttons;\\n\\t\\topenInWorld! !\\n\\n!Speaker methodsFor: 'editing' stamp: 'len 12/2/1999 03:19'!\\nfindAVoice: aClass\\n\\t(self voice isKindOf: aClass) ifTrue: [^ self voice].\\n\\t(self voice isKindOf: CompositeVoice)\\n\\t\\tifTrue: [self voice do: [ :each | (each isKindOf: aClass) ifTrue: [^ each]]].\\n\\t^ nil! !\\n\\n!Speaker methodsFor: 'editing' stamp: 'len 12/2/1999 03:27'!\\nmakeGestural\\n\\t(self findAVoice: GesturalVoice) isNil ifFalse: [^ self].\\n\\tself voice: self voice + GesturalVoice new! !\\n\\n!Speaker methodsFor: 'editing' stamp: 'len 12/2/1999 03:27'!\\nnewHead\\n\\tself makeGestural.\\n\\t(self findAVoice: GesturalVoice) newHead! !\\n\\n!Speaker methodsFor: 'editing' stamp: 'len 12/14/1999 05:24'!\\nsaySomething\\n\\tself say: #('This is my voice.' 'I am speaking.' 'Do you like my voice?' 'Listen to my voice.' 'Hello.' 'Hay. What are you doing?' 'How are you?' 'Is this my voice?' 'Are you there?' 'Help, please.' 'Howdy.' 'Ha ha he he hi.') atRandom! !\\n\\n\\n!Speaker methodsFor: 'initialization' stamp: 'len 11/27/2000 09:59'!\\ninitialize\\n\\tself pitch: 100.0; range: 0.3; loudness: 1.0; speed: 0.6; \\\"normalizer: TextNormalizer new;\\\" transcriber: PhoneticTranscriber default; visitors: {IntonationVisitor default. DurationsVisitor default. F0RenderingVisitor default}! !\\n\\n\\n!Speaker methodsFor: 'parsing' stamp: 'len 12/14/1999 02:13'!\\nclauseFromString: aString\\n\\t^ Clause new\\n\\t\\tstring: aString;\\n\\t\\tphrases: ((aString findTokens: '!!?.,;()') collect: [ :each | self phraseFromString: each])! !\\n\\n!Speaker methodsFor: 'parsing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\neventsFromString: aString\\n\\t| clause |\\n\\tclause := self clauseFromString: aString.\\n\\tclause phrases do: [ :each | each lastSyllable events add: (PhoneticEvent new phoneme: self phonemes silence; duration: 0.1)].\\n\\tclause lastSyllable events last duration: 0.5.\\n\\tvisitors do: [ :each | each speaker: self. clause accept: each].\\n\\tclause eventsDo: [ :each | each loudness: self loudness].\\n\\t^ clause events! !\\n\\n!Speaker methodsFor: 'parsing' stamp: 'len 12/13/1999 03:19'!\\nphraseFromString: aString\\n\\t^ Phrase new\\n\\t\\tstring: aString;\\n\\t\\twords: ((aString findTokens: ' !!?.,;()') collect: [ :each | self wordFromString: each])! !\\n\\n!Speaker methodsFor: 'parsing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nsyllabizationOf: phonemes\\n\\t| syllable stream last answer |\\n\\tanswer := OrderedCollection new.\\n\\tsyllable := Syllable new phonemes: (OrderedCollection new: 4).\\n\\tstream := ReadStream on: phonemes.\\n\\t[stream atEnd]\\n\\t\\twhileFalse: [syllable phonemes add: (last := stream next).\\n\\t\\t\\t\\t\\t(stream atEnd not and: [last isConsonant not and: [stream peek isConsonant]])\\n\\t\\t\\t\\t\\t\\tifTrue: [answer add: syllable. syllable := Syllable new phonemes: (OrderedCollection new: 4)]].\\n\\tsyllable phonemes isEmpty ifFalse: [answer add: syllable].\\n\\t^ answer! !\\n\\n!Speaker methodsFor: 'parsing' stamp: 'len 12/8/1999 18:24'!\\nwordFromString: aString\\n\\t^ Word new\\n\\t\\tstring: aString;\\n\\t\\tsyllables: (self syllabizationOf: (self transcriber transcriptionOf: aString))! !\\n\\n\\n!Speaker methodsFor: 'playing' stamp: 'nk 2/19/2004 16:50'!\\nnumberSignDelay\\n\\t\\\"Answer the number of milliseconds that a # symbol in the string given to say: will generate.\\\"\\n\\t^200! !\\n\\n!Speaker methodsFor: 'playing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nsay: aString \\n\\t\\\"aString may contain characters and punctuation.\\n\\tYou may also include the # symbol in aString;\\n\\tfor each one of these, a 200msec delay will be generated.\\\"\\n\\n\\t| events stream string token delay |\\n\\n\\tstream := ReadStream\\n\\t\\t\\t\\ton: ((aString\\n\\t\\t\\t\\t\\t\\tcopyReplaceAll: '-'\\n\\t\\t\\t\\t\\t\\twith: ' '\\n\\t\\t\\t\\t\\t\\tasTokens: false)\\n\\t\\t\\t\\t\\t\\tfindTokens: '?# '\\n\\t\\t\\t\\t\\t\\tkeep: '?#').\\n\\tstring := ''.\\n\\tdelay := 0.\\n\\t[stream atEnd]\\n\\t\\twhileFalse: [token := stream next.\\n\\t\\t\\ttoken = '#'\\n\\t\\t\\t\\tifTrue: [ self voice playSilenceMSecs: self numberSignDelay.\\n\\t\\t\\t\\t\\tdelay := delay + self numberSignDelay ]\\n\\t\\t\\t\\tifFalse: [string := string , ' ' , token.\\n\\t\\t\\t\\t\\t(token = '?' or: [stream atEnd])\\n\\t\\t\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\t\\t\\tevents := CompositeEvent new.\\n\\t\\t\\t\\t\\t\\t\\tevents addAll: (self eventsFromString: string).\\n\\t\\t\\t\\t\\t\\t\\tevents playOn: self voice delayed: delay.\\n\\t\\t\\t\\t\\t\\t\\tdelay := delay + (events duration * 1000).\\n\\t\\t\\t\\t\\t\\t\\tstring := '' ]]].\\n\\tself voice flush! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSpeaker class\\n\\tinstanceVariableNames: ''!\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 03:17'!\\nbicyclic\\n\\t\\\"\\n\\tSpeaker bicyclic say: 'This is my voice. I am a woman with bicyclic voice.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 200.0;\\n\\t\\tvoice: (KlattVoice new diplophonia: 0.4; tract: 14.4)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 03:56'!\\nbigMan\\n\\t\\\"\\n\\tSpeaker bigMan say: 'I am the child? No. I am the big man speaking.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 90.0;\\n\\t\\trange: 0.5;\\n\\t\\tvoice: (KlattVoice new tract: 20)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 03:19'!\\nbreathy\\n\\t\\\"\\n\\tSpeaker breathy say: 'This is my breathy voice.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 100.0;\\n\\t\\tvoice: (KlattVoice new ro: 0.6; turbulence: 70)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 04:07'!\\nchild\\n\\t\\\"\\n\\tSpeaker child say: 'Hello. I am a child speaking.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 320.0;\\n\\t\\tvoice: (KlattVoice new tract: 12)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 03:21'!\\ncreaky\\n\\t\\\"\\n\\tSpeaker creaky say: 'This is my creaky voice with hight jitter and shimmer.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 90.0;\\n\\t\\tspeed: 0.5;\\n\\t\\tvoice: (KlattVoice new jitter: 0.5; shimmer: 0.5)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 11/27/2000 10:01'!\\ndefault\\n\\t\\\"\\n\\tSpeaker default say: 'This is the default voice.'\\n\\t\\\"\\n\\n\\t^ self new voice: KlattVoice new! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 04:13'!\\nexorsist\\n\\t\\\"\\n\\tSpeaker exorsist say: 'This is an scary voice. Boo.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 40.0;\\n\\t\\tspeed: 0.5;\\n\\t\\tvoice: (KlattVoice new tract: 10; diplophonia: 0.4; jitter: 0.3; shimmer: 0.5; turbulence: 50)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 04:13'!\\nfly\\n\\t\\\"\\n\\tSpeaker fly say: 'Haaaaaalp.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 650.0;\\n\\t\\tloudness: 0.5;\\n\\t\\tspeed: 0.8;\\n\\t\\tvoice: (KlattVoice new flutter: 1.0; tract: 1)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 04:01'!\\nkid\\n\\t\\\"\\n\\tSpeaker kid say: 'Do you like my voice? I am the kid speaking.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 170.0;\\n\\t\\trange: 0.4;\\n\\t\\tvoice: (KlattVoice new tract: 16)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 11/27/2000 10:01'!\\nman\\n\\t\\\"\\n\\tSpeaker man say: 'Listen to my voice. I am a man speaking.'\\n\\t\\\"\\n\\n\\t^ self default pitch: 90.0! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 03:26'!\\nnotPressed\\n\\t\\\"\\n\\tSpeaker notPressed say: 'This is a non pressed voice.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 100.0;\\n\\t\\tvoice: (KlattVoice new ro: 0.9)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 03:26'!\\npressed\\n\\t\\\"\\n\\tSpeaker pressed say: 'This is a pressed voice.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 100.0;\\n\\t\\tvoice: (KlattVoice new ro: 0.1)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 03:27'!\\nwhispery\\n\\t\\\"\\n\\tSpeaker whispery say: 'This is my whispery voice.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tvoice: (KlattVoice new breathiness: 1.0)! !\\n\\n!Speaker class methodsFor: 'examples' stamp: 'len 12/14/1999 04:10'!\\nwoman\\n\\t\\\"\\n\\tSpeaker woman say: 'Do you listen? I am a woman speaking.'\\n\\t\\\"\\n\\n\\t^ self new\\n\\t\\tpitch: 230.0;\\n\\t\\trange: 0.5;\\n\\t\\tspeed: 0.7;\\n\\t\\tvoice: (KlattVoice new flutter: 0.5; ro: 0.3; ra: 0.003; tract: 14.4)! !\\n\\n\\n!Speaker class methodsFor: 'examples-others' stamp: 'len 12/2/1999 03:46'!\\nmanWithEditor\\n\\t\\\"\\n\\tSpeaker manWithEditor say: 'With this editor you can change my voice.'\\n\\t\\\"\\n\\n\\t^ self man edit! !\\n\\n!Speaker class methodsFor: 'examples-others' stamp: 'len 12/14/1999 05:10'!\\nmanWithHead\\n\\t\\\"\\n\\tSpeaker manWithHead say: 'This is my voice. Can you see my lips?'\\n\\t\\\"\\n\\n\\t^ self man newHead! !\\nMorph subclass: #SpeakerMorph\\n\\tinstanceVariableNames: 'bufferSize buffer lastConePosition sound'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SoundInterface'!\\n\\n!SpeakerMorph methodsFor: 'initialization' stamp: 'nk 6/12/2004 10:05'!\\naddGraphic\\n\\n\\t| graphic |\\n\\tgraphic _ World drawingClass withForm: self speakerGraphic.\\n\\tgraphic position: bounds center - (graphic extent // 2).\\n\\tself addMorph: graphic.\\n! !\\n\\n!SpeakerMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:51'!\\ndefaultColor\\n\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color\\n\\t\\tr: 1.0\\n\\t\\tg: 0.484\\n\\t\\tb: 0.258! !\\n\\n!SpeakerMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:51'!\\ninitialize\\n\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\\"\\\"\\n\\tself addGraphic.\\n\\tbufferSize _ 5000.\\n\\tbuffer _ WriteStream\\n\\t\\t\\t\\ton: (SoundBuffer newMonoSampleCount: bufferSize).\\n\\tlastConePosition _ 0.\\n\\tsound _ SequentialSound new! !\\n\\n!SpeakerMorph methodsFor: 'initialization' stamp: 'jm 4/22/1999 22:58'!\\nspeakerGraphic\\n\\n\\t^ Form\\n\\t\\textent: 19@18\\n\\t\\tdepth: 8\\n\\t\\tfromArray: #(0 0 1493172224 2816 0 0 0 1493172224 11 0 0 138 1493172224 184549376 184549376 0 35509 2315255808 720896 720896 0 9090522 2315255808 2816 720896 0 2327173887 2315255819 2816 720896 138 3051028442 2315255819 2816 2816 1505080590 4294957786 2315255808 184549387 2816 3053453311 4292532917 1493172224 184549387 2816 1505080714 3048584629 1493172224 184549387 2816 9079434 3048584629 1493172224 184549387 2816 138 2327164341 1493172235 2816 2816 0 2324346293 1493172235 2816 720896 0 9079477 1493172224 2816 720896 0 35466 1493172224 720896 720896 0 138 0 184549376 184549376 0 0 0 11 0 0 0 0 2816 0)\\n\\t\\toffset: 0@0\\n! !\\n\\n\\n!SpeakerMorph methodsFor: 'speaker' stamp: 'jdl 3/28/2003 09:38'!\\nappendSample: aFloat \\n\\t\\\"Append the given sample, a number between -100.0 and 100.0, to my buffer. Flush the buffer if it is full.\\\"\\n\\n\\tlastConePosition := aFloat.\\n\\tlastConePosition := lastConePosition min: 100.0.\\n\\tlastConePosition := lastConePosition max: -100.0.\\n\\tbuffer nextPut: (327.67 * lastConePosition) truncated.\\n\\tbuffer position >= bufferSize ifTrue: [self flushBuffer]\\n! !\\n\\n!SpeakerMorph methodsFor: 'speaker' stamp: 'jm 4/21/1999 10:18'!\\nconePosition\\n\\n\\t^ lastConePosition\\n! !\\n\\n!SpeakerMorph methodsFor: 'speaker' stamp: 'jm 4/22/1999 16:46'!\\nconePosition: aNumber\\n\\n\\tself appendSample: aNumber asFloat. \\\"sets lastConePosition\\\"\\n! !\\n\\n!SpeakerMorph methodsFor: 'speaker' stamp: 'jm 4/22/1999 13:29'!\\nflushBuffer\\n\\n\\t| buf |\\n\\tbuf _ buffer contents.\\n\\tbuffer resetContents.\\n\\tsound isPlaying ifFalse: [sound _ SequentialSound new].\\n\\tsound add: (SampledSound samples: buf samplingRate: 11025).\\n\\tsound isPlaying\\n\\t\\tifTrue: [sound pruneFinishedSounds]\\n\\t\\tifFalse: [sound play].\\n! !\\n\\n!SpeakerMorph methodsFor: 'speaker' stamp: 'jm 4/22/1999 15:33'!\\nstopSound\\n\\n\\tsound pause.\\n\\tbuffer resetContents.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSpeakerMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!SpeakerMorph class methodsFor: '*eToys-scripting' stamp: 'sw 9/26/2001 04:27'!\\nadditionsToViewerCategories\\n\\t\\\"Answer a list of (<categoryName> <list of category specs>) pairs that characterize the phrases this kind of morph wishes to add to various Viewer categories.\\\"\\n\\n\\t^ #((speaker\\n\\n((slot conePosition 'the position of the speaker cone' Number readWrite Player getConePosition Player setConePosition:))))\\n\\n\\n\\n! !\\nAlignmentMorph subclass: #SpectrumAnalyzerMorph\\n\\tinstanceVariableNames: 'soundInput statusLight levelMeter graphMorph sonogramMorph fft displayType'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SoundInterface'!\\n!SpectrumAnalyzerMorph commentStamp: '<historical>' prior: 0!\\nI am a tool for analyzing sound data from a microphone, CD, or other input source in real time. I have several display modes:\\n\\n\\tsignal\\t\\tsnapshots of the raw signal data as it arrives\\n\\tspectrum\\tfrequency spectrum of the signal data as it arrives\\n\\tsonogram\\tscrolling plot of the frequency spectrum over time,\\n\\t\\t\\t where the vertical axis is frequency, the horizontal\\n\\t\\t\\t\\t axis is time, and amount of energy at a given\\n\\t\\t\\t\\t frequency is shown as a grayscale value with\\n\\t\\t\\t\\t larger values being darker\\n\\nTo use this tool, be sure that you have selected the proper sound source using you host OS facilities. Set the desired sampling rate and FFT size (try 22050 samples/sec and an FFT size of 512) then click on the 'start' button. Use the slider to adjust the level so that the yellow level indicator peaks somewhere between the middle and the right edge at the maximum signal level.\\n\\nNote that if the level meter peaks hit the right edge, you will get 'clipping', which creates a bunch of spurious high frequency noise in the frequency spectrum. If the display is set to 'signal' mode, you can actually see the tops and bottoms of the waveform being cut off when clipping occurs.\\n\\nMany machines may not be able to perform spectrum analysis in real time, especially at higher sampling rates and larger FFT sizes. In both 'signal' and 'spectrum' modes, this tool will skip data to try to keep up with real time. However, in 'sonogram' mode it always processes all the data, even if it falls behind. This allows you to get a complete sonogram without dropouts even on a slower machine. However, as the sonogram display falls behind there will be a larger and larger time lag between when a sound is input and when it appears on the display.\\n\\nThe smaller the FFT size, the less frequency resolution you get. The lower the sampling rate, the less total frequency range you get. For an FFT size of N and a sampling rate of R, each of the N/2 'bins' of the frequency spectrum has a frequency resolution of R / N. For example, at a sampleing rate of 22050 samples/second, the total frequency range is 0 to 11025 Hz and an FFT of size 256 would divide this range into 128 bins (the output of an FFT of size N has N/2 bins), each of which covers a frequency band about 86 Hz wide.\\n\\nTo increase time resolution, increase the sampling rate and decrease the FFT size.\\n!\\n\\n\\n!SpectrumAnalyzerMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:52'!\\ndefaultBorderWidth\\n\\\"answer the default border width for the receiver\\\"\\n\\t^ 2! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:52'!\\ninitialize\\n\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\\"\\\"\\n\\tself listDirection: #topToBottom.\\n\\tsoundInput _ SoundInputStream new samplingRate: 22050.\\n\\tfft _ FFT new: 512.\\n\\tdisplayType _ 'sonogram'.\\n\\tself hResizing: #shrinkWrap.\\n\\tself vResizing: #shrinkWrap.\\n\\tself addButtonRow.\\n\\tself addLevelSlider.\\n\\tself addMorphBack: self makeLevelMeter.\\n\\tself addMorphBack: (Morph new extent: 10 @ 10;\\n\\t\\t\\t color: Color transparent).\\n\\t\\\"spacer\\\"\\n\\tself resetDisplay! !\\n\\n\\n!SpectrumAnalyzerMorph methodsFor: 'menu and buttons' stamp: 'dgd 9/19/2003 13:25'!\\ninvokeMenu\\n\\t\\\"Invoke the settings menu.\\\"\\n\\n\\t| aMenu |\\n\\taMenu _ CustomMenu new.\\n\\taMenu addList:\\t{\\n\\t\\t{'set sampling rate' translated.\\t\\t#setSamplingRate}.\\n\\t\\t{'set FFT size' translated.\\t\\t\\t#setFFTSize}.\\n\\t\\t{'set display type' translated.\\t\\t#setDisplayType}}.\\n\\taMenu invokeOn: self defaultSelection: nil.\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'menu and buttons' stamp: 'jm 9/8/1999 12:52'!\\nresetDisplay\\n\\t\\\"Recreate my display after changing some parameter such as FFT size.\\\"\\n\\n\\tdisplayType = 'signal' ifTrue: [self showSignal].\\n\\tdisplayType = 'spectrum' ifTrue: [self showSpectrum].\\n\\tdisplayType = 'sonogram' ifTrue: [self showSonogram].\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'menu and buttons' stamp: 'dgd 9/19/2003 13:29'!\\nsetDisplayType\\n\\t\\\"Set the display type.\\\"\\n\\n\\t| aMenu choice on |\\n\\taMenu _ CustomMenu new title: ('display type (currently {1})' translated format:{displayType}).\\n\\taMenu addList:\\t{\\n\\t\\t{'signal' translated.\\t'signal'}.\\n\\t\\t{'spectrum' translated.\\t'spectrum'}.\\n\\t\\t{'sonogram' translated.\\t'sonogram'}}.\\n\\tchoice _ aMenu startUp.\\n\\tchoice ifNil: [^ self].\\n\\n\\ton _ soundInput isRecording.\\n\\tself stop.\\n\\tdisplayType _ choice.\\n\\tself resetDisplay.\\n\\ton ifTrue: [self start].\\n\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'menu and buttons' stamp: 'dgd 9/19/2003 13:27'!\\nsetFFTSize\\n\\t\\\"Set the size of the FFT used for frequency analysis.\\\"\\n\\n\\t| aMenu sz on |\\n\\taMenu _ CustomMenu new title: ('FFT size (currently {1})' translated format:{fft n}).\\n\\t((7 to: 10) collect: [:n | 2 raisedTo: n]) do:[:r | aMenu add: r printString action: r].\\n\\tsz _ aMenu startUp.\\n\\tsz ifNil: [^ self].\\n\\ton _ soundInput isRecording.\\n\\tself stop.\\n\\tfft _ FFT new: sz.\\n\\tself resetDisplay.\\n\\ton ifTrue: [self start].\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'menu and buttons' stamp: 'dgd 9/19/2003 13:26'!\\nsetSamplingRate\\n\\t\\\"Set the sampling rate to be used for incoming sound data.\\\"\\n\\n\\t| aMenu rate on |\\n\\taMenu _ CustomMenu new title:\\n\\t\\t('Sampling rate (currently {1})' translated format:{soundInput samplingRate}).\\n\\t#(11025 22050 44100) do:[:r | aMenu add: r printString action: r].\\n\\trate _ aMenu startUp.\\n\\trate ifNil: [^ self].\\n\\ton _ soundInput isRecording.\\n\\tself stop.\\n\\tsoundInput samplingRate: rate.\\n\\tself resetDisplay.\\n\\ton ifTrue: [self start].\\n\\n! !\\n\\n\\n!SpectrumAnalyzerMorph methodsFor: 'stepping and presenter' stamp: 'jm 9/8/1999 15:12'!\\nstart\\n\\t\\\"Start displaying sound data.\\\"\\n\\n\\tdisplayType = 'signal'\\n\\t\\tifTrue: [soundInput bufferSize: graphMorph width - (2 * graphMorph borderWidth)]\\n\\t\\tifFalse: [soundInput bufferSize: fft n].\\n\\tsoundInput startRecording.\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'stepping and presenter' stamp: 'jm 9/8/1999 19:05'!\\nstep\\n\\t\\\"Update the record light, level meter, and display.\\\"\\n\\n\\t| w |\\n\\t\\\"update the record light and level meter\\\"\\n\\tsoundInput isRecording\\n\\t\\tifTrue: [statusLight color: Color yellow]\\n\\t\\tifFalse: [statusLight color: Color gray].\\n\\tw _ ((121 * soundInput meterLevel) // 100) max: 1.\\n\\tlevelMeter width ~= w ifTrue: [levelMeter width: w].\\n\\n\\t\\\"update the display if any data is available\\\"\\n\\tself updateDisplay.\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'stepping and presenter' stamp: 'jm 9/8/1999 15:12'!\\nstop\\n\\t\\\"Stop displaying sound data.\\\"\\n\\n\\tsoundInput stopRecording.\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'stepping and presenter' stamp: 'jm 9/6/1999 12:12'!\\nstopStepping\\n\\t\\\"Turn off recording.\\\"\\n\\n\\tsuper stopStepping.\\n\\tsoundInput stopRecording.\\n! !\\n\\n\\n!SpectrumAnalyzerMorph methodsFor: 'submorphs-add/remove' stamp: 'jm 9/6/1999 14:40'!\\ndelete\\n\\t\\\"Turn off recording when this morph is deleted.\\\"\\n\\n\\tsuper delete.\\n\\tsoundInput stopRecording.\\n! !\\n\\n\\n!SpectrumAnalyzerMorph methodsFor: 'testing' stamp: 'jm 9/7/1999 22:26'!\\nstepTime\\n\\n\\t^ 0\\n! !\\n\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'dgd 9/19/2003 13:30'!\\naddButtonRow\\n\\n\\t| r |\\n\\tr _ AlignmentMorph newRow vResizing: #shrinkWrap.\\n\\tr addMorphBack: (self buttonName: 'Menu' translated action: #invokeMenu).\\n\\tr addMorphBack: (Morph new extent: 4@1; color: Color transparent).\\n\\tr addMorphBack: (self buttonName: 'Start' translated action: #start).\\n\\tr addMorphBack: (Morph new extent: 4@1; color: Color transparent).\\n\\tr addMorphBack: (self buttonName: 'Stop' translated action: #stop).\\n\\tr addMorphBack: (Morph new extent: 12@1; color: Color transparent).\\n\\tr addMorphBack: self makeStatusLight.\\n\\tself addMorphBack: r.\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'ar 11/9/2000 21:23'!\\naddLevelSlider\\n\\n\\t| levelSlider r |\\n\\tlevelSlider _ SimpleSliderMorph new\\n\\t\\tcolor: color;\\n\\t\\textent: 100@2;\\n\\t\\ttarget: soundInput;\\n\\t\\tactionSelector: #recordLevel:;\\n\\t\\tadjustToValue: soundInput recordLevel.\\n\\tr _ AlignmentMorph newRow\\n\\t\\tcolor: color;\\n\\t\\tlayoutInset: 0;\\n\\t\\twrapCentering: #center; cellPositioning: #leftCenter;\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #rigid;\\n\\t\\theight: 24.\\n\\tr addMorphBack: (StringMorph contents: '0 ').\\n\\tr addMorphBack: levelSlider.\\n\\tr addMorphBack: (StringMorph contents: ' 10').\\n\\tself addMorphBack: r.\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'jhm 10/15/97 14:30'!\\nbuttonName: aString action: aSymbol\\n\\n\\t^ SimpleButtonMorph new\\n\\t\\ttarget: self;\\n\\t\\tlabel: aString;\\n\\t\\tactionSelector: aSymbol\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'jm 9/8/1999 13:27'!\\nmakeLevelMeter\\n\\n\\t| outerBox |\\n\\touterBox _ RectangleMorph new extent: 125@14; color: Color lightGray.\\n\\tlevelMeter _ Morph new extent: 2@10; color: Color yellow.\\n\\tlevelMeter position: outerBox topLeft + (2@2).\\n\\touterBox addMorph: levelMeter.\\n\\t^ outerBox\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'dgd 9/19/2003 13:31'!\\nmakeStatusLight\\n\\n\\t| s |\\n\\tstatusLight _ RectangleMorph new extent: 24@19.\\n\\tstatusLight color: Color gray.\\n\\ts _ StringMorph contents: 'On' translated.\\n\\ts position: statusLight center - (s extent // 2).\\n\\tstatusLight addMorph: s.\\n\\t^ statusLight\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'gm 2/28/2003 00:11'!\\nprocessBuffer: buf \\n\\t\\\"Analyze one buffer of data.\\\"\\n\\n\\t| data |\\n\\tdata := displayType = 'signal' \\n\\t\\tifTrue: [buf]\\n\\t\\tifFalse: [fft transformDataFrom: buf startingAt: 1].\\n\\tgraphMorph ifNotNil: \\n\\t\\t\\t[graphMorph\\n\\t\\t\\t\\tdata: data;\\n\\t\\t\\t\\tchanged].\\n\\tsonogramMorph ifNotNil: \\n\\t\\t\\t[data := data collect: [:v | v sqrt].\\t\\\"square root compresses dynamic range\\\"\\n\\t\\t\\tdata /= 400.0.\\n\\t\\t\\tsonogramMorph plotColumn: (data copyFrom: 1 to: data size // 1)]! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'jm 9/8/1999 12:49'!\\nremoveAllDisplays\\n\\t\\\"Remove all currently showing displays.\\\"\\n\\n\\tsonogramMorph ifNotNil: [sonogramMorph delete].\\n\\tgraphMorph ifNotNil: [graphMorph delete].\\n\\tsonogramMorph _ graphMorph _ nil.\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'jm 9/8/1999 19:56'!\\nshowSignal\\n\\t\\\"Display the actual signal waveform.\\\"\\n\\n\\tdisplayType _ 'signal'.\\n\\tself removeAllDisplays.\\n\\tgraphMorph _ GraphMorph new.\\n\\tgraphMorph extent: (400 + (2 * graphMorph borderWidth))@128.\\n\\tgraphMorph data: (Array new: 100 withAll: 0).\\n\\tgraphMorph color: (Color r: 0.8 g: 1.0 b: 1.0).\\n\\tself addMorphBack: graphMorph.\\n\\tself extent: 10@10. \\\"shrink to minimum size\\\"\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'jm 9/8/1999 19:43'!\\nshowSonogram\\n\\t\\\"Display a sonogram showing the frequency spectrum versus time.\\\"\\n\\n\\t| zeros h w |\\n\\tdisplayType _ 'sonogram'.\\n\\tself removeAllDisplays.\\n\\th _ fft n // 2.\\n\\th _ h min: 512 max: 64.\\n\\tw _ 400.\\n\\tsonogramMorph _\\n\\t\\tSonogram new\\n\\t\\t\\textent: w@h\\n\\t\\t\\tminVal: 0.0\\n\\t\\t\\tmaxVal: 1.0\\n\\t\\t\\tscrollDelta: w.\\n\\tzeros _ Array new: sonogramMorph height withAll: 0.\\n\\tsonogramMorph width timesRepeat: [sonogramMorph plotColumn: zeros].\\n\\tself addMorphBack: sonogramMorph.\\n\\tself extent: 10@10. \\\"shrink to minimum size\\\"\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'jm 9/8/1999 15:10'!\\nshowSpectrum\\n\\t\\\"Display the frequency spectrum.\\\"\\n\\n\\tdisplayType _ 'spectrum'.\\n\\tself removeAllDisplays.\\n\\tgraphMorph _ GraphMorph new.\\n\\tgraphMorph extent: ((fft n // 2) + (2 * graphMorph borderWidth))@128.\\n\\tgraphMorph data: (Array new: fft n // 2 withAll: 0).\\n\\tself addMorphBack: graphMorph.\\n\\tself extent: 10@10. \\\"shrink to minimum size\\\"\\n! !\\n\\n!SpectrumAnalyzerMorph methodsFor: 'private' stamp: 'jm 9/8/1999 19:39'!\\nupdateDisplay\\n\\t\\\"Update the display if any data is available.\\\"\\n\\n\\t| buf bufCount |\\n\\tsoundInput bufferCount = 0 ifTrue: [^ self].\\n\\n\\tgraphMorph ifNotNil: [\\n\\t\\t[soundInput bufferCount > 0] whileTrue: [\\n\\t\\t\\t\\\"skip to the most recent buffer\\\"\\n\\t\\t\\tbuf _ soundInput nextBufferOrNil].\\n\\t\\t^ self processBuffer: buf].\\n\\n\\tsonogramMorph ifNotNil: [\\n\\t\\t\\\"at small buffer sizes we have to update the sonogram in\\n\\t\\t batches or we may get behind; shoot for 8 updates/second\\\"\\n\\t\\tbufCount _ (soundInput samplingRate / (8 * soundInput bufferSize)) truncated max: 1.\\n\\t\\t[bufCount > 0 and: [soundInput bufferCount > 0]] whileTrue: [\\n\\t\\t\\tself processBuffer: (soundInput nextBufferOrNil)]].\\n! !\\nPath subclass: #Spline\\n\\tinstanceVariableNames: 'coefficients'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Paths'!\\n!Spline commentStamp: '<historical>' prior: 0!\\nI represent a collection of Points through which a cubic spline curve is fitted.!\\n\\n\\n!Spline methodsFor: 'accessing'!\\ncoefficients\\n\\t\\\"Answer an eight-element Array of Arrays each of which is the length \\n\\tof the receiver. The first four arrays are the values, first, second and \\n\\tthird derivatives, respectively, for the parametric spline in x. The last \\n\\tfour elements are for y.\\\"\\n\\n\\t^coefficients! !\\n\\n\\n!Spline methodsFor: 'displaying'!\\ncomputeCurve\\n\\t\\\"Compute an array for the coefficients.\\\"\\n\\n\\t| length extras |\\n\\tlength _ self size.\\n\\textras _ 0.\\n\\tcoefficients _ Array new: 8.\\n\\t1 to: 8 do: [:i | coefficients at: i put: (Array new: length + extras)].\\n\\t1 to: 5 by: 4 do: \\n\\t\\t[:k | \\n\\t\\t1 to: length do:\\n\\t\\t\\t[:i | (coefficients at: k)\\n\\t\\t\\t\\t\\tat: i put: (k = 1\\n\\t\\t\\t\\t\\t\\tifTrue: [(self at: i) x asFloat]\\n\\t\\t\\t\\t\\t\\tifFalse: [(self at: i) y asFloat])].\\n\\t\\t\\t1 to: extras do: [:i | (coefficients at: k)\\n\\t\\t\\t\\t\\tat: length + i put: ((coefficients at: k)\\n\\t\\t\\t\\t\\t\\tat: i + 1)].\\n\\t\\t\\tself derivs: (coefficients at: k)\\n\\t\\t\\t\\tfirst: (coefficients at: k + 1)\\n\\t\\t\\t\\tsecond: (coefficients at: k + 2)\\n\\t\\t\\t\\tthird: (coefficients at: k + 3)].\\n\\textras > 0 \\n\\t\\tifTrue: [1 to: 8 do: \\n\\t\\t\\t\\t\\t[:i | \\n\\t\\t\\t\\t\\tcoefficients at: i put: ((coefficients at: i)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcopyFrom: 2 to: length + 1)]]! !\\n\\n!Spline methodsFor: 'displaying'!\\ndisplayOn: aDisplayMedium at: aPoint clippingBox: clipRect rule: anInteger fillColor: aForm \\n\\t\\\"Display the receiver, a spline curve, approximated by straight line\\n\\tsegments.\\\"\\n\\n\\t| n line t x y x1 x2 x3 y1 y2 y3 |\\n\\tcollectionOfPoints size < 1 ifTrue: [self error: 'a spline must have at least one point'].\\n\\tline _ Line new.\\n\\tline form: self form.\\n\\tline beginPoint: \\n\\t\\t(x _ (coefficients at: 1) at: 1) rounded @ (y _ (coefficients at: 5) at: 1) rounded.\\n\\t1 to: (coefficients at: 1) size - 1 do: \\n\\t\\t[:i | \\n\\t\\t\\\"taylor series coefficients\\\"\\n\\t\\tx1 _ (coefficients at: 2) at: i.\\n\\t\\ty1 _ (coefficients at: 6) at: i.\\n\\t\\tx2 _ ((coefficients at: 3) at: i) / 2.0.\\n\\t\\ty2 _ ((coefficients at: 7) at: i) / 2.0.\\n\\t\\tx3 _ ((coefficients at: 4) at: i) / 6.0.\\n\\t\\ty3 _ ((coefficients at: 8) at: i) / 6.0.\\n\\t\\t\\\"guess n\\\"\\n\\t\\tn _ 5 max: (x2 abs + y2 abs * 2.0 + ((coefficients at: 3)\\n\\t\\t\\t\\t\\t\\t\\tat: i + 1) abs + ((coefficients at: 7)\\n\\t\\t\\t\\t\\t\\t\\tat: i + 1) abs / 100.0) rounded.\\n\\t\\t1 to: n - 1 do: \\n\\t\\t\\t[:j | \\n\\t\\t\\tt _ j asFloat / n.\\n\\t\\t\\tline endPoint: \\n\\t\\t\\t\\t(x3 * t + x2 * t + x1 * t + x) rounded \\n\\t\\t\\t\\t\\t\\t\\t@ (y3 * t + y2 * t + y1 * t + y) rounded.\\n\\t\\t\\tline\\n\\t\\t\\t\\tdisplayOn: aDisplayMedium\\n\\t\\t\\t\\tat: aPoint\\n\\t\\t\\t\\tclippingBox: clipRect\\n\\t\\t\\t\\trule: anInteger\\n\\t\\t\\t\\tfillColor: aForm.\\n\\t\\t\\tline beginPoint: line endPoint].\\n\\t\\tline beginPoint: \\n\\t\\t\\t\\t(x _ (coefficients at: 1) at: i + 1) rounded \\n\\t\\t\\t\\t\\t@ (y _ (coefficients at: 5) at: i + 1) rounded.\\n\\t\\tline\\n\\t\\t\\tdisplayOn: aDisplayMedium\\n\\t\\t\\tat: aPoint\\n\\t\\t\\tclippingBox: clipRect\\n\\t\\t\\trule: anInteger\\n\\t\\t\\tfillColor: aForm]! !\\n\\n!Spline methodsFor: 'displaying'!\\ndisplayOn: aDisplayMedium transformation: aTransformation clippingBox: clipRect rule: anInteger fillColor: aForm \\n\\t\\\"Get the scaled and translated path of newKnots.\\\"\\n\\n\\t| newKnots newSpline |\\n\\tnewKnots _ aTransformation applyTo: self.\\n\\tnewSpline _ Spline new.\\n\\tnewKnots do: [:knot | newSpline add: knot].\\n\\tnewSpline form: self form.\\n\\tnewSpline\\n\\t\\tdisplayOn: aDisplayMedium\\n\\t\\tat: 0 @ 0\\n\\t\\tclippingBox: clipRect\\n\\t\\trule: anInteger\\n\\t\\tfillColor: aForm! !\\n\\n\\n!Spline methodsFor: 'private'!\\nderivs: a first: point1 second: point2 third: point3\\n\\t\\\"Compute the first, second and third derivitives (in coefficients) from\\n\\tthe Points in this Path (coefficients at: 1 and coefficients at: 5).\\\"\\n\\n\\t| l v anArray |\\n\\tl _ a size.\\n\\tl < 2 ifTrue: [^self].\\n\\tl > 2\\n\\t ifTrue:\\n\\t\\t[v _ Array new: l.\\n\\t\\t v at: 1 put: 4.0.\\n\\t\\t anArray _ Array new: l.\\n\\t\\t anArray at: 1 put: (6.0 * ((a at: 1) - ((a at: 2) * 2.0) + (a at: 3))).\\n\\t\\t 2 to: l - 2 do:\\n\\t\\t\\t[:i | \\n\\t\\t\\tv at: i put: (4.0 - (1.0 / (v at: (i - 1)))).\\n\\t\\t\\tanArray\\n\\t\\t\\t\\tat: i \\n\\t\\t\\t\\tput: (6.0 * ((a at: i) - ((a at: (i + 1)) * 2.0) + (a at: (i + 2)))\\n\\t\\t\\t\\t\\t\\t- ((anArray at: (i - 1)) / (v at: (i - 1))))].\\n\\t\\t point2 at: (l - 1) put: ((anArray at: (l - 2)) / (v at: (l - 2))).\\n\\t\\t l - 2 to: 2 by: 0-1 do: \\n\\t\\t\\t[:i | \\n\\t\\t\\tpoint2 \\n\\t\\t\\t\\tat: i \\n\\t\\t\\t\\tput: ((anArray at: (i - 1)) - (point2 at: (i + 1)) / (v at: (i - 1)))]].\\n\\tpoint2 at: 1 put: (point2 at: l put: 0.0).\\n\\t1 to: l - 1 do:\\n\\t\\t[:i | point1 \\n\\t\\t\\t\\tat: i \\n\\t\\t\\t\\tput: ((a at: (i + 1)) - (a at: i) - \\n\\t\\t\\t\\t\\t\\t((point2 at: i) * 2.0 + (point2 at: (i + 1)) / 6.0)).\\n\\t\\t point3 at: i put: ((point2 at: (i + 1)) - (point2 at: i))]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSpline class\\n\\tinstanceVariableNames: ''!\\n\\n!Spline class methodsFor: 'examples' stamp: '6/8/97 13:55 di'!\\nexample\\n\\t\\\"Designate points on the Path by clicking the red button. Terminate by\\n\\tpressing any other button. A curve will be displayed, through the\\n\\tselected points, using a long black form.\\\"\\n\\n\\t| splineCurve aForm flag|\\n\\taForm _ Form extent: 2@2.\\n\\taForm fillBlack.\\n\\tsplineCurve _ Spline new.\\n\\tsplineCurve form: aForm.\\n\\tflag _ true.\\n\\t[flag] whileTrue:\\n\\t\\t[Sensor waitButton.\\n\\t\\t Sensor redButtonPressed\\n\\t\\t\\tifTrue: \\n\\t\\t\\t\\t[splineCurve add: Sensor waitButton. \\n\\t\\t\\t\\t Sensor waitNoButton.\\n\\t\\t\\t\\t aForm displayOn: Display at: splineCurve last]\\n\\t\\t\\tifFalse: [flag_false]].\\n\\tsplineCurve computeCurve.\\n\\tsplineCurve isEmpty \\n\\t\\tifFalse: [splineCurve displayOn: Display.\\n\\t\\t\\t\\tSensor waitNoButton].\\n \\n\\t\\\"Spline example\\\"! !\\nObject subclass: #SqNumberParser\\n\\tinstanceVariableNames: 'sourceStream base neg integerPart fractionPart exponent scale nDigits lastNonZero requestor failBlock'\\n\\tclassVariableNames: 'BelllerophonBase10'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Numbers'!\\n!SqNumberParser commentStamp: 'nice 4/27/2006 22:38' prior: 0!\\nThis is a class specialized in parsing and building numbers.\\nNumber syntax should follow Smalltalk syntax.\\n\\nIf you have to read foreign number syntax, create a subclass.!\\n\\n\\n!SqNumberParser methodsFor: 'error' stamp: 'nice 4/28/2006 00:20'!\\nexpected: errorString \\n\\trequestor isNil\\n\\t\\tifFalse: [requestor\\n\\t\\t\\t\\tnotify: errorString , ' ->'\\n\\t\\t\\t\\tat: sourceStream position\\n\\t\\t\\t\\tin: sourceStream].\\n\\tself fail! !\\n\\n!SqNumberParser methodsFor: 'error' stamp: 'nice 4/28/2006 00:19'!\\nfail\\n\\tfailBlock isNil ifFalse: [^failBlock value].\\n\\tself error: 'Reading a number failed'! !\\n\\n\\n!SqNumberParser methodsFor: 'accessing' stamp: 'nice 4/27/2006 22:57'!\\nexponentLetters\\n\\t\\\"answer the list of possible exponents for Numbers.\\n\\tNote: this parser will not honour precision attached to the exponent.\\n\\tdifferent exponent do not lead to different precisions.\\n\\tonly IEEE 754 floating point numbers will be created\\\"\\n\\t\\n\\t^'edq'! !\\n\\n!SqNumberParser methodsFor: 'accessing' stamp: 'nice 5/1/2006 01:58'!\\nfailBlock: aBlockOrNil\\n\\tfailBlock := aBlockOrNil! !\\n\\n!SqNumberParser methodsFor: 'accessing' stamp: 'nice 5/1/2006 01:59'!\\nrequestor: anObjectOrNil\\n\\trequestor := anObjectOrNil! !\\n\\n\\n!SqNumberParser methodsFor: 'parsing-private' stamp: 'nice 5/7/2006 17:33'!\\nmakeFloatFromMantissa: m exponent: k base: aRadix \\n\\t\\\"Convert infinite precision arithmetic into Floating point.\\n\\tThis alogrithm rely on correct IEEE rounding mode\\n\\tbeing implemented in Integer>>asFloat and Fraction>>asFloat\\\"\\n\\n\\t^(k positive\\n\\t\\tifTrue: [m * (aRadix raisedTo: k)]\\n\\t\\tifFalse: [Fraction numerator: m denominator: (aRadix raisedTo: k negated)]) asFloat! !\\n\\n!SqNumberParser methodsFor: 'parsing-private' stamp: 'nice 4/28/2006 00:52'!\\nmakeIntegerOrScaledInteger\\n\\t\\\"at this point, there is no digit, nor fractionPart.\\n\\tmaybe it can be a scaled decimal with fraction omitted...\\\"\\n\\t\\n\\tneg\\n\\t\\tifTrue: [integerPart := integerPart negated].\\n\\tself readExponent\\n\\t\\tifTrue: [integerPart := integerPart\\n\\t\\t\\t\\t\\t\\t* (base raisedTo: exponent)]\\n\\t\\tifFalse: [self readScale\\n\\t\\t\\t\\tifTrue: [nil.\\n\\t\\t\\t\\t\\t^ ScaledDecimal newFromNumber: integerPart scale: scale]].\\n\\t^ integerPart! !\\n\\n!SqNumberParser methodsFor: 'parsing-private' stamp: 'nice 4/28/2006 01:14'!\\nreadExponent\\n\\t\\\"read the exponent if any (stored in instVar).\\n\\tAnswer true if found, answer false if none.\\n\\tIf exponent letter is not followed by a digit,\\n\\tthis is not considered as an error.\\n\\tExponent are always read in base 10, though i do not see why...\\\"\\n\\t\\n\\t| eneg |\\n\\texponent := 0.\\n\\tsourceStream atEnd\\n\\t\\tifTrue: [^ false].\\n\\t(self exponentLetters includes: sourceStream next)\\n\\t\\tifFalse: [sourceStream skip: -1.\\n\\t\\t\\t^ false].\\n\\teneg := sourceStream peekFor: $-.\\n\\texponent := self\\n\\t\\t\\t\\tnextUnsignedIntegerBase: 10\\n\\t\\t\\t\\tifFail: [sourceStream\\n\\t\\t\\t\\t\\t\\tskip: (eneg\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [-2]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [-1]).\\n\\t\\t\\t\\t\\t^ false].\\n\\teneg\\n\\t\\tifTrue: [exponent := exponent negated].\\n\\t^ true! !\\n\\n!SqNumberParser methodsFor: 'parsing-private' stamp: 'nice 4/28/2006 03:08'!\\nreadScale\\n\\t\\\"read the scale if any (stored in instVar).\\n\\tAnswer true if found, answer false if none.\\n\\tIf scale letter is not followed by a digit,\\n\\tthis is not considered as an error.\\n\\tScales are always read in base 10, though i do not see why...\\\"\\n\\t\\n\\tscale := 0.\\n\\tsourceStream atEnd ifTrue: [^ false].\\n\\t('s' includes: sourceStream next)\\n\\t\\tifFalse: [sourceStream skip: -1.\\n\\t\\t\\t^ false].\\n\\tscale := self\\n\\t\\t\\t\\tnextUnsignedIntegerBase: 10\\n\\t\\t\\t\\tifFail: [sourceStream skip: -1.\\n\\t\\t\\t\\t\\t^ false].\\n\\t^ true! !\\n\\n\\n!SqNumberParser methodsFor: 'parsing-public' stamp: 'nice 4/27/2006 23:08'!\\nnextIntegerBase: aRadix\\n\\t\\\"Form an integer with following digits\\\"\\n\\t\\n\\t| isNeg value |\\n\\tisNeg := sourceStream peekFor: $-.\\n\\tvalue := self nextUnsignedIntegerBase: aRadix.\\n\\t^isNeg\\n\\t\\tifTrue: [value negated]\\n\\t\\tifFalse: [value]! !\\n\\n!SqNumberParser methodsFor: 'parsing-public' stamp: 'nice 4/28/2006 01:12'!\\nnextIntegerBase: aRadix ifFail: aBlock\\n\\t\\\"Form an integer with following digits\\\"\\n\\t\\n\\t| isNeg value |\\n\\tisNeg := sourceStream peekFor: $-.\\n\\tvalue := self nextUnsignedIntegerBase: aRadix ifFail: [^aBlock value].\\n\\t^isNeg\\n\\t\\tifTrue: [value negated]\\n\\t\\tifFalse: [value]! !\\n\\n!SqNumberParser methodsFor: 'parsing-public' stamp: 'nice 4/28/2006 03:38'!\\nnextNumber\\n\\t\\\"main method for reading a number.\\n\\tThis one can read Float Integer and ScaledDecimal\\\"\\n\\t\\n\\t| numberOfTrailingZeroInIntegerPart numberOfNonZeroFractionDigits mantissa decimalMultiplier decimalFraction value numberOfTrailingZeroInFractionPart |\\n\\t(sourceStream nextMatchAll: 'NaN')\\n\\t\\tifTrue: [^ Float nan].\\n\\tneg := sourceStream peekFor: $-.\\n\\t(sourceStream nextMatchAll: 'Infinity')\\n\\t\\tifTrue: [^ neg\\n\\t\\t\\t\\tifTrue: [Float infinity negated]\\n\\t\\t\\t\\tifFalse: [Float infinity]].\\n\\tintegerPart := self nextUnsignedIntegerBase: base.\\n\\tnumberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.\\n\\t(sourceStream peekFor: $r)\\n\\t\\tifTrue: [\\\"<base>r<integer>\\\"\\n\\t\\t\\t(base := integerPart) < 2\\n\\t\\t\\t\\tifTrue: [^ self expected: 'an integer greater than 1 as valid radix'].\\n\\t\\t\\t(sourceStream peekFor: $-)\\n\\t\\t\\t\\tifTrue: [neg := neg not].\\n\\t\\t\\tintegerPart := self nextUnsignedIntegerBase: base.\\n\\t\\t\\tnumberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].\\n\\t^ (sourceStream peekFor: $.)\\n\\t\\tifTrue: [fractionPart := self\\n\\t\\t\\t\\t\\t\\tnextUnsignedIntegerBase: base\\n\\t\\t\\t\\t\\t\\tifFail: [sourceStream skip: -1.\\n\\t\\t\\t\\t\\t\\t\\t^ neg\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [integerPart negated]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [integerPart]].\\n\\t\\t\\tnumberOfNonZeroFractionDigits := lastNonZero.\\n\\t\\t\\tnumberOfTrailingZeroInFractionPart := nDigits - lastNonZero.\\n\\t\\t\\tself readExponent\\n\\t\\t\\t\\tifFalse: [self readScale\\n\\t\\t\\t\\t\\t\\tifTrue: [decimalMultiplier := base raisedTo: numberOfNonZeroFractionDigits.\\n\\t\\t\\t\\t\\t\\t\\tdecimalFraction := integerPart * decimalMultiplier + fractionPart / decimalMultiplier.\\n\\t\\t\\t\\t\\t\\t\\tneg\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [decimalFraction := decimalFraction negated].\\n\\t\\t\\t\\t\\t\\t\\t^ ScaledDecimal newFromNumber: decimalFraction scale: scale]].\\n\\t\\t\\tfractionPart isZero\\n\\t\\t\\t\\tifTrue: [mantissa := integerPart\\n\\t\\t\\t\\t\\t\\t\\t\\t// (base raisedTo: numberOfTrailingZeroInIntegerPart).\\n\\t\\t\\t\\t\\texponent := exponent + numberOfTrailingZeroInIntegerPart]\\n\\t\\t\\t\\tifFalse: [mantissa := integerPart\\n\\t\\t\\t\\t\\t\\t\\t\\t* (base raisedTo: numberOfNonZeroFractionDigits) + (fractionPart // (base raisedTo: numberOfTrailingZeroInFractionPart)).\\n\\t\\t\\t\\t\\texponent := exponent - numberOfNonZeroFractionDigits].\\n\\t\\t\\t\\\"very naive algorithm\\\"\\n\\t\\t\\tvalue := self makeFloatFromMantissa: mantissa exponent: exponent base: base.\\n\\t\\t\\t^ neg\\n\\t\\t\\t\\tifTrue: [value isZero\\n\\t\\t\\t\\t\\t\\tifTrue: [Float negativeZero]\\n\\t\\t\\t\\t\\t\\tifFalse: [value negated]]\\n\\t\\t\\t\\tifFalse: [value]]\\n\\t\\tifFalse: [self makeIntegerOrScaledInteger]! !\\n\\n!SqNumberParser methodsFor: 'parsing-public' stamp: 'nice 4/28/2006 01:10'!\\nnextUnsignedIntegerBase: aRadix \\n\\t\\\"Form an unsigned integer with incoming digits from sourceStream.\\n\\tCount the number of digits and the lastNonZero digit and store int in\\n\\tinstVar \\\"\\n\\t\\n\\t^ self\\n\\t\\tnextUnsignedIntegerBase: aRadix\\n\\t\\tifFail: [self expected: 'a digit between 0 and 9']! !\\n\\n!SqNumberParser methodsFor: 'parsing-public' stamp: 'nice 4/28/2006 03:14'!\\nnextUnsignedIntegerBase: aRadix ifFail: errorBlock\\n\\t\\\"Form an unsigned integer with incoming digits from sourceStream.\\n\\tCount the number of digits and the lastNonZero digit and store int in instVar\\\"\\n\\t\\n\\t| value digit |\\n\\tvalue := 0.\\n\\tnDigits := 0.\\n\\tlastNonZero := 0.\\n\\t[sourceStream atEnd\\n\\t\\tor: [digit := sourceStream next digitValue.\\n\\t\\t\\t(digit < 0\\n\\t\\t\\t\\t\\tor: [digit >= aRadix])\\n\\t\\t\\t\\tand: [sourceStream skip: -1.\\n\\t\\t\\t\\t\\ttrue]]]\\n\\t\\twhileFalse: [nDigits := nDigits + 1.\\n\\t\\t\\tdigit isZero\\n\\t\\t\\t\\tifFalse: [lastNonZero := nDigits].\\n\\t\\t\\tvalue := value * aRadix + digit].\\n\\tnDigits = 0\\n\\t\\tifTrue: [errorBlock value].\\n\\t^value! !\\n\\n\\n!SqNumberParser methodsFor: 'initialize-release' stamp: 'nice 5/1/2006 00:41'!\\non: aStringOrStream\\n\\tsourceStream := aStringOrStream isString\\n\\t\\tifTrue: [ReadStream on: aStringOrStream]\\n\\t\\tifFalse: [aStringOrStream].\\n\\tbase := 10.\\n\\tneg := false.\\n\\tintegerPart := fractionPart := exponent := scale := 0.\\n\\trequestor := failBlock := nil.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSqNumberParser class\\n\\tinstanceVariableNames: ''!\\n\\n!SqNumberParser class methodsFor: 'instance creation' stamp: 'nice 5/1/2006 00:45'!\\non: aStringOrStream\\n\\t^self new on: aStringOrStream! !\\n\\n!SqNumberParser class methodsFor: 'instance creation' stamp: 'nice 5/1/2006 02:02'!\\nparse: aStringOrStream \\n\\t^(self new)\\n\\t\\ton: aStringOrStream;\\n\\t\\tnextNumber! !\\n\\n!SqNumberParser class methodsFor: 'instance creation' stamp: 'nice 5/1/2006 02:02'!\\nparse: aStringOrStream onError: failBlock \\n\\t^(self new)\\n\\t\\ton: aStringOrStream;\\n\\t\\tfailBlock: failBlock;\\n\\t\\tnextNumber! !\\nClassTestCase subclass: #SqNumberParserTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'KernelTests-Numbers'!\\n!SqNumberParserTest commentStamp: 'nice 5/7/2006 17:54' prior: 0!\\nProvide tests for new clas aimed at parsing numbers.\\n\\nIt duplicates NumberParsingTest, with few more tests.!\\n\\n\\n!SqNumberParserTest methodsFor: 'tests - Float' stamp: 'nice 5/7/2006 17:46'!\\ntestFloatFromStreamAsNumber\\n\\t\\\"This covers parsing in Number>>readFrom:\\\"\\n\\n\\t| rs aFloat |\\n\\trs := '10r-12.3456' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: -12.3456 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs := '10r-12.3456e2' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs := '10r-12.3456e2e2' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs upToEnd = 'e2'.\\n\\n\\trs := '10r-12.3456d2' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs := '10r-12.3456q2' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs := '-12.3456q2' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: -1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs := '12.3456q2' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: 1234.56 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs := '12.3456z2' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: 12.3456 = aFloat.\\n\\tself assert: rs upToEnd = 'z2'.\\n! !\\n\\n!SqNumberParserTest methodsFor: 'tests - Float' stamp: 'nice 5/7/2006 17:46'!\\ntestFloatFromStreamWithExponent\\n\\t\\\"This covers parsing in Number>>readFrom:\\\"\\n\\n\\t| rs aFloat |\\n\\trs := '1.0e-14' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: 1.0e-14 = aFloat.\\n\\tself assert: rs atEnd.\\n\\n\\trs := '1.0e-14 1' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: 1.0e-14 = aFloat.\\n\\tself assert: rs upToEnd = ' 1'.\\n\\n\\trs := '1.0e-14eee' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: 1.0e-14 = aFloat.\\n\\tself assert: rs upToEnd = 'eee'.\\n\\n\\trs := '1.0e14e10' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: 1.0e14 = aFloat.\\n\\tself assert: rs upToEnd = 'e10'.\\n\\n\\trs := '1.0e+14e' readStream. \\\"Plus sign is not parseable\\\"\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: 1.0 = aFloat.\\n\\tself assert: rs upToEnd = 'e+14e'.\\n\\n\\trs := '1.0e' readStream.\\n\\taFloat := SqNumberParser parse: rs.\\n\\tself assert: 1.0 = aFloat.\\n\\tself assert: rs upToEnd = 'e'.! !\\n\\n!SqNumberParserTest methodsFor: 'tests - Float' stamp: 'nice 5/1/2006 00:40'!\\ntestFloatPrintString\\n\\t\\\"self debug: #testFloatPrintString\\\"\\n\\t\\n\\t| f r |\\n\\tf := Float basicNew: 2.\\n\\tr := Random new seed: 1234567.\\n\\t100\\n\\t\\ttimesRepeat: [f basicAt: 1 put: (r nextInt: 16r100000000)- 1.\\n\\t\\t\\tf basicAt: 2 put: (r nextInt: 16r100000000) - 1.\\n\\t\\t\\t#(2 8 10 16)\\n\\t\\t\\t\\tdo: [:base | | str |\\n\\t\\t\\t\\t\\t\\tstr := (String new: 64) writeStream.\\n\\t\\t\\t\\t\\t\\tf negative ifTrue: [str nextPut: $-].\\n\\t\\t\\t\\t\\t\\tstr print: base; nextPut: $r.\\n\\t\\t\\t\\t\\t\\tf absPrintExactlyOn: str base: base.\\n\\t\\t\\t\\t\\t\\tself assert: (SqNumberParser parse: str contents) = f]].\\n\\t\\\"test big num near infinity\\\"\\n\\t10\\n\\t\\ttimesRepeat: [f basicAt: 1 put: 16r7FE00000 + ((r nextInt: 16r100000) - 1).\\n\\t\\t\\tf basicAt: 2 put: (r nextInt: 16r100000000) - 1.\\n\\t\\t\\t#(2 8 10 16)\\n\\t\\t\\t\\tdo: [:base | | str |\\n\\t\\t\\t\\t\\t\\tstr := (String new: 64) writeStream.\\n\\t\\t\\t\\t\\t\\tf negative ifTrue: [str nextPut: $-].\\n\\t\\t\\t\\t\\t\\tstr print: base; nextPut: $r.\\n\\t\\t\\t\\t\\t\\tf absPrintExactlyOn: str base: base.\\n\\t\\t\\t\\t\\t\\tself assert: (SqNumberParser parse: str contents) = f]].\\n\\t\\\"test infinitesimal (gradual underflow)\\\"\\n\\t10\\n\\t\\ttimesRepeat: [f basicAt: 1 put: 0 + ((r nextInt: 16r100000) - 1).\\n\\t\\t\\tf basicAt: 2 put: (r nextInt: 16r100000000) - 1.\\n\\t\\t\\t#(2 8 10 16)\\n\\t\\t\\t\\tdo: [:base | | str |\\n\\t\\t\\t\\t\\t\\tstr := (String new: 64) writeStream.\\n\\t\\t\\t\\t\\t\\tf negative ifTrue: [str nextPut: $-].\\n\\t\\t\\t\\t\\t\\tstr print: base; nextPut: $r.\\n\\t\\t\\t\\t\\t\\tf absPrintExactlyOn: str base: base.\\n\\t\\t\\t\\t\\t\\tself assert: (SqNumberParser parse: str contents) = f]].! !\\n\\n!SqNumberParserTest methodsFor: 'tests - Float' stamp: 'nice 5/1/2006 00:40'!\\ntestFloatReadError\\n\\t\\\"This covers parsing in Number>>readFrom:\\\"\\n\\n\\t| rs num |\\n\\trs := '1e' readStream.\\n\\tnum := SqNumberParser parse: rs.\\n\\tself assert: 1 = num.\\n\\tself assert: rs upToEnd = 'e'.\\n\\t\\n\\trs := '1s' readStream.\\n\\tnum := SqNumberParser parse: rs.\\n\\tself assert: 1 = num.\\n\\tself assert: rs upToEnd = 's'.\\n\\n\\trs := '1.' readStream.\\n\\tnum := SqNumberParser parse: rs.\\n\\tself assert: 1 = num.\\n\\tself assert: num isInteger.\\n\\tself assert: rs upToEnd = '.'.\\n\\t\\n\\trs := '' readStream.\\n\\tself should: [SqNumberParser parse: rs] raise: Error.\\n\\t\\n\\trs := 'foo' readStream.\\n\\tself should: [SqNumberParser parse: rs] raise: Error.\\n\\n\\trs := 'radix' readStream.\\n\\tself should: [SqNumberParser parse: rs] raise: Error.\\n\\t\\n\\trs := '.e0' readStream.\\n\\tself should: [SqNumberParser parse: rs] raise: Error.\\n\\t\\n\\trs := '-.e0' readStream.\\n\\tself should: [SqNumberParser parse: rs] raise: Error.\\n\\t\\n\\trs := '--1' readStream.\\n\\tself should: [SqNumberParser parse: rs] raise: Error.! !\\n\\n!SqNumberParserTest methodsFor: 'tests - Float' stamp: 'nice 5/7/2006 17:46'!\\ntestFloatReadWithRadix\\n\\t\\\"This covers parsing in Number>>readFrom:\\n\\tNote: In most Smalltalk dialects, the radix notation is not used for numbers\\n\\twith exponents. In Squeak, a string with radix and exponent can be parsed,\\n\\tand the exponent is always treated as base 10 (not the base indicated in the\\n\\tradix prefix). I am not sure if this is a feature, a bug, or both, but the\\n\\tSqueak behavior is documented in this test. -dtl\\\"\\n\\n\\t| aNumber rs |\\n\\taNumber := '2r1.0101e9' asNumber.\\n\\tself assert: 672.0 = aNumber.\\n\\tself assert: (SqNumberParser parse: '2r1.0101e9') = (1.3125 * (2 raisedTo: 9)).\\n\\trs := ReadStream on: '2r1.0101e9e9'.\\n\\tself assert: (SqNumberParser parse: rs) = 672.0.\\n\\tself assert: rs upToEnd = 'e9'\\n! !\\n\\n\\n!SqNumberParserTest methodsFor: 'tests - Integer' stamp: 'nice 5/7/2006 17:46'!\\ntestIntegerReadFrom\\n\\t\\\"Ensure remaining characters in a stream are not lost when parsing an integer.\\\"\\n\\n\\t| rs i s |\\n\\trs := ReadStream on: '123s could be confused with a ScaledDecimal'.\\n\\ti := SqNumberParser parse: rs.\\n\\tself assert: i == 123.\\n\\ts := rs upToEnd.\\n\\tself assert: 's could be confused with a ScaledDecimal' = s.\\n\\trs := ReadStream on: '123.s could be confused with a ScaledDecimal'.\\n\\ti := SqNumberParser parse: rs.\\n\\tself assert: i == 123.\\n\\ts := rs upToEnd.\\n\\tself assert: '.s could be confused with a ScaledDecimal' = s\\n! !\\n\\n!SqNumberParserTest methodsFor: 'tests - Integer' stamp: 'nice 5/7/2006 17:46'!\\ntestIntegerReadWithRadix\\n\\t\\\"This covers parsing in Number>>readFrom:\\n\\tNote: In most Smalltalk dialects, the radix notation is not used for numbers\\n\\twith exponents. In Squeak, a string with radix and exponent can be parsed,\\n\\tand the exponent is always treated as base 10 (not the base indicated in the\\n\\tradix prefix). I am not sure if this is a feature, a bug, or both, but the\\n\\tSqueak behavior is documented in this test. -dtl\\\"\\n\\n\\t| aNumber rs |\\n\\taNumber := '2r1e26' asNumber.\\n\\tself assert: 67108864 = aNumber.\\n\\tself assert: (SqNumberParser parse: '2r1e26') = (2 raisedTo: 26).\\n\\trs := '2r1e26eee' readStream.\\n\\tself assert: (SqNumberParser parse: rs) = 67108864.\\n\\tself assert: rs upToEnd = 'eee'\\n! !\\nObject subclass: #SqueakPage\\n\\tinstanceVariableNames: 'url title comment thumbnail contentsMorph creationTime creationAuthor lastChangeTime lastChangeAuthor policy dirty'\\n\\tclassVariableNames: 'MaxThumbnailWidthOrHeight RecentMaxNum RecentStem'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SqueakPage'!\\n!SqueakPage commentStamp: '<historical>' prior: 0!\\nA SqueakPage is holder for a page of morphs that live on the disk or on a server.\\nA URLMorph is a thumbnail sized stand-in for the page. Clicking on it gets the page.\\nAn ObjectOut is a fake object that stands for an object that is out on the disk. (Like ObjectTracer or ObjectViewer.)\\nA MorphObjectOut is a subclass that stands for a Morph that is out on the disk.\\n\\nTo find out how to make the pages of any BookMorph go out to the disk (or a server), see \\thttp://minnow.cc.gatech.edu/SqueakDoc.1 then go to 'SqueakPages'.\\n\\nA SqueakPage is always in-memory. Its contentsMorph will be 'become-ed' to a MorphObjectOut tombstone when it goes out. (A page may or may not be in the cache. First put it in, then ask it for the data.) Sending any message to the contentsMorph triggers the fetch. Many URLMorphs may hold onto one page. A page has a thumbnail. A URLMorph points at its page object.\\n\\nStates of a SqueakPage, and the transitions to another state:\\n1) have a url as a string. Then: (URLMorph grabURL: 'file://Ted''s/books/tryThis/p1'). \\n\\tDrop it into any morph.\\n2) have a URLMorph, with page==nil. Click it. (makes an empty page, installs \\n\\tit in the global page cache)\\n3) have a URLMorph with a SqueakPage, with contentsMorph==nil, \\n\\tbut page is not in the cache (this is a rare case). ask page contentsMorph.\\n4) OUT: have a URLMorph with a SqueakPage, with contentsMorph being a MorphObjectOut, \\n\\tand its page is in the cache. Sending the contentsMorph any message brings it in and\\n\\tbecomes it to the morph. (fix up morph's pointer to the page.)\\n5) Totally IN: a morph, owned by a SqueakPage, has a page in the cache. \\n\\tThe morph is clean. \\n\\tWhenever someone triggers a purge (when?), contentsMorph is becomed\\n\\tto a MorphObjectOut. (go to 4)\\n\\tCausing the morph to execute layoutChanged marks the morph as dirty.\\n\\t(morph's property #pageDirty is set to true) (go to 6)\\n6) Totally IN and dirty. \\n\\tWhenever any other page is fetched from the disk or the net, all other \\n\\tdirty pages are written and marked clean. (go to 5)\\n\\nNote that the entire tree of submorphs goes out -- hundreds of objects. Bringing the object back in brings in the SqueakPage, installs it in the cache. Classes other than PasteUpMorph can easily be made to send their contents out if there is any need.\\n\\nNote that every book is now automatically a WebBook. We simply give a page a url and tell it to purge.\\n\\nurl\\t\\ta string\\ntitle\\t\\t\\ncomment\\t\\t\\nthumbnail\\t\\t\\ncontentsMorph\\t\\t(1) a pasteUpMorph with other morphs in it.\\n\\t\\t\\t\\t\\t(2) a MorphObjectOut. Sending any message brings it in. \\n\\t\\t\\t\\t\\t(3) nil if the page has never been in this image.\\ncreationTime\\t\\t\\ncreationAuthor\\t\\t\\nlastChangeTime\\t\\t\\nlastChangeAuthor \\npolicy\\t\\t#alwaysWrite, #neverWrite, #ask. (cache can override with a global policy)\\n\\t\\t\\t(Explicit writing by user has policy #neverWrite)\\ndirty \\t\\t(Morph>>layoutChanged sends changed: #SqueakPage. If policy==#check, \\n\\t\\t\\t\\tthen the page sets dirty_true.)\\n\\t\\t\\t(If policy==#alwaysWrite, then set dirty when the page is retrieved from the cache.)\\n\\nClass MorphObjectOut has an instance variable called page.\\nAll messages to an MorphObjectOut cause it to be brought in. Except the messages needed to write the MorphObjectOut on the disk as part of a parent's being sent out. (size, class, instSize, instVar:at:. Can rename these and call from its own version of the writing routine.)\\n\\tTo purge, go through the clean pages, and any that have world not equal to this world, entomb them. \\n\\t(If an object in the subtree is held by an object outside the tree, it will remain, And will be duplicated when the tree comes back in. This is a problem already in normal uses of SmartRefStream.)\\n\\n\\n!\\n\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 2/5/1999 16:47'!\\nasMorph\\n\\t^ self fetchContents! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'jm 6/16/1998 13:47'!\\ncomment\\n\\n\\tcomment ifNil: [^ ''] ifNotNil: [^ comment].\\n! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'jm 6/16/1998 18:12'!\\ncomment: aString\\n\\n\\taString isEmpty\\n\\t\\tifTrue: [comment _ nil]\\n\\t\\tifFalse: [comment _ aString].\\n! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 10/2/1998 11:27'!\\ncontentsMorph\\n\\t\\\"Return what it is now. If the morph is out on the disk, return nil. Use fetchContents to get the data for sure.\\\"\\n\\n\\t^ contentsMorph\\n! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 11/11/1998 12:54'!\\ncontentsMorph: aPasteUpMorph\\n\\n\\tcontentsMorph _ aPasteUpMorph! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 2/23/1999 14:39'!\\ncopyForSaving\\n\\t\\\"Make a copy and configure me to be put out on the disk. When it is brought in and touched, it will turn into the object at the url.\\\"\\n\\n\\t| forDisk holder |\\n\\tforDisk _ self clone.\\n\\tholder _ MorphObjectOut new xxxSetUrl: url page: forDisk.\\n\\tforDisk contentsMorph: holder.\\n\\t^ holder\\t\\t\\\"directly representing the object\\\"! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 10/30/1998 15:08'!\\nfetchContents\\n\\t\\\"Make every effort to get contentsMorph.\\\"\\n\\n\\tself isContentsInMemory ifTrue: [^ contentsMorph].\\n\\t^ self fetchInformIfError! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'ar 4/10/2005 18:52'!\\nfetchContentsIfAbsent: failBlock\\n\\t\\\"Make every effort to get contentsMorph. Assume I am in the cache already.\\\"\\n\\t| strm page temp temp2 |\\n\\tSqueakPageCache write.\\t\\t\\\"sorry about the pause\\\"\\n\\tCursor wait showWhile: [\\n\\t\\tstrm _ (ServerFile new fullPath: url) asStream].\\n\\tstrm isString ifTrue: [^ failBlock value].\\t\\t\\n\\tpage _ strm fileInObjectAndCode.\\n\\tpage isMorph ifTrue: [contentsMorph _ page].\\t\\\"may be a bare morph\\\"\\n\\t\\\"copy over the state\\\"\\n\\ttemp _ url.\\n\\ttemp2 _ policy.\\n\\tself copyAddedStateFrom: page.\\n\\turl _ temp.\\t\\\"don't care what it says\\\"\\n\\ttemp2 ifNotNil: [policy _ temp2].\\t\\t\\\"use mine\\\"\\n\\tcontentsMorph setProperty: #pageDirty toValue: nil.\\n\\tself dirty: false.\\n\\t^ contentsMorph! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'ar 4/10/2005 18:52'!\\nfetchInformIfError\\n\\t\\\"Make every effort to get contentsMorph. Put up a good notice if can't get it. Assume page is in the cache already. Overwrite the contentsMorph no matter what.\\\"\\n\\t| strm page temp temp2 |\\n\\n\\tSqueakPageCache write.\\t\\t\\\"sorry about the pause\\\"\\n\\tCursor wait showWhile: [\\n\\t\\tstrm _ (ServerFile new fullPath: url) asStream].\\n\\tstrm isString ifTrue: [self inform: 'Sorry, ',strm. ^ nil].\\t\\\"<<<<< Note Diff\\\"\\n\\t(url beginsWith: 'file:') ifTrue: [Transcript show: 'Fetching ', url; cr].\\t\\n\\tpage _ strm fileInObjectAndCode.\\n\\tpage isMorph \\n\\t\\tifTrue: [contentsMorph _ page]\\t\\\"may be a bare morph\\\"\\n\\t\\tifFalse: [\\\"copy over the state\\\"\\n\\t\\t\\ttemp _ url.\\n\\t\\t\\ttemp2 _ policy.\\n\\t\\t\\tself copyFrom: page.\\t\\\"including contentsMorph\\\"\\n\\t\\t\\turl _ temp.\\t\\\"I know best!!\\\"\\n\\t\\t\\ttemp2 ifNotNil: [policy _ temp2]].\\t\\t\\\"use mine\\\"\\n\\tcontentsMorph setProperty: #pageDirty toValue: nil.\\n\\tcontentsMorph setProperty: #SqueakPage toValue: self.\\n\\tself dirty: false.\\n\\t^ contentsMorph! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 10/30/1998 15:08'!\\nisContentsInMemory\\n\\t\\\"Is my contentsMorph in memory, or is it an ObjectOut tombstone? Be careful not to send it any message.\\\"\\n\\n\\t^ (contentsMorph xxxClass inheritsFrom: Object) and: [(contentsMorph == nil) not]! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 12/4/1998 01:00'!\\nlastChangeTime\\n\\t^ lastChangeTime! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 2/24/1999 12:06'!\\nsaveMorph: aMorph author: authorString\\n\\t\\\"Save the given morph as this page's contents. Update its thumbnail and inform references to this URL that the page has changed.\\\"\\n\\t\\\"Details: updateThumbnail releases the cached state of the saved page contents after computing the thumbnail.\\\"\\n\\n\\t| n |\\n\\tcontentsMorph _ aMorph.\\n\\tn _ aMorph knownName.\\n\\tn ifNotNil: [self title: n].\\n\\tcreationAuthor ifNil: [\\n\\t\\tcreationAuthor _ authorString.\\n\\t\\tcreationTime _ Time totalSeconds].\\n\\\"\\tlastChangeAuthor _ authorString.\\n\\tlastChangeTime _ Time totalSeconds.\\tdo it when actually write\\\"\\n\\tself computeThumbnail.\\n\\tself postChangeNotification.\\n! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'jm 6/16/1998 17:45'!\\nthumbnail\\n\\n\\t^ thumbnail\\n! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'jm 6/16/1998 13:47'!\\ntitle\\n\\n\\ttitle ifNil: [^ ''] ifNotNil: [^ title].\\n! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'jm 6/16/1998 18:12'!\\ntitle: aString\\n\\n\\taString isEmpty\\n\\t\\tifTrue: [title _ nil]\\n\\t\\tifFalse: [title _ aString].\\n! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 11/4/1998 20:34'!\\nurl\\n\\n\\t^ url! !\\n\\n!SqueakPage methodsFor: 'accessing' stamp: 'tk 1/14/1999 23:50'!\\nurl: aString\\n\\n\\t| sd |\\n\\taString isEmpty ifTrue: [url _ nil. ^ self].\\n\\n\\t\\\"Expand ./ and store as an absolute url\\\"\\n\\tsd _ ServerFile new.\\n\\tsd fullPath: aString.\\n\\turl _ sd realUrl.! !\\n\\n\\n!SqueakPage methodsFor: 'saving' stamp: 'tk 9/30/1998 22:40'!\\ndirty: aBool\\n\\tdirty _ aBool! !\\n\\n!SqueakPage methodsFor: 'saving' stamp: 'tk 10/8/1998 13:18'!\\npolicy\\n\\t^ policy! !\\n\\n!SqueakPage methodsFor: 'saving' stamp: 'tk 9/30/1998 22:39'!\\npolicy: aSymbol\\n\\tpolicy _ aSymbol! !\\n\\n!SqueakPage methodsFor: 'saving' stamp: 'ar 3/17/2001 23:36'!\\nprePurge\\n\\t\\\"Return self if ready to be purged, or nil if not\\\"\\n\\n\\tself isContentsInMemory ifFalse: [^ nil].\\n\\tcontentsMorph ifNil: [^ nil]. \\\"out already\\\"\\n\\turl ifNil: [^ nil].\\t\\\"just to be safe\\\"\\n\\t^ (World ~~ nil and: [contentsMorph world == World]) \\n\\t\\tifTrue: [nil \\\"showing now\\\"] ifFalse: [self]! !\\n\\n!SqueakPage methodsFor: 'saving' stamp: 'tk 12/16/1998 08:24'!\\npurge\\n\\t\\\"Replace my morph with a tombstone, if I am not in a world that is being shown.\\\"\\n\\n\\t(self prePurge) ifNotNil: [\\n\\t\\tcontentsMorph become: (MorphObjectOut new xxxSetUrl: url page: self)].\\n\\t\\t\\\"Simple, isn't it!!\\\"! !\\n\\n!SqueakPage methodsFor: 'saving' stamp: 'tk 1/23/1999 13:19'!\\nurlNoOverwrite: suggested\\n\\t\\\"Look in the directory. If there is a file of this name, create a new name. Keep track of highest numbers used as a hint.\\\"\\n\\n\\t| dir ll stem num local trial suffix |\\n\\t(suggested endsWith: '.sp') ifTrue: [suffix _ '.sp'].\\n\\t(suggested endsWith: '.bo') ifTrue: [suffix _ '.bo'].\\n\\tsuffix ifNil: [self error: 'unknown suffix'].\\n\\tdir _ ServerFile new fullPath: suggested.\\n\\t(dir includesKey: dir fileName) ifFalse: [^ url _ suggested].\\n\\t\\\"File already exists!! Create a new name\\\"\\n\\t\\\"Find the stem file name\\\"\\n\\tstem _ SqueakPage stemUrl: suggested.\\n\\tnum _ stem = RecentStem ifTrue: [RecentMaxNum+1] ifFalse: [1].\\n\\n\\tlocal _ dir fileName.\\t\\\"ugh, take stem again...\\\"\\n\\tll _ local findLast: [:char | char == $.].\\n\\tll = 0 ifFalse: [local _ local copyFrom: 1 to: ll-1].\\t\\\"remove .sp\\\"\\n\\tlocal _ (local splitInteger) at: 1.\\t\\t\\\"remove trailing number\\\"\\n\\tlocal last == $x ifFalse: [local _ local , 'x'].\\n\\t[trial _ local, num printString, suffix.\\n\\t\\tdir includesKey: trial] whileTrue: [num _ num + 1].\\n\\tRecentStem _ stem. RecentMaxNum _ num.\\n\\t^ url _ stem, 'x', num printString, suffix! !\\n\\n!SqueakPage methodsFor: 'saving' stamp: 'RAA 8/30/2000 11:43'!\\nwrite\\n\\t\\\"Decide whether to write this page on the disk.\\\"\\n\\t| sf remoteFile |\\n\\tpolicy == #neverWrite ifTrue: [^ self].\\n\\t\\t\\\"demo mode, or write only when user explicitly orders it\\\"\\n\\n\\t\\\"All other policies do write: #now\\\"\\n\\tcontentsMorph ifNil: [^ self].\\n\\tdirty _ dirty | ((contentsMorph valueOfProperty: #pageDirty) == true).\\n\\t\\t\\\"set by layoutChanged\\\"\\n\\tdirty == true ifTrue: [ \\n\\t\\tsf _ ServerDirectory new fullPath: url.\\n\\t\\t\\\"check for shared password\\\"\\n\\t\\t\\\"contentsMorph allMorphsDo: [:m | m prepareToBeSaved].\\n\\t\\t\\t\\tdone in objectToStoreOnDataStream\\\"\\n\\t\\tlastChangeAuthor _ Utilities authorInitialsPerSe ifNil: ['*'].\\n\\t\\tlastChangeTime _ Time totalSeconds.\\n\\t\\tCursor wait showWhile: [\\n\\t\\t\\tremoteFile _ sf fileNamed: url.\\t\\\"no notification when overwriting\\\"\\n\\t\\t\\tremoteFile dataIsValid.\\n\\t\\t\\tremoteFile fileOutClass: nil andObject: self.\\n\\t\\t\\t\\\"remoteFile close\\\"].\\n\\t\\tcontentsMorph setProperty: #pageDirty toValue: nil.\\n\\t\\tdirty _ false].! !\\n\\n\\n!SqueakPage methodsFor: 'private' stamp: 'tk 2/25/1999 09:13'!\\ncomputeThumbnail\\n\\t\\\"Make a thumbnail from my morph.\\\"\\n\\n\\t(contentsMorph isKindOf: PasteUpMorph) \\n\\t\\tifTrue: [thumbnail _ contentsMorph smallThumbnailForPageSorter]\\n\\t\\tifFalse: [self updateThumbnail]! !\\n\\n!SqueakPage methodsFor: 'private' stamp: 'tk 6/24/1999 11:42'!\\npostChangeNotification\\n\\t\\\"Inform all thumbnails and books that this page has been updated.\\\"\\n\\n\\tURLMorph allSubInstancesDo: [:m | m pageHasChanged: self].\\n! !\\n\\n!SqueakPage methodsFor: 'private' stamp: 'jm 6/18/1998 11:31'!\\nupdateThumbnail\\n\\t\\\"Update my thumbnail from my morph.\\\"\\n\\n\\t| f scale scaleX scaleY shrunkF |\\n\\tcontentsMorph ifNil: [thumbnail _ nil. ^ self].\\n\\tf _ contentsMorph imageForm.\\n\\tscaleX _ MaxThumbnailWidthOrHeight asFloat / f height.\\n\\tscaleY _ MaxThumbnailWidthOrHeight asFloat/ f width.\\n\\tscale _ scaleX min: scaleY. \\\"choose scale that maintains aspect ratio\\\"\\n\\tshrunkF _ (f magnify: f boundingBox by: scale@scale smoothing: 2).\\n\\tthumbnail _ Form extent: shrunkF extent depth: 8. \\\"force depth to be 8\\\"\\n\\tshrunkF displayOn: thumbnail.\\n\\tcontentsMorph allMorphsDo: [:m | m releaseCachedState].\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSqueakPage class\\n\\tinstanceVariableNames: ''!\\n\\n!SqueakPage class methodsFor: 'as yet unclassified' stamp: 'jm 6/18/1998 11:15'!\\ninitialize\\n\\t\\\"SqueakPage initialize\\\"\\n\\n\\tMaxThumbnailWidthOrHeight _ 60.\\n! !\\n\\n!SqueakPage class methodsFor: 'as yet unclassified' stamp: 'sw 7/6/1998 11:49'!\\nnewURLAndPageFor: aMorph\\n\\t\\\"Create a new SqueakPage whose contents is the given morph. Assign a URL for that page, record it in the page cache, and answer its URL.\\\"\\n\\n\\t| pg newURL stamp |\\n\\tpg _ self new.\\n\\tstamp _ Utilities authorInitialsPerSe ifNil: ['*'].\\n\\tpg saveMorph: aMorph author: stamp.\\n\\tnewURL _ SqueakPageCache generateURL.\\n\\tSqueakPageCache atURL: newURL put: pg.\\n\\t^ newURL \\n! !\\n\\n!SqueakPage class methodsFor: 'as yet unclassified' stamp: 'tk 1/15/1999 08:13'!\\nstemUrl: aUrlString\\n\\t\\\"Peel off the 'x5.sp' or '.bo' from the end of a url of a SqueakPage or a BookMorph index file\\\"\\n\\n\\t| ll aUrl |\\n\\tll _ aUrlString findLast: [:char | char == $.].\\n\\tll = 0 \\n\\t\\tifTrue: [aUrl _ aUrlString]\\n\\t\\tifFalse: [aUrl _ aUrlString copyFrom: 1 to: ll-1].\\t\\\"remove .sp\\\"\\n\\taUrl _ (aUrl stemAndNumericSuffix) at: 1.\\n\\t\\t\\t\\\"remove trailing number\\\"\\n\\taUrl size = 0 ifTrue: [^ aUrl].\\t\\\"empty\\\"\\n\\t[aUrl last == $x] whileTrue: [aUrl _ aUrl allButLast].\\n\\t^ aUrl! !\\nObject subclass: #SqueakPageCache\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'GlobalPolicy PageCache'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-SqueakPage'!\\n!SqueakPageCache commentStamp: '<historical>' prior: 0!\\nA global cache of web pages known to this Squeak image. Since there is a single, global page cache, it is implemented entirely as class methods.\\n\\nOnce a page has an entry, keep it. (url string -> A SqueakPage) The SqueakPage has a thumbnail and other info, but may not have the contentsMorph. The morph is purged when space is needed, and fetched from the server as needed.\\n\\nSee SqueakPage's comment for the stages of in/out.!\\n\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSqueakPageCache class\\n\\tinstanceVariableNames: ''!\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'jm 6/25/1998 11:06'!\\nallURLs\\n\\t\\\"Answer a collection of URLs for all pages in the cache.\\\"\\n\\n\\t^ PageCache keys\\n\\n! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 10/2/1998 12:07'!\\natURL: aURLString\\n\\t\\\"Answer the page corresponding to this URL. Evaluate the given block if there is no entry for the given URL.\\\"\\n\\n\\t| pg |\\n\\t^ PageCache at: aURLString ifAbsent: [\\n\\t\\tpg _ SqueakPage new.\\n\\t\\t\\\"stamp _ Utilities authorInitialsPerSe ifNil: ['*'].\\\"\\n\\t\\t\\\"pg author: stamp.\\\"\\n\\t\\t\\\"Need to deal with inst vars if we turn out to be new!!\\\"\\n\\t\\t\\\"pg url: aURLString. \\tdone by atURL:put:\\\"\\n\\t\\tself atURL: aURLString put: pg.\\n\\t\\tpg]\\n! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 10/2/1998 12:06'!\\natURL: aURLString ifAbsent: failBlock\\n\\t\\\"Answer the page corresponding to this URL. Evaluate the given block if there is no entry for the given URL.\\\"\\n\\n\\tself halt. \\\"use atURL:\\\"\\n! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 10/20/1998 15:51'!\\natURL: aURLString oldPage: aPage\\n\\t\\\"Bring in page and return the object. First try looking up my url in the pageCache. Then try the page (and install it, under its url). Then start from scratch with the url.\\\"\\n\\n\\t| myPage |\\n\\t(myPage _ PageCache at: aURLString ifAbsent: [nil]) ifNotNil: [\\n\\t\\t^ myPage].\\n\\taPage url: aURLString.\\t\\\"for consistancy\\\"\\n\\tPageCache at: aPage url put: aPage.\\n\\t^ aPage! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 12/8/1998 21:51'!\\natURL: aURLString put: aSqueakPage\\n\\t\\\"Store the given page in the cache entry for the given URL.\\\"\\n\\n\\taSqueakPage url: aURLString.\\n\\taSqueakPage contentsMorph isInMemory ifTrue: [\\n\\t\\taSqueakPage contentsMorph ifNotNil: [\\n\\t\\t\\taSqueakPage contentsMorph setProperty: #SqueakPage \\n\\t\\t\\t\\ttoValue: aSqueakPage]].\\n\\tPageCache at: aURLString put: aSqueakPage.\\n! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 10/30/1998 15:08'!\\ndoPagesInMemory: aBlock\\n\\t\\\"Evaluate aBlock for each page whose contentsMorph is in-memory. Don't add or remove pages while in this loop.\\\"\\n\\n\\tPageCache do: [:sqkPage |\\n\\t\\tsqkPage isContentsInMemory ifTrue: [aBlock value: sqkPage]].! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 11/24/1998 14:52'!\\ngenerateURL\\n\\t\\\"Generate an unused URL for an in-memory page.\\\"\\n\\t\\\"SqueakPageCache generateURL\\\"\\n\\n\\t| sd |\\n\\tsd _ ServerFile new on: 'file:./'.\\n\\tsd fileName: 'page1.sp'.\\n\\t^ SqueakPage new urlNoOverwrite: sd pathForFile\\n! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 10/1/1998 13:02'!\\nincludesMorph: aPasteUp\\n\\n\\tPageCache do: [:squeakPage |\\n\\t\\tsqueakPage contentsMorph == aPasteUp ifTrue: [^ true]].\\n\\t^ false! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 10/20/1998 15:11'!\\npageCache\\n\\n\\t^ PageCache! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 10/1/1998 13:04'!\\npageForMorph: aPasteUp\\n\\n\\tPageCache do: [:squeakPage |\\n\\t\\tsqueakPage contentsMorph == aPasteUp ifTrue: [^ squeakPage]].\\n\\t^ nil! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 12/16/1998 08:30'!\\npurge\\n\\t\\\"Replace morphs with tombstones in all pages that are clean and not being shown. Write any dirty ones first, if allowed to.\\\"\\n\\n\\t| list |\\n\\tlist _ OrderedCollection new.\\n\\tGlobalPolicy == #neverWrite \\n\\t\\tifTrue: [PageCache doPagesInMemory: [:aPage | list add: aPage prePurge]]\\n\\t\\t\\t\\\"Writing only done by user's command\\\"\\n\\t\\tifFalse: [\\n\\t\\t\\tPageCache doPagesInMemory: [:aPage | aPage write\\n\\t\\t\\t\\t\\t list add: aPage prePurge]].\\n\\tlist _ list select: [:each | each notNil].\\n\\t\\\"do bulk become:\\\"\\n\\t(list collect: [:each | each contentsMorph])\\n\\t\\telementsExchangeIdentityWith:\\n\\t\\t\\t(list collect: [:pg | MorphObjectOut new xxxSetUrl: pg url page: pg])\\n! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 10/21/1998 13:28'!\\npurge: megs\\n\\t\\\"Replace morphs with tombstones in all pages that are clean and not being shown. Do this until megs of new memory have been recovered. Write any dirty ones first, if allowed to.\\\"\\n\\n\\t| goal |\\n\\tgoal _ Smalltalk garbageCollect + (megs * 1000000) asInteger.\\n\\tPageCache doPagesInMemory: [:aPage | \\n\\t\\tGlobalPolicy == #neverWrite ifFalse: [aPage write].\\n\\t\\taPage purge.\\n\\t\\tSmalltalk garbageCollect > goal ifTrue: [^ true]].\\t\\\"got enough\\\"\\n\\t^ false\\t\\\"caller may want to tell the user to write out more pages\\\"! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'jm 6/16/1998 18:12'!\\nremoveURL: aURLString\\n\\t\\\"Remove the cache entry for the given URL. Do nothing if it has no cache entry.\\\"\\n\\n\\tPageCache removeKey: aURLString ifAbsent: [].\\n! !\\n\\n!SqueakPageCache class methodsFor: 'cache access' stamp: 'tk 10/22/1998 11:07'!\\nwrite\\n\\t\\\"Write out all dirty pages\\\"\\n\\tGlobalPolicy == #neverWrite ifTrue: [^ self].\\n\\tself doPagesInMemory: [:aPage | aPage write].! !\\n\\n\\n!SqueakPageCache class methodsFor: 'class initialization' stamp: 'tk 11/24/1998 14:53'!\\ninitialize\\n\\t\\\"SqueakPageCache initialize\\\"\\n\\n\\tGlobalPolicy _ #neverWrite.\\n\\tPageCache _ Dictionary new: 100.\\n\\t\\t\\\"forgets urls of pages, but ObjectOuts still remember them\\\"\\n! !\\n\\n\\n!SqueakPageCache class methodsFor: 'housekeeping' stamp: 'tk 6/24/1999 11:42'!\\ndeleteUnreferencedPages\\n\\t\\\"Remove any pages that are not current referred to by any book or URL morph.\\\"\\n\\t\\\"Details: Since unreferenced pages could refer to other pages, this process is iterated until no unreferenced pages can be found. It currently does not collect cycles.\\\"\\n\\t\\\"SqueakPageCache deleteUnreferencedPages\\\"\\n\\n\\t| unreferenced |\\n\\t[true] whileTrue: [\\n\\t\\tSmalltalk garbageCollect.\\n\\t\\tunreferenced _ PageCache keys.\\n\\t\\tURLMorph allSubInstancesDo: [:m | unreferenced remove: m url ifAbsent: []].\\n\\t\\tMorphObjectOut allInstancesDo: [:ticklish |\\n\\t\\t\\tunreferenced remove: ticklish url ifAbsent: []].\\n\\t\\tunreferenced size = 0 ifTrue: [^ self].\\n\\t\\tunreferenced do: [:url | PageCache removeKey: url ifAbsent: []]].\\n! !\\n\\n!SqueakPageCache class methodsFor: 'housekeeping' stamp: 'jm 6/25/1998 13:00'!\\nreleaseCachedStateOfPages\\n\\t\\\"Note: This shouldn't be necessary if we are doing a good job of releasing cached state as we go. If running this doesn't do very much, we're doing well!!\\\"\\n\\t\\\"SqueakPageCache releaseCachedStateOfPages\\\"\\n\\n\\t| memBytes |\\n\\tmemBytes _ Smalltalk garbageCollect.\\n\\tPageCache do: [:pg |\\n\\t\\tpg contentsMorph allMorphsDo: [:m | m releaseCachedState]].\\n\\t^ (Smalltalk garbageCollect - memBytes) printString, ' bytes recovered'\\n! !\\nMorph subclass: #SquishedNameMorph\\n\\tinstanceVariableNames: 'target getSelector setSelector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Navigators'!\\n\\n!SquishedNameMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/11/2000 23:19'!\\ncolorAroundName\\n\\n\\t^Color gray: 0.8! !\\n\\n!SquishedNameMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/11/2000 23:18'!\\nfontForName\\n\\n\\t| pickem |\\n\\tpickem _ 3.\\n\\n\\tpickem = 1 ifTrue: [\\n\\t\\t^(((TextStyle named: #Helvetica) ifNil: [TextStyle default]) fontOfSize: 13) emphasized: 1.\\n\\t].\\n\\tpickem = 2 ifTrue: [\\n\\t\\t^(((TextStyle named: #Palatino) ifNil: [TextStyle default]) fontOfSize: 12) emphasized: 1.\\n\\t].\\n\\t^((TextStyle default) fontAt: 1) emphasized: 1\\n! !\\n\\n!SquishedNameMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/11/2000 23:17'!\\nisEditingName\\n\\n\\t^((self findA: UpdatingStringMorph) ifNil: [^false]) hasFocus\\n! !\\n\\n!SquishedNameMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/11/2000 23:32'!\\nstringToShow\\n\\n\\t(target isNil or: [getSelector isNil]) ifTrue: [^'????'].\\n\\t^target perform: getSelector! !\\n\\n!SquishedNameMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/11/2000 23:31'!\\ntarget: aTarget getSelector: symbol1 setSelector: symbol2\\n\\n\\ttarget _ aTarget.\\n\\tgetSelector _ symbol1.\\n\\tsetSelector _ symbol2.! !\\n\\n\\n!SquishedNameMorph methodsFor: 'drawing' stamp: 'RAA 11/11/2000 23:17'!\\ndrawOn: aCanvas\\n\\n\\t| font stringToShow nameForm rectForName |\\n\\n\\tsuper drawOn: aCanvas.\\n\\tself isEditingName ifTrue: [^self].\\n\\n\\tfont _ self fontForName.\\n\\tstringToShow _ self stringToShow.\\n\\tnameForm _ (StringMorph contents: stringToShow font: font) imageForm.\\n\\tnameForm _ nameForm scaledToSize: (self extent - (4@2) min: nameForm extent).\\n\\trectForName _ self bottomLeft + \\n\\t\\t\\t(self width - nameForm width // 2 @ (nameForm height + 2) negated)\\n\\t\\t\\t\\textent: nameForm extent.\\n\\trectForName topLeft eightNeighbors do: [ :pt |\\n\\t\\taCanvas\\n\\t\\t\\tstencil: nameForm \\n\\t\\t\\tat: pt\\n\\t\\t\\tcolor: self colorAroundName.\\n\\t].\\n\\taCanvas\\n\\t\\tstencil: nameForm \\n\\t\\tat: rectForName topLeft \\n\\t\\tcolor: Color black.\\n\\n\\n\\t\\n! !\\nObject subclass: #Stack\\n\\tinstanceVariableNames: 'linkedList'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Collections-Stack'!\\n!Stack commentStamp: 'dc 7/24/2005 15:41' prior: 0!\\nI implement a simple Stack. #push: adds a new object of any kind on top of the stack. #pop returns the first element and remove it from the stack. #top answer the first element of the stack without removing it.!\\n\\n\\n!Stack methodsFor: 'accessing' stamp: 'dc 7/25/2005 10:04'!\\nsize\\n\\t\\\"How many objects in me ?\\\"\\n\\t^ self linkedList size! !\\n\\n!Stack methodsFor: 'accessing' stamp: 'sd 3/25/2006 15:05'!\\ntop\\n\\t\\\"Answer the first element of the stack without removing it.\\\"\\n\\tself notEmptyCheck.\\n\\t^ self linkedList first element! !\\n\\n\\n!Stack methodsFor: 'adding' stamp: 'dc 7/25/2005 10:22'!\\npush: anObject \\n\\t\\\"Adds a new object of any kind on top of the stack.\\\"\\n\\tself linkedList\\n\\t\\taddFirst: (StackLink with: anObject).\\n\\t^ anObject.! !\\n\\n\\n!Stack methodsFor: 'initialize-release' stamp: 'dc 7/25/2005 11:39'!\\ninitialize\\n\\tsuper initialize.\\n\\tlinkedList := LinkedList new! !\\n\\n\\n!Stack methodsFor: 'removing' stamp: 'dc 7/24/2005 16:16'!\\npop\\n\\t\\\"Returns the first element and remove it from the stack.\\\"\\n\\n\\tself notEmptyCheck.\\n\\t^self linkedList removeFirst element! !\\n\\n\\n!Stack methodsFor: 'testing' stamp: 'dc 7/25/2005 10:05'!\\nisEmpty\\n\\t^ self linkedList isEmpty! !\\n\\n\\n!Stack methodsFor: 'private' stamp: 'dc 7/25/2005 10:05'!\\nerrorEmptyStack\\n\\tself error: 'this stack is empty'! !\\n\\n!Stack methodsFor: 'private' stamp: 'dc 7/25/2005 10:20'!\\nlinkedList\\n\\t\\\"The stack is implemented with a LinkedList. Do NOT call this function, it \\n\\tis for private use !!\\\"\\n\\t^ linkedList! !\\n\\n!Stack methodsFor: 'private' stamp: 'dc 7/25/2005 10:05'!\\nnotEmptyCheck\\n\\t\\\"Ensure the stack is not empty.\\\"\\n\\tself isEmpty\\n\\t\\tifTrue: [self errorEmptyStack]! !\\nLink subclass: #StackLink\\n\\tinstanceVariableNames: 'element'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Collections-Stack'!\\n!StackLink commentStamp: '<historical>' prior: 0!\\nI implement an element of a stack. I'm a container for any type of object, saved into the 'element' variable. My superclass Link allows me to be part of a LinkedList.!\\n\\n\\n!StackLink methodsFor: 'accessing' stamp: 'dc 7/24/2005 15:34'!\\nelement\\n\\t^element! !\\n\\n!StackLink methodsFor: 'accessing' stamp: 'dc 7/25/2005 10:16'!\\nelement: anObject \\n\\t\\\"Any kind of Object.\\\"\\n\\telement := anObject! !\\n\\n\\n!StackLink methodsFor: 'printing' stamp: 'dc 7/25/2005 10:15'!\\nprintOn: aStream \\n\\taStream nextPutAll: self class printString;\\n\\t\\t nextPutAll: ' with: ';\\n\\t\\t nextPutAll: self element printString! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStackLink class\\n\\tinstanceVariableNames: ''!\\n\\n!StackLink class methodsFor: 'instance creation' stamp: 'dc 7/25/2005 10:15'!\\nwith: anObject \\n\\t^ self new element: anObject! !\\nBookMorph subclass: #StackMorph\\n\\tinstanceVariableNames: 'cards'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Stacks'!\\n!StackMorph commentStamp: '<historical>' prior: 0!\\nA book that is very much like a HyperCard stack. \\n\\nEach book page represents a different background. The page stays while different cards are projected onto it. \\n\\tThe data for a single card is stored in a CardPlayer. There is a list of objects that only appear on this card (privateMorphs) and the card-specific text to be inserted into the background fields.\\n\\nItem\\t\\t\\t\\t\\tHow it is stored\\na background\\t\\t\\ta page of the StackMorph\\na card\\t\\t\\t\\t\\tdata is in an instance of a subclass of CardPlayer.\\n\\t\\t\\t\\t\\t\\tA list of CardPlayers is in the 'cards' inst var of the StackMorph.\\na background field\\t\\ta TextMorph on a page of the StackMorph\\na background picture\\ta morph of any kind on a page of the StackMorph\\nscript for bkgnd button\\t\\tmethod in Player. Button is its costume.\\ntext in a background field\\t\\tvalue of inst var 'field1' in a CardPlayer.\\n\\t\\t\\t\\t\\t\\t\\t\\t(The CardPlayer is also pointed at by the #cardInstance \\n\\t\\t\\t\\t\\t\\t\\t\\tproperty of the bkgnd field (TextMorph))\\ntext in a card field\\t\\tin the TextMorph in privateMorphs in the CardPlayer.\\npicture on a card\\t\\ta morph of any kind in privateMorphs in the CardPlayer.\\nscript for card button\\tmethod in the CardPlayer. Button is its costume.\\n\\nSee VariableDock.!\\n\\n\\n!StackMorph methodsFor: 'accessing' stamp: 'sw 11/2/2002 15:51'!\\ncardNumberOf: aPlayer\\n\\t\\\"Answer the card-number of the given player, in the which-card-of-the-stack sense.\\\"\\n\\n\\t^ self cards identityIndexOf: aPlayer ifAbsent: [0]! !\\n\\n!StackMorph methodsFor: 'accessing' stamp: 'sw 3/18/2002 02:09'!\\ncardsOrPages\\n\\t\\\"The turnable and printable entities\\\"\\n\\n\\t^ self cards! !\\n\\n\\n!StackMorph methodsFor: 'as yet unclassified' stamp: 'sw 10/23/2000 16:27'!\\ncommitCardData\\n\\t\\\"Make certain that the player data are written back to the player instance\\\"\\n\\n\\t^ self currentCard commitCardPlayerData \\n! !\\n\\n!StackMorph methodsFor: 'as yet unclassified' stamp: 'em 3/31/2005 10:56'!\\ninsertCardOfBackground\\n\\t\\\"Prompt the user for choice of a background, and insert a new card of that background\\\"\\n\\n\\t| bgs aMenu aBackground |\\n\\t(bgs _ self backgrounds) size == 1 ifTrue:\\n\\t\\t[self inform: \\n'At this time, there IS only one kind of\\nbackground in this stack, so that''s\\nwhat you''ll get' translated.\\n\\t\\t^ self insertCard].\\n\\taMenu _ SelectionMenu\\n\\t\\tlabels: \\t\\t(bgs collect: [:bg | bg externalName])\\n\\t\\tselections: \\tbgs.\\n\\t(aBackground _ aMenu startUp) ifNotNil:\\n\\t\\t[self insertCardOfBackground: aBackground]! !\\n\\n!StackMorph methodsFor: 'as yet unclassified' stamp: 'sw 3/18/2002 02:02'!\\ninsertCardOfBackground: aBackground\\n\\t\\\"Insert a new card of the given background and have it become the current card\\\"\\n\\n\\t| newCard |\\n\\tnewCard _ aBackground newCard.\\n\\tself privateCards add: newCard after: self currentCard.\\n\\tself goToCard: newCard! !\\n\\n!StackMorph methodsFor: 'as yet unclassified' stamp: 'sw 10/30/2000 10:08'!\\nopenInsideLook\\n\\t\\\"Open an inside-look at the current page. This is a previously-demoed feature not presently incorporated in released code,\\\"\\n\\n\\ttrue ifTrue: [self notYetImplemented] ifFalse: [self currentPage openInsideLook]\\n! !\\n\\n\\n!StackMorph methodsFor: 'background' stamp: 'nb 6/17/2003 12:25'!\\naddCardsFromAFile\\n\\t\\\"Using the current background, create new cards by reading in data from a fileThe data are in each record are expected to be tab-delimited, and to occur in the same order as the instance variables of the current-background's cards \\\"\\n\\n\\t| aFileStream |\\n\\t(aFileStream _ FileList2 modalFileSelector) ifNil: [^ Beeper beep].\\n\\tself addCardsFromString: aFileStream contentsOfEntireFile.\\n\\taFileStream close! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'nb 6/17/2003 12:25'!\\naddCardsFromClipboardData\\n\\t\\\"Using the current background, paste data from the (textual) clipboard to create new records. The data are in each record are expected to be tab-delimited, and to occur in the same order as the instance variables of the current-background's cards \\\"\\n\\n\\t| clip |\\n\\t(clip _ Clipboard clipboardText) isEmptyOrNil ifTrue: [^ Beeper beep].\\n\\tself addCardsFromString: clip! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'nb 6/17/2003 12:25'!\\naddCardsFromClipboardDataForInstanceVariables: slotNames\\n\\t\\\"Using the current background, paste data from the (textual) clipboard to create new records. No senders, but can be usefully called manually for selectively bringing in data in oddball format.\\\"\\n\\n\\t| clip |\\n\\t(clip _ Clipboard clipboardText) isEmptyOrNil ifTrue: [^ Beeper beep].\\n\\tself addCardsFromString: clip slotNames: slotNames! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'nb 6/17/2003 12:25'!\\naddCardsFromFile: fileStream\\n\\t\\\"Using the current background, take tab delimited data from the file to create new records.\\\"\\n\\n\\t| aString |\\n\\t(aString _ fileStream contentsOfEntireFile) isEmptyOrNil ifTrue: [^ Beeper beep].\\n\\tself addCardsFromString: aString! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'sw 12/18/2001 11:35'!\\naddCardsFromString: aString\\n\\t\\\"Using the current background, add cards from a string, which is expected be tab- and return-delimited. The data are in each record are expected to be tab-delimited, and to occur in the same order as the instance variables of the current-background's cards \\\"\\n\\n\\tself addCardsFromString: aString slotNames: self currentCard slotNames\\n \\n! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'em 3/31/2005 10:23'!\\naddCardsFromString: aString slotNames: slotNames \\n\\t\\\"Using the current background, add cards from a string, which is expected be tab- and return-delimited\\\"\\n\\n\\t| count |\\n\\tcount := 0.\\n\\taString asString linesDo: \\n\\t\\t\\t[:aLine | \\n\\t\\t\\taLine notEmpty \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[count := count + 1.\\n\\t\\t\\t\\t\\tself \\n\\t\\t\\t\\t\\t\\tinsertCardOfBackground: self currentPage\\n\\t\\t\\t\\t\\t\\twithDataFrom: aLine\\n\\t\\t\\t\\t\\t\\tforInstanceVariables: slotNames]].\\n\\tself inform: count asString , ' card(s) added' translated! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'sw 10/26/2000 14:41'!\\nbackgroundWithCard: aCard\\n\\t\\\"Answer the background which contains aCard.\\\"\\n\\n\\t^ self backgrounds detect:\\n\\t\\t[:aBackground | aBackground containsCard: aCard] ifNone: [nil]! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'sw 10/30/2000 10:04'!\\nbackgrounds\\n\\t\\\"Answer the list of backgrounds available in the receiver\\\"\\n\\n\\t^ self pages! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'sw 12/6/2001 21:26'!\\nbeDefaultsForNewCards\\n\\t\\\"Make the values that I see here all be accepted as defaults for new cards\\\"\\n\\n\\tself currentPage submorphs do:\\n\\t\\t[:aMorph | aMorph holdsSeparateDataForEachInstance ifTrue:\\n\\t\\t\\t[aMorph setAsDefaultValueForNewCard]]! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'sw 11/2/2002 17:56'!\\nchangeInstVarOrder\\n\\t\\\"Change the order of the receiver's instance variables\\\"\\n\\n\\t| reply |\\n\\treply _ FillInTheBlank request: 'rearrange, then accept; or cancel' initialAnswer:\\n\\t\\t((self currentPage player class instVarNames asArray collect: [:v | v asSymbol]) storeString copyWithoutAll: #($# $( $))) asString.\\n\\treply isEmptyOrNil ifTrue: [^ self].\\n\\tself flag: #deferred. \\\"Error checking and graceful escape wanted\\\"\\n\\tself currentPage player class resortInstanceVariables: (Compiler evaluate:\\n\\t\\t('#(', reply, ')'))! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'em 3/30/2005 14:47'!\\ninsertAsBackground: newPage resize: doResize\\n\\t\\\"Make a new background for the stack. Obtain a name for it from the user. It starts out life empty\\\"\\n\\n\\t| aName |\\n\\taName _ FillInTheBlank request: 'What should we call this new background?' translated initialAnswer: 'alternateBackground' translated.\\n\\taName isEmptyOrNil ifTrue: [^ self].\\n\\tnewPage beSticky.\\n\\tdoResize ifTrue: [newPage extent: currentPage extent].\\n\\tnewPage beAStackBackground.\\n\\tnewPage setNameTo: aName.\\n\\tnewPage vResizeToFit: false.\\n\\tpages isEmpty\\n\\t\\tifTrue: [pages add: newPage]\\n\\t\\tifFalse: [pages add: newPage after: currentPage].\\n\\tself privateCards add: newPage currentDataInstance after: currentPage currentDataInstance.\\n\\tself nextPage.\\n! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'tk 10/30/2001 19:01'!\\nmakeNewBackground\\n\\t\\\"Make a new background for the stack. Obtain a name for it from the user. It starts out life empty\\\"\\n\\n\\t| newPage |\\n\\t(newPage _ PasteUpMorph newSticky) color: self color muchLighter.\\n\\tnewPage borderWidth: currentPage borderWidth; borderColor: currentPage borderColor.\\n\\tself insertAsBackground: newPage resize: true. \\n! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'sw 3/18/2002 02:14'!\\nsortByField: varName\\n\\t\\\"Perform a simple reordering of my cards, sorting by the given field name. If there are multiple backgrounds, then sort the current one, placing all its cards first, followed by all others in unchanged order\\\"\\n\\n\\t| holdCards thisClassesInstances sortedList |\\n\\tholdCards _ self privateCards copy.\\n\\n\\tthisClassesInstances _ self privateCards select: [:c | c isKindOf: self currentCard class].\\n\\tsortedList _ thisClassesInstances asSortedCollection:\\n\\t\\t[:a :b | (a instVarNamed: varName) asString <= (b instVarNamed: varName) asString].\\n\\tsortedList _ sortedList asOrderedCollection.\\n\\tholdCards removeAllFoundIn: sortedList.\\n\\tself privateCards: (sortedList asOrderedCollection, holdCards).\\n\\tself goToFirstCardOfStack\\n! !\\n\\n!StackMorph methodsFor: 'background' stamp: 'sw 12/6/2001 22:08'!\\nsortCards\\n\\t\\\"Let the user provide an inst var on which to sort the cards of a background.\\\"\\n\\n\\t| names aMenu |\\n\\tnames _ self currentPage player class instVarNames.\\n\\taMenu _ MenuMorph new defaultTarget: self.\\n\\taMenu addTitle: 'Choose field by which to sort:'.\\n\\tnames do: [:n | aMenu add: n selector: #sortByField: argument: n].\\n\\taMenu popUpInWorld! !\\n\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 10/23/2000 16:24'!\\nbrowseCardClass\\n\\t\\\"Browse the class of the current card\\\"\\n\\n\\t| suffix |\\n\\tsuffix _ self currentCard class name numericSuffix.\\n\\tHierarchyBrowser newFor: self currentCard class labeled: 'Background ', suffix asString\\n! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 02:20'!\\ncardIndexOf: aCard\\n\\t\\\"Answer the ordinal position of aCard in the receiver's list\\\"\\n\\n\\t^ self privateCards indexOf: aCard ifAbsent: [nil]! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 02:12'!\\ncards\\n\\t\\\"Answer a list of the cards of the receiver, in order\\\"\\n\\n\\t^ self privateCards copy! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 10/23/2000 16:27'!\\ncurrentCard\\n\\t\\\"Answer the current card of the current background of the receiver\\\"\\n\\n\\t^ currentPage currentDataInstance! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'em 3/31/2005 10:24'!\\ndeleteAllCardsExceptThisOne\\n\\t\\\"Delete all cards except the current one\\\"\\n\\n\\tself privateCards size <= 1 ifTrue: [^ Beeper beep].\\n\\t(self confirm: 'Really delete ' translated, self privateCards size asString, ' card(s) and all of their data?' translated) ifTrue:\\n\\t\\t[self privateCards: (OrderedCollection with: self currentCard)].! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sd 11/13/2003 21:03'!\\ndeleteCard\\n\\t\\\"Delete the current card from the stack\\\"\\n\\n\\t| aCard |\\n\\taCard _ self currentCard.\\n\\tself privateCards size = 1 ifTrue: [^ Beeper beep].\\n\\t(self confirm: 'Really delete this card and all of its data?' translated) ifTrue:\\n\\t\\t[self goToNextCardInStack.\\n\\t\\tself privateCards remove: aCard].! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'nb 6/17/2003 12:25'!\\ndeleteCard: aCard\\n\\t\\\"Delete the current card from the stack.\\\"\\n\\n\\tself privateCards size = 1 ifTrue: [^ Beeper beep].\\n\\t(aCard == self currentCard) ifTrue: [^ self deleteCard].\\n\\n\\tself privateCards remove: aCard ifAbsent: []! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'em 3/31/2005 10:23'!\\ngoToCard\\n\\t\\\"prompt the user for an ordinal number, and use that as a basis for choosing a new card to install in the receiver\\\"\\n\\n\\t| reply index |\\n\\treply _ FillInTheBlank request: 'Which card number? ' translated initialAnswer: '1'.\\n\\treply isEmptyOrNil ifTrue: [^ self].\\n\\t((index _ reply asNumber) > 0 and: [index <= self privateCards size])\\n\\t\\tifFalse: [^ self inform: 'no such card'].\\n\\tself goToCard: (self privateCards at: index)! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 11/8/2002 15:15'!\\ngoToCard: destinationCard\\n\\t\\\"Install the indicated destinationCard as the current card in the receiver. Any viewer currently open on the current card will get retargeted to look at the new one.\\\"\\n\\n\\t| aBackground existingCard oldViewers |\\n\\tdestinationCard == self currentCard ifTrue: [^ self].\\n\\tself currentPlayerDo:\\n\\t\\t[:aPlayer | aPlayer runAllClosingScripts]. \\\"Like HyperCard 'on closeCard'\\\"\\n\\n\\taBackground _ self backgroundWithCard: destinationCard.\\n\\texistingCard _ aBackground currentDataInstance.\\n\\toldViewers _ existingCard ifNil: [#()] ifNotNil: [existingCard allOpenViewers].\\n\\n\\taBackground installAsCurrent: destinationCard.\\n\\taBackground setProperty: #myStack toValue: self.\\t\\\"pointer cardMorph -> stack\\\"\\n\\n\\taBackground ~~ currentPage ifTrue:\\n\\t\\t[self goToPageMorph: aBackground runTransitionScripts: false].\\n\\tself currentPlayerDo:\\n\\t\\t[:aPlayer | aPlayer runAllOpeningScripts] . \\\"Like HyperCard 'on opencard'\\\"\\n\\n\\toldViewers do: [:aViewer | aViewer retargetFrom: existingCard to: destinationCard]! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 11/11/2002 03:07'!\\ngoToCardNumber: aCardNumber\\n\\t\\\"Install the card whose ordinal number is provided as the current card in the stack\\\"\\n\\n\\tself goToCard: (self privateCards atWrap: aCardNumber)! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'nb 6/17/2003 12:25'!\\ngoToFirstCardInBackground\\n\\t\\\"Install the initial card in the current background as the current card in the stack\\\"\\n\\n\\t| kind |\\n\\tkind _ currentPage player class baseUniclass.\\n\\tself goToCard: (self privateCards detect: [:aCard | aCard isKindOf: kind] ifNone: [^ Beeper beep])! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 02:01'!\\ngoToFirstCardOfStack\\n\\t\\\"Install the initial card in the stack as the current card\\\"\\n\\n\\tself goToCard: self privateCards first! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'nb 6/17/2003 12:25'!\\ngoToLastCardInBackground\\n\\t\\\"Install the final card in the current background as the current card\\\"\\n\\n\\t| kind |\\n\\tkind _ currentPage player class baseUniclass.\\n\\tself goToCard: (self privateCards reversed detect: [:aCard | aCard isKindOf: kind] ifNone: [^ Beeper beep])! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 02:09'!\\ngoToLastCardOfStack\\n\\t\\\"Install the final card in the stack as the current card\\\"\\n\\n\\tself goToCard: self privateCards last! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 02:03'!\\ninsertCardOfBackground: aBackground withDataFrom: aLine forInstanceVariables: slotNames\\n\\t\\\"Insert a new card of the given background and have it become the current card. \\\"\\n\\n\\t| newCard |\\n\\tnewCard _ aBackground newCard.\\n\\tself privateCards add: newCard after: self currentCard.\\n\\tnewCard absorbBackgroundDataFrom: aLine forInstanceVariables: slotNames.\\n\\tself goToCard: newCard! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 01:57'!\\nmakeCurrentCardFirstInStack\\n\\t\\\"Move the current card such that it becomes the first card in the stack\\\"\\n\\n\\t| aCard |\\n\\taCard _ self currentCard.\\n\\tself privateCards remove: aCard ifAbsent: [];\\n\\t\\taddFirst: aCard.\\n\\tself currentPage flash! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 02:03'!\\nmakeCurrentCardLastInStack\\n\\t\\\"Move the current card such that it becomes the last card in the stack\\\"\\n\\n\\t| aCard |\\n\\taCard _ self currentCard.\\n\\tself privateCards remove: aCard ifAbsent: [];\\n\\t\\taddLast: aCard.\\n\\tself currentPage flash! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 02:08'!\\nmoveCardOnePositionEarlier\\n\\t\\\"Move the current card such that its ordinal position is one fewer than it formerly was. If the current card is already the first one one in the stack, then do nothing\\\"\\n\\n\\t| aCard aPosition |\\n\\taCard _ self currentCard.\\n\\taCard == self privateCards first ifTrue: [^ self].\\n\\taPosition _ self privateCards indexOf: aCard.\\n\\tself privateCards remove: aCard;\\n\\t\\tadd: aCard afterIndex: (aPosition - 2).\\n\\tself currentPage flash! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 02:05'!\\nmoveCardOnePositionLater\\n\\t\\\"Move the current card such that its ordinal position is one greater than it formerly was. If the current card is already the last one one in the stack, then do nothing\\\"\\n\\n\\t| aCard aPosition privateCards |\\n\\taCard _ self currentCard.\\n\\tprivateCards _ self privateCards.\\n\\taCard == privateCards last ifTrue: [^ self].\\n\\taPosition _ privateCards indexOf: aCard.\\n\\tprivateCards remove: aCard.\\n\\tprivateCards add: aCard afterIndex: aPosition.\\n\\tself currentPage flash! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 01:56'!\\nprivateCards\\n\\t\\\"Private - answer the collection object that sits in my cards instance variable\\\"\\n\\n\\t^ cards! !\\n\\n!StackMorph methodsFor: 'card access' stamp: 'sw 3/18/2002 02:51'!\\nprivateCards: aCollection\\n\\t\\\"Private - Make my cards be te given colllection\\\"\\n\\n\\tcards _ aCollection! !\\n\\n\\n!StackMorph methodsFor: 'card in a stack' stamp: 'sw 10/30/2000 10:03'!\\nexplainDesignations\\n\\t\\\"Give the user an explanation of what the designations mean\\\"\\n\\n\\tself currentPage explainDesignations\\n! !\\n\\n!StackMorph methodsFor: 'card in a stack' stamp: 'sw 3/18/2002 02:03'!\\ngoToNextCardInStack\\n\\t\\\"Make the card *after* the current card become the current card\\\"\\n\\n\\t| anIndex newCard |\\n\\tanIndex _ self privateCards indexOf: currentPage currentDataInstance.\\n\\tnewCard _ self privateCards atWrap: anIndex + 1.\\n\\tself goToCard: newCard! !\\n\\n!StackMorph methodsFor: 'card in a stack' stamp: 'sw 3/18/2002 02:01'!\\ngoToPreviousCardInStack\\n\\t\\\"Install the previous card as my current one\\\"\\n\\n\\t| anIndex newCard |\\n\\tanIndex _ self privateCards indexOf: currentPage currentDataInstance.\\n\\tnewCard _ self privateCards atWrap: anIndex - 1.\\n\\tself goToCard: newCard! !\\n\\n!StackMorph methodsFor: 'card in a stack' stamp: 'sw 10/23/2000 16:02'!\\ninsertCard\\n\\t\\\"Create a new card of the current background and make it become the current card\\\"\\n\\n\\tself insertCardOfBackground: currentPage! !\\n\\n!StackMorph methodsFor: 'card in a stack' stamp: 'tk 10/5/2001 06:27'!\\nreassessBackgroundShape\\n\\t\\\"Have the current page reconsider its cards' instance structure\\\"\\n\\n\\tcurrentPage setProperty: #myStack toValue: self. \\t\\\"pointer cardMorph -> stack\\\"\\n\\t^ self currentPage reassessBackgroundShape \\n! !\\n\\n!StackMorph methodsFor: 'card in a stack' stamp: 'sw 10/30/2000 10:04'!\\nrelaxGripOnVariableNames\\n\\t\\\"Have the current background relax its grip on existing variable name\\\"\\n\\n\\t^ self currentPage relaxGripOnVariableNames \\n! !\\n\\n!StackMorph methodsFor: 'card in a stack' stamp: 'sw 10/30/2000 10:15'!\\nreshapeBackground\\n\\t\\\"Abandon any memory of variable-name preferences for the current background, and reassess its instance structure\\\"\\n\\n\\t^ self currentPage reshapeBackground \\n! !\\n\\n!StackMorph methodsFor: 'card in a stack' stamp: 'sw 10/30/2000 10:10'!\\nshowDesignationsOfObjects\\n\\t\\\"Momentarily show which objects on the current card belong to which designation category\\\"\\n\\n\\tself currentPage showDesignationsOfObjects\\n! !\\n\\n!StackMorph methodsFor: 'card in a stack' stamp: 'sw 10/23/2000 17:37'!\\nstackDo: aBlock\\n\\t\\\"Evaluate aBlock on behalf of the receiver stack\\\"\\n\\n\\t^ aBlock value: self! !\\n\\n\\n!StackMorph methodsFor: 'controls' stamp: 'sw 10/30/2000 16:31'!\\npageControlsMorphFrom: controlSpecs\\n\\t\\\"Answer a controls morph derived from the spec supplied\\\"\\n\\n\\t| controls |\\n\\tcontrols _ super pageControlsMorphFrom: controlSpecs.\\n\\tcontrols eventHandler: nil. \\\"not grabbable\\\"\\n\\t^ controls! !\\n\\n\\n!StackMorph methodsFor: 'debugging' stamp: 'sw 10/30/2000 10:13'!\\ninspectCurrentBackground\\n\\t\\\"Open an inspector on the corrent background. Ideally should put include the background name in the inspector's title.\\\"\\n\\n\\t^ self currentPage inspectWithLabel: 'A Background'\\n! !\\n\\n!StackMorph methodsFor: 'debugging' stamp: 'sw 10/23/2000 16:37'!\\ninspectCurrentCard\\n\\t\\\"For debugging: open an Inspector on the receiver's current card\\\"\\n\\n\\t^ self currentCard inspectWithLabel: 'A Card'\\n! !\\n\\n!StackMorph methodsFor: 'debugging' stamp: 'sw 10/30/2000 10:09'!\\ninspectCurrentStack\\n\\t\\\"Triggered from the stack-debug menu, open an Inspector on the receiver\\\"\\n\\n\\t^ self inspectWithLabel: 'A Stack'\\n! !\\n\\n\\n!StackMorph methodsFor: 'initialization' stamp: 'sw 6/5/2003 04:04'!\\naddPane: aPane paneType: aType\\n\\n\\t| anIndex |\\n\\n\\tanIndex _ self insertionIndexForPaneOfType: aType.\\n\\n\\tself privateAddMorph: aPane atIndex: anIndex! !\\n\\n!StackMorph methodsFor: 'initialization' stamp: 'sw 3/18/2002 02:12'!\\ninitialize\\n\\t\\\"Initialize the stack\\\"\\n\\n\\t| initialBackground |\\n\\tsuper initialize.\\n\\tinitialBackground _ pages first.\\n\\tinitialBackground extent: (640@480); beSticky.\\n\\tinitialBackground beAStackBackground.\\n\\tself beUnsticky.\\n\\tself setProperty: #controlsAtBottom toValue: true.\\n\\tself privateCards: (OrderedCollection with: initialBackground currentDataInstance).\\n\\n\\\"self currentHand attachMorph: StackMorph authoringPrototype\\\"! !\\n\\n!StackMorph methodsFor: 'initialization' stamp: 'sw 3/18/2002 02:13'!\\ninitializeWith: aCardMorph\\n\\t\\\"Install the card inside a new stack. Make no border or controls, so I the card's look is unchanged. Card already has a CardPlayer.\\\"\\n\\t\\n\\t| wld |\\n\\twld _ aCardMorph world.\\n\\tself initialize.\\n\\tself pageSize: aCardMorph extent.\\n\\tself borderWidth: 0; layoutInset: 0; color: Color transparent.\\n\\tpages _ Array with: aCardMorph.\\n\\tcurrentPage _ aCardMorph.\\n\\tself privateCards: (OrderedCollection with: currentPage currentDataInstance).\\n\\tcurrentPage beAStackBackground.\\n\\tself position: aCardMorph position.\\n\\tsubmorphs last delete.\\n\\tself addMorph: currentPage.\\t\\n\\tself showPageControls: self fullControlSpecs.\\n\\twld addMorph: self.\\n! !\\n\\n\\n!StackMorph methodsFor: 'insert and delete' stamp: 'sw 10/30/2000 10:10'!\\ndefaultNameStemForNewPages\\n\\t\\\"Answer the stem to use as the default for names of cards in the stack\\\"\\n\\n\\t^ 'card'\\n! !\\n\\n\\n!StackMorph methodsFor: 'menu' stamp: 'dgd 8/30/2003 21:14'!\\naddBookMenuItemsTo: aMenu hand: aHandMorph\\n\\t\\\"Add book-related items to the given menu\\\"\\n\\n\\t| controlsShowing subMenu |\\n\\tsubMenu _ MenuMorph new defaultTarget: self.\\n\\tsubMenu add: 'previous card' translated action: #goToPreviousCardInStack.\\n\\tsubMenu add: 'next card' translated action: #goToNextCardInStack.\\n\\tsubMenu add: 'go to card...' translated action: #goToCard.\\n\\tsubMenu add: 'insert a card' translated action: #insertCard.\\n\\tsubMenu add: 'delete this card' translated action: #deleteCard.\\n\\n\\tcontrolsShowing _ self hasSubmorphWithProperty: #pageControl.\\n\\tcontrolsShowing\\n\\t\\tifTrue:\\n\\t\\t\\t[subMenu add: 'hide card controls' translated action: #hidePageControls.\\n\\t\\t\\tsubMenu add: 'fewer card controls' translated action: #fewerPageControls]\\n\\t\\tifFalse:\\n\\t\\t\\t[subMenu add: 'show card controls' translated action: #showPageControls].\\n\\n\\tsubMenu addLine.\\n\\tsubMenu add: 'sound effect for all backgrounds' translated action: #menuPageSoundForAll:.\\n\\tsubMenu add: 'sound effect this background only' translated action: #menuPageSoundForThisPage:.\\n\\tsubMenu add: 'visual effect for all backgrounds' translated action: #menuPageVisualForAll:.\\n\\tsubMenu add: 'visual effect this background only' translated action: #menuPageVisualForThisPage:.\\n\\n\\tsubMenu addLine.\\n\\tsubMenu add: 'sort pages' translated action: #sortPages:.\\n\\tsubMenu add: 'uncache page sorter' translated action: #uncachePageSorter.\\n\\t(self hasProperty: #dontWrapAtEnd)\\n\\t\\tifTrue: [subMenu add: 'wrap after last page' translated selector: #setWrapPages: argument: true]\\n\\t\\tifFalse: [subMenu add: 'stop at last page' translated selector: #setWrapPages: argument: false].\\n\\n\\tsubMenu addUpdating: #showingFullScreenString action: #toggleFullScreen.\\n\\tsubMenu addLine.\\n\\tsubMenu add: 'search for text' translated action: #textSearch.\\n\\t(self primaryHand pasteBuffer class isKindOf: PasteUpMorph class) ifTrue:\\n\\t\\t[subMenu add: 'paste book page' translated action: #pasteBookPage].\\n\\n\\tsubMenu add: 'send all pages to server' translated action: #savePagesOnURL.\\n\\tsubMenu add: 'send this page to server' translated action: #saveOneOnURL.\\n\\tsubMenu add: 'reload all from server' translated action: #reload.\\n\\tsubMenu add: 'copy page url to clipboard' translated action: #copyUrl.\\n\\tsubMenu add: 'keep in one file' translated action: #keepTogether.\\n\\tsubMenu add: 'save as new-page prototype' translated action: #setNewPagePrototype.\\n\\tnewPagePrototype ifNotNil:\\n\\t\\t[subMenu add: 'clear new-page prototype' translated action: #clearNewPagePrototype].\\n\\n\\taMenu add: 'book...' translated subMenu: subMenu\\n! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'sw 3/18/2002 02:06'!\\nfindText: wants\\n\\t\\\"Turn to the next card that has all of the strings mentioned on it. Highlight where it is found. allText and allTextUrls have been set. Case insensitive search.\\n\\tResuming a search. If container's text is still in the list and secondary keys are still in the page, (1) search rest of that container. (2) search rest of containers on that page (3) pages till end of book, (4) from page 1 to this page again.\\\"\\n\\n\\t\\\"Later sort wants so longest key is first\\\"\\n\\t| allText good thisWord here fromHereOn startToHere oldContainer oldIndex otherKeys strings |\\n\\tallText _ self valueOfProperty: #allText ifAbsent: [#()].\\n\\there _ self privateCards identityIndexOf: self currentCard ifAbsent: [1].\\n\\tfromHereOn _ here+1 to: self privateCards size.\\n\\tstartToHere _ 1 to: here.\\t\\t\\\"repeat this page\\\"\\n\\t(self valueOfProperty: #searchKey ifAbsent: [#()]) = wants ifTrue: [\\n\\t\\t\\\"does page have all the other keys? No highlight if found!!\\\"\\n\\t\\totherKeys _ wants allButFirst.\\n\\t\\tstrings _ allText at: here.\\n\\t\\tgood _ true.\\n\\t\\totherKeys do: [:searchString | \\\"each key\\\"\\n\\t\\t\\tgood ifTrue: [thisWord _ false.\\n\\t\\t\\t\\tstrings do: [:longString |\\n\\t\\t\\t\\t\\t(longString findWordStart: searchString startingAt: 1) > 0 ifTrue: [\\n\\t\\t\\t\\t\\t\\t\\tthisWord _ true]].\\n\\t\\t\\t\\tgood _ thisWord]].\\n\\t\\tgood ifTrue: [\\\"all are on this page. Look in rest for string again.\\\"\\n\\t\\t\\toldContainer _ self valueOfProperty: #searchContainer.\\n\\t\\t\\toldIndex _ self valueOfProperty: #searchOffset.\\n\\t\\t\\t(self findText: (OrderedCollection with: wants first) inStrings: strings\\t\\n\\t\\t\\t\\tstartAt: oldIndex+1 container: oldContainer \\n\\t\\t\\t\\tcardNum: here) ifTrue: [\\n\\t\\t\\t\\t\\tself setProperty: #searchKey toValue: wants.\\n\\t\\t\\t\\t\\t^ true]]]\\n\\t\\tifFalse: [fromHereOn _ here to: self privateCards size].\\t\\\"do search this page\\\"\\n\\t\\\"other pages\\\"\\n\\tfromHereOn do: [:cardNum |\\n\\t\\t(self findText: wants inStrings: (allText at: cardNum) startAt: 1 container: nil \\n\\t\\t\\t\\tcardNum: cardNum) \\n\\t\\t\\t\\t\\tifTrue: [^ true]].\\n\\tstartToHere do: [:cardNum |\\n\\t\\t(self findText: wants inStrings: (allText at: cardNum) startAt: 1 container: nil \\n\\t\\t\\t\\tcardNum: cardNum) \\n\\t\\t\\t\\t\\tifTrue: [^ true]].\\n\\t\\\"if fail\\\"\\n\\tself setProperty: #searchContainer toValue: nil.\\n\\tself setProperty: #searchOffset toValue: nil.\\n\\tself setProperty: #searchKey toValue: nil.\\n\\t^ false! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'gm 2/22/2003 13:13'!\\nfindText: keys inStrings: rawStrings startAt: startIndex container: oldContainer cardNum: cardNum \\n\\t\\\"Call once to search a card of the stack. Return true if found and highlight the text. oldContainer should be NIL. \\n\\t(oldContainer is only non-nil when (1) doing a 'search again' and (2) the page is in memory and (3) keys has just one element. oldContainer is a TextMorph.)\\\"\\n\\n\\t| good thisWord index insideOf place container start strings old |\\n\\tgood := true.\\n\\tstart := startIndex.\\n\\tstrings := oldContainer ifNil: \\n\\t\\t\\t\\t\\t[\\\"normal case\\\"\\n\\n\\t\\t\\t\\t\\trawStrings]\\n\\t\\t\\t\\tifNotNil: [self currentPage allStringsAfter: oldContainer text].\\n\\tkeys do: \\n\\t\\t\\t[:searchString | \\n\\t\\t\\t\\\"each key\\\"\\n\\n\\t\\t\\tgood \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[thisWord := false.\\n\\t\\t\\t\\t\\tstrings do: \\n\\t\\t\\t\\t\\t\\t\\t[:longString | \\n\\t\\t\\t\\t\\t\\t\\t(index := longString findWordStart: searchString startingAt: start) > 0 \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[thisWord not & (searchString == keys first) \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[insideOf := longString.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tplace := index].\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tthisWord := true].\\n\\t\\t\\t\\t\\t\\t\\tstart := 1].\\t\\\"only first key on first container\\\"\\n\\t\\t\\t\\t\\tgood := thisWord]].\\n\\tgood \\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"all are on this page\\\"\\n\\n\\t\\t\\t\\\"wasIn _ (pages at: pageNum) isInMemory.\\\"\\n\\n\\t\\t\\tself goToCardNumber: cardNum\\n\\t\\t\\t\\\"wasIn ifFalse: ['search again, on the real current text. Know page is in.'.\\n\\t\\t\\t^ self findText: keys \\n\\t\\t\\t\\tinStrings: ((pages at: pageNum) allStringsAfter: nil) recompute it\\t\\n\\t\\t\\t\\tstartAt: startIndex container: oldContainer \\n\\t\\t\\t\\tpageNum: pageNum]\\\"].\\n\\t(old := self valueOfProperty: #searchContainer) ifNotNil: \\n\\t\\t\\t[(old respondsTo: #editor) \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[old editor selectFrom: 1 to: 0.\\t\\\"trying to remove the previous selection!!\\\"\\n\\t\\t\\t\\t\\told changed]].\\n\\tgood \\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"have the exact string object\\\"\\n\\n\\t\\t\\t(container := oldContainer) ifNil: \\n\\t\\t\\t\\t\\t[container := self \\n\\t\\t\\t\\t\\t\\t\\t\\thighlightText: keys first\\n\\t\\t\\t\\t\\t\\t\\t\\tat: place\\n\\t\\t\\t\\t\\t\\t\\t\\tin: insideOf]\\n\\t\\t\\t\\tifNotNil: \\n\\t\\t\\t\\t\\t[container userString == insideOf \\n\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t[container := self \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\thighlightText: keys first\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tat: place\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tin: insideOf]\\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[(container isTextMorph) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[container editor selectFrom: place to: keys first size - 1 + place.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcontainer changed]]].\\n\\t\\t\\tself setProperty: #searchContainer toValue: container.\\n\\t\\t\\tself setProperty: #searchOffset toValue: place.\\n\\t\\t\\tself setProperty: #searchKey toValue: keys.\\t\\\"override later\\\"\\n\\t\\t\\tActiveHand newKeyboardFocus: container.\\n\\t\\t\\t^true].\\n\\t^false! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'em 3/31/2005 10:20'!\\nfindViaTemplate\\n\\t| list pl cardInst |\\n\\t\\\"Current card is the template. Only search cards in this background. Look at cards directly (not allText). Key must be found in the same field as in the template. HyperCard style (multiple starts of words). \\n\\tPut results in a list, outside the stack.\\\"\\n\\n\\tlist _ self templateMatches.\\n\\tlist isEmpty ifTrue: [^ self inform: 'No matches were found.\\nBe sure the current card is mostly blank\\nand only has text you want to match.' translated]. \\n\\t\\\"put up a PluggableListMorph\\\"\\n\\tcardInst _ self currentCard.\\n\\tcardInst matchIndex: 0.\\t\\\"establish entries\\\"\\n\\tcardInst results at: 1 put: list.\\n\\tself currentPage setProperty: #myStack toValue: self.\\t\\\"way to get back\\\"\\n\\n\\tpl _ PluggableListMorph new\\n\\t\\t\\ton: cardInst list: #matchNames\\n\\t\\t\\tselected: #matchIndex changeSelected: #matchIndex:\\n\\t\\t\\tmenu: nil \\\"#matchMenu:shifted:\\\" keystroke: nil.\\n\\tActiveHand attachMorph: (self formatList: pl).\\n! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'tk 6/2/2001 11:40'!\\nformatList: pl\\n\\t| rr ff |\\n\\t\\\"Turn this plugglable list into a good looking morph.\\\"\\n\\n\\tpl color: Color transparent; borderWidth: 0.\\n\\tpl font: ((TextStyle named: #Palatino) fontOfSize: 14).\\n\\tpl toggleCornerRounding; width: 252; retractableOrNot; hResizing: #spaceFill.\\n\\trr _ (RectangleMorph new) toggleCornerRounding; extent: pl extent + (30@30).\\n\\trr color: self currentPage color; fillStyle: (ff _ self currentPage fillStyle copy).\\n\\tff isGradientFill ifTrue: [\\n\\t\\trr fillStyle direction: (ff direction * self currentPage extent / rr extent) rounded.\\n\\t\\trr fillStyle origin: rr bounds origin].\\n\\trr addMorph: pl.\\n\\trr layoutPolicy: TableLayout new.\\n\\trr layoutInset: 10@15; cellInset: 10@15; wrapDirection: #leftToRight.\\n\\trr listCentering: #center; borderWidth: 5; borderColor: #raised.\\n\\t\\\"Up and down buttons on left with arrows in a holder.\\\"\\n\\t\\\"lb _ (RectangleMorph new) color: transparent; borderWidth: 0.\\\"\\n\\t^ rr! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'sw 3/18/2002 02:07'!\\ngetAllText\\n\\t\\\"Collect the text for each card. Just point at strings so don't have to recopy them. (Parallel array of urls for ID of cards. Remote cards not working yet.)\\n\\tallText = Array (cards size) of arrays (fields in it) of strings of text.\\n\\tallTextUrls = Array (cards size) of urls or card numbers.\\\"\\n\\n\\t| oldUrls oldStringLists allText allTextUrls aUrl which |\\n\\tself writeSingletonData.\\n\\toldUrls _ self valueOfProperty: #allTextUrls ifAbsent: [#()].\\n\\toldStringLists _ self valueOfProperty: #allText ifAbsent: [#()].\\n\\tallText _ self privateCards collect: [:pg | OrderedCollection new].\\n\\tallTextUrls _ Array new: self privateCards size.\\n\\tself privateCards doWithIndex: [:aCard :ind | aUrl _ aCard url. aCard isInMemory \\n\\t\\tifTrue: [(allText at: ind) addAll: (aCard allStringsAfter: nil).\\n\\t\\t\\taUrl ifNil: [aUrl _ ind].\\n\\t\\t\\tallTextUrls at: ind put: aUrl]\\n\\t\\tifFalse: [\\\"Order of cards on server may be different. (later keep up to date?)\\\"\\n\\t\\t\\t\\\"*** bug in this algorithm if delete a page?\\\"\\n\\t\\t\\twhich _ oldUrls indexOf: aUrl.\\n\\t\\t\\tallTextUrls at: ind put: aUrl.\\n\\t\\t\\twhich = 0 ifFalse: [allText at: ind put: (oldStringLists at: which)]]].\\n\\tself setProperty: #allText toValue: allText.\\n\\tself setProperty: #allTextUrls toValue: allTextUrls.\\n\\t^ allText! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'dgd 9/29/2004 20:47'!\\ninvokeBookMenu\\n\\t\\\"Invoke the book's control panel menu.\\\"\\n\\n\\t| aMenu |\\n\\taMenu _ MenuMorph new defaultTarget: self.\\n\\taMenu addTitle: 'Stack' translated.\\n\\tPreferences noviceMode\\n\\t\\tifFalse: [aMenu addStayUpItem].\\n\\taMenu addList: {\\n\\t\\t{'find...' translated.\\t\\t\\t\\t\\t#textSearch}.\\n\\t\\t{'find via this template' translated.\\t\\t\\t#findViaTemplate}.\\n\\t\\t{'show designations' translated. \\t\\t\\t#showDesignationsOfObjects}.\\n\\t\\t{'explain designations' translated.\\t\\t\\t#explainDesignations}.\\n\\t\\t#-.\\n\\t\\t{'previous card' translated. \\t\\t\\t\\t#goToPreviousCardInStack}.\\n\\t\\t{'next card' translated. \\t\\t\\t\\t#goToNextCardInStack}.\\n\\t\\t{'first card' translated. \\t\\t\\t\\t#goToFirstCardOfStack}.\\n\\t\\t{'last card' translated. \\t\\t\\t\\t#goToLastCardOfStack}.\\n\\t\\t{'go to card...' translated. \\t\\t\\t\\t#goToCard}.\\n\\t\\t#-.\\n\\t\\t{'add a card of this background' translated. \\t\\t#insertCard}.\\n\\t\\t{'add a card of background...' translated.\\t\\t#insertCardOfBackground}.\\n\\t\\t{'make a new background...' translated. \\t\\t#makeNewBackground}.\\n\\t\\t#-.\\n\\t\\t{'insert cards from clipboard data' translated.\\t\\t#addCardsFromClipboardData.\\t'Create new cards from a formatted string on the clipboard' translated}.\\n\\t\\t{'insert cards from a file...' translated.\\t\\t#addCardsFromAFile.\\t\\t'Create new cards from data in a file' translated}.\\n\\t\\t#-.\\n\\t\\t{'instance variable order...' translated.\\t\\t#changeInstVarOrder.\\t\\t'Caution -- DANGER. Change the order of the variables on the cards' translated}.\\n\\t\\t{'be defaults for new cards' translated. \\t\\t#beDefaultsForNewCards.\\t\\t'Make these current field values be the defaults for their respective fields on new cards' translated}.\\n\\t\\t {'sort cards by...' translated.\\t\\t\\t#sortCards.\\t\\t\\t'Sort all the cards of the current background using some field as the sort key' translated}.\\n\\t\\t#-.\\n\\t\\t{'delete this card' translated. \\t\\t\\t#deleteCard}.\\n\\t\\t{'delete all cards *except* this one' translated.\\t#deleteAllCardsExceptThisOne}.\\n\\t\\t#-.\\n\\t\\t{'move card to front of stack' translated.\\t\\t#makeCurrentCardFirstInStack}.\\n\\t\\t{'move card to back of stack' translated.\\t\\t#makeCurrentCardLastInStack}.\\n\\t\\t{'move card one position earlier' translated.\\t\\t#moveCardOnePositionEarlier}.\\n\\t\\t{'move card one position later' translated.\\t\\t#moveCardOnePositionLater}.\\n\\t\\t#-.\\n\\t\\t{'scripts for this background' translated.\\t\\t#browseCardClass}.\\n\\t\\t#-.\\n\\t\\t{'debug...' translated.\\t\\t\\t\\t\\t#offerStackDebugMenu}.\\n\\t\\t{'bookish items...' translated. \\t\\t\\t#offerBookishMenu}}.\\n\\n\\taMenu addUpdating: #showingPageControlsString action: #toggleShowingOfPageControls.\\n\\taMenu addUpdating: #showingFullScreenString action: #toggleFullScreen.\\n\\n\\taMenu popUpEvent: self world activeHand lastEvent in: self world\\n! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'dgd 4/4/2006 16:49'!\\nofferBookishMenu\\n\\t\\\"Offer a menu with book-related items in it\\\"\\n\\n\\t| aMenu |\\n\\taMenu := MenuMorph new defaultTarget: self.\\n\\taMenu addTitle: 'Stack / Book' translated.\\n\\tPreferences noviceMode\\n\\t\\tifFalse: [aMenu addStayUpItem].\\n\\taMenu addList:\\n\\t\\t#(('sort pages' sortPages)\\n\\t\\t('uncache page sorter' uncachePageSorter)).\\n\\t(self hasProperty: #dontWrapAtEnd)\\n\\t\\tifTrue: [aMenu add: 'wrap after last page' translated selector: #setWrapPages: argument: true]\\n\\t\\tifFalse: [aMenu add: 'stop at last page' translated selector: #setWrapPages: argument: false].\\n\\taMenu addList:\\n\\t\\t#(('make bookmark'\\t bookmarkForThisPage)\\n\\t\\t('make thumbnail' thumbnailForThisPage)).\\n\\n\\taMenu addLine.\\n\\taMenu add: 'sound effect for all pages' translated action: #menuPageSoundForAll:.\\n\\taMenu add: 'sound effect this page only' translated action: #menuPageSoundForThisPage:.\\n\\taMenu add: 'visual effect for all pages' translated action: #menuPageVisualForAll:.\\n\\taMenu add: 'visual effect this page only' translated action: #menuPageVisualForThisPage:.\\n\\n\\taMenu addLine.\\n\\t(self primaryHand pasteBuffer class isKindOf: PasteUpMorph class) ifTrue:\\n\\t\\t[aMenu add: 'paste book page' translated action: #pasteBookPage].\\n\\n\\taMenu add: 'save as new-page prototype' translated action: #setNewPagePrototype.\\n\\tnewPagePrototype ifNotNil: [\\n\\t\\taMenu add: 'clear new-page prototype' translated action: #clearNewPagePrototype].\\n\\n\\taMenu add: (self dragNDropEnabled ifTrue: ['close' translated ] ifFalse: ['open' translated]) , ' dragNdrop' translated\\n\\t\\t\\taction: #toggleDragNDrop.\\n\\taMenu addLine.\\n\\taMenu add: 'make all pages this size' translated action: #makeUniformPageSize.\\n\\taMenu addUpdating: #keepingUniformPageSizeString target: self action: #toggleMaintainUniformPageSize.\\n\\taMenu addLine.\\n\\taMenu add: 'send all pages to server' translated action: #savePagesOnURL.\\n\\taMenu add: 'send this page to server' translated action: #saveOneOnURL.\\n\\taMenu add: 'reload all from server' translated action: #reload.\\n\\taMenu add: 'copy page url to clipboard' translated action: #copyUrl.\\n\\taMenu add: 'keep in one file' translated action: #keepTogether.\\n\\n\\taMenu addLine.\\n\\taMenu add: 'load PPT images from slide #1' translated action: #loadImagesIntoBook.\\n\\taMenu add: 'background color for all pages...' translated action: #setPageColor.\\n\\n\\taMenu popUpEvent: self world activeHand lastEvent in: self world\\n! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'dgd 9/29/2004 20:47'!\\nofferStackDebugMenu\\n\\t\\\"Put up a menu offering debugging items for the stack\\\"\\n\\n\\t| aMenu |\\n\\taMenu _ MenuMorph new defaultTarget: self.\\n\\taMenu addTitle: 'Stack debugging'.\\n\\tPreferences noviceMode\\n\\t\\tifFalse: [aMenu addStayUpItem].\\n\\taMenu addList: #(\\n\\t\\t('reassess'\\t\\t\\t\\t\\t\\t\\t\\treassessBackgroundShape)\\n\\t\\t('relax grip on variable names'\\t\\t\\trelaxGripOnVariableNames)\\n\\t\\t('commit card data'\\t\\t\\t\\t\\t\\tcommitCardData)\\n\\t\\t-\\n\\t\\t('browse card uniclass'\\t\\t\\t\\t\\tbrowseCardClass)\\n\\t\\t('inspect card'\\t\\t\\t\\t\\t\\t\\tinspectCurrentCard)\\n\\t\\t('inspect background'\\t\\t\\t\\t\\tinspectCurrentBackground)\\n\\t\\t('inspect stack'\\t\\t\\t\\t\\t\\t\\tinspectCurrentStack)).\\n\\taMenu popUpInWorld: (self world ifNil: [self currentWorld])\\n! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'sw 3/18/2002 01:58'!\\ntemplateMatches\\n\\t| template docks keys bkg |\\n\\t\\\"Current card is the template. Only search cards in this background. Look at cards directly (not allText). Key must be found in the same field as in the template. HyperCard style (multiple starts of words). \\n\\tPut results in a list, outside the stack.\\\"\\n\\n\\ttemplate _ self currentCard.\\n\\ttemplate commitCardPlayerData.\\n\\tdocks _ template class variableDocks.\\n\\t(keys _ template asKeys) ifNil: [^ #()]. \\\"nothing to match against\\\"\\n\\tbkg _ self currentPage.\\n\\t^ self privateCards select: [:cardPlayer | \\n\\t\\t(((cardPlayer == template) not) and: [cardPlayer costume == bkg]) \\n\\t\\t\\tand: [cardPlayer match: keys fields: docks]].\\n! !\\n\\n!StackMorph methodsFor: 'menu' stamp: 'sw 3/18/2002 02:00'!\\nwriteSingletonData\\n\\t\\\"Backgrounds that have just one card, may never get their data written into a CardPlayer. Make sure we do it.\\\"\\n\\n\\t| sieve |\\n\\tsieve _ IdentityDictionary new.\\n\\tpages do: [:pp | sieve at: pp put: 0].\\n\\tself privateCards do: [:cc | sieve at: cc costume put: (sieve at: cc costume) + 1].\\n\\tsieve associationsDo: [:ass | \\n\\t\\tass value = 1 ifTrue:\\n\\t\\t\\t[ass key player commitCardPlayerDataFrom: ass key]].\\n\\t\\t\\t\\\"If currently showing card, may be some trouble... <- tk note 5/01\\\"! !\\n\\n\\n!StackMorph methodsFor: 'page controls' stamp: 'sw 6/6/2003 13:59'!\\naddPageControlMorph: aMorph\\n\\n\\t\\\"Add the given morph as a page-control, at the appropriate place\\\"\\n\\n\\n\\n\\taMorph setProperty: #pageControl toValue: true.\\n\\n\\tself addPane: aMorph paneType: #pageControl! !\\n\\n!StackMorph methodsFor: 'page controls' stamp: 'tk 11/5/2001 08:21'!\\nfullControlSpecs\\n\\t\\\"Answer specifications for the long form of iconic stack/book controls\\\"\\n\\n\\t^ #(\\n\\t\\tspacer\\n\\t\\tvariableSpacer\\n\\t\\t('-'\\t\\t\\tdeleteCard\\t\\t\\t\\t\\t'Delete this card')\\n\\t\\tspacer\\n\\t\\t( '\\U00ab'\\t\\tgoToFirstCardOfStack\\t\\t\\t'First card')\\n\\t\\tspacer\\n\\t\\t( '<' \\t\\tgoToPreviousCardInStack\\t\\t'Previous card')\\n\\t\\tspacer\\n\\t\\t('\\U00b7'\\t\\t\\tinvokeBookMenu \\t\\t\\t'Click here to get a menu of options for this stack.')\\n\\t\\t\\\"spacer\\t('\\U00b6'\\t\\t\\treshapeBackground \\t\\t'Reshape')\\t\\\"\\n\\n\\t\\tspacer\\n\\t\\t('\\U00a7'\\t\\t\\tshowDesignationsOfObjects \\t'Show designations')\\n\\t\\tspacer\\n\\t\\t('>'\\t\\t\\tgoToNextCardInStack\\t\\t\\t'Next card')\\n\\t\\tspacer\\n\\t\\t( '\\U00bb'\\t\\tgoToLastCardOfStack\\t\\t\\t'Final card')\\n\\t\\tspacer\\n\\t\\t('+'\\t\\t\\tinsertCard\\t\\t\\t\\t\\t'Add a new card after this one')\\n\\t\\tvariableSpacer\\n\\t\\t('\\U00b3'\\t\\t\\tfewerPageControls\\t\\t\\t'Fewer controls\\n(if shift key pressed,\\ndeletes controls)')\\n)! !\\n\\n!StackMorph methodsFor: 'page controls' stamp: 'sw 10/30/2000 10:09'!\\nshortControlSpecs\\n\\t\\\"Answer specficiations for the shorter form of stack controls\\\"\\n\\n\\t^ #(\\n\\t\\tspacer\\n\\t\\tvariableSpacer\\n\\t\\t( '<'\\t\\tgoToPreviousCardInStack\\t\\t'Previous card')\\n\\t\\tspacer\\n\\t\\t('\\U00b7'\\t\\tinvokeBookMenu \\t\\t\\t'Click here to get a menu for this stack.')\\n\\t\\tspacer\\n\\t\\t('>'\\t\\tgoToNextCardInStack\\t\\t\\t'Next card')\\n\\t\\tvariableSpacer\\n\\t\\t('\\U00b3'\\tshowMoreControls\\t\\t\\t\\t'More controls\\n(if shift key pressed,\\ndeletes controls)'))! !\\n\\n\\n!StackMorph methodsFor: 'parts bin' stamp: 'sw 8/2/2001 18:14'!\\ninitializeToStandAlone\\n\\t\\n\\tself initialize.\\n\\tself pageSize: (480 @ 320); color: (Color gray: 0.7).\\n\\tself borderWidth: 1; borderColor: Color black.\\n\\tself currentPage extent: self pageSize.\\n\\tself showPageControls: self fullControlSpecs.\\n\\t^ self\\n\\n\\\"StackMorph initializedInstance openInHand\\\"! !\\n\\n\\n!StackMorph methodsFor: 'submorphs-accessing' stamp: 'sw 3/18/2002 02:20'!\\nallNonSubmorphMorphs\\n\\t\\\"Return a collection containing all morphs in this morph which are not currently in the submorph containment hierarchy. Especially the non-showing pages in BookMorphs.\\\"\\n\\n\\t| coll |\\n\\tcoll _ OrderedCollection new.\\n\\tself privateCards do: [:cd | \\n\\t\\tcd privateMorphs ifNotNil: [coll addAll: cd privateMorphs]].\\n\\t^ coll! !\\n\\n!StackMorph methodsFor: 'submorphs-accessing' stamp: 'sw 6/5/2003 04:01'!\\ninsertionIndexForPaneOfType: aType\\n\\n\\t| naturalIndex insertionIndex |\\n\\n\\tnaturalIndex _ self naturalPaneOrder indexOf: aType.\\n\\n\\tinsertionIndex _ 1.\\n\\n\\t(self naturalPaneOrder copyFrom: 1 to: (naturalIndex - 1)) do: \\\"guys that would precede\\\"\\n\\n\\t\\t[:sym | (self hasSubmorphWithProperty: sym)\\n\\n\\t\\t\\tifTrue:\\n\\n\\t\\t\\t\\t[insertionIndex _ insertionIndex + 1]].\\n\\n\\t^ insertionIndex! !\\n\\n!StackMorph methodsFor: 'submorphs-accessing' stamp: 'sw 6/5/2003 04:02'!\\nnaturalPaneOrder\\n\\n\\t^ #(header pageControl retrieve search index content)! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStackMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!StackMorph class methodsFor: 'authoring prototype' stamp: 'nk 7/12/2003 08:59'!\\ndesignationsExplainer\\n\\t\\\"Answer a morph that contains designation explanation\\\"\\n\\n\\t| aMorph aSwatch aTextMorph |\\n\\taMorph _ AlignmentMorph newColumn color: Color black; layoutInset: 1.\\n\\t#((green\\t\\t\\n'Shared items on\\nBackground.\\nExact same item\\nshared by every card')\\n\\t(orange\\n'Data items on\\nBackground\\nEach card has its\\nown data')\\n\\t(red\\n'Instance-specific\\nitems\\nunique\\nto this card')) do:\\n\\n\\t[:aPair |\\n\\t\\taSwatch _ AlignmentMorph new extent: 132 @80; color: (Color perform: aPair first); lock.\\n\\t\\taSwatch hResizing: #rigid; vResizing: #rigid; layoutInset: 0.\\n\\t\\taSwatch borderColor: Color black.\\n\\t\\taTextMorph _ TextMorph new string: aPair second fontName: Preferences standardEToysFont familyName size: 18.\\n\\t\\taTextMorph width: 130.\\n\\t\\taTextMorph centered.\\n\\t\\taSwatch addMorphBack: aTextMorph.\\n\\t\\taMorph addMorphBack: aSwatch].\\n\\taMorph hResizing: #shrinkWrap; vResizing: #shrinkWrap.\\n\\n\\t^ aMorph\\n\\n\\t\\\"StackMorph designationsExplainer openInHand\\\"\\n! !\\n\\n\\n!StackMorph class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 11:30'!\\ninitialize\\n\\n\\tself registerInFlapsRegistry.\\t! !\\n\\n!StackMorph class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 11:36'!\\nregisterInFlapsRegistry\\n\\t\\\"Register the receiver in the system's flaps registry\\\"\\n\\tself environment\\n\\t\\tat: #Flaps\\n\\t\\tifPresent: [:cl | cl registerQuad: #(StackMorph\\tauthoringPrototype\\t'Stack'\\t\\t'A multi-card data base'\\t)\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Scripting'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(StackMorph\\tauthoringPrototype\\t'Stack'\\t\\t'A multi-card data base'\\t)\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Stack Tools'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(StackMorph\\tstackHelpWindow\\t'Stack Help'\\t'Some hints about how to use Stacks')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Stack Tools'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(StackMorph\\tpreviousCardButton\\t'Previous Card'\\t'A button that takes the user to the previous card in the stack')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Stack Tools'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(StackMorph\\tnextCardButton\\t'Next Card'\\t\\t'A button that takes the user to the next card in the stack')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Stack Tools']! !\\n\\n!StackMorph class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 12:40'!\\nunload\\n\\t\\\"Unload the receiver from global registries\\\"\\n\\n\\tself environment at: #Flaps ifPresent: [:cl |\\n\\tcl unregisterQuadsWithReceiver: self] ! !\\n\\n\\n!StackMorph class methodsFor: 'misc' stamp: 'tk 12/14/2001 19:23'!\\ndiscoverSlots: aMorph\\n\\t\\\"Examine the parts of the morph for ones that couldHoldSeparateData. Return a pair of lists: Named morphs, and unnamed morphs (which may be labels, and non-data). Examine all submorphs.\\\"\\n\\n\\t| named unnamed got sn generic |\\n\\tnamed _ OrderedCollection new.\\n\\tunnamed _ OrderedCollection new.\\n\\taMorph submorphsDo: [:direct | \\n\\t\\tgot _ false.\\n\\t\\tdirect allMorphsDo: [:sub |\\n\\t\\t\\tsub couldHoldSeparateDataForEachInstance ifTrue: [\\n\\t\\t\\t\\t(sn _ sub knownName) ifNotNil: [\\n\\t\\t\\t\\t\\tgeneric _ (#('Number (fancy)' 'Number (mid)' 'Number (bare)')\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tincludes: sn).\\n\\t\\t\\t\\t\\t(sn beginsWith: 'shared' \\\"label\\\") | generic ifFalse: [\\n\\t\\t\\t\\t\\t\\tnamed add: sub.\\n\\t\\t\\t\\t\\t\\tgot _ true]]]].\\n\\t\\tgot ifFalse: [unnamed add: direct]].\\n\\t^ Array with: named with: unnamed\\n\\t\\t! !\\n\\n\\n!StackMorph class methodsFor: 'navigation buttons' stamp: 'sw 10/27/2000 10:53'!\\nnextCardButton\\n\\t\\\"Answer a button that advances the user to the next card in the stack\\\"\\n\\n\\t| aButton |\\n\\taButton _ SimpleButtonMorph new.\\n\\taButton target: aButton; actionSelector: #goToNextCardInStack; label: '>'; color: Color yellow; borderWidth: 0.\\n\\taButton setNameTo: 'next'.\\n\\t^ aButton! !\\n\\n!StackMorph class methodsFor: 'navigation buttons' stamp: 'sw 10/27/2000 10:53'!\\npreviousCardButton\\n\\t\\\"Answer a button that will take the user to the preceding card in the stack\\\"\\n\\n\\t| aButton |\\n\\taButton _ SimpleButtonMorph new.\\n\\taButton target: aButton; actionSelector: #goToPreviousCardInStack; label: '<'; color: Color yellow ; borderWidth: 0.\\n\\taButton setNameTo: 'previous'.\\n\\t^ aButton! !\\n\\n\\n!StackMorph class methodsFor: 'parts bin' stamp: 'sw 8/2/2001 12:52'!\\ndescriptionForPartsBin\\n\\t^ self partName:\\t'Stack'\\n\\t\\tcategories:\\t\\t#('Presentation')\\n\\t\\tdocumentation:\\t'A database of any sort -- slide show, rolodex, and any point in between'! !\\n\\n!StackMorph class methodsFor: 'parts bin' stamp: 'sw 4/8/2002 09:30'!\\nstackHelpWindow\\n\\t^ (Workspace new contents: 'A \\\"stack\\\" is a place where you can create, store, view and retrieve data \\\"fields\\\" from a set of \\\"cards\\\". Data that you want to occur on every card (such as a name and an address in an Address Stack) are represented by objects such as \\\"Simple Text\\\", \\\"Fancy Text\\\", and \\\"Scrolling Text\\\" that you obtain from the Stack Tools flap.\\n\\nWhen you look at a card in a Stack, you may be seeing three different kinds of material. Press the \\U00a7 button in the stack''s controls to see the current designations, and use the \\\"explain designations\\\" to get a reminder of what the three different colors mean.\\n\\U00b7 Things that are designated to be seen on every card, and have the same contents whichever card is being shown. (green)\\n\\U00b7 Things that are designated to be seen on every card, with each card having its own value for them. (orange)\\n\\U00b7 Things that are designated to occur only on the particular card at hand. (red)\\n\\nUse the \\\"stack/cards\\\" menu (in an object''s halo menu) to change the designation of any object. For example, if you have an object that is private to just one card, and you want to make it visible on all cards, use \\\"place onto background\\\". If you further want it to hold a separate value for each separate card, use \\\"start holding separate data for each instance\\\".\\n\\nThe normal sequence to define a Stack''s structure is to obtain a blank Stack, then create your fields by grabbing what you want from the Stack Tools flap and dropping it where you want it in the stack. For easiest use, give a name to each field (by editing the name in its halo) *before* you put it onto the background.. Those fields that you want to represent the basic data of the stack need to be given names, placed on the background, and then told to hold separate data.\\n\\nWhen you hit the + button in a stack''s controls, a new card is created with default values in all the fields. You can arrange for a particular default value to be used in a field -- do this either for one field at a time with \\\"be default value on new card\\\", or you can request that the all the values seen on a particular card serve as default by choosing \\\"be defaults for new cards\\\" from the stack''s \\U00b7 menu.\\n\\nIt is also possible to have multiple \\\"backgrounds\\\" in the same stack -- each different background defines a different data structure, and cards from multiple backgrounds can be freely mixed in the same stack.\\n\\nBesides text fields, it is also possible to have picture-valued fields -- and potentially fields with data values of any other type as well.')\\n\\n\\tembeddedInMorphicWindowLabeled: 'Stack Help'\\n\\n\\t\\\"StackMorph stackHelpWindow\\\"! !\\n\\n\\n!StackMorph class methodsFor: 'scripting' stamp: 'sw 11/2/2002 15:47'!\\nadditionsToViewerCategories\\n\\t\\\"Answer a list of (<categoryName> <list of category specs>) pairs that characterize the phrases this kind of morph wishes to add to various Viewer categories.\\\"\\n\\n\\t^ # ((#'stack navigation'\\n\\t\\t\\t((command goToNextCardInStack 'Go to the next card')\\n\\t\\t\\t(command goToPreviousCardInStack 'Go to the previous card')\\n\\t\\t\\t(command goToFirstCardInBackground 'Go to the first card of the current background')\\n\\t\\t\\t(command goToFirstCardOfStack 'Go to the first card of the entire stack')\\n\\t\\t\\t(command goToLastCardInBackground 'Go to the last card of the current background')\\n\\t\\t\\t(command goToLastCardOfStack 'Go to the last card of the entire stack')\\n\\t\\t\\t(command deleteCard 'Delete the current card')\\n\\t\\t\\t(command insertCard 'Create a new card')\\n\\t\\t\\t(slot cardNumber 'The ordinal number of the current card' Number readWrite Player getCardNumber Player setCardNumber:))))! !\\n\\n!StackMorph class methodsFor: 'scripting' stamp: 'sw 10/9/2000 07:43'!\\nauthoringPrototype\\n\\t\\\"Answer an instance of the receiver suitable for placing in a parts bin for authors\\\"\\n\\t\\n\\t| book |\\n\\tbook _ self new markAsPartsDonor.\\n\\tbook pageSize: (480 @ 320); color: (Color gray: 0.7).\\n\\tbook borderWidth: 1; borderColor: Color black.\\n\\tbook currentPage extent: book pageSize.\\n\\tbook showPageControls: book fullControlSpecs.\\n\\t^ book\\n\\n\\\"self currentHand attachMorph: StackMorph authoringPrototype\\\"! !\\nTestCase subclass: #StackTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'CollectionsTests-Stack'!\\n\\n!StackTest methodsFor: 'test' stamp: 'dc 6/21/2006 10:55'!\\ntestEmptyError\\n\\n\\t| aStack |\\n\\taStack := Stack new.\\n\\tself should: [ aStack top ] raise: Error.\\n\\tself should: [ aStack pop] raise: Error.\\n\\t\\n\\taStack push: 'element'.\\n\\t\\n\\tself shouldnt: [ aStack top ] raise: Error.\\n\\tself shouldnt: [ aStack pop] raise: Error.\\n\\t\\n\\t\\n\\t\\\"The stack is empty again due to previous pop\\\"\\n\\tself should: [ aStack top ] raise: Error.\\n\\tself should: [ aStack pop] raise: Error.! !\\n\\n!StackTest methodsFor: 'test' stamp: 'sd 3/21/2006 22:13'!\\ntestPop\\n\\n\\t| aStack res elem |\\n\\telem := 'anElement'.\\t\\n\\taStack := Stack new.\\n\\tself assert: aStack isEmpty.\\n\\t\\n\\taStack push: 'a'.\\n\\taStack push: elem.\\n\\tres := aStack pop.\\t\\n\\tself assert: res = elem.\\n\\tself assert: res == elem.\\n\\t\\n\\tself assert: aStack size = 1.\\n\\taStack pop.\\n\\tself assert: aStack isEmpty.\\n\\n! !\\n\\n!StackTest methodsFor: 'test' stamp: 'sd 3/21/2006 22:13'!\\ntestPush\\n\\t\\n\\t| aStack |\\n\\taStack := Stack new.\\n\\taStack push: 'a'.\\n\\tself assert: aStack size = 1.\\t\\n\\taStack push: 'b'.\\n\\tself assert: aStack size = 2.\\n\\t! !\\n\\n!StackTest methodsFor: 'test' stamp: 'sd 3/21/2006 22:13'!\\ntestSize\\n\\t\\n\\t| aStack |\\n\\taStack := Stack new.\\n\\tself assert: aStack size = 0.\\n\\taStack push: 'a'.\\n\\tself assert: aStack size = 1.\\n\\taStack push: 'b'.\\n\\tself assert: aStack size = 2.\\n\\taStack pop.\\n\\tself assert: aStack size = 1.\\n\\taStack pop.\\n\\tself assert: aStack size = 0.\\n\\n \\n\\t\\n\\n\\n! !\\n\\n!StackTest methodsFor: 'test' stamp: 'sd 3/21/2006 22:13'!\\ntestTop\\n\\n\\t| aStack |\\n\\taStack := Stack new.\\n\\tself assert: aStack isEmpty.\\n\\taStack push: 'a'.\\n\\taStack push: 'b'.\\n\\tself assert: aStack top = 'b'.\\n\\tself assert: aStack top = 'b'.\\n\\tself assert: aStack size = 2.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStackTest class\\n\\tinstanceVariableNames: 'testSize'!\\nSelectionMenu subclass: #StandardFileMenu\\n\\tinstanceVariableNames: 'canTypeFileName pattern'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-FileList'!\\n!StandardFileMenu commentStamp: 'mp 8/15/2005 18:44' prior: 0!\\nI represent a SelectionMenu which operates like a modal dialog for selecting files, somewhat similar to the StandardFile dialogs in MacOS and Java Swing.\\n\\nTry for example, the following:\\n\\n\\tStandardFileMenu oldFile inspect\\n\\n\\tStandardFileMenu oldFileStream inspect\\n\\n\\tStandardFileMenu newFile inspect\\n\\n\\tStandardFileMenu newFileStream inspect\\n\\t\\n\\t(StandardFileMenu oldFileMenu: FileDirectory default withPattern: '*') startUpWithCaption: 'Select a file:'\\n\\t\\n\\t(StandardFileMenu oldFileMenu: (FileDirectory default) withPatternList: {'*.txt'. '*.changes'}) startUpWithCaption: 'Select a file:'\\n!\\n\\n\\n!StandardFileMenu methodsFor: 'basic control sequences' stamp: 'rbb 2/16/2005 16:59'!\\nconfirmExistingFiles: aResult\\n\\n\\t|choice|\\n\\t(aResult directory fileExists: aResult name) ifFalse: [^aResult].\\n\\t\\n\\tchoice _ (UIManager default chooseFrom: #('overwrite that file' 'choose another name'\\n 'cancel')\\n\\t\\ttitle: aResult name, '\\nalready exists.').\\n\\n\\tchoice = 1 ifTrue: [\\n\\t\\taResult directory \\n\\t\\t\\tdeleteFileNamed: aResult name\\n\\t\\t\\tifAbsent: \\n\\t\\t\\t\\t[^self startUpWithCaption: \\n'Can''t delete ', aResult name, '\\nSelect another file'].\\n\\t\\t^aResult].\\n\\tchoice = 2 ifTrue: [^self startUpWithCaption: 'Select Another File'].\\n\\t^nil\\n ! !\\n\\n!StandardFileMenu methodsFor: 'basic control sequences' stamp: 'rbb 3/1/2005 11:14'!\\ngetTypedFileName: aResult\\n\\n\\t| name |\\n\\tname := UIManager default \\n\\t\\trequest: 'Enter a new file name' \\n\\t\\tinitialAnswer: ''.\\n\\tname = '' ifTrue: [^self startUpWithCaption: 'Select a File:' translated].\\n\\tname := aResult directory fullNameFor: name.\\n\\t^ StandardFileMenuResult\\n\\t\\t\\tdirectory: (FileDirectory forFileName: name)\\n\\t\\t\\tname: (FileDirectory localNameFor: name)\\n! !\\n\\n!StandardFileMenu methodsFor: 'basic control sequences' stamp: 'acg 9/28/1999 23:34'!\\nstartUpWithCaption: aString at: location\\n\\n\\t|result|\\n\\tresult _ super startUpWithCaption: aString at: location.\\n\\tresult ifNil: [^nil].\\n\\tresult isDirectory ifTrue:\\n\\t\\t[self makeFileMenuFor: result directory.\\n\\t\\t self computeForm.\\n\\t\\t ^self startUpWithCaption: aString at: location].\\n\\tresult isCommand ifTrue: \\n\\t\\t[result _ self getTypedFileName: result.\\n\\t\\tresult ifNil: [^nil]].\\n\\tcanTypeFileName ifTrue: [^self confirmExistingFiles: result].\\n\\t^result\\n\\t! !\\n\\n\\n!StandardFileMenu methodsFor: 'menu building' stamp: 'di 5/12/2000 10:31'!\\ndirectoryNamesString: aDirectory\\n\\\"Answer a string concatenating the directory name strings in aDirectory, each string followed by a '[...]' indicator, and followed by a cr.\\\"\\n\\n\\t^ String streamContents:\\n\\t\\t[:s | aDirectory directoryNames do: \\n\\t\\t\\t\\t[:dn | s nextPutAll: dn withBlanksTrimmed , ' [...]'; cr]]\\n\\n! !\\n\\n!StandardFileMenu methodsFor: 'menu building' stamp: 'zz 8/15/2005 17:33'!\\nfileNamesString: aDirectory\\n\\\"Answer a string concatenating the file name strings in aDirectory, each string followed by a cr.\\\"\\n\\n\\t^String streamContents:\\n\\t\\t[:s | \\n\\t\\t\\taDirectory fileNames do: \\n\\t\\t\\t\\t[:fn |\\n\\t\\t\\t\\t\\tpattern do:[:each | (each match: fn) ifTrue: [\\n\\t\\t\\t\\t\\t\\ts nextPutAll: fn withBlanksTrimmed; cr]]]]\\n\\t\\t! !\\n\\n!StandardFileMenu methodsFor: 'menu building' stamp: 'zz 8/15/2005 16:28'!\\nmakeFileMenuFor: aDirectory\\n\\\"Initialize an instance of me to operate on aDirectory\\\"\\n\\n\\t| theMenu |\\n\\tpattern ifNil: [pattern := {'*'}].\\n\\tCursor wait showWhile: \\n\\t\\t[self \\n\\t\\t\\tlabels: \\t(self menuLabelsString: aDirectory)\\n\\t\\t\\tfont: \\t(MenuStyle fontAt: 1) \\n\\t\\t\\tlines: \\t(self menuLinesArray: aDirectory).\\n\\t\\ttheMenu := self selections: (self menuSelectionsArray: aDirectory)].\\n\\t^theMenu! !\\n\\n!StandardFileMenu methodsFor: 'menu building' stamp: 'acg 4/15/1999 21:57'!\\nmenuLabelsString: aDirectory\\n\\\"Answer a menu labels object corresponding to aDirectory\\\"\\n\\n\\t^ String streamContents: \\n\\t\\t[:s | \\n\\t\\t\\tcanTypeFileName ifTrue: \\n\\t\\t\\t\\t[s nextPutAll: 'Enter File Name...'; cr].\\n\\t\\t\\ts nextPutAll: (self pathPartsString: aDirectory).\\n\\t\\t\\ts nextPutAll: (self directoryNamesString: aDirectory).\\n\\t\\t\\ts nextPutAll: (self fileNamesString: aDirectory).\\n\\t\\t\\ts skip: -1]! !\\n\\n!StandardFileMenu methodsFor: 'menu building' stamp: 'tpr 11/28/2003 15:12'!\\nmenuLinesArray: aDirectory\\n\\\"Answer a menu lines object corresponding to aDirectory\\\"\\n\\n\\t| typeCount nameCnt dirDepth|\\n\\ttypeCount _ canTypeFileName \\n\\t\\tifTrue: [1] \\n\\t\\tifFalse: [0].\\n\\tnameCnt _ aDirectory directoryNames size.\\n\\tdirDepth _ aDirectory pathParts size.\\n\\t^Array streamContents: [:s |\\n\\t\\tcanTypeFileName ifTrue: [s nextPut: 1].\\n\\t\\ts nextPut: dirDepth + typeCount + 1.\\n\\t\\ts nextPut: dirDepth + nameCnt + typeCount + 1]! !\\n\\n!StandardFileMenu methodsFor: 'menu building' stamp: 'zz 8/15/2005 18:18'!\\nmenuSelectionsArray: aDirectory\\n\\\"Answer a menu selections object corresponding to aDirectory. The object is an array corresponding to each item, each element itself constituting a two-element array, the first element of which contains a selector to operate on and the second element of which contains the parameters for that selector.\\\"\\n\\n\\t|dirSize|\\n\\tdirSize := aDirectory pathParts size.\\n\\t^Array streamContents: [:s |\\n\\t\\tcanTypeFileName ifTrue:\\n\\t\\t\\t[s nextPut: (StandardFileMenuResult\\n\\t\\t\\t\\tdirectory: aDirectory\\n\\t\\t\\t\\tname: nil)].\\n\\t\\ts nextPut: (StandardFileMenuResult\\n\\t\\t\\tdirectory: (FileDirectory root)\\n\\t\\t\\tname: '').\\n\\t\\taDirectory pathParts doWithIndex: \\n\\t\\t\\t[:d :i | s nextPut: (StandardFileMenuResult\\n\\t\\t\\t\\t\\tdirectory: (self \\n\\t\\t\\t\\t\\t\\tadvance: dirSize - i\\n\\t\\t\\t\\t\\t\\tcontainingDirectoriesFrom: aDirectory)\\n\\t\\t\\t\\t\\tname: '')].\\n\\t\\taDirectory directoryNames do: \\n\\t\\t\\t[:dn | s nextPut: (StandardFileMenuResult\\n\\t\\t\\t\\t\\t\\tdirectory: (FileDirectory on: (aDirectory fullNameFor: dn))\\n\\t\\t\\t\\t\\t\\tname: '')].\\n\\t\\taDirectory fileNames do: \\n\\t\\t\\t[:fn | pattern do: [:pat | (pat match: fn) ifTrue: [\\n\\t\\t\\t\\t\\ts nextPut: (StandardFileMenuResult\\n\\t\\t\\t\\t\\t\\tdirectory: aDirectory\\n\\t\\t\\t\\t\\t\\tname: fn)]]]]! !\\n\\n!StandardFileMenu methodsFor: 'menu building' stamp: 'acg 4/15/1999 21:03'!\\npathPartsString: aDirectory\\n\\\"Answer a string concatenating the path parts strings in aDirectory, each string followed by a cr.\\\"\\n\\n\\t^String streamContents:\\n\\t\\t[:s | \\n\\t\\t\\ts nextPutAll: '[]'; cr.\\n\\t\\t\\taDirectory pathParts asArray doWithIndex: \\n\\t\\t\\t\\t[:part :i |\\n\\t\\t\\t\\t\\ts next: i put: $ .\\n\\t\\t\\t\\t\\ts nextPutAll: part withBlanksTrimmed; cr]]! !\\n\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'acg 4/15/1999 00:32'!\\nadvance: anInteger containingDirectoriesFrom: aDirectory\\n\\n\\t| theDirectory |\\n\\ttheDirectory _ aDirectory.\\n\\t1 to: anInteger do: [:i | theDirectory _ theDirectory containingDirectory].\\n\\t^theDirectory! !\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'acg 4/15/1999 20:50'!\\ncomputeLabelParagraph\\n\\t\\\"Answer a Paragraph containing this menu's labels, one per line and centered.\\\"\\n\\n\\t^ Paragraph withText: labelString asText style: (MenuStyle leftFlush)! !\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'acg 4/15/1999 22:03'!\\nnewFileFrom: aDirectory\\n\\n\\tcanTypeFileName _ true.\\n\\t^self makeFileMenuFor: aDirectory! !\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'zz 8/15/2005 18:25'!\\nnewFileFrom: aDirectory withPatternList: aPatternList\\n\\n\\tcanTypeFileName := true.\\n\\tpattern := aPatternList.\\n\\t^self makeFileMenuFor: aDirectory! !\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'zz 8/15/2005 16:29'!\\nnewFileFrom: aDirectory withPattern: aPattern\\n\\n\\tcanTypeFileName := true.\\n\\tpattern := {aPattern}.\\n\\t^self makeFileMenuFor: aDirectory! !\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'acg 4/15/1999 22:03'!\\noldFileFrom: aDirectory\\n\\n\\tcanTypeFileName _ false.\\n\\t^self makeFileMenuFor: aDirectory! !\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'zz 8/15/2005 17:28'!\\noldFileFrom: aDirectory withPatternList: aPatternList\\n\\n\\tcanTypeFileName := false.\\n\\tpattern := aPatternList.\\n\\t^self makeFileMenuFor: aDirectory! !\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'zz 8/15/2005 16:28'!\\noldFileFrom: aDirectory withPattern: aPattern\\n\\n\\tcanTypeFileName := false.\\n\\tpattern := {aPattern}.\\n\\t^self makeFileMenuFor: aDirectory! !\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'zz 8/15/2005 17:29'!\\npatternList: aPatternList\\n\\n\\tpattern := aPatternList! !\\n\\n!StandardFileMenu methodsFor: 'private' stamp: 'zz 8/15/2005 16:31'!\\npattern: aPattern\\n\\t\\\" * for all files, or '*.cs' for changeSets, etc. Just like fileLists\\\"\\n\\n\\tpattern := {aPattern}! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStandardFileMenu class\\n\\tinstanceVariableNames: ''!\\n\\n!StandardFileMenu class methodsFor: 'instance creation' stamp: 'sma 4/30/2000 10:14'!\\nnewFileMenu: aDirectory\\n\\tSmalltalk isMorphic ifFalse: [^ PluggableFileList newFileMenu: aDirectory].\\n\\t^ super new newFileFrom: aDirectory! !\\n\\n!StandardFileMenu class methodsFor: 'instance creation' stamp: 'zz 8/15/2005 18:21'!\\nnewFileMenu: aDirectory withPatternList: aPatternList\\n\\tSmalltalk isMorphic ifFalse: [^ PluggableFileList newFileMenu: aDirectory].\\n\\t^ super new newFileFrom: aDirectory withPatternList: aPatternList! !\\n\\n!StandardFileMenu class methodsFor: 'instance creation' stamp: 'rww 9/23/2001 09:56'!\\nnewFileMenu: aDirectory withPattern: aPattern\\n\\tSmalltalk isMorphic ifFalse: [^ PluggableFileList newFileMenu: aDirectory].\\n\\t^ super new newFileFrom: aDirectory withPattern: aPattern! !\\n\\n!StandardFileMenu class methodsFor: 'instance creation' stamp: 'sma 4/30/2000 10:15'!\\noldFileMenu: aDirectory\\n\\tSmalltalk isMorphic ifFalse: [^ PluggableFileList oldFileMenu: aDirectory].\\n\\t^ super new oldFileFrom: aDirectory! !\\n\\n!StandardFileMenu class methodsFor: 'instance creation' stamp: 'zz 8/15/2005 17:41'!\\noldFileMenu: aDirectory withPatternList: aPatternList\\n\\n\\tSmalltalk isMorphic ifFalse: [^PluggableFileList oldFileMenu: aDirectory].\\n\\t^super new oldFileFrom: aDirectory withPatternList: aPatternList! !\\n\\n!StandardFileMenu class methodsFor: 'instance creation' stamp: 'RAA 5/25/2000 09:30'!\\noldFileMenu: aDirectory withPattern: aPattern\\n\\n\\tSmalltalk isMorphic ifFalse: [^PluggableFileList oldFileMenu: aDirectory].\\n\\t^super new oldFileFrom: aDirectory withPattern: aPattern! !\\n\\n\\n!StandardFileMenu class methodsFor: 'standard file operations' stamp: 'tk 2/14/2000 14:28'!\\nnewFile\\n\\n\\t^self newFileFrom: (FileDirectory default)! !\\n\\n!StandardFileMenu class methodsFor: 'standard file operations' stamp: 'dgd 9/21/2003 13:17'!\\nnewFileFrom: aDirectory\\n\\n\\t^(self newFileMenu: aDirectory)\\n\\t\\tstartUpWithCaption: 'Select a File:' translated! !\\n\\n!StandardFileMenu class methodsFor: 'standard file operations' stamp: 'acg 4/15/1999 22:18'!\\nnewFileStream\\n\\n\\t^self newFileStreamFrom: (FileDirectory default)! !\\n\\n!StandardFileMenu class methodsFor: 'standard file operations' stamp: 'tk 2/14/2000 14:28'!\\nnewFileStreamFrom: aDirectory\\n\\n\\t| sfmResult fileStream |\\n\\tsfmResult _ self newFileFrom: aDirectory.\\n\\tsfmResult ifNil: [^nil].\\n\\tfileStream _ sfmResult directory newFileNamed: sfmResult name.\\n\\t[fileStream isNil] whileTrue:\\n\\t\\t[sfmResult _ self newFileFrom: aDirectory.\\n\\t\\tsfmResult ifNil: [^nil].\\n\\t\\tfileStream _ sfmResult directory newFileNamed: sfmResult name].\\n\\t^fileStream\\n! !\\n\\n!StandardFileMenu class methodsFor: 'standard file operations' stamp: 'tk 2/14/2000 14:28'!\\noldFile\\n\\n\\t^self oldFileFrom: (FileDirectory default)! !\\n\\n!StandardFileMenu class methodsFor: 'standard file operations' stamp: 'dgd 9/21/2003 13:17'!\\noldFileFrom: aDirectory\\n\\n\\t^(self oldFileMenu: aDirectory)\\n\\t\\tstartUpWithCaption: 'Select a File:' translated! !\\n\\n!StandardFileMenu class methodsFor: 'standard file operations' stamp: 'MM 4/6/2004 22:56'!\\noldFileFrom: aDirectory withPattern: aPattern\\n\\\"\\nSelect an existing file from a selection conforming to aPattern.\\n\\\"\\n\\t^(self oldFileMenu: aDirectory withPattern: aPattern)\\n\\t\\tstartUpWithCaption: 'Select a File:' translated! !\\n\\n!StandardFileMenu class methodsFor: 'standard file operations' stamp: 'acg 4/15/1999 22:17'!\\noldFileStream\\n\\n\\t^self oldFileStreamFrom: (FileDirectory default)\\n! !\\n\\n!StandardFileMenu class methodsFor: 'standard file operations' stamp: 'tk 2/14/2000 14:27'!\\noldFileStreamFrom: aDirectory\\n\\n\\t| sfmResult fileStream |\\n\\tsfmResult _ self oldFileFrom: aDirectory.\\n\\tsfmResult ifNil: [^nil].\\n\\tfileStream _ sfmResult directory oldFileNamed: sfmResult name.\\n\\t[fileStream isNil] whileTrue:\\n\\t\\t[sfmResult _ self oldFileFrom: aDirectory.\\n\\t\\tsfmResult ifNil: [^nil].\\n\\t\\tfileStream _ sfmResult directory oldFileNamed: sfmResult name].\\n\\t^fileStream\\n! !\\nObject subclass: #StandardFileMenuResult\\n\\tinstanceVariableNames: 'directory name'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-FileList'!\\n\\n!StandardFileMenuResult methodsFor: 'accessing' stamp: 'acg 4/15/1999 08:43'!\\ndirectory\\n\\n\\t^directory! !\\n\\n!StandardFileMenuResult methodsFor: 'accessing' stamp: 'acg 4/15/1999 08:43'!\\ndirectory: aDirectory\\n\\n\\t^directory _ aDirectory! !\\n\\n!StandardFileMenuResult methodsFor: 'accessing' stamp: 'acg 4/15/1999 08:43'!\\nname\\n\\n\\t^name! !\\n\\n!StandardFileMenuResult methodsFor: 'accessing' stamp: 'acg 4/15/1999 08:43'!\\nname: aString\\n\\n\\t^name _ aString! !\\n\\n!StandardFileMenuResult methodsFor: 'accessing' stamp: 'sw 6/9/1999 11:50'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream nextPutAll: ' with directory: '.\\n\\tdirectory printOn: aStream.\\n\\taStream nextPutAll: ' name: '.\\n\\tname printOn: aStream\\n\\n\\\"StandardFileMenu oldFile\\\"! !\\n\\n\\n!StandardFileMenuResult methodsFor: 'testing' stamp: 'acg 4/15/1999 09:05'!\\nisCommand\\n\\n\\t^name isNil! !\\n\\n!StandardFileMenuResult methodsFor: 'testing' stamp: 'acg 4/15/1999 20:57'!\\nisDirectory\\n\\n\\t^name = ''! !\\n\\n\\n!StandardFileMenuResult methodsFor: 'private' stamp: 'acg 4/15/1999 08:42'!\\ndirectory: aDirectory name: aString\\n\\n\\tdirectory _ aDirectory.\\n\\tname _ aString.\\n\\t^self! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStandardFileMenuResult class\\n\\tinstanceVariableNames: ''!\\n\\n!StandardFileMenuResult class methodsFor: 'instance creation' stamp: 'acg 4/15/1999 08:42'!\\ndirectory: aDirectory name: aString\\n\\n\\t^super new directory: aDirectory name: aString! !\\nFileStream subclass: #StandardFileStream\\n\\tinstanceVariableNames: 'name fileID buffer1'\\n\\tclassVariableNames: 'Registry'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Files-Kernel'!\\n!StandardFileStream commentStamp: '<historical>' prior: 0!\\nProvides a simple, platform-independent, interface to a file system. This initial version ignores issues of Directories etc. The instance-variable fallbackStream at the moment holds an instance of HFSMacFileStream, to bridge us to the new world while in the old. The instance variable rwmode, inherited from class PositionableStream, here is used to hold a Boolean -- true means opened for read-write, false means opened for read-only. 2/12/96 sw!\\n\\n\\n!StandardFileStream methodsFor: 'access' stamp: 'jm 9/21/1998 14:16'!\\ndirectory\\n\\t\\\"Return the directory containing this file.\\\"\\n\\n\\t^ FileDirectory forFileName: self fullName\\n! !\\n\\n!StandardFileStream methodsFor: 'access' stamp: 'tk 3/14/2000 23:31'!\\ndirectoryUrl\\n\\n\\t^ self directory url! !\\n\\n!StandardFileStream methodsFor: 'access'!\\nfile\\n\\t\\\"Answer the object representing the receiver's file. Need for compatibility with some calls -- check senders. 2/14/96 sw\\\"\\n\\n\\t^ self! !\\n\\n!StandardFileStream methodsFor: 'access' stamp: 'jm 9/21/1998 14:19'!\\nfullName\\n\\t\\\"Answer this file's full path name.\\\"\\n\\n\\t^ name\\n! !\\n\\n!StandardFileStream methodsFor: 'access'!\\nisDirectory\\n\\t\\\"Answer whether the receiver represents a directory. For the post-transition case, uncertain what to do. 2/14/96 sw\\\"\\n\\t^ false! !\\n\\n!StandardFileStream methodsFor: 'access' stamp: 'ar 11/24/1998 14:00'!\\nlocalName\\n\\t^ name ifNotNil: [(name findTokens: FileDirectory pathNameDelimiter asString) last]! !\\n\\n!StandardFileStream methodsFor: 'access' stamp: 'jm 9/21/1998 14:19'!\\nname\\n\\t\\\"Answer this file's full path name.\\\"\\n\\n\\t^ name\\n! !\\n\\n!StandardFileStream methodsFor: 'access' stamp: 'stephaneducasse 2/4/2006 20:32'!\\npeekFor: item \\n\\t\\\"Answer false and do not advance if the next element is not equal to item, or if this stream is at the end. If the next element is equal to item, then advance over it and return true\\\"\\n\\t| next |\\n\\t\\\"self atEnd ifTrue: [^ false]. -- SFStream will give nil\\\"\\n\\t(next := self next) == nil ifTrue: [^ false].\\n\\titem = next ifTrue: [^ true].\\n\\tself skip: -1.\\n\\t^ false! !\\n\\n!StandardFileStream methodsFor: 'access'!\\nprintOn: aStream\\n\\t\\\"Put a printed version of the receiver onto aStream. 1/31/96 sw\\\"\\n\\n\\taStream nextPutAll: self class name; nextPutAll: ': '; print: name! !\\n\\n!StandardFileStream methodsFor: 'access' stamp: 'ar 6/16/2002 18:58'!\\nreset\\n\\tself ensureOpen.\\n\\tself position: 0.! !\\n\\n!StandardFileStream methodsFor: 'access'!\\nsize\\n\\t\\\"Answer the size of the file in characters. 2/12/96 sw\\\"\\n\\n\\t^ self primSize: fileID! !\\n\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'mir 1/11/2000 10:44'!\\ndefaultBrowserReadyWait\\n\\t^5000! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'stephaneducasse 2/4/2006 20:32'!\\npost: data target: target url: url ifError: errorBlock\\n\\t\\\"Post data to the given URL. The returned file stream contains the reply of the server.\\n\\tIf Squeak is not running in a browser evaluate errorBlock\\\"\\n\\t| sema index request result |\\n\\tself waitBrowserReadyFor: self defaultBrowserReadyWait ifFail: [^errorBlock value].\\n\\tsema := Semaphore new.\\n\\tindex := Smalltalk registerExternalObject: sema.\\n\\trequest := self primURLPost: url target: target data: data semaIndex: index.\\n\\trequest == nil ifTrue:[\\n\\t\\n\\tSmalltalk unregisterExternalObject: sema.\\n\\t\\t^errorBlock value.\\n\\t] ifFalse:[\\n\\t\\t[sema wait. \\\"until something happens\\\"\\n\\t\\tresult := self primURLRequestState: request.\\n\\t\\tresult == nil] whileTrue.\\n\\t\\tresult ifTrue:[fileID := self primURLRequestFileHandle: request].\\n\\t\\tself primURLRequestDestroy: request.\\n\\t].\\n\\tSmalltalk unregisterExternalObject: sema.\\n\\tfileID == nil ifTrue:[^nil].\\n\\tself register.\\n\\tname := url.\\n\\trwmode := false.\\n\\tbuffer1 := String new: 1.! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'mir 2/2/2001 14:22'!\\npost: data url: url ifError: errorBlock\\n\\n\\tself post: data target: nil url: url ifError: errorBlock! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'ar 2/26/2001 15:58'!\\nprimBrowserReady\\n\\t<primitive:'primitivePluginBrowserReady'>\\n\\t^nil! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'mir 9/21/2000 16:58'!\\nprimURLPost: url data: contents semaIndex: index\\n\\t^self primURLPost: url target: nil data: contents semaIndex: index! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'mir 9/21/2000 16:58'!\\nprimURLPost: url target: target data: contents semaIndex: index\\n\\t\\\"Post the data (url might be 'mailto:' etc)\\\"\\n\\t<primitive:'primitivePluginPostURL'>\\n\\t^nil\\n ! !\\n\\n!StandardFileStream methodsFor: 'browser requests'!\\nprimURLRequest: url semaIndex: index\\n\\t<primitive:'primitivePluginRequestURLStream'>\\n\\t^nil! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nprimURLRequest: url target: target semaIndex: index\\n\\t\\\"target - String (frame, also ':=top', ':=parent' etc)\\\"\\n\\t<primitive:'primitivePluginRequestURL'>\\n\\t^nil\\n ! !\\n\\n!StandardFileStream methodsFor: 'browser requests'!\\nprimURLRequestDestroy: request\\n\\t<primitive:'primitivePluginDestroyRequest'>\\n\\t^nil! !\\n\\n!StandardFileStream methodsFor: 'browser requests'!\\nprimURLRequestFileHandle: request\\n\\t<primitive: 'primitivePluginRequestFileHandle'>\\n\\t^nil! !\\n\\n!StandardFileStream methodsFor: 'browser requests'!\\nprimURLRequestState: request\\n\\t<primitive:'primitivePluginRequestState'>\\n\\t^false! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'mir 2/29/2000 11:22'!\\nrequestURL: url target: target\\n\\t^self requestURL: url target: target ifError: [nil]! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nrequestURL: url target: target ifError: errorBlock\\n\\t\\\"Request to go to the target for the given URL.\\n\\tIf Squeak is not running in a browser evaluate errorBlock\\\"\\n\\n\\t| sema index request result |\\n\\tself waitBrowserReadyFor: self defaultBrowserReadyWait ifFail: [^errorBlock value].\\n\\tsema := Semaphore new.\\n\\tindex := Smalltalk registerExternalObject: sema.\\n\\trequest := self primURLRequest: url target: target semaIndex: index.\\n\\trequest == nil ifTrue:[\\n\\t\\n\\tSmalltalk unregisterExternalObject: sema.\\n\\t\\t^errorBlock value.\\n\\t] ifFalse:[\\n\\t\\t[sema wait. \\\"until something happens\\\"\\n\\t\\tresult := self primURLRequestState: request.\\n\\t\\tresult == nil] whileTrue.\\n\\t\\tself primURLRequestDestroy: request.\\n\\t].\\n\\tSmalltalk unregisterExternalObject: sema.\\n\\tfileID == nil ifTrue:[^nil].\\n\\tself register.\\n\\tname := url.\\n\\trwmode := false.\\n\\tbuffer1 := String new: 1.! !\\n\\n!StandardFileStream methodsFor: 'browser requests'!\\nrequestURLStream: url\\n\\t\\\"FileStream requestURLStream:'http://www.squeak.org'\\\"\\n\\t^self requestURLStream: url ifError:[nil]! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nrequestURLStream: url ifError: errorBlock\\n\\t\\\"Request a FileStream for the given URL.\\n\\tIf Squeak is not running in a browser evaluate errorBlock\\\"\\n\\t\\\"FileStream requestURLStream:'http://www.squeak.org'\\\"\\n\\t| sema index request result |\\n\\tself waitBrowserReadyFor: self defaultBrowserReadyWait ifFail: [^errorBlock value].\\n\\tsema := Semaphore new.\\n\\tindex := Smalltalk registerExternalObject: sema.\\n\\trequest := self primURLRequest: url semaIndex: index.\\n\\trequest == nil ifTrue:[\\n\\t\\n\\tSmalltalk unregisterExternalObject: sema.\\n\\t\\t^errorBlock value.\\n\\t] ifFalse:[\\n\\t\\t[sema wait. \\\"until something happens\\\"\\n\\t\\tresult := self primURLRequestState: request.\\n\\t\\tresult == nil] whileTrue.\\n\\t\\tresult ifTrue:[fileID := self primURLRequestFileHandle: request].\\n\\t\\tself primURLRequestDestroy: request.\\n\\t].\\n\\tSmalltalk unregisterExternalObject: sema.\\n\\tfileID == nil ifTrue:[^nil].\\n\\tself register.\\n\\tname := url.\\n\\trwmode := false.\\n\\tbuffer1 := String new: 1.! !\\n\\n!StandardFileStream methodsFor: 'browser requests' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nwaitBrowserReadyFor: timeout ifFail: errorBlock\\n\\t| startTime delay okay |\\n\\tokay := self primBrowserReady.\\n\\tokay ifNil:[^errorBlock value].\\n\\tokay ifTrue: [^true].\\n\\tstartTime := Time millisecondClockValue.\\n\\tdelay := Delay forMilliseconds: 100.\\n\\t[(Time millisecondsSince: startTime) < timeout]\\n\\t\\twhileTrue: [\\n\\t\\t\\tdelay wait.\\n\\t\\t\\tokay := self primBrowserReady.\\n\\t\\t\\tokay ifNil:[^errorBlock value].\\n\\t\\t\\tokay ifTrue: [^true]].\\n\\t^errorBlock value! !\\n\\n\\n!StandardFileStream methodsFor: 'dnd requests' stamp: 'ar 1/10/2001 20:01'!\\nprimDropRequestFileHandle: dropIndex\\n\\t\\\"Primitive. Return the (read-only) file handle for some file that was just dropped onto Squeak.\\n\\tFail if dropIndex is out of range or the primitive is not supported.\\\"\\n\\t<primitive: 'primitiveDropRequestFileHandle' module:'DropPlugin'>\\n\\t^nil! !\\n\\n!StandardFileStream methodsFor: 'dnd requests' stamp: 'ar 1/10/2001 20:01'!\\nprimDropRequestFileName: dropIndex\\n\\t\\\"Primitive. Return the file name for some file that was just dropped onto Squeak.\\n\\tFail if dropIndex is out of range or the primitive is not supported.\\\"\\n\\t<primitive: 'primitiveDropRequestFileName' module:'DropPlugin'>\\n\\t^nil! !\\n\\n!StandardFileStream methodsFor: 'dnd requests' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nrequestDropStream: dropIndex\\n\\t\\\"Return a read-only stream for some file the user has just dropped onto Squeak.\\\"\\n\\tname := self primDropRequestFileName: dropIndex.\\n\\tfileID := self primDropRequestFileHandle: dropIndex.\\n\\tfileID == nil ifTrue:[^nil].\\n\\tself register.\\n\\trwmode := false.\\n\\tbuffer1 := String new: 1.\\n\\n! !\\n\\n\\n!StandardFileStream methodsFor: 'finalization' stamp: 'ar 3/21/98 18:16'!\\nactAsExecutor\\n\\tsuper actAsExecutor.\\n\\tname := nil.! !\\n\\n!StandardFileStream methodsFor: 'finalization' stamp: 'ar 10/7/1998 15:44'!\\nfinalize\\n\\tself primCloseNoError: fileID.! !\\n\\n\\n!StandardFileStream methodsFor: 'open/close' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nclose\\n\\t\\\"Close this file.\\\"\\n\\n\\tfileID ifNotNil: [\\n\\t\\tself primClose: fileID.\\n\\t\\tself unregister.\\n\\t\\tfileID := nil].\\n! !\\n\\n!StandardFileStream methodsFor: 'open/close' stamp: 'jm 2/6/2002 08:33'!\\nclosed\\n\\t\\\"Answer true if this file is closed.\\\"\\n\\n\\t^ fileID isNil or: [(self primSizeNoError: fileID) isNil]\\n! !\\n\\n!StandardFileStream methodsFor: 'open/close' stamp: 'jm 9/21/1998 16:20'!\\nensureOpen\\n\\t\\\"Make sure that this file really is open.\\\"\\n\\n\\tself closed ifTrue: [^ self reopen].\\n\\t(self primSizeNoError: fileID) ifNotNil: [^ self].\\n\\tself reopen.\\n! !\\n\\n!StandardFileStream methodsFor: 'open/close'!\\nopen\\n\\t\\\"For compatibility with a few existing things. 2/14/96 sw\\\"\\n\\n\\t^ self reopen! !\\n\\n!StandardFileStream methodsFor: 'open/close' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nopen: fileName forWrite: writeMode \\n\\t\\\"Open the file with the given name. If writeMode is true, allow writing, otherwise open the file in read-only mode.\\\"\\n\\t\\\"Changed to do a GC and retry before failing ar 3/21/98 17:25\\\"\\n\\t| f |\\n\\tf := fileName asVmPathName.\\n\\n\\tfileID := StandardFileStream retryWithGC:[self primOpen: f writable: writeMode] \\n\\t\\t\\t\\t\\tuntil:[:id| id notNil] \\n\\t\\t\\t\\t\\tforFileNamed: fileName.\\n\\tfileID ifNil: [^ nil]. \\\"allows sender to detect failure\\\"\\n\\tself register.\\n\\tname := fileName.\\n\\trwmode := writeMode.\\n\\tbuffer1 := String new: 1.\\n! !\\n\\n!StandardFileStream methodsFor: 'open/close'!\\nopenReadOnly\\n\\t\\\"Open the receiver as a read-only file. 1/31/96 sw\\\"\\n\\n\\t^ self open: name forWrite: false! !\\n\\n!StandardFileStream methodsFor: 'open/close' stamp: 'jm 9/21/1998 13:58'!\\nreopen\\n\\t\\\"Close and reopen this file. The file position is reset to zero.\\\"\\n\\t\\\"Details: Files that were open when a snapshot occurs are no longer valid when the snapshot is resumed. This operation re-opens the file if that has happened.\\\"\\n\\n\\tfileID ifNotNil: [self primCloseNoError: fileID].\\n\\tself open: name forWrite: rwmode.\\n! !\\n\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimAtEnd: id\\n\\t\\\"Answer true if the file position is at the end of the file.\\\"\\n\\n\\t<primitive: 'primitiveFileAtEnd' module: 'FilePlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimClose: id\\n\\t\\\"Close this file.\\\"\\n\\n\\t<primitive: 'primitiveFileClose' module: 'FilePlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimCloseNoError: id\\n\\t\\\"Close this file. Don't raise an error if the primitive fails.\\\"\\n\\n\\t<primitive: 'primitiveFileClose' module: 'FilePlugin'>\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nprimFlush: id\\n\\t\\\"Flush pending changes to the disk\\\"\\n\\t| p |\\n\\t<primitive: 'primitiveFileFlush' module: 'FilePlugin'>\\n\\t\\\"In some OS's seeking to 0 and back will do a flush\\\"\\n\\tp := self position.\\n\\tself position: 0; position: p! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimGetPosition: id\\n\\t\\\"Get this files current position.\\\"\\n\\n\\t<primitive: 'primitiveFileGetPosition' module: 'FilePlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimOpen: fileName writable: writableFlag\\n\\t\\\"Open a file of the given name, and return the file ID obtained.\\n\\tIf writableFlag is true, then\\n\\t\\tif there is none with this name, then create one\\n\\t\\telse prepare to overwrite the existing from the beginning\\n\\totherwise\\n\\t\\tif the file exists, open it read-only\\n\\t\\telse return nil\\\"\\n\\n\\t<primitive: 'primitiveFileOpen' module: 'FilePlugin'>\\n\\t^ nil\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimRead: id into: byteArray startingAt: startIndex count: count\\n\\t\\\"Read up to count bytes of data from this file into the given string or byte array starting at the given index. Answer the number of bytes actually read.\\\"\\n\\n\\t<primitive: 'primitiveFileRead' module: 'FilePlugin'>\\n\\tself closed ifTrue: [^ self error: 'File is closed'].\\n\\tself error: 'File read failed'.\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSetPosition: id to: anInteger\\n\\t\\\"Set this file to the given position.\\\"\\n\\n\\t<primitive: 'primitiveFileSetPosition' module: 'FilePlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSize: id\\n\\t\\\"Answer the size of this file.\\\"\\n\\n\\t<primitive: 'primitiveFileSize' module: 'FilePlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimSizeNoError: id\\n\\t\\\"Answer the size of this file. Answer nil if the primitive fails; this indicates that the file handle has become stale.\\\"\\n\\n\\t<primitive: 'primitiveFileSize' module: 'FilePlugin'>\\n\\t^ nil\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'JMM 5/24/2001 21:55'!\\nprimTruncate: id to: anInteger\\n\\t\\\"Truncate this file to the given position.\\\"\\n\\n\\t<primitive: 'primitiveFileTruncate' module: 'FilePlugin'>\\n\\tself primitiveFailed\\n! !\\n\\n!StandardFileStream methodsFor: 'primitives' stamp: 'ar 2/2/2001 15:09'!\\nprimWrite: id from: stringOrByteArray startingAt: startIndex count: count\\n\\t\\\"Write count bytes onto this file from the given string or byte array starting at the given index. Answer the number of bytes written.\\\"\\n\\n\\t<primitive: 'primitiveFileWrite' module: 'FilePlugin'>\\n\\tself closed ifTrue: [^ self error: 'File is closed'].\\n\\tself error: 'File write failed'.\\n! !\\n\\n\\n!StandardFileStream methodsFor: 'properties-setting'!\\nasHtml\\n\\t\\\"Convert me in to an HtmlFileStream. 4/11/96 tk\\\"\\n\\n\\t^ self as: HtmlFileStream \\n! !\\n\\n!StandardFileStream methodsFor: 'properties-setting' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nascii\\n\\t\\\"opposite of binary\\\"\\n\\tbuffer1 := String new: 1! !\\n\\n!StandardFileStream methodsFor: 'properties-setting' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nbinary\\n\\tbuffer1 := ByteArray new: 1! !\\n\\n!StandardFileStream methodsFor: 'properties-setting' stamp: 'JMM 1/28/2001 18:44'!\\ngetFileType\\n\\t\\\"On the Macintosh, get the file type and creator of this file. On other platforms, do nothing.\\\"\\n\\n\\t^FileDirectory default\\n\\t\\tgetMacFileTypeAndCreator: self fullName\\n\\t\\t\\n! !\\n\\n!StandardFileStream methodsFor: 'properties-setting' stamp: 'stephaneducasse 2/4/2006 20:32'!\\ninsertLineFeeds\\n\\t\\\"(FileStream oldFileNamed: 'BBfix2.st') insertLineFeeds\\\"\\n\\t| s crLf f |\\n\\tcrLf := String with: Character cr with: (Character value: 10).\\n\\ts := ReadStream on: (self next: self size).\\n\\tself close.\\n\\tf := FileStream newFileNamed: self name.\\n\\t[s atEnd] whileFalse: \\n\\t\\t[f nextPutAll: (s upTo: Character cr); nextPutAll: crLf].\\n\\tf close! !\\n\\n!StandardFileStream methodsFor: 'properties-setting'!\\nisBinary\\n\\t^ buffer1 class == ByteArray! !\\n\\n!StandardFileStream methodsFor: 'properties-setting' stamp: 'tk 11/4/1998 19:17'!\\nisReadOnly\\n\\n\\t^ rwmode not\\n! !\\n\\n!StandardFileStream methodsFor: 'properties-setting' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nreadOnly\\n\\t\\\"Make this file read-only.\\\"\\n\\n\\trwmode := false.\\n! !\\n\\n!StandardFileStream methodsFor: 'properties-setting' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nreadWrite\\n\\t\\\"Make this file writable.\\\"\\n\\n\\trwmode := true.\\n! !\\n\\n!StandardFileStream methodsFor: 'properties-setting' stamp: 'jm 12/5/97 15:14'!\\nsetFileTypeToObject\\n\\t\\\"On the Macintosh, set the file type and creator of this file to be a Squeak object file. On other platforms, do nothing. Setting the file type allows Squeak object files to be sent as email attachments and launched by double-clicking. On other platforms, similar behavior is achieved by creating the file with the '.sqo' file name extension.\\\"\\n\\n\\tFileDirectory default\\n\\t\\tsetMacFileNamed: self fullName\\n\\t\\ttype: 'SOBJ'\\n\\t\\tcreator: 'FAST'.\\n! !\\n\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'sw 2/12/96'!\\natEnd\\n\\t\\\"Answer whether the receiver is at its end. \\\"\\n\\t^ self primAtEnd: fileID! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nbasicNext\\n\\t\\\"Answer the next byte from this file, or nil if at the end of the file.\\\"\\n\\n\\t| count |\\n\\tcount := self primRead: fileID into: buffer1 startingAt: 1 count: 1.\\n\\tcount = 1\\n\\t\\tifTrue: [^ buffer1 at: 1]\\n\\t\\tifFalse: [^ nil].\\n! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'stephaneducasse 2/4/2006 20:32'!\\ncompressFile\\n\\t\\\"Write a new file that has the data in me compressed in GZip format.\\\"\\n\\t| zipped buffer |\\n\\n\\tself readOnly; binary.\\n\\tzipped := self directory newFileNamed: (self name, FileDirectory dot, 'gz').\\n\\tzipped binary; setFileTypeToObject.\\n\\t\\t\\\"Type and Creator not to be text, so can be enclosed in an email\\\"\\n\\tzipped := GZipWriteStream on: zipped.\\n\\tbuffer := ByteArray new: 50000.\\n\\t'Compressing ', self fullName displayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0 to: self size\\n\\t\\tduring: [:bar |\\n\\t\\t\\t[self atEnd] whileFalse: [\\n\\t\\t\\t\\tbar value: self position.\\n\\t\\t\\t\\tzipped nextPutAll: (self nextInto: buffer)].\\n\\t\\t\\tzipped close.\\n\\t\\t\\tself close].\\n\\t^zipped! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nfindString: string\\n\\t\\\"Fast version of #upToAll: to find a String in a file starting from the beginning.\\n\\tReturns the position and also sets the position there.\\n\\tIf string is not found 0 is returned and position is unchanged.\\\"\\n\\n\\t| pos buffer count oldPos sz |\\n\\toldPos := self position.\\n\\tself reset.\\n\\tsz := self size.\\n\\tpos := 0.\\n\\tbuffer := String new: 2000.\\n\\t[ buffer := self nextInto: buffer.\\n\\t(count := buffer findString: string) > 0\\n\\t\\tifTrue: [\\\"Found the string part way into buffer\\\"\\n\\t\\t\\tself position: pos.\\n\\t\\t\\tself next: count - 1.\\n\\t\\t\\t^self position ].\\n\\tpos := ((pos + 2000 - string size) min: sz).\\n\\tself position: pos.\\n\\tpos = sz] whileFalse.\\n\\t\\\"Never found it, and hit end of file\\\"\\n\\tself position: oldPos.\\n\\t^0! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nfindStringFromEnd: string\\n\\t\\\"Fast version to find a String in a file starting from the end.\\n\\tReturns the position and also sets the position there.\\n\\tIf string is not found 0 is returned and position is unchanged.\\\"\\n\\n\\t| pos buffer count oldPos |\\n\\toldPos := self position.\\n\\tself setToEnd.\\n\\tpos := self position.\\n\\t[ pos := ((pos - 2000 + string size) max: 0). \\\"the [+ string size] allows for the case where the end of the search string is at the beginning of the current buffer\\\"\\n\\tself position: pos.\\n\\tbuffer := self next: 2000.\\n\\t(count := buffer findString: string) > 0\\n\\t\\tifTrue: [\\\"Found the string part way into buffer\\\"\\n\\t\\t\\tself position: pos.\\n\\t\\t\\tself next: count-1. \\\"use next instead of position:, so that CrLfFileStream can do its magic if it is being used\\\"\\n\\t\\t\\t^self position].\\n\\tpos = 0] whileFalse.\\n\\t\\\"Never found it, and hit beginning of file\\\"\\n\\tself position: oldPos.\\n\\t^0! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'ar 2/6/2001 17:59'!\\nflush\\n\\t\\\"Flush pending changes\\\"\\n\\t^self primFlush: fileID! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'mir 2/25/2000 12:37'!\\nnext\\n\\t\\\"Answer the next byte from this file, or nil if at the end of the file.\\\"\\n\\n\\t^ self basicNext! !\\n\\n!StandardFileStream methodsFor: 'read, write, position'!\\nnext: n\\n\\t\\\"Return a string with the next n characters of the filestream in it. 1/31/96 sw\\\"\\n\\t^ self nextInto: (buffer1 class new: n)! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nnext: n into: aString startingAt: startIndex\\n\\t\\\"Read n bytes into the given string.\\n\\tReturn aString or a partial copy if less than\\n\\tn elements have been read.\\\"\\n\\t| count |\\n\\tcount := self primRead: fileID into: aString\\n\\t\\t\\t\\tstartingAt: startIndex count: n.\\n\\tcount = n\\n\\t\\tifTrue:[^aString]\\n\\t\\tifFalse:[^aString copyFrom: 1 to: startIndex+count-1]! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'ar 1/2/2000 15:33'!\\nnext: anInteger putAll: aString startingAt: startIndex\\n\\t\\\"Store the next anInteger elements from the given collection.\\\"\\n\\trwmode ifFalse: [^ self error: 'Cannot write a read-only file'].\\n\\tself primWrite: fileID from: aString startingAt: startIndex count: anInteger.\\n\\t^aString! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'jm 9/21/1998 13:55'!\\nnextPut: char\\n\\t\\\"Write the given character to this file.\\\"\\n\\n\\trwmode ifFalse: [^ self error: 'Cannot write a read-only file'].\\n\\tbuffer1 at: 1 put: char.\\n\\tself primWrite: fileID from: buffer1 startingAt: 1 count: 1.\\n\\t^ char\\n! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'tk 2/5/2000 21:43'!\\nnextPutAll: aString\\n\\t\\\"Write all the characters of the given string to this file.\\\"\\n\\n\\trwmode ifFalse: [^ self error: 'Cannot write a read-only file'].\\n\\tself primWrite: fileID from: aString startingAt: 1 count: aString basicSize.\\n\\t^ aString\\n! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'tk 2/5/2000 21:58'!\\nnextWordsInto: aBitmap\\n\\t\\\"Note: The file primitives automatically adjust for word based objects.\\\"\\n\\n\\tself next: aBitmap basicSize into: aBitmap startingAt: 1.\\n\\taBitmap restoreEndianness.\\n\\t^ aBitmap! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'stephaneducasse 2/4/2006 20:32'!\\npadToEndWith: aChar\\n\\t\\\"On the Mac, files do not truncate. One can delete the old file and write a new one, but sometime deletion fails (file still open? file stale?). This is a sad compromise. Just let the file be the same length but pad it with a harmless character.\\\"\\n\\n\\t| pad |\\n\\tself atEnd ifTrue: [^ self].\\n\\tpad := self isBinary \\n\\t\\tifTrue: [aChar asCharacter asciiValue]\\t\\\"ok for char or number\\\"\\n\\t\\tifFalse: [aChar asCharacter].\\n\\tself nextPutAll: (buffer1 class new: ((self size - self position) min: 20000) \\n\\t\\t\\t\\t\\t\\t\\twithAll: pad).! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'stephaneducasse 2/4/2006 20:32'!\\npeek\\n\\t\\\"Answer what would be returned if the message next were sent to the receiver. If the receiver is at the end, answer nil. \\\"\\n\\t| next |\\n\\tself atEnd ifTrue: [^ nil].\\n\\tnext := self basicNext.\\n\\tself position: self position - 1.\\n\\t^ next! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'tk 10/19/2001 11:29'!\\npeekLast\\n\\t\\\"Return that item just put at the end of the stream\\\"\\n\\n\\t^ buffer1 size > 0 \\n\\t\\tifTrue: [buffer1 last]\\n\\t\\tifFalse: [nil]\\n! !\\n\\n!StandardFileStream methodsFor: 'read, write, position'!\\nposition\\n\\t\\\"Return the receiver's current file position. 2/12/96 sw\\\"\\n\\n\\t^ self primGetPosition: fileID! !\\n\\n!StandardFileStream methodsFor: 'read, write, position'!\\nposition: pos\\n\\t\\\"Set the receiver's position as indicated. 2/12/96 sw\\\"\\n\\n\\t^ self primSetPosition: fileID to: pos! !\\n\\n!StandardFileStream methodsFor: 'read, write, position'!\\nreadInto: byteArray startingAt: startIndex count: count\\n\\t\\\"Read into the given array as specified, and return the count\\n\\tactually transferred. index and count are in units of bytes or\\n\\tlongs depending on whether the array is Bitmap, String or ByteArray\\\"\\n\\t^ self primRead: fileID into: byteArray\\n\\t\\t\\tstartingAt: startIndex count: count\\n! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'yo 10/31/2002 22:33'!\\nreadOnlyCopy\\n\\n\\t^ self class readOnlyFileNamed: self name.\\n! !\\n\\n!StandardFileStream methodsFor: 'read, write, position'!\\nsetToEnd\\n\\t\\\"Set the position of the receiver to the end of file. 1/31/96 sw\\\"\\n\\n\\tself position: self size! !\\n\\n!StandardFileStream methodsFor: 'read, write, position'!\\nskip: n\\n\\t\\\"Set the character position to n characters from the current position.\\n\\tError if not enough characters left in the file. 1/31/96 sw\\\"\\n\\n\\tself position: self position + n! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'JMM 5/24/2001 22:00'!\\ntruncate\\n\\t\\\"Truncate to zero\\\"\\n\\n\\t^ self truncate: 0! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'JMM 5/24/2001 22:47'!\\ntruncate: pos\\n\\t\\\"Truncate to this position\\\"\\n\\n\\tself position: pos.\\n\\t^self primTruncate: fileID to: pos! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nupTo: delim \\n\\t\\\"Fast version to speed up nextChunk\\\"\\n\\t| pos buffer count |\\n\\tpos := self position.\\n\\tbuffer := self next: 2000.\\n\\t(count := buffer indexOf: delim) > 0 ifTrue: \\n\\t\\t[\\\"Found the delimiter part way into buffer\\\"\\n\\t\\tself position: pos + count.\\n\\t\\t^ buffer copyFrom: 1 to: count - 1].\\n\\tself atEnd ifTrue:\\n\\t\\t[\\\"Never found it, and hit end of file\\\"\\n\\t\\t^ buffer].\\n\\t\\\"Never found it, but there's more...\\\"\\n\\t^ buffer , (self upTo: delim)! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nupToEnd\\n\\t\\\"Answer a subcollection from the current access position through the last element of the receiver.\\\"\\n\\n\\t| newStream buffer |\\n\\tbuffer := buffer1 species new: 1000.\\n\\tnewStream := WriteStream on: (buffer1 species new: 100).\\n\\t[self atEnd] whileFalse: [newStream nextPutAll: (self nextInto: buffer)].\\n\\t^ newStream contents! !\\n\\n!StandardFileStream methodsFor: 'read, write, position' stamp: 'jm 9/21/1998 13:56'!\\nverbatim: aString\\n\\t\\\"A version of nextPutAll that can be called knowing it won't call nextPut: \\\"\\n\\n\\t^ self nextPutAll: aString\\n! !\\n\\n\\n!StandardFileStream methodsFor: 'registry' stamp: 'ar 3/21/98 17:23'!\\nregister\\n\\t^self class register: self! !\\n\\n!StandardFileStream methodsFor: 'registry' stamp: 'ar 3/21/98 17:23'!\\nunregister\\n\\t^self class unregister: self! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStandardFileStream class\\n\\tinstanceVariableNames: ''!\\n\\n!StandardFileStream class methodsFor: 'browser requests' stamp: 'mir 3/8/2001 16:28'!\\nisRunningAsBrowserPlugin\\n\\tself new waitBrowserReadyFor: 1000 ifFail: [^false].\\n\\t^true! !\\n\\n!StandardFileStream class methodsFor: 'browser requests' stamp: 'mir 9/7/2000 16:08'!\\nprivateCheckForBrowserPrimitives\\n\\t<primitive:'primitivePluginBrowserReady'>\\n\\t^false! !\\n\\n\\n!StandardFileStream class methodsFor: 'error handling' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nfileDoesNotExistUserHandling: fullFileName\\n\\n\\t| selection newName |\\n\\tselection := (PopUpMenu labels:\\n'create a new file\\nchoose another name\\ncancel')\\n\\t\\t\\tstartUpWithCaption: (FileDirectory localNameFor: fullFileName) , '\\ndoes not exist.'.\\n\\tselection = 1 ifTrue:\\n\\t\\t[^ self new open: fullFileName forWrite: true].\\n\\tselection = 2 ifTrue:\\n\\t\\t[ newName := FillInTheBlank request: 'Enter a new file name'\\n\\t\\t\\t\\t\\t\\tinitialAnswer: fullFileName.\\n\\t\\t^ self oldFileNamed:\\n\\t\\t\\t(self fullName: newName)].\\n\\tself halt! !\\n\\n!StandardFileStream class methodsFor: 'error handling' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nfileExistsUserHandling: fullFileName\\n\\t| dir localName choice newName newFullFileName |\\n\\tdir := FileDirectory forFileName: fullFileName.\\n\\tlocalName := FileDirectory localNameFor: fullFileName.\\n\\tchoice := (PopUpMenu\\n\\t\\tlabels:\\n'overwrite that file\\\\choose another name\\\\cancel' withCRs)\\n\\t\\tstartUpWithCaption: localName, '\\nalready exists.'.\\n\\n\\tchoice = 1 ifTrue: [\\n\\t\\tdir deleteFileNamed: localName\\n\\t\\t\\tifAbsent: [self error: 'Could not delete the old version of that file'].\\n\\t\\t^ self new open: fullFileName forWrite: true].\\n\\n\\tchoice = 2 ifTrue: [\\n\\t\\tnewName := FillInTheBlank request: 'Enter a new file name' initialAnswer: fullFileName.\\n\\t\\tnewFullFileName := self fullName: newName.\\n\\t\\t^ self newFileNamed: newFullFileName].\\n\\n\\tself error: 'Please close this to abort file opening'! !\\n\\n!StandardFileStream class methodsFor: 'error handling' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nreadOnlyFileDoesNotExistUserHandling: fullFileName\\n\\n\\t| dir files choices selection newName fileName |\\n\\tdir := FileDirectory forFileName: fullFileName.\\n\\tfiles := dir fileNames.\\n\\tfileName := FileDirectory localNameFor: fullFileName.\\n\\tchoices := fileName correctAgainst: files.\\n\\tchoices add: 'Choose another name'.\\n\\tchoices add: 'Cancel'.\\n\\tselection := (PopUpMenu labelArray: choices lines: (Array with: 5) )\\n\\t\\tstartUpWithCaption: (FileDirectory localNameFor: fullFileName), '\\ndoes not exist.'.\\n\\tselection = choices size ifTrue:[\\\"cancel\\\" ^ nil \\\"should we raise another exception here?\\\"].\\n\\tselection < (choices size - 1) ifTrue: [\\n\\t\\tnewName := (dir pathName , FileDirectory slash , (choices at: selection))].\\n\\tselection = (choices size - 1) ifTrue: [\\n\\t\\tnewName := FillInTheBlank \\n\\t\\t\\t\\t\\t\\t\\trequest: 'Enter a new file name' \\n\\t\\t\\t\\t\\t\\t\\tinitialAnswer: fileName].\\n\\tnewName = '' ifFalse: [^ self readOnlyFileNamed: (self fullName: newName)].\\n\\t^ self error: 'Could not open a file'! !\\n\\n\\n!StandardFileStream class methodsFor: 'file creation' stamp: 'TPR 8/13/1999 21:22'!\\nfileNamed: fileName\\n\\t\\\"Open a file with the given name for reading and writing. If the name has no directory part, then the file will be created in the default directory. If the file already exists, its prior contents may be modified or replaced, but the file will not be truncated on close.\\\"\\n\\n\\t^ self new open: (self fullName: fileName) forWrite: true\\n! !\\n\\n!StandardFileStream class methodsFor: 'file creation' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nforceNewFileNamed: fileName \\n\\t\\\"Create a new file with the given name, and answer a stream opened \\n\\tfor writing on that file. If the file already exists, delete it without \\n\\tasking before creating the new file.\\\"\\n\\t| dir localName fullName f |\\n\\tfullName := self fullName: fileName.\\n\\t(self isAFileNamed: fullName)\\n\\t\\tifFalse: [f := self new open: fullName forWrite: true.\\n\\t\\t\\t^ f isNil\\n\\t\\t\\t\\tifTrue: [\\\"Failed to open the file\\\"\\n\\t\\t\\t\\t\\t(FileDoesNotExistException fileName: fullName) signal]\\n\\t\\t\\t\\tifFalse: [f]].\\n\\tdir := FileDirectory forFileName: fullName.\\n\\tlocalName := FileDirectory localNameFor: fullName.\\n\\tdir\\n\\t\\tdeleteFileNamed: localName\\n\\t\\tifAbsent: [(CannotDeleteFileException new\\n\\t\\t\\tmessageText: 'Could not delete the old version of file ' , fullName) signal].\\n\\tf := self new open: fullName forWrite: true.\\n\\t^ f isNil\\n\\t\\tifTrue: [\\\"Failed to open the file\\\"\\n\\t\\t\\t(FileDoesNotExistException fileName: fullName) signal]\\n\\t\\tifFalse: [f]! !\\n\\n!StandardFileStream class methodsFor: 'file creation' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nisAFileNamed: fileName\\n\\t\\\"Answer true if a file of the given name exists.\\\"\\n\\n\\t| f |\\n\\tf := self new open: fileName forWrite: false.\\n\\tf ifNil: [^ false].\\n\\tf close.\\n\\t^ true\\n! !\\n\\n!StandardFileStream class methodsFor: 'file creation' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nnewFileNamed: fileName\\n \\t\\\"Create a new file with the given name, and answer a stream opened for writing on that file. If the file already exists, ask the user what to do.\\\"\\n\\n\\t| fullName |\\n\\tfullName := self fullName: fileName.\\n\\n\\t^(self isAFileNamed: fullName)\\n\\t\\tifTrue: [\\\"file already exists:\\\"\\n\\t\\t\\t(FileExistsException fileName: fullName fileClass: self) signal]\\n\\t\\tifFalse: [self new open: fullName forWrite: true]\\n\\n! !\\n\\n!StandardFileStream class methodsFor: 'file creation' stamp: 'stephaneducasse 2/4/2006 20:32'!\\noldFileNamed: fileName\\n\\t\\\"Open an existing file with the given name for reading and writing. If the name has no directory part, then the file will be created in the default directory. If the file already exists, its prior contents may be modified or replaced, but the file will not be truncated on close.\\\"\\n\\n\\t| fullName |\\n\\tfullName := self fullName: fileName.\\n\\n\\t^(self isAFileNamed: fullName)\\n\\t\\tifTrue: [self new open: fullName forWrite: true]\\n\\t\\tifFalse: [\\\"File does not exist...\\\"\\n\\t\\t\\t(FileDoesNotExistException fileName: fullName) signal]! !\\n\\n!StandardFileStream class methodsFor: 'file creation' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nreadOnlyFileNamed: fileName \\n\\t\\\"Open an existing file with the given name for reading.\\\"\\n\\n\\t| fullName f |\\n\\tfullName := self fullName: fileName.\\n\\tf := self new open: fullName forWrite: false.\\n\\t^ f isNil\\n\\t\\tifFalse: [f]\\n\\t\\tifTrue: [\\\"File does not exist...\\\"\\n\\t\\t\\t((FileDoesNotExistException fileName: fullName) readOnly: true) signal].\\n\\n\\t\\\"StandardFileStream readOnlyFileNamed: 'kjsd.txt' \\\"! !\\n\\n\\n!StandardFileStream class methodsFor: 'registry' stamp: 'ar 10/7/1998 14:41'!\\nregister: anObject\\n\\tWeakArray isFinalizationSupported ifFalse:[^anObject].\\n\\tself registry add: anObject! !\\n\\n!StandardFileStream class methodsFor: 'registry' stamp: 'ar 10/7/1998 14:41'!\\nregistry\\n\\tWeakArray isFinalizationSupported ifFalse:[^nil].\\n\\t^Registry isNil\\n\\t\\tifTrue:[Registry := WeakRegistry new]\\n\\t\\tifFalse:[Registry].! !\\n\\n!StandardFileStream class methodsFor: 'registry' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nretryWithGC: execBlock until: testBlock forFileNamed: fullName\\n\\t\\\"Re-implemented to only force GC if a file with the given name exists\\\"\\n\\t| blockValue foundIt |\\n\\tblockValue := execBlock value.\\n\\t(testBlock value: blockValue) ifTrue:[^blockValue].\\n\\t\\\"See if we have a file with the given name\\\"\\n\\tfoundIt := Registry keys \\\"hold on strongly for now\\\" \\n\\t\\tanySatisfy:[:file| file name sameAs: fullName].\\n\\tfoundIt ifFalse:[^blockValue].\\n\\tSmalltalk garbageCollectMost.\\n\\tblockValue := execBlock value.\\n\\t(testBlock value: blockValue) ifTrue:[^blockValue].\\n\\tSmalltalk garbageCollect.\\n\\t^execBlock value.! !\\n\\n!StandardFileStream class methodsFor: 'registry' stamp: 'ar 10/7/1998 15:23'!\\nunregister: anObject\\n\\tWeakArray isFinalizationSupported ifFalse:[^anObject].\\n\\tself registry remove: anObject ifAbsent:[]! !\\nObject subclass: #StandardScriptingSystem\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'ClassVarNamesInUse FormDictionary HelpStrings StandardPartsBin'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Refactoring Candidates'!\\n!StandardScriptingSystem commentStamp: '<historical>' prior: 0!\\nAn instance of this is installed as the value of the global variable \\\"ScriptingSystem\\\". Client subclasses are invited, such as one used internally by squeak team for ongoing internal work.!\\n\\n\\n!StandardScriptingSystem methodsFor: 'form dictionary' stamp: 'ar 3/3/2001 19:45'!\\ndeletePrivateGraphics\\n\\t\\\"ScriptingSystem deletePrivateGraphics\\\"\\n\\tself deletePrivateGraphics: self privateGraphics\\n\\t\\tafterStoringToFileNamed: 'disGraphics'! !\\n\\n!StandardScriptingSystem methodsFor: 'form dictionary' stamp: 'di 2/3/2001 20:10'!\\ndeletePrivateGraphics: nameList afterStoringToFileNamed: aFileName\\n\\t\\\"This method is used to strip private graphics from the FormDictionary and store them on a file of the given name\\\"\\n\\n\\t| replacement toRemove aReferenceStream keySymbol |\\n\\ttoRemove _ Dictionary new.\\n\\treplacement _ FormDictionary at: #Gets.\\n\\n\\tnameList do:\\n\\t\\t[:aKey |\\n\\t\\t\\tkeySymbol _ aKey asSymbol.\\n\\t\\t\\t(toRemove at: keySymbol put: (self formAtKey: keySymbol)).\\n\\t\\t\\tFormDictionary at: keySymbol put: replacement].\\n\\n\\taReferenceStream _ ReferenceStream fileNamed: aFileName.\\n\\taReferenceStream nextPut: toRemove.\\n\\taReferenceStream close! !\\n\\n!StandardScriptingSystem methodsFor: 'form dictionary' stamp: 'sw 2/24/2003 16:28'!\\nformAtKey: aString\\n\\t\\\"Answer the form saved under the given key\\\"\\n\\n\\tSymbol hasInterned: aString ifTrue:\\n\\t\\t[:aKey | ^ FormDictionary at: aKey ifAbsent: [nil]].\\n\\t^ nil! !\\n\\n!StandardScriptingSystem methodsFor: 'form dictionary' stamp: 'ar 3/3/2001 19:46'!\\nformAtKey: aKey extent: extent depth: depth\\n\\t\\\"ScriptingSystem saveForm: (TileMorph downPicture) atKey: 'downArrow'\\\"\\n\\t^ FormDictionary at: aKey asSymbol ifAbsent: [Form extent: extent depth: depth]! !\\n\\n!StandardScriptingSystem methodsFor: 'form dictionary' stamp: 'ar 3/3/2001 19:49'!\\nformDictionary\\n\\t^FormDictionary! !\\n\\n!StandardScriptingSystem methodsFor: 'form dictionary' stamp: 'sd 5/11/2003 21:32'!\\ninspectFormDictionary\\n\\t\\\"ScriptingSystem inspectFormDictionary\\\"\\n\\t\\n\\tGraphicalDictionaryMenu openOn: FormDictionary withLabel: 'Testing One Two Three'! !\\n\\n!StandardScriptingSystem methodsFor: 'form dictionary' stamp: 'ar 3/3/2001 19:44'!\\nprivateGraphics\\n\\t\\\"ScriptingSystem deletePrivateGraphics\\\"\\n\\t^#(#BadgeMiniPic #BadgePic #Broom #CedarPic #CollagePic #CoverMain #CoverSpiral #CoverTexture #Fred #ImagiPic #KayaPic #StudioPic)! !\\n\\n!StandardScriptingSystem methodsFor: 'form dictionary' stamp: 'sw 10/6/1999 20:57'!\\nsaveForm: aForm atKey: aKey\\n\\tFormDictionary at: aKey asSymbol put: aForm! !\\n\\n!StandardScriptingSystem methodsFor: 'form dictionary' stamp: 'sw 10/24/1998 14:12'!\\nsqueakyMouseForm\\n\\t^ self formAtKey: 'squeakyMouse'\\n\\n\\\"\\n\\tScriptingSystem saveForm: (Form\\n\\textent: 30@29\\n\\tdepth: 16\\n\\tfromArray: #( 1811114995 1878286257 2012637171 1811180532 1811180533 1811179508 1811180532 1811179508 1744006133 1878289396 1811180533 1878289396 1744007156 1674736630 1744006132 1811114995 1811181556 1744006131 1811246068 1811180532 1811179508 1811180532 1744071668 1811113972 1811180532 1811180532 1811179507 1878288338 1945529332 1744071668 1743941620 1811112945 1811179506 1811114995 1744006131 1744006130 1744005106 1811048434 1811113969 1743939570 1811179506 1743939571 1676833782 1676765171 1811047410 1744006131 1811048435 1811116020 1811180531 1743939571 1811048435 1743939570 1743939570 1743939570 1743940594 1744005106 1811181556 1811180532 1676766196 1743939570 1878420468 1676963830 1189896082 1811245044 1744137204 1744070644 1811179508 1811113971 1743939571 1811179508 1811246070 1811309524 1811302093 1811310580 1811246068 1674867703 1744049472 1120606594 1118465013 1744137205 1811179508 1811180532 1744071667 1744006132 1811112947 1811247095 1605584589 358761132 289435638 1676830707 1741975543 1462778473 1811312631 702891724 1811310548 1945528308 1811178450 1945528307 1878288372 1878353875 1878421494 1051471335 1809213397 1118524175 1811246068 1945659348 1185698607 1878486005 1672694510 1118531574 1607626741 1878420467 1811180533 1743942645 1744072693 1811301035 1185770487 1878486006 1324239597 1811180533 1811116019 1120623438 1878352818 1945462739 704868339 1878289395 1811049459 1878221808 1878223859 1743876083 1811162563 1945463796 1811181556 1464746666 1811116018 1809019893 1120551562 1945464821 1741844468 1466842760 1878289395 1811048434 1811050483 1811050483 1878223859 1049188174 1741910004 1811181556 1256998634 1811114994 1878289396 1466840647 1744007156 1744006131 1676877216 1743940596 1878222835 1743938545 1878351792 1676833781 358641652 1743940596 1811050484 845566798 1811113970 1811114995 1811163652 1811112913 1878420468 1878282028 1811179506 1607560178 1878289395 1676900342 1878351825 1466853330 1811113971 1811116019 635659217 1811179506 1811245045 1676942754 1744137206 1744201717 1676962806 1676962805 1811310581 1676896245 1744199635 1811376117 1744072695 1744005109 1811244019 499279861 1811310581 1811244020 1811293668 1399943159 1605528567 1744136181 982063522 986342388 1744070645 1744189066 430063308 1744071669 1744070644 1744067504 566519797 1744136181 1744137205 1743999854 912813044 1811311606 1742162607 4195488 283139922 1945531382 1253113857 144710948 1601400791 1811246069 1811167879 1464821747 1744136180 1674799094 1811178482 843473875 1811311606 1878533542 2106790 2080066222 1876193270 696845376 627472380 1185772536 1878355957 1743990309 1744007157 1676898294 1744006132 1811114996 1743941620 1811180533 1809204941 4194368 4217681 1878290421 1252982848 4194336 1670540278 1739811795 1878353906 1744006131 1811179506 1744007157 1744005106 1945462771 1811182582 1811311574 1393641133 1462856629 2012638196 1876382449 1112301394 1742041045 1945596917 1676833781 1811113970 1811179507 1811180532 1672705014 1674735606 1672697648 1945725943 1878551479 1809215479 1811312629 1809216504 1809215479 1809215478 1462853490 1878487029 1744007158 1744005075 1811239726 704979363 495004132 700789287 562372997 631646663 1739998892 4194400 1116497846 698688932 562375109 770124262 633609569 495070758 1257010166 562315916 1809279958 2012894002 1047280171 980237901 910966381 1668677696 4194400 6314867 1047281260 908804749 910968495 1393719290 1809279959 1185750370 1809214455 1878469062 423836236 1532188466 1601592148 1462986647 1672937568 4194368 6319062 1603622706 1601525554 1601522417 1047336194 770206679 1878487031 1878409899 977955830 1809145716 1118586509 980105834 980045584 1811372914 980104778 1605526483 1395605131 910769804 1118651052 1534358520 1809136234 1118596053 1532059506 1878485973 1326456163 1945660374 1742106615 1811311607 1945725942 1742107641 1744072693 1811311605 1744203767 1878551543 564478604 1878553591 1603428242 1811048433 1811049459 1051290611 1744006131 1811049459 1878156273 1743874034 1744007156 1743874033 1811048434 1811113970 1743939571 1743933228 1603301363 1743875059 1811049458 1945461745 1811181556 1811113971 1811049458 1811048434 1811116020 1878287346 1878223857 1743940594 1744006130 1744007157 1945395153 1945400309 1811048434 1743810547 1676765170 1878353906 1811113970 1743874032 1810983921 1743874033 1811113971 1676765169 1743874034 1743940593 1743939569 1811047409 1676765168 1743940595 1810981872 1945397235 1607560179 1743941620 1810982897 1810983921 1811048433 1744007155 1743875059 1811048434 1743875058 1743939568 1676832754 1811116019 1811114994 1811244019 1676962805 1677029367 1811244020 1744005106 1743940594 1811246068 1744070645 1676961781 1744004084 1676897269 1811180533 1878353908 1744004083 1744070645)\\n\\toffset: 0@0) atKey: 'squeakyMouse'\\\"! !\\n\\n\\n!StandardScriptingSystem methodsFor: 'help dictionary' stamp: 'dgd 9/1/2003 14:25'!\\nhelpStringOrNilFor: aSymbol \\n\\t\\\"If my HelpStrings dictionary has an entry at the given symbol, \\n\\tanswer that entry's value, else answer nil\\\"\\n\\tHelpStrings\\n\\t\\tat: aSymbol\\n\\t\\tifPresent:[:string | ^ string translated].\\n^ nil! !\\n\\n!StandardScriptingSystem methodsFor: 'help dictionary' stamp: 'sw 6/15/1999 17:03'!\\ninitializeHelpStrings\\n\\t\\\"Initialize the data structure that determines, for the etoy system, help messages for various scripting elements. The structure is built up by letting every Morph subclass contribute elements simply by implementing method #helpContributions. Consult implementors of #helpContributions for examples of how this goes.\\\"\\n\\n\\t\\\"ScriptingSystem initializeHelpStrings\\\"\\n\\n\\t| aDictionary |\\n\\taDictionary _ IdentityDictionary new. \\n\\t\\\"For safety, the new copy is built up in this temp first, so that if an error occurs during the creation of the structure, the old version will remain remain in place\\\"\\n\\n\\tMorph withAllSubclasses do:\\n\\t\\t[:aClass | (aClass class selectors includes: #helpContributions)\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[aClass helpContributions do:\\n\\t\\t\\t\\t\\t[:pair | aDictionary at: pair first put: pair second]]].\\n\\n\\t\\tHelpStrings _ aDictionary! !\\n\\n\\n!StandardScriptingSystem methodsFor: 'utilities' stamp: 'sw 10/30/2000 16:33'!\\nallClassVarNamesInSystem\\n\\t\\\"Compute and answer a set of all the class variable names known to the sytem from any class\\\"\\n\\n\\t| aList |\\n\\taList _ OrderedCollection new.\\n\\tObject withAllSubclasses do:\\n\\t\\t[:c | aList addAll: c allClassVarNames].\\n\\t^ aList asSet\\n\\n\\t\\\"ScriptingSystem allClassVarNamesInSystem\\\"\\n! !\\n\\n!StandardScriptingSystem methodsFor: 'utilities' stamp: 'sw 6/16/2005 01:35'!\\ncustomizeForEToyUsers: aBoolean\\n\\t\\\"If aBoolean is true, set things up for etoy users. If it's false, unset some of those things. Some things are set when switching into etoy mode but not reversed when switching out of etoy mode.\\\"\\n \\n\\t#(\\t\\n\\t\\t(allowEtoyUserCustomEvents\\tno\\t\\treverse)\\n\\t\\t(balloonHelpEnabled\\t\\t\\tyes\\t\\tdontReverse)\\n\\t\\t(debugHaloHandle\\t\\t\\tno\\t\\treverse)\\n\\t\\t(modalColorPickers\\t\\t\\tyes\\t\\tdontReverse)\\n\\t\\t(oliveHandleForScriptedObjects\\tno\\tdontReverse)\\n\\t\\t(uniqueNamesInHalos\\t\\tyes\\t\\treverse)\\n\\t\\t(useUndo\\t\\t\\t\\t\\tyes\\t\\tdontReverse)\\n\\t\\t(infiniteUndo\\t\\t\\t\\tno\\t\\tdontReverse)\\n\\t\\t(warnIfNoChangesFile\\t\\tno\\t\\treverse)\\n\\t\\t(warnIfNoSourcesFile\\t\\tno\\t\\treverse)) do:\\n\\t\\t\\t[:trip |\\n\\t\\t\\t\\t(aBoolean or: [trip third == #reverse]) ifTrue:\\n\\t\\t\\t\\t\\t[Preferences enableOrDisable: trip first asPer:\\n\\t\\t\\t\\t\\t\\t((trip second == #yes) & aBoolean) | ((trip second == #no) & aBoolean not)]]! !\\n\\n!StandardScriptingSystem methodsFor: 'utilities' stamp: 'sw 4/6/2005 09:30'!\\nsoundNamesToSuppress\\n\\t\\\"Answer a list of sound-names that are not to be offered in sound-choice pop-ups unless they are the current choice\\\"\\n\\n\\t^ #('scrape' 'scritch' 'peaks')! !\\n\\n!StandardScriptingSystem methodsFor: 'utilities' stamp: 'sw 11/26/1999 15:44'!\\nstripGraphicsForExternalRelease\\n\\t\\\"ScriptingSystem stripGraphicsForExternalRelease\\\"\\n\\n\\t| replacement |\\n\\treplacement _ FormDictionary at: #Gets.\\n\\n\\t#('BadgeMiniPic' 'BadgePic' 'Broom' 'CedarPic' 'CollagePic' 'CoverMain' 'CoverSpiral' 'CoverTexture' 'Fred' 'ImagiPic' 'KayaPic' 'StudioPic')\\n\\t\\tdo:\\n\\t\\t\\t[:aKey | FormDictionary at: aKey asSymbol put: replacement]! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 11/1/2004 07:47'!\\naddCustomEventFor: registrantClass named: aSymbol help: helpString targetMorphClass: targetClass\\n\\t| registration |\\n\\tregistration _ self customEventsRegistry at: aSymbol ifAbsentPut: [ IdentityDictionary new ].\\n\\tregistration at: registrantClass put: { helpString. targetClass }.\\n! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 9/26/2003 23:23'!\\naddUserCustomEventNamed: aSymbol help: helpString\\n\\tself currentWorld addUserCustomEventNamed: aSymbol help: helpString.\\n\\t\\\"Vocabulary addStandardVocabulary: UserCustomEventNameType new.\\\"\\n\\tVocabulary customEventsVocabulary.\\n\\tSymbolListTile updateAllTilesForVocabularyNamed: #CustomEvents! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 11/1/2004 08:19'!\\ncustomEventNamesAndHelpStringsFor: aPlayer\\n\\t| retval help helpStrings morph |\\n\\tmorph := aPlayer costume renderedMorph.\\n\\tretval := SortedCollection sortBlock: [ :a :b | a first < b first ].\\n\\tself customEventsRegistry\\n\\t\\tkeysAndValuesDo: [ :k :v |\\n\\t\\t\\thelpStrings := Array streamContents: [ :hsStream |\\n\\t\\t\\t\\tv keysAndValuesDo: [ :registrant :array |\\n\\t\\t\\t\\t\\t(morph isKindOf: array second) ifTrue: [\\n\\t\\t\\t\\t\\t\\thelp := String streamContents: [ :stream |\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tv size > 1\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [ stream nextPut: $(;\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tnextPutAll: array second name;\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tnextPut: $);\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tspace ].\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tstream nextPutAll: array first ].\\n\\t\\t\\t\\t\\t\\thsStream nextPut: help ]]].\\n\\t\\t\\thelpStrings isEmpty ifFalse: [retval add: { k. helpStrings } ]].\\n\\t^ retval! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 9/26/2003 23:31'!\\ncustomEventStati\\n\\t^self globalCustomEventNames,\\n\\tself userCustomEventNames! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 10/12/2003 13:14'!\\ncustomEventsRegistry\\n\\t^Smalltalk at: #CustomEventsRegistry ifAbsentPut: [ IdentityDictionary new ].! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 9/26/2003 23:30'!\\nglobalCustomEventNames\\n\\t^self customEventsRegistry keys asArray sort! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 11/1/2004 07:56'!\\nglobalCustomEventNamesFor: aPlayer\\n\\t| morph names |\\n\\tmorph := aPlayer costume renderedMorph.\\n\\tnames := SortedCollection new.\\n\\tself customEventsRegistry keysAndValuesDo: [ :k :v |\\n\\t\\t(v anySatisfy: [ :array | morph isKindOf: array second ])\\n\\t\\t\\tifTrue: [ names add: k ]].\\n\\t^names asArray! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 7/20/2003 12:37'!\\nremoveCustomEventNamed: aSymbol for: registrant\\n\\t| registration helpString |\\n\\tregistration _ self customEventsRegistry at: aSymbol ifAbsent: [ ^nil ].\\n\\thelpString _ registration removeKey: registrant ifAbsent: [].\\n\\tregistration isEmpty ifTrue: [ self customEventsRegistry removeKey: aSymbol ].\\n\\t^helpString! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 9/26/2003 23:26'!\\nremoveUserCustomEventNamed: eventName\\n\\t| retval |\\n\\tretval _ self currentWorld removeUserCustomEventNamed: eventName.\\n\\t\\\"Vocabulary addStandardVocabulary: UserCustomEventNameType new.\\\"\\n\\tVocabulary customEventsVocabulary.\\n\\tSymbolListTile updateAllTilesForVocabularyNamed: #CustomEvents.\\n\\t^retval! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 6/30/2004 18:16'!\\nstandardEventStati\\n\\t\\\"Answer the events that can be directed to a particular morph by its event handler.\\\"\\n\\t^ #(mouseDown\\t\\\"run when mouse goes down on me\\\"\\n\\t\\tmouseStillDown\\t\\\"while mouse still down\\\"\\n\\t\\tmouseUp\\t\\t\\\"when mouse comes back up\\\"\\n\\t\\tmouseEnter\\t\\\"when mouse enters my bounds, button up\\\"\\n\\t\\tmouseLeave\\t\\\"when mouse exits my bounds, button up\\\"\\n\\t\\tmouseEnterDragging\\t\\\"when mouse enters my bounds, button down\\\"\\n\\t\\tmouseLeaveDragging\\t\\\"when mouse exits my bounds, button down\\\"\\n\\t\\t\\\"keyStroke\\\"\\n\\t\\t\\\"gesture\\\"\\n\\t)\\n! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-custom events' stamp: 'nk 9/26/2003 23:22'!\\nuserCustomEventNames\\n\\t^ self currentWorld userCustomEventNames! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-customevents-help dictionary' stamp: 'nk 11/1/2004 08:21'!\\nstatusHelpStringFor: aPlayer\\n\\t^String streamContents: [ :stream |\\n\\t\\tstream nextPutAll: 'normal -- run when called\\npaused -- ready to run all the time\\nticking -- run all the time\\nmouseDown -- run when mouse goes down on me\\nmouseStillDown -- while mouse still down\\nmouseUp -- when mouse comes back up\\nmouseEnter -- when mouse enters my bounds, button up\\nmouseLeave -- when mouse exits my bounds, button up\\nmouseEnterDragging -- when mouse enters my bounds, button down\\nmouseLeaveDragging -- when mouse exits my bounds, button down\\nopening -- when I am being opened\\nclosing -- when I am being closed' translated.\\n\\n\\\"'keyStroke -- run when user hits a key' \\\"\\n\\n\\tstream cr; cr; nextPutAll: 'More events:' translated; cr.\\n\\n\\t(self customEventNamesAndHelpStringsFor: aPlayer) do: [ :array |\\n\\t\\tstream cr;\\n\\t\\tnextPutAll: array first;\\n\\t\\tnextPutAll: ' -- '.\\n\\t\\tarray second do: [ :help | stream nextPutAll: help translated ]\\n\\t\\t\\tseparatedBy: [ stream nextPutAll: ' or ' translated ]].\\n\\n\\t(Preferences allowEtoyUserCustomEvents) ifTrue: [\\n\\tself userCustomEventNames isEmpty ifFalse: [\\n\\t\\tstream cr; cr; nextPutAll: 'User custom events:' translated; cr.\\n\\t\\tself currentWorld userCustomEventsRegistry keysAndValuesDo: [ :key :value |\\n\\t\\t\\tstream cr; nextPutAll: key; nextPutAll: ' -- '; nextPutAll: value ]]]]! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-font & color choices' stamp: 'sw 5/2/1998 14:26'!\\ncolorBehindTiles\\n\\t^ Color r: 0.903 g: 1.0 b: 0.903! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-font & color choices' stamp: 'dgd 7/12/2003 12:06'!\\nfontForNameEditingInScriptor\\n\\t^ Preferences standardEToysFont! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-font & color choices' stamp: 'dgd 7/12/2003 12:05'!\\nfontForTiles\\n\\t^ Preferences standardEToysFont! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-font & color choices' stamp: 'nk 7/12/2003 08:59'!\\nsmallBoldFont\\n\\t\\\"Answer a small bold font for use in some standard scripting-support structures\\\"\\n\\n\\t^ StrikeFont familyName: Preferences standardEToysFont familyName size: 12! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-font & color choices' stamp: 'sw 9/14/1998 14:41'!\\nstatusColorSymbolFor: statusSymbol\\n\\t#(\\t(normal\\t\\t\\t\\t\\tgreen)\\n\\t\\t(ticking\\t\\t\\t\\t\\tblue)\\n\\t\\t(paused\\t\\t\\t\\t\\tred)\\n\\t\\t(mouseDown\\t\\t\\t\\tyellow)\\n\\t\\t(mouseStillDown\\t\\t\\tlightYellow)\\n\\t\\t(mouseUp\\t\\t\\t\\tlightBlue)\\n\\t\\t(mouseEnter\\t\\t\\t\\tlightBrown)\\n\\t\\t(mouseLeave\\t\\t\\tlightRed)\\n\\t\\t(mouseEnterDragging\\tlightGray)\\n\\t\\t(mouseLeaveDragging\\tdarkGray)\\n\\t\\t(keyStroke\\t\\t\\t\\tlightGreen)) do:\\n\\n\\t\\t\\t[:pair | statusSymbol == pair first ifTrue: [^ pair second]].\\n\\n\\t\\t^ #blue! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-font & color choices' stamp: 'sw 5/2/1998 14:23'!\\nuniformTileInteriorColor\\n\\t^ Color r: 0.806 g: 1.0 b: 0.806! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-form dictionary' stamp: 'sw 5/12/1999 10:09'!\\ninstallSolidMenuForm\\n\\t\\\"ScriptingSystem installSolidMenuForm\\\"\\n\\tself saveForm:\\n\\t\\t(Form extent: 14@16 depth: 16\\n\\tfromArray: #( 1 0 0 0 0 0 0 65537 65536 0 0 0 65537 0 65537 65537 65537 65537 65537 65537 65536 65537 65537 65537 65537 65537 1600061441 65536 65537 1600085855 1600085855 1600085855 1600085855 1600061441 65536 65537 1600085855 65537 65537 65537 65537 65536 65537 1600085855 65537 65537 65537 1600061441 65536 65537 1600085855 1600085855 1600085855 1600085855 1600085855 65537 65537 1600085855 65537 65537 65537 1600085855 65537 65537 1600085855 1600061441 65537 65537 89951 65537 65537 1600085855 1600085855 1600085855 1600085855 1600085855 65537 65537 1600085855 1600061441 65537 65537 65537 65537 65537 1600085855 65537 65537 65537 65536 65537 65537 65537 65537 65537 65537 65537 65537 1 65537 65537 65537 65537 65537 65536 0 65536 0 0 0 0 0) offset: 0@0)\\n\\t\\tatKey: 'SolidMenu'! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-form dictionary' stamp: 'sw 11/26/1999 15:37'!\\nmergeGraphicsFrom: aDictionary\\n\\t\\\"aDictionary is assumed to hold associations of the form <formName> -> <form>. Merge the graphics held by that dictionary into the internal FormDictionary, overlaying any existing entries with the ones found in aDictionary\\\"\\n\\n\\taDictionary associationsDo:\\n\\t\\t[:assoc | self saveForm: assoc value atKey: assoc key]\\n\\n\\t\\t\\\"works ok even if keys in aDictionary are strings rather than symbols\\\"! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-form dictionary' stamp: 'sw 2/20/2002 01:09'!\\npatchInNewStandardPlayerForm\\n\\t\\\"Patch in a darker and larger representation of a Dot. No senders -- called from the postscript of an update\\\"\\n\\n\\t\\\"ScriptingSystem patchInNewStandardPlayerForm\\\"\\n\\n\\tFormDictionary at: #standardPlayer put:\\n\\t\\t(Form\\n\\textent: 13@13\\n\\tdepth: 16\\n\\tfromArray: #( 0 0 0 65536 0 0 0 0 0 65537 65537 65536 0 0 0 65537 65537 65537 65537 65536 0 0 65537 65537 65537 65537 65536 0 1 65537 65537 65537 65537 65537 0 1 65537 65537 65537 65537 65537 0 65537 65537 65537 65537 65537 65537 65536 1 65537 65537 65537 65537 65537 0 1 65537 65537 65537 65537 65537 0 0 65537 65537 65537 65537 65536 0 0 65537 65537 65537 65537 65536 0 0 0 65537 65537 65536 0 0 0 0 0 65536 0 0 0)\\n\\toffset: 0@0)! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-form dictionary' stamp: 'sw 5/2/1998 14:01'!\\nreadFormsFromFileNamed: aFileName\\n\\t\\\"Read the entire FormDictionary in from a designated file on disk\\\"\\n\\n\\t| aReferenceStream |\\n\\taReferenceStream _ ReferenceStream fileNamed: aFileName.\\n\\tFormDictionary _ aReferenceStream next.\\n\\taReferenceStream close\\n\\n\\t\\\"ScriptingSystem readFormsFromFileNamed: 'EToyForms22Apr'\\\"! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-form dictionary' stamp: 'sw 9/14/2000 21:29'!\\nreadFormsFromFileNamed: aFileName andStoreIntoGlobal: globalName\\n\\t\\\"Read the a FormDictionary in from a designated file on disk and save it in the designated global\\\"\\n\\n\\t| aReferenceStream |\\n\\taReferenceStream _ ReferenceStream fileNamed: aFileName.\\n\\tSmalltalk at: globalName put: aReferenceStream next.\\n\\taReferenceStream close\\n\\n\\t\\\"ScriptingSystem readFormsFromFileNamed: 'SystemFormsFromFwdF.forms' andStoreIntoGlobal: #FormsTemp\\\"\\n\\n\\t\\\"ScriptingSystem saveForm: (FormsTemp at: #StackElementDesignationHelp) atKey: #StackElementDesignationHelp\\\"! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-form dictionary' stamp: 'sw 4/23/1999 11:24'!\\nrestorePrivateGraphics\\n\\t\\\"ScriptingSystem restorePrivateGraphics\\\"\\n\\t| aReferenceStream |\\n\\taReferenceStream _ ReferenceStream fileNamed: 'disGraphics'.\\n\\tself mergeGraphicsFrom: aReferenceStream next.\\n\\taReferenceStream close.\\n! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-form dictionary' stamp: 'sw 5/6/1998 17:46'!\\nsaveFormsToFileNamed: aFileName\\n\\t\\\"Save the current state of form dictionary to disk for possible later retrieval\\\"\\n \\t (ReferenceStream fileNamed: aFileName) nextPut: FormDictionary; close\\n\\n\\t\\\"ScriptingSystem saveFormsToFileNamed: 'SystemForms06May98.forms'\\\"! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-form dictionary' stamp: 'sw 12/7/1998 16:47'!\\nstandardForms\\n\\t\\\"ScriptingSystem standardForms\\\"\\n\\t^ FormDictionary collect: [:f | f]! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-parts bin' stamp: 'tk 10/20/2004 15:52'!\\nanyButtonPressedTiles\\n\\t\\\"Answer tiles representing the query 'is any button pressed?'\\\"\\n\\n\\t^ self tilesForQuery: '(ActiveHand anyButtonPressed)' label: 'button down?' translated! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-parts bin' stamp: 'sw 11/16/2004 13:56'!\\nnoButtonPressedTiles\\n\\t\\\"Answer tiles representing the query 'is no button pressed?'\\\"\\n\\n\\t^ self tilesForQuery: '(ActiveHand noButtonPressed)' label: 'button up?' translated! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-parts bin' stamp: 'sw 5/3/1999 22:40'!\\nprototypicalHolder\\n\\t| aHolder |\\n\\taHolder _ PasteUpMorph authoringPrototype color: Color orange muchLighter; borderColor: Color orange lighter.\\n\\taHolder setNameTo: 'holder'; extent: 160 @ 110.\\n\\t^ aHolder behaveLikeHolder.\\n! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-parts bin' stamp: 'sw 10/27/1998 13:35'!\\nresetStandardPartsBin\\n\\t\\\"ScriptingSystem resetStandardPartsBin\\\"\\n\\n\\tStandardPartsBin _ nil! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-parts bin' stamp: 'sw 7/3/2001 08:01'!\\ntilesForQuery: expressionString label: aLabel\\n\\t\\\"Answer scripting tiles that represent the query,\\\"\\n\\n\\t| aPhrase aTile |\\n\\taPhrase _ SystemQueryPhrase new.\\n\\taTile _ BooleanTile new.\\n\\taTile setExpression: expressionString label: aLabel.\\n\\taPhrase addMorph: aTile.\\n\\t^ aPhrase\\n! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-script-control' stamp: 'dgd 9/19/2003 14:40'!\\ngoButton\\n\\t| aButton |\\n\\taButton _ ThreePhaseButtonMorph new.\\n\\taButton image: (ScriptingSystem formAtKey: 'GoPicOn');\\n\\t\\t\\toffImage: (ScriptingSystem formAtKey: 'GoPic');\\n\\t\\t\\tpressedImage: (ScriptingSystem formAtKey: 'GoPicOn');\\n\\t\\t\\tactionSelector: #goUp:with:; \\n\\t\\t\\targuments: (Array with: nil with: aButton);\\n\\t\\t\\tactWhen: #buttonUp;\\n\\t\\t\\ttarget: self;\\n\\t\\t\\tsetNameTo: 'Go Button';\\n\\t\\t\\tsetBalloonText:\\n'Resume running all paused scripts' translated.\\n\\t^ aButton! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-script-control' stamp: 'sw 11/11/1998 15:24'!\\ngoUp: evt with: aGoButton\\n\\taGoButton presenter startRunningScriptsFrom: aGoButton! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-script-control' stamp: 'sw 1/23/2001 11:39'!\\nscriptControlButtons\\n\\t\\\"Answer a composite object that serves to control the stop/stop/go status of a Presenter\\\"\\n\\n\\t| wrapper |\\n\\twrapper _ AlignmentMorph newRow setNameTo: 'script controls'.\\n\\twrapper vResizing: #shrinkWrap.\\n\\twrapper hResizing: #shrinkWrap.\\n\\twrapper addMorph: self stopButton.\\n\\twrapper addMorphBack: self stepButton.\\n\\twrapper addMorphBack: self goButton.\\n\\twrapper beTransparent.\\n\\t^ wrapper! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-script-control' stamp: 'dgd 9/19/2003 14:41'!\\nstepButton\\n\\t| aButton |\\n\\tself flag: #deferred. \\\"ambiguity about recipients\\\"\\n\\taButton _ ThreePhaseButtonMorph new.\\n\\t\\taButton\\n\\t\\t\\timage: (ScriptingSystem formAtKey: 'StepPicOn');\\n\\t\\t\\toffImage: (ScriptingSystem formAtKey: 'StepPic');\\n\\t\\t\\tpressedImage: (ScriptingSystem formAtKey: 'StepPicOn');\\n\\t\\t\\targuments: (Array with: nil with: aButton);\\n\\t\\t \\tactionSelector: #stepStillDown:with:; \\n\\t\\t\\ttarget: self;\\n\\t\\t\\tsetNameTo: 'Step Button'; \\n\\t\\t\\tactWhen: #whilePressed;\\n\\t\\t\\ton: #mouseDown send: #stepDown:with: to: self;\\n\\t\\t\\ton: #mouseStillDown send: #stepStillDown:with: to: self;\\n\\t\\t\\ton: #mouseUp send: #stepUp:with: to: self;\\n\\t\\t\\tsetBalloonText:\\n'Run every paused script exactly once. Keep the mouse button down over \\\"Step\\\" and everything will keep running until you release it' translated.\\n\\t^ aButton! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-script-control' stamp: 'sw 10/30/1998 15:33'!\\nstepDown: evt with: aMorph\\n\\taMorph presenter stopRunningScripts! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-script-control' stamp: 'sw 10/30/1998 15:35'!\\nstepStillDown: dummy with: theButton\\n\\ttheButton presenter stepStillDown: dummy with: theButton! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-script-control' stamp: 'sw 10/30/1998 15:35'!\\nstepUp: evt with: aMorph\\n\\taMorph presenter stepUp: evt with: aMorph! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-script-control' stamp: 'dgd 9/19/2003 14:41'!\\nstopButton\\n\\t\\\"Answer a new button that can serve as a stop button\\\"\\n\\t| aButton |\\n\\taButton _ ThreePhaseButtonMorph new.\\n\\taButton\\n\\t\\timage: (ScriptingSystem formAtKey: 'StopPic');\\n\\t\\toffImage: (ScriptingSystem formAtKey: 'StopPic');\\n\\t\\tpressedImage: (ScriptingSystem formAtKey: 'StopPicOn').\\n\\t\\taButton actionSelector: #stopUp:with:; \\n\\t\\targuments: (Array with: nil with: aButton);\\n\\t\\tactWhen: #buttonUp;\\n\\t\\ttarget: self;\\n\\t\\tsetNameTo: 'Stop Button'; \\n\\t\\tsetBalloonText: 'Pause all ticking scripts.' translated.\\n\\t^ aButton! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-script-control' stamp: 'sw 11/11/1998 15:16'!\\nstopUp: dummy with: theButton\\n\\t| aPresenter |\\n\\t(aPresenter _ theButton presenter) flushPlayerListCache. \\\"catch guys not in cache but who're running\\\"\\n\\taPresenter stopRunningScriptsFrom: theButton! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-tile colors' stamp: 'sw 8/28/2004 15:19'!\\ncolorForType: typeSymbol\\n\\t\\\"Answer the color to use to represent the given type symbol\\\"\\n\\n\\ttrue ifTrue:\\n\\t\\t[^ self standardTileBorderColor].\\n\\n\\ttypeSymbol capitalized = #Command ifTrue:\\n\\t\\t[^ Color fromRgbTriplet: #(0.065 0.258 1.0)].\\n\\t\\\"Command is historical and idiosyncratic and should be regularized\\\"\\n\\n\\t^ (Vocabulary vocabularyForType: typeSymbol) typeColor! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-tile colors' stamp: 'sw 10/29/1998 16:18'!\\ncolorFudge\\n\\t^ 0.4! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-tile colors' stamp: 'sw 8/28/2004 20:31'!\\nstandardTileBorderColor\\n\\t\\\"Answer the color to use for tile borders\\\"\\n\\n\\t^ Color r: 0.804 g: 0.76 b: 0.564! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-universal slots & scripts' stamp: 'sw 1/4/2005 02:20'!\\nacceptableSlotNameFrom: originalString forSlotCurrentlyNamed: currentName asSlotNameIn: aPlayer world: aWorld\\n\\t\\\"Produce an acceptable slot name, derived from the current name, for aPlayer. This method will always return a valid slot name that will be suitable for use in the given situation, though you might not like its beauty sometimes.\\\"\\n\\n\\t| aString stemAndSuffix proscribed stem suffix putative |\\n\\taString _ originalString asIdentifier: false. \\\"get an identifier not lowercase\\\"\\n\\tstemAndSuffix _ aString stemAndNumericSuffix.\\n\\tproscribed _ #(self super thisContext costume costumes dependents #true #false size), aPlayer class allInstVarNames.\\n\\n\\tstem _ stemAndSuffix first.\\n\\tsuffix _ stemAndSuffix last.\\n\\tputative _ aString asSymbol.\\n\\t\\n\\t[(putative ~~ currentName) and: [(proscribed includes: putative)\\n\\t\\tor:\\t[(aPlayer respondsTo: putative)\\n\\t\\tor:\\t[Smalltalk includesKey: putative]]]]\\n\\twhileTrue:\\n\\t\\t[suffix _ suffix + 1.\\n\\t\\tputative _ (stem, suffix printString) asSymbol].\\n\\t^ putative! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-universal slots & scripts' stamp: 'kfr 9/23/2003 09:29'!\\ndoesOperatorWantArrows: aSymbol\\n\\taSymbol = #, ifTrue:[^ false].\\n\\t^ aSymbol isInfix or: [#(isDivisibleBy:) includes: aSymbol]! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-universal slots & scripts' stamp: 'sw 9/27/2001 04:08'!\\nsystemSlotNamesOfType: aType\\n\\t\\\"Answer the type of the slot name, or nil if not found.\\\"\\n\\t\\n\\t| aList |\\n\\tself flag: #deferred. \\\"Hard-coded etoyVocabulary needed here to make this work.\\\"\\n\\taList _ OrderedCollection new.\\n\\tVocabulary eToyVocabulary methodInterfacesDo:\\n\\t\\t [:anInterface |\\n\\t\\t\\tanInterface resultType = aType ifTrue:\\n\\t\\t\\t\\t[aList add: anInterface selector]].\\n\\t^ aList! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 10/30/2000 16:37'!\\nallKnownClassVariableNames\\n\\t\\\"Answer a set of all the knwon class variable names in the system. This normally retrieves them from a cache, and at present there is no organized mechanism for invalidating the cache. The idea is to avoid, in the References scheme, names that may create a conflict\\\"\\n\\n\\t^ ClassVarNamesInUse ifNil: [ClassVarNamesInUse _ self allClassVarNamesInSystem]\\n\\n\\t\\\"ClassVarNamesInUse _ nil.\\n\\tTime millisecondsToRun: [ScriptingSystem allKnownClassVariableNames]\\\"\\n! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'kfr 9/23/2003 09:44'!\\narithmeticalOperatorsAndHelpStrings\\n\\t\\\"Answer an array consisting of lists of the standard arithmetical operator tiles and of the corresponding balloon help for them\\\"\\n\\n\\t^ #((+ - * / // \\\\\\\\ max: min:)\\n\\t \\t('add' 'subtract' 'multiply' 'divide' 'divide & truncate' 'remainder when divided by' 'larger value' 'smaller value' ))! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'tk 10/20/2004 15:52'!\\nbuttonDownTile\\n\\t\\\"Answer a boolean-valued tile which reports whether the button is down\\\"\\n\\n\\t^ self systemQueryPhraseWithActionString: '(ActiveHand anyButtonPressed)' labelled: 'button down?' translated! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'tk 10/20/2004 15:52'!\\nbuttonUpTile\\n\\t\\\"Answer a boolean-valued tile which reports whether the button is up\\\"\\n\\n\\t^ self systemQueryPhraseWithActionString: '(ActiveHand noButtonPressed)' labelled: 'button up?' translated! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'tk 8/21/2000 12:59'!\\ncleanupsForRelease\\n\\t\\\"Miscellaneous space cleanups to do before a release.\\\"\\n\\t\\\"EToySystem cleanupsForRelease\\\"\\n\\n\\tSocket deadServer: ''. \\\"Don't reveal any specific server name\\\"\\n\\tHandMorph initialize. \\\"free cached ColorChart\\\"\\n\\tPaintBoxMorph initialize.\\t\\\"forces Prototype to let go of extra things it might hold\\\"\\n\\tSmalltalk removeKey: #AA ifAbsent: [].\\n\\tSmalltalk removeKey: #BB ifAbsent: [].\\n\\tSmalltalk removeKey: #CC ifAbsent: [].\\n\\tSmalltalk removeKey: #DD ifAbsent: [].\\n\\tSmalltalk removeKey: #Temp ifAbsent: [].\\n\\n\\tScriptingSystem reclaimSpace.\\n\\tSmalltalk cleanOutUndeclared.\\n\\tSmalltalk reclaimDependents.\\n\\tSmalltalk forgetDoIts.\\n\\tSmalltalk removeEmptyMessageCategories.\\n\\tSymbol rehash! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 3/10/2004 23:24'!\\nhelpStringForOperator: anOperator\\n\\t\\\"Answer the help string associated with the given operator. If none found, return a standard no-help-available reply\\\"\\n\\n\\t^ (self helpStringOrNilForOperator: anOperator) ifNil:\\n\\t\\t['Sorry, no help available here' translated] \\\"This should never be seen, but is provided as a backstop\\\"! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 6/27/2004 11:11'!\\nhelpStringOrNilForOperator: anOperator\\n\\t\\\"Answer the help string associated with the given operator, nil if none found.\\\"\\n\\n\\t| anIndex opsAndHelp |\\n\\t(anIndex _ (opsAndHelp _ self arithmeticalOperatorsAndHelpStrings) first indexOf: anOperator) > 0\\n\\t\\tifTrue:\\t[^ (opsAndHelp second at: anIndex) translated].\\n\\n\\t(anIndex _ (opsAndHelp _ self numericComparitorsAndHelpStrings) first indexOf: anOperator) > 0\\n\\t\\tifTrue:\\t[^ (opsAndHelp second at: anIndex) translated].\\n\\n\\tanOperator = #, ifTrue:\\n\\t\\t[^ 'Concatenate two Strings' translated].\\n\\n\\t^ nil! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'nk 7/12/2003 08:59'!\\nholderWithAlphabet\\n\\t\\\"Answer a fully instantiated Holder that has submorphs that represent the letters of the uppercase alphabet, with each one having an 'index' slot which bears the letter's index in the alphabet -- 1 for A, 2 for B, etc. A few special characters are provided as per ack request 10/00; for these the index provided is rather arbitrarily assigned\\\"\\n\\n\\t| aMorph aPlayer newMorph oneCharString aContainer aWrapper |\\n\\n\\t\\\"ScriptingSystem holderWithAlphabet openInHand\\\"\\n\\n\\taContainer _ self prototypicalHolder useRoundedCorners.\\n\\taContainer borderColor: Color blue lighter.\\n\\n\\taWrapper _ AlignmentMorph new hResizing: #shrinkWrap; vResizing: #shrinkWrap; layoutInset: 0.\\n\\taWrapper addMorphBack: (aMorph _ TextMorph new contents: 'A').\\n\\taMorph beAllFont: ((TextStyle named: Preferences standardEToysFont familyName) fontOfSize: 24).\\n\\taMorph width: 14; lock.\\n\\taWrapper beTransparent; setNameTo: 'A'.\\n\\taPlayer _ aWrapper assuredPlayer.\\n\\taPlayer addInstanceVariableNamed: #index type: #Number value: 1.\\n\\taContainer addMorphBack: aWrapper.\\n\\t2 to: 26 do:\\n\\t\\t[:anIndex |\\n\\t\\t\\tnewMorph _ aWrapper usableSiblingInstance.\\n\\t\\t\\tnewMorph player perform: #setIndex: with: anIndex.\\n\\t\\t\\tnewMorph firstSubmorph contents: (oneCharString _ ($A asciiValue + anIndex - 1) asCharacter asString).\\n\\t\\t\\tnewMorph setNameTo: oneCharString.\\n\\n\\t\\t\\taContainer addMorphBack: newMorph].\\n\\n\\t#(' ' '.' '#') with: #(27 28 29) do:\\n\\t\\t[:aString :anIndex |\\n\\t\\t\\tnewMorph _ aWrapper usableSiblingInstance.\\n\\t\\t\\tnewMorph player perform: #setIndex: with: anIndex.\\n\\t\\t\\tnewMorph firstSubmorph contents: aString.\\n\\t\\t\\taString = ' '\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[newMorph setNameTo: 'space'.\\n\\t\\t\\t\\t\\tnewMorph color: (Color gray alpha: 0.2)]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[newMorph setNameTo: aString].\\n\\t\\t\\taContainer addMorphBack: newMorph].\\n\\n\\taContainer setNameTo: 'alphabet'.\\n\\taContainer isPartsBin: true.\\n\\taContainer enableDrop: false.\\n\\taContainer indicateCursor: false; width: 162.\\n\\taContainer color: (Color r: 0.839 g: 1.0 b: 1.0). \\\"Color fromUser\\\"\\n\\t^ aContainer! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 9/15/2000 06:24'!\\ninformScriptingUser: aString\\n\\t\\\"This provides a hook for logging messages that the user or the developer may wish to see; at present it simply logs the message to the Transcript, with a standard prefix to signal their provenance. Such messages will fall on the floor if there is no Transcript window open\\\"\\n\\n\\tTranscript cr; show: 'SCRIPT NOTE: ', aString! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 2/26/2003 22:44'!\\nnameForInstanceVariablesCategory\\n\\t\\\"Answer the name to use for the viewer category that contains instance variables\\\"\\n\\n\\t^ #variables \\n\\t\\\"^ #'instance variables'\\\"\\n\\n\\\"ScriptingSystem nameForInstanceVariablesCategory\\\"! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 2/6/2003 18:00'!\\nnameForScriptsCategory\\n\\t\\\"Answer the name to use for the viewer category that contains scripts\\\"\\n\\n\\t^ #scripts! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 2/18/2001 17:50'!\\nnewScriptingSpace\\n\\t\\\"Answer a complete scripting space - raa 19 sept 2000 - experiment for Alan, a variant *not* in a window, now adopted as the only true scripting space\\\"\\n\\n\\t^ self newScriptingSpace2! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 11/13/2001 14:41'!\\nnewScriptingSpace2\\n\\t\\\"Answer a complete scripting space\\\"\\n\\n\\t| aTemplate aPlayfield aControl |\\n\\t\\n\\t(aTemplate _ PasteUpMorph new)\\n\\t\\tsetNameTo: 'etoy';\\n\\t\\textent: 638 @ 470;\\n\\t\\tcolor: Color white;\\n\\t\\timpartPrivatePresenter;\\n\\t\\tsetProperty: #automaticPhraseExpansion toValue: true;\\n\\t\\tbeSticky.\\n\\taTemplate useRoundedCorners; borderWidth: 2. \\n\\taControl _ ScriptingSystem scriptControlButtons setToAdhereToEdge: #bottomLeft.\\n\\taControl beSticky; borderWidth: 0; beTransparent.\\n\\taTemplate addMorphBack: aControl.\\n\\taTemplate presenter addTrashCan.\\n\\n\\taTemplate addMorph: (aPlayfield _ PasteUpMorph new).\\n\\taPlayfield\\n\\t\\tsetNameTo: 'playfield';\\n\\t\\tuseRoundedCorners;\\n\\t\\tsetToAdhereToEdge: #topLeft;\\n\\t\\textent: 340@300;\\n\\t\\tposition: aTemplate topRight - (400@0);\\n\\t\\tbeSticky;\\n\\t\\tautomaticViewing: true;\\n\\t\\twantsMouseOverHalos: true.\\n\\taTemplate presenter standardPlayfield: aPlayfield.\\n\\t\\n\\t^ aTemplate\\n\\n! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 9/21/2000 22:39'!\\nnumericComparitorsAndHelpStrings\\n\\t\\\"Answer an array whose first element is the list of comparitors, and whose second element is a list of the corresponding help strings\\\"\\n\\n\\t^ #((< <= = ~= > >= isDivisibleBy:)\\n\\t \\t('less than' 'less than or equal' 'equal' 'not equal' 'greater than' 'greater than or equal' 'divisible by' ))! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities'!\\nprepareForExternalReleaseNamed: aReleaseName\\n\\t\\\"ScriptingSystem prepareForExternalReleaseNamed: '2.2Beta'\\\"\\n\\n\\tEToySystem stripMethodsForExternalRelease.\\n\\n\\tScriptingSystem saveFormsToFileNamed: aReleaseName, '.Dis.Forms'.\\n\\tScriptingSystem stripGraphicsForExternalRelease.\\n\\tScriptingSystem cleanupsForRelease.\\n\\tScreenController initialize.\\n! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 5/2/1998 14:17'!\\nreclaimSpace\\n\\t\\\"Reclaim space from the scripting system, and report the result in an informer\\\"\\n\\t\\\"ScriptingSystem reclaimSpace\\\"\\n\\n\\t| reclaimed |\\n\\t(reclaimed _ self spaceReclaimed) > 0\\n\\t\\tifTrue:\\t[self inform: reclaimed printString, ' bytes reclaimed']\\n\\t\\tifFalse:\\t[self inform: 'Hmm... Nothing gained this time.']! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 10/30/2000 09:08'!\\nreferenceAt: aSymbol\\n\\t\\\"Answer the object referred to by aSymbol in the 'References' scheme of things, or nil if none\\\"\\n\\n\\t^ References at: aSymbol ifAbsent: [nil]! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 10/30/2000 09:33'!\\nreferenceAt: aSymbol put: anObject\\n\\t\\\"Store a reference to anObject at the given symbol in the References directory\\\"\\n\\n\\t^ References at: aSymbol put: anObject! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 6/9/2000 18:44'!\\nreinvigorateThumbnailsInViewerFlapTabs\\n\\t\\\"It has happened that the thumbnail in a viewer flap tab will go solid gray because it got associated with some passing and disused player temporarily created during the initial painting process. This method takes a sledge hammer to repair such thumbnails. At its genesis, this method is called only from the postscript of its defining fileout.\\\"\\n\\t| vwr thumbnail |\\n\\tViewerFlapTab allInstancesDo:\\n\\t\\t[:aTab | \\n\\t\\t\\tvwr _ aTab referent findA: StandardViewer.\\n\\t\\t\\tthumbnail _ aTab findA: ThumbnailMorph.\\n\\t\\t\\t(vwr notNil and: [thumbnail notNil]) ifTrue:\\n\\t\\t\\t\\t[thumbnail objectToView: vwr scriptedPlayer]]\\n\\n\\t\\\"ScriptingSystem reinvigorateThumbnailsInViewerFlapTabs\\\"! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 12/20/2003 18:02'!\\nreportToUser: aString\\n\\t\\\"Make a message accessible to the user. For the moment, we simply defer to the Transcript mechanism\\\"\\n\\n\\tTranscript cr; show: aString! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 10/30/2000 16:47'!\\nresetAllScriptingReferences\\n\\t\\\"Clear out all the elements in the References directory\\\"\\n\\t\\n\\tSmalltalk at: #References put: IdentityDictionary new\\n\\n\\t\\\"ScriptingSystem resetAllScriptingReferences\\\"! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 10/30/2000 16:45'!\\nresetStaleScriptingReferences\\n\\t\\\"Remove all scripting references that are no longer needed\\\"\\n\\n\\tReferences removeUnreferencedKeys\\n\\n\\t\\\"ScriptingSystem resetStaleScriptingReferences\\\"\\n! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 7/25/2004 17:27'!\\nrestoreClassicEToyLook\\n\\t\\\"Restore classic EToy look, as closely as possible. If ComicBold is present, restore it as the standard etoy and button font. Substitute ComicSansMS and Accuny as respective alternatives if the classic fonts are absent. If those also aren't available, do nothing.\\\"\\n\\n\\t| aTextStyle aFont | \\n\\t(aTextStyle _ TextStyle named: #ComicBold)\\n\\t\\tifNotNil:\\n\\t\\t\\t[aFont _ aTextStyle fontOfSize: 16.\\n\\t\\t\\tPreferences setEToysFontTo: aFont.\\n\\t\\t\\tPreferences setButtonFontTo: aFont]\\n\\t\\tifNil:\\n\\t\\t\\t[(aTextStyle _ TextStyle named: #ComicSansMS) ifNotNil:\\n\\t\\t\\t\\t[Preferences setEToysFontTo: (aTextStyle fontOfSize: 18)].\\n\\t\\t\\t(aTextStyle _ TextStyle named: #Accuny) ifNotNil:\\n\\t\\t\\t\\t[Preferences setButtonFontTo: (aTextStyle fontOfSize: 12)]].\\n\\n\\t(aTextStyle _ TextStyle named: #NewYork)\\n\\t\\tifNotNil:\\n\\t\\t\\t[Preferences setSystemFontTo: (aTextStyle fontOfSize: 12)]! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 5/16/2001 12:58'!\\nsetterSelectorForGetter: aGetterSymbol\\n\\t\\\"Answer the setter selector corresponding to a given getter\\\"\\n\\n\\t^ (('s', (aGetterSymbol copyFrom: 2 to: aGetterSymbol size)), ':') asSymbol\\n\\n\\t\\\"ScriptingSystem setterSelectorForGetter: #getCursor\\\"! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'di 3/3/2001 08:47'!\\nspaceReclaimed\\n\\t\\\"Reclaim space from the EToy system, and return the number of bytes reclaimed\\\"\\n\\t\\\"ScriptingSystem spaceReclaimed\\\"\\n\\n\\t| oldFree |\\n\\toldFree _ Smalltalk garbageCollect.\\n\\tThumbnailMorph recursionReset.\\n\\tPlayer removeUninstantiatedSubclassesSilently.\\n\\tSmalltalk cleanOutUndeclared.\\n\\tSmalltalk reclaimDependents.\\n\\t^ Smalltalk garbageCollect - oldFree.! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'sw 9/27/2001 13:28'!\\ntileForArgType: aType\\n\\t\\\"Anwer a default tile to represent a datum of the given argument type, which may be either a symbol (e.g. #Color) or a class\\\"\\n\\n\\t(aType isKindOf: Class) \\\"Allowed in Ted's work\\\"\\n\\t\\tifTrue:\\n\\t\\t\\t[^ aType name asString newTileMorphRepresentative typeColor: Color gray].\\n\\n\\t^ (Vocabulary vocabularyForType: aType) defaultArgumentTile! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'dgd 7/12/2003 12:05'!\\ntryButtonFor: aPhraseTileMorph \\n\\t| aButton |\\n\\taButton := SimpleButtonMorph new.\\n\\taButton target: aPhraseTileMorph;\\n\\t\\t actionSelector: #try;\\n\\t\\t\\n\\t\\tlabel: '!!'\\n\\t\\tfont: Preferences standardEToysFont;\\n\\t\\t color: Color yellow;\\n\\t\\t borderWidth: 0.\\n\\taButton actWhen: #whilePressed.\\n\\taButton balloonTextSelector: #try.\\n\\t^ aButton! !\\n\\n!StandardScriptingSystem methodsFor: '*eToys-utilities' stamp: 'nk 10/14/2004 11:19'!\\nwordingForOperator: aString\\n\\t\\\"Answer the wording to be seen by the user for the given operator symbol/string\\\"\\n\\n\\t| toTest |\\n\\ttoTest _ aString asString.\\n\\t#(\\t(append:\\t\\t\\t\\t'include at end')\\n\\t\\t(arrowheadsOnAllPens\\t'arrowheads on all pens')\\n\\t\\t(beep:\\t\\t\\t\\t\\t'make sound')\\n\\t\\t(bounce:\\t\\t\\t\\t'bounce')\\n\\t\\t(clearTurtleTrails\\t\\t'clear pen trails')\\n\\t\\t(clearOwnersPenTrails\\t'clear all pen trails')\\n\\t\\t(colorSees\\t\\t\\t\\t'color sees')\\n\\t\\t(color:sees:\\t\\t\\t\\t'color sees')\\n\\t\\t(doMenuItem:\\t\\t\\t'do menu item')\\n\\t\\t(doScript:\\t\\t\\t\\t'do')\\n\\t\\t(forward:\\t\\t\\t\\t'forward by')\\n\\t\\t(goToRightOf:\\t\\t\\t'align after')\\n\\t\\t(includeAtCursor:\\t\\t'include at cursor')\\n\\t\\t(isDivisibleBy:\\t\\t\\t'is divisible by')\\n\\t\\t(liftAllPens\\t\\t\\t\\t'lift all pens')\\n\\t\\t(lowerAllPens\\t\\t\\t'lower all pens')\\n\\t\\t(makeNewDrawingIn:\\t'start painting in')\\n\\t\\t(max:\\t\\t\\t\\t\\t'max')\\n\\t\\t(min:\\t\\t\\t\\t\\t'min')\\n\\t\\t(moveToward:\\t\\t\\t'move toward')\\n\\t\\t(noArrowheadsOnAllPens\\t'no arrowheads on pens')\\n\\t\\t(overlapsAny\\t\\t\\t'overlaps any')\\n\\t\\t(pauseAll:\\t\\t\\t\\t'pause all')\\n\\t\\t(pauseScript:\\t\\t\\t'pause script')\\n\\t\\t(prepend:\\t\\t\\t\\t'include at beginning')\\n\\t\\t(seesColor:\\t\\t\\t\\t'is over color')\\n\\t\\t(startAll:\\t\\t\\t\\t'start all')\\n\\t\\t(startScript:\\t\\t\\t\\t'start script')\\n\\t\\t(stopProgramatically\\t'stop')\\n\\t\\t(stopAll:\\t\\t\\t\\t\\t'stop all')\\n\\t\\t(stopScript:\\t\\t\\t\\t'stop script')\\n\\t\\t(tellAllSiblings:\\t\\t\\t'tell all siblings')\\n\\t\\t(tellSelfAndAllSiblings:\\t'send to all')\\n\\t\\t(turn:\\t\\t\\t\\t\\t'turn by')\\n\\t\\t(turnToward:\\t\\t\\t\\t'turn toward')\\n\\t\\t(wearCostumeOf:\\t\\t'look like'))\\n\\n\\tdo:\\n\\t\\t[:pair | toTest = pair first ifTrue: [^ pair second]].\\n\\n\\t^ toTest\\n\\n\\t\\\"StandardScriptingSystem initialize\\\"\\n\\n! !\\n\\n\\n!StandardScriptingSystem methodsFor: '*eToys-viewer' stamp: 'sw 10/30/2000 09:07'!\\nuniqueNameForReference\\n\\t\\\"Answer a more-or-less global name by which the receiver can be referred to in scripts\\\"\\n\\n\\t^ #ScriptingSystem! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStandardScriptingSystem class\\n\\tinstanceVariableNames: ''!\\n\\n!StandardScriptingSystem class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 19:04'!\\ninitialize\\n\\t\\\"Initialize the scripting system. Sometimes this method is vacuously changed just to get it in a changeset so that its invocation will occur as part of an update\\\"\\n\\n\\t(self environment at: #ScriptingSystem ifAbsent: [nil]) ifNil:\\n\\t\\t[self environment at: #ScriptingSystem put: self new].\\n\\n\\tScriptingSystem\\n\\t\\tinitializeHelpStrings.\\n\\n\\tself registerInFlapsRegistry.\\n\\n\\\"StandardScriptingSystem initialize\\\"! !\\n\\n\\n!StandardScriptingSystem class methodsFor: 'utilities' stamp: 'nk 9/1/2004 10:53'!\\napplyNewEToyLook\\n\\t\\\"Apply the new EToy look based on free fonts, approximating the classic look as closely as possible.\\\"\\n\\n\\t\\\"StandardScriptingSystem applyNewEToyLook\\\"\\n\\n\\\"\\t| aTextStyle aFont | \\n\\taTextStyle _ TextStyle named: #BitstreamVeraSansMono.\\n\\taFont _ aTextStyle fontOfSize: 12.\\n\\taFont _ aFont emphasis: 1.\\n\\tPreferences setEToysFontTo: aFont.\\n\\tPreferences setButtonFontTo: aFont.\\n\\n\\taTextStyle _ TextStyle named: #Accushi.\\n\\taFont _ aTextStyle fontOfSize: 12.\\n\\tPreferences setFlapsFontTo: aFont.\\n\\n\\t(aTextStyle _ TextStyle named: #Accuny)\\n\\t\\tifNotNil:\\n\\t\\t\\t[Preferences setSystemFontTo: (aTextStyle fontOfSize: 12)]\\\"\\n\\n\\tPreferences setDefaultFonts: #(\\n\\t\\t(setEToysFontTo:\\t\\t\\tBitstreamVeraSansBold\\t10)\\n\\t\\t(setButtonFontTo:\\t\\tBitstreamVeraSansMono\\t9)\\n\\t\\t(setFlapsFontTo:\\t\\t\\tAccushi\\t\\t\\t\\t12)\\n\\t\\t(setSystemFontTo:\\t\\tAccuny\\t\\t\\t\\t10)\\n\\t\\t(setWindowTitleFontTo:\\tBitstreamVeraSansBold\\t12)\\n\\t)\\n! !\\n\\n!StandardScriptingSystem class methodsFor: 'utilities' stamp: 'mir 11/26/2004 16:14'!\\nremovePlayersIn: project\\n\\t\\\"Remove existing player references for project\\\"\\n\\n\\tReferences keys do: \\n\\t\\t[:key | (References at: key) costume pasteUpMorph == project world\\n\\t\\t\\tifTrue: [References removeKey: key]].\\n! !\\n\\n!StandardScriptingSystem class methodsFor: 'utilities' stamp: 'mir 11/25/2004 19:01'!\\nremoveUnreferencedPlayers\\n\\t\\\"Remove existing but unreferenced player references\\\"\\n\\t\\\"StandardScriptingSystem removeUnreferencedPlayers\\\"\\n\\tReferences keys do: \\n\\t\\t[:key | (References at: key) costume pasteUpMorph\\n\\t\\t\\tifNil: [References removeKey: key]].\\n! !\\n\\n\\n!StandardScriptingSystem class methodsFor: '*MorphicExtras-class initialization' stamp: 'asm 4/11/2003 19:08'!\\nregisterInFlapsRegistry\\n\\t\\\"Register the receiver in the system's flaps registry\\\"\\n\\tself environment\\n\\t\\tat: #Flaps\\n\\t\\tifPresent: [:cl | cl registerQuad: #(ScriptingSystem\\tprototypicalHolder\\t'Holder'\\t\\t'A place for storing alternative pictures in an animation, etc.')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'PlugIn Supplies'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(ScriptingSystem\\tprototypicalHolder\\t'Holder'\\t\\t'A place for storing alternative pictures in an animation, etc.')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Supplies'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(ScriptingSystem\\tnewScriptingSpace\\t'Scripting'\\t'A confined place for drawing and scripting, with its own private stop/step/go buttons.')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Widgets'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(ScriptingSystem\\tholderWithAlphabet\\t'Alphabet'\\t'A source for single-letter objects')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Widgets'.]! !\\n\\n!StandardScriptingSystem class methodsFor: '*MorphicExtras-class initialization' stamp: 'asm 4/12/2003 14:38'!\\nunload\\n\\t\\\"Unload the receiver from global registries\\\"\\n\\n\\tself environment at: #Flaps ifPresent: [:cl |\\n\\tcl unregisterQuadsWithReceiver: ScriptingSystem] ! !\\n\\n\\n\\n!StandardScriptingSystem class methodsFor: '*flexibleVocabularies-flexibleVocabularies' stamp: 'NS 4/8/2004 19:06'!\\nnoteAddedSelector: aSelector meta: isMeta\\n\\taSelector == #wordingForOperator: ifTrue:\\n\\t\\t[Vocabulary changeMadeToViewerAdditions].\\n\\tsuper noteAddedSelector: aSelector meta: isMeta! !\\n\\n!StandardScriptingSystem class methodsFor: '*flexibleVocabularies-flexibleVocabularies' stamp: 'NS 4/15/2004 12:41'!\\nnoteCompilationOf: aSelector meta: isMeta\\n\\t\\\"This method does nothing and should be removed.\\\"\\n\\n\\t^ super noteCompilationOf: aSelector meta: isMeta! !\\nSourceFileArray subclass: #StandardSourceFileArray\\n\\tinstanceVariableNames: 'files'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Files-System'!\\n!StandardSourceFileArray commentStamp: '<historical>' prior: 0!\\nThis class implements the source file management behavior of traditional Squeak, with a sources file and a changes file. File positions are mapped such that those files can be up to 32MBytes in size.\\n\\nStructure:\\n files\\t\\tArray -- storing the actual source files\\n!\\n\\n\\n!StandardSourceFileArray methodsFor: 'accessing' stamp: 'hmm 4/25/2000 21:20'!\\nat: index\\n\\t^files at: index! !\\n\\n!StandardSourceFileArray methodsFor: 'accessing' stamp: 'hmm 4/25/2000 21:20'!\\nat: index put: aFile\\n\\tfiles at: index put: aFile! !\\n\\n!StandardSourceFileArray methodsFor: 'accessing' stamp: 'hmm 4/25/2000 21:20'!\\nsize\\n\\t^files size! !\\n\\n\\n!StandardSourceFileArray methodsFor: 'initialize-release' stamp: 'stephaneducasse 2/4/2006 20:32'!\\ninitialize\\n\\tfiles := Array new: 2.\\n\\tfiles at: 1 put: (SourceFiles at: 1).\\n\\tfiles at: 2 put: (SourceFiles at: 2)! !\\n\\n!StandardSourceFileArray methodsFor: 'initialize-release' stamp: 'stephaneducasse 2/4/2006 20:32'!\\ninitialize: nFiles\\n\\tfiles := Array new: nFiles! !\\n\\n\\n!StandardSourceFileArray methodsFor: 'sourcePointer conversion' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nfileIndexFromSourcePointer: anInteger\\n\\t\\\"Return the index of the source file which contains the source chunk addressed by anInteger\\\"\\n\\t\\\"This implements the recent 32M source file algorithm\\\"\\n\\n\\t| hi |\\n\\thi := anInteger // 16r1000000.\\n\\t^hi < 3\\n\\t\\tifTrue: [hi]\\n\\t\\tifFalse: [hi - 2]! !\\n\\n!StandardSourceFileArray methodsFor: 'sourcePointer conversion' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nfilePositionFromSourcePointer: anInteger\\n\\t\\\"Return the position of the source chunk addressed by anInteger\\\"\\n\\t\\\"This implements the recent 32M source file algorithm\\\"\\n\\n\\t| hi lo |\\n\\thi := anInteger // 16r1000000.\\n\\tlo := anInteger \\\\\\\\ 16r1000000.\\n\\t^hi < 3\\n\\t\\tifTrue: [lo]\\n\\t\\tifFalse: [lo + 16r1000000]! !\\n\\n!StandardSourceFileArray methodsFor: 'sourcePointer conversion' stamp: 'stephaneducasse 2/4/2006 20:32'!\\nsourcePointerFromFileIndex: index andPosition: position\\n\\t| hi lo |\\n\\t\\\"Return a source pointer according to the new 32M algorithm\\\"\\n\\t((index between: 1 and: 2) and: [position between: 0 and: 16r1FFFFFF])\\n\\t\\tifFalse: [self error: 'invalid source code pointer'].\\n\\thi := index.\\n\\tlo := position.\\n\\tlo >= 16r1000000 ifTrue: [\\n\\t\\thi := hi+2.\\n\\t\\tlo := lo - 16r1000000].\\n\\t^hi * 16r1000000 + lo! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStandardSourceFileArray class\\n\\tinstanceVariableNames: ''!\\n\\n!StandardSourceFileArray class methodsFor: 'initialize-release' stamp: 'nk 7/30/2004 21:50'!\\ninstall\\n\\t\\\"Replace SourceFiles by an instance of me with the standard sources and changes files.\\n\\tThis only works if SourceFiles is either an Array or an instance of this class\\\"\\n\\n\\t\\\"StandardSourceFileArray install\\\"\\n\\n\\tSourceFiles := self new! !\\n\\n!StandardSourceFileArray class methodsFor: 'initialize-release' stamp: 'ar 5/17/2000 18:27'!\\nnew: nFiles\\n\\t^self new initialize: nFiles.! !\\nMouseMenuController subclass: #StandardSystemController\\n\\tinstanceVariableNames: 'status'\\n\\tclassVariableNames: 'HBorderCursor ScheduledBlueButtonMenu ScheduledBlueButtonMessages VBorderCursor'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Support'!\\n!StandardSystemController commentStamp: '<historical>' prior: 0!\\nI am a controller for StandardSystemViews, that is, those views that are at the top level of a project in the system user interface. I am a kind of MouseMenuController that creates a blue button menu for moving, framing, collapsing, and closing ScheduledViews, and for selecting views under the view of my instance.!\\n\\n\\n!StandardSystemController methodsFor: 'basic control sequence' stamp: 'sw 10/20/1999 09:52'!\\ncontrolInitialize\\n\\tview displayEmphasized.\\n\\tview uncacheBits. \\\"Release cached bitmap while active\\\"\\n\\tmodel windowActiveOnFirstClick ifFalse: [sensor waitNoButton].\\n\\tstatus _ #active.\\n\\tview isCollapsed ifFalse: [model modelWakeUpIn: view]! !\\n\\n!StandardSystemController methodsFor: 'basic control sequence' stamp: 'di 5/11/1999 22:05'!\\ncontrolTerminate\\n\\tstatus == #closed\\n\\t\\tifTrue: \\n\\t\\t\\t[view ~~ nil ifTrue: [view release].\\n\\t\\t\\tScheduledControllers unschedule: self.\\n\\t\\t\\t^self].\\n\\tview deEmphasize; cacheBits.\\n\\tview isCollapsed ifFalse: [model modelSleep].! !\\n\\n\\n!StandardSystemController methodsFor: 'borders' stamp: 'ls 7/11/1998 07:45'!\\nadjustPaneBorders \\n\\t| side sub newRect outerFrame |\\n\\touterFrame _ view displayBox.\\n\\tside _ #none.\\n\\tVBorderCursor showWhile:\\n\\t\\t[ [sub _ view subviewWithLongestSide: [:s | side _ s]\\n\\t\\t\\t\\t\\t\\tnear: sensor cursorPoint.\\n\\t\\t self cursorOnBorder and: [(side = #left) | (side = #right)]]\\n\\t\\t\\twhileTrue: [\\n\\t\\t\\t\\tself interActivityPause.\\n\\t\\t\\t\\tsensor redButtonPressed ifTrue:\\n\\t\\t\\t\\t[side = #left ifTrue:\\n\\t\\t\\t\\t\\t[newRect _ sub stretchFrame:\\n\\t\\t\\t\\t\\t\\t[:f | (f withLeft: sensor cursorPoint x)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: outerFrame]\\n\\t\\t\\t\\t\\t\\tstartingWith: sub displayBox].\\n\\t\\t\\t\\tside = #right ifTrue:\\n\\t\\t\\t\\t\\t[newRect _ sub stretchFrame:\\n\\t\\t\\t\\t\\t\\t[:f | (f withRight: sensor cursorPoint x)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: outerFrame]\\n\\t\\t\\t\\t\\t\\tstartingWith: sub displayBox].\\n\\t\\t\\t\\tview reframePanesAdjoining: sub along: side to: newRect]]].\\n\\tHBorderCursor showWhile:\\n\\t\\t[ [sub _ view subviewWithLongestSide: [:s | side _ s]\\n\\t\\t\\t\\t\\t\\tnear: sensor cursorPoint.\\n\\t\\t self cursorOnBorder and: [(side = #top) | (side = #bottom)]]\\n\\t\\t\\twhileTrue: [\\n\\t\\t\\t\\tself interActivityPause.\\n\\t\\t\\t\\tsensor redButtonPressed ifTrue:\\n\\t\\t\\t\\t[side = #top ifTrue:\\n\\t\\t\\t\\t\\t[newRect _ sub stretchFrame:\\n\\t\\t\\t\\t\\t\\t[:f | (f withTop: sensor cursorPoint y)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: outerFrame]\\n\\t\\t\\t\\t\\t\\tstartingWith: sub displayBox].\\n\\t\\t\\t\\tside = #bottom ifTrue:\\n\\t\\t\\t\\t\\t[newRect _ sub stretchFrame:\\n\\t\\t\\t\\t\\t\\t[:f | (f withBottom: sensor cursorPoint y)\\n\\t\\t\\t\\t\\t\\t\\t\\tintersect: outerFrame]\\n\\t\\t\\t\\t\\t\\tstartingWith: sub displayBox].\\n\\t\\t\\t\\tview reframePanesAdjoining: sub along: side to: newRect]]]! !\\n\\n!StandardSystemController methodsFor: 'borders' stamp: 'di 11/16/2001 22:22'!\\nadjustWindowBorders \\n\\t| side noClickYet |\\n\\tnoClickYet _ true.\\n\\tVBorderCursor showWhile:\\n\\t\\t[ [side _ view displayBox sideNearestTo: sensor cursorPoint.\\n\\t\\t self cursorOnBorder\\n\\t\\t\\tand: [(side = #left) | (side = #right)\\n\\t\\t\\tand: [noClickYet or: [sensor redButtonPressed]]]]\\n\\t\\t\\twhileTrue:\\n\\t\\t\\t[sensor redButtonPressed ifTrue:\\n\\t\\t\\t\\t[noClickYet _ false.\\n\\t\\t\\t\\tside = #left ifTrue:\\n\\t\\t\\t\\t\\t[view newFrame: [:f | f withLeft: sensor cursorPoint x]].\\n\\t\\t\\t\\tside = #right ifTrue:\\n\\t\\t\\t\\t\\t[view newFrame: [:f | f withRight: sensor cursorPoint x]]].\\n\\t\\t\\tself interActivityPause]].\\n\\tHBorderCursor showWhile:\\n\\t\\t[ [side _ view displayBox sideNearestTo: sensor cursorPoint.\\n\\t\\t self cursorOnBorder\\n\\t\\t\\tand: [(side = #top) | (side = #bottom)\\n\\t\\t\\tand: [noClickYet or: [sensor redButtonPressed]]]]\\n\\t\\t\\twhileTrue:\\n\\t\\t\\t[sensor redButtonPressed ifTrue:\\n\\t\\t\\t\\t[noClickYet _ false.\\n\\t\\t\\t\\tside = #top ifTrue:\\n\\t\\t\\t\\t\\t[view newFrame: [:f | f withTop: sensor cursorPoint y]].\\n\\t\\t\\t\\tside = #bottom ifTrue:\\n\\t\\t\\t\\t\\t[view newFrame: [:f | f withBottom: sensor cursorPoint y]]].\\n\\t\\t self interActivityPause]]! !\\n\\n!StandardSystemController methodsFor: 'borders' stamp: 'ls 7/11/1998 07:38'!\\nadjustWindowCorners \\n\\t| box cornerBox p clicked f2 |\\n\\tbox _ view windowBox.\\n\\tclicked _ false.\\n\\t#(topLeft topRight bottomRight bottomLeft)\\n\\t\\tdo: [:readCorner |\\n\\t\\t\\tcornerBox _ ((box insetBy: 2) perform: readCorner) - (10@10) extent: 20@20.\\n\\t\\t\\t(cornerBox containsPoint: sensor cursorPoint)\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t[\\\"Display reverse: cornerBox.\\\"\\n\\t\\t\\t\\t(Cursor perform: readCorner) showWhile:\\n\\t\\t\\t\\t\\t[[(cornerBox containsPoint: (p _ sensor cursorPoint))\\n\\t\\t\\t\\t\\t\\tand: [(clicked _ sensor anyButtonPressed) not]]\\n\\t\\t\\t\\t\\t\\twhileTrue: [ self interActivityPause ].\\n\\t\\t\\t\\t\\\"Display reverse: cornerBox.\\\"\\n\\t\\t\\t\\tclicked ifTrue:\\n\\t\\t\\t\\t\\t[view newFrame:\\n\\t\\t\\t\\t\\t\\t[:f | p _ sensor cursorPoint.\\n\\t\\t\\t\\t\\t\\treadCorner = #topLeft ifTrue:\\n\\t\\t\\t\\t\\t\\t\\t[f2 _ p corner: f bottomRight].\\n\\t\\t\\t\\t\\t\\treadCorner = #bottomLeft ifTrue:\\n\\t\\t\\t\\t\\t\\t\\t[f2 _ (f withBottom: p y) withLeft: p x].\\n\\t\\t\\t\\t\\t\\treadCorner = #bottomRight ifTrue:\\n\\t\\t\\t\\t\\t\\t\\t[f2 _ f topLeft corner: p].\\n\\t\\t\\t\\t\\t\\treadCorner = #topRight ifTrue:\\n\\t\\t\\t\\t\\t\\t\\t[f2 _ (f withTop: p y) withRight: p x].\\n\\t\\t\\t\\t\\t\\tf2]]]]].\\n\\t^ clicked! !\\n\\n!StandardSystemController methodsFor: 'borders' stamp: 'di 11/16/2001 22:30'!\\ncheckForReframe\\n\\t| cp |\\n\\tview isCollapsed ifTrue: [^ self].\\n\\tcp _ sensor cursorPoint.\\n\\t((view closeBoxFrame expandBy: 2) containsPoint: cp)\\n\\t\\t| ((view growBoxFrame expandBy: 2) containsPoint: cp)\\n\\t\\tifTrue: [^ self]. \\\"Dont let reframe interfere with close/grow\\\"\\n\\tself adjustWindowCorners.\\n\\tself cursorOnBorder ifFalse: [^ self].\\n\\t((view insetDisplayBox insetBy: 2@2) containsPoint: cp)\\n\\t\\tifFalse: [^ self adjustWindowBorders].\\n\\tview subViews size <= 1 ifTrue: [^ self].\\n\\t(view subviewWithLongestSide: [:s | ] near: cp) == nil\\n\\t\\tifFalse: [^ self adjustPaneBorders].! !\\n\\n!StandardSystemController methodsFor: 'borders'!\\ncursorOnBorder \\n\\t| cp i box |\\n\\tview isCollapsed ifTrue: [^ false].\\n\\tcp _ sensor cursorPoint.\\n\\t((view labelDisplayBox insetBy: (0@2 corner: 0@-2)) containsPoint: cp)\\n\\t\\tifTrue: [^ false].\\n\\t(i _ view subViews findFirst: [:v | v displayBox containsPoint: cp]) = 0\\n\\t\\tifTrue: [box _ view windowBox]\\n\\t\\tifFalse: [box _ (view subViews at: i) insetDisplayBox].\\n\\t^ ((box insetBy: 3) containsPoint: cp) not\\n\\t\\tand: [(box expandBy: 4) containsPoint: cp]! !\\n\\n!StandardSystemController methodsFor: 'borders'!\\nfullScreen\\n\\t\\\"Make the receiver's window occupy jes' about the full screen. 6/10/96 sw\\\"\\n\\n\\tview fullScreen! !\\n\\n\\n!StandardSystemController methodsFor: 'control defaults' stamp: 'sma 3/11/2000 12:01'!\\nblueButtonActivity\\n\\tScheduledBlueButtonMenu ifNil: [^ super controlActivity].\\n\\tScheduledBlueButtonMenu invokeOn: self! !\\n\\n!StandardSystemController methodsFor: 'control defaults' stamp: 'sma 3/11/2000 15:20'!\\ncontrolActivity\\n\\tself checkForReframe.\\n\\t^ super controlActivity! !\\n\\n!StandardSystemController methodsFor: 'control defaults'!\\nisControlActive\\n\\tstatus == #active ifFalse: [^ false].\\n\\tsensor anyButtonPressed ifFalse: [^ true].\\n\\tself viewHasCursor\\n\\t\\tifTrue: [^ true]\\n\\t\\tifFalse: [ScheduledControllers noteNewTop.\\n\\t\\t\\t\\t^ false]! !\\n\\n!StandardSystemController methodsFor: 'control defaults' stamp: 'sma 3/15/2000 22:19'!\\nredButtonActivity\\n\\t\\\"If cursor is in label of a window when red button is pushed,\\n\\tcheck for closeBox or growBox, else drag the window frame\\n\\tor edit the label.\\\"\\n\\n\\t| box p |\\n\\tp _ sensor cursorPoint.\\n\\tself labelHasCursor ifFalse: [super redButtonActivity. ^ self].\\n\\t((box _ view closeBoxFrame) containsPoint: p)\\n\\t\\tifTrue:\\n\\t\\t\\t[Utilities\\n\\t\\t\\t\\tawaitMouseUpIn: box\\n\\t\\t\\t\\trepeating: []\\n\\t\\t\\t\\tifSucceed: [self close. ^ self].\\n\\t\\t\\t^ self].\\n\\t((box _ view growBoxFrame) containsPoint: p)\\n\\t\\tifTrue:\\n\\t\\t\\t[Utilities\\n\\t\\t\\t\\tawaitMouseUpIn: box\\n\\t\\t\\t\\trepeating: []\\n\\t\\t\\t\\tifSucceed:\\n\\t\\t\\t\\t\\t[Sensor controlKeyPressed ifTrue: [^ self expand; fullScreen].\\n\\t\\t\\t\\t\\t^ view isCollapsed\\n\\t\\t\\t\\t\\t\\tifTrue: [self expand]\\n\\t\\t\\t\\t\\t\\tifFalse: [self collapse]].\\n\\t\\t\\t^ self].\\n\\t(((box _ view labelTextRegion expandBy: 1) containsPoint: p)\\n\\t\\t\\tand: [Preferences clickOnLabelToEdit or: [sensor leftShiftDown]])\\n\\t\\tifTrue:\\n\\t\\t\\t[Utilities\\n\\t\\t\\t\\tawaitMouseUpIn: box\\n\\t\\t\\t\\trepeating: []\\n\\t\\t\\t\\tifSucceed: [^ self label].\\n\\t\\t\\t^ self].\\n\\tself move! !\\n\\n\\n!StandardSystemController methodsFor: 'cursor'!\\nlabelHasCursor\\n\\t\\\"Answer true if the cursor is within the window's label\\\"\\n\\t^view labelContainsPoint: sensor cursorPoint! !\\n\\n\\n!StandardSystemController methodsFor: 'initialize-release' stamp: 'sma 3/11/2000 11:48'!\\ninitialize\\n\\tsuper initialize.\\n\\tstatus _ #inactive! !\\n\\n\\n!StandardSystemController methodsFor: 'menu messages'!\\nchooseColor\\n\\t\\\"Allow the user to specify a new background color for the receiver's window. 5/6/96 sw.\\n\\t 7/31/96 sw: use Color fromUser\\\"\\n\\n\\tview backgroundColor: Color fromUser; uncacheBits; display! !\\n\\n!StandardSystemController methodsFor: 'menu messages'!\\nclose\\n\\t\\\"The receiver's view should be removed from the screen and from the \\n\\tcollection of scheduled views.\\\"\\n\\n\\tmodel okToChange ifFalse: [^self].\\n\\tstatus _ #closed.\\n\\tview erase! !\\n\\n!StandardSystemController methodsFor: 'menu messages'!\\ncollapse\\n\\t\\\"Get the receiver's view to change to a collapsed view on the screen.\\\"\\n\\tview collapseToPoint: view chooseCollapsePoint! !\\n\\n!StandardSystemController methodsFor: 'menu messages'!\\nexpand\\n\\t\\\"The receiver's view was collapsed; open it again and ask the user to \\n\\tdesignate its rectangular area.\\\"\\n\\tview expand; emphasize! !\\n\\n!StandardSystemController methodsFor: 'menu messages' stamp: 'rbb 3/1/2005 11:14'!\\nlabel\\n\\n\\t| newLabel |\\n\\tnewLabel := UIManager default\\n\\t\\trequest: 'Edit the label, then type RETURN'\\n\\t\\tinitialAnswer: view label.\\n\\tnewLabel isEmpty ifFalse: [view relabel: newLabel].\\n! !\\n\\n!StandardSystemController methodsFor: 'menu messages'!\\nmove\\n\\t\\\"Ask the user to designate a new origin position for the receiver's view.\\n\\t6/10/96 sw: tell the view that it has moved\\\"\\n\\n\\t| oldBox | \\n\\toldBox _ view windowBox.\\n\\tview uncacheBits.\\n\\tview align: view windowBox topLeft\\n\\t\\twith: view chooseMoveRectangle topLeft.\\n\\tview displayEmphasized.\\n\\tview moved. \\\"In case its model wishes to take note.\\\"\\n\\t(oldBox areasOutside: view windowBox) do:\\n\\t\\t[:rect | ScheduledControllers restore: rect]! !\\n\\n!StandardSystemController methodsFor: 'menu messages'!\\nreframe\\n\\t^ view reframeTo: view getFrame! !\\n\\n!StandardSystemController methodsFor: 'menu messages'!\\ntoggleTwoTone\\n\\t(view isMemberOf: StandardSystemView) ifTrue:\\n\\t\\t[^ view become: (view as: ColorSystemView)].\\n\\t(view isMemberOf: ColorSystemView) ifTrue:\\n\\t\\t[^ view become: (view as: StandardSystemView)].\\n! !\\n\\n!StandardSystemController methodsFor: 'menu messages'!\\nunder\\n\\t\\\"Deactive the receiver's scheduled view and pass control to any view that \\n\\tmight be positioned directly underneath it and the cursor.\\\"\\n\\n\\tstatus _ #inactive! !\\n\\n\\n!StandardSystemController methodsFor: 'pluggable menus' stamp: 'sma 3/11/2000 15:12'!\\ngetPluggableYellowButtonMenu: shiftKeyState\\n\\t^ nil! !\\n\\n\\n!StandardSystemController methodsFor: 'scheduling' stamp: 'sw 9/30/97 22:04'!\\ncloseAndUnschedule\\n\\t\\\"Erase the receiver's view and remove it from the collection of scheduled \\n\\tviews.\\\"\\n\\n\\tstatus _ #closed.\\n\\tview erase.\\n\\tview release.\\n\\tScheduledControllers unschedule: self; searchForActiveController\\n! !\\n\\n!StandardSystemController methodsFor: 'scheduling'!\\ncloseAndUnscheduleNoErase\\n\\t\\\"Remove the scheduled view from the collection of scheduled views. Set \\n\\tits status to closed but do not erase.\\\"\\n\\n\\tstatus _ #closed.\\n\\tview release.\\n\\tScheduledControllers unschedule: self! !\\n\\n!StandardSystemController methodsFor: 'scheduling' stamp: 'jm 3/18/98 19:21'!\\ncloseAndUnscheduleNoTerminate\\n\\t\\\"Erase the receiver's view and remove it from the collection of scheduled views, but do not terminate the current process.\\\"\\n\\n\\tstatus _ #closed.\\n\\tview erase.\\n\\tview release.\\n\\tScheduledControllers unschedule: self.\\n! !\\n\\n!StandardSystemController methodsFor: 'scheduling'!\\nopen\\n\\t\\\"Create an area on the screen in which the receiver's scheduled view can \\n\\tbe displayed. Make it the active view.\\\"\\n\\n\\tview resizeInitially.\\n\\tstatus _ #open.\\n\\tScheduledControllers scheduleActive: self! !\\n\\n!StandardSystemController methodsFor: 'scheduling'!\\nopenDisplayAt: aPoint \\n\\t\\\"Create an area with origin aPoint in which the receiver's scheduled \\n\\tview can be displayed. Make it the active view.\\\"\\n\\n\\tview align: view viewport center with: aPoint.\\n\\tview translateBy:\\n\\t\\t(view displayBox amountToTranslateWithin: Display boundingBox).\\n\\tstatus _ #open.\\n\\tScheduledControllers scheduleActive: self! !\\n\\n!StandardSystemController methodsFor: 'scheduling' stamp: 'jm 10/22/97 08:16'!\\nopenNoTerminate\\n\\t\\\"Create an area in which the receiver's scheduled view can be displayed. \\n\\tMake it the active view. Do not terminate the currently active process.\\\"\\n\\n\\tview resizeInitially.\\n\\tstatus _ #open.\\n\\tScheduledControllers scheduleActiveNoTerminate: self! !\\n\\n!StandardSystemController methodsFor: 'scheduling'!\\nopenNoTerminateDisplayAt: aPoint \\n\\t\\\"Create an area with origin aPoint in which the receiver's scheduled \\n\\tview can be displayed. Make it the active view. Do not terminate the \\n\\tcurrently active process.\\\"\\n\\n\\tview resizeMinimumCenteredAt: aPoint.\\n\\tstatus _ #open.\\n\\tScheduledControllers scheduleActiveNoTerminate: self! !\\n\\n!StandardSystemController methodsFor: 'scheduling'!\\nstatus: aSymbol\\n\\tstatus _ aSymbol! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStandardSystemController class\\n\\tinstanceVariableNames: ''!\\n\\n!StandardSystemController class methodsFor: 'class initialization' stamp: 'sma 3/11/2000 11:57'!\\ninitialize\\n\\t\\\"StandardSystemController initialize\\\"\\n\\n\\tScheduledBlueButtonMenu _ SelectionMenu\\n\\t\\tlabels:\\n'edit label\\nchoose color...\\ntwo-tone/full color\\nmove\\nframe\\nfull screen\\ncollapse\\nclose'\\n\\tlines: #(3 7)\\n\\tselections: #(label chooseColor toggleTwoTone move reframe fullScreen collapse close).\\n\\n\\tVBorderCursor _ Cursor extent: 16@16 fromArray: #(\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010010000100000\\n\\t\\t2r1010110000110000\\n\\t\\t2r1011111111111000\\n\\t\\t2r1010110000110000\\n\\t\\t2r1010010000100000\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010000000000000\\n\\t\\t2r1010000000000000)\\n\\t\\t\\toffset: 0@0.\\n\\tHBorderCursor _ Cursor extent: 16@16 fromArray: #(\\n\\t\\t2r1111111111111111\\n\\t\\t2r0000000000000000\\n\\t\\t2r1111111111111111\\n\\t\\t2r0000000100000000\\n\\t\\t2r0000001110000000\\n\\t\\t2r0000011111000000\\n\\t\\t2r0000000100000000\\n\\t\\t2r0000000100000000\\n\\t\\t2r0000000100000000\\n\\t\\t2r0000000100000000\\n\\t\\t2r0000011111000000\\n\\t\\t2r0000001110000000\\n\\t\\t2r0000000100000000\\n\\t\\t2r0000000000000000\\n\\t\\t2r0000000000000000\\n\\t\\t2r0000000000000000)\\n\\t\\t\\toffset: 0@0.! !\\nTestCase subclass: #StandardSystemFontsTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Support-Tests'!\\n\\n!StandardSystemFontsTest methodsFor: 'testing' stamp: 'bp 11/6/2004 23:15'!\\ntestRestoreDefaultFonts\\n\\n\\tself saveStandardSystemFontsDuring: [\\n\\t\\tPreferences restoreDefaultFonts.\\n\\t\\tself assert: #standardDefaultTextFont familyName: 'Accuny' pointSize: 10.\\n\\t\\tself assert: #standardListFont familyName: 'Accuny' pointSize: 10.\\n\\t\\tself assert: #standardFlapFont familyName: 'Accushi' pointSize: 12.\\n\\t\\tself assert: #standardEToysFont familyName: 'BitstreamVeraSans' pointSize: 9.\\n\\t\\tself assert: #standardMenuFont familyName: 'Accuny' pointSize: 10.\\n\\t\\tself assert: #windowTitleFont familyName: 'BitstreamVeraSans' pointSize: 12.\\n\\t\\tself assert: #standardBalloonHelpFont familyName: 'Accujen' pointSize: 9.\\n\\t\\tself assert: #standardCodeFont familyName: 'Accuny' pointSize: 10.\\n\\t\\tself assert: #standardButtonFont familyName: 'BitstreamVeraSansMono' pointSize: 9]! !\\n\\n\\n!StandardSystemFontsTest methodsFor: 'utilities' stamp: 'bp 6/13/2004 18:22'!\\nassert: selector familyName: aString pointSize: anInteger\\n\\n\\t| font |\\n\\tfont _ Preferences perform: selector.\\n\\tself assert: font familyName = aString.\\n\\tself assert: font pointSize = anInteger\\n\\t! !\\n\\n!StandardSystemFontsTest methodsFor: 'utilities' stamp: 'bp 6/13/2004 21:51'!\\nsaveStandardSystemFontsDuring: aBlock\\n\\n\\t| standardDefaultTextFont standardListFont standardEToysFont standardMenuFont \\n\\twindowTitleFont standardBalloonHelpFont standardCodeFont standardButtonFont |\\n\\n\\tstandardDefaultTextFont _ Preferences standardDefaultTextFont.\\n\\tstandardListFont _ Preferences standardListFont.\\n\\tstandardEToysFont _ Preferences standardEToysFont.\\n\\tstandardMenuFont _ Preferences standardMenuFont.\\n\\twindowTitleFont _ Preferences windowTitleFont.\\n\\tstandardBalloonHelpFont _ Preferences standardBalloonHelpFont.\\n\\tstandardCodeFont _ Preferences standardCodeFont.\\n\\tstandardButtonFont _ Preferences standardButtonFont.\\n\\t[aBlock value] ensure: [\\n\\t\\tPreferences setSystemFontTo: standardDefaultTextFont.\\n\\t\\tPreferences setListFontTo: standardListFont.\\n\\t\\tPreferences setEToysFontTo: standardEToysFont.\\n\\t\\tPreferences setMenuFontTo: standardMenuFont.\\n\\t\\tPreferences setWindowTitleFontTo: windowTitleFont.\\n\\t\\tPreferences setBalloonHelpFontTo: standardBalloonHelpFont.\\n\\t\\tPreferences setCodeFontTo: standardCodeFont.\\n\\t\\tPreferences setButtonFontTo: standardButtonFont].\\n! !\\nView subclass: #StandardSystemView\\n\\tinstanceVariableNames: 'labelFrame labelText isLabelComplemented savedSubViews minimumSize maximumSize collapsedViewport expandedViewport labelBits windowBits bitsValid updatablePanes'\\n\\tclassVariableNames: 'CacheBits LabelStyle'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Support'!\\n!StandardSystemView commentStamp: '<historical>' prior: 0!\\nI represent a view that has a label above its top left corner. The text in the label identifies the kind of view. In addition to a label, I add control over the maximum and minimum size of the display box of my instance. My default controller is StandardSystemController. The elements of ScheduledControllers, the sole instance of ControlManager, are usually controllers for instances of me.!\\n\\n\\n!StandardSystemView methodsFor: 'clipping box access'!\\nclippingBox\\n\\t\\\"Answer the rectangular area in which the receiver can show its label.\\\"\\n\\n\\t^self isTopView\\n\\t\\tifTrue: [self labelDisplayBox]\\n\\t\\tifFalse: [super insetDisplayBox]! !\\n\\n!StandardSystemView methodsFor: 'clipping box access' stamp: 'BG 12/5/2003 11:13'!\\nconstrainFrame: aRectangle\\n\\t\\\"Constrain aRectangle, to the minimum and maximum size\\n\\tfor this window\\\"\\n\\n | adjustmentForLabel |\\n adjustmentForLabel := 0 @ (labelFrame height - labelFrame borderWidth).\\n\\t^ aRectangle origin extent:\\n\\t\\t((aRectangle extent max: minimumSize + adjustmentForLabel)\\n\\t\\t min: maximumSize + adjustmentForLabel).! !\\n\\n\\n!StandardSystemView methodsFor: 'controller access'!\\ndefaultControllerClass \\n\\t\\\"Refer to the comment in View|defaultControllerClass.\\\"\\n\\n\\t^StandardSystemController! !\\n\\n\\n!StandardSystemView methodsFor: 'deEmphasizing'!\\ndeEmphasizeView \\n\\t\\\"Refer to the comment in View|deEmphasizeView.\\\"\\n\\n\\tisLabelComplemented ifTrue:\\n\\t\\t[self deEmphasizeLabel.\\n\\t\\tisLabelComplemented _ false]! !\\n\\n!StandardSystemView methodsFor: 'deEmphasizing'!\\nemphasizeView \\n\\t\\\"Refer to the comment in View|emphasizeView.\\\"\\n\\n\\tself emphasizeLabel! !\\n\\n\\n!StandardSystemView methodsFor: 'displaying'!\\ncacheBits\\n\\t| oldLabelState |\\n\\tCacheBits ifFalse: [^ self uncacheBits].\\n\\t(oldLabelState _ isLabelComplemented) ifTrue: [ self deEmphasize ].\\n\\tself cacheBitsAsIs.\\n\\t(isLabelComplemented _ oldLabelState) ifTrue: [ self emphasize ].\\n! !\\n\\n!StandardSystemView methodsFor: 'displaying'!\\ncacheBitsAsIs\\n\\tCacheBits ifFalse: [^ self uncacheBits].\\n\\twindowBits _ (self cacheBitsAsTwoTone and: [Display depth > 1])\\n\\t\\tifTrue: [ColorForm\\n\\t\\t\\t\\t\\ttwoToneFromDisplay: self windowBox\\n\\t\\t\\t\\t\\tusing: windowBits\\n\\t\\t\\t\\t\\tbackgroundColor: self backgroundColor]\\n\\t\\tifFalse: [Form fromDisplay: self windowBox using: windowBits].\\n\\tbitsValid _ true.\\n! !\\n\\n!StandardSystemView methodsFor: 'displaying'!\\ncacheBitsAsTwoTone\\n\\t^ true! !\\n\\n!StandardSystemView methodsFor: 'displaying'!\\ndeEmphasizeForDebugger\\n\\t\\\"Carefully de-emphasis this window because a debugger is being opened. Care must be taken to avoid invoking potentially buggy window display code that could cause a recursive chain of errors eventually resulting in a virtual machine crash. In particular, do not de-emphasize the subviews.\\\"\\n\\n\\tself deEmphasizeView. \\\"de-emphasize this top-level view\\\"\\n\\tself uncacheBits.\\n\\tSmalltalk garbageCollectMost > 1000000 ifTrue: [\\n\\t\\t\\\"if there is enough space, cache current window screen bits\\\"\\n\\t\\tself cacheBitsAsIs].\\n! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'di 10/3/97 13:18'!\\ndeEmphasizeLabel\\n\\t\\\"Un-Highlight the label.\\\"\\n\\tlabelFrame height = 0 ifTrue: [^ self]. \\\"no label\\\"\\n\\tself displayLabelBackground: false.\\n\\tself displayLabelText.! !\\n\\n!StandardSystemView methodsFor: 'displaying'!\\ndisplay\\n\\tisLabelComplemented\\n\\t\\tifTrue: [self displayEmphasized]\\n\\t\\tifFalse: [self displayDeEmphasized]! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'hmm 7/21/1999 07:37'!\\ndisplayDeEmphasized \\n\\t\\\"Display this view with emphasis off.\\n\\tIf windowBits is not nil, then simply BLT if possible,\\n\\t\\tbut force full display for top window so color is preserved.\\\"\\n\\t(bitsValid and: [controller ~~ ScheduledControllers activeController])\\n\\t\\tifTrue: [self lock.\\n\\t\\t\\t\\twindowBits displayAt: self windowOrigin]\\n\\t\\tifFalse: [Display deferUpdates: true.\\n\\t\\t\\t\\tsuper display.\\n\\t\\t\\t\\tDisplay deferUpdates: false; forceToScreen: self windowBox.\\n\\t\\t\\t\\tCacheBits ifTrue: [self cacheBitsAsIs]]\\n! !\\n\\n!StandardSystemView methodsFor: 'displaying'!\\ndisplayEmphasized\\n\\t\\\"Display with label highlighted to indicate that it is active.\\\"\\n\\n\\tself displayDeEmphasized; emphasize.\\n\\tisLabelComplemented _ true! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'di 5/15/1998 21:55'!\\ndisplayLabelBackground: emphasized\\n\\t\\\"Clear or emphasize the inner region of the label\\\"\\n\\t| r1 r2 r3 c3 c2 c1 |\\n\\temphasized ifFalse:\\n\\t\\t[\\\"Just clear the label if not emphasized\\\"\\n\\t\\t^ Display fill: (self labelDisplayBox insetBy: 2) fillColor: self labelColor].\\n\\tr1 _ self labelDisplayBox insetBy: 2.\\n\\tr2 _ r1 insetBy: 0@2.\\n\\tr3 _ r2 insetBy: 0@3.\\n\\tc3 _ self labelColor.\\n\\tc2 _ c3 dansDarker.\\n\\tc1 _ c2 dansDarker.\\n\\tDisplay fill: r1 fillColor: c1.\\n\\tDisplay fill: r2 fillColor: c2.\\n\\tDisplay fill: r3 fillColor: c3.\\n \\n\\\"\\tHere is the Mac racing stripe code\\n\\tstripes _ Bitmap with: (self labelColor pixelWordForDepth: Display depth)\\n\\t\\t\\t\\t\\twith: (Form black pixelWordForDepth: Display depth).\\n\\tself windowOrigin y even ifTrue: [stripes swap: 1 with: 2].\\n\\tDisplay fill: (self labelDisplayBox insetBy: 3) fillColor: stripes.\\n\\\"! !\\n\\n!StandardSystemView methodsFor: 'displaying'!\\ndisplayLabelBoxes\\n\\t\\\"closeBox, growBox.\\\"\\n\\t| aRect smallRect backColor |\\n\\taRect _ self closeBoxFrame.\\n\\tbackColor _ self labelColor.\\n\\tDisplay fill: (aRect insetBy: -2) fillColor: backColor.\\n\\tDisplay fillBlack: aRect.\\n\\tDisplay fill: (aRect insetBy: 1) fillColor: backColor.\\n\\n\\taRect _ self growBoxFrame.\\n\\tsmallRect _ aRect origin extent: 7@7.\\n\\tDisplay fill: (aRect insetBy: -2) fillColor: backColor.\\n\\taRect _ aRect insetOriginBy: 2@2 cornerBy: 0@0.\\n\\tDisplay fillBlack: aRect.\\n\\tDisplay fill: (aRect insetBy: 1) fillColor: backColor.\\n\\tDisplay fillBlack: smallRect.\\n\\tDisplay fill: (smallRect insetBy: 1) fillColor: backColor! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'di 9/10/1998 09:43'!\\ndisplayLabelText\\n\\t\\\"The label goes in the center of the window\\\"\\n\\t| labelRect |\\n\\tlabelText foregroundColor: self foregroundColor\\n\\t\\t\\tbackgroundColor: self labelColor.\\n\\tlabelRect _ self labelTextRegion.\\n\\tDisplay fill: (labelRect expandBy: 3@0) fillColor: self labelColor.\\n\\tlabelText displayOn: Display at: labelRect topLeft clippingBox: labelRect\\n\\t\\t\\trule: labelText rule fillColor: labelText fillColor.\\n\\tlabelText destinationForm: nil! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'di 8/29/97 18:57'!\\ndisplayOn: aPort\\n\\tbitsValid ifFalse:\\n\\t\\t[^ Display clippingTo: aPort clipRect do: [super display]].\\n\\twindowBits displayOnPort: aPort at: self windowOrigin! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'ar 5/14/2001 23:40'!\\ndisplayRacingStripes\\n\\t\\\"Display Racing Stripes in the label\\\"\\n\\t| labelDisplayBox stripes top bottom left box right |\\n\\tlabelDisplayBox _ self labelDisplayBox.\\n\\ttop _ labelDisplayBox top + 3.\\n\\tbottom _ labelDisplayBox bottom - 3.\\n\\tstripes _ Bitmap with: (Display pixelWordFor: self labelColor)\\n\\t\\t\\twith: (Display pixelWordFor: Color black).\\n\\ttop even ifFalse: [stripes swap: 1 with: 2].\\n\\n\\tleft _ labelDisplayBox left + 3.\\n\\n\\tbox _ self closeBoxFrame.\\n\\tright _ box left - 2.\\n\\tDisplay fill: (Rectangle left: left right: right top: top bottom: bottom)\\n\\t\\t\\tfillColor: stripes.\\n\\tleft _ box right + 2.\\n\\n\\tbox _ self labelTextRegion.\\n\\tright _ box left - 3.\\n\\tDisplay fill: (Rectangle left: left right: right top: top bottom: bottom)\\n\\t\\t\\tfillColor: stripes.\\n\\tleft _ box right + 2.\\n\\n\\tbox _ self growBoxFrame.\\n\\tright _ box left - 2.\\n\\tDisplay fill: (Rectangle left: left right: right top: top bottom: bottom)\\n\\t\\t\\tfillColor: stripes.\\n\\tleft _ box right + 2.\\n\\n\\tright _ labelDisplayBox right - 3.\\n\\tDisplay fill: (Rectangle left: left right: right top: top bottom: bottom)\\n\\t\\t\\tfillColor: stripes.\\n! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'di 10/3/97 13:14'!\\ndisplayView\\n\\t\\\"Refer to the comment in View|displayView. \\\"\\n\\tlabelFrame height = 0 ifTrue: [^ self]. \\\"no label\\\"\\n\\tself displayBox width = labelFrame width ifFalse:\\n\\t\\t[\\\"recompute label width when window changes size\\\"\\n\\t\\tself setLabelRegion].\\n\\t(labelFrame align: labelFrame topLeft with: self windowOrigin)\\n\\t\\tinsideColor: self labelColor;\\n\\t\\tdisplayOn: Display.\\n\\tself displayLabelText! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'di 10/3/97 13:18'!\\nemphasizeLabel\\n\\t\\\"Highlight the label.\\\"\\n\\tlabelFrame height = 0 ifTrue: [^ self]. \\\"no label\\\"\\n\\tself displayLabelBackground: true.\\n\\tself displayLabelBoxes.\\n\\tself displayLabelText.! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'di 8/30/97 11:07'!\\nerase\\n\\t\\\"Clear the display box of the receiver to be gray, as the screen background.\\\"\\n\\t| oldValid |\\n\\tCacheBits\\n\\t\\tifTrue:\\n\\t\\t\\t[oldValid _ bitsValid.\\n\\t\\t\\tbitsValid _ false.\\n\\t\\t\\tScheduledControllers restore: self windowBox without: self.\\n\\t\\t\\tbitsValid _ oldValid]\\n\\t\\tifFalse:\\n\\t\\t\\t[ScheduledControllers restore: self windowBox without: self]! !\\n\\n!StandardSystemView methodsFor: 'displaying' stamp: 'RAA 6/14/2000 17:27'!\\nmakeMeVisible\\n\\n | newLoc portRect |\\n ((Display boundingBox insetBy: (0@0 corner: self labelHeight asPoint))\\n containsPoint: self displayBox topLeft) ifTrue: [^ self \\\"OK -- my top left is visible\\\"].\\n\\n \\\"window not on screen (probably due to reframe) -- move it now\\\"\\n newLoc _ self isCollapsed\\n ifTrue: [RealEstateAgent assignCollapsePointFor: self]\\n ifFalse: [(RealEstateAgent initialFrameFor: self world: nil) topLeft].\\n portRect _ newLoc + self labelOffset\\n extent: self windowBox extent - self labelOffset.\\n self resizeTo: portRect.\\n self setLabelRegion.\\n! !\\n\\n!StandardSystemView methodsFor: 'displaying'!\\nuncacheBits\\n\\twindowBits _ nil.\\n\\tbitsValid _ false.! !\\n\\n!StandardSystemView methodsFor: 'displaying'!\\nwindowBits\\n\\t^ windowBits! !\\n\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'sr 3/26/2000 03:47'!\\nchooseCollapsePoint\\n\\t\\\"Answer the point at which to place the collapsed window.\\\"\\n\\t| pt labelForm beenDown offset |\\n\\tlabelForm _ Form fromDisplay: self labelDisplayBox.\\n\\tself uncacheBits.\\n\\tself erase.\\n\\tbeenDown _ Sensor anyButtonPressed.\\n\\tself isCollapsed ifTrue:\\n\\t\\t[offset _ self labelDisplayBox topLeft - self growBoxFrame topLeft.\\n\\t\\tlabelForm follow: [pt _ (Sensor cursorPoint + offset max: 0@0) truncateTo: 8]\\n\\t\\t\\t\\twhile: [Sensor anyButtonPressed\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [beenDown _ true]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [beenDown not]].\\n\\t\\t^ pt].\\n\\t^ (RealEstateAgent assignCollapseFrameFor: self) origin.\\n! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\nchooseFrame\\n\\t\\\"Answer a new frame, depending on whether the view is currently \\n\\tcollapsed or not.\\\"\\n\\t| labelForm f |\\n\\tself isCollapsed & expandedViewport notNil\\n\\t\\tifTrue:\\n\\t\\t\\t[labelForm _ bitsValid\\n\\t\\t\\t\\tifTrue: [windowBits]\\n\\t\\t\\t\\tifFalse: [Form fromDisplay: self labelDisplayBox].\\n\\t\\t\\tbitsValid _ false.\\n\\t\\t\\tself erase.\\n\\t\\t\\tlabelForm slideFrom: self labelDisplayBox origin\\n\\t\\t\\t\\t\\tto: expandedViewport origin-self labelOffset\\n\\t\\t\\t\\t\\tnSteps: 10.\\n\\t\\t\\t^ expandedViewport]\\n\\t\\tifFalse:\\n\\t\\t\\t[f _ self getFrame.\\n\\t\\t\\tbitsValid _ false.\\n\\t\\t\\tself erase.\\n\\t\\t\\t^ f topLeft + self labelOffset extent: f extent]! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\nchooseMoveRectangle\\n\\t\\\"Ask the user to designate a new window rectangle.\\\"\\n\\t| offset p |\\n\\toffset _ Sensor anyButtonPressed \\\"Offset if draggin, eg, label\\\"\\n\\t\\tifTrue: [self windowBox topLeft - Sensor cursorPoint]\\n\\t\\tifFalse: [0@0].\\n\\tself isCollapsed\\n\\t\\tifTrue: [^ self labelDisplayBox newRectFrom:\\n\\t\\t\\t\\t\\t[:f | p _ Sensor cursorPoint + offset.\\n\\t\\t\\t\\t\\tp _ (p max: 0@0) truncateTo: 8.\\n\\t\\t\\t\\t\\tp extent: f extent]]\\n\\t\\tifFalse: [^ self windowBox newRectFrom:\\n\\t\\t\\t\\t\\t[:f | p _ Sensor cursorPoint + offset.\\n\\t\\t\\t\\t\\tself constrainFrame: (p extent: f extent)]]! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'di 5/11/1999 22:09'!\\ncollapse\\n\\t\\\"If the receiver is not already collapsed, change its view to be that of its \\n\\tlabel only.\\\"\\n\\n\\tself isCollapsed ifFalse:\\n\\t\\t\\t[model modelSleep.\\n\\t\\t\\t(subViews ~~ nil and: [subViews size = 1 and: [subViews first isKindOf: MorphWorldView]])\\n\\t\\t\\t\\tifTrue: [subViews first deEmphasizeView].\\n\\t\\t\\texpandedViewport _ self viewport.\\n\\t\\t\\tsavedSubViews _ subViews.\\n\\t\\t\\tself resetSubViews.\\n\\t\\t\\tlabelText isNil ifTrue: [self label: nil. bitsValid _ false.].\\n\\t\\t\\tself window: (self inverseDisplayTransform:\\n\\t\\t\\t\\t\\t((self labelDisplayBox topLeft extent: (labelText extent x + 70) @ self labelHeight)\\n\\t\\t\\t\\t\\t\\t intersect: self labelDisplayBox))]! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\ncollapseToPoint: collapsePoint\\n\\tself collapse.\\n\\tself align: self displayBox topLeft with: collapsePoint.\\n\\tcollapsedViewport _ self viewport.\\n\\tself displayEmphasized! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\ncollapsedFrame\\n\\t\\\"Answer the rectangle occupied by this window when collapsed.\\\"\\n\\t^ collapsedViewport \\\"NOTE may be nil\\\"! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'sw 10/20/1999 09:46'!\\nexpand\\n\\t\\\"If the receiver is collapsed, change its view to be that of all of its subviews, not its label alone.\\\"\\n\\t| newFrame |\\n\\tself isCollapsed\\n\\t\\tifTrue:\\n\\t\\t\\t[newFrame _ self chooseFrame expandBy: borderWidth.\\n\\t\\t\\tcollapsedViewport _ self viewport.\\n\\t\\t\\tsubViews _ savedSubViews.\\n\\t\\t\\tlabelFrame borderWidthLeft: 2 right: 2 top: 2 bottom: 2.\\n\\t\\t\\tsavedSubViews _ nil.\\n\\t\\t\\tself setWindow: nil.\\n\\t\\t\\tself resizeTo: newFrame.\\n\\t\\t\\tself displayDeEmphasized.\\n\\t\\t\\tmodel modelWakeUpIn: self]! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\nexpandedFrame\\n\\t\\\"Answer the rectangle occupied by this window when expanded.\\\"\\n\\t^ expandedViewport \\\"NOTE may be nil\\\"! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'sw 8/15/97 17:18'!\\nfullScreen\\n\\t\\\"Expand the receiver to fill the screen. Let the model decide how big is full -- allows for flop-out scrollbar on left if desired\\\"\\n\\n\\tself isCollapsed ifFalse:\\n\\t\\t[self reframeTo: model fullScreenSize]! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\ngetFrame\\n\\t\\\"Ask the user to designate a rectangular area in which\\n\\tthe receiver should be displayed.\\\"\\n\\t| minFrame |\\n\\tminFrame _ Cursor origin showWhile: \\n\\t\\t[(Sensor cursorPoint extent: self minimumSize) newRectFrom:\\n\\t\\t\\t[:f | Sensor cursorPoint extent: self minimumSize]].\\n\\tself maximumSize <= self minimumSize ifTrue: [^ minFrame].\\n\\t^ Cursor corner showWhile:\\n\\t\\t[minFrame newRectFrom:\\n\\t\\t\\t[:f | self constrainFrame: (f origin corner: Sensor cursorPoint)]]! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'sw 1/22/96'!\\ninitialExtent\\n\\t\\\"Answer the desired extent for the receiver when it is first opened on the screen. \\\"\\n\\n\\t^ model initialExtent min: maximumSize max: minimumSize! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'RAA 6/14/2000 17:27'!\\ninitialFrame\\n \\\"Find a plausible initial screen area for the receiver, taking into account user preference, the size needed, and other windows currently on the screen. 5/22/96 sw: let RealEstateAgent do it for us\\\"\\n\\n ^ RealEstateAgent initialFrameFor: self world: nil! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\nmoved\\n\\t\\\"The user has moved the receiver; after a new view rectangle is chosen, this method is called to allow certain views to take note of the change. 6/10/96 sw\\\" ! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\nnewFrame: frameChangeBlock\\n\\tself reframeTo: (self windowBox newRectFrom:\\n\\t\\t[:f | self constrainFrame: (frameChangeBlock value: f)])! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'di 10/22/1998 16:15'!\\nreframePanesAdjoining: subView along: side to: aDisplayBox \\n\\t| newBox delta newRect minDim theMin |\\n\\tnewRect _ aDisplayBox.\\n\\ttheMin _ 16.\\n\\t\\\"First check that this won't make any pane smaller than theMin screen dots\\\"\\n\\tminDim _ ((subViews select: [:sub | sub displayBox bordersOn: subView displayBox along: side])\\n\\t\\tcollect: [:sub | sub displayBox adjustTo: newRect along: side])\\n\\t\\t\\tinject: 999 into: [:was :rect | (was min: rect width) min: rect height].\\n\\t\\\"If so, amend newRect as required\\\"\\n\\tminDim < theMin ifTrue:\\n\\t\\t[delta _ minDim - theMin.\\n\\t\\tnewRect _ newRect withSide: side setTo: \\n\\t\\t\\t\\t((newRect perform: side) > (subView displayBox perform: side)\\n\\t\\t\\t\\t\\tifTrue: [(newRect perform: side) + delta]\\n\\t\\t\\t\\t\\tifFalse: [(newRect perform: side) - delta])].\\n\\t\\\"Now adjust all adjoining panes for real\\\"\\n\\tsubViews do:\\n\\t\\t[:sub | (sub displayBox bordersOn: subView displayBox along: side) ifTrue:\\n\\t\\t\\t[newBox _ sub displayBox adjustTo: newRect along: side.\\n\\t\\t\\tsub window: sub window viewport:\\n\\t\\t\\t\\t(sub transform: (sub inverseDisplayTransform: newBox)) rounded]].\\n\\t\\\"And adjust the growing pane itself\\\"\\n\\tsubView window: subView window viewport:\\n\\t\\t\\t(subView transform: (subView inverseDisplayTransform: newRect)) rounded.\\n\\n\\t\\\"Finally force a recomposition of the whole window\\\"\\n\\tviewport _ nil.\\n\\tself resizeTo: self viewport.\\n\\tself uncacheBits; displayEmphasized! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'BG 12/4/2003 13:14'!\\nreframeTo: newFrame\\n\\t\\\"Reframe the receiver to the given screen rectangle. \\n\\tRepaint difference after the change. \\\"\\n\\t| oldBox newBox portRect |\\n\\tself uncacheBits.\\n\\toldBox _ self windowBox.\\n\\tportRect _ newFrame topLeft + self labelOffset\\n\\t\\t\\t\\tcorner: newFrame corner.\\n\\tself setWindow: nil.\\n\\tself resizeTo: portRect.\\n\\tself setLabelRegion.\\n\\tnewBox _ self windowBox.\\n\\t(oldBox areasOutside: newBox) do:\\n\\t\\t[:rect | ScheduledControllers restore: rect].\\n\\tself displayEmphasized! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\nresize\\n\\t\\\"Determine the rectangular area for the receiver, adjusted to the \\n\\tminimum and maximum sizes.\\\"\\n\\t| f |\\n\\tf _ self getFrame.\\n\\tself resizeTo: (f topLeft + self labelOffset extent: f extent)\\n! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\nresizeInitially\\n\\t\\\"Determine the rectangular area for the receiver, adjusted to the \\n\\tminimum and maximum sizes.\\\"\\n\\tself resizeTo: self initialFrame\\n! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'di 4/6/98 15:12'!\\nresizeMinimumCenteredAt: aPoint \\n\\t\\\"Determine the rectangular area for the receiver, adjusted so that it is \\n\\tcentered a position, aPoint.\\\"\\n\\t| aRectangle |\\n\\taRectangle _ 0 @ 0 extent: self minimumSize.\\n\\taRectangle _ aRectangle align: aRectangle center with: aPoint.\\n\\tself resizeTo: aRectangle! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'di 4/6/98 15:29'!\\nresizeTo: aRectangle\\n\\t\\\"Resize this view to aRectangle\\\"\\n\\n\\t\\\"First get scaling right inside borders\\\"\\n\\tself window: (self window insetBy: borderWidth)\\n\\t\\tviewport: (aRectangle insetBy: borderWidth).\\n\\n\\t\\\"Then ensure window maps to aRectangle\\\"\\n\\twindow _ transformation applyInverseTo: aRectangle! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\nstandardWindowOffset\\n\\t^ Preferences standardWindowOffset! !\\n\\n!StandardSystemView methodsFor: 'framing'!\\nwindowBox\\n\\t^ self displayBox merge: self labelDisplayBox! !\\n\\n!StandardSystemView methodsFor: 'framing' stamp: 'di 10/3/97 14:19'!\\nwindowOrigin\\n\\t^ (self isCollapsed or: [labelFrame height = 0 \\\"no label\\\"])\\n\\t\\tifTrue: [self displayBox topLeft]\\n\\t\\tifFalse: [self displayBox topLeft - self labelOffset]! !\\n\\n\\n!StandardSystemView methodsFor: 'initialize-release' stamp: 'sw 10/29/1999 12:58'!\\ninitialize \\n\\t\\\"Refer to the comment in View|initialize.\\\"\\n\\tsuper initialize.\\n\\tlabelFrame _ Quadrangle new.\\n\\tlabelFrame region: (Rectangle origin: 0 @ 0 extent: 50 @ self labelHeight).\\n\\tlabelFrame borderWidthLeft: 2 right: 2 top: 2 bottom: 2.\\n\\tself label: nil.\\n\\tisLabelComplemented _ false.\\n\\tminimumSize _ 50 @ 50.\\n\\tmaximumSize _ Display extent.\\n\\tcollapsedViewport _ nil.\\n\\texpandedViewport _ nil.\\n\\tbitsValid _ false.\\n\\tupdatablePanes _ #()! !\\n\\n!StandardSystemView methodsFor: 'initialize-release'!\\nmodel: aModel\\n\\t\\\"Set the receiver's model. For a Standard System View, we also at this time get the default background color set up. 7/30/96 sw\\\"\\n\\tsuper model: aModel.\\n\\tself setDefaultBackgroundColor! !\\n\\n!StandardSystemView methodsFor: 'initialize-release' stamp: 'jm 8/20/1998 18:29'!\\nrelease\\n\\n\\tmodel windowIsClosing.\\n\\tself isCollapsed ifTrue: [savedSubViews do: [:v | v release]].\\n\\tsuper release.\\n! !\\n\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'di 6/16/97 12:30'!\\ncloseBoxFrame\\n\\t^ Rectangle origin: (self labelDisplayBox leftCenter + (10@-5)) extent: (11@11)! !\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'di 6/16/97 12:29'!\\ngrowBoxFrame\\n\\t^ Rectangle origin: (self labelDisplayBox rightCenter + (-22@-5)) extent: (11@11)! !\\n\\n!StandardSystemView methodsFor: 'label access'!\\nlabel\\n\\t\\\"Answer the string that appears in the receiver's label.\\\"\\n\\tlabelText isNil\\n\\t\\tifTrue: [^ 'Untitled' copy]\\n\\t\\tifFalse: [^ labelText asString]! !\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'sw 12/9/1999 17:44'!\\nlabel: aString \\n\\t\\\"Set aString to be the receiver's label.\\\"\\n\\tlabelText _ Paragraph\\n\\t\\t\\twithText: (Text string: ((aString == nil or: [aString isEmpty])\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: ['Untitled' copy]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [aString])\\n\\t\\t\\t\\t\\t\\t\\tattributes: (Array with: TextEmphasis bold))\\n\\t\\t\\tstyle: LabelStyle.\\n\\tinsetDisplayBox == nil ifTrue: [^ self]. \\\"wait for further initialization\\\"\\n\\tself setLabelRegion! !\\n\\n!StandardSystemView methodsFor: 'label access'!\\nlabelColor\\n\\t\\\"Answer the color to use as the background for the receiver's label. By default, this is the same as the background color of the window, but need not be. 7/16/96 sw\\\"\\n\\n\\t^ self backgroundColor! !\\n\\n!StandardSystemView methodsFor: 'label access'!\\nlabelDisplayBox\\n\\t\\\"Answer the rectangle that borders the visible parts of the receiver's label \\n\\ton the display screen.\\\"\\n\\n\\t^ labelFrame region\\n\\t\\talign: labelFrame topLeft\\n\\t\\twith: self windowOrigin! !\\n\\n!StandardSystemView methodsFor: 'label access'!\\nlabelFrame\\n\\t^labelFrame! !\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'sw 12/9/1999 17:47'!\\nlabelHeight\\n\\t^ ((LabelStyle fontAt: 1) height + 4) max: 20! !\\n\\n!StandardSystemView methodsFor: 'label access'!\\nlabelOffset\\n\\t^ 0 @ (self labelHeight-2)! !\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'sr 3/26/2000 04:26'!\\nlabelText\\n\\t^labelText! !\\n\\n!StandardSystemView methodsFor: 'label access'!\\nlabelTextRegion\\n\\tlabelText == nil ifTrue: [^ self labelDisplayBox center extent: 0@0].\\n\\t^ (labelText boundingBox\\n\\t\\t\\talign: labelText boundingBox center\\n\\t\\t\\twith: self labelDisplayBox center)\\n\\t\\tintersect: (self labelDisplayBox insetBy: 35@0)! !\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'di 10/3/97 14:20'!\\nnoLabel\\n\\t\\\"A label of zero height indicates no label\\\"\\n\\tlabelFrame height > 0\\n\\t\\tifTrue: [labelFrame region: (labelFrame bottomLeft + (0@1) extent: labelFrame width@0).\\n\\t\\t\\t\\tlabelFrame borderWidth: 0.\\n\\t\\t\\t\\tself uncacheBits]! !\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'di 6/10/1998 13:18'!\\nrelabel: aString \\n\\t\\\"A new string for the label. Window is assumed to be active.\\n\\tWindow will redisplay only if label bar has to grow.\\\"\\n\\t| oldRegion oldWidth |\\n\\t(model windowReqNewLabel: aString) ifFalse: [^ self].\\n\\toldRegion _ self labelTextRegion.\\n\\toldWidth _ self insetDisplayBox width.\\n\\tself label: aString.\\n\\tDisplay fill: ((oldRegion merge: self labelTextRegion) expandBy: 3@0)\\n\\t\\t\\tfillColor: self labelColor.\\n\\tself insetDisplayBox width = oldWidth\\n\\t\\tifTrue: [self displayLabelText; emphasizeLabel]\\n\\t\\tifFalse: [self uncacheBits; displayEmphasized].\\n! !\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'sw 1/19/2001 20:13'!\\nsetLabel: aLabel\\n\\t\\\"For compatibility with morphic\\\"\\n\\n\\tself relabel: aLabel! !\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'di 10/3/97 13:35'!\\nsetLabelRegion\\n\\t\\\"Always follows view width\\\"\\n\\n\\tlabelFrame region: (0 @ 0 extent: self displayBox width @ self labelHeight).\\n\\tlabelFrame borderWidth: 2! !\\n\\n!StandardSystemView methodsFor: 'label access' stamp: 'sumim 2/8/2002 14:36'!\\nsetLabelTo: aString \\n\\t\\\"Force aString to be the new label of the receiver, bypassing any logic about whether it is acceptable and about propagating information about the change.\\\"\\n\\n\\t| oldRegion oldWidth |\\n\\tself label: aString.\\n\\tself controller isControlActive ifFalse: [^ self].\\n\\toldRegion _ self labelTextRegion.\\n\\toldWidth _ self insetDisplayBox width.\\n\\tDisplay fill: ((oldRegion merge: self labelTextRegion) expandBy: 3@0)\\n\\t\\t\\tfillColor: self labelColor.\\n\\tself insetDisplayBox width = oldWidth\\n\\t\\tifTrue: [self displayLabelText; emphasizeLabel]\\n\\t\\tifFalse: [self uncacheBits; displayEmphasized]! !\\n\\n\\n!StandardSystemView methodsFor: 'object fileIn' stamp: 'RAA 12/20/2000 17:49'!\\nconvertToCurrentVersion: varDict refStream: smartRefStrm\\n\\t\\n\\tupdatablePanes ifNil: [updatablePanes _ #()].\\n\\t^super convertToCurrentVersion: varDict refStream: smartRefStrm.\\n\\n! !\\n\\n\\n!StandardSystemView methodsFor: 'size'!\\nmaximumSize\\n\\t\\\"Answer a point representing the maximum width and height of the \\n\\treceiver.\\\"\\n\\n\\t^maximumSize! !\\n\\n!StandardSystemView methodsFor: 'size'!\\nmaximumSize: aPoint \\n\\t\\\"Set the argument, aPoint, to be the maximum width and height of the \\n\\treceiver.\\\"\\n\\n\\tmaximumSize _ aPoint! !\\n\\n!StandardSystemView methodsFor: 'size'!\\nminimumSize\\n\\t\\\"Answer a point representing the minimum width and height of the \\n\\treceiver.\\\"\\n\\n\\t^minimumSize! !\\n\\n!StandardSystemView methodsFor: 'size'!\\nminimumSize: aPoint \\n\\t\\\"Set the argument, aPoint, to be the minimum width and height of the \\n\\treceiver.\\\"\\n\\n\\tminimumSize _ aPoint! !\\n\\n\\n!StandardSystemView methodsFor: 'testing'!\\ncontainsPoint: aPoint \\n\\t\\\"Refer to the comment in View|containsPoint:.\\\"\\n\\n\\t^(super containsPoint: aPoint) | (self labelContainsPoint: aPoint)! !\\n\\n!StandardSystemView methodsFor: 'testing'!\\nisCollapsed\\n\\t\\\"Answer whether the receiver is collapsed (true) or expanded (false).\\\"\\n\\n\\t^savedSubViews ~~ nil! !\\n\\n!StandardSystemView methodsFor: 'testing'!\\nlabelContainsPoint: aPoint \\n\\t\\\"Answer TRUE if aPoint is in the label box.\\\"\\n\\n\\t^self labelDisplayBox containsPoint: aPoint! !\\n\\n\\n!StandardSystemView methodsFor: 'updating' stamp: 'sw 10/29/1999 12:57'!\\nsetUpdatablePanesFrom: getSelectors\\n\\t| aList aPane |\\n\\t\\\"Set my updatablePanes inst var to the list of panes which are list panes with the given get-list selectors. Order is important here!! Note that the method is robust in the face of panes not found, but a warning is printed in the transcript in each such case\\\"\\n\\n\\taList _ OrderedCollection new.\\n\\tgetSelectors do:\\n\\t\\t[:sel | aPane _ self subViewSatisfying:\\n\\t\\t\\t\\t[:pane | (pane isKindOf: PluggableListView) and: [pane getListSelector == sel]].\\n\\t\\t\\taPane\\n\\t\\t\\t\\tifNotNil:\\n\\t\\t\\t\\t\\t[aList add: aPane]\\n\\t\\t\\t\\tifNil:\\n\\t\\t\\t\\t\\t[Transcript cr; show: 'Warning: view ', sel, ' not found.']].\\n\\tupdatablePanes _ aList asArray! !\\n\\n!StandardSystemView methodsFor: 'updating' stamp: 'sw 10/29/1999 21:20'!\\nupdatablePanes\\n\\t\\\"Answer the list of panes, in order, which might be sent the #verifyContents message upon window activation or expansion.\\\"\\n\\t^ updatablePanes ifNil: [updatablePanes _ #()]! !\\n\\n!StandardSystemView methodsFor: 'updating' stamp: 'sw 1/11/2000 15:30'!\\nupdate: aSymbol\\n\\taSymbol = #relabel\\n\\t\\tifTrue: [^ self setLabelTo: model labelString].\\n\\t^ super update: aSymbol! !\\n\\n\\n!StandardSystemView methodsFor: 'private'!\\nsetTransformation: aTransformation \\n\\t\\\"Override to support label size changes \\\"\\n\\tsuper setTransformation: aTransformation.\\n\\tself label: self label! !\\n\\n!StandardSystemView methodsFor: 'private' stamp: 'di 10/21/1998 16:12'!\\nsubviewWithLongestSide: sideBlock near: aPoint \\n\\t| theSub theSide theLen box |\\n\\ttheLen _ 0.\\n\\tsubViews do:\\n\\t\\t[:sub | box _ sub insetDisplayBox.\\n\\t\\tbox forPoint: aPoint closestSideDistLen:\\n\\t\\t\\t[:side :dist :len |\\n\\t\\t\\t(dist <= 5 and: [len > theLen]) ifTrue:\\n\\t\\t\\t\\t[theSub _ sub.\\n\\t\\t\\t\\ttheSide _ side.\\n\\t\\t\\t\\ttheLen _ len]]].\\n\\tsideBlock value: theSide.\\n\\t^ theSub! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStandardSystemView class\\n\\tinstanceVariableNames: ''!\\n\\n!StandardSystemView class methodsFor: 'class initialization'!\\ncachingBits\\n\\t^ CacheBits! !\\n\\n!StandardSystemView class methodsFor: 'class initialization'!\\ndoCacheBits\\n\\t\\\"StandardSystemView doCacheBits - Enable fast window repaint feature\\\"\\n\\tCacheBits _ true.\\n\\tScheduledControllers unCacheWindows.\\n\\tScheduledControllers restore! !\\n\\n!StandardSystemView class methodsFor: 'class initialization'!\\ndontCacheBits\\n\\t\\\"StandardSystemView dontCacheBits - Disable fast window repaint feature.\\n\\tReturn true iff bits were cached, ie if space was been recovered\\\"\\n\\tCacheBits ifFalse: [^ false].\\n\\tCacheBits _ false.\\n\\tScheduledControllers unCacheWindows.\\n\\t^ true! !\\n\\n!StandardSystemView class methodsFor: 'class initialization' stamp: 'sw 12/6/1999 23:42'!\\ninitialize\\t\\t\\\"StandardSystemView initialize\\\"\\n\\tself doCacheBits.\\n\\tself setLabelStyle! !\\n\\n!StandardSystemView class methodsFor: 'class initialization' stamp: 'nk 9/1/2004 10:26'!\\nsetLabelStyle\\n\\t| aFont |\\n\\t\\\"StandardSystemView setLabelStyle\\\"\\n\\taFont _ Preferences windowTitleFont.\\n\\tLabelStyle _ TextStyle fontArray: { aFont }.\\n\\tLabelStyle gridForFont: 1 withLead: 0! !\\nObject subclass: #StandardToolSet\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tools-Base'!\\n!StandardToolSet commentStamp: '<historical>' prior: 0!\\nMain comment stating the purpose of this class and relevant relationship to other classes.\\n\\nPossible useful expressions for doIt or printIt.\\n\\nStructure:\\n instVar1\\t\\ttype -- comment about the purpose of instVar1\\n instVar2\\t\\ttype -- comment about the purpose of instVar2\\n\\nAny further useful comments about the general approach of this implementation.!\\n\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStandardToolSet class\\n\\tinstanceVariableNames: ''!\\n\\n!StandardToolSet class methodsFor: 'browsing' stamp: 'ar 7/16/2005 15:20'!\\nbrowseChangeSetsWithClass: aClass selector: aSelector\\n\\t\\\"Browse all the change sets with the given class/selector\\\"\\n\\t^ChangeSorter browseChangeSetsWithClass: aClass selector: aSelector! !\\n\\n!StandardToolSet class methodsFor: 'browsing' stamp: 'md 3/10/2006 21:42'!\\nbrowseHierarchy: aClass selector: aSelector\\n\\t\\\"Open a browser\\\"\\n\\t| newBrowser |\\n\\t(aClass == nil) ifTrue: [^ self].\\n\\t(newBrowser := SystemBrowser default new) setClass: aClass selector: aSelector.\\n\\tnewBrowser spawnHierarchy.! !\\n\\n!StandardToolSet class methodsFor: 'browsing' stamp: 'ar 7/17/2005 11:12'!\\nbrowseMessageNames: aString\\n\\t^(MessageNames methodBrowserSearchingFor: aString) openInWorld! !\\n\\n!StandardToolSet class methodsFor: 'browsing' stamp: 'ar 7/17/2005 11:13'!\\nbrowseMessageSet: messageList name: title autoSelect: autoSelectString\\n\\t\\\"Open a message set browser\\\"\\n\\t^MessageSet\\n\\t\\topenMessageList: messageList \\n\\t\\tname: title \\n\\t\\tautoSelect: autoSelectString! !\\n\\n!StandardToolSet class methodsFor: 'browsing' stamp: 'ar 7/17/2005 11:35'!\\nbrowseVersionsOf: aClass selector: aSelector\\n\\t\\\"Open a browser\\\"\\n\\tVersionsBrowser\\n\\t\\tbrowseVersionsOf: (aClass compiledMethodAt: aSelector)\\n\\t\\tclass: aClass theNonMetaClass\\n\\t\\tmeta: aClass isMeta\\n\\t\\tcategory: (aClass organization categoryOfElement: aSelector)\\n\\t\\tselector: aSelector! !\\n\\n!StandardToolSet class methodsFor: 'browsing' stamp: 'md 3/10/2006 21:43'!\\nbrowse: aClass selector: aSelector\\n\\t\\\"Open a browser\\\"\\n\\t^SystemBrowser default fullOnClass: aClass selector: aSelector! !\\n\\n!StandardToolSet class methodsFor: 'browsing' stamp: 'ar 7/15/2005 18:58'!\\nopenChangedMessageSet: aChangeSet\\n\\t\\\"Open a ChangedMessageSet for aChangeSet\\\"\\n\\tChangedMessageSet openFor: aChangeSet! !\\n\\n!StandardToolSet class methodsFor: 'browsing' stamp: 'ar 7/15/2005 18:58'!\\nopenClassListBrowser: anArray title: aString\\n\\t\\\"Open a class list browser\\\"\\n\\t^ClassListBrowser new initForClassesNamed: anArray title: aString\\n! !\\n\\n\\n!StandardToolSet class methodsFor: 'class initialization' stamp: 'ar 7/17/2005 01:04'!\\ninitialize\\n\\tToolSet register: self.\\n\\tPreferences installMissingWindowColors.! !\\n\\n!StandardToolSet class methodsFor: 'class initialization' stamp: 'ar 7/16/2005 16:18'!\\nunload\\n\\tToolSet unregister: self.! !\\n\\n\\n!StandardToolSet class methodsFor: 'debugging' stamp: 'ar 7/15/2005 19:15'!\\ndebugContext: aContext label: aString contents: contents\\n\\t\\\"Open a debugger on the given process and context.\\\"\\n\\t^Debugger openContext: aContext label: aString contents: contents! !\\n\\n!StandardToolSet class methodsFor: 'debugging' stamp: 'ar 7/17/2005 11:16'!\\ndebugError: anError\\n\\t\\\"Handle an otherwise unhandled error\\\"\\n\\t^Processor activeProcess\\n\\t\\tdebug: anError signalerContext\\n\\t\\ttitle: anError description! !\\n\\n!StandardToolSet class methodsFor: 'debugging' stamp: 'ar 9/27/2005 19:18'!\\ndebugSyntaxError: anError\\n\\t\\\"Handle a syntax error\\\"\\n\\t| notifier |\\n\\tnotifier := SyntaxError new\\n\\t\\tsetClass: anError errorClass\\n\\t\\tcode: anError errorCode\\n\\t\\tdebugger: (Debugger context: anError signalerContext)\\n\\t\\tdoitFlag: anError doitFlag.\\n\\tnotifier category: anError category.\\n\\tSyntaxError open: notifier.! !\\n\\n!StandardToolSet class methodsFor: 'debugging' stamp: 'ar 7/15/2005 18:57'!\\ndebug: aProcess context: aContext label: aString contents: contents fullView: aBool\\n\\t\\\"Open a debugger on the given process and context.\\\"\\n\\t^Debugger openOn: aProcess context: aContext label: aString contents: contents fullView: aBool! !\\n\\n!StandardToolSet class methodsFor: 'debugging' stamp: 'ar 7/17/2005 11:16'!\\ninterrupt: aProcess label: aString\\n\\t\\\"Open a debugger on the given process and context.\\\"\\n\\tDebugger\\n\\t\\topenInterrupt: aString\\n\\t\\tonProcess: aProcess! !\\n\\n\\n!StandardToolSet class methodsFor: 'inspecting' stamp: 'ar 7/15/2005 18:57'!\\nbasicInspect: anObject\\n\\t\\\"Open an inspector on the given object. The tool set must know which inspector type to use for which object - the object cannot possibly know what kind of inspectors the toolset provides.\\\"\\n\\t^BasicInspector openOn: anObject! !\\n\\n!StandardToolSet class methodsFor: 'inspecting' stamp: 'ar 7/15/2005 19:34'!\\nexplore: anObject\\n\\t\\\"Open an explorer on the given object.\\\"\\n\\t^ObjectExplorer new openExplorerFor: anObject! !\\n\\n!StandardToolSet class methodsFor: 'inspecting' stamp: 'ar 7/15/2005 19:54'!\\ninspectorClassOf: anObject\\n\\t\\\"Answer the inspector class for the given object. The tool set must know which inspector type to use for which object - the object cannot possibly know what kind of inspectors the toolset provides.\\\"\\n\\t| map |\\n\\tmap := Dictionary new.\\n\\t#(\\n\\t\\t(CompiledMethod\\t\\tCompiledMethodInspector)\\n\\t\\t(CompositeEvent\\t\\tOrderedCollectionInspector)\\n\\t\\t(Dictionary\\t\\t\\tDictionaryInspector)\\n\\t\\t(ExternalStructure\\tExternalStructureInspector)\\n\\t\\t(FloatArray\\t\\t\\tOrderedCollectionInspector)\\n\\t\\t(OrderedCollection\\tOrderedCollectionInspector)\\n\\t\\t(Set\\t\\t\\t\\t\\tSetInspector)\\n\\t\\t(WeakSet\\t\\t\\tWeakSetInspector)\\n\\t) do:[:spec|\\n\\t\\tmap at: spec first put: spec last.\\n\\t].\\n\\tanObject class withAllSuperclassesDo:[:cls|\\n\\t\\tmap at: cls name ifPresent:[:inspectorName| ^Smalltalk classNamed: inspectorName].\\n\\t].\\n\\t^Inspector! !\\n\\n!StandardToolSet class methodsFor: 'inspecting' stamp: 'ar 7/15/2005 18:58'!\\ninspect: anObject\\n\\t\\\"Open an inspector on the given object. The tool set must know which inspector type to use for which object - the object cannot possibly know what kind of inspectors the toolset provides.\\\"\\n\\t^(self inspectorClassOf: anObject) openOn: anObject! !\\n\\n!StandardToolSet class methodsFor: 'inspecting' stamp: 'ar 7/15/2005 19:57'!\\ninspect: anObject label: aString\\n\\t\\\"Open an inspector on the given object. The tool set must know which inspector type to use for which object - the object cannot possibly know what kind of inspectors the toolset provides.\\\"\\n\\t^(self inspectorClassOf: anObject) openOn: anObject withEvalPane: true withLabel: aString! !\\n\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'ar 7/17/2005 13:19'!\\nmenuItems\\n\\t\\\"Answer the menu items available for this tool set\\\"\\n\\t^#(\\n\\t\\t('class browser' \\t\\t\\t#openClassBrowser)\\n\\t\\t('workspace'\\t\\t\\t\\t#openWorkspace)\\n\\t\\t('file list'\\t\\t\\t\\t\\t#openFileList)\\n\\t\\t('package pane browser' \\t#openPackagePaneBrowser)\\n\\t\\t('process browser' \\t\\t\\t#openProcessBrowser)\\n\\t\\t-\\n\\t\\t('method finder'\\t\\t\\t\\t#openSelectorBrowser)\\n\\t\\t('message names'\\t\\t\\t#openMessageNames)\\n\\t\\t-\\n\\t\\t('simple change sorter'\\t\\t#openChangeSorter)\\n\\t\\t('dual change sorter'\\t\\t#openDualChangeSorter)\\n\\t)\\n! !\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'ar 7/17/2005 13:05'!\\nopenChangeSorter\\n\\tChangeSorter new morphicWindow openInWorld! !\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'md 3/10/2006 21:47'!\\nopenClassBrowser\\n\\tSystemBrowser default open! !\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'ar 7/17/2005 13:05'!\\nopenDualChangeSorter\\n\\tDualChangeSorter new morphicWindow openInWorld! !\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'md 2/24/2006 15:21'!\\nopenFileList\\n\\tFileList2 prototypicalToolWindow openInWorld.! !\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'ar 7/17/2005 12:59'!\\nopenMessageNames\\n\\t\\\"Bring a MessageNames tool to the front\\\"\\n\\tMessageNames openMessageNames! !\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'ar 7/17/2005 13:04'!\\nopenPackagePaneBrowser\\n\\tPackagePaneBrowser openBrowser.! !\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'ar 7/17/2005 12:59'!\\nopenProcessBrowser\\n\\tProcessBrowser open! !\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'ar 7/17/2005 13:00'!\\nopenSelectorBrowser\\n\\tSelectorBrowser new morphicWindow openInWorld! !\\n\\n!StandardToolSet class methodsFor: 'menu' stamp: 'md 1/18/2006 19:08'!\\nopenWorkspace\\n\\tWorkspace open! !\\nViewer subclass: #StandardViewer\\n\\tinstanceVariableNames: 'firstPanel'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting'!\\n!StandardViewer commentStamp: 'sw 8/17/2002 02:04' prior: 0!\\nA structure that allows you to view state and behavior of an object; it consists of a header and then any number of CategoryViewers.!\\n\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 12/28/1998 15:22'!\\naddCategoryViewer\\t\\n\\tself addCategoryViewerFor: self likelyCategoryToShow! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 8/23/2002 14:50'!\\naddCategoryViewerFor: categoryInfo\\n\\t\\\"Add a category viewer for the given category info\\\"\\n\\n\\tself addCategoryViewerFor: categoryInfo atEnd: true! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 8/23/2002 14:56'!\\naddCategoryViewerFor: categoryInfo atEnd: atEnd\\n\\t\\\"Add a category viewer for the given category info. If atEnd is true, add it at the end, else add it just after the header morph\\\"\\n\\n\\t| aViewer |\\n\\taViewer _ self categoryViewerFor: categoryInfo.\\n\\tatEnd\\n\\t\\tifTrue:\\n\\t\\t\\t[self addMorphBack: aViewer]\\n\\t\\tifFalse:\\n\\t\\t\\t[self addMorph: aViewer after: submorphs first].\\n\\taViewer establishContents.\\n\\tself world ifNotNil: [self world startSteppingSubmorphsOf: aViewer].\\n\\tself fitFlap! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 8/23/2002 14:18'!\\naddSearchPane\\n\\t\\\"Add a search pane\\\"\\n\\n\\tself addCategoryViewerFor: #(search '') atEnd: false! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 11/18/1999 16:00'!\\ncategoriesCurrentlyShowing\\n\\t^ self categoryMorphs collect: [:m | m currentCategory]! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 10/30/1998 18:38'!\\ncategoryMorphs\\n\\t^ self submorphsSatisfying: [:m | m isKindOf: CategoryViewer]! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'gm 2/22/2003 13:01'!\\ncategoryViewerFor: categoryInfo \\n\\t\\\"Answer a category viewer for the given category info\\\"\\n\\n\\t| aViewer |\\n\\taViewer := ((categoryInfo isCollection) \\n\\t\\t\\t\\tand: [categoryInfo first == #search]) \\n\\t\\t\\t\\t\\tifFalse: [CategoryViewer new]\\n\\t\\t\\t\\t\\tifTrue: [SearchingViewer new].\\n\\taViewer initializeFor: scriptedPlayer categoryChoice: categoryInfo.\\n\\t^aViewer! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 8/3/2001 18:22'!\\nchooseLimitClass\\n\\t\\\"Put up a menu allowing the user to choose the most generic class to show\\\"\\n\\n\\t| aMenu limitClass |\\n\\taMenu _ MenuMorph new defaultTarget: self.\\n\\tlimitClass _ self limitClass.\\n\\tscriptedPlayer class withAllSuperclasses do:\\n\\t\\t[:aClass | \\n\\t\\t\\taClass == ProtoObject\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[aMenu addLine].\\n\\t\\t\\taMenu add: aClass name selector: #setLimitClass: argument: aClass.\\n\\t\\t\\taClass == limitClass ifTrue:\\n\\t\\t\\t\\t[aMenu lastItem color: Color red].\\n\\t\\t\\taClass == limitClass ifTrue: [aMenu addLine]].\\n\\taMenu addTitle: 'Show only methods\\nimplemented at or above...'. \\\"heh heh -- somebody please find nice wording here!!\\\"\\n\\taMenu popUpInWorld: self currentWorld! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'ka 11/29/2005 20:53'!\\nlikelyCategoryToShow\\n\\t\\\"Choose a category to show based on what's already showing and on some predefined heuristics\\\"\\n\\n\\t| possible all aCat currVocab |\\n\\tall := (scriptedPlayer categoriesForViewer: self) asOrderedCollection.\\n\\tpossible _ all copy.\\n\\n\\tcurrVocab := self currentVocabulary.\\n\\tself categoryMorphs do: \\n\\t\\t\\t[:m | \\n\\t\\t\\taCat := currVocab categoryWhoseTranslatedWordingIs: m currentCategory.\\n\\t\\t\\taCat ifNotNil: [possible remove: aCat wording ifAbsent: []]].\\n\\n\\t(possible includes: ScriptingSystem nameForInstanceVariablesCategory translated) ifTrue:\\n\\t\\t[^ ScriptingSystem nameForInstanceVariablesCategory].\\n\\n\\t(currVocab isEToyVocabulary) \\n\\t\\tifTrue: \\n\\t\\t\\t[(possible includes: ScriptingSystem nameForScriptsCategory translated) \\n\\t\\t\\t\\tifTrue: [^ ScriptingSystem nameForScriptsCategory]].\\n\\t{'kedama' translated. #basic translated} \\n\\t\\tdo: [:preferred | (possible includes: preferred) ifTrue: [^ preferred]].\\n\\t((scriptedPlayer isPlayerLike) \\n\\t\\tand: [scriptedPlayer hasOnlySketchCostumes]) \\n\\t\\t\\tifTrue: [(possible includes: #tests translated) ifTrue: [^#tests translated]].\\n\\t{#'color & border' translated. #tests translated. #color translated. #flagging translated. #comparing translated.} \\n\\t\\tdo: [:preferred | (possible includes: preferred) ifTrue: [^ preferred]].\\n\\t^ possible isEmpty ifFalse: [possible first] ifTrue: [all first]! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 8/3/2001 18:17'!\\nlimitClass\\n\\t\\\"Answer the limit class to use in this viewer\\\"\\n\\n\\t| aClass |\\n\\t(aClass _ self valueOfProperty: #limitClass) ifNotNil:\\n\\t\\t[^ aClass].\\n\\n\\taClass _ scriptedPlayer defaultLimitClassForVocabulary: self currentVocabulary.\\n\\tself setProperty: #limitClass toValue: aClass.\\n\\t^ aClass! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 8/3/2001 18:31'!\\nlimitClass: aClass\\n\\t\\\"Set aClass as the limit class for this viewer, without side effects\\\"\\n\\n\\tself setProperty: #limitClass toValue: aClass\\n! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 12/11/2000 10:51'!\\nouterViewer\\n\\t\\\"Answer the StandardViewer or equivalent that contains this object\\\"\\n\\n\\t^ self! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'di 2/19/2001 10:39'!\\nrecreateCategories\\n\\t\\\"To change from old to new tiles\\\"\\n\\t| cats |\\n\\tcats _ self categoriesCurrentlyShowing.\\n\\tself removeAllMorphsIn: self categoryMorphs.\\n\\tcats do: [:cat | self addCategoryViewerFor: cat]! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'yo 4/4/2005 14:42'!\\nsearchingViewerMorphs\\n\\t^ self submorphsSatisfying: [:m | m isKindOf: SearchingViewer].! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 8/3/2001 18:31'!\\nsetLimitClass: aClass\\n\\t\\\"Set aClass as the limit class for this viewer\\\"\\n\\n\\tself limitClass: aClass.\\n\\tself relaunchViewer\\n! !\\n\\n!StandardViewer methodsFor: 'categories' stamp: 'sw 5/29/2001 22:43'!\\nsymbolsOfCategoriesCurrentlyShowing\\n\\t\\\"Answer the category symbols of my categoryMorphs\\\"\\n\\n\\t^ self categoryMorphs collect: [:m | m chosenCategorySymbol]! !\\n\\n\\n!StandardViewer methodsFor: 'classification' stamp: 'ar 6/30/2001 13:13'!\\nisStandardViewer\\n\\t^true! !\\n\\n\\n!StandardViewer methodsFor: 'debug and other' stamp: 'sw 6/20/2001 12:47'!\\nviewMorphDirectly\\n\\t\\\"Launch a new viewer to replace the receiver.\\\"\\n\\n\\tself delete.\\n\\tself presenter viewObjectDirectly: scriptedPlayer costume renderedMorph! !\\n\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'nk 9/2/2004 11:30'!\\naddHeaderMorphWithBarHeight: anInteger includeDismissButton: aBoolean\\n\\t\\\"Add the header morph to the receiver, using anInteger as a guide for its height, and if aBoolean is true, include a dismiss buton for it\\\"\\n\\n\\t| header aFont aButton aTextMorph nail wrpr costs headWrapper |\\n\\theader _ AlignmentMorph newRow color: self color muchLighter; wrapCentering: #center; cellPositioning: #leftCenter.\\n\\taFont _ Preferences standardButtonFont.\\n\\taBoolean ifTrue:\\n\\t\\t[aButton _ self tanOButton.\\n\\t\\theader addMorph: aButton.\\n\\t\\taButton target: self;\\n\\t\\t\\t\\tactionSelector: #dismiss;\\n\\t\\t\\t\\tsetBalloonText: 'remove this entire Viewer from the screen\\ndon''t worry -- nothing will be lost!!.' translated.\\n\\t\\theader addTransparentSpacerOfSize: 4@1].\\n\\n\\taButton _ IconicButton new borderWidth: 0;\\n\\t\\t\\tlabelGraphic: (ScriptingSystem formAtKey: #AddCategoryViewer); color: Color transparent; \\n\\t\\t\\tactWhen: #buttonDown;\\n\\t\\t\\ttarget: self;\\n\\t\\t\\tactionSelector: #addCategoryViewer;\\n\\t\\t\\tsetBalloonText: 'click here to add\\nanother category pane' translated;\\n\\t\\t\\tshedSelvedge.\\n\\theader addMorphBack: aButton.\\n\\theader addTransparentSpacerOfSize: 4@1.\\n\\n\\tcosts _ scriptedPlayer costumes.\\n\\tcosts ifNotNil:\\n\\t[(costs size > 1 or: [costs size = 1 and: [costs first ~~ scriptedPlayer costume]]) ifTrue:\\n\\t\\t[header addUpDownArrowsFor: self.\\n\\t\\t(wrpr _ header submorphs last) submorphs second setBalloonText: 'switch to previous costume' translated.\\t\\n\\t\\twrpr submorphs first setBalloonText: 'switch to next costume' translated]].\\t\\n\\n\\tnail _ (self hasProperty: #noInteriorThumbnail)\\n\\t\\tifFalse:\\n\\t\\t\\t[ThumbnailMorph new objectToView: scriptedPlayer viewSelector: #costume]\\n\\t\\tifTrue:\\n\\t\\t\\t[ImageMorph new image: Cursor menu].\\n\\tnail on: #mouseDown send: #offerViewerMenuForEvt:morph: to: scriptedPlayer.\\n\\theader addMorphBack: nail.\\n\\tnail setBalloonText: 'click here to get a menu\\nthat will allow you to\\nadd a variable,\\ntear off a tile, etc..' translated.\\n\\t(self hasProperty: #noInteriorThumbnail)\\n\\t\\tifFalse:\\n\\t\\t\\t[nail borderWidth: 3; borderColor: #raised].\\n\\n\\theader addTransparentSpacerOfSize: 5@5.\\n\\n\\\"\\taButton _ SimpleButtonMorph new target: self; actionSelector: #newEmptyScript; label: 'S' translated font: (aFont _ StrikeFont familyName: #ComicBold size: 16); color: Color transparent; borderWidth: 0; actWhen: #buttonDown.\\n\\taButton setBalloonText: 'drag from here to\\ncreate a new script\\nfor this object' translated.\\t\\n\\theader addMorphBack: aButton.\\n\\n\\theader addTransparentSpacerOfSize: 8@5.\\\"\\n\\t\\n\\taButton _ SimpleButtonMorph new target: scriptedPlayer; actionSelector: #addInstanceVariable; label: 'v' translated font: (aFont emphasized: 1); color: Color transparent; borderWidth: 1; actWhen: #buttonUp.\\n\\t\\\"aButton firstSubmorph color: Color gray.\\\"\\n\\taButton setBalloonText: 'click here to add a variable\\nto this object.' translated.\\n\\theader addMorphBack: aButton.\\n\\n\\theader addTransparentSpacerOfSize: 5@5.\\n\\tself viewsMorph ifTrue: [scriptedPlayer costume assureExternalName].\\n\\taTextMorph _ UpdatingStringMorph new\\n\\t\\tuseStringFormat;\\n\\t\\ttarget: scriptedPlayer;\\n\\t\\tgetSelector: #nameForViewer;\\n\\t\\tsetNameTo: 'name';\\n\\t\\tfont: ScriptingSystem fontForNameEditingInScriptor.\\n\\tself viewsMorph ifTrue:\\n\\t\\t[aTextMorph putSelector: #setName:.\\n\\t\\taTextMorph setProperty: #okToTextEdit toValue: true].\\n\\taTextMorph step.\\n\\theader addMorphBack: aTextMorph.\\n\\taTextMorph setBalloonText: 'Click here to edit the player''s name.' translated.\\t\\n\\n\\theader beSticky.\\n\\tanInteger > 0\\n\\t\\tifTrue:\\n\\t\\t\\t[headWrapper _ AlignmentMorph newColumn color: self color.\\n\\t\\t\\theadWrapper addTransparentSpacerOfSize: (0 @ anInteger).\\n\\t\\t\\theadWrapper addMorphBack: header.\\n\\t\\t\\tself addMorph: headWrapper]\\n\\t\\tifFalse:\\n\\t\\t\\t[self addMorph: header]! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'gm 2/22/2003 13:44'!\\naffordsUniclass\\n\\t\\\"Answer true iff the receiver operates on behalf of an object that is, or could become, a member of a Uniclass\\\"\\n\\n\\t| viewee |\\n\\t^(viewee := self objectViewed) belongsToUniClass or: \\n\\t\\t\\t[((viewee isInteger) not and: [viewee isBehavior not]) \\n\\t\\t\\t\\tand: [self userLevel > 0]]! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'ar 6/30/2001 13:23'!\\nfitFlap\\n\\t(owner notNil and:[owner isFlap]) ifTrue:[\\n\\t\\towner width < self fullBounds width ifTrue:[\\n\\t\\t\\towner assureFlapWidth: self fullBounds width + 25.\\n\\t\\t].\\n\\t].! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'sw 12/23/1998 23:26'!\\ninitialHeightToAllow\\n\\t^ 300! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'sw 6/25/1999 23:04'!\\ninitializeFor: aPlayer barHeight: anInteger\\n\\t^ self initializeFor: aPlayer barHeight: anInteger includeDismissButton: true! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'sw 8/4/2000 13:02'!\\ninitializeFor: aPlayer barHeight: anInteger includeDismissButton: aBoolean\\n\\tself initializeFor: aPlayer barHeight: anInteger includeDismissButton: aBoolean showCategories: nil! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'yo 8/18/2005 13:43'!\\ninitializeFor: aPlayer barHeight: anInteger includeDismissButton: aBoolean showCategories: categoryInfo\\n\\t\\\"Initialize the receiver to be a look inside the given Player. The categoryInfo, if present, describes which categories should be present in it, in which order\\\"\\n\\n\\tscriptedPlayer _ aPlayer.\\n\\tself listDirection: #topToBottom;\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tborderWidth: 1.\\n\\tself color: self standardViewerColor.\\n\\tself addHeaderMorphWithBarHeight: anInteger includeDismissButton: aBoolean.\\n\\n\\tcategoryInfo isEmptyOrNil\\n\\t\\tifFalse: \\\"Reincarnating an pre-existing list\\\"\\n\\t\\t\\t[categoryInfo do:\\n\\t\\t\\t\\t[:aCat | self addCategoryViewerFor: aCat]]\\n\\t\\tifTrue: \\\"starting fresh\\\"\\n\\t\\t\\t[self addSearchPane. \\n\\t\\t\\tself addCategoryViewer.\\n\\t\\t\\tself addCategoryViewer.\\n\\t\\t\\t(scriptedPlayer costume isMemberOf: KedamaMorph) ifTrue: [self addCategoryViewer].\\n\\t\\t].! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'sw 6/4/2001 18:06'!\\nrawVocabulary: aVocabulary\\n\\t\\\"Mark the receiver as having aVocabulary as its vocabulary\\\"\\n\\n\\tself setProperty: #currentVocabularySymbol toValue: aVocabulary vocabularyName! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'nk 8/29/2004 17:18'!\\nswitchToVocabulary: aVocabulary\\n\\t\\\"Make the receiver show categories and methods as dictated by aVocabulary. If this constitutes a switch, then wipe out existing category viewers, which may be showing the wrong thing.\\\"\\n\\n\\tself adoptVocabulary: aVocabulary. \\\"for benefit of submorphs\\\"\\n\\tself setProperty: #currentVocabularySymbol toValue: aVocabulary vocabularyName.\\n\\t((scriptedPlayer isPlayerLike) and: [self isUniversalTiles not]) ifTrue:\\n\\t\\t[scriptedPlayer allScriptEditors do:\\n\\t\\t\\t[:aScriptEditor |\\n\\t\\t\\t\\taScriptEditor adoptVocabulary: aVocabulary]]! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'sw 6/4/2001 19:40'!\\nuseVocabulary: aVocabulary\\n\\t\\\"Make the receiver show categories and methods as dictated by aVocabulary\\\"\\n\\n\\t| itsName |\\n\\t((self valueOfProperty: #currentVocabularySymbol ifAbsent: [nil]) == (itsName _ aVocabulary vocabularyName)) ifFalse:\\n\\t\\t[self setProperty: #currentVocabularySymbol toValue: itsName.\\n\\t\\tself removeProperty: #currentVocabulary. \\\"grandfathered\\\"\\n\\t\\t(self submorphs select: [:m | m isKindOf: CategoryViewer]) do: [:m | m delete]]! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'sw 10/26/2000 09:42'!\\nuserLevel\\n\\t\\\"Answer the user level for this viewer, which can be used in figuring out what to display in the viewer. Initially, we make little use of this, but in past prototypes, and in future deployments, it may be handy.\\\"\\n\\n\\t^ self valueOfProperty: #userLevel ifAbsent: [1]! !\\n\\n!StandardViewer methodsFor: 'initialization' stamp: 'nk 8/29/2004 17:18'!\\nviewsMorph\\n\\t\\\"Answer whether the receiver views a morph. Traditional viewers up until late 2000 *all* viewed morphs (as per the morph/player architecture), but viewers on non-morph/players have now become possible\\\"\\n\\n\\t^ scriptedPlayer isPlayerLike! !\\n\\n\\n!StandardViewer methodsFor: 'macpal' stamp: 'sw 6/4/2001 18:05'!\\ncurrentVocabulary\\n\\t\\\"Answer the vocabulary currently associated with the receiver\\\"\\n\\n\\t| aSym aVocab |\\n\\taSym _ self valueOfProperty: #currentVocabularySymbol ifAbsent: [nil].\\n\\taSym ifNil:\\n\\t\\t[aVocab _ self valueOfProperty: #currentVocabulary ifAbsent: [nil].\\n\\t\\taVocab ifNotNil:\\n\\t\\t\\t[aSym _ aVocab vocabularyName.\\n\\t\\t\\tself removeProperty: #currentVocabulary.\\n\\t\\t\\tself setProperty: #currentVocabularySymbol toValue: aSym]].\\n\\t^ aSym\\n\\t\\tifNotNil:\\n\\t\\t\\t[Vocabulary vocabularyNamed: aSym]\\n\\t\\tifNil:\\n\\t\\t\\t[(self world ifNil: [ActiveWorld]) currentVocabularyFor: scriptedPlayer]! !\\n\\n\\n!StandardViewer methodsFor: 'user interface' stamp: 'sw 10/25/1999 22:08'!\\ndismiss\\n\\t| aFlapTab |\\n\\t\\\"User hit the dismiss button.\\\"\\n\\t(owner isKindOf: TabbedPalette)\\n\\t\\tifTrue:\\n\\t\\t\\t[^ owner showNoPalette].\\n\\t(aFlapTab _ self pasteUpMorph correspondingFlapTab) ifNotNil:\\n\\t\\t[^ aFlapTab dismissViaHalo].\\n\\tself topRendererOrSelf delete! !\\n\\n!StandardViewer methodsFor: 'user interface' stamp: 'sw 10/24/1998 14:34'!\\ndownArrowHit\\n\\tself nextCostume! !\\n\\n!StandardViewer methodsFor: 'user interface' stamp: 'sw 10/26/1999 01:07'!\\nhasDismissButton\\n\\tsubmorphs isEmptyOrNil ifTrue: [^ false].\\n\\t^ (submorphs first allMorphs detect:\\n\\t\\t[:possible | (possible isKindOf: SimpleButtonMorph) and: [possible actionSelector == #dismiss]]\\n\\t\\t\\tifNone: [nil]) notNil! !\\n\\n!StandardViewer methodsFor: 'user interface' stamp: 'sw 5/18/2001 10:46'!\\nopenLexicon\\n\\t\\\"Open a lexicon browser on the receiver, showing its current vocabulary\\\"\\n\\n\\t| littleHim | \\n\\tlittleHim _ scriptedPlayer assureUniClass.\\n\\n\\t(InstanceBrowser new useVocabulary: self currentVocabulary) openOnObject: littleHim inWorld: ActiveWorld showingSelector: nil! !\\n\\n!StandardViewer methodsFor: 'user interface' stamp: 'sw 4/20/2001 21:22'!\\nrelaunchViewer\\n\\t\\\"Launch a new viewer to replace the receiver.\\\"\\n\\n\\tself presenter updateViewer: self forceToShow: nil! !\\n\\n!StandardViewer methodsFor: 'user interface' stamp: 'sw 12/23/1998 22:45'!\\nstandardViewerColor\\n\\t ^ Color r: 0.572 g: 0.883 b: 0.572! !\\n\\n!StandardViewer methodsFor: 'user interface' stamp: 'sw 10/24/1998 14:33'!\\nupArrowHit\\n\\tself previousCostume! !\\nPolygonMorph subclass: #StarMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Widgets'!\\n!StarMorph commentStamp: 'wiz 9/6/2005 12:30' prior: 0!\\nI am a very flexible star..\\n\\nGrab me from the supplies flap or from the graphic objects.\\nAdd my handles and you can move and resize me.\\nThe up and down arrows increase or reduce the number of my sides.\\nThe right and left arrows cycle thru different amounts of pointiness.\\n\\n\\nUse the arrows right and left of my center or get stars with a specific amount of pointyness. The left side goes from fat to thin and then cycles around again. The right goes from thin to fat. Hold down the shift key if you wish to stop the cycling at the extremes.\\n\\nUse the arrows up and down to change the number of sides if you would like a different number of points.\\n\\nTo add or remove just one side hold the shift key down as you use the arrows or use the menu items for that purpose.\\n\\n\\nIf you add or remove just one point I will have an odd number of sides. When that happens I can only look like a regular polygon. The right and left arrows will have no effect. Add or remove just one more side and you can shift drag the outer handle or use the arrows to restore my pointiness. \\n\\nThat was too complicated. It is gone. You can get regular polygon shapes by adjusting my pointiness. For example the extreme of a five pointed star is a dodecahedron (10 sided regular polygon) and one step less extreme is a pentagon (5 sided regular polygon).\\n\\n\\nAt some time you will probably shift drag the outer handle thru the center handle.\\nWhile I looked round as you shrunk me, I will look very much like an asterisk as you pull me away. What happens is that inside bend shrunk on the way down because it can never be larger than the outer point (or it wouldn't be the innerbend would it).\\nBut on the way out it is perfectly happy to remain small. So I look like an asterisk.\\n\\nTo fatten me up (if you haven't already figured this out by fooling around) hold the shift down an move the outer handle towards the center (but not quite all the way) then let the shift up and move the outer handle away. A couple of cycles like this and I'll be looking fat and jolly again. Or you can now just use the right arrow to make me fatter.\\n\\nThis is also the reason I don't let the inside bend get larger than the outer point.\\nIf I did the same process that fattened me when I was an asterisk would also grow an asterisk so large squeak would complain about not having enough memory.\\n\\nHistorical note:\\n\\nThe former star had two bugs that are fixed here.\\nThe outer handle now no longer jumps from one point to another.\\nThe other bug prevented some higher order stars from looking right. \\nWhich is why the former star didn't allow you to change the number of points. !\\n\\n\\n!StarMorph methodsFor: 'access' stamp: 'wiz 1/11/2005 03:58'!\\nskipRatios\\n\\\"Return an array of ratios of the inner radius to the outer radius.\\nRatios are in ascending order from 0.0 to 1.0.\\\"\\n\\\"Assume we have at least one vertex.\\nAll ways return a number <= 1.0\\\"\\n\\n| n alpha |\\n\\\"Odd vertices sizes can not be stars only regular polygons\\\"\\nn:= vertices size . n odd ifTrue: [ ^ #( 1.0) ] .\\n\\nalpha := Float pi / (n//2) asFloat .\\n\\n^ (((( Float halfPi -alpha to: alpha /2.0 by: alpha negated ) \\n\\tcollect: [:angle |( (angle) sin )/\\n\\t\\t\\t\\t\\t(angle + alpha ) sin ]\\n\\t) copyWith: 0.0) copyWithFirst: 1.0) reversed .! !\\n\\n!StarMorph methodsFor: 'access' stamp: 'wiz 1/4/2005 20:14'!\\nstarRatio\\n\\\"Return the ratio of the inner radius to the outer radius.\\\"\\n\\\"Assume we have at least one vertex.\\nAll ways return a number <= 1.0\\\"\\n| r c |\\nc := vertices average rounded .\\nr := (c dist: vertices last) / (c dist: vertices first) .\\n^ r > 1.0 ifTrue: [ r reciprocal ] ifFalse: [r ] .! !\\n\\n\\n!StarMorph methodsFor: 'accessing' stamp: 'wiz 1/4/2005 19:47'!\\nstarRatio: r\\n\\\"Set the star s.t. the ratio of the inner radius to the outer radius is r.\\nIf r is > 1 use the reciprocal to keep the outer radius first.\\\"\\n\\\"Assume we have at least one vertex.\\nset\\nAll ways return a number <= 1.0\\\"\\nself makeVertices: vertices size starRatio:( r > 1.0 ifTrue: [ r reciprocal ] ifFalse: [r ] ).! !\\n\\n\\n!StarMorph methodsFor: 'editing' stamp: 'wiz 12/15/2004 00:59'!\\naddHandles\\n\\tself addStarHandles! !\\n\\n!StarMorph methodsFor: 'editing' stamp: 'wiz 1/15/2005 00:20'!\\naddStarHandles\\n\\t\\\"Outer handle must not be blocked so it comes first. \\n\\tThe editing routine expects to find the center handle second.\\n\\tThe side and shape changing handles follow these.\\\"\\n\\t| center |\\n\\tself removeHandles.\\n\\t\\\"Check for old stars and correct order of vertices.\\\"\\n\\tself insureCompatability .\\n\\thandles := OrderedCollection new.\\n\\tcenter := vertices average rounded.\\n\\tself withCenterOuterHandles; withUpDownLeftRightHandlesAround: 6 center: center.\\n\\tself placeHandles.\\n\\tself changed.\\n\\t! !\\n\\n!StarMorph methodsFor: 'editing' stamp: 'wiz 9/5/2005 23:12'!\\nchangeVertices: label event: evt fromHandle: handle \\n\\t| |\\n\\tlabel == #more\\n\\t\\tifTrue: [evt shiftPressed\\n\\t\\t\\t\\tifTrue: [self moreVertices \\\"not oneMoreVertex\\\"]\\n\\t\\t\\t\\tifFalse: [self moreVertices]].\\n\\tlabel == #less\\n\\t\\tifTrue: [evt shiftPressed\\n\\t\\t\\t\\tifTrue: [self lessVertices \\\"not oneLessVertex\\\"]\\n\\t\\t\\t\\tifFalse: [self lessVertices]].\\n\\tlabel == #next\\n\\t\\tifTrue: [evt shiftPressed\\n\\t\\t\\t\\tifTrue: [self makeVertices: vertices size starRatio: self nextSkip]\\n\\t\\t\\t\\tifFalse: [self makeVertices: vertices size starRatio: self nextTwinkleSkip]].\\n\\tlabel == #prev\\n\\t\\tifTrue: [evt shiftPressed\\n\\t\\t\\t\\tifTrue: [self makeVertices: vertices size starRatio: self prevSkip]\\n\\t\\t\\t\\tifFalse: [self makeVertices: vertices size starRatio: self prevTwinkleSkip]].\\n\\tself computeBounds! !\\n\\n!StarMorph methodsFor: 'editing' stamp: 'wiz 1/20/2005 19:07'!\\ndragVertex: label event: evt fromHandle: handle \\n\\t| center r1 rN rNext a1 rTotal |\\n\\tlabel == #outside\\n\\t\\tifTrue: [center := handles second center.\\n\\t\\t\\tr1 := center dist: vertices first.\\n\\t\\t\\t\\\"Rounding and what happens as the outer handle\\n\\t\\t\\tapproached the center, \\n\\t\\t\\trequires we guard the inner radius \\n\\t\\t\\tfrom becoming larger than the outer radius.\\\"\\n\\t\\t\\trN := r1\\n\\t\\t\\t\\t\\t\\tmin: (center dist: vertices last).\\n\\t\\t\\trNext := 1\\n\\t\\t\\t\\t\\t\\tmax: (center dist: evt cursorPoint).\\n\\t\\t\\ta1 := 270.0\\n\\t\\t\\t\\t\\t\\t+ (center bearingToPoint: evt cursorPoint).\\n\\t\\t\\trTotal := vertices size even\\n\\t\\t\\t\\t\\t\\tifTrue: [evt shiftPressed\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [rNext + rNext min: rNext + rN]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [r1 + rN * rNext / r1]]\\n\\t\\t\\t\\t\\t\\tifFalse: [rNext + rNext].\\n\\t\\t\\trNext := rTotal - rNext.\\n\\t\\t\\tvertices := ((a1 to: a1 + 359.999 by: 360.0 / vertices size)\\n\\t\\t\\t\\t\\t\\tcollect: [:angle | center\\n\\t\\t\\t\\t\\t\\t\\t\\t+ (Point r: (rNext := rTotal - rNext) degrees: angle)]) .\\n\\t\\t\\thandle align: handle center with: evt cursorPoint].\\n\\tlabel == #center\\n\\t\\tifTrue: [evt shiftPressed\\n\\t\\t\\t\\tifTrue: [self updateFormFromUser]\\n\\t\\t\\t\\tifFalse: [self position: self position + (evt cursorPoint - handle center)]].\\n\\tself computeBounds! !\\n\\n!StarMorph methodsFor: 'editing' stamp: 'wiz 1/15/2005 00:19'!\\nplaceHandles\\n\\t\\\"Add the handles to my submorphs.\\\"\\n\\thandles reverseDo: [:each | self addMorphFront: each ] .\\n\\t\\n\\t! !\\n\\n!StarMorph methodsFor: 'editing' stamp: 'di 9/26/97 11:11'!\\nupdateHandles! !\\n\\n!StarMorph methodsFor: 'editing' stamp: 'wiz 1/11/2005 19:39'!\\nwithCenterOuterHandles\\n\\t\\\"Add to our handles the center positioning and outer resizing\\n\\thandles. Outer handle must not be blocked so it comes first. \\n\\tThe editing routine expects to find the center handle second.\\n\\tThe side and shape changing handles follow these.\\\"\\n\\t| center v1 hExtent holder |\\n\\tcenter := vertices average rounded.\\n\\thExtent := 8 @ 8.\\n\\tv1 := vertices first.\\n\\tholder := {(EllipseMorph\\n\\t\\t\\t\\tnewBounds: (Rectangle center: v1 extent: hExtent)\\n\\t\\t\\t\\tcolor: Color yellow)\\n\\t\\t\\t\\tsetBalloonText: 'Move me to adjust size. Shift move to adjust pointiness'. (EllipseMorph\\n\\t\\t\\t\\tnewBounds: (Rectangle center: center extent: hExtent)\\n\\t\\t\\t\\tcolor: Color yellow)\\n\\t\\t\\t\\tsetBalloonText: 'Move me to adjust position'}.\\n\\tholder\\n\\t\\twith: {#outside. #center}\\n\\t\\tdo: [:handle :which | handle\\n\\t\\t\\t\\ton: #mouseDown\\n\\t\\t\\t\\tsend: #dragVertex:event:fromHandle:\\n\\t\\t\\t\\tto: self\\n\\t\\t\\t\\twithValue: which;\\n\\t\\t\\t\\t\\n\\t\\t\\t\\ton: #mouseMove\\n\\t\\t\\t\\tsend: #dragVertex:event:fromHandle:\\n\\t\\t\\t\\tto: self\\n\\t\\t\\t\\twithValue: which].\\n\\thandles addAll: holder! !\\n\\n!StarMorph methodsFor: 'editing' stamp: 'wiz 1/11/2005 19:47'!\\nwithUpDownLeftRightHandlesAround: radius center: center\\n\\t\\\"Add to our handles the side and shape changing handles.\\\"\\n\\t| tri above holder triAbove triBelow triRight triLeft |\\n\\tabove := 0 @ radius negated.\\n\\t\\n\\ttri := Array\\n\\t\\t\\t\\twith: 0 @ -5\\n\\t\\t\\t\\twith: 4 @ 3\\n\\t\\t\\t\\twith: -4 @ 3.\\n\\ttriAbove := tri + (center + above).\\n\\ttriBelow := triAbove\\n\\t\\t\\t\\tcollect: [:pt | pt rotateBy: #pi centerAt: center].\\n\\ttriRight := triAbove\\n\\t\\t\\t\\tcollect: [:pt | pt rotateBy: #right centerAt: center].\\n\\ttriLeft := triAbove\\n\\t\\t\\t\\tcollect: [:pt | pt rotateBy: #left centerAt: center].\\n\\t\\t\\t\\t\\n\\tholder := { (PolygonMorph\\n\\t\\t\\t\\tvertices: triAbove\\n\\t\\t\\t\\tcolor: Color green\\n\\t\\t\\t\\tborderWidth: 1\\n\\t\\t\\t\\tborderColor: Color black)\\n\\t\\t\\t\\t setBalloonText: 'More points.'. \\n\\t\\t\\t\\t\\n\\t\\t\\t\\t(PolygonMorph\\n\\t\\t\\t\\tvertices: triBelow\\n\\t\\t\\t\\tcolor: Color magenta\\n\\t\\t\\t\\tborderWidth: 1\\n\\t\\t\\t\\tborderColor: Color black)\\n\\t\\t\\t\\t setBalloonText: 'Fewer points.'. \\n\\t\\t\\t\\t\\n\\t\\t\\t\\t(PolygonMorph\\n\\t\\t\\t\\tvertices: triRight\\n\\t\\t\\t\\tcolor: Color green\\n\\t\\t\\t\\tborderWidth: 1\\n\\t\\t\\t\\tborderColor: Color black)\\n\\t\\t\\t\\t setBalloonText: 'Twinkle fatter.'. \\n\\t\\t\\t\\t\\n\\t\\t\\t\\t(PolygonMorph\\n\\t\\t\\t\\tvertices: triLeft\\n\\t\\t\\t\\tcolor: Color magenta\\n\\t\\t\\t\\tborderWidth: 1\\n\\t\\t\\t\\tborderColor: Color black)\\n\\t\\t\\t\\t setBalloonText: 'Twinkle thinner.'}.\\n\\t\\n\\tholder\\n\\t\\twith: {#more. #less. #next. #prev}\\n\\t\\tdo: [:handle :which | handle\\n\\t\\t\\t\\ton: #mouseDown\\n\\t\\t\\t\\tsend: #changeVertices:event:fromHandle:\\n\\t\\t\\t\\tto: self\\n\\t\\t\\t\\twithValue: which;\\n\\t\\t\\t\\t\\n\\t\\t\\t\\ton: #mouseMove\\n\\t\\t\\t\\tsend: #changeVertices:event:fromHandle:\\n\\t\\t\\t\\tto: self\\n\\t\\t\\t\\twithValue: which].\\n\\t^ handles addAll: holder! !\\n\\n\\n!StarMorph methodsFor: 'geometry' stamp: 'wiz 1/19/2005 22:34'!\\nnextSkip\\n\\t\\\"Set starRatio to next skip wrapping if needed.\\\"\\n\\t| skips n c r1 rN |\\n\\tc := vertices average rounded.\\n\\tr1 := (c dist: vertices first) truncated asFloat.\\n\\trN := c dist: vertices last.\\n\\tskips := self skipRatios.\\n\\tn := skips * r1\\n\\t\\t\\t\\tfindFirst: [:r | r > (rN + 1.0)].\\n\\t\\\"n = 0\\n\\t\\tifTrue: [n := skips size].\\\"\\n\\t^ skips atWrap: n! !\\n\\n!StarMorph methodsFor: 'geometry' stamp: 'wiz 1/19/2005 22:42'!\\nnextTwinkleSkip\\n\\t\\\"Set starRatio to next skip wrapping if needed.\\\"\\n\\t| skips n c r1 rN |\\n\\tc := vertices average rounded.\\n\\tr1 := (c dist: vertices first) truncated asFloat.\\n\\trN := c dist: vertices last.\\n\\tskips := self skipRatios.\\n\\tn := skips * r1\\n\\t\\t\\t\\tfindFirst: [:r | r > (rN + 1.0)].\\n\\tn = 0\\n\\t\\tifTrue: [ n := 1].\\n\\t^ skips atWrap: n! !\\n\\n!StarMorph methodsFor: 'geometry' stamp: 'wiz 1/19/2005 22:41'!\\nprevSkip\\n\\t\\\"Set starRatio to next skip wrapping if necessary\\\"\\n\\t| skips n c r1 rN |\\n\\tc := vertices average rounded.\\n\\tr1 := c dist: vertices first.\\n\\trN := (c dist: vertices last) truncated asFloat.\\n\\tskips := self skipRatios.\\n\\tn := skips * r1\\n\\t\\t\\t\\tfindLast: [:r | r + 1.0 < rN].\\n\\tn = 0\\n\\t\\tifTrue: [n := 1].\\n\\t^ skips at: n! !\\n\\n!StarMorph methodsFor: 'geometry' stamp: 'wiz 1/19/2005 22:19'!\\nprevTwinkleSkip\\n\\t\\\"Set starRatio to next skip wrapping if necessary\\\"\\n\\t| skips n c r1 rN |\\n\\tc := vertices average rounded.\\n\\tr1 := c dist: vertices first.\\n\\trN := (c dist: vertices last) truncated asFloat.\\n\\tskips := self skipRatios.\\n\\tn := skips * r1\\n\\t\\t\\t\\tfindLast: [:r | r + 1.0 < rN].\\n\\t\\\"n = 0\\n\\tifTrue: [^ oldR].\\\"\\n\\t^ skips atWrap: n! !\\n\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:35'!\\ndefaultBorderColor\\n\\t\\\"answer the default border color/fill style for the receiver\\\"\\n\\t^ Color black! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:40'!\\ndefaultBorderWidth\\n\\t\\\"answer the default border width for the receiver\\\"\\n\\t^ 1! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:33'!\\ndefaultCenter\\n\\t\\\"answer the default center for the receiver\\\"\\n\\t^ 0 asPoint! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:31'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color lightBlue! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:33'!\\ndefaultFirstVertex\\n\\t\\\"answer the default first outer point for the receiver.\\n\\tThis with the center determines the angle and size of the outer radius.\\\"\\n\\t^ 10 asPoint! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:28'!\\ndefaultSides\\n\\t\\\"answer the default number of sides for the receiver\\\"\\n\\t^ 10! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:29'!\\ndefaultStarRatio\\n\\t\\\"answer the default ratio of outer radius to inner radius for the receiver\\\"\\n\\t^ 5.0 / 12.0! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:36'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\tself\\n\\t\\tmakeVertices: self defaultSides\\n\\t\\tstarRatio: self defaultStarRatio\\n\\t\\twithCenter: self defaultCenter\\n\\t\\twithPoint: self defaultFirstVertex.\\n\\tself computeBounds! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'wiz 1/9/2005 20:15'!\\ninsureCompatability\\n\\\"The old stars had the point on the second not the first vertex. So we need to check for this special case.\\\"\\n | c v1 v2 |\\nc := vertices average rounded.\\n v1 := vertices first .\\n v2 := vertices second .\\n(c dist: v1) + 0.001 < (c dist: v2) ifTrue: [vertices := vertices allButFirst copyWith: v1]\\n\\n! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'wiz 12/30/2004 02:57'!\\nmakeVertices: nSides \\n\\t\\\"Assuming vertices has at least one point, make a new star \\n\\tor regular polygon (for odd sided polygons).\\n\\tThe center of the polygon and the first vertex remain in\\n\\tplace. The inner distances for stars remain the same also if\\n\\tpossible.\\\"\\n\\t| center r1 rN rNext a1 rTotal |\\n\\tcenter := vertices average rounded.\\n\\tr1 := center dist: vertices first.\\n\\trN := center dist: vertices last.\\n\\trNext := 1 max: r1.\\n\\ta1 := 270.0\\n\\t\\t\\t\\t+ (center bearingToPoint: vertices first).\\n\\trTotal := nSides even\\n\\t\\t\\t\\tifTrue: [rNext + rNext min: rNext + rN]\\n\\t\\t\\t\\tifFalse: [rNext + rNext].\\n\\trNext := rTotal - rNext.\\n\\tself changed .\\n\\tvertices := (a1 to: a1 + 359.999 by: 360.0 / nSides)\\n\\t\\t\\t\\tcollect: [:angle | center\\n\\t\\t\\t\\t\\t\\t+ (Point r: (rNext := rTotal - rNext) degrees: angle)].\\n\\tself computeBounds.\\n\\tself changed! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'wiz 1/4/2005 19:31'!\\nmakeVertices: nSides starRatio: fraction\\n\\t\\\"Assuming vertices has at least one point, make a new star \\n\\tor regular polygon (for odd sided polygons).\\n\\tThe center of the polygon and the first vertex remain in\\n\\tplace. The inner distances for stars remain the same also if\\n\\tpossible.\\\"\\n\\t| center r1 rN rNext a1 rTotal |\\n\\tcenter := vertices average rounded.\\n\\tr1 := center dist: vertices first.\\n\\trNext := 1 max: r1.\\n\\trN := (1.0 min: fraction) * rNext.\\n\\ta1 := 270.0\\n\\t\\t\\t\\t+ (center bearingToPoint: vertices first).\\n\\trTotal := nSides even\\n\\t\\t\\t\\tifTrue: [rNext + rNext min: rNext + rN]\\n\\t\\t\\t\\tifFalse: [rNext + rNext].\\n\\trNext := rTotal - rNext.\\n\\tself changed .\\n\\tvertices := (a1 to: a1 + 359.999 by: 360.0 / nSides)\\n\\t\\t\\t\\tcollect: [:angle | center\\n\\t\\t\\t\\t\\t\\t+ (Point r: (rNext := rTotal - rNext) degrees: angle)].\\n\\tself computeBounds.\\n\\tself changed! !\\n\\n!StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 21:36'!\\nmakeVertices: nSides starRatio: fraction withCenter: center withPoint: aPoint \\n\\t\\\"Make a new star or regular polygon (for odd sided polygons).\\n\\tThis makes star vertices from scratch without any feedback from existing vertices.\\\"\\n\\t| r1 rN rNext a1 rTotal |\\n\\tr1 := center dist: aPoint.\\n\\trNext := 1 max: r1.\\n\\trN := (1.0 min: fraction)\\n\\t\\t\\t\\t* rNext.\\n\\ta1 := 270.0\\n\\t\\t\\t\\t+ (center bearingToPoint: aPoint).\\n\\trTotal := nSides even\\n\\t\\t\\t\\tifTrue: [rNext + rNext min: rNext + rN]\\n\\t\\t\\t\\tifFalse: [rNext + rNext].\\n\\trNext := rTotal - rNext.\\n\\tself changed.\\n\\tvertices := (a1 to: a1 + 359.999 by: 360.0 / nSides)\\n\\t\\t\\t\\tcollect: [:angle | center\\n\\t\\t\\t\\t\\t\\t+ (Point r: (rNext := rTotal - rNext) degrees: angle)].\\n\\tself computeBounds.\\n\\tself changed! !\\n\\n\\n!StarMorph methodsFor: 'menu' stamp: 'wiz 9/5/2005 23:08'!\\naddChangeSidesMenuItems: aCustomMenu hand: aHandMorph \\n\\t\\\"Menu items to change number of sides.\\\"\\n\\taCustomMenu addLine.\\n\\taCustomMenu add: 'more sides' translated action: #moreVertices.\\n\\taCustomMenu add: 'fewer sides' translated action: #lessVertices.\\n\\\"\\tRegular polygons can be simulated with the one of the skip stars \\n\\tand it would confuse users to have stars be limited to Regular polygons.\\n\\tSo we've removed those menu items - wiz\\\"\\n\\\"\\taCustomMenu add: 'one more side' translated action: #oneMoreVertex.\\n\\taCustomMenu add: 'one fewer side' translated action: #oneLessVertex\\\"! !\\n\\n!StarMorph methodsFor: 'menu' stamp: 'wiz 1/11/2005 14:55'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph \\n\\tsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.\\nself addChangeSidesMenuItems: aCustomMenu hand: aHandMorph.\\nself addTwinkleMenuItems: aCustomMenu hand: aHandMorph.\\n\\t! !\\n\\n!StarMorph methodsFor: 'menu' stamp: 'wiz 1/11/2005 20:38'!\\naddTwinkleMenuItems: aCustomMenu hand: aHandMorph \\n\\t\\\"Menu items to change the sharpness of the star.\\\"\\n\\taCustomMenu addLine.\\n\\taCustomMenu add: 'twinkle fatter' translated action: #nextTwinkle.\\n\\taCustomMenu add: 'twinkle thinner' translated action: #prevTwinkle.\\n\\\"\\taCustomMenu add: 'fatter star' translated action: #nextFatter.\\n\\taCustomMenu add: 'thinner star' translated action: #prevThinner\\\"\\n\\t\\n\\t\\n\\n\\n! !\\n\\n!StarMorph methodsFor: 'menu' stamp: 'wiz 12/11/2004 16:45'!\\noneLessVertex\\n\\tself\\n\\t\\tmakeVertices: (3 max: 1 negated + vertices size)! !\\n\\n!StarMorph methodsFor: 'menu' stamp: 'wiz 12/11/2004 16:46'!\\noneMoreVertex\\n\\tself makeVertices: 1 + vertices size! !\\n\\n\\n!StarMorph methodsFor: 'menus' stamp: 'wiz 12/12/2004 16:43'!\\nlessVertices\\n\\\"Reduce the number of points by one until we are a diamond. If odd reduce the number of sides by two until we become a triangle. See class comment.\\\"\\n\\t| nVerts |\\n\\t( nVerts := 2 negated + vertices size) < 3 ifFalse: [\\n\\tself\\n\\t\\tmakeVertices: nVerts]! !\\n\\n!StarMorph methodsFor: 'menus' stamp: 'wiz 12/11/2004 16:45'!\\nmoreVertices\\n\\tself makeVertices: 2+ vertices size! !\\n\\n!StarMorph methodsFor: 'menus' stamp: 'wiz 1/11/2005 20:37'!\\nnextTwinkle\\n\\tself makeVertices: vertices size starRatio: self nextTwinkleSkip .\\n\\tself computeBounds.! !\\n\\n!StarMorph methodsFor: 'menus' stamp: 'wiz 1/11/2005 20:37'!\\nprevTwinkle\\n\\tself makeVertices: vertices size starRatio: self prevTwinkleSkip .\\n\\tself computeBounds.! !\\n\\n!StarMorph methodsFor: 'menus' stamp: 'wiz 1/15/2005 02:26'!\\nupdateFormFromUser\\n\\\"Does nothing here. Overridden in subclasses e.g. Kaleidoscope.\\\"\\n^ self.! !\\n\\n\\n!StarMorph methodsFor: 'parts bin' stamp: 'sw 7/2/2001 11:07'!\\ninitializeToStandAlone\\n\\t^ self initialize removeHandles! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStarMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!StarMorph class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 11:37'!\\ninitialize\\n\\n\\tself registerInFlapsRegistry.\\t! !\\n\\n!StarMorph class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 11:39'!\\nregisterInFlapsRegistry\\n\\t\\\"Register the receiver in the system's flaps registry\\\"\\n\\tself environment\\n\\t\\tat: #Flaps\\n\\t\\tifPresent: [:cl | cl registerQuad: #(StarMorph\\t\\tauthoringPrototype\\t'Star'\\t'A star')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'PlugIn Supplies'.\\n\\t\\t\\t\\t\\t\\tcl registerQuad: #(StarMorph\\tauthoringPrototype\\t'Star'\\t'A star')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Supplies'.]! !\\n\\n!StarMorph class methodsFor: 'class initialization' stamp: 'asm 4/11/2003 12:41'!\\nunload\\n\\t\\\"Unload the receiver from global registries\\\"\\n\\n\\tself environment at: #Flaps ifPresent: [:cl |\\n\\tcl unregisterQuadsWithReceiver: self] ! !\\n\\n\\n!StarMorph class methodsFor: 'parts bin' stamp: 'sw 8/2/2001 16:22'!\\ndescriptionForPartsBin\\n\\t^ self partName:\\t'Star'\\n\\t\\tcategories:\\t\\t#('Graphics')\\n\\t\\tdocumentation:\\t'A symmetrical polygon in the shape of a star'! !\\nStarSqueakMorph subclass: #StarSqueakAntColony\\n\\tinstanceVariableNames: 'antCount'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'StarSqueak-Worlds'!\\n\\n!StarSqueakAntColony methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitialize\\n\\n\\tantCount := 50.\\n\\tsuper initialize.\\n! !\\n\\n\\n!StarSqueakAntColony methodsFor: 'menu' stamp: 'jm 2/7/2001 18:41'!\\nsliderParameters\\n\\t\\\"Answer a list of parameters that the user can change via a slider. Each parameter is described by an array of: <name> <min value> <max value> <balloon help string>.\\\"\\n\\n\\t^ super sliderParameters, #(\\n\\t\\t(antCount 10 500 'The number of ants searching for food.'))\\n! !\\n\\n\\n!StarSqueakAntColony methodsFor: 'other' stamp: 'jm 1/19/2001 10:30'!\\ndiffusePheromone\\n\\n\\tself diffusePatchVariable: 'pheromone'.\\n! !\\n\\n!StarSqueakAntColony methodsFor: 'other' stamp: 'jm 1/19/2001 18:02'!\\nevaporatePheromone\\n\\n\\tself decayPatchVariable: 'pheromone'.\\n! !\\n\\n!StarSqueakAntColony methodsFor: 'other' stamp: 'jm 2/7/2001 08:03'!\\nsetupFood: aPatch\\n\\t\\\"Create several food caches.\\\"\\n\\n\\taPatch set: 'food' to: 0. \\\"patch default is no food\\\"\\n\\n\\t((aPatch distanceTo: 15@15) <= 1 or:\\n\\t [(aPatch distanceTo: 80@20) <= 1 or:\\n\\t [(aPatch distanceTo: 25@80) <= 1 or:\\n\\t [(aPatch distanceTo: 70@70) <= 1]]]) ifTrue: [\\n\\t\\taPatch set: 'food' to: 10.\\n\\t\\taPatch color: Color red].\\n\\n! !\\n\\n!StarSqueakAntColony methodsFor: 'other' stamp: 'sd 11/20/2005 21:26'!\\nsetupNest: aPatch\\n\\t\\\"Create a nest of radius 5 centered at 50@50.\\\"\\n\\n\\t| distanceToNest |\\n\\tdistanceToNest := aPatch distanceTo: 50@50.\\n\\tdistanceToNest <= 4\\n\\t\\tifTrue: [\\n\\t\\t\\taPatch set: 'isNest' to: 1.\\n\\t\\t\\taPatch color: Color brown lighter]\\n\\t\\tifFalse: [aPatch set: 'isNest' to: 0].\\n\\n\\t\\\"create a 'hill' of nest scent centered on the nest\\\"\\n\\tdistanceToNest > 0 ifTrue: [\\n\\t\\taPatch set: 'nestScent' to: 10000.0 // distanceToNest].\\n\\n! !\\n\\n!StarSqueakAntColony methodsFor: 'other' stamp: 'jm 3/8/2001 14:23'!\\nsetupPatches\\n\\t\\\"Create patch variables for sensing the nest and food caches. The nestScent variable is diffused so that it forms a 'hill' of scent over the entire world with its peak at the center of the nest. That way, the ants always know which way the nest is.\\\"\\n\\n\\tself createPatchVariable: 'food'.\\t\\t\\t\\\"greater than zero if patch has food\\\"\\n\\tself createPatchVariable: 'isNest'.\\t\\t\\\"greater than zero if patch is nest\\\"\\n\\tself createPatchVariable: 'nestScent'.\\t\\\"circular gradient with peak centered on nest\\\"\\n\\tself createPatchVariable: 'pheromone'.\\t\\\"dropped by ants when carrying food\\\"\\n\\tself displayPatchVariable: 'pheromone'.\\n\\tself patchesDo: [:p |\\n\\t\\tp color: self backgroundColor.\\n\\t\\tself setupNest: p.\\n\\t\\tself setupFood: p].\\n\\n! !\\n\\n!StarSqueakAntColony methodsFor: 'other' stamp: 'jm 3/8/2001 14:24'!\\nsetupTurtles\\n\\n\\tself makeTurtles: antCount class: AntColonyTurtle.\\n\\tturtles do: [:t |\\n\\t\\tt goto: 50@50.\\n\\t\\tt color: Color black.\\n\\t\\tt isCarryingFood: false.\\n\\t\\tt pheromoneDropSize: 100].\\n! !\\n\\n\\n!StarSqueakAntColony methodsFor: 'parameters' stamp: 'jm 2/7/2001 14:45'!\\nantCount\\n\\n\\t^ antCount\\n! !\\n\\n!StarSqueakAntColony methodsFor: 'parameters' stamp: 'sd 11/20/2005 21:26'!\\nantCount: aNumber\\n\\n\\tantCount := aNumber.\\n! !\\n\\n!StarSqueakAntColony methodsFor: 'parameters' stamp: 'jm 3/11/2001 17:10'!\\nbackgroundColor\\n\\n\\t^ Color brown lighter lighter lighter! !\\n\\n\\n!StarSqueakAntColony methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\nsetup\\n\\n\\tself clearAll.\\n\\tself setupPatches.\\n\\tself setupTurtles.\\n\\tturtleDemons := #(searchForFood pickUpFood returnToNest dropFoodInNest).\\n\\tworldDemons := #(evaporatePheromone diffusePheromone).\\n! !\\nStarSqueakMorph subclass: #StarSqueakDiffusion\\n\\tinstanceVariableNames: 'waterCount dyeCount'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'StarSqueak-Worlds'!\\n\\n!StarSqueakDiffusion methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitialize\\n\\n\\tdyeCount := 200.\\n\\twaterCount := 2000.\\n\\tsuper initialize.\\n! !\\n\\n\\n!StarSqueakDiffusion methodsFor: 'menu' stamp: 'jm 3/8/2001 14:08'!\\nsliderParameters\\n\\t\\\"Answer a list of parameters that the user can change via a slider. Each parameter is described by an array of: <name> <min value> <max value> <balloon help string>.\\\"\\n\\n\\t^ super sliderParameters, #(\\n\\t\\t(dyeCount 50 1000 'The number of dye particles.')\\n\\t\\t(waterCount 100 4000 'The number of water particles.'))\\n! !\\n\\n\\n!StarSqueakDiffusion methodsFor: 'other' stamp: 'sd 11/20/2005 21:26'!\\nsetupTurtles\\n\\n\\t| radius t |\\n\\tdyeCount ifNil: [dyeCount := 200].\\n\\twaterCount ifNil: [waterCount := 2000].\\n\\tradius := 10.\\n\\tself makeTurtles: waterCount class: DiffusionTurtle.\\n\\tturtles do: [:each |\\n\\t\\teach color: (Color gray: 0.7).\\n\\t\\t(each distanceTo: 50@50) < radius ifTrue: [each die]].\\n\\n\\tself makeTurtles: dyeCount class: DiffusionTurtle.\\n\\tturtles size - (dyeCount - 1) to: turtles size do: [:i |\\n\\t\\tt := turtles at: i.\\n\\t\\tt goto: 50@50.\\n\\t\\tt forward: (self random: radius).\\n\\t\\tt color: Color green darker darker].\\n! !\\n\\n\\n!StarSqueakDiffusion methodsFor: 'parameters' stamp: 'jm 3/8/2001 14:07'!\\ndyeCount\\n\\n\\t^ dyeCount\\n! !\\n\\n!StarSqueakDiffusion methodsFor: 'parameters' stamp: 'sd 11/20/2005 21:26'!\\ndyeCount: aNumber\\n\\n\\tdyeCount := aNumber asInteger max: 1.\\n! !\\n\\n!StarSqueakDiffusion methodsFor: 'parameters' stamp: 'jm 3/8/2001 14:07'!\\nwaterCount\\n\\n\\t^ waterCount\\n! !\\n\\n!StarSqueakDiffusion methodsFor: 'parameters' stamp: 'sd 11/20/2005 21:26'!\\nwaterCount: aNumber\\n\\n\\twaterCount := aNumber asInteger max: 1.\\n! !\\n\\n\\n!StarSqueakDiffusion methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\nsetup\\n\\n\\tself clearAll.\\n\\tself patchesDo: [:p | p color: (Color gray: 0.9)].\\n\\tself setupTurtles.\\n\\tturtleDemons := #(move bounce).\\n! !\\nStarSqueakMorph subclass: #StarSqueakForestFire\\n\\tinstanceVariableNames: 'treePercentage'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'StarSqueak-Worlds'!\\n\\n!StarSqueakForestFire methodsFor: 'demons' stamp: 'sd 11/20/2005 21:26'!\\nconsumeFuel\\n\\n\\t| level |\\n\\tself patchesDo: [:p |\\n\\t\\tlevel := p get: #flameLevel.\\n\\t\\tlevel > 0 ifTrue: [\\n\\t\\t\\tlevel := (level - 15) max: 0.\\n\\t\\t\\tp set: #flameLevel to: level.\\n\\t\\t\\tp brightness: level]].\\n! !\\n\\n!StarSqueakForestFire methodsFor: 'demons' stamp: 'jm 1/28/2001 16:33'!\\nspreadFire\\n\\n\\tself patchesDo: [:p |\\n\\t\\t(p get: #isUnburnt) > 0 ifTrue: [\\n\\t\\t\\t((p neighborN get: #flameLevel) +\\n\\t\\t\\t (p neighborS get: #flameLevel) +\\n\\t\\t\\t (p neighborE get: #flameLevel) +\\n\\t\\t\\t (p neighborW get: #flameLevel)) > 0 ifTrue: [\\n\\t\\t\\t\\tp set: #isUnburnt to: 0.\\n\\t\\t\\t\\tp set: #flameLevel to: 100.\\n\\t\\t\\t\\tp color: Color red]]].\\n! !\\n\\n\\n!StarSqueakForestFire methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitialize\\n\\n\\ttreePercentage := 70.\\n\\tsuper initialize.\\n! !\\n\\n\\n!StarSqueakForestFire methodsFor: 'menu' stamp: 'jm 3/10/2001 11:06'!\\nsliderParameters\\n\\t\\\"Answer a list of parameters that the user can change via a slider. Each parameter is described by an array of: <name> <min value> <max value> <balloon help string>.\\\"\\n\\n\\t^ super sliderParameters, #(\\n\\t\\t(treePercentage 0 100 'The probability of that a given patch has a tree.'))\\n! !\\n\\n\\n!StarSqueakForestFire methodsFor: 'parameters' stamp: 'jm 3/10/2001 11:06'!\\ntreePercentage\\n\\n\\t^ treePercentage\\n! !\\n\\n!StarSqueakForestFire methodsFor: 'parameters' stamp: 'sd 11/20/2005 21:26'!\\ntreePercentage: aNumber\\n\\n\\ttreePercentage := aNumber.\\n! !\\n\\n\\n!StarSqueakForestFire methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\nsetup\\n\\n\\tself clearAll.\\n\\tself createPatchVariable: #isUnburnt.\\n\\tself createPatchVariable: #flameLevel.\\n\\tself setupTrees.\\n\\tself setupFire.\\n\\tself setupBorder.\\n\\tworldDemons := #(spreadFire consumeFuel).\\n\\n! !\\n\\n!StarSqueakForestFire methodsFor: 'setup' stamp: 'jm 1/28/2001 16:32'!\\nsetupBorder\\n\\n\\tself patchesDo: [:p |\\n\\t\\tp isLeftEdge | p isRightEdge |\\n\\t\\tp isTopEdge | p isBottomEdge ifTrue: [\\n\\t\\t\\tp set: #isUnburnt to: 0.\\n\\t\\t\\tp color: Color blue]].\\n! !\\n\\n!StarSqueakForestFire methodsFor: 'setup' stamp: 'jm 1/28/2001 16:32'!\\nsetupFire\\n\\n\\tself patchesDo: [:p |\\n\\t\\tp neighborW isLeftEdge ifTrue: [\\n\\t\\t\\tp set: #isUnburnt to: 0.\\n\\t\\t\\tp set: #flameLevel to: 100.\\n\\t\\t\\tp color: Color red]].\\n! !\\n\\n!StarSqueakForestFire methodsFor: 'setup' stamp: 'jm 3/10/2001 11:09'!\\nsetupTrees\\n\\t\\\"Setup a forest with treePercentage of trees.\\\"\\n\\n\\tself patchesDo: [:p |\\n\\t\\tp set: #isUnburnt to: 0.\\n\\t\\tp set: #flameLevel to: 0.\\n\\t\\t(10 * treePercentage) > (self random: 1000) ifTrue: [\\n\\t\\t\\tp set: #isUnburnt to: 1.\\n\\t\\t\\tp color: Color green]].\\n! !\\nMorph subclass: #StarSqueakMorph\\n\\tinstanceVariableNames: 'dimensions pixelsPerPatch patchVariables patchVariableToDisplay logPatchVariableScale patchVarDisplayForm patchForm patchColorSetter patchColorGetter turtles turtleDemons worldDemons sniffRange scaledEvaporationRate diffusionRate lastTurtleID generation running stepTime turtlesAtPatchCache turtlesAtPatchCacheValid'\\n\\tclassVariableNames: 'RandomSeed'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'StarSqueak-Kernel'!\\n!StarSqueakMorph commentStamp: '<historical>' prior: 0!\\nI implement a StarSqueak simulation. StarSqueak is a Squeak version of Mitchel Resnick's Star Logo, a simulation environment designed to explore massively parallel simulations with hundreds or thousands of turtles. See the excellent book \\\"Turtles, Termites, and Traffic Jams: Explorations in Massively Parallel Microworlds\\\" by Mitchel Resnick, MIT Press, 1994.\\n!\\n\\n\\n!StarSqueakMorph methodsFor: 'accessing' stamp: 'jm 2/7/2001 13:48'!\\ndiffusionRate\\n\\n\\t^ diffusionRate\\n! !\\n\\n!StarSqueakMorph methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\ndiffusionRate: newRate\\n\\t\\\"Set the diffusion rate to an integer between 0 and 10. The diffusion rate gives the number of patches on one size of the area averaged to compute the next value of the variable for a given patch. Larger numbers cause faster diffusion. Zero means no diffusion.\\\"\\n\\n\\tdiffusionRate := (newRate rounded max: 0) min: 10.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'accessing' stamp: 'jm 2/7/2001 18:59'!\\nevaporationRate\\n\\n\\t^ 1024 - scaledEvaporationRate! !\\n\\n!StarSqueakMorph methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\nevaporationRate: newRate\\n\\t\\\"Set the evaporation rate. The useful range is 0 to 25 or so. Larger numbers cause faster evaporation. Zero means no evaporization.\\\"\\n\\n\\tscaledEvaporationRate := ((1024 - newRate truncated) max: 1) min: 1024.\\n\\n! !\\n\\n!StarSqueakMorph methodsFor: 'accessing' stamp: 'jm 3/3/2001 12:50'!\\npixelsPerPatch\\n\\n\\t^ pixelsPerPatch\\n! !\\n\\n!StarSqueakMorph methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\npixelsPerPatch: anInteger\\n\\t\\\"Set the width of one patch in pixels. Larger numbers scale up this StarSqueak world, but numbers larger than 2 or 3 result in a blocky look. The useful range is 1 to 10.\\\"\\n\\n\\tpixelsPerPatch := (anInteger rounded max: 1) min: 10.\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'drawing' stamp: 'jm 3/3/2001 12:55'!\\nareasRemainingToFill: aRectangle\\n\\t\\\"Drawing optimization. Since I completely fill my bounds with opaque pixels, this method tells Morphic that it isn't necessary to draw any morphs covered by me.\\\"\\n\\t\\n\\t^ aRectangle areasOutside: self bounds\\n! !\\n\\n!StarSqueakMorph methodsFor: 'drawing' stamp: 'sd 11/20/2005 21:26'!\\ndisplay\\n\\t\\\"Display this world on the Display. Used for debugging.\\\"\\n\\n\\t| c |\\n\\tc := FormCanvas extent: (dimensions * pixelsPerPatch) depth: 32.\\n\\tc := c copyOffset: bounds origin negated.\\n\\tself drawOn: c.\\n\\tc form display.\\n\\n! !\\n\\n!StarSqueakMorph methodsFor: 'drawing' stamp: 'sd 11/20/2005 21:26'!\\ndrawOn: aCanvas\\n\\t\\\"Display this StarSqueak world.\\\"\\n\\n\\t| tmpForm bitBlt t |\\n\\t\\\"copy the patches form\\\"\\n\\ttmpForm := patchForm deepCopy.\\n\\n\\t\\\"draw patchVariableToDisplay on top of tmpForm as translucent color\\\"\\n\\tself displayPatchVariableOn: tmpForm color: Color yellow shift: logPatchVariableScale.\\n\\n\\t\\\"draw turtles on top of tmpForm\\\"\\n\\tbitBlt := (BitBlt toForm: tmpForm)\\n\\t\\tclipRect: tmpForm boundingBox;\\n\\t\\tcombinationRule: Form over.\\n\\t1 to: turtles size do: [:i |\\n\\t\\tt := turtles at: i.\\n\\t\\tbitBlt\\n\\t\\t\\tdestX: (pixelsPerPatch * t x truncated)\\n\\t\\t\\tdestY: (pixelsPerPatch * t y truncated)\\n\\t\\t\\twidth: pixelsPerPatch\\n\\t\\t\\theight: pixelsPerPatch.\\n\\t\\tbitBlt\\n\\t\\t\\tfillColor: t color;\\n\\t\\t\\tcopyBits].\\n\\n\\t\\\"display tmpForm\\\"\\n\\taCanvas paintImage: tmpForm at: bounds origin.\\n\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'geometry' stamp: 'jm 2/7/2001 13:31'!\\nextent: aPoint\\n\\t\\\"Do nothing; my extent is determined by my StarSqueak world dimensions and pixelsPerPatch.\\\"\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitialize\\n\\n\\tsuper initialize.\\n\\tdimensions := self starSqueakDimensions. \\\"dimensions of this StarSqueak world in patches\\\"\\n\\tpixelsPerPatch := 2.\\n\\tsuper extent: dimensions * pixelsPerPatch.\\n\\tself evaporationRate: 6.\\n\\tself diffusionRate: 1.\\n\\tself clearAll. \\\"be sure this is done once in case setup fails to do it\\\"\\n\\tself setup.\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'dgd 8/30/2003 22:17'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\n\\tsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.\\n\\taCustomMenu addLine.\\n\\taCustomMenu add: 'start' translated action: #startRunning.\\n\\taCustomMenu add: 'stop' translated action: #stopRunning.\\n\\taCustomMenu add: 'step' translated action: #singleStep.\\n\\taCustomMenu add: 'start over' translated action: #startOver.\\n\\taCustomMenu addLine.\\n\\taCustomMenu add: 'full speed' translated action: #fullSpeed.\\n\\taCustomMenu add: 'slow speed' translated action: #slowSpeed.\\n\\taCustomMenu addLine.\\n\\taCustomMenu add: 'set scale' translated action: #setScale.\\n\\taCustomMenu add: 'make parameter slider' translated action: #makeParameterSlider.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'sd 11/20/2005 21:26'!\\nfullSpeed\\n\\t\\\"Run at maximum speed.\\\"\\n\\n\\tstepTime := 0.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'dgd 2/21/2003 22:53'!\\nmakeParameterSlider\\n\\t| menu choice s |\\n\\tmenu := CustomMenu new title: 'Parameter?'.\\n\\tself sliderParameters do: [:rec | menu add: rec first action: rec].\\n\\tchoice := menu startUp.\\n\\tchoice ifNil: [^self].\\n\\ts := self \\n\\t\\t\\t\\tnewSliderForParameter: choice first\\n\\t\\t\\t\\ttarget: self\\n\\t\\t\\t\\tmin: (choice second)\\n\\t\\t\\t\\tmax: (choice third)\\n\\t\\t\\t\\tdescription: (choice fourth).\\n\\tself world activeHand attachMorph: s! !\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'sd 11/20/2005 21:26'!\\nsetScale\\n\\n\\t| reply |\\n\\treply := FillInTheBlank\\n\\t\\trequest: 'Set the number of pixels per patch (a number between 1 and 10)?'\\n\\t\\t initialAnswer: pixelsPerPatch printString.\\n\\treply isEmpty ifTrue: [^ self].\\n\\tpixelsPerPatch := ((reply asNumber rounded) max: 1) min: 10.\\n\\tself changed.\\n\\tsuper extent: dimensions * pixelsPerPatch.\\n\\tself clearAll. \\\"be sure this is done once in case setup fails to do it\\\"\\n\\tself setup.\\n\\tself startOver.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'jm 2/5/2001 17:52'!\\nsingleStep\\n\\t\\\"Take one step and redisplay.\\\"\\n\\n\\tself oneStep.\\n\\tself changed.\\n\\n! !\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'jm 2/7/2001 19:07'!\\nsliderParameters\\n\\t\\\"Answer a list of parameters that the user can change via a slider. Each parameter is described by an array of: <name> <min value> <max value> <balloon help string>.\\\"\\n\\n\\t^ #((evaporationRate 0 40\\n\\t\\t\\t'The rate at which chemicals evaporate in this world. Larger numbers give faster evaporation.')\\n\\t\\t(diffusionRate 0 5\\n\\t\\t\\t'The rate of chemical diffusion. Larger numbers give quicker diffusion.'))\\n! !\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'sd 11/20/2005 21:26'!\\nslowSpeed\\n\\t\\\"Run at slow speed.\\\"\\n\\n\\tstepTime := 250.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'jm 2/6/2001 22:04'!\\nstartOver\\n\\t\\\"Restart this StarSqueak simulation from its initial conditions.\\\"\\n\\n\\tself clearAll.\\n\\tself setup.\\n\\tself changed.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'sd 11/20/2005 21:26'!\\nstartRunning\\n\\t\\\"Start running this StarSqueak simulation.\\\"\\n\\n\\trunning := true.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'menu' stamp: 'sd 11/20/2005 21:26'!\\nstopRunning\\n\\t\\\"STop running this StarSqueak simulation.\\\"\\n\\n\\trunning := false.\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'parts bin' stamp: 'sw 7/13/2001 22:22'!\\ninitializeToStandAlone\\n\\tself initialize.\\n\\tself startRunning! !\\n\\n\\n!StarSqueakMorph methodsFor: 'patches' stamp: 'jm 3/8/2001 13:47'!\\nclearPatches\\n\\t\\\"Clear patch colors, including turtle trails.\\\"\\n\\n\\tpatchForm fill: patchForm boundingBox fillColor: Color black.\\n\\n! !\\n\\n!StarSqueakMorph methodsFor: 'patches' stamp: 'jm 1/22/2001 16:52'!\\ncreatePatchVariable: patchVarName\\n\\t\\\"Create a patch variable of the given name. It is initialized to a value of zero for every patch.\\\"\\n\\n\\tpatchVariables\\n\\t\\tat: patchVarName\\n\\t\\tput: (Bitmap new: (dimensions x * dimensions y) withAll: 0).\\n! !\\n\\n!StarSqueakMorph methodsFor: 'patches' stamp: 'sd 11/20/2005 21:26'!\\ndecayPatchVariable: patchVarName\\n\\t\\\"Decay the values of the patch variable of the given name. That is, the value of each patch is replaced by a fraction of its former value, resulting in an expontial decay each patch's value over time. This can be used to model evaporation of a pheromone.\\\"\\n\\n\\t| patchVar |\\n\\tpatchVar := patchVariables at: patchVarName ifAbsent: [^ self].\\n\\tself primEvaporate: patchVar rate: scaledEvaporationRate.\\n\\n! !\\n\\n!StarSqueakMorph methodsFor: 'patches' stamp: 'sd 11/20/2005 21:26'!\\ndiffusePatchVariable: patchVarName\\n\\t\\\"Diffuse the patch variable of the given name.\\\"\\n\\n\\t| v newV |\\n\\tdiffusionRate = 0 ifTrue: [^ self]. \\\"no diffusion\\\"\\n\\tv := patchVariables at: patchVarName ifAbsent: [^ self].\\n\\tnewV := Bitmap new: v size.\\n\\tself primDiffuseFrom: v\\n\\t\\tto: newV\\n\\t\\twidth: dimensions x\\n\\t\\theight: dimensions y\\n\\t\\tdelta: diffusionRate truncated.\\n\\tpatchVariables at: patchVarName put: newV.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'patches' stamp: 'sd 11/20/2005 21:26'!\\npatchesDo: aBlock\\n\\t\\\"Evaluate the given block for every patch in this world.\\\"\\n\\n\\t| patch |\\n\\tpatch := StarSqueakPatch new world: self.\\n\\t0 to: dimensions y - 1 do: [:y |\\n\\t\\tpatch y: y.\\n\\t\\t0 to: dimensions x - 1 do: [:x |\\n\\t\\t\\tpatch x: x.\\n\\t\\t\\taBlock value: patch]].\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\naddTurtleDemon: aSelector\\n\\t\\\"Add the given selector to the list of selectors sent to every turtle on every step.\\\"\\n\\n\\tturtleDemons := turtleDemons copyWith: aSelector.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\naddWorldDemon: aSelector\\n\\t\\\"Add the given selector to the list of selectors sent to the world on every step.\\\"\\n\\n\\tworldDemons := worldDemons copyWith: aSelector.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\nclearAll\\n\\t\\\"Reset this StarSqueak world. All patch variables are cleared, all turtles are removed, and all demons are turned off.\\\"\\n\\n\\tpatchVariables := Dictionary new: 10.\\n\\tpatchVariableToDisplay := nil.\\n\\tlogPatchVariableScale := 0.\\n\\tpatchForm := Form extent: (dimensions * pixelsPerPatch) depth: 32.\\n\\tself createPatchFormGetterAndSetter.\\n\\tpatchVarDisplayForm := nil.\\n\\tself clearPatches.\\n\\tturtles := #().\\n\\tturtleDemons := #().\\n\\tworldDemons := #().\\n\\tsniffRange := 1.\\n\\tlastTurtleID := -1.\\n\\tgeneration := 0.\\n\\trunning := false.\\n\\tstepTime := 0. \\\"full speed\\\"\\n\\tturtlesAtPatchCache := nil.\\n\\tturtlesAtPatchCacheValid := false.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'setup' stamp: 'jm 1/24/2001 12:42'!\\ndisplayPatchVariable: patchVarName\\n\\t\\\"Make this StarSqueak world display the patch variable of the given name. Only one patch variable can be displayed at any given time.\\\"\\n\\n\\tself displayPatchVariable: patchVarName logScale: -2.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\ndisplayPatchVariable: patchVarName logScale: logBase2OfScaleFactor\\n\\t\\\"Make this StarSqueak world display the patch variable of the given name. Only one patch variable can be displayed at any given time. Values are scaled by 2^logBase2OfScaleFactor. For example, a value of 5 scales by 32 and a value of -2 scales by 1/4.\\\"\\n\\n\\t(patchVariables includesKey: patchVarName) ifFalse: [\\n\\t\\tpatchVariableToDisplay := nil.\\n\\t\\tpatchVarDisplayForm := nil.\\n\\t\\t^ self].\\n\\tpatchVariableToDisplay := patchVarName.\\n\\tpatchVarDisplayForm := Form extent: (dimensions * pixelsPerPatch) depth: 32.\\n\\tlogPatchVariableScale := logBase2OfScaleFactor.\\n\\tself clearPatches.\\n\\n! !\\n\\n!StarSqueakMorph methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\nrandom: range\\n\\t\\\"Answer a random integer between 0 and range.\\\"\\n\\n\\tRandomSeed := ((RandomSeed * 1309) + 13849) bitAnd: 65535.\\n\\t^ (RandomSeed * (range + 1)) // 65536\\n! !\\n\\n!StarSqueakMorph methodsFor: 'setup' stamp: 'jm 1/23/2001 07:24'!\\nsetup\\n\\t\\\"Subclasses should override this to setup the initial conditions of this StarSqueak world. The method should start with 'self clearAll'.\\\"\\n\\n\\tself clearAll.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'setup' stamp: 'jm 3/3/2001 12:54'!\\nstarSqueakDimensions\\n\\t\\\"Answer the dimensions of this StarSqueak simulation. Subclasses can override this method to define their own world size.\\\"\\n\\n\\t^ 100@100\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'stepping and presenter' stamp: 'dgd 2/21/2003 22:53'!\\noneStep\\n\\t\\\"Perform one step of the StarSqueak world. Execute all turtle and world demons.\\\"\\n\\n\\t\\\"run demons in random order and increment the generation counter\\\"\\n\\n\\t| currentTurtles |\\n\\tturtleDemons notEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"Note: Make a copy of turtles list that won't change if turtles are created/deleted.\\\"\\n\\n\\t\\t\\tcurrentTurtles := turtles copy.\\n\\t\\t\\tturtleDemons shuffled \\n\\t\\t\\t\\tdo: [:sel | 1 to: currentTurtles size do: [:i | (currentTurtles at: i) perform: sel]]].\\n\\tworldDemons shuffled do: [:sel | self perform: sel].\\n\\tgeneration := generation + 1.\\n\\tturtlesAtPatchCacheValid := false! !\\n\\n!StarSqueakMorph methodsFor: 'stepping and presenter' stamp: 'jm 1/26/2001 17:21'!\\nstep\\n\\n\\trunning ifTrue: [\\n\\t\\tself oneStep.\\n\\t\\tself changed].\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'testing' stamp: 'jm 1/22/2001 17:52'!\\nstepTime\\n\\n\\t^ stepTime\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'turtles' stamp: 'jm 3/12/2001 09:44'!\\nmakeTurtles: count\\n\\t\\\"Create the given number of generic turtles.\\\"\\n\\n\\tself makeTurtles: count class: StarSqueakTurtle.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'turtles' stamp: 'sd 11/20/2005 21:26'!\\nmakeTurtles: count class: turtleClass\\n\\t\\\"Create the given number of turtles of the given turtle class.\\\"\\n\\n\\tturtles := turtles,\\n\\t\\t((1 to: count) collect: [:i |\\n\\t\\t\\tturtleClass new\\n\\t\\t\\t\\tinitializeWorld: self\\n\\t\\t\\t\\twho: (lastTurtleID := lastTurtleID + 1)]).\\n\\tself changed.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'turtles' stamp: 'jm 1/28/2001 10:55'!\\nturtles\\n\\n\\t^ turtles\\n! !\\n\\n!StarSqueakMorph methodsFor: 'turtles' stamp: 'dgd 2/21/2003 22:53'!\\nturtlesAtX: x y: y do: aBlock \\n\\t\\\"Evaluate the given block for each turtle at the given location.\\\"\\n\\n\\t| t |\\n\\tt := self firstTurtleAtX: x y: y.\\n\\t[t isNil] whileFalse: \\n\\t\\t\\t[aBlock value: t.\\n\\t\\t\\tt := t nextTurtle]! !\\n\\n!StarSqueakMorph methodsFor: 'turtles' stamp: 'jm 3/3/2001 18:08'!\\nturtlesDo: aBlock\\n\\t\\\"Evaluate the given block for every turtle. For example:\\n\\t\\tw turtlesDo: [:t | t forward: 1]\\n\\twill tell every turtle to go forward by one turtle step.\\\"\\n\\n\\tturtles do: aBlock.\\n\\tself changed.\\n! !\\n\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\ncreatePatchFormGetterAndSetter\\n\\t\\\"Create BitBlt's for getting and setting patch colors.\\\"\\n\\n\\tpatchColorGetter := BitBlt bitPeekerFromForm: patchForm.\\n\\tpatchColorSetter :=\\n\\t\\t(BitBlt toForm: patchForm)\\n\\t\\t\\tcombinationRule: Form over;\\n\\t\\t\\tclipRect: patchForm boundingBox;\\n\\t\\t\\twidth: pixelsPerPatch;\\n\\t\\t\\theight: pixelsPerPatch.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\ndeleteTurtle: aTurtle\\n\\t\\\"Delete the given turtle from this world.\\\"\\n\\n\\tturtles := turtles copyWithout: aTurtle.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'jm 1/22/2001 16:58'!\\ndimensions\\n\\n\\t^ dimensions\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'jdl 3/28/2003 09:32'!\\ndisplayPatchVariableOn: aForm color: aColor shift: shiftAmount \\n\\t\\\"Display patchVariableToDisplay in the given color. The opacity (alpha) of of each patch is determined by the patch variable value for that patch and shiftAmount. If shiftAmount is zero, the source value is unscaled. Positive shiftAmount values result in right shifting the source value by the given number of bits (That is, multiplying by 2^N. Negative values perform right shifts, dividing by 2^N).\\\"\\n\\n\\t| patchVar bitBlt w rowOffset alpha |\\n\\tpatchVariableToDisplay ifNil: [^self].\\n\\tpatchVar := patchVariables at: patchVariableToDisplay ifAbsent: [^self].\\n\\n\\t\\\"set up the BitBlt\\\"\\n\\tbitBlt := (BitBlt toForm: aForm)\\n\\t\\t\\t\\tsourceRect: (0 @ 0 extent: pixelsPerPatch);\\n\\t\\t\\t\\tfillColor: aColor;\\n\\t\\t\\t\\tcombinationRule: 30.\\n\\tw := dimensions x.\\n\\t0 to: dimensions y - 1\\n\\t\\tdo: \\n\\t\\t\\t[:y | \\n\\t\\t\\trowOffset := y * w + 1.\\n\\t\\t\\t0 to: w - 1\\n\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t[:x | \\n\\t\\t\\t\\t\\talpha := (patchVar at: rowOffset + x) bitShift: shiftAmount.\\n\\t\\t\\t\\t\\talpha := alpha min: 255.\\n\\t\\t\\t\\t\\talpha > 1 \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[\\\"if not transparent, fill using the given alpha\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\tbitBlt destOrigin: (x * pixelsPerPatch) @ (y * pixelsPerPatch).\\n\\t\\t\\t\\t\\t\\t\\tbitBlt copyBitsTranslucent: alpha]]]! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\nfirstTurtleAtX: xPos y: yPos \\n\\n\\t| w t x y index |\\n\\t\\\"create turtlesAtPatchCache if necessary\\\"\\n\\tturtlesAtPatchCache ifNil: [\\n\\t\\tturtlesAtPatchCache := Array new: (dimensions x * dimensions y) withAll: nil.\\n\\t\\tturtlesAtPatchCacheValid := false].\\n\\n\\tw := dimensions y.\\n\\tturtlesAtPatchCacheValid ifFalse: [\\n\\t\\tturtlesAtPatchCache atAllPut: nil.\\n\\t\\t\\\"cache not yet computed for this step; make linked list of turtles for each patch\\\"\\n\\t\\t1 to: turtles size do: [:i |\\n\\t\\t\\tt := turtles at: i.\\n\\t\\t\\tx := t x truncated.\\n\\t\\t\\ty := t y truncated.\\n\\t\\t\\tindex := (w * y) + x + 1.\\n\\t\\t\\tt nextTurtle: (turtlesAtPatchCache at: index).\\n\\t\\t\\tturtlesAtPatchCache at: index put: t].\\n\\t\\tturtlesAtPatchCacheValid := true].\\n\\n\\tx := xPos truncated.\\n\\ty := yPos truncated.\\n\\tindex := (w * y) + x + 1.\\n\\t^ turtlesAtPatchCache at: index\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\ngetPatchBrightnessAtX: x y: y\\n\\t\\\"Answer the brightness of the patch at the given location, a number from 0 to 100.\\\"\\n\\n\\t| c |\\n\\tc := self getPatchColorAtX: x y: y.\\n\\t^ (c brightness * 100.0) rounded\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\ngetPatchColorAtX: x y: y\\n\\t\\\"Answer the color of the patch at the given location.\\\"\\n\\n\\t| pixel |\\n\\tpixel := patchColorGetter pixelAt:\\n\\t\\t(pixelsPerPatch * x truncated)@(pixelsPerPatch * y truncated).\\n\\t^ Color colorFromPixelValue: pixel depth: patchForm depth\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\ngetPatchVariable: patchVarName atX: xPos y: yPos\\n\\t\\\"Answer the value of the given patch variable at the given turtle. Answer zero if the turtle is out of bounds.\\\"\\n\\n\\t| x y i |\\n\\tx := xPos truncated.\\n\\ty := yPos truncated.\\n\\t((x < 0) or: [y < 0]) ifTrue: [^ 0].\\n\\t((x >= dimensions x) or: [y >= dimensions y]) ifTrue: [^ 0].\\n\\ti := ((y * dimensions x) + x) truncated + 1.\\n\\t^ (patchVariables at: patchVarName ifAbsent: [^ 0]) at: i\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\nincrementPatchVariable: patchVarName atX: xPos y: yPos by: amount\\n\\t\\\"Increment the value of the given patch variable at the given location by the given amount. Do nothing if the location is out of bounds.\\\"\\n\\n\\t| x y i var |\\n\\tx := xPos truncated.\\n\\ty := yPos truncated.\\n\\t((x < 0) or: [y < 0]) ifTrue: [^ self].\\n\\t((x >= dimensions x) or: [y >= dimensions y]) ifTrue: [^ self].\\n\\ti := ((y * dimensions x) + x) truncated + 1.\\n\\tvar := patchVariables at: patchVarName ifAbsent: [^ self].\\n\\tvar at: i put: ((var at: i) + amount).\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\nnewSliderForParameter: parameter target: target min: min max: max description: description\\n\\n\\t| c slider r s |\\n\\tc := (AlignmentMorph newColumn)\\n\\t\\tcolor: Color lightBlue;\\n\\t\\tborderWidth: 2;\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tuseRoundedCorners.\\n\\tslider := SimpleSliderMorph new\\n\\t\\tcolor: (Color r: 0.065 g: 0.548 b: 0.645);\\n\\t\\textent: 150@2;\\n\\t\\ttarget: target;\\n\\t\\tactionSelector: (parameter, ':') asSymbol;\\n\\t\\tminVal: min;\\n\\t\\tmaxVal: max;\\n\\t\\tadjustToValue: (target perform: parameter asSymbol).\\n\\tc addMorphBack: slider.\\n\\tr := (AlignmentMorph newRow)\\n\\t\\tcolor: Color lightBlue;\\n\\t\\thResizing: #spaceFill;\\n\\t\\tvResizing: #spaceFill.\\n\\ts := StringMorph new contents: parameter, ': '.\\n\\tr addMorphBack: s.\\n\\ts := UpdatingStringMorph new\\n\\t\\ttarget: target;\\n\\t\\tgetSelector: parameter asSymbol;\\n\\t\\tputSelector: (parameter, ':') asSymbol;\\n\\t\\tfloatPrecision: (10.0 raisedTo: (((max - min) / 150.0) log: 10) floor);\\n\\t\\tstep.\\n\\tr addMorphBack: s.\\n\\tc addMorphBack: r.\\n\\tc setBalloonText: description.\\n\\t^ c\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'jm 1/18/2001 21:58'!\\npatchVariable: patchVarName ifAbsent: aBlock\\n\\t\\\"Answer the patch variable array of the given name. If no such patch variables exists, answer the result of evaluating the given block.\\\"\\n\\n\\t^ patchVariables at: patchVarName ifAbsent: aBlock\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\nreplicateTurtle: aTurtle\\n\\t\\\"Create an exact copy of the given turtle and add it to this world.\\\"\\n\\n\\t| newTurtle |\\n\\tnewTurtle := aTurtle clone who: (lastTurtleID := lastTurtleID + 1).\\n\\tturtles := turtles copyWith: newTurtle.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'jdl 3/28/2003 09:34'!\\nsetPatchBrightnessAtX: x y: y to: percent \\n\\t\\\"Set the brightness of the patch at the given location to the given level, where 0 is black and 100 is full brightness.\\\"\\n\\n\\t| c brightness |\\n\\tc := self getPatchColorAtX: x y: y.\\n\\tbrightness := percent / 100.0.\\n\\tbrightness := brightness max: 0.03125.\\n\\tself \\n\\t\\tsetPatchColorAtX: x\\n\\t\\ty: y\\n\\t\\tto: (Color \\n\\t\\t\\t\\th: c hue\\n\\t\\t\\t\\ts: c saturation\\n\\t\\t\\t\\tv: brightness)! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'jm 2/7/2001 07:20'!\\nsetPatchColorAtX: x y: y to: aColor\\n\\t\\\"Paint the patch at the given location with the given color.\\\"\\n\\n\\tpatchColorSetter\\n\\t\\tfillColor: aColor;\\n\\t\\tdestX: (pixelsPerPatch * x truncated);\\n\\t\\tdestY: (pixelsPerPatch * y truncated);\\n\\t\\tcopyBits.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\nsetPatchVariable: patchVarName atX: xPos y: yPos to: newValue\\n\\t\\\"Set the value of the given patch variable below the given turtle to the given value. Do nothing if the turtle is out of bounds.\\\"\\n\\n\\t| x y i var |\\n\\tx := xPos truncated.\\n\\ty := yPos truncated.\\n\\t((x < 0) or: [y < 0]) ifTrue: [^ self].\\n\\t((x >= dimensions x) or: [y >= dimensions y]) ifTrue: [^ self].\\n\\ti := ((y * dimensions x) + x) truncated + 1.\\n\\tvar := patchVariables at: patchVarName ifAbsent: [^ self].\\n\\tvar at: i put: newValue.\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'sd 11/20/2005 21:26'!\\nsumPatchVariable: patchVarName neighborsAtX: xPos y: yPos\\n\\t\\\"Answer the sum of the given patch variable for the eight neighbors of the patch at the given location. Answer zero if the location is out of bounds.\\\"\\n\\n\\t| patchVar x y w h xLeft xRight rowOffset sum |\\n\\tpatchVar := patchVariables at: patchVarName ifAbsent: [^ 0].\\n\\tx := xPos truncated.\\n\\ty := yPos truncated.\\n\\tw := dimensions x.\\n\\th := dimensions y.\\n\\t((x < 0) or: [y < 0]) ifTrue: [^ 0].\\n\\t((x >= w) or: [y >= h]) ifTrue: [^ 0].\\n\\txLeft := (x - 1) \\\\\\\\ w. \\\"column before x, wrapped\\\"\\n\\txRight := (x + 1) \\\\\\\\ w. \\\"column after x, wrapped\\\"\\n\\trowOffset := y * w.\\n\\tsum :=\\n\\t\\t(patchVar at: rowOffset + xLeft) +\\n\\t\\t(patchVar at: rowOffset + xRight).\\n\\trowOffset := ((y - 1) \\\\\\\\ h) * w. \\\"row above y, wrapped\\\"\\n\\tsum := sum +\\n\\t\\t(patchVar at: rowOffset + xLeft) +\\n\\t\\t(patchVar at: rowOffset + x) +\\n\\t\\t(patchVar at: rowOffset + xRight).\\n\\trowOffset := ((y + 1) \\\\\\\\ h) * w. \\\"row below y, wrapped\\\"\\n\\tsum := sum +\\n\\t\\t(patchVar at: rowOffset + xLeft) +\\n\\t\\t(patchVar at: rowOffset + x) +\\n\\t\\t(patchVar at: rowOffset + xRight).\\n\\t^ sum\\n\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private' stamp: 'jdl 3/28/2003 09:36'!\\nuphillOf: patchVarName forTurtle: aTurtle \\n\\t\\\"Answer the heading the points in the direction of increasing value for the given patch variable. If there is no gradient, or if the turtle is outside the world bounds, answer the turtles current heading.\\\"\\n\\n\\t| patchVar turtleX turtleY startX endX startY endY maxVal rowOffset thisVal maxValX maxValY |\\n\\tpatchVar := patchVariables at: patchVarName ifAbsent: [^aTurtle heading].\\n\\tturtleX := aTurtle x truncated + 1.\\n\\tturtleY := aTurtle y truncated + 1.\\n\\tturtleX := turtleX max: 1.\\n\\tturtleY := turtleY max: 1.\\n\\tturtleX := turtleX min: dimensions x.\\n\\tturtleY := turtleY min: dimensions y.\\n\\tstartX := turtleX - sniffRange max: 1.\\n\\tendX := turtleX + sniffRange min: dimensions x.\\n\\tstartY := turtleY - sniffRange max: 1.\\n\\tendY := turtleY + sniffRange min: dimensions y.\\n\\tmaxVal := patchVar at: (turtleY - 1) * dimensions x + turtleX.\\n\\tmaxValX := nil.\\n\\tstartY to: endY\\n\\t\\tdo: \\n\\t\\t\\t[:y | \\n\\t\\t\\trowOffset := (y - 1) * dimensions x.\\n\\t\\t\\tstartX to: endX\\n\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t[:x | \\n\\t\\t\\t\\t\\tthisVal := patchVar at: rowOffset + x.\\n\\t\\t\\t\\t\\tthisVal > maxVal \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[maxValX := x.\\n\\t\\t\\t\\t\\t\\t\\tmaxValY := y.\\n\\t\\t\\t\\t\\t\\t\\tmaxVal := thisVal]]].\\n\\tnil = maxValX ifTrue: [^aTurtle heading].\\n\\t^(((maxValX - turtleX) @ (maxValY - turtleY)) degrees + 90.0) \\\\\\\\ 360.0! !\\n\\n\\n!StarSqueakMorph methodsFor: 'private-primitives' stamp: 'jdl 3/28/2003 09:46'!\\nprimDiffuseFrom: srcBitmap to: dstBitmap width: width height: height delta: delta \\n\\t\\\"Diffuse the integer values of the source patch variable Bitmap into the output Bitmap. Each cell of the output is the average of the NxN area around it in the source, where N = (2 * delta) + 1.\\\"\\n\\n\\t| area startY endY startX endX sum rowStart |\\n\\t<primitive: 'primitiveDiffuseFromToWidthHeightDelta' module: 'StarSqueakPlugin'>\\n\\tarea := (2 * delta + 1) * (2 * delta + 1).\\n\\t1 to: height\\n\\t\\tdo: \\n\\t\\t\\t[:y | \\n\\t\\t\\tstartY := y - delta.\\n\\t\\t\\tstartY := startY max: 1.\\n\\t\\t\\tendY := y + delta.\\n\\t\\t\\tendY := endY min: height.\\n\\t\\t\\t1 to: width\\n\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t[:x | \\n\\t\\t\\t\\t\\tstartX := x - delta.\\n\\t\\t\\t\\t\\tstartX := startX max: 1.\\n\\t\\t\\t\\t\\tendX := x + delta.\\n\\t\\t\\t\\t\\tendX := endX min: width.\\n\\t\\t\\t\\t\\tsum := 0.\\n\\t\\t\\t\\t\\tstartY to: endY\\n\\t\\t\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t\\t\\t[:y2 | \\n\\t\\t\\t\\t\\t\\t\\trowStart := (y2 - 1) * width.\\n\\t\\t\\t\\t\\t\\t\\tstartX to: endX do: [:x2 | sum := sum + (srcBitmap at: rowStart + x2)]].\\n\\t\\t\\t\\t\\tdstBitmap at: (y - 1) * width + x put: sum // area]]! !\\n\\n!StarSqueakMorph methodsFor: 'private-primitives' stamp: 'jm 3/12/2001 09:45'!\\nprimEvaporate: aBitmap rate: rate\\n\\t\\\"Evaporate the integer values of the source Bitmap at the given rate, an integer between 0 and 1024, where 1024 is a scale factor of 1.0 (i.e., no evaporation). That is, replace each integer element v with (rate * v) / 1024.\\\"\\n\\n\\t<primitive: 'primitiveEvaporateRate' module: 'StarSqueakPlugin'>\\n\\t1 to: aBitmap size do: [:i |\\n\\t\\taBitmap at: i put: (((aBitmap at: i) * rate) bitShift: -10)].\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private-primitives' stamp: 'sd 11/20/2005 21:26'!\\nprimMapFrom: srcBitmap to: dstBitmap width: w height: h patchSize: patchSize rgbFlags: rgbFlags shift: shiftAmount \\n\\t\\\"Map values in the source bitmap (interpreted as unsigned 32-bit integers) to 2x2 patches of color in the destination bitmap. The color brightness level is determined by the source value and the color hue is determined by the bottom three bits of the rgbFlags value. For example, if rgbFlags is 1, you get shades of blue, if it is 6 you get shades of yellow, and if it is 7, you get shades of gray. The shiftAmount is used to scale the source data values by a power of two. If shiftAmount is zero, the data is unscaled. Positive shiftAmount values result in right shifting the source data by the given number of bits (multiplying by 2^N, negative values perform right shifts (dividing by 2^N). The width parameter gives the width of the Form that owns the destination bitmap.\\\"\\n\\n\\t| rgbMult srcIndex level pixel offset |\\n\\t<primitive: 'primitiveMapFromToWidthHeightPatchSizeRgbFlagsShift' module: 'StarSqueakPlugin'>\\n\\trgbMult := 0.\\n\\t(rgbFlags bitAnd: 4) > 0 ifTrue: [rgbMult := rgbMult + 65536].\\n\\t(rgbFlags bitAnd: 2) > 0 ifTrue: [rgbMult := rgbMult + 256].\\n\\t(rgbFlags bitAnd: 1) > 0 ifTrue: [rgbMult := rgbMult + 1].\\n\\tsrcIndex := 0.\\n\\t0 to: h // patchSize - 1\\n\\t\\tdo: \\n\\t\\t\\t[:y | \\n\\t\\t\\t0 to: w // patchSize - 1\\n\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t[:x | \\n\\t\\t\\t\\t\\tlevel := (srcBitmap at: (srcIndex := srcIndex + 1)) bitShift: shiftAmount.\\n\\t\\t\\t\\t\\tlevel := level min: 255.\\n\\t\\t\\t\\t\\tpixel := level <= 0 \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[\\\"non-transparent black\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t1]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [level * rgbMult].\\n\\n\\t\\t\\t\\t\\t\\\"fill a patchSize x patchSize square with the pixel value\\\"\\n\\t\\t\\t\\t\\toffset := (y * w + x) * patchSize.\\n\\t\\t\\t\\t\\toffset to: offset + ((patchSize - 1) * w)\\n\\t\\t\\t\\t\\t\\tby: w\\n\\t\\t\\t\\t\\t\\tdo: \\n\\t\\t\\t\\t\\t\\t\\t[:rowStart | \\n\\t\\t\\t\\t\\t\\t\\trowStart + 1 to: rowStart + patchSize\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:dstIndex | dstBitmap at: dstIndex put: pixel]]]]! !\\n\\n!StarSqueakMorph methodsFor: 'private-primitives' stamp: 'sd 11/20/2005 21:26'!\\ntestDiffusePrim\\n\\t\\\"This test should diffuse the initial value in the center cell so that each cell has 1000.\\\"\\n\\t\\\"StarSqueakMorph new testDiffusePrim\\\"\\n\\n\\t| src dst |\\n\\tsrc := Bitmap new: 49.\\n\\tsrc at: 25 put: 49000.\\n\\tdst := Bitmap new: 49.\\n\\tself primDiffuseFrom: src to: dst width: 7 height: 7 delta: 3.\\n\\t^ dst asArray\\n! !\\n\\n!StarSqueakMorph methodsFor: 'private-primitives' stamp: 'sd 11/20/2005 21:26'!\\ntestEvaporatePrim\\n\\t\\\"This test should result in reducing each element of the array to 75% of its initial value.\\\"\\n\\t\\\"StarSqueakMorph new testEvaporatePrim\\\"\\n\\n\\t| data |\\n\\tdata := Bitmap new: 10.\\n\\t1 to: data size do: [:i | data at: i put: (10000 * i)].\\n\\tself primEvaporate: data rate: (75 * 1024) // 100.\\n\\t^ data asArray\\n\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStarSqueakMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!StarSqueakMorph class methodsFor: 'class initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitialize\\n\\t\\\"StarSqueakMorph initialize\\\"\\n\\n\\tRandomSeed := 17.\\n! !\\nObject subclass: #StarSqueakPatch\\n\\tinstanceVariableNames: 'world worldWidth worldHeight x y'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'StarSqueak-Kernel'!\\n!StarSqueakPatch commentStamp: '<historical>' prior: 0!\\nI represent a patch in a StarSqueak world. Patch objects are not retained, but are created as needed, such as in patchesDo:.\\n!\\n\\n\\n!StarSqueakPatch methodsFor: 'accessing' stamp: 'jm 1/27/2001 08:59'!\\nasPoint\\n\\n\\t^ x @ y\\n! !\\n\\n!StarSqueakPatch methodsFor: 'accessing' stamp: 'jm 1/19/2001 08:28'!\\nworld\\n\\n\\t^ world\\n! !\\n\\n!StarSqueakPatch methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\nworld: aStarSqueakMorph\\n\\t\\\"Set the world for this patch. Also record the world's width and height.\\\"\\n\\n\\t| dims |\\n\\tworld := aStarSqueakMorph.\\n\\tdims := world dimensions.\\n\\tworldWidth := dims x.\\n\\tworldHeight := dims y.\\n! !\\n\\n!StarSqueakPatch methodsFor: 'accessing' stamp: 'jm 1/18/2001 21:27'!\\nx\\n\\n\\t^ x\\n! !\\n\\n!StarSqueakPatch methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\nx: anInteger\\n\\n\\tx := anInteger.\\n! !\\n\\n!StarSqueakPatch methodsFor: 'accessing' stamp: 'jm 1/18/2001 21:27'!\\ny\\n\\n\\t^ y\\n! !\\n\\n!StarSqueakPatch methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\ny: anInteger\\n\\n\\ty := anInteger.\\n! !\\n\\n\\n!StarSqueakPatch methodsFor: 'geometry' stamp: 'jm 1/28/2001 15:27'!\\nisBottomEdge\\n\\n\\t^ y = (worldHeight - 1)\\n! !\\n\\n!StarSqueakPatch methodsFor: 'geometry' stamp: 'jm 1/28/2001 15:27'!\\nisLeftEdge\\n\\n\\t^ x = 0\\n! !\\n\\n!StarSqueakPatch methodsFor: 'geometry' stamp: 'jm 1/28/2001 15:27'!\\nisRightEdge\\n\\n\\t^ x = (worldWidth - 1)\\n! !\\n\\n!StarSqueakPatch methodsFor: 'geometry' stamp: 'jm 1/28/2001 15:27'!\\nisTopEdge\\n\\n\\t^ y = 0\\n! !\\n\\n\\n!StarSqueakPatch methodsFor: 'neighborhood' stamp: 'jm 1/28/2001 15:06'!\\nneighborE\\n\\t\\\"Answer the neightboring patch directly south of (below) this patch.\\\"\\n\\n\\t^ self clone x: ((x + 1) \\\\\\\\ worldWidth)\\n! !\\n\\n!StarSqueakPatch methodsFor: 'neighborhood' stamp: 'jm 1/28/2001 15:06'!\\nneighborN\\n\\t\\\"Answer the neightboring patch directly north of (above) this patch.\\\"\\n\\n\\t^ self clone y: ((y - 1) \\\\\\\\ worldHeight)\\n! !\\n\\n!StarSqueakPatch methodsFor: 'neighborhood' stamp: 'hh 8/26/2001 17:03'!\\nneighborNE\\n\\t\\\"Answer the neightboring patch directly south of (below) this patch.\\\"\\n\\n\\t^ self clone\\n\\t\\tx: ((x + 1) \\\\\\\\ worldWidth);\\n\\t\\ty: ((y - 1) \\\\\\\\ worldHeight)\\n! !\\n\\n!StarSqueakPatch methodsFor: 'neighborhood' stamp: 'hh 8/26/2001 17:03'!\\nneighborNW\\n\\t\\\"Answer the neightboring patch directly south of (below) this patch.\\\"\\n\\n\\t^ self clone\\n\\t\\tx: ((x - 1) \\\\\\\\ worldWidth);\\n\\t\\ty: ((y - 1) \\\\\\\\ worldHeight)\\n! !\\n\\n!StarSqueakPatch methodsFor: 'neighborhood' stamp: 'jm 1/28/2001 15:06'!\\nneighborS\\n\\t\\\"Answer the neightboring patch directly south of (below) this patch.\\\"\\n\\n\\t^ self clone y: ((y + 1) \\\\\\\\ worldHeight)\\n! !\\n\\n!StarSqueakPatch methodsFor: 'neighborhood' stamp: 'hh 8/26/2001 17:03'!\\nneighborSE\\n\\t\\\"Answer the neightboring patch directly south of (below) this patch.\\\"\\n\\n\\t^ self clone\\n\\t\\tx: ((x + 1) \\\\\\\\ worldWidth);\\n\\t\\ty: ((y + 1) \\\\\\\\ worldHeight)\\n! !\\n\\n!StarSqueakPatch methodsFor: 'neighborhood' stamp: 'hh 8/26/2001 17:04'!\\nneighborSW\\n\\t\\\"Answer the neightboring patch directly south of (below) this patch.\\\"\\n\\n\\t^ self clone\\n\\t\\tx: ((x - 1) \\\\\\\\ worldWidth);\\n\\t\\ty: ((y + 1) \\\\\\\\ worldHeight)\\n! !\\n\\n!StarSqueakPatch methodsFor: 'neighborhood' stamp: 'jm 1/28/2001 15:06'!\\nneighborW\\n\\t\\\"Answer the neightboring patch directly south of (below) this patch.\\\"\\n\\n\\t^ self clone x: ((x - 1) \\\\\\\\ worldWidth)\\n! !\\n\\n\\n!StarSqueakPatch methodsFor: 'patch color' stamp: 'jm 1/24/2001 15:57'!\\nbrightness\\n\\t\\\"Answer the brightness of this patch, a number from 0 to 100.\\\"\\n\\n\\t^ world getPatchBrightnessAtX: x y: y\\n! !\\n\\n!StarSqueakPatch methodsFor: 'patch color' stamp: 'jm 1/24/2001 15:56'!\\nbrightness: percent\\n\\t\\\"Set the brightness of this patch to the given level, where 0 is nearly black and 100 is full brightness.\\\"\\n\\n\\tworld setPatchBrightnessAtX: x y: y to: percent.\\n! !\\n\\n!StarSqueakPatch methodsFor: 'patch color' stamp: 'jm 1/24/2001 15:58'!\\ncolor\\n\\t\\\"Answer the color of this patch.\\\"\\n\\n\\t^ world getPatchColorAtX: x y: y\\n! !\\n\\n!StarSqueakPatch methodsFor: 'patch color' stamp: 'jm 1/24/2001 15:58'!\\ncolor: aColor\\n\\t\\\"Paint this patch the given color.\\\"\\n\\n\\tworld setPatchColorAtX: x y: y to: aColor.\\n! !\\n\\n\\n!StarSqueakPatch methodsFor: 'patch variables' stamp: 'jm 1/18/2001 21:31'!\\ndistanceTo: aPoint\\n\\t\\\"Answer the distance from this patch to the given point.\\\"\\n\\n\\t^ ((x - aPoint x) squared + (y - aPoint y) squared) sqrt\\n! !\\n\\n!StarSqueakPatch methodsFor: 'patch variables' stamp: 'sd 11/20/2005 21:26'!\\nget: patchVarName\\n\\t\\\"Answer the value of the given patch variable for this patch.\\\"\\n\\n\\t| patchVar |\\n\\tpatchVar := world patchVariable: patchVarName ifAbsent: [^ 0].\\n\\t^ patchVar at: (y * world dimensions x) + x + 1\\n! !\\n\\n!StarSqueakPatch methodsFor: 'patch variables' stamp: 'sd 11/20/2005 21:26'!\\nset: patchVarName to: newValue\\n\\t\\\"Set the value of the given patch variable for this patch to the given value.\\\"\\n\\n\\t| patchVar |\\n\\tpatchVar := world patchVariable: patchVarName ifAbsent: [^ self].\\n\\tpatchVar at: (y * world dimensions x) + x + 1 put: newValue.\\n! !\\nStarSqueakMorph subclass: #StarSqueakSlimeMold\\n\\tinstanceVariableNames: 'cellCount'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'StarSqueak-Worlds'!\\n\\n!StarSqueakSlimeMold methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitialize\\n\\n\\tcellCount := 200.\\n\\tsuper initialize.\\n! !\\n\\n\\n!StarSqueakSlimeMold methodsFor: 'menu' stamp: 'jm 2/7/2001 19:51'!\\nsliderParameters\\n\\t\\\"Answer a list of parameters that the user can change via a slider. Each parameter is described by an array of: <name> <min value> <max value> <balloon help string>.\\\"\\n\\n\\t^ super sliderParameters, #(\\n\\t\\t(cellCount 50 2000 'The number of slime mold cells.'))\\n! !\\n\\n\\n!StarSqueakSlimeMold methodsFor: 'other' stamp: 'jm 1/19/2001 18:36'!\\ndiffusePheromone\\n\\n\\tself diffusePatchVariable: 'pheromone'.\\n! !\\n\\n!StarSqueakSlimeMold methodsFor: 'other' stamp: 'jm 1/19/2001 18:36'!\\nevaporatePheromone\\n\\n\\tself decayPatchVariable: 'pheromone'.\\n! !\\n\\n\\n!StarSqueakSlimeMold methodsFor: 'parameters' stamp: 'jm 2/7/2001 19:28'!\\ncellCount\\n\\n\\t^ cellCount\\n! !\\n\\n!StarSqueakSlimeMold methodsFor: 'parameters' stamp: 'sd 11/20/2005 21:26'!\\ncellCount: aNumber\\n\\n\\tcellCount := aNumber asInteger.\\n\\n! !\\n\\n\\n!StarSqueakSlimeMold methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\nsetup\\n\\n\\tself clearAll.\\n\\tself makeTurtles: cellCount class: SlimeMoldTurtle.\\n\\tself createPatchVariable: 'pheromone'. \\\"emitted by slime mold cells\\\"\\n\\tturtleDemons := #(dropPheromone followPheromone breakLoose).\\n\\tworldDemons := #(evaporatePheromone diffusePheromone).\\n\\tself displayPatchVariable: 'pheromone'.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStarSqueakSlimeMold class\\n\\tinstanceVariableNames: ''!\\n\\n!StarSqueakSlimeMold class methodsFor: 'parts bin' stamp: 'sw 10/24/2001 16:36'!\\ndescriptionForPartsBin\\n\\t\\\"Answer a description of the receiver for use in a parts bin\\\"\\n\\n\\t^ self partName:\\t'SlimeMold'\\n\\t\\tcategories:\\t\\t#('StarSqueak')\\n\\t\\tdocumentation:\\t'A slime-mold simulation using StarSqueak'\\n\\t\\tsampleImageForm: (Form\\n\\textent: 92@96\\n\\tdepth: 8\\n\\tfromArray: #( 673720360 676154664 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911693 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1398364499 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1396729208 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1296911693 1294477352 674900008 673720360 673720360 673720360 673720360 673720360 673729869 1918072946 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1296911693 1296902184 674900008 673720360 673720360 673720360 673720360 673720360 673729869 1296911693 1296902184 673720360 673720360 673720360 673720360 673720360 676154701 1296911693 673720360 673720360 673720360 673720360 1296921202 1920103026 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296911693 1294477352 673720360 673720360 673720360 673720360 673720397 1296911693 1296911693 1296902184 673720360 673720360 673720397 1296921239 2021169010 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296911693 1294477352 673720360 673720360 673720360 673720360 673720397 1296921202 1917668685 1296911656 673720360 673720360 673720397 1299346040 1701148786 1917668685 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729832 673720360 673720360 673720360 673720360 673720360 673729869 1299355580 2543284850 1296911656 673720360 673720360 673720397 1296921276 2122234994 1917668685 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1920121883 3784808306 1296911656 673720360 673720360 673720397 1296921202 2543294322 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1922530886 3787233138 1296911656 673720360 673720360 673720397 1296911730 1920103026 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1918442267 3784808306 1296911656 673720360 673720360 673720397 1296911693 1920093517 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1299365052 3164041842 1296911656 673720360 673720360 673720397 1296911693 1296911693 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1296902184 673720360 673720360 673720360 673720360 673720397 1299346034 2540859981 1296911656 673720360 673720360 673720397 1296911693 1296911693 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911693 1294477352 673720360 673720360 673720360 673720397 1296911730 1920093517 1296911656 673720360 673720360 673729869 1296911693 1296911693 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1296911693 1296902184 673720360 673720360 673720360 673720360 1296911693 1296911693 1296911656 673720360 673720360 676154701 1296911693 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1299336525 1296911693 673720360 673720360 673720360 673720360 1296911693 1296911693 1296911656 673720360 673720360 1296911693 1296911693 1294477352 673720360 1179002920 673720360 673720360 673720360 673720360 673720360 673720360 1296911730 1920103026 1917668685 1296902184 673720360 673720360 673720360 676154701 1296911693 1296911656 673720360 673720397 1296911693 1179471181 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1296921202 2543294359 1920093517 1296911693 1294477352 673720360 673720360 673729869 1296911693 1296911656 673720360 673720397 1296462450 1917668685 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296921177 1189199036 2540850509 1296911693 1296911656 673720360 673720360 673729869 1296911693 1296911693 673720360 673720397 1299346071 1917668685 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296921276 3779479228 2540859981 1296911693 1296911693 673720360 673720360 673729869 1296921202 1917668685 1294477352 673720397 1299334726 1179471181 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1299346108 1179050465 2543284850 1920103026 1917668685 1294477352 673720360 673729869 1299346034 1920093517 1294477352 673720397 1299346071 1917668685 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296921276 3779518908 2540860018 1920103001 1500663117 1294477352 673720360 673729869 1920112454 2540859981 1296902184 673720397 1296921202 1917668648 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296921239 3166485692 1920103026 1920104537 1501065805 1296902184 673720360 673729869 1922530886 2123854413 1296902184 673720360 1296911693 1296911656 673720360 673720360 975710248 673720360 673720360 673720360 673720360 673720360 673720397 1296921202 1920103026 1920093554 1920104549 1702392397 1296902184 673720360 673729869 1922530886 1503097421 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673721896 673720360 673720360 673720360 673720360 1296911693 1920103026 1296911693 1920103032 2020756813 1296902184 673720360 673729869 1920121945 2540859981 1294477352 673720360 673720360 673720360 673720360 774383656 673720360 673720360 673721896 673720360 673720360 673720360 673720360 676154701 1296911693 1296911693 1299346040 2020756813 1294477352 673720360 673729869 1299346034 1500663117 1294477352 673720360 673720360 673720360 673720360 774383656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911693 1296911693 1296911699 1397574989 1294477352 673720360 673729869 1296911693 877481293 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 774776872 673720360 673720360 673720360 673720360 673720360 676154701 1296911693 1296911693 1296911693 673720360 673720360 673720397 1296911693 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 774776872 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1296902184 673720360 673720360 673720397 1296911693 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1296911693 1296911693 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296911693 1296911693 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1299346034 1920102989 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1299355580 3164041842 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1922546845 2646382450 1296911656 673720360 673720360 673720360 674900008 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1924981019 454777202 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1920917787 454777202 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1920122044 3166466674 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1920103001 1180267085 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1299346034 1920093517 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911730 1296911693 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911693 1296911693 1294477352 673720360 673720360 673724968 673720360 673720397 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1296911693 1296911693 673720360 673720360 673720360 673720360 673720360 676154701 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1296911693 1296902184 673720360 673720360 673720360 673720360 673720360 1296911693 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1296911693 1296911693 1296902184 673720360 673720360 673720360 673720360 673720397 1296921202 1499024717 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296911693 1296911693 1294477352 673720360 673720360 673720360 673720360 673720397 1296921239 2540850509 1294477352 673720360 673720360 673720360 673720360 675686440 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911693 1296911693 1294477352 673720360 673720360 673720360 673720360 673729869 1296914758 1180257613 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296462450 1917668685 1294477352 673720360 673720360 673720360 673720360 673729869 1299346009 1500663117 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1920112535 2540850509 1294477352 673720360 673720360 673720360 673720360 676154701 1296921202 1920093517 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1920112454 2539205709 1294477352 673720360 673720360 673720360 673720360 676154701 1296921202 1917668685 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1922516550 3161607501 1294477352 673720360 673720360 673720360 673720360 1296911693 1299345997 1296911693 1294477352 673720360 673720360 673720360 673720390 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1299339609 2540850509 1294477352 673720360 673720360 673720360 673720360 1296911730 1920093517 1296911693 1294477352 673729832 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1299346009 1917668685 1294477352 673720360 673720360 673720360 673720360 1296921202 1500672589 1296911693 673720397 1296911693 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911705 1296911693 673720360 673720360 673720360 673720360 673720397 1296914839 1181905491 1397574989 673729869 1296911668 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296911693 1296911656 673720360 673720360 673720360 673720360 673720360 1296914802 1181896019 1397574952 676154701 1296921177 1917668685 1294477352 673720360 673720360 673720366 673720360 673720360 673720360 673720360 673720360 673720360 1296911693 1296902184 673720360 673720360 673720360 673720360 673720360 1296911730 1181896013 1296902184 673729869 1299346009 1397969741 1296902184 673720360 673720360 673720366 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 674900008 673720360 673720360 676154701 877481293 1294477352 673729869 1296914777 1397969741 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 674900008 673720360 673720360 673729869 1296911693 673720360 673720397 1296914802 1917668685 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1296911705 1296911693 1294477352 673729844 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154676 1296911656 673720360 673729844 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911693 673720360 673720360 673720360 673720360 673729869 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 674113576 673720360 673720360 673720360 673720360 673720360 676154701 1296911693 1294477352 673720360 673720360 673720360 1296911693 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 674113576 673720360 673720360 673720360 673720360 673720360 1296911693 1296911693 1296902184 673724986 673720360 673720397 1296921202 1917668685 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296921202 1920103026 1296911656 673720360 673720360 673720397 1299355543 1917668685 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1299346071 2543294322 1917668648 673720360 673720360 673720397 1299334726 1498238285 673720360 673720360 673720360 673720360 673720360 673720360 673720378 975710248 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1920112572 3789676988 1917668648 673720360 673720360 673720397 1299339609 1917668685 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1922546913 3779518908 1920093480 673720360 673720360 673720397 1296921202 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1922516705 3779468121 1499024717 673720360 673720360 673720360 1296911693 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1922546913 3779518908 1920093480 673720360 673720360 673720360 676154701 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1920112572 3789676988 1917668648 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 674904616 673720397 1299334726 2543294322 1917668648 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1299346034 1920103026 1296911656 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673724986 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296911730 1920093517 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1294477352 673720360 673720360 673720360 1296911693 1296911693 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676148294 877471784 673720360 673720360 673720360 676154701 1296911693 673720360 673720360 673720360 675686440 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1296911668 877013032 673720360 673720360 673720360 673720360 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1296911693 1296902184 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720397 1296911656 673720360 673720360 676154701 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1397968205 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1497387853 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1497387853 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676154701 1397968205 1294477352 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673729869 1296911693 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1296911668 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720378 673720360 673720360 673720360 673720360 673720360 673720360 673721896 673720360 673720360 673720360)\\n\\toffset: 152@256)! !\\nStarSqueakMorph subclass: #StarSqueakTermites\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'StarSqueak-Worlds'!\\n\\n!StarSqueakTermites methodsFor: 'all' stamp: 'jm 1/24/2001 08:50'!\\nsetupPatches\\n\\t\\\"Create patch variables for sensing the nest and food caches. The nestScent variable is diffused so that it forms a 'hill' of scent over the entire world with its peak at the center of the nest. That way, the ants always know which way the nest is.\\\"\\n\\n\\tself createPatchVariable: 'woodChips'. \\\"number of wood chips on patch\\\"\\n\\tself displayPatchVariable: 'woodChips' logScale: 5.\\n\\tself patchesDo: [:p |\\n\\t\\t(self random: 8) = 0\\n\\t\\t\\tifTrue: [p set: 'woodChips' to: 1]\\n\\t\\t\\tifFalse: [p set: 'woodChips' to: 0]].\\n! !\\n\\n!StarSqueakTermites methodsFor: 'all' stamp: 'jm 1/28/2001 15:35'!\\nsetupTurtles\\n\\t\\\"Create an initialize my termites.\\\"\\n\\n\\tself makeTurtles: 400 class: TermiteTurtle.\\n\\tself turtlesDo: [:t | t isCarryingChip: false].\\n! !\\n\\n\\n!StarSqueakTermites methodsFor: 'setup' stamp: 'sd 11/20/2005 21:26'!\\nsetup\\n\\n\\tself clearAll.\\n\\tself setupPatches.\\n\\tself setupTurtles.\\n\\tturtleDemons := #(walk wiggle lookForChip lookForPile).\\n! !\\nStarSqueakMorph subclass: #StarSqueakTrees\\n\\tinstanceVariableNames: 'depth treeTypeSelector'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'StarSqueak-Worlds'!\\n\\n!StarSqueakTrees methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitialize\\n\\n\\tsuper initialize.\\n\\tdepth := 8.\\n\\ttreeTypeSelector := #tree1.\\n\\tself setup.\\n! !\\n\\n\\n!StarSqueakTrees methodsFor: 'menu' stamp: 'dgd 8/30/2003 22:17'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\n\\tsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.\\n\\taCustomMenu addLine.\\n\\taCustomMenu add: 'set tree depth' translated action: #setTreeDepth.\\n\\taCustomMenu add: 'set tree type' translated action: #setTreeType.\\n! !\\n\\n!StarSqueakTrees methodsFor: 'menu' stamp: 'rbb 3/1/2005 11:15'!\\nsetTreeDepth\\n\\n\\t| reply |\\n\\treply := UIManager default\\n\\t\\trequest: 'Tree depth (a number between 1 and 12)?'\\n\\t\\tinitialAnswer: depth printString.\\n\\treply isEmpty ifTrue: [^ self].\\n\\tdepth := ((reply asNumber rounded) max: 1) min: 12.\\n\\tself startOver.\\n! !\\n\\n!StarSqueakTrees methodsFor: 'menu' stamp: 'sd 11/20/2005 21:26'!\\nsetTreeType\\n\\n\\t| menu choice |\\n\\tmenu := CustomMenu new title: 'Choose tree type:'.\\n\\tmenu add: 'tree1' action: #tree1.\\n\\tmenu add: 'tree2' action: #tree2.\\n\\tchoice := menu startUp.\\n\\tchoice ifNotNil: [\\n\\t\\ttreeTypeSelector := choice.\\n\\t\\tself startOver].\\n! !\\n\\n\\n!StarSqueakTrees methodsFor: 'parts bin' stamp: 'sd 11/20/2005 21:26'!\\ninitializeToStandAlone\\n\\tself initialize.\\n\\ttreeTypeSelector := #tree2.\\n\\tself setup. \\\"Run earlier, but need to run again to get the #tree2 used\\\"\\n\\tself startRunning! !\\n\\n\\n!StarSqueakTrees methodsFor: 'setup' stamp: 'jm 3/12/2001 09:59'!\\nsetup\\n\\n\\tself clearAll.\\n\\tself makeTurtles: 1 class: TreeTurtle.\\n\\tself turtlesDo: [:t |\\n\\t\\tt goto: 50@90.\\n\\t\\tt penDown.\\n\\t\\tt color: Color red.\\n\\t\\tt heading: 0.\\n\\t\\tt length: 15.\\n\\t\\tt depth: depth].\\n\\tself addTurtleDemon: treeTypeSelector.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStarSqueakTrees class\\n\\tinstanceVariableNames: ''!\\n\\n!StarSqueakTrees class methodsFor: 'parts bin' stamp: 'sw 10/24/2001 16:37'!\\ndescriptionForPartsBin\\n\\t\\\"Answer a description of the receiver for use in a parts bin\\\"\\n\\n\\t^ self partName:\\t'Trees'\\n\\t\\tcategories:\\t\\t#('StarSqueak')\\n\\t\\tdocumentation:\\t'A tree-growing simulation using StarSqueak'\\n\\t\\tsampleImageForm: (Form\\n\\textent: 70@72\\n\\tdepth: 8\\n\\tfromArray: #( 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 681453608 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 681453608 673720360 673720360 673720360 673710080 673720360 673720360 673720360 1313744936 2661165134 2655922216 673720360 676241054 673720360 673720360 673720360 673720360 2653431848 1311284776 673720398 673720360 673720360 673710080 673720360 673720360 673720398 1313744936 2661195342 1311254568 673720360 676241054 2653431848 673750686 2661174862 2653431848 2655931944 1318987816 673720398 681453608 673720360 673710080 673720360 673720360 673750686 1313754664 2661195342 1311254568 673750606 673750686 673720360 673750686 2655931982 1318987816 2655922254 2653462174 673720398 2653431848 673720360 673710080 673720360 673720360 681453646 1319018024 2653431966 1311254568 673750686 1311284894 673720360 673720478 2661174862 2661165096 2653441694 2661195422 673720398 673750568 673720360 673710080 673720360 673720360 2661195342 676220574 2653431886 1313775262 681483934 1311284776 2653441576 673720478 681463374 2653431848 3257421470 2653462174 1311264334 681453726 673720360 673710080 673720360 673720398 2661195342 673730206 2653431848 1318997662 2661174862 3262300712 2653462174 1311254722 683852402 673720514 683843230 2661195422 1311264334 2661195304 673720360 673710080 673720360 673720360 2661195342 1313754782 2661165096 1920093854 2653441614 3262300712 681483854 1313744936 3262300786 673720514 3257411662 2661195304 673730206 673720360 673720360 673710080 673720360 673720398 681483934 2661195422 2661165096 1319018142 2653462094 678609448 681463454 2655922216 3262280232 673759938 3257421470 3267504286 676220456 673750568 673720360 673710080 673720360 673730206 673750606 2655922370 673759902 2661174942 3257421352 678570024 683852366 673720360 3245437224 683786792 683831848 1915264670 1316123176 673750686 673720360 673710080 673720360 673720360 2661165134 678589122 673750686 3267514049 2663524392 678504488 683812904 673720360 683766056 683747368 3267543746 2661195304 3262261288 2661165214 1311254568 673710080 673720360 673720360 673750606 673739304 3265175118 2661174977 3267504168 678504488 3240634408 673720360 678504488 1898496449 673720433 3265175198 3267543746 2661195422 1311254568 673710080 673720360 673730206 673720398 673720514 3257411742 2663563969 683812904 673759681 3240634408 673720360 678504488 1908484136 673720433 1898487490 1915234344 673720360 673720360 673710080 673720360 676241054 673720434 3262261288 3257441832 673739458 683747368 673759528 673720360 673720360 678504561 1898457128 673720433 1908484136 673720360 2661165096 673720360 673710080 673720360 676220456 2661195304 1920084008 3250661416 673720513 3250661416 673759528 673720360 673720360 678504561 1898457128 673739121 1898457128 673720360 2661195422 673720360 673710080 673720360 673730206 2653432002 3267523112 673759528 673720360 3250661416 673759528 673720360 673720360 678523249 673720360 673739201 1898457128 673720360 2661195304 673720360 673710080 673720360 676154958 1311254642 1920103025 1898496296 673720360 3245428008 676163880 673720360 673720360 681341261 673720360 676163953 1294477352 673720397 1313754702 673720360 673710080 673720360 676154664 673720360 673729905 1903280461 673720360 3240653133 678504488 673720360 673720360 681332008 673720360 681341224 673720360 676164253 676220574 673720360 673710080 673720360 673720360 673720360 673720360 678523292 1294477352 3240653212 1299261480 673720360 673720360 1903241256 673720360 681332008 673720360 1302109554 1319018142 673720360 673710080 673720360 673720360 673720360 673720360 673720433 1903250728 3240643996 1903241256 673720360 673720360 3243059240 673720360 1900881960 673720433 1903250728 1313775262 673720360 673710080 673720360 673720360 673720360 673720360 673720360 1299280168 3240634445 1906059304 673720360 673720360 3223857192 673720433 1898457165 1903260097 1898457128 1917754958 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673739121 1903241256 1302079528 673720360 673720360 3223857192 673739121 1903260017 1903260017 1903260274 1917734440 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673729905 1908484136 678504488 673720360 673720360 3223857192 678543729 1903259981 673720360 1299280498 1917724712 1296902184 673710080 673720360 673720360 673720360 673720360 673720360 673720360 1908418600 678504488 673720360 673720360 3223857192 1287680369 673720360 673720360 673720360 1922977358 1313679400 673710080 673720360 673720360 673720360 673720360 673720360 673720360 678513704 678504488 673720360 673720360 3223857228 1903241256 673720360 673720360 673720360 676240974 1313679400 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673739084 678504488 673720360 673720433 1898466417 1277700136 673720360 673720360 673720360 673750606 1296902184 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673739163 1282484264 673720360 673720512 676098380 673720360 673720360 673720360 673720360 673730206 1294477352 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673729691 1903241256 673720360 673720512 1903250472 673720360 673720360 673720360 673720360 673720478 1294477352 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720396 1905993768 673720360 673720512 1900816424 673720360 673720360 673720360 673720360 673720398 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1285236776 673720360 673739200 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 678504488 673720360 673759345 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 678504488 673720360 673759272 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 676098344 673720360 676098344 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673739121 673720360 678504488 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720512 673720360 1282484264 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720433 1898457128 1903241256 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 3223857192 1903241256 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 3223857228 1900816424 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 1903241329 1898457128 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 683681905 1898457128 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 683681905 1898457128 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673759345 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673759345 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673739121 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673738864 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673720360 673710080)\\n\\toffset: 478@345)! !\\nObject subclass: #StarSqueakTurtle\\n\\tinstanceVariableNames: 'world who x y wrapX wrapY headingRadians color penDown nextTurtle'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'StarSqueak-Kernel'!\\n!StarSqueakTurtle commentStamp: '<historical>' prior: 0!\\nI represent a \\\"creature\\\" that can move about on the surface of a StarSqueak world. I have a position and a heading (direction), and respond commands such as \\\"turnRight:\\\" and \\\"forward:\\\" by turning or moving. I also have an imaginary pen that can draw a trail as I move. In StarSqueak, turtles are born with random positions and headings.\\n\\nHere are some expressions to try in a workspace:\\n\\tw _ StarSqueakMorph new openInWorld.\\t\\\"make an empty world\\\"\\n\\tw makeTurtles: 100.\\t\\t\\t\\t\\t\\t\\\"create 100 turtles\\\"\\n\\tw turtlesDo: [:t | t forward: 1].\\t\\t\\t\\\"tell all turtles to take a step\\\"\\n\\tw turtlesDo: [:t | t goto: 50@50].\\t\\t\\t\\\"tell all turtles to go to 50@50\\\"\\n\\tw turtlesDo: [:t | t forward: 10].\\t\\t\\t\\\"tell all turtles to take 10 steps\\\"\\n\\nStructure:\\n world\\t\\t\\t\\tStarSqueakMorph\\t\\tthe world that owns this turtle\\n who\\t\\t\\t\\tinteger\\t\\t\\t\\t\\tunique id\\n x\\t\\t\\t\\t\\tnumber\\t\\t\\t\\t\\tx position in world\\n y\\t\\t\\t\\t\\tnumber\\t\\t\\t\\t\\ty position in world\\n wrapX\\t\\t\\t\\tfloat\\t\\t\\t\\t\\tprivate; used for wrapping in x\\n wrapY\\t\\t\\tfloat\\t\\t\\t\\t\\tprivate; used for wrapping in y\\n headingRadians\\tfloat\\t\\t\\t\\t\\theading in radians\\n color\\t\\t\\t\\tcolor\\t\\t\\t\\t\\tturtle color and its pen color\\n penDown\\t\\t\\tboolean\\t\\t\\t\\t\\ttrue if drawing a pen trail\\n nextTurtle\\t\\t\\tStarSqueaktTurtle\\t\\tprivate; used to make linked list of turtles\\n!\\n\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'jm 1/27/2001 08:59'!\\nasPoint\\n\\n\\t^ x truncated @ y truncated\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'jm 2/25/2000 16:03'!\\ncolor\\n\\n\\t^ color\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\ncolor: aColor\\n\\n\\tcolor := aColor.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\nheading\\n\\t\\\"Answer my heading in degrees.\\\"\\n\\n\\t| degrees |\\n\\tdegrees := 90.0 - headingRadians radiansToDegrees.\\n\\t^ degrees >= 0.0 ifTrue: [degrees] ifFalse: [degrees + 360.0].\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\nheading: angleInDegrees\\n\\t\\\"Set my heading in degrees. Like a compass, up or north is 0 degrees and right or east is 90 degrees.\\\"\\n\\n\\theadingRadians := ((90.0 - angleInDegrees) \\\\\\\\ 360.0) degreesToRadians.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'jm 3/3/2001 17:49'!\\nnextTurtle\\n\\t\\\"The nextTurtle slot is used to make a linked list of turtles at a given patch.\\\"\\n\\n\\t^ nextTurtle\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\nnextTurtle: aStarSqueakTurtle\\n\\t\\\"The nextTurtle slot is used to make a linked list of turtles at a given patch.\\\"\\n\\n\\tnextTurtle := aStarSqueakTurtle.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'jm 1/26/2001 17:36'!\\nwho\\n\\n\\t^ who\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\nwho: anInteger\\n\\n\\twho := anInteger.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'jm 2/25/2000 16:02'!\\nx\\n\\n\\t^ x\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\nx: aNumber\\n\\n\\tx := aNumber.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'jm 2/25/2000 16:02'!\\ny\\n\\n\\t^ y\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:26'!\\ny: aNumber\\n\\n\\ty := aNumber.\\n! !\\n\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'jm 1/26/2001 17:39'!\\ndie\\n\\t\\\"Delete this turtle at the end of the current cycle. The turtle will finish running all demons for the current cycle before it dies.\\\"\\n\\n\\tworld deleteTurtle: self.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'jm 1/23/2001 17:26'!\\nforward: dist\\n\\t\\\"Move the given distance in the direction of my heading.\\\"\\n\\n\\t1 to: dist do: [:i | self forwardOne].\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'sd 11/20/2005 21:26'!\\nforwardOne\\n\\t\\\"Move one turtle step in the direction of my heading.\\\"\\n\\n\\tpenDown ifTrue: [world setPatchColorAtX: x y: y to: color].\\n\\tx := x + headingRadians cos.\\n\\ty := y - headingRadians sin.\\n\\tx < 0.0 ifTrue: [x := x + wrapX].\\n\\ty < 0.0 ifTrue: [y := y + wrapY].\\n\\tx >= wrapX ifTrue: [x := x - wrapX].\\n\\ty >= wrapY ifTrue: [y := y - wrapY].\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'sd 11/20/2005 21:26'!\\ngoto: aPoint\\n\\t\\\"Jump to the given location.\\\"\\n\\n\\tx := aPoint x.\\n\\ty := aPoint y.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'sd 11/20/2005 21:26'!\\npenDown\\n\\t\\\"Put down this turtle's pen. That is, the turtle will leave a trail the same color as itself when it moves.\\\"\\n\\n\\tpenDown := true.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'sd 11/20/2005 21:26'!\\npenUp\\n\\t\\\"Lift this turtle's pen. The turtle will stop leaving a trail.\\\"\\n\\n\\tpenDown := false.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'jm 1/19/2001 19:20'!\\nrandom: range\\n\\t\\\"Answer a random integer between 0 and range.\\\"\\n\\n\\t^ world random: range\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'jm 1/27/2001 08:47'!\\nreplicate\\n\\t\\\"Add an exact replica of this turtle to the world. The new turtle does not become active until the next cycle.\\\"\\n\\t\\\"Note: We call this operation 'replicate' instead of Mitch Resnick's term 'clone' because Squeak already used the message 'clone' for cloning a generic object.\\\"\\n\\n\\tworld replicateTurtle: self.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'jm 1/29/2001 10:11'!\\nstop\\n\\t\\\"Stop running.\\\"\\n\\n\\tworld stopRunning.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'jm 1/19/2001 19:14'!\\nturnLeft: degrees\\n\\t\\\"Turn left by the given number of degrees.\\\"\\n\\n\\tself heading: (self heading - degrees).\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'jm 2/27/2000 18:19'!\\nturnRight: degrees\\n\\t\\\"Turn right by the given number of degrees.\\\"\\n\\n\\tself heading: (self heading + degrees).\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'sd 11/20/2005 21:26'!\\nturnTowards: aPointTurtleOrPatch\\n\\t\\\"Turn to face the given point, turtle, or patch.\\\"\\n\\n\\t| degrees |\\n\\tdegrees := (aPointTurtleOrPatch asPoint - self asPoint) degrees.\\n\\theadingRadians := (0.0 - degrees) degreesToRadians.\\n\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'commands' stamp: 'jm 1/27/2001 08:58'!\\nturnTowardsStrongest: patchVarName\\n\\t\\\"Turn to point toward the nearby patch having the highest value of the given patch variable. This command uses only local information. In particular, it only considers patches within 'sniffRange' of this turtles location. For example, with the default 'sniffRange' of 1, it only considers the immediate neighbors of the patch this turtle is on.\\\"\\n\\n\\tself heading: (world uphillOf: patchVarName forTurtle: self).\\n! !\\n\\n\\n!StarSqueakTurtle methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:26'!\\ninitializeWorld: aStarSqueakWorld who: anInteger\\n\\n\\t| dims |\\n\\tdims := aStarSqueakWorld dimensions.\\n\\tworld := aStarSqueakWorld.\\n\\twho := anInteger.\\n\\tx := world random: dims x - 1.\\n\\ty := world random: dims y - 1.\\n\\twrapX := dims x asFloat.\\n\\twrapY := dims y asFloat.\\n\\theadingRadians := ((self random: 36000) / 100.0) degreesToRadians.\\n\\tcolor := Color blue.\\n\\tpenDown := false.\\n\\tnextTurtle := nil.\\n! !\\n\\n\\n!StarSqueakTurtle methodsFor: 'patches' stamp: 'jm 1/19/2001 19:08'!\\nget: patchVar\\n\\t\\\"Answer the value of the given patch variable below this turtle.\\\"\\n\\n\\t^ world getPatchVariable: patchVar atX: x y: y\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'patches' stamp: 'jm 1/27/2001 08:49'!\\nincrement: patchVar by: delta\\n\\t\\\"Increment the value of the given patch variable below this turtle by the given amount (positive or negative).\\\"\\n\\n\\t world incrementPatchVariable: patchVar atX: x y: y by: delta.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'patches' stamp: 'hh 8/26/2001 19:49'!\\npatchBrightness\\n\\t\\\"Answer the brightness of the patch below this turtle, where 0 is black and 100 is full brightness.\\\"\\n\\n\\t^world getPatchBrightnessAtX: x y: y.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'patches' stamp: 'jm 1/24/2001 13:28'!\\npatchBrightness: percent\\n\\t\\\"Set the brightness of the patch below this turtle to the given value, where 0 is black and 100 is full brightness.\\\"\\n\\n\\tworld setPatchBrightnessAtX: x y: y to: percent.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'patches' stamp: 'jm 1/23/2001 17:17'!\\npatchColor\\n\\t\\\"Answer the color of the patch below this turtle.\\\"\\n\\n\\t^ world getPatchColorAtX: x y: y.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'patches' stamp: 'jm 1/24/2001 13:37'!\\npatchColor: aColor\\n\\t\\\"Paint the patch below this turtle with the given color.\\\"\\n\\n\\tworld setPatchColorAtX: x y: y to: aColor.\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'patches' stamp: 'jm 1/19/2001 19:09'!\\nset: patchVar to: newValue\\n\\t\\\"Set the value of the given patch variable below this turtle to the given value.\\\"\\n\\n\\t world setPatchVariable: patchVar atX: x y: y to: newValue.\\n! !\\n\\n\\n!StarSqueakTurtle methodsFor: 'sensing' stamp: 'jm 2/5/2001 19:42'!\\ndistanceTo: aPoint\\n\\t\\\"Answer the distance from this turtle to the given point.\\\"\\n\\n\\t^ ((x - aPoint x) squared + (y - aPoint y) squared) sqrt\\n! !\\n\\n!StarSqueakTurtle methodsFor: 'sensing' stamp: 'sd 11/20/2005 21:26'!\\nturtleCountHere\\n\\t\\\"Answer a collection of turtles at this turtle's current location, including this turtle itself.\\\"\\n\\n\\t| n |\\n\\tn := 0.\\n\\tworld turtlesAtX: x y: y do: [:t | n := n + 1].\\n\\t^ n\\n! !\\nChangeSetCategory subclass: #StaticChangeSetCategory\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tools-Changes'!\\n!StaticChangeSetCategory commentStamp: '<historical>' prior: 0!\\nStaticChangeSetCategory is a user-defined change-set category that has in it only those change sets specifically placed there.!\\n\\n\\n!StaticChangeSetCategory methodsFor: 'add' stamp: 'sw 4/11/2001 15:58'!\\naddChangeSet: aChangeSet\\n\\t\\\"Add the change set manually\\\"\\n\\n\\tself elementAt: aChangeSet name put: aChangeSet! !\\n\\n\\n!StaticChangeSetCategory methodsFor: 'queries' stamp: 'sw 4/11/2001 16:10'!\\nacceptsManualAdditions\\n\\t\\\"Answer whether the user is allowed manually to manipulate the contents of the change-set-category.\\\"\\n\\n\\t^ true! !\\n\\n!StaticChangeSetCategory methodsFor: 'queries' stamp: 'sw 4/11/2001 16:00'!\\nincludesChangeSet: aChangeSet\\n\\t\\\"Answer whether the receiver includes aChangeSet in its retrieval list\\\"\\n\\n\\t^ elementDictionary includesKey: aChangeSet name! !\\n\\n\\n!StaticChangeSetCategory methodsFor: 'updating' stamp: 'sd 11/20/2005 21:27'!\\nreconstituteList\\n\\t\\\"Reformulate the list. Here, since we have a manually-maintained list, at this juncture we only make sure change-set-names are still up to date, and we purge moribund elements\\\"\\n\\n\\t| survivors |\\n\\tsurvivors := elementDictionary select: [:aChangeSet | aChangeSet isMoribund not].\\n\\tself clear.\\n\\t(survivors asSortedCollection: [:a :b | a name <= b name]) reverseDo:\\n\\t\\t[:aChangeSet | self addChangeSet: aChangeSet]! !\\nForm subclass: #StaticForm\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Graphics-Display Objects'!\\n!StaticForm commentStamp: '<historical>' prior: 0!\\nAn optimization for Nebraska - a StaticForm does not change once created so it may be cached on the remote end.!\\n\\n\\n!StaticForm methodsFor: 'as yet unclassified' stamp: 'RAA 8/14/2000 09:59'!\\nisStatic\\n\\n\\t^true! !\\nMorphicAlarm subclass: #StepMessage\\n\\tinstanceVariableNames: 'stepTime'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Events'!\\n\\n!StepMessage methodsFor: 'accessing' stamp: 'ar 10/22/2000 16:56'!\\nstepTime: aNumber\\n\\t\\\"Set the step time for this message. If nil, the receiver of the message will be asked for its #stepTime.\\\"\\n\\tstepTime _ aNumber! !\\n\\n\\n!StepMessage methodsFor: 'printing' stamp: 'ar 10/22/2000 15:59'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream \\n\\t\\tnextPut: $(;\\n\\t\\tprint: receiver;\\n\\t\\tspace;\\n\\t\\tprint: selector;\\n\\t\\tspace;\\n\\t\\tprint: scheduledTime;\\n\\t\\tnextPut: $).! !\\n\\n\\n!StepMessage methodsFor: 'testing' stamp: 'ar 10/22/2000 16:56'!\\nstepTime\\n\\t\\\"Return the step time for this message. If nil, the receiver of the message will be asked for its #stepTime.\\\"\\n\\t^stepTime! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStepMessage class\\n\\tinstanceVariableNames: ''!\\n\\n!StepMessage class methodsFor: 'instance creation' stamp: 'ar 10/22/2000 15:48'!\\nscheduledAt: scheduledTime stepTime: stepTime receiver: aTarget selector: aSelector arguments: argArray\\n\\t^(self receiver: aTarget selector: aSelector arguments: argArray)\\n\\t\\tscheduledTime: scheduledTime;\\n\\t\\tstepTime: stepTime! !\\nRectangleMorph subclass: #StickyPadMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'Colors LastColorIndex'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Demo'!\\n!StickyPadMorph commentStamp: 'sw 3/3/2004 13:31' prior: 0!\\nA custom item for the Squeakland Supplies bin, as defined by Kim Rose and BJ Con.A parts bin will deliver up translucent, borderless Rectangles in a sequence of 6 colors. It offers some complication to the parts-bin protocols in two ways::\\n* The multi-colored icon seen in the parts bin is not a thumbnail of any actual instance, all of which are monochrome\\n* New instances need to be given default names that are not the same as the name seen in the parts bin.!\\n\\n\\n!StickyPadMorph methodsFor: 'visual properties' stamp: 'dgd 9/18/2004 18:52'!\\ncanHaveFillStyles\\n\\t\\\"Return true if the receiver can have general fill styles; not just \\n\\tcolors. This method is for gradually converting old morphs.\\\"\\n\\t^ true! !\\n\\n\\n!StickyPadMorph methodsFor: 'parts bin' stamp: 'sw 4/3/2003 15:25'!\\ninitializeToStandAlone\\n\\t\\\"Initialize the receiver to stand alone. Use the next color in the standard sequence.\\\"\\n\\n\\tColors ifNil: [self initialize].\\n\\tLastColorIndex _ \\n\\t\\tLastColorIndex\\n\\t\\t\\tifNil:\\n\\t\\t\\t\\t[1]\\n\\t\\t\\tifNotNil:\\n\\t\\t\\t\\t[(LastColorIndex \\\\\\\\ Colors size) + 1].\\n\\tsuper initializeToStandAlone.\\n\\tself assureExternalName.\\n\\tself color: (Colors at: LastColorIndex).\\n\\tself extent: 100@80.\\n\\tself borderWidth: 0\\n\\t! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStickyPadMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!StickyPadMorph class methodsFor: 'as yet unclassified' stamp: 'sw 3/3/2004 13:42'!\\nregisterInFlapsRegistry\\n\\t\\\"Register the receiver in the system's flaps registry\\\"\\n\\t\\n\\tself environment\\n\\t\\tat: #Flaps\\n\\t\\tifPresent: [:cl | cl registerQuad: #(StickyPadMorph\\t\\tnewStandAlone\\t\\t\\t'Sticky Pad'\\t\\t\\t'Each time you obtain one of these pastel, translucent, borderless rectangles, it will be a different color from the previous time.')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'Supplies'.\\n\\t\\t\\t\\tcl registerQuad: #(StickyPadMorph\\t\\tnewStandAlone\\t\\t\\t'Sticky Pad'\\t\\t\\t'Each time you obtain one of these pastel, translucent, borderless rectangles, it will be a different color from the previous time.')\\n\\t\\t\\t\\t\\t\\tforFlapNamed: 'PlugIn Supplies'.]! !\\n\\n\\n!StickyPadMorph class methodsFor: 'class initialization' stamp: 'sw 3/3/2004 13:44'!\\ninitialize\\n\\t\\\"Class initialization\\\"\\n\\n\\tLastColorIndex _ 0.\\n\\tColors _ {\\n\\t\\tTranslucentColor r: 0.0 g: 0.0 b: 0.839 alpha: 0.267.\\n\\t\\tTranslucentColor r: 0.484 g: 1.0 b: 0.452 alpha: 0.706.\\n\\t\\tTranslucentColor r: 1.0 g: 0.355 b: 0.71 alpha: 0.569.\\n\\t\\tTranslucentColor r: 1.0 g: 1.0 b: 0.03 alpha: 0.561.\\n\\t\\tTranslucentColor r: 0.484 g: 0.161 b: 1.0 alpha: 0.529.\\n\\t\\tTranslucentColor r: 0.097 g: 0.097 b: 0.097 alpha: 0.192.\\n\\t}.\\n\\t\\n\\tself registerInFlapsRegistry.\\t\\n\\n\\\"StickyPadMorph initialize\\\"! !\\n\\n\\n!StickyPadMorph class methodsFor: 'parts bin' stamp: 'sw 4/3/2003 14:26'!\\ndefaultNameStemForInstances\\n\\t\\\"Answer the default name stem to use\\\"\\n\\n\\t^ 'tear off'! !\\n\\n!StickyPadMorph class methodsFor: 'parts bin' stamp: 'sw 4/4/2003 11:12'!\\ndescriptionForPartsBin\\n\\t\\\"Answer a description of the receiver for use in a parts bin\\\"\\n\\n\\t^ self partName: \\t'Sticky Pad'\\n\\t\\tcategories:\\t\\t#('Graphics')\\n\\t\\tdocumentation:\\t'A translucent, borderless rectangle of a standard size, delivered in a predictable sequence of pastel colors'\\n\\t\\tsampleImageForm: (Form extent: 50@40 depth: 16\\n\\tfromArray: #( 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461414680 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1796762392 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461414680 1796762392 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1796762392 1796762392 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461409563 1461414680 1796762392 1796762392 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1723098804 1723098804 1723098804 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521903284 1723098804 1723098804 1723096921 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1723098804 1723098804 1723098804 1599692633 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521903284 1723098804 1723098804 1723096921 1599692633 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1723098804 1723098804 1723098804 1599692633 1599692633 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1521900214 1521900214 1521900214 1521903284 1723098804 1723098804 1723096921 1599692633 1599692633 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1322274512 1322274512 1322274512 1389318863 1389318863 1389318863 1328697138 1328697138 1328697138 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1322274512 1322274512 1322275535 1389318863 1389318863 1389317938 1328697138 1328697138 1328702226 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1322274512 1322274512 1389318863 1389318863 1389318863 1328697138 1328697138 1328697138 1662149394 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1322274512 1322275535 1389318863 1389318863 1389317938 1328697138 1328697138 1328702226 1662149394 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1322274512 1389318863 1389318863 1389318863 1328697138 1328697138 1328697138 1662149394 1662149394 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1322275535 1389318863 1389318863 1389317938 1328697138 1328697138 1328702226 1662149394 1662149394 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521900214 1389318863 1389318863 1389318863 1460426508 1460426508 1460426508 1659658988 1659658988 1659658988 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1521903284 1389318863 1389318863 1389317938 1460426508 1460426508 1460429548 1659658988 1659658988 1659660157 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521900214 1723098804 1389318863 1389318863 1328697138 1460426508 1460426508 1659658988 1659658988 1659658988 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1521903284 1723098804 1389318863 1389317938 1328697138 1460426508 1460429548 1659658988 1659658988 1659660157 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521900214 1723098804 1723098804 1389318863 1328697138 1328697138 1460426508 1659658988 1659658988 1659658988 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1521903284 1723098804 1723098804 1389317938 1328697138 1328697138 1460429548 1659658988 1659658988 1659660157 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461409563 1723098804 1723098804 1723098804 1328697138 1328697138 1328697138 1659658988 1659658988 1659658988 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1461414680 1723098804 1723098804 1723096921 1328697138 1328697138 1328702226 1659658988 1659658988 1659660157 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461409563 1796762392 1723098804 1723098804 1599692633 1328697138 1328697138 1662149394 1659658988 1659658988 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1461414680 1796762392 1723098804 1723096921 1599692633 1328697138 1328702226 1662149394 1659658988 1659660157 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461409563 1796762392 1796762392 1723098804 1599692633 1599692633 1328697138 1662149394 1662149394 1659658988 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1736271741 1461414680 1796762392 1796762392 1723096921 1599692633 1599692633 1328702226 1662149394 1662149394 1659660157 1736271741 1736271741 1736271741 1736271741 1736271741)\\n\\toffset: 0@0)! !\\n\\n!StickyPadMorph class methodsFor: 'parts bin' stamp: 'sw 7/5/2004 18:09'!\\nlaunchPartVia: aSelector label: aString\\n\\t\\\"Obtain a morph by sending aSelector to self, and attach it to the morphic hand. This provides a general protocol for parts bins. Overridden here so that all instances will be given the name, unlike the prevailing convention for other object types\\\"\\n\\n\\t| aMorph |\\n\\taMorph _ self perform: aSelector.\\n\\taMorph setNameTo: self defaultNameStemForInstances. \\\"i.e., circumvent uniqueness in this case\\\"\\n\\taMorph setProperty: #beFullyVisibleAfterDrop toValue: true.\\n\\taMorph openInHand! !\\nSketchMorph subclass: #StickySketchMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting Support'!\\n\\n!StickySketchMorph methodsFor: 'e-toy support' stamp: 'sw 4/16/1998 13:44'!\\nmustBeBackmost\\n\\t^ true! !\\n\\n\\n!StickySketchMorph methodsFor: 'halos and balloon help' stamp: 'sw 9/18/97 15:37'!\\nwantsHalo\\n\\t^ false! !\\n\\n\\n!StickySketchMorph methodsFor: 'thumbnail' stamp: 'sw 6/16/1999 11:32'!\\npermitsThumbnailing\\n\\t^ false! !\\nObject subclass: #Stopwatch\\n\\tinstanceVariableNames: 'timespans state'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Kernel-Chronology'!\\n!Stopwatch commentStamp: '<historical>' prior: 0!\\nA Stopwatch maintains a collection of timespans.!\\n\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/24/2003 23:12'!\\nactivate\\n\\n\\tself isSuspended ifTrue:\\n\\t\\t[self timespans add: \\n\\t\\t\\t(Timespan starting: DateAndTime now duration: Duration zero).\\n\\t\\tself state: #active]\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/24/2003 23:45'!\\nduration\\n\\n\\t| ts last |\\n\\tself isSuspended \\n\\t\\tifTrue:\\n\\t\\t\\t[ (ts _ self timespans) isEmpty ifTrue: \\n\\t\\t\\t\\t[ ts _ { Timespan starting: DateAndTime now duration: Duration zero } ] ]\\n\\t\\tifFalse:\\n\\t\\t\\t[ last _ self timespans last.\\n\\t\\t\\tts _ self timespans allButLast\\n\\t\\t\\t\\tadd: (last duration: (DateAndTime now - last start); yourself);\\n\\t\\t\\t\\tyourself ].\\n\\t\\t\\n\\t^ (ts collect: [ :t | t duration ]) sum\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/25/2003 11:21'!\\nend\\n\\n\\t^ self timespans last next\\n\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/24/2003 22:48'!\\nisActive\\n\\n\\t^ self state = #active\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/24/2003 22:48'!\\nisSuspended\\n\\n\\t^ self state = #suspended\\n\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/25/2003 13:25'!\\nprintOn: aStream\\n\\n\\tsuper printOn: aStream.\\n\\taStream\\n\\t\\tnextPut: $(;\\n\\t\\tnextPutAll: self state;\\n\\t\\tnextPut: $:;\\n\\t\\tprint: self duration;\\n\\t\\tnextPut: $).\\n\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/25/2003 12:03'!\\nreActivate\\n\\n\\tself \\n\\t\\tsuspend;\\n\\t\\tactivate.\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/25/2003 11:54'!\\nreset\\n\\n\\tself suspend.\\n\\ttimespans _ nil.\\n\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/24/2003 23:18'!\\nstart\\n\\n\\t^ self timespans first start\\n\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/24/2003 22:47'!\\nstate\\n\\n\\t^ state ifNil: [ state _ #suspended ]\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/24/2003 22:46'!\\nstate: aSymbol\\n\\n\\tstate _ aSymbol\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/24/2003 23:13'!\\nsuspend\\n\\n\\t| ts |\\n\\tself isActive ifTrue:\\n\\t\\t[ ts _ self timespans last.\\n\\t\\tts duration: (DateAndTime now - ts start).\\n\\t\\tself state: #suspended]\\n! !\\n\\n!Stopwatch methodsFor: 'squeak protocol' stamp: 'brp 9/24/2003 22:44'!\\ntimespans\\n\\n\\t^ timespans ifNil: [ timespans _ OrderedCollection new ]\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStopwatch class\\n\\tinstanceVariableNames: ''!\\nClassTestCase subclass: #StopwatchTest\\n\\tinstanceVariableNames: 'aStopwatch aDelay'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'KernelTests-Chronology'!\\n\\n!StopwatchTest methodsFor: 'Coverage' stamp: 'brp 9/24/2003 22:49'!\\nclassToBeTested\\n\\n\\t^ Stopwatch\\n\\n! !\\n\\n!StopwatchTest methodsFor: 'Coverage' stamp: 'brp 9/24/2003 23:01'!\\nselectorsToBeIgnored\\n\\n\\t| private | \\n\\tprivate := #( #printOn: #state: ).\\n\\n\\t^ super selectorsToBeIgnored, private\\n! !\\n\\n\\n!StopwatchTest methodsFor: 'running' stamp: 'brp 1/21/2004 18:49'!\\nsetUp\\n\\taStopwatch := Stopwatch new.\\n\\taDelay := Delay forMilliseconds: 1.! !\\n\\n\\n!StopwatchTest methodsFor: 'Tests' stamp: 'brp 9/25/2003 11:45'!\\ntestActive\\n\\n\\t| sw |\\n\\tsw _ Stopwatch new.\\n\\tsw activate.\\n\\t\\n\\t1 seconds asDelay wait.\\n\\tself \\n\\t\\tassert: (sw duration >= 1 seconds).\\n\\n\\t2 seconds asDelay wait.\\n\\tself \\n\\t\\tassert: (sw duration >= 3 seconds).\\n\\n\\tsw suspend.! !\\n\\n!StopwatchTest methodsFor: 'Tests' stamp: 'brp 9/24/2003 22:56'!\\ntestNew\\n\\n\\t| sw |\\n\\tsw _ Stopwatch new.\\n\\t\\n\\tself \\n\\t\\tassert: (sw isSuspended);\\n\\t\\tassert: (sw state = #suspended);\\n\\t\\tdeny: (sw isActive);\\n\\t\\tassert: (sw timespans isEmpty)\\n\\n! !\\n\\n!StopwatchTest methodsFor: 'Tests' stamp: 'brp 9/25/2003 12:02'!\\ntestReActivate\\n\\n\\t| sw |\\n\\tsw _ Stopwatch new.\\n\\tsw \\n\\t\\tactivate;\\n\\t\\tsuspend;\\n\\t\\treActivate.\\n\\t\\n\\tself \\n\\t\\tassert: (sw isActive).\\n! !\\n\\n!StopwatchTest methodsFor: 'Tests' stamp: 'brp 9/25/2003 11:56'!\\ntestReset\\n\\n\\t| sw |\\n\\tsw _ Stopwatch new.\\n\\tsw activate.\\n\\t\\n\\tsw reset.\\n\\tself \\n\\t\\tassert: (sw isSuspended);\\n\\t\\tassert: (sw timespans isEmpty)\\n! !\\n\\n!StopwatchTest methodsFor: 'Tests' stamp: 'brp 9/26/2004 19:36'!\\ntestStartStop\\n\\n\\t| sw t1 t2 t3 t4 |\\n\\tsw := Stopwatch new.\\n\\tt1 := DateAndTime now.\\n\\t(Delay forMilliseconds: 10) wait.\\n\\tsw activate; activate.\\n\\t(Delay forMilliseconds: 10) wait.\\n\\tt2 := DateAndTime now.\\n\\t\\n\\tself \\n\\t\\tdeny: (sw isSuspended);\\n\\t\\tassert: (sw isActive);\\n\\t\\tassert: (sw timespans size = 1);\\n\\t\\tassert: (t1 <= sw start);\\n\\t\\tassert: (sw start <= t2).\\n\\n\\t(Delay forMilliseconds: 10) wait.\\n\\tt3 := DateAndTime now.\\n\\t(Delay forMilliseconds: 10) wait.\\n\\tsw suspend; suspend.\\n\\t(Delay forMilliseconds: 10) wait.\\n\\tt4 := DateAndTime now.\\n\\n\\tself \\n\\t\\tassert: (sw isSuspended);\\n\\t\\tdeny: (sw isActive);\\n\\t\\tassert: (sw timespans size = 1);\\n\\t\\tassert: (sw end between: t3 and: t4);\\n\\t\\tassert: (t3 <= sw end);\\n\\t\\tassert: (sw end <= t4).\\n! !\\n\\n\\n!StopwatchTest methodsFor: 'testing' stamp: 'brp 1/21/2004 18:49'!\\ntestChangingStatus\\n\\taStopwatch activate.\\n\\tself assert: aStopwatch isActive.\\n\\tself assert: aStopwatch timespans size = 1.\\n\\taStopwatch suspend.\\n\\tself assert: aStopwatch isSuspended.\\n\\tself assert: aStopwatch timespans size = 1.\\n\\taStopwatch activate.\\n\\taStopwatch reActivate.\\n\\tself assert: aStopwatch isActive.\\n\\tself assert: aStopwatch timespans size = 3.\\n\\taStopwatch reset.\\n\\tself assert: aStopwatch isSuspended.\\n\\tself assert: aStopwatch timespans size = 0.! !\\n\\n!StopwatchTest methodsFor: 'testing' stamp: 'brp 1/21/2004 18:49'!\\ntestInitialStatus\\n\\tself assert: aStopwatch isSuspended.\\n\\tself deny: aStopwatch isActive.\\n\\tself assert: aStopwatch duration = 0 seconds! !\\n\\n!StopwatchTest methodsFor: 'testing' stamp: 'brp 9/26/2004 19:32'!\\ntestMultipleTimings\\n\\taStopwatch activate.\\n\\taDelay wait.\\n\\taStopwatch suspend.\\n\\taStopwatch activate.\\n\\taDelay wait.\\n\\taStopwatch suspend.\\n\\tself assert: aStopwatch timespans size = 2. \\n\\tself assert: aStopwatch timespans first asDateAndTime <= \\n\\t\\t\\t\\t\\taStopwatch timespans last asDateAndTime.\\n! !\\n\\n!StopwatchTest methodsFor: 'testing' stamp: 'brp 1/21/2004 18:49'!\\ntestPrintOn\\n\\t| cs rw |\\n\\tcs := ReadStream on: 'a Stopwatch(suspended:0:00:00:00)'.\\n\\trw := ReadWriteStream on: ''.\\n\\taStopwatch printOn: rw.\\n\\tself assert: rw contents = cs contents! !\\n\\n!StopwatchTest methodsFor: 'testing' stamp: 'brp 9/26/2004 19:32'!\\ntestSingleTiming\\n\\t| timeBefore |\\n\\ttimeBefore := DateAndTime now.\\n\\taStopwatch activate.\\n\\taDelay wait.\\n\\taStopwatch suspend.\\n\\tself assert: aStopwatch timespans size = 1. \\n\\tself assert: aStopwatch timespans first asDateAndTime >= timeBefore. \\n\\tself assert: aStopwatch timespans first asDateAndTime <= aStopwatch end.\\n! !\\nPrintableEncoder subclass: #StoreEncoder\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Postscript Filters'!\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStoreEncoder class\\n\\tinstanceVariableNames: ''!\\n\\n!StoreEncoder class methodsFor: 'configuring' stamp: 'MPW 1/1/1901 01:52'!\\nfilterSelector\\n ^#storeOnStream:.\\n! !\\nBookMorph subclass: #StoryboardBookMorph\\n\\tinstanceVariableNames: 'alansSliders panAndTiltFactor zoomFactor zoomController'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Books'!\\n!StoryboardBookMorph commentStamp: '<historical>' prior: 0!\\nA BookMorph variant whose pages are instances of ZoomAndScrollMorph. I have a control area where the user may pan, tilt and zoom over the image shown in the page.\\n\\n- drag up and down to zoom in and out\\n- drag left and right to pan\\n- shift-drag up and down to tilt.!\\n\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/30/2000 16:37'!\\nchangeTiltFactor: x\\n\\n\\tcurrentPage changeTiltFactor: x.\\n\\tpanAndTiltFactor _ x.\\n\\n! !\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/30/2000 16:37'!\\nchangeZoomFactor: x\\n\\n\\tcurrentPage changeZoomFactor: x.\\n\\tzoomFactor _ x.! !\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/30/2000 16:38'!\\ngetTiltFactor\\n\\n\\t^panAndTiltFactor ifNil: [panAndTiltFactor _ 0.5].! !\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/30/2000 16:38'!\\ngetZoomFactor\\n\\n\\t^zoomFactor ifNil: [zoomFactor _ 0.5]! !\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/22/2000 08:41'!\\noffsetX\\n\\n\\t^currentPage offsetX! !\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/22/2000 08:41'!\\noffsetX: aNumber\\n\\n\\tcurrentPage offsetX: aNumber! !\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/22/2000 08:41'!\\noffsetY\\n\\n\\t^currentPage offsetY! !\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/22/2000 08:41'!\\noffsetY: aNumber\\n\\n\\tcurrentPage offsetY: aNumber! !\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/22/2000 08:35'!\\nscale\\n\\n\\t^currentPage scale! !\\n\\n!StoryboardBookMorph methodsFor: 'as yet unclassified' stamp: 'RAA 11/22/2000 08:26'!\\nscale: aValue\\n\\n\\tcurrentPage scale: aValue! !\\n\\n\\n!StoryboardBookMorph methodsFor: 'initialization' stamp: 'RAA 12/1/2000 15:22'!\\ninitialize\\n\\n\\tnewPagePrototype _ ZoomAndScrollMorph new extent: Display extent // 3.\\n\\tzoomController _ ZoomAndScrollControllerMorph new\\n\\t\\t\\tsetBalloonText: 'Drag in here to zoom, tilt and pan the page above'.\\n\\n\\tsuper initialize.\\n\\n\\tself addMorphBack: zoomController.\\n\\n\\talansSliders _ {\\n\\t\\t{#changeTiltFactor: . #getTiltFactor . 'Pan and tilt sensitivity'}.\\n\\t\\t{#changeZoomFactor: . #getZoomFactor . 'Zoom sensitivity'}.\\n\\t} collect: [ :sData |\\n\\t\\t{\\n\\t\\t\\tSimpleSliderMorph new\\n\\t\\t\\t\\textent: 150@10;\\n\\t\\t\\t\\tcolor: Color orange;\\n\\t\\t\\t\\tsliderColor: Color gray;\\n\\t\\t\\t\\ttarget: self; \\n\\t\\t\\t\\tactionSelector: sData first;\\n\\t\\t\\t\\tsetBalloonText: sData third;\\n\\t\\t\\t\\tadjustToValue: (self perform: sData second).\\n\\t\\t\\tsData second\\n\\t\\t}\\n\\t].\\n\\talansSliders do: [ :each | self addMorphBack: each first]\\n! !\\n\\n\\n!StoryboardBookMorph methodsFor: 'navigation' stamp: 'sw 7/25/2003 16:47'!\\ninsertPageMorphInCorrectSpot: aPageMorph\\n\\t\\\"Insert the page morph at the correct spot\\\"\\n\\t\\n\\t| place |\\n\\tplace _ submorphs size > 1 ifTrue: [submorphs second] ifFalse: [submorphs first].\\n\\t\\\"Old architecture had a tiny spacer morph as the second morph; now architecture does not\\\"\\n\\tself addMorph: (currentPage _ aPageMorph) behind: place.\\n\\tself changeTiltFactor: self getTiltFactor.\\n\\tself changeZoomFactor: self getZoomFactor.\\n\\tzoomController target: currentPage.\\n\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStoryboardBookMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!StoryboardBookMorph class methodsFor: 'parts bin' stamp: 'sw 8/2/2001 12:53'!\\ndescriptionForPartsBin\\n\\t^ self partName:\\t'Storyboard'\\n\\t\\tcategories:\\t\\t#('Presentation')\\n\\t\\tdocumentation:\\t'A storyboard authoring tool'! !\\nObject subclass: #Stream\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Collections-Streams'!\\n!Stream commentStamp: '<historical>' prior: 0!\\nI am an abstract class that represents an accessor for a sequence of objects. This sequence is referred to as my \\\"contents\\\".!\\n\\n\\n!Stream methodsFor: 'accessing' stamp: 'yo 8/30/2002 17:13'!\\nbasicNext\\n\\n\\t^ self next.\\n! !\\n\\n!Stream methodsFor: 'accessing' stamp: 'yo 8/30/2002 17:13'!\\nbasicNextPut: anObject \\n\\n\\t^ self nextPut: anObject! !\\n\\n!Stream methodsFor: 'accessing' stamp: 'yo 8/30/2002 17:13'!\\nbasicNextPutAll: aCollection \\n\\n\\t^ self nextPutAll: aCollection.\\n! !\\n\\n!Stream methodsFor: 'accessing' stamp: 'nk 2/24/2001 17:31'!\\nbinary! !\\n\\n!Stream methodsFor: 'accessing'!\\ncontents\\n\\t\\\"Answer all of the contents of the receiver.\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n!Stream methodsFor: 'accessing' stamp: 'sma 4/22/2000 17:07'!\\nflush\\n\\t\\\"Do nothing by default\\\"! !\\n\\n!Stream methodsFor: 'accessing' stamp: 'nk 4/29/2004 10:38'!\\nlocalName\\n\\t^'a stream'! !\\n\\n!Stream methodsFor: 'accessing'!\\nnext\\n\\t\\\"Answer the next object accessible by the receiver.\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n!Stream methodsFor: 'accessing'!\\nnext: anInteger \\n\\t\\\"Answer the next anInteger number of objects accessible by the receiver.\\\"\\n\\n\\t| aCollection |\\n\\taCollection _ OrderedCollection new.\\n\\tanInteger timesRepeat: [aCollection addLast: self next].\\n\\t^aCollection! !\\n\\n!Stream methodsFor: 'accessing'!\\nnext: anInteger put: anObject \\n\\t\\\"Make anObject be the next anInteger number of objects accessible by the \\n\\treceiver. Answer anObject.\\\"\\n\\n\\tanInteger timesRepeat: [self nextPut: anObject].\\n\\t^anObject! !\\n\\n!Stream methodsFor: 'accessing'!\\nnextMatchAll: aColl\\n \\\"Answer true if next N objects are the ones in aColl,\\n else false. Advance stream of true, leave as was if false.\\\"\\n | save |\\n save _ self position.\\n aColl do: [:each |\\n (self next) = each ifFalse: [\\n self position: save.\\n ^ false]\\n ].\\n ^ true! !\\n\\n!Stream methodsFor: 'accessing'!\\nnextMatchFor: anObject \\n\\t\\\"Gobble the next object and answer whether it is equal to the argument, \\n\\tanObject.\\\"\\n\\n\\t^anObject = self next! !\\n\\n!Stream methodsFor: 'accessing'!\\nnextPut: anObject \\n\\t\\\"Insert the argument, anObject, as the next object accessible by the \\n\\treceiver. Answer anObject.\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n!Stream methodsFor: 'accessing'!\\nnextPutAll: aCollection \\n\\t\\\"Append the elements of aCollection to the sequence of objects accessible \\n\\tby the receiver. Answer aCollection.\\\"\\n\\n\\taCollection do: [:v | self nextPut: v].\\n\\t^aCollection! !\\n\\n!Stream methodsFor: 'accessing' stamp: 'nk 4/29/2004 10:40'!\\nopenReadOnly\\n\\t^self! !\\n\\n!Stream methodsFor: 'accessing' stamp: 'ajh 7/31/2001 20:34'!\\nprintOn: stream\\n\\n\\tsuper printOn: stream.\\n\\tstream space.\\n\\tself contents printOn: stream.\\n! !\\n\\n!Stream methodsFor: 'accessing' stamp: 'nk 4/29/2004 10:41'!\\nreadOnly\\n\\t^self! !\\n\\n!Stream methodsFor: 'accessing' stamp: 'ls 9/12/1998 20:55'!\\nupToEnd\\n\\t\\\"answer the remaining elements in the string\\\"\\n\\t| elements |\\n\\telements _ OrderedCollection new.\\n\\t[ self atEnd ] whileFalse: [ \\n\\t\\telements add: self next ].\\n\\t^elements! !\\n\\n\\n!Stream methodsFor: 'alternate syntax' stamp: 'RAA 6/20/2000 12:52'!\\ndialect\\n\\n\\t^#ST80\\t\\t\\\"in case a regular stream is used to print parse nodes\\\"! !\\n\\n!Stream methodsFor: 'alternate syntax' stamp: 'RAA 6/20/2000 12:54'!\\nwithStyleFor: elementType do: aBlock\\n\\n\\t^aBlock value\\t\\t\\\"in case a regular stream is used to print parse nodes\\\"\\n\\\">>\\n(Compiler new compile: 'blah ^self' in: String notifying: nil ifFail: []) printString\\n<<\\\"! !\\n\\n\\n!Stream methodsFor: 'as yet unclassified' stamp: 'RAA 9/11/2000 19:12'!\\nsleep\\n\\n\\t\\\"an FTP-based stream might close the connection here\\\"! !\\n\\n\\n!Stream methodsFor: 'enumerating'!\\ndo: aBlock \\n\\t\\\"Evaluate aBlock for each of the objects accessible by receiver.\\\"\\n\\n\\t[self atEnd]\\n\\t\\twhileFalse: [aBlock value: self next]! !\\n\\n\\n!Stream methodsFor: 'file open/close' stamp: 'mir 8/10/1999 12:04'!\\nclose! !\\n\\n\\n!Stream methodsFor: 'filter streaming' stamp: 'MPW 1/1/1901 00:48'!\\nwrite:encodedObject\\n\\t^encodedObject putOn:self.\\n! !\\n\\n\\n!Stream methodsFor: 'printing' stamp: 'sma 6/1/2000 09:56'!\\nprint: anObject\\n\\t\\\"Have anObject print itself on the receiver.\\\"\\n\\n\\tanObject printOn: self! !\\n\\n!Stream methodsFor: 'printing' stamp: 'djp 7/21/1998 17:13'!\\nprintHtml: anObject\\n\\tanObject printHtmlOn: self! !\\n\\n\\n!Stream methodsFor: 'testing'!\\natEnd\\n\\t\\\"Answer whether the receiver can access any more objects.\\\"\\n\\n\\tself subclassResponsibility! !\\n\\n!Stream methodsFor: 'testing' stamp: 'ab 8/28/2003 18:30'!\\nclosed\\n\\t^ false! !\\n\\n!Stream methodsFor: 'testing' stamp: 'ar 12/23/1999 15:43'!\\nisStream\\n\\t\\\"Return true if the receiver responds to the stream protocol\\\"\\n\\t^true! !\\n\\n!Stream methodsFor: 'testing' stamp: 'mir 11/10/2003 18:22'!\\nisTypeHTTP\\n\\n\\t^false! !\\n\\n!Stream methodsFor: 'testing' stamp: 'ar 5/17/2001 19:07'!\\nnextWordsPutAll: aCollection\\n\\t\\\"Write the argument a word-like object in big endian format on the receiver.\\n\\tMay be used to write other than plain word-like objects (such as ColorArray).\\\"\\n\\taCollection class isPointers | aCollection class isWords not \\n\\t\\tifTrue: [^self error: aCollection class name,' is not word-like'].\\n\\t1 to: aCollection basicSize do:[:i|\\n\\t\\tself nextNumber: 4 put: (aCollection basicAt: i).\\n\\t].\\n\\t^aCollection! !\\n\\n\\n!Stream methodsFor: '*monticello' stamp: 'cwp 8/9/2003 12:02'!\\nisMessageStream\\n\\t^ false! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStream class\\n\\tinstanceVariableNames: ''!\\n\\n!Stream class methodsFor: 'instance creation'!\\nnew\\n\\n\\tself error: 'Streams are created with on: and with:'! !\\nTestCase subclass: #StreamBugz\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tests-Bugs'!\\n\\n!StreamBugz methodsFor: 'as yet unclassified' stamp: 'ar 8/5/2003 02:25'!\\ntestReadWriteStreamNextNBug\\n\\t| aStream |\\n\\taStream := ReadWriteStream on: String new.\\n\\taStream nextPutAll: 'Hello World'.\\n\\tself shouldnt:[aStream next: 5] raise: Error.\\n! !\\nAbstractSound subclass: #StreamingMP3Sound\\n\\tinstanceVariableNames: 'volume repeat mpegFile mpegStreamIndex totalSamples streamSamplingRate mixer lastBufferMSecs mutex'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Movies-Kernel'!\\n!StreamingMP3Sound commentStamp: '<historical>' prior: 0!\\nI implement a streaming player for MPEG or MP3 files.\\nExample of use:\\n\\t(StreamingMP3Sound onFileNamed: 'song.mp3') play.\\n!\\n\\n\\n!StreamingMP3Sound methodsFor: 'accessing' stamp: 'jm 11/16/2001 17:16'!\\nduration\\n\\t\\\"Answer the duration of this sound in seconds.\\\"\\n\\n\\t^ totalSamples asFloat / streamSamplingRate\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nrepeat\\n\\t\\\"Answer the repeat flag.\\\"\\n\\n\\trepeat ifNil: [repeat := false].\\n\\t^ repeat\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nrepeat: aBoolean\\n\\t\\\"Set the repeat flag. If true, this sound will loop back to the beginning when it gets to the end.\\\"\\n\\n\\trepeat := aBoolean.\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'accessing' stamp: 'jm 11/16/2001 16:18'!\\nsoundPosition\\n\\t\\\"Answer the relative position of sound playback as a number between 0.0 and 1.0.\\\"\\n\\n\\tself mpegFileIsOpen ifFalse: [^ 0.0].\\n\\tmpegFile hasAudio ifFalse: [^ 0.0].\\n\\t^ (mpegFile audioGetSample: 0) asFloat / totalSamples\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nsoundPosition: fraction\\n\\t\\\"Jump to the position the given fraction through the sound file. The argument is a number between 0.0 and 1.0.\\\"\\n\\n\\t| sampleIndex |\\n\\tself mpegFileIsOpen ifFalse: [^ self].\\n\\tmpegFile hasAudio ifTrue: [\\n\\t\\tsampleIndex := ((totalSamples * fraction) truncated max: 0) min: totalSamples.\\n\\t\\tmpegFile audioSetSample: 0 stream: 0. \\\"work around for library bug: first seek to zero\\\"\\n\\t\\tmpegFile audioSetSample: sampleIndex stream: 0].\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'accessing' stamp: 'jm 11/16/2001 15:34'!\\nstreamSamplingRate\\n\\t\\\"Answer the sampling rate of the MP3 stream.\\\"\\n\\n\\t^ streamSamplingRate\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'accessing' stamp: 'jm 9/26/2000 07:49'!\\nvolume\\n\\t\\\"Answer my volume.\\\"\\n\\n\\t^ volume\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nvolume: aNumber\\n\\t\\\"Set my volume to the given number between 0.0 and 1.0.\\\"\\n\\n\\tvolume := aNumber.\\n\\tself createMixer.\\n! !\\n\\n\\n!StreamingMP3Sound methodsFor: 'converting' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nsaveAsFileNamed: newFileName compressionType: compressionTypeString\\n\\t\\\"Store this MP3 sound in a SunAudio file with the given name using the given compression type.\\\"\\n\\n\\t| outFile |\\n\\toutFile := (FileStream newFileNamed: newFileName) binary.\\n\\tself storeSunAudioOn: outFile compressionType: compressionTypeString.\\n\\toutFile close.\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'converting' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nstoreSunAudioOn: aBinaryStream compressionType: compressionName\\n\\t\\\"Store myself on the given stream as a monophonic sound compressed with the given type of compression. The sampling rate is reduced to 22050 samples/second if it is higher.\\\"\\n\\n\\t| fmt inBufSize samplesPerFrame codec inBuf compressed outSamplingRate audioWriter samplesRemaining outBuf counts byteCount |\\n\\tself pause; reset. \\\"stop playing and return to beginning\\\"\\n\\n\\tfmt := SunAudioFileWriter formatCodeForCompressionType: compressionName.\\n\\tinBufSize := 64000.\\n\\tsamplesPerFrame := 1.\\n\\tcodec := SunAudioFileWriter codecForFormatCode: fmt.\\n\\tcodec ifNotNil: [\\n\\t\\tsamplesPerFrame := codec samplesPerFrame.\\n\\t\\tinBufSize := inBufSize roundUpTo: (2 * samplesPerFrame).\\n\\t\\tcompressed := ByteArray new:\\n\\t\\t\\t(inBufSize // samplesPerFrame) * codec bytesPerEncodedFrame].\\n\\tinBuf := SoundBuffer newMonoSampleCount: inBufSize.\\n\\toutSamplingRate := streamSamplingRate.\\n\\tstreamSamplingRate > 22050 ifTrue: [\\n\\t\\tstreamSamplingRate = 44100 ifFalse: [self error: 'unexpected MP3 sampling rate'].\\n\\t\\toutSamplingRate := 22050].\\n\\n\\t\\\"write audio header\\\"\\n\\taudioWriter := SunAudioFileWriter onStream: aBinaryStream.\\n\\taudioWriter writeHeaderSamplingRate: outSamplingRate format: fmt.\\n\\n\\t\\\"convert and write sound data\\\"\\n\\t'Storing audio...' displayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0 to: totalSamples during: [:bar |\\n\\t\\t\\tsamplesRemaining := totalSamples.\\n\\t\\t\\t[samplesRemaining > 0] whileTrue: [\\n\\t\\t\\t\\tbar value: totalSamples - samplesRemaining.\\n\\t\\t\\t\\tsamplesRemaining < inBuf monoSampleCount ifTrue: [\\n\\t\\t\\t\\t\\tinBuf := SoundBuffer newMonoSampleCount:\\n\\t\\t\\t\\t\\t\\t(samplesRemaining roundUpTo: 2 * samplesPerFrame)].\\n\\t\\t\\t\\tmpegFile audioReadBuffer: inBuf stream: 0 channel: 0.\\n\\t\\t\\t\\toutSamplingRate < streamSamplingRate\\n\\t\\t\\t\\t\\tifTrue: [outBuf := inBuf downSampledLowPassFiltering: true]\\n\\t\\t\\t\\t\\tifFalse: [outBuf := inBuf].\\n\\t\\t\\t\\tcodec\\n\\t\\t\\t\\t\\tifNil: [audioWriter appendSamples: outBuf]\\n\\t\\t\\t\\t\\tifNotNil: [\\n\\t\\t\\t\\t\\t\\tcounts := codec\\n\\t\\t\\t\\t\\t\\t\\tencodeFrames: (outBuf size // samplesPerFrame)\\n\\t\\t\\t\\t\\t\\t\\tfrom: outBuf at: 1\\n\\t\\t\\t\\t\\t\\t\\tinto: compressed at: 1.\\n\\t\\t\\t\\t\\t\\tbyteCount := counts last.\\n\\t\\t\\t\\t\\t\\tbyteCount = compressed size\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [audioWriter appendBytes: compressed]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [audioWriter appendBytes: (compressed copyFrom: 1 to: byteCount)]].\\n\\t\\t\\t\\tsamplesRemaining := samplesRemaining - inBuf monoSampleCount]].\\n\\n\\t\\\"update audio header\\\"\\n\\taudioWriter updateHeaderDataSize.\\n! !\\n\\n\\n!StreamingMP3Sound methodsFor: 'file ops' stamp: 'stephaneducasse 2/4/2006 20:48'!\\ncloseFile\\n\\t\\\"Close the MP3 or MPEG file.\\\"\\n\\n\\tself pause.\\n\\tmpegFile ifNil: [^ self].\\n\\tmpegFile closeFile.\\n\\tmpegFile := nil.\\n\\tmixer := nil.\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'file ops' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nmpegFileIsOpen\\n\\t\\\"Answer true if I have an open, valid MPEG file handle. If the handle is not valid, try to re-open the file.\\\"\\n\\n\\tmpegFile ifNil: [^ false].\\n\\tmpegFile fileHandle ifNil: [\\n\\t\\t\\\"try to reopen the file, which may have been saved in a snapshot\\\"\\n\\t\\tmpegFile openFile: mpegFile fileName.\\n\\t\\tmpegFile fileHandle ifNil: [mpegFile := nil]].\\n\\t^ mpegFile notNil\\n! !\\n\\n\\n!StreamingMP3Sound methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:48'!\\ninitMPEGFile: anMPEGFile streamIndex: anInteger\\n\\t\\\"Initialize for playing the given stream of the given MPEG or MP3 file.\\\"\\n\\n\\tvolume := 0.3.\\n\\trepeat := false.\\n\\tmpegFile := anMPEGFile.\\n\\tmpegStreamIndex := anInteger.\\n\\ttotalSamples := mpegFile audioSamples: mpegStreamIndex.\\n\\tself reset.\\n! !\\n\\n\\n!StreamingMP3Sound methodsFor: 'playing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nmillisecondsSinceStart\\n\\t\\\"Answer the number of milliseconds since this sound started playing.\\\"\\n\\n\\t| i mSecs |\\n\\tmpegFile ifNil: [^ 0].\\n\\tmpegFile fileHandle ifNil: [^ 0]. \\\"mpeg file not open\\\"\\n\\ti := mpegFile audioGetSample: mpegStreamIndex.\\n\\ti < 0 ifTrue: [^ 0]. \\\"movie file has no audio\\\"\\n\\tmSecs := i * 1000 // streamSamplingRate.\\n\\t(self isPlaying and: [lastBufferMSecs > 0]) ifTrue: [\\n\\t\\t\\\"adjust mSecs by the milliseconds since the last buffer\\\"\\n\\t\\tmutex critical: [\\n\\t\\t\\tmSecs := i * 1000 // streamSamplingRate.\\n\\t\\t\\tmSecs := mSecs + ((Time millisecondClockValue - lastBufferMSecs) max: 0)]].\\n\\t^ mSecs + 350 - (2 * SoundPlayer bufferMSecs)\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'playing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nplaySampleCount: n into: aSoundBuffer startingAt: startIndex\\n\\t\\\"Mix the next n samples of this sound into the given buffer starting at the given index\\\"\\n\\n\\t| current |\\n\\tself repeat ifTrue: [ \\\"loop if necessary\\\"\\n\\t\\tcurrent := mpegFile audioGetSample: mpegStreamIndex.\\n\\t\\t(totalSamples - current) < n ifTrue: [\\n\\t\\t\\tmpegFile audioSetSample: 0 stream: mpegStreamIndex]].\\n\\n\\tmutex critical: [\\n\\t\\tlastBufferMSecs := Time millisecondClockValue.\\n\\t\\tself loadBuffersForSampleCount: (n * streamSamplingRate) // SoundPlayer samplingRate.\\n\\t\\tmixer playSampleCount: n into: aSoundBuffer startingAt: startIndex].\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'playing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nreset\\n\\n\\tsuper reset.\\n\\tself createMixer.\\n\\tmpegFile audioSetSample: 0 stream: mpegStreamIndex.\\n\\tlastBufferMSecs := 0.\\n\\tmutex := Semaphore forMutualExclusion.\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'playing' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nsamplesRemaining\\n\\n\\t| samplesPlayed |\\n\\tmpegFile ifNil: [^ 0].\\n\\tself repeat ifTrue: [^ 1000000].\\n\\tsamplesPlayed := mpegFile audioGetSample: mpegStreamIndex.\\n\\tsamplesPlayed > totalSamples ifTrue: [^ 0].\\n\\t^ totalSamples - samplesPlayed\\n! !\\n\\n\\n!StreamingMP3Sound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:48'!\\ncreateMixer\\n\\t\\\"Create a mixed sound consisting of sampled sounds with one sound buffer's worth of samples. The sound has the same sampling rate and number of channels as the MPEG or MP3 file.\\\"\\n\\n\\t| channels pan snd |\\n\\tmpegFile ifNil: [^ self error: 'No MPEG or MP3 file'].\\n\\tchannels := mpegFile audioChannels: mpegStreamIndex.\\n\\tstreamSamplingRate := mpegFile audioSampleRate: mpegStreamIndex.\\n\\tmixer := MixedSound new.\\n\\t1 to: channels do: [:c |\\n\\t\\tchannels = 1\\n\\t\\t\\tifTrue: [pan := 0.5]\\n\\t\\t\\tifFalse: [pan := (c - 1) asFloat / (channels - 1)].\\n\\t\\tsnd := SampledSound\\n\\t\\t\\tsamples: (SoundBuffer newMonoSampleCount: 2) \\\"buffer size will be adjusted dynamically\\\"\\n\\t\\t\\tsamplingRate: streamSamplingRate.\\n\\t\\tmixer add: snd pan: pan volume: volume].\\n! !\\n\\n!StreamingMP3Sound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nloadBuffersForSampleCount: count\\n \\\"Load the sound buffers for all tracks with the next count\\nsamples from the MPEG\\nfile sound track.\\\"\\n\\n | snd buf |\\n 1 to: mixer sounds size do: [:i |\\n snd := mixer sounds at: i.\\n buf := snd samples.\\n buf monoSampleCount = count ifFalse: [\\n buf := SoundBuffer newMonoSampleCount: count.\\n snd setSamples: buf samplingRate:\\nstreamSamplingRate].\\n i = 1 ifTrue: [ \\\"first channel\\\"\\n mpegFile\\n audioReadBuffer: buf\\n stream: mpegStreamIndex\\n channel: 0]\\n ifFalse: [ \\\"all other channels\\\"\\n mpegFile\\n audioReReadBuffer: buf\\n stream: mpegStreamIndex\\n channel: 1]].\\n mixer reset.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStreamingMP3Sound class\\n\\tinstanceVariableNames: ''!\\n\\n!StreamingMP3Sound class methodsFor: 'instance creation' stamp: 'stephaneducasse 2/4/2006 20:48'!\\nonFileNamed: fileName\\n\\t\\\"Answer an instance of me for playing the sound track of the MPEG or MP3 file with the given name. Answer nil the file is not a valid MPEG or MP3 file.\\\"\\n\\n\\t| mpegFile |\\n\\t(MPEGFile isFileValidMPEG: fileName) ifFalse: [^ nil].\\n\\tmpegFile := MPEGFile openFile: fileName.\\n\\t^ self new initMPEGFile: mpegFile streamIndex: 0 \\\"assume sound track is in stream 0\\\"\\n! !\\nAbstractSound subclass: #StreamingMonoSound\\n\\tinstanceVariableNames: 'stream volume repeat headerStart audioDataStart streamSamplingRate totalSamples codec mixer leftoverSamples lastBufferMSecs mutex'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n!StreamingMonoSound commentStamp: '<historical>' prior: 0!\\nI implement a streaming player for monophonic Sun (.au) and AIFF (.aif) audio files.\\nExample of use:\\n\\t(StreamingMonoSound onFileNamed: 'song.aif') play.\\n!\\n\\n\\n!StreamingMonoSound methodsFor: 'accessing' stamp: 'jm 11/16/2001 17:12'!\\nduration\\n\\t\\\"Answer the duration of this sound in seconds.\\\"\\n\\n\\t^ totalSamples asFloat / streamSamplingRate\\n! !\\n\\n!StreamingMonoSound methodsFor: 'accessing' stamp: 'jm 10/18/2001 15:46'!\\nrepeat\\n\\t\\\"Answer the repeat flag.\\\"\\n\\n\\t^ repeat\\n! !\\n\\n!StreamingMonoSound methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nrepeat: aBoolean\\n\\t\\\"Set the repeat flag. If true, this sound will loop back to the beginning when it gets to the end.\\\"\\n\\n\\trepeat := aBoolean.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'accessing' stamp: 'jm 11/16/2001 17:05'!\\nsoundPosition\\n\\t\\\"Answer the relative position of sound playback as a number between 0.0 and 1.0.\\\"\\n\\n\\t(stream isNil or: [stream closed]) ifTrue: [^ 0.0].\\n\\t^ self currentSampleIndex asFloat / totalSamples\\n! !\\n\\n!StreamingMonoSound methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsoundPosition: fraction\\n\\t\\\"Jump to the position the given fraction through the sound file. The argument is a number between 0.0 and 1.0.\\\"\\n\\n\\t| desiredSampleIndex |\\n\\t(stream isNil or: [stream closed]) ifTrue: [^ self].\\n\\tdesiredSampleIndex := ((totalSamples * fraction) truncated max: 0) min: totalSamples.\\n\\tcodec\\n\\t\\tifNil: [stream position: audioDataStart + (desiredSampleIndex * 2)]\\n\\t\\tifNotNil: [self positionCodecTo: desiredSampleIndex].\\n\\tleftoverSamples := SoundBuffer new.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'accessing' stamp: 'jm 11/20/2001 16:59'!\\nstreamSamplingRate\\n\\t\\\"Answer the sampling rate of the MP3 stream.\\\"\\n\\n\\t^ streamSamplingRate\\n! !\\n\\n!StreamingMonoSound methodsFor: 'accessing' stamp: 'jm 9/26/2000 07:49'!\\nvolume\\n\\t\\\"Answer my volume.\\\"\\n\\n\\t^ volume\\n! !\\n\\n!StreamingMonoSound methodsFor: 'accessing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nvolume: aNumber\\n\\t\\\"Set my volume to the given number between 0.0 and 1.0.\\\"\\n\\n\\tvolume := aNumber.\\n\\tself createMixer.\\n! !\\n\\n\\n!StreamingMonoSound methodsFor: 'converting' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsaveAsFileNamed: newFileName compressionType: compressionTypeString\\n\\t\\\"Store this sound in a new file with the given name using the given compression type. Useful for converting between compression formats.\\\"\\n\\n\\t| outFile |\\n\\toutFile := (FileStream newFileNamed: newFileName) binary.\\n\\tself storeSunAudioOn: outFile compressionType: compressionTypeString.\\n\\toutFile close.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'converting' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstoreSunAudioOn: aBinaryStream compressionType: compressionName\\n\\t\\\"Store myself on the given stream as a monophonic sound compressed with the given type of compression. The sampling rate is reduced to 22050 samples/second if it is higher.\\\"\\n\\n\\t| fmt inBufSize samplesPerFrame outCodec compressed outSamplingRate audioWriter samplesRemaining inBuf outBuf counts byteCount |\\n\\tself pause; reset. \\\"stop playing and return to beginning\\\"\\n\\n\\tfmt := SunAudioFileWriter formatCodeForCompressionType: compressionName.\\n\\tinBufSize := 64000.\\n\\tsamplesPerFrame := 1.\\n\\toutCodec := SunAudioFileWriter codecForFormatCode: fmt.\\n\\toutCodec ifNotNil: [\\n\\t\\tsamplesPerFrame := outCodec samplesPerFrame.\\n\\t\\tinBufSize := inBufSize roundUpTo: (2 * samplesPerFrame).\\n\\t\\tcompressed := ByteArray new:\\n\\t\\t\\t(inBufSize // samplesPerFrame) * outCodec bytesPerEncodedFrame].\\n\\toutSamplingRate := streamSamplingRate.\\n\\tstreamSamplingRate > 22050 ifTrue: [\\n\\t\\tstreamSamplingRate = 44100 ifFalse: [self error: 'unexpected MP3 sampling rate'].\\n\\t\\toutSamplingRate := 22050].\\n\\n\\t\\\"write audio header\\\"\\n\\taudioWriter := SunAudioFileWriter onStream: aBinaryStream.\\n\\taudioWriter writeHeaderSamplingRate: outSamplingRate format: fmt.\\n\\n\\t\\\"convert and write sound data\\\"\\n\\t'Storing audio...' displayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0 to: totalSamples during: [:bar |\\n\\t\\t\\tsamplesRemaining := totalSamples.\\n\\t\\t\\t[samplesRemaining > 0] whileTrue: [\\n\\t\\t\\t\\tbar value: totalSamples - samplesRemaining.\\n\\t\\t\\t\\tself loadBuffersForSampleCount: (inBufSize min: samplesRemaining).\\n\\t\\t\\t\\tinBuf := mixer sounds first samples.\\n\\t\\t\\t\\toutSamplingRate < streamSamplingRate\\n\\t\\t\\t\\t\\tifTrue: [outBuf := inBuf downSampledLowPassFiltering: true]\\n\\t\\t\\t\\t\\tifFalse: [outBuf := inBuf].\\n\\t\\t\\t\\toutCodec\\n\\t\\t\\t\\t\\tifNil: [audioWriter appendSamples: outBuf]\\n\\t\\t\\t\\t\\tifNotNil: [\\n\\t\\t\\t\\t\\t\\tcounts := outCodec\\n\\t\\t\\t\\t\\t\\t\\tencodeFrames: (outBuf size // samplesPerFrame)\\n\\t\\t\\t\\t\\t\\t\\tfrom: outBuf at: 1\\n\\t\\t\\t\\t\\t\\t\\tinto: compressed at: 1.\\n\\t\\t\\t\\t\\t\\tbyteCount := counts last.\\n\\t\\t\\t\\t\\t\\tbyteCount = compressed size\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [audioWriter appendBytes: compressed]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [audioWriter appendBytes: (compressed copyFrom: 1 to: byteCount)]].\\n\\t\\t\\t\\tsamplesRemaining := samplesRemaining - inBuf monoSampleCount]].\\n\\n\\t\\\"update audio header\\\"\\n\\taudioWriter updateHeaderDataSize.\\n! !\\n\\n\\n!StreamingMonoSound methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ninitStream: aStream headerStart: anInteger\\n\\t\\\"Initialize for streaming from the given stream. The audio file header starts at the given stream position.\\\"\\n\\n\\tstream := aStream.\\n\\tvolume := 1.0.\\n\\trepeat := false.\\n\\theaderStart := anInteger.\\n\\tself reset.\\n! !\\n\\n\\n!StreamingMonoSound methodsFor: 'other' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncloseFile\\n\\t\\\"Close my stream, if it responds to close.\\\"\\n\\n\\tstream ifNotNil: [\\n\\t\\t(stream respondsTo: #close) ifTrue: [stream close]].\\n\\tmixer := nil.\\n\\tcodec := nil.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'other' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nextractFrom: startSecs to: endSecs\\n\\t\\\"Extract a portion of this sound between the given start and end times. The current implementation only works if the sound is uncompressed.\\\"\\n\\n\\t| emptySound first last sampleCount byteStream sndBuf |\\n\\tcodec ifNotNil: [^ self error: 'only works on uncompressed sounds'].\\n\\temptySound := SampledSound samples: SoundBuffer new samplingRate: streamSamplingRate.\\n\\tfirst := (startSecs * streamSamplingRate) truncated max: 0.\\n\\tlast := ((endSecs * streamSamplingRate) truncated min: totalSamples) - 1.\\n\\tfirst >= last ifTrue: [^ emptySound].\\n\\tcodec ifNotNil: [self error: 'extracting from compressed sounds is not supported'].\\n\\tsampleCount := last + 1 - first.\\n\\tstream position: audioDataStart + (2 * first).\\n\\tbyteStream := ReadStream on: (stream next: 2 * sampleCount).\\n\\tsndBuf := SoundBuffer newMonoSampleCount: sampleCount.\\n\\t1 to: sampleCount do: [:i | sndBuf at: i put: byteStream int16].\\n\\t^ SampledSound samples: sndBuf samplingRate: streamSamplingRate\\n! !\\n\\n\\n!StreamingMonoSound methodsFor: 'playing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nmillisecondsSinceStart\\n\\t\\\"Answer the number of milliseconds of this sound started playing.\\\"\\n\\n\\t| mSecs |\\n\\t(stream isNil or: [stream closed]) ifTrue: [^ 0].\\n\\tmSecs := self currentSampleIndex * 1000 // streamSamplingRate.\\n\\t(self isPlaying and: [lastBufferMSecs > 0]) ifTrue: [\\n\\t\\t\\\"adjust mSecs by the milliseconds since the last buffer\\\"\\n\\t\\tmutex critical: [\\n\\t\\t\\tmSecs := self currentSampleIndex * 1000 // streamSamplingRate.\\n\\t\\t\\tmSecs := mSecs + ((Time millisecondClockValue - lastBufferMSecs) max: 0)]].\\n\\t^ mSecs + 350 - (2 * SoundPlayer bufferMSecs)\\n! !\\n\\n!StreamingMonoSound methodsFor: 'playing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nplaySampleCount: n into: aSoundBuffer startingAt: startIndex\\n\\t\\\"Mix the next n samples of this sound into the given buffer starting at the given index\\\"\\n\\n\\tself repeat ifTrue: [ \\\"loop if necessary\\\"\\n\\t\\t(totalSamples - self currentSampleIndex) < n ifTrue: [self startOver]].\\n\\n\\tmutex critical: [\\n\\t\\tlastBufferMSecs := Time millisecondClockValue.\\n\\t\\tself loadBuffersForSampleCount: (n * streamSamplingRate) // SoundPlayer samplingRate.\\n\\t\\tmixer playSampleCount: n into: aSoundBuffer startingAt: startIndex].\\n! !\\n\\n!StreamingMonoSound methodsFor: 'playing' stamp: 'jm 10/21/2001 09:45'!\\nreset\\n\\n\\tsuper reset.\\n\\tself startOver.\\n\\tself createMixer.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'playing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsamplesRemaining\\n\\t\\\"Answer the number of samples remaining to be played.\\\"\\n\\n\\t| result |\\n\\t(stream isNil or: [stream closed]) ifTrue: [^ 0].\\n\\tself repeat ifTrue: [^ 1000000].\\n\\tresult := (totalSamples - self currentSampleIndex) max: 0.\\n\\tresult <= 0 ifTrue: [self closeFile].\\n\\t^ result\\n! !\\n\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncreateMixer\\n\\t\\\"Create a mixed sound consisting of sampled sounds with one sound buffer's worth of samples.\\\"\\n\\n\\t| snd |\\n\\tmixer := MixedSound new.\\n\\tsnd := SampledSound\\n\\t\\tsamples: (SoundBuffer newMonoSampleCount: 2) \\\"buffer size will be adjusted dynamically\\\"\\n\\t\\tsamplingRate: streamSamplingRate.\\n\\tmixer add: snd pan: 0.5 volume: volume.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\ncurrentSampleIndex\\n\\t\\\"Answer the index of the current sample.\\\"\\n\\n\\t| bytePosition frameIndex |\\n\\tbytePosition := stream position - audioDataStart.\\n\\tcodec\\n\\t\\tifNil: [^ bytePosition // 2]\\n\\t\\tifNotNil: [\\n\\t\\t\\tframeIndex := bytePosition // codec bytesPerEncodedFrame.\\n\\t\\t\\t^ (frameIndex * codec samplesPerFrame) - leftoverSamples monoSampleCount].\\n! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nloadBuffer: aSoundBuffer compressedSampleCount: sampleCount\\n\\t\\\"Load the given sound buffer from the compressed sample stream.\\\"\\n\\t\\\"Details: Most codecs decode in multi-sample units called 'frames'. Since the requested sampleCount is typically not an even multiple of the frame size, we need to deal with partial frames. The unused samples from a partial frame are retained until the next call to this method.\\\"\\n\\n\\t| n samplesNeeded frameCount encodedBytes r decodedCount buf j |\\n\\t\\\"first, use any leftover samples\\\"\\n\\tn := self loadFromLeftovers: aSoundBuffer sampleCount: sampleCount.\\n\\tsamplesNeeded := sampleCount - n.\\n\\tsamplesNeeded <= 0 ifTrue: [^ self].\\n\\n\\t\\\"decode an integral number of full compression frames\\\"\\n\\tframeCount := samplesNeeded // codec samplesPerFrame.\\n\\tencodedBytes := stream next: (frameCount * codec bytesPerEncodedFrame).\\n\\tr := codec decodeFrames: frameCount from: encodedBytes at: 1 into: aSoundBuffer at: n + 1.\\n\\tdecodedCount := r last.\\n\\tdecodedCount >= samplesNeeded ifTrue: [^ self].\\n\\n\\t\\\"decode one last compression frame to finish filling the buffer\\\"\\n\\tbuf := SoundBuffer newMonoSampleCount: codec samplesPerFrame.\\n\\tencodedBytes := stream next: codec bytesPerEncodedFrame.\\n\\tcodec decodeFrames: 1 from: encodedBytes at: 1 into: buf at: 1.\\n\\tj := 0.\\n\\t(n + decodedCount + 1) to: sampleCount do: [:i |\\n\\t\\taSoundBuffer at: i put: (buf at: (j := j + 1))].\\n\\n\\t\\\"save the leftover samples\\\"\\n\\tleftoverSamples := buf copyFrom: (j + 1) to: buf monoSampleCount.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'jm 11/21/2001 08:03'!\\nloadBuffer: aSoundBuffer uncompressedSampleCount: sampleCount\\n\\t\\\"Load the given sound buffer from the uncompressed sample stream.\\\"\\n\\n\\t\\\"read directly into the sample buffer; count is in 32-bit words\\\"\\n\\tstream next: sampleCount // 2 into: aSoundBuffer startingAt: 1.\\n\\taSoundBuffer restoreEndianness.\\n\\n\\t\\\"read the final sample if sampleCount is odd:\\\"\\n\\tsampleCount odd ifTrue: [aSoundBuffer at: sampleCount put: stream int16].\\n! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nloadBuffersForSampleCount: count\\n\\t\\\"Load the sound buffers from the stream.\\\"\\n\\n\\t| snd buf sampleCount |\\n\\tsnd := mixer sounds first.\\n\\tbuf := snd samples.\\n\\tbuf monoSampleCount = count ifFalse: [\\n\\t\\tbuf := SoundBuffer newMonoSampleCount: count.\\n\\t\\tsnd setSamples: buf samplingRate: streamSamplingRate].\\n\\tsampleCount := count min: (totalSamples - self currentSampleIndex).\\n\\tsampleCount < count ifTrue: [buf primFill: 0].\\n\\n\\tcodec\\n\\t\\tifNil: [self loadBuffer: buf uncompressedSampleCount: sampleCount]\\n\\t\\tifNotNil: [self loadBuffer: buf compressedSampleCount: sampleCount].\\n\\n\\tmixer reset.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nloadFromLeftovers: aSoundBuffer sampleCount: sampleCount\\n\\t\\\"Load the given sound buffer from the samples leftover from the last frame. Answer the number of samples loaded, which typically is less than sampleCount.\\\"\\n\\n\\t| leftoverCount n |\\n\\tleftoverCount := leftoverSamples monoSampleCount.\\n\\tleftoverCount = 0 ifTrue: [^ 0].\\n\\n\\tn := leftoverCount min: sampleCount.\\n\\t1 to: n do: [:i | aSoundBuffer at: i put: (leftoverSamples at: i)].\\n\\tn < sampleCount\\n\\t\\tifTrue: [leftoverSamples := SoundBuffer new]\\n\\t\\tifFalse: [leftoverSamples := leftoverSamples copyFrom: n + 1 to: leftoverSamples size].\\n\\t^ n\\n! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\npositionCodecTo: desiredSampleIndex\\n\\t\\\"Position to the closest frame before the given sample index when using a codec. If using the ADPCM codec, try to ensure that it is in sync with the compressed sample stream.\\\"\\n\\n\\t| desiredFrameIndex desiredPosition tmpStream tmpCodec byteBuf bufFrames sampleBuf frameCount n startOffset |\\n\\t(codec isKindOf: ADPCMCodec) ifFalse: [\\n\\t\\t\\\"stateless codecs (or relatively stateless ones, like GSM: just jump to frame boundary\\\"\\n\\t\\tdesiredFrameIndex := desiredSampleIndex // codec samplesPerFrame.\\n\\t\\tstream position: audioDataStart + (desiredFrameIndex * codec bytesPerEncodedFrame).\\n\\t\\tcodec reset.\\n\\t\\t^ self].\\n\\n\\t\\\"compute the desired stream position\\\"\\n\\tdesiredFrameIndex := desiredSampleIndex // codec samplesPerFrame.\\n\\tdesiredPosition := audioDataStart + (desiredFrameIndex * codec bytesPerEncodedFrame).\\n\\n\\t\\\"copy stream and codec\\\"\\n\\t(stream isKindOf: FileStream)\\n\\t\\tifTrue: [tmpStream := (FileStream readOnlyFileNamed: stream name) binary]\\n\\t\\tifFalse: [tmpStream := stream deepCopy].\\n\\ttmpCodec := codec copy reset.\\n\\n\\t\\\"reset the codec and start back about 30 seconds to try to get codec in sync\\\"\\n\\tstartOffset := ((desiredFrameIndex - 80000) max: 0) * codec bytesPerEncodedFrame.\\n\\ttmpStream position: audioDataStart + startOffset.\\n\\n\\t\\\"decode forward to the desired position\\\"\\n\\tbyteBuf := ByteArray new: (32000 roundTo: codec bytesPerEncodedFrame).\\n\\tbufFrames := byteBuf size // codec bytesPerEncodedFrame.\\n\\tsampleBuf := SoundBuffer newMonoSampleCount: bufFrames * codec samplesPerFrame.\\n\\tframeCount := (desiredPosition - tmpStream position) // codec bytesPerEncodedFrame.\\n\\t[frameCount > 0] whileTrue: [\\n\\t\\tn := bufFrames min: frameCount.\\n\\t\\ttmpStream next: n * codec bytesPerEncodedFrame into: byteBuf startingAt: 1.\\n\\t\\ttmpCodec decodeFrames: n from: byteBuf at: 1 into: sampleBuf at: 1.\\n\\t\\tframeCount := frameCount - n].\\n\\n\\tcodec := tmpCodec.\\n\\tstream position: tmpStream position.\\n\\t(tmpStream isKindOf: FileStream) ifTrue: [tmpStream close].! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nreadAIFFHeader\\n\\t\\\"Read an AIFF file header from stream.\\\"\\n\\n\\t| aiffReader |\\n\\taiffReader := AIFFFileReader new.\\n\\taiffReader readFromStream: stream mergeIfStereo: false skipDataChunk: true.\\n\\taiffReader channelCount = 1 ifFalse: [self error: 'not monophonic'].\\n\\taiffReader bitsPerSample = 16 ifFalse: [self error: 'not 16-bit'].\\n\\n\\taudioDataStart := headerStart + aiffReader channelDataOffset.\\n\\tstreamSamplingRate := aiffReader samplingRate.\\n\\ttotalSamples := aiffReader frameCount min: (stream size - audioDataStart) // 2.\\n\\tcodec := nil.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nreadHeader\\n\\t\\\"Read the sound file header from my stream.\\\"\\n\\n\\t| id |\\n\\tstream position: headerStart.\\n\\tid := (stream next: 4) asString.\\n\\tstream position: headerStart.\\n\\tid = '.snd' ifTrue: [^ self readSunAudioHeader].\\n\\tid = 'FORM' ifTrue: [^ self readAIFFHeader].\\n\\tself error: 'unrecognized sound file format'.\\n! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nreadSunAudioHeader\\n\\t\\\"Read a Sun audio file header from my stream.\\\"\\n\\n\\t| id headerBytes dataBytes format channelCount |\\n\\tid := (stream next: 4) asString.\\n\\theaderBytes := stream uint32. \\\"header bytes\\\"\\n\\tdataBytes := stream uint32.\\n\\tformat := stream uint32.\\n\\tstreamSamplingRate := stream uint32.\\n\\tchannelCount := stream uint32.\\n\\n\\tid = '.snd' ifFalse: [self error: 'not Sun audio format'].\\n\\tdataBytes := dataBytes min: (stream size - headerBytes).\\n\\tchannelCount = 1 ifFalse: [self error: 'not monophonic'].\\n\\taudioDataStart := headerStart + headerBytes.\\n\\tcodec := nil.\\n\\tformat = 1 ifTrue: [ \\\"8-bit u-LAW\\\"\\n\\t\\tcodec := MuLawCodec new.\\n\\t\\ttotalSamples := dataBytes.\\n\\t\\t^ self].\\n\\tformat = 3 ifTrue: [ \\\"16-bit linear\\\"\\n\\t\\ttotalSamples := dataBytes // 2.\\n\\t\\t^ self].\\n\\tformat = 23 ifTrue: [ \\\"ADPCM-4 bit (CCITT G.721)\\\"\\n\\t\\tcodec := ADPCMCodec new\\n\\t\\t\\tinitializeForBitsPerSample: 4 samplesPerFrame: 0.\\n\\t\\ttotalSamples := (dataBytes // 4) * 8.\\n\\t\\t^ self].\\n\\tformat = 25 ifTrue: [ \\\"ADPCM-3 bit (CCITT G.723)\\\"\\n\\t\\tcodec := ADPCMCodec new\\n\\t\\t\\tinitializeForBitsPerSample: 3 samplesPerFrame: 0.\\n\\t\\ttotalSamples := (dataBytes // 3) * 8.\\n\\t\\t^ self].\\n\\tformat = 26 ifTrue: [ \\\"ADPCM-5 bit (CCITT G.723)\\\"\\n\\t\\tcodec := ADPCMCodec new\\n\\t\\t\\tinitializeForBitsPerSample: 5 samplesPerFrame: 0.\\n\\t\\ttotalSamples := (dataBytes // 5) * 8.\\n\\t\\t^ self].\\n\\tformat = 610 ifTrue: [ \\\"GSM 06.10 (this format was added by Squeak)\\\"\\n\\t\\tcodec := GSMCodec new.\\n\\t\\ttotalSamples := (dataBytes // 33) * 160.\\n\\t\\t^ self].\\n\\tself error: 'unsupported Sun audio format ', format printString\\n! !\\n\\n!StreamingMonoSound methodsFor: 'private' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstartOver\\n\\t\\\"Jump back to the first sample.\\\"\\n\\n\\tstream reopen; binary.\\n\\tself readHeader.\\n\\tstream position: audioDataStart.\\n\\tleftoverSamples := SoundBuffer new.\\n\\tlastBufferMSecs := 0.\\n\\tmutex := Semaphore forMutualExclusion.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStreamingMonoSound class\\n\\tinstanceVariableNames: ''!\\n\\n!StreamingMonoSound class methodsFor: 'instance creation' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nonFileNamed: fileName\\n\\t\\\"Answer an instance of me for playing the file with the given name.\\\"\\n\\n\\t| f |\\n\\tf := FileDirectory default readOnlyFileNamed: fileName.\\n\\tf ifNil: [^ self error: 'could not open ', fileName].\\n\\t^ self new initStream: f headerStart: 0\\n! !\\n\\n!StreamingMonoSound class methodsFor: 'instance creation' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nonFileNamed: fileName headerStart: anInteger\\n\\t\\\"Answer an instance of me for playing audio data starting at the given position in the file with the given name.\\\"\\n\\n\\t| f |\\n\\tf := FileDirectory default readOnlyFileNamed: fileName.\\n\\tf ifNil: [^ self error: 'could not open ', fileName].\\n\\t^ self new initStream: f headerStart: anInteger\\n! !\\nAlignmentMorphBob1 subclass: #StretchyImageMorph\\n\\tinstanceVariableNames: 'form cache'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Experimental'!\\n!StretchyImageMorph commentStamp: '<historical>' prior: 0!\\nI draw a form to fill whatever bounds I have.!\\n\\n\\n!StretchyImageMorph methodsFor: 'as yet unclassified' stamp: 'RAA 7/10/2000 16:20'!\\nform: aForm\\n\\n\\tform _ aForm! !\\n\\n\\n!StretchyImageMorph methodsFor: 'drawing' stamp: 'nk 1/3/2004 17:40'!\\ndrawOn: aCanvas\\n| t |\\n\\\"\\nSmalltalk at: #Q4 put: OrderedCollection new.\\n\\\"\\n\\tform ifNil: [form _ (Form extent: 32@32 depth: 8) fillColor: Color green].\\n\\t(cache isNil or: [cache extent ~= bounds extent]) ifTrue: [\\n\\t\\tt _ [cache _ Form extent: bounds extent depth: form depth.\\n\\t\\tform displayInterpolatedIn: cache boundingBox on: cache.\\n\\t\\tcache _ cache asFormOfDepth: aCanvas depth] timeToRun.\\n\\t\\t\\\"Q4 add: {t. form. cache}.\\\"\\n\\t].\\n\\taCanvas paintImage: cache at: bounds origin.\\n! !\\n\\n\\n!StretchyImageMorph methodsFor: 'initialization' stamp: 'ar 10/30/2000 15:31'!\\ninitialize\\n\\n\\tsuper initialize.\\n\\tself hResizing: #spaceFill.\\n\\tself vResizing: #spaceFill.\\n! !\\nAbstractFont subclass: #StrikeFont\\n\\tinstanceVariableNames: 'characterToGlyphMap xTable glyphs name type minAscii maxAscii maxWidth strikeLength ascent descent xOffset raster subscript superscript emphasis derivativeFonts pointSize fallbackFont charIndex'\\n\\tclassVariableNames: 'DefaultStringScanner'\\n\\tpoolDictionaries: 'TextConstants'\\n\\tcategory: 'Graphics-Fonts'!\\n!StrikeFont commentStamp: '<historical>' prior: 0!\\nI represent a compact encoding of a set of Forms corresponding to characters in the ASCII character set. All the forms are placed side by side in a large form whose height is the font height, and whose width is the sum of all the character widths. The xTable variable gives the left-x coordinates of the subforms corresponding to the glyphs. Characters are mapped to glyphs by using the characterToGyphMap.\\n\\nSubclasses can have non-trivial mapping rules as well as different representations for glyphs sizes (e.g., not using an xTable). If so, these classes should return nil when queried for xTable and/or the characterToGlyphMap. This will cause the CharacterScanner primitive to fail and query the font for the width of a character (so that a more programatical approach can be implemented).\\n\\nFor display, fonts need to implement two messages:\\n\\t#installOn: aDisplayContext foregroundColor: foregroundColor backgroundColor: backgroundColor\\nThis method installs the receiver (a font) on the given DisplayContext (which may be an instance of BitBlt or Canvas (or any of it's subclasses). The font should take the appropriate action to initialize the display context so that further display operations can be optimized.\\n\\t#displayString: aString on: aDisplayContext from: startIndex to: stopIndex at: aPoint kern: kernDelta\\nThis method is called for each subsequent run of characters in aString which is to be displayed with the (previously installed) settings.\\n!\\n\\n\\n!StrikeFont methodsFor: 'accessing'!\\nascent\\n\\t\\\"Answer the receiver's maximum extent of characters above the baseline.\\\"\\n\\n\\t^ascent! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'di 9/2/2000 13:06'!\\nascentKern\\n\\t\\\"Return the kern delta for ascenders.\\\"\\n\\t(emphasis noMask: 2) ifTrue: [^ 0].\\n\\t^ (self ascent-5+4)//4 max: 0 \\\"See makeItalicGlyphs\\\"\\n\\n! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'yo 1/6/2005 04:19'!\\nascentOf: aCharacter\\n\\n\\t(self hasGlyphOf: aCharacter) ifFalse: [\\n\\t\\tfallbackFont ifNotNil: [\\n\\t\\t\\t^ fallbackFont ascentOf: aCharacter.\\n\\t\\t].\\n\\t].\\n\\t^ self ascent.\\n! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'di 9/1/2000 17:17'!\\nbaseKern\\n\\t\\\"Return the base kern value to be used for all characters.\\\"\\n\\t(emphasis noMask: 2) ifTrue: [^ 0].\\n\\t^ ((self height-1-self ascent+4)//4 max: 0) \\\"See makeItalicGlyphs\\\"\\n\\t\\t+ (((self ascent-5+4)//4 max: 0))\\n! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'ar 5/23/2000 12:52'!\\ncharacterToGlyphMap\\n\\t^characterToGlyphMap ifNil:[characterToGlyphMap _ self createCharacterToGlyphMap].! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'ar 5/23/2000 12:52'!\\ncharacterToGlyphMap: anArray\\n\\tcharacterToGlyphMap _ anArray.! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'nk 3/15/2004 18:57'!\\nderivativeFonts\\n\\t^derivativeFonts copyWithout: nil! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\ndescent\\n\\t\\\"Answer the receiver's maximum extent of characters below the baseline.\\\"\\n\\n\\t^descent! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'di 9/2/2000 13:06'!\\ndescentKern\\n\\t\\\"Return the kern delta for descenders.\\\"\\n\\t(emphasis noMask: 2) ifTrue: [^ 0].\\n\\t^ (self height-1-self ascent+4)//4 max: 0 \\\"See makeItalicGlyphs\\\"\\n\\n! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'yo 1/6/2005 04:19'!\\ndescentOf: aCharacter\\n\\n\\t(self hasGlyphOf: aCharacter) ifFalse: [\\n\\t\\tfallbackFont ifNotNil: [\\n\\t\\t\\t^ fallbackFont descentOf: aCharacter.\\n\\t\\t].\\n\\t].\\n\\t^ self descent.\\n! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'tak 12/22/2004 01:25'!\\nfallbackFont\\n\\t^ fallbackFont\\n\\t\\tifNil: [fallbackFont _ FixedFaceFont new errorFont fontSize: self height]! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'yo 5/20/2004 11:01'!\\nfallbackFont: aFontSetOrNil\\n\\n\\tfallbackFont _ aFontSetOrNil.\\n! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nfamilyName\\n\\t^self name withoutTrailingDigits.\\n\\n! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'tk 6/26/1998 16:45'!\\nfamilySizeFace\\n\\t\\\"Answer an array with familyName, a String, pointSize, an Integer, and\\n\\tfaceCode, an Integer.\\\"\\n\\n\\t^Array with: name\\n\\t\\twith: self height\\n\\t\\twith: emphasis\\n\\n\\t\\\"(1 to: 12) collect: [:x | (TextStyle default fontAt: x) familySizeFace]\\\"! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'ar 9/21/2000 11:53'!\\nfontNameWithPointSize\\n\\t^self name withoutTrailingDigits, ' ', self pointSize printString! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'yo 1/7/2005 11:15'!\\nglyphInfoOf: aCharacter into: glyphInfoArray\\n\\t\\\"Answer the width of the argument as a character in the receiver.\\\"\\n\\n\\t| code |\\n\\t(self hasGlyphOf: aCharacter) ifFalse: [\\n\\t\\tfallbackFont ifNotNil: [\\n\\t\\t\\t^ fallbackFont glyphInfoOf: aCharacter into: glyphInfoArray.\\n\\t\\t].\\n\\t\\tcode _ 0.\\n\\t] ifTrue: [\\n\\t\\tcode _ aCharacter charCode.\\n\\t].\\n\\tglyphInfoArray at: 1 put: glyphs;\\n\\t\\tat: 2 put: (xTable at: code + 1);\\n\\t\\tat: 3 put: (xTable at: code + 2);\\n\\t\\tat: 4 put: (self ascentOf: aCharacter);\\n\\t\\tat: 5 put: self.\\n\\t^ glyphInfoArray.\\n! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'yo 1/6/2005 04:19'!\\nglyphOf: aCharacter \\n\\t\\\"Answer the width of the argument as a character in the receiver.\\\"\\n\\n\\t| code |\\n\\t(self hasGlyphOf: aCharacter) ifFalse: [\\n\\t\\tfallbackFont ifNotNil: [\\n\\t\\t\\t^ fallbackFont glyphOf: aCharacter.\\n\\t\\t].\\n\\t\\t^ (Form extent: 1@self height) fillColor: Color white\\n\\t].\\n\\tcode _ aCharacter charCode.\\n\\t^ glyphs copy: (((xTable at: code + 1)@0) corner: (xTable at: code +2)@self height).\\n! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nglyphs\\n\\t\\\"Answer a Form containing the bits representing the characters of the \\n\\treceiver.\\\"\\n\\n\\t^glyphs! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nheight\\n\\t\\\"Answer the height of the receiver, total of maximum extents of \\n\\tcharacters above and below the baseline.\\\"\\n\\n\\t^self ascent + self descent! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'yo 1/6/2005 04:19'!\\nheightOf: aCharacter\\n\\n\\t(self hasGlyphOf: aCharacter) ifFalse: [\\n\\t\\tfallbackFont ifNotNil: [\\n\\t\\t\\t^ fallbackFont heightOf: aCharacter.\\n\\t\\t].\\n\\t].\\n\\t^ self height.\\n! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nlineGrid\\n\\t^ ascent + descent! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nmaxAscii\\n\\t\\\"Answer the integer that is the last Ascii character value of the receiver.\\\"\\n\\n\\t^maxAscii! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nmaxWidth\\n\\t\\\"Answer the integer that is the width of the receiver's widest character.\\\"\\n\\n\\t^maxWidth! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nminAscii\\n\\t\\\"Answer the integer that is the first Ascii character value of the receiver.\\\"\\n\\n\\t^minAscii! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'ls 3/27/2000 19:54'!\\nname\\n\\t\\\"Answer the receiver's name.\\\"\\n\\n\\t^name ifNil: ['(unnamed)']! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nname: aString\\n\\t\\\"Set the receiver's name.\\\"\\n\\n\\tname _ aString! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'sw 1/18/2000 20:54'!\\npointSize\\n\\t^ pointSize! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'sma 5/5/2000 14:21'!\\npointSize: anInteger\\n\\tpointSize _ anInteger! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nraster\\n\\t\\\"Answer an integer that specifies the layout of the glyphs' form.\\\"\\n\\n\\t^raster! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nsetGlyphs: newGlyphs\\n\\t\\\"Replace the glyphs form. Used to make a synthetic bold or italic font quickly.\\\"\\n\\n\\tglyphs _ newGlyphs! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nsubscript\\n\\t\\\"Answer an integer that is the further vertical offset relative to the \\n\\tbaseline for positioning characters as subscripts.\\\"\\n\\n\\t^subscript! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nsuperscript\\n\\t\\\"Answer an integer that is the further vertical offset relative to the \\n\\tbaseline for positioning characters as superscripts.\\\"\\n\\n\\t^superscript! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'nk 6/17/2003 14:26'!\\ntextStyle\\n\\t^ TextStyle actualTextStyles detect:\\n\\t\\t[:aStyle | aStyle fontArray includes: self] ifNone: [nil]! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'ar 4/12/2005 17:12'!\\nwidthOf: aCharacter \\n\\t\\\"Answer the width of the argument as a character in the receiver.\\\"\\n\\t| code |\\n\\tcode := aCharacter charCode.\\n\\t((code < minAscii or: [maxAscii < code]) \\n\\t\\tor: [(xTable at: code + 1) < 0])\\n\\t\\t\\tifTrue: [^ self fallbackFont widthOf: aCharacter].\\n\\t^ (xTable at: code + 2) - (xTable at: code + 1)! !\\n\\n!StrikeFont methodsFor: 'accessing'!\\nxTable\\n\\t\\\"Answer an Array of the left x-coordinate of characters in glyphs.\\\"\\n\\n\\t^xTable! !\\n\\n!StrikeFont methodsFor: 'accessing' stamp: 'yo 8/28/2002 16:33'!\\nxTable: anObject\\n\\n\\txTable _ anObject.\\n! !\\n\\n\\n!StrikeFont methodsFor: 'character shapes'!\\nalter: char formBlock: formBlock\\n\\tself characterFormAt: char \\n\\t\\tput: (formBlock value: (self characterFormAt: char))! !\\n\\n!StrikeFont methodsFor: 'character shapes' stamp: 'yo 12/28/2002 22:37'!\\ncharacterFormAtMulti: character \\n\\t\\\"Answer a Form copied out of the glyphs for the argument, character.\\\"\\n\\t| ascii leftX rightX |\\n\\tascii _ character charCode.\\n\\t(ascii between: minAscii and: maxAscii) ifFalse: [ascii _ maxAscii + 1].\\n\\tleftX _ xTable at: ascii + 1.\\n\\trightX _ xTable at: ascii + 2.\\n\\t^ glyphs copy: (leftX @ 0 corner: rightX @ self height)! !\\n\\n!StrikeFont methodsFor: 'character shapes' stamp: 'yo 12/1/2003 17:01'!\\ncharacterFormAt: character \\n\\t\\\"Answer a Form copied out of the glyphs for the argument, character.\\\"\\n\\t| ascii leftX rightX |\\n\\tascii _ character charCode.\\n\\t(ascii between: minAscii and: maxAscii) ifFalse: [ascii _ maxAscii + 1].\\n\\tleftX _ xTable at: ascii + 1.\\n\\trightX _ xTable at: ascii + 2.\\n\\tleftX < 0 ifTrue: [^ glyphs copy: (0@0 corner: 0@self height)].\\n\\t^ glyphs copy: (leftX @ 0 corner: rightX @ self height)! !\\n\\n!StrikeFont methodsFor: 'character shapes' stamp: 'di 8/30/2000 10:00'!\\ncharacterFormAt: character put: characterForm\\n\\t\\\"Copy characterForm over the glyph for the argument, character.\\\"\\n\\t| ascii leftX rightX widthDif newGlyphs |\\n\\tascii _ character asciiValue.\\n\\tascii < minAscii ifTrue: [^ self error: 'Cant store characters below min ascii'].\\n\\tascii > maxAscii ifTrue:\\n\\t\\t[(self confirm:\\n'This font does not accomodate ascii values higher than ' , maxAscii printString , '.\\nDo you wish to extend it permanently to handle values up to ' , ascii printString)\\n\\t\\t\\tifTrue: [self extendMaxAsciiTo: ascii]\\n\\t\\t\\tifFalse: [^ self error: 'No change made']].\\n\\tleftX _ xTable at: ascii + 1.\\n\\trightX _ xTable at: ascii + 2.\\n\\twidthDif _ characterForm width - (rightX - leftX).\\n\\twidthDif ~= 0 ifTrue:\\n\\t\\t[\\\"Make new glyphs with more or less space for this char\\\"\\n\\t\\tnewGlyphs _ Form extent: (glyphs width + widthDif) @ glyphs height.\\n\\t\\tnewGlyphs copy: (0@0 corner: leftX@glyphs height)\\n\\t\\t\\tfrom: 0@0 in: glyphs rule: Form over.\\n\\t\\tnewGlyphs copy: ((rightX+widthDif)@0 corner: newGlyphs width@glyphs height)\\n\\t\\t\\tfrom: rightX@0 in: glyphs rule: Form over.\\n\\t\\tglyphs _ newGlyphs.\\n\\t\\t\\\"adjust further entries on xTable\\\"\\n\\t\\txTable _ xTable copy.\\n\\t\\tascii+2 to: xTable size\\n\\t\\t\\tdo: [:i | xTable at: i put: (xTable at: i) + widthDif]].\\n\\tglyphs copy: (leftX @ 0 extent: characterForm extent)\\n\\t\\tfrom: 0@0 in: characterForm rule: Form over\\n\\\"\\n| f | f _ TextStyle defaultFont.\\nf characterFormAt: $ put: (Form extent: (f widthOf: $ )+10@f height)\\n\\\"! !\\n\\n!StrikeFont methodsFor: 'character shapes'!\\ncharacterForm: char pixelValueAt: pt put: val\\n\\t| f |\\n\\tf _ self characterFormAt: char.\\n\\tf pixelAt: pt put: val.\\n\\tself characterFormAt: char put: val! !\\n\\n!StrikeFont methodsFor: 'character shapes' stamp: 'btr 11/18/2002 15:00'!\\nedit: character \\n\\t\\\"Open a Bit Editor on the given character. Note that you must do an accept \\n\\t(in the option menu of the bit editor) if you want this work. \\n\\tAccepted edits will not take effect in the font until you leave or close the bit editor. \\n\\tAlso note that unaccepted edits will be lost when you leave or close.\\\"\\n\\t\\\"Note that BitEditor only works in MVC currently.\\\"\\n\\n\\t\\\"(TextStyle default fontAt: 1) edit: $_\\\"\\n\\n\\t| charForm editRect scaleFactor bitEditor savedForm r |\\n\\tcharForm _ self characterFormAt: character.\\n\\teditRect _ BitEditor locateMagnifiedView: charForm scale: (scaleFactor _ 8 @ 8).\\n\\tbitEditor _ BitEditor\\n\\t\\t\\t\\tbitEdit: charForm\\n\\t\\t\\t\\tat: editRect topLeft\\n\\t\\t\\t\\tscale: scaleFactor\\n\\t\\t\\t\\tremoteView: nil.\\n\\tsavedForm _ Form fromDisplay: (r _ bitEditor displayBox\\n\\t\\t\\t\\t\\t\\t\\texpandBy: (0 @ 23 corner: 0 @ 0)).\\n\\tbitEditor controller startUp.\\n\\tbitEditor release.\\n\\tsavedForm displayOn: Display at: r topLeft.\\n\\tself characterFormAt: character put: charForm! !\\n\\n!StrikeFont methodsFor: 'character shapes' stamp: 'BG 12/6/2004 19:22'!\\nensureCleanBold\\n\\t\\\"This ensures that all character glyphs have at least one pixel of white space on the right\\n\\tso as not to cause artifacts in neighboring characters in bold or italic.\\\"\\n\\n\\t| newGlyphs newXTable newGlyphPos startPos newWidth widthOfGlyph increment lastCol |\\n\\temphasis = 0 ifFalse: [^ self].\\n newWidth := glyphs width + maxAscii - minAscii + 1.\\n lastCol := Form extent: 1@ glyphs height.\\n newGlyphs := Form extent: newWidth @ glyphs height.\\n newXTable := Array new: xTable size.\\n 1 to: minAscii do: [:idx | newXTable at: idx put: (xTable at: idx)].\\n \\n newGlyphPos := startPos := 0.\\n minAscii to: maxAscii do:\\n [:idx | \\n newXTable at: idx + 1 put: newGlyphPos.\\n widthOfGlyph := (xTable at: idx + 2 ) - (xTable at: idx + 1).\\n widthOfGlyph > 0\\n ifTrue:\\n [newGlyphs copy: (newGlyphPos @ 0 extent: widthOfGlyph @ glyphs height)\\n from: startPos@0 in: glyphs rule: Form over.\\n lastCol copy: (0 @ 0 extent: 1 @ glyphs height)\\n from: startPos + widthOfGlyph - 1 @0 in: glyphs rule: Form over.\\n increment := lastCol isAllWhite ifTrue: [0] ifFalse: [1].\\n startPos := startPos + widthOfGlyph.\\n newGlyphPos := newGlyphPos + widthOfGlyph + increment.\\n ].\\n ].\\n maxAscii + 2 to: newXTable size do: [:idx | newXTable at: idx put: newGlyphPos.].\\n glyphs := Form extent: newGlyphPos @ glyphs height.\\n glyphs copy: (0 @ 0 extent: glyphs extent)\\n from: 0@0 in: newGlyphs rule: Form over.\\n xTable := newXTable.\\n\\\"\\nStrikeFont allInstancesDo: [:f | f ensureCleanBold].\\n(StrikeFont familyName: 'NewYork' size: 21) ensureCleanBold.\\nStrikeFont shutDown. 'Flush synthetic fonts'.\\n\\\"\\n! !\\n\\n!StrikeFont methodsFor: 'character shapes' stamp: 'ar 5/23/2000 12:48'!\\nextendMaxAsciiTo: newMax\\n\\t\\\"Extend the range of this font so that it can display glyphs up to newMax.\\\"\\n\\n\\t(newMax+3) <= xTable size ifTrue: [^ self]. \\\"No need to extend.\\\"\\n\\txTable size = (maxAscii+3) ifFalse:\\n\\t\\t[^ self error: 'This font is not well-formed.'].\\n\\n\\t\\\"Insert a bunch of zero-width characters...\\\"\\n\\txTable _ (xTable copyFrom: 1 to: maxAscii+2) ,\\n\\t\\t\\t((maxAscii+1 to: newMax) collect: [:i | xTable at: maxAscii+2]) ,\\n\\t\\t\\t{ xTable at: maxAscii+3 }.\\n\\tmaxAscii _ newMax.\\n\\tself fillZeroWidthSlots.\\n\\tcharacterToGlyphMap _ nil.! !\\n\\n!StrikeFont methodsFor: 'character shapes' stamp: 'di 3/27/2000 16:10'!\\nfillZeroWidthSlots\\n\\t| nullGlyph |\\n\\t\\\"Note: this is slow because it copies the font once for every replacement.\\\"\\n\\n\\tnullGlyph _ (Form extent: 1@glyphs height) fillGray.\\n\\t\\\"Now fill the empty slots with narrow box characters.\\\"\\n\\tminAscii to: maxAscii do:\\n\\t\\t[:i | (self widthOf: (Character value: i)) = 0 ifTrue:\\n\\t\\t\\t[self characterFormAt: (Character value: i) put: nullGlyph]].\\n! !\\n\\n!StrikeFont methodsFor: 'character shapes' stamp: 'di 4/28/2000 16:10'!\\nfixOneWideChars \\n\\t\\\"This fixes all 1-wide characters to be 2 wide with blank on the right\\n\\tso as not to cause artifacts in neighboring characters in bold or italic.\\\"\\n\\t| twoWide |\\n\\tminAscii to: maxAscii do:\\n\\t\\t[:i | (self widthOf: (Character value: i)) = 1 ifTrue:\\n\\t\\t\\t[twoWide _ Form extent: 2@glyphs height.\\n\\t\\t\\t(self characterFormAt: (Character value: i)) displayOn: twoWide at: 0@0.\\n\\t\\t\\tself characterFormAt: (Character value: i) put: twoWide]].\\n\\\"\\nStrikeFont allInstancesDo: [:f | f fixOneWideChars].\\nStrikeFont shutDown. 'Flush synthetic fonts'.\\n\\\"\\n! !\\n\\n!StrikeFont methodsFor: 'character shapes' stamp: 'RAA 7/6/2000 16:50'!\\nmakeCarriageReturnsWhite\\n\\t| crForm |\\n\\t\\\"Some larger fonts have a gray carriage return (from the zero wide fixup) make it white so it doesn't show\\\"\\n\\n\\tcrForm _ self characterFormAt: 13 asCharacter.\\n\\tcrForm fillWhite.\\n\\tself characterFormAt: 13 asCharacter put: crForm.\\n! !\\n\\n!StrikeFont methodsFor: 'character shapes'!\\nwiden: char by: delta\\n\\t| newForm |\\n\\t^ self alter: char formBlock: \\\"Make a new form, wider or narrower...\\\"\\n\\t\\t[:charForm | newForm _ Form extent: charForm extent + (delta@0).\\n\\t\\tcharForm displayOn: newForm. \\\"Copy this image into it\\\"\\n\\t\\tnewForm] \\\"and substitute it in the font\\\"! !\\n\\n\\n!StrikeFont methodsFor: 'copying' stamp: 'BG 12/9/2004 17:27'!\\ndeepCopy\\n \\\" there is a circular reference from the derivative fonts back to the receiver. It is therefore not possible to make a deep copy. We make a sahllow copy. The method postCopy can be used to modify the shallow copy. \\\" \\n ^self copy! !\\n\\n!StrikeFont methodsFor: 'copying' stamp: 'BG 12/9/2004 17:35'!\\npostCopy\\n \\\" the receiver is a just created shallow copy. This method gives it the final touch. \\\" \\n \\n glyphs := glyphs copy.\\n xTable := xTable copy.\\n characterToGlyphMap := characterToGlyphMap copy.\\n \\n self reset. \\\" takes care of the derivative fonts \\\"! !\\n\\n!StrikeFont methodsFor: 'copying' stamp: 'tk 8/19/1998 16:15'!\\nveryDeepCopyWith: deepCopier\\n\\t\\\"Return self. I am shared. Do not record me.\\\"! !\\n\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'yo 5/19/2004 11:34'!\\ncharacters: anInterval in: sourceString displayAt: aPoint clippedBy: clippingRectangle rule: ruleInteger fillColor: aForm kernDelta: kernDelta on: aBitBlt\\n\\t\\\"Simple, slow, primitive method for displaying a line of characters.\\n\\tNo wrap-around is provided.\\\"\\n\\t| ascii destPoint leftX rightX sourceRect |\\n\\tdestPoint _ aPoint.\\n\\tanInterval do: \\n\\t\\t[:i |\\n\\t\\tself flag: #yoDisplay.\\n\\t\\t\\\"if the char is not supported, fall back to the specified fontset.\\\"\\n\\t\\tascii _ (sourceString at: i) charCode.\\n\\t\\t(ascii < minAscii or: [ascii > maxAscii])\\n\\t\\t\\tifTrue: [ascii _ maxAscii].\\n\\t\\tleftX _ xTable at: ascii + 1.\\n\\t\\trightX _ xTable at: ascii + 2.\\n\\t\\tsourceRect _ leftX@0 extent: (rightX-leftX) @ self height.\\n\\t\\taBitBlt copyFrom: sourceRect in: glyphs to: destPoint.\\n\\t\\tdestPoint _ destPoint + ((rightX-leftX+kernDelta)@0).\\n\\t\\t\\\"destPoint printString displayAt: 0@(i*20)\\\"].\\n\\t^ destPoint! !\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'yo 5/19/2004 11:36'!\\ndisplayLine: aString at: aPoint \\n\\t\\\"Display the characters in aString, starting at position aPoint.\\\"\\n\\n\\tself characters: (1 to: aString size)\\n\\t\\tin: aString\\n\\t\\tdisplayAt: aPoint\\n\\t\\tclippedBy: Display boundingBox\\n\\t\\trule: Form over\\n\\t\\tfillColor: nil\\n\\t\\tkernDelta: 0\\n\\t\\ton: (BitBlt current toForm: Display).\\n! !\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'yo 1/7/2005 15:16'!\\ndisplayMultiString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY\\n\\n\\t| destPoint leftX rightX glyphInfo char displayInfo destY |\\n\\tdestPoint _ aPoint.\\n\\tcharIndex _ startIndex.\\n\\tglyphInfo _ Array new: 5.\\n\\t[charIndex <= stopIndex] whileTrue: [\\n\\t\\tchar _ aString at: charIndex.\\n\\t\\t(self hasGlyphOf: char) not ifTrue: [\\n\\t\\t\\t\\tdisplayInfo _ self fallbackFont displayString: aString on: aBitBlt from: charIndex to: stopIndex at: destPoint kern: kernDelta from: self baselineY: baselineY.\\n\\t\\t\\t\\tcharIndex _ displayInfo first.\\n\\t\\t\\t\\tdestPoint _ displayInfo second.\\n\\t\\t] ifFalse: [\\n\\t\\t\\tself glyphInfoOf: char into: glyphInfo.\\n\\t\\t\\tleftX _ glyphInfo second.\\n\\t\\t\\trightX _ glyphInfo third.\\n\\t\\t\\t(glyphInfo fifth ~= aBitBlt lastFont) ifTrue: [\\n\\t\\t\\t\\tglyphInfo fifth installOn: aBitBlt.\\n\\t\\t\\t].\\n\\t\\t\\taBitBlt sourceForm: glyphInfo first.\\n\\t\\t\\tdestY _ baselineY - glyphInfo fourth. \\n\\t\\t\\taBitBlt destX: destPoint x.\\n\\t\\t\\taBitBlt destY: destY.\\n\\t\\t\\taBitBlt sourceOrigin: leftX @ 0.\\n\\t\\t\\taBitBlt width: rightX - leftX.\\n\\t\\t\\taBitBlt height: self height.\\n\\t\\t\\taBitBlt copyBits.\\n\\t\\t\\tdestPoint _ destPoint + (rightX - leftX + kernDelta @ 0).\\n\\t\\t\\tcharIndex _ charIndex + 1.\\n\\t\\t].\\n\\t].\\n\\t^ Array with: charIndex with: destPoint.\\n! !\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'yo 12/20/2002 18:54'!\\ndisplayStringR2L: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta\\n\\t\\\"You are screwed if you reach this method.\\\"\\n\\tself halt.\\n\\taBitBlt displayString: aString \\n\\t\\t\\tfrom: startIndex \\n\\t\\t\\tto: stopIndex \\n\\t\\t\\tat: aPoint \\n\\t\\t\\tstrikeFont: self\\n\\t\\t\\tkern: kernDelta.! !\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'ar 4/10/2005 18:06'!\\ndisplayString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta\\n\\t\\\"Draw the given string from startIndex to stopIndex \\n\\tat aPoint on the (already prepared) BitBlt.\\\"\\n\\t\\n\\t(aString isByteString) ifFalse: [^ self displayMultiString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: aPoint y + self ascent.].\\n\\n\\t^ aBitBlt displayString: aString \\n\\t\\t\\tfrom: startIndex \\n\\t\\t\\tto: stopIndex \\n\\t\\t\\tat: aPoint \\n\\t\\t\\tstrikeFont: self\\n\\t\\t\\tkern: kernDelta.! !\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'ar 4/10/2005 18:06'!\\ndisplayString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY\\n\\t\\\"Draw the given string from startIndex to stopIndex \\n\\tat aPoint on the (already prepared) BitBlt.\\\"\\n\\t\\n\\t(aString isByteString) ifFalse:[^ self displayMultiString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY.].\\n\\n\\t^ aBitBlt displayString: aString \\n\\t\\t\\tfrom: startIndex \\n\\t\\t\\tto: stopIndex \\n\\t\\t\\tat: aPoint \\n\\t\\t\\tstrikeFont: self\\n\\t\\t\\tkern: kernDelta.! !\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'BG 3/16/2005 08:27'!\\nfontDisplay\\n\\t\\\"TextStyle default defaultFont fontDisplay.\\\"\\n\\n\\tDisplay restoreAfter:\\n\\t\\t[(Form extent: 440@400) displayAt: 90@90.\\n\\t\\t 0 to: 15 do:\\n\\t\\t\\t[:i |\\n\\t\\t\\ti storeStringHex displayAt: 100 @ (20 * i + 100).\\n\\t\\t\\t0 to: 15 do:\\n\\t\\t\\t\\t[:j |\\n\\t\\t\\t\\t((16*i+j) between: 1 and: (self xTable size - 2)) ifTrue:\\n\\t\\t\\t\\t\\t[(self characterFormAt: (16 * i + j) asCharacter)\\n\\t\\t\\t\\t\\t\\tdisplayAt: (20 * j + 150) @ (20 * i + 100)]]].\\n\\t\\t\\t'Click to continue...' asDisplayText displayAt: 100@450]! !\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'yo 1/5/2005 13:59'!\\ninstallOn: aDisplayContext\\n\\n\\t^aDisplayContext installStrikeFont: self.\\n! !\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'ar 5/19/2000 15:08'!\\ninstallOn: aDisplayContext foregroundColor: foregroundColor backgroundColor: backgroundColor\\n\\t^aDisplayContext \\n\\t\\tinstallStrikeFont: self\\n\\t\\tforegroundColor: foregroundColor \\n\\t\\tbackgroundColor: backgroundColor! !\\n\\n!StrikeFont methodsFor: 'displaying' stamp: 'tak 1/11/2005 18:03'!\\nwidthOfString: aString from: firstIndex to: lastIndex\\n\\t| resultX |\\n\\tresultX _ 0.\\n\\tfirstIndex to: lastIndex do:[:i | \\n\\t\\tresultX _ resultX + (self widthOf: (aString at: i))].\\n\\t^ resultX.\\n! !\\n\\n\\n!StrikeFont methodsFor: 'emphasis' stamp: 'yo 12/18/2003 23:30'!\\nbonk: glyphForm with: bonkForm\\n\\t\\\"Bonking means to run through the glyphs clearing out black pixels\\n\\tbetween characters to prevent them from straying into an adjacent\\n\\tcharacter as a result of, eg, bolding or italicizing\\\"\\n\\t\\\"Uses the bonkForm to erase at every character boundary in glyphs.\\\"\\n\\t| bb offset x |\\n\\toffset _ bonkForm offset x.\\n\\tbb _ BitBlt current toForm: glyphForm.\\n\\tbb sourceForm: bonkForm; sourceRect: bonkForm boundingBox;\\n\\t\\tcombinationRule: Form erase; destY: 0.\\n\\tx _ self xTable.\\n\\t(x isMemberOf: SparseLargeTable) ifTrue: [\\n\\t\\tx base to: x size-1 do: [:i | bb destX: (x at: i) + offset; copyBits].\\n\\t] ifFalse: [\\n\\t\\t1 to: x size-1 do: [:i | bb destX: (x at: i) + offset; copyBits].\\n\\t].\\n! !\\n\\n!StrikeFont methodsFor: 'emphasis'!\\nemphasis\\n\\t\\\"Answer the integer code for synthetic bold, italic, underline, and \\n\\tstrike-out.\\\"\\n\\n\\t^emphasis! !\\n\\n!StrikeFont methodsFor: 'emphasis'!\\nemphasis: code \\n\\t\\\"Set the integer code for synthetic bold, itallic, underline, and strike-out, \\n\\twhere bold=1, italic=2, underlined=4, and struck out=8.\\\"\\n\\n\\temphasis _ code! !\\n\\n!StrikeFont methodsFor: 'emphasis' stamp: 'di 9/3/2000 13:22'!\\nemphasized: code \\n\\t\\\"Answer a copy of the receiver with emphasis set to include code.\\\"\\n\\t| derivative addedEmphasis base safeCode |\\n\\tcode = 0 ifTrue: [^ self].\\n\\t(derivativeFonts == nil or: [derivativeFonts size = 0]) ifTrue: [^ self].\\n\\tderivative _ derivativeFonts at: (safeCode _ code min: derivativeFonts size).\\n\\tderivative == nil ifFalse: [^ derivative]. \\\"Already have this style\\\"\\n\\n\\t\\\"Dont have it -- derive from another with one with less emphasis\\\"\\n\\taddedEmphasis _ 1 bitShift: safeCode highBit - 1.\\n\\tbase _ self emphasized: safeCode - addedEmphasis. \\\"Order is Bold, Ital, Under, Narrow\\\"\\n\\taddedEmphasis = 1 ifTrue: \\\"Compute synthetic bold version of the font\\\"\\n\\t\\t[derivative _ (base copy ensureCleanBold name: base name , 'B') makeBoldGlyphs].\\n\\taddedEmphasis = 2 ifTrue: \\\"Compute synthetic italic version of the font\\\"\\n\\t\\t[ derivative _ (base copy name: base name , 'I') makeItalicGlyphs].\\n\\taddedEmphasis = 4 ifTrue: \\\"Compute underlined version of the font\\\"\\n\\t\\t[derivative _ (base copy name: base name , 'U') makeUnderlinedGlyphs].\\n\\taddedEmphasis = 8 ifTrue: \\\"Compute narrow version of the font\\\"\\n\\t\\t[derivative _ (base copy name: base name , 'N') makeCondensedGlyphs].\\n\\taddedEmphasis = 16 ifTrue: \\\"Compute struck-out version of the font\\\"\\n\\t\\t[derivative _ (base copy name: base name , 'X') makeStruckOutGlyphs].\\n\\tderivative emphasis: safeCode.\\n\\tderivativeFonts at: safeCode put: derivative.\\n\\t^ derivative! !\\n\\n!StrikeFont methodsFor: 'emphasis' stamp: 'yo 5/24/2004 17:54'!\\nmakeBoldGlyphs\\n\\t\\\"Make a bold set of glyphs with same widths by ORing 1 bit to the right\\n\\t\\t(requires at least 1 pixel of intercharacter space)\\\"\\n\\t| g bonkForm |\\n\\tg _ glyphs deepCopy.\\n\\tbonkForm _ (Form extent: 1@16) fillBlack offset: -1@0.\\n\\tself bonk: g with: bonkForm.\\n\\tg copyBits: g boundingBox from: g at: (1@0)\\n\\t\\tclippingBox: g boundingBox rule: Form under fillColor: nil.\\n\\tglyphs _ g.\\n\\tfallbackFont ifNotNil: [\\n\\t\\tfallbackFont _ fallbackFont emphasized: 1\\n\\t].\\n! !\\n\\n!StrikeFont methodsFor: 'emphasis' stamp: 'yo 5/24/2004 17:51'!\\nmakeCondensedGlyphs\\n\\t\\\"Make a condensed set of glyphs with same widths.\\n\\tNOTE: this has been superceded by kerning -- should not get called\\\"\\n\\t| g newXTable x x1 w |\\n\\tg _ glyphs deepCopy.\\n\\tnewXTable _ Array new: xTable size.\\n\\tnewXTable at: 1 put: (x _ xTable at: 1).\\n\\t1 to: xTable size-1 do:\\n\\t\\t[:i | x1 _ xTable at: i. w _ (xTable at: i+1) - x1.\\n\\t\\tw > 1 ifTrue: [w _ w-1]. \\\"Shrink every character wider than 1\\\"\\n\\t\\tg copy: (x@0 extent: w@g height) from: x1@0 in: glyphs rule: Form over.\\n\\t\\tnewXTable at: i+1 put: (x _ x + w)].\\n\\txTable _ newXTable.\\n\\tglyphs _ g.\\n\\tfallbackFont ifNotNil: [\\n\\t\\tfallbackFont emphasized: 8\\n\\t].\\n\\n\\\"\\n(TextStyle default fontAt: 1) copy makeCondensedGlyphs\\n\\tdisplayLine: 'The quick brown fox jumps over the lazy dog'\\n\\tat: Sensor cursorPoint\\n\\\"! !\\n\\n!StrikeFont methodsFor: 'emphasis' stamp: 'yo 5/24/2004 17:54'!\\nmakeItalicGlyphs\\n\\t\\\"Make an italic set of glyphs with same widths by skewing left and right.\\n\\tIn the process, characters would overlap, so we widen them all first.\\n\\t\\\"\\n\\t| extraWidth newGlyphs newXTable x newX w extraOnLeft | \\n\\textraOnLeft _ (self height-1-self ascent+4)//4 max: 0.\\n\\textraWidth _ ((self ascent-5+4)//4 max: 0) + extraOnLeft.\\n\\tnewGlyphs _ Form extent: (glyphs width + (maxAscii + 1 - minAscii*extraWidth)) @ glyphs height.\\n\\tnewXTable _ xTable copy.\\n\\n\\t\\\"Copy glyphs into newGlyphs with room on left and right for overlap.\\\"\\n\\tminAscii to: maxAscii+1 do:\\n\\t\\t[:ascii | x _ xTable at: ascii+1. w _ (xTable at: ascii+2) - x.\\n\\t\\tnewX _ newXTable at: ascii+1.\\n\\t\\tnewGlyphs copy: ((newX + extraOnLeft) @ 0 extent: w @ glyphs height)\\n\\t\\t\\tfrom: x @ 0 in: glyphs rule: Form over.\\n\\t\\tnewXTable at: ascii+2 put: newX + w + extraWidth].\\t\\t\\n\\tglyphs _ newGlyphs. \\n\\txTable _ newXTable.\\n\\t\\\"Slide the bitmaps left and right for synthetic italic effect.\\\"\\n\\t4 to: self ascent-1 by: 4 do:\\n\\t\\t[:y | \\t\\t\\\"Slide ascenders right...\\\"\\n\\t\\tglyphs copy: (1@0 extent: glyphs width @ (self ascent - y))\\n\\t\\t\\tfrom: 0@0 in: glyphs rule: Form over].\\n\\tself ascent to: self height-1 by: 4 do:\\n\\t\\t[:y | \\t\\t\\\"Slide descenders left...\\\"\\n\\t\\tglyphs copy: (0@y extent: glyphs width @ glyphs height)\\n\\t\\t\\tfrom: 1@y in: glyphs rule: Form over].\\n\\tfallbackFont ifNotNil: [\\n\\t\\tfallbackFont _ fallbackFont emphasized: 2\\n\\t].\\n\\n! !\\n\\n!StrikeFont methodsFor: 'emphasis' stamp: 'yo 5/24/2004 17:54'!\\nmakeStruckOutGlyphs\\n\\t\\\"Make a struck-out set of glyphs with same widths\\\"\\n\\t| g |\\n\\tg _ glyphs deepCopy.\\n\\tg fillBlack: (0 @ (self ascent - (self ascent//3)) extent: g width @ 1).\\n\\tglyphs _ g.\\n\\tfallbackFont ifNotNil: [\\n\\t\\tfallbackFont _ fallbackFont emphasized: 16\\n\\t].\\n! !\\n\\n!StrikeFont methodsFor: 'emphasis' stamp: 'yo 5/24/2004 17:54'!\\nmakeUnderlinedGlyphs\\n\\t\\\"Make an underlined set of glyphs with same widths\\\"\\n\\t| g |\\n\\tg _ glyphs deepCopy.\\n\\tg fillBlack: (0 @ (self ascent+1) extent: g width @ 1).\\n\\tglyphs _ g.\\n\\tfallbackFont ifNotNil: [\\n\\t\\tfallbackFont _ fallbackFont emphasized: 4\\n\\t].\\n! !\\n\\n!StrikeFont methodsFor: 'emphasis' stamp: 'nk 3/15/2004 18:46'!\\nreleaseCachedState\\n\\n\\tself reset.! !\\n\\n!StrikeFont methodsFor: 'emphasis' stamp: 'tak 3/11/2005 17:09'!\\nreset\\n\\t\\\"Reset the cache of derivative emphasized fonts\\\"\\n\\n\\t| style font |\\n\\tfallbackFont class = FixedFaceFont\\n\\t\\tifTrue: [fallbackFont _ nil].\\n\\tderivativeFonts _ Array new: 32.\\n\\t#('B' 'I' 'BI') doWithIndex:\\n\\t\\t[:tag :index | \\n\\t\\t(style _ TextStyle named: self familyName) ifNotNil:\\n\\t\\t\\t[(font _ style fontArray\\n\\t\\t\\t\\tdetect: [:each | each name = (self name , tag)]\\n\\t\\t\\t\\tifNone: [nil]) ifNotNil: [derivativeFonts at: index put: font]]]! !\\n\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'ar 5/23/2000 12:50'!\\nbuildfontNamed: nm fromForms: forms startingAtAscii: startAscii\\n\\tascent: a descent: d maxWid: m\\n\\t\\\"This builds a StrikeFont instance from existing forms.\\\"\\n\\n\\t| lastAscii width ascii charForm missingForm tempGlyphs |\\n\\tname _ nm.\\n\\tascent _ 11.\\n\\tdescent _ 3.\\n\\tmaxWidth _ 16.\\n\\tpointSize _ 8.\\n\\tname _ (name copyWithout: Character space) ,\\n\\t\\t\\t\\t(pointSize < 10\\n\\t\\t\\t\\t\\tifTrue: ['0' , pointSize printString]\\n\\t\\t\\t\\t\\tifFalse: [pointSize printString]).\\n\\tminAscii _ 258.\\n\\tmaxAscii _ 0.\\n\\tsuperscript _ ascent - descent // 3.\\t\\n\\tsubscript _ descent - ascent // 3.\\t\\n\\temphasis _ 0.\\n\\ttype _ 0. \\\"ignored for now\\\"\\n\\n\\ttempGlyphs _ Form extent: (maxWidth*257) @ self height.\\n\\txTable _ (Array new: 258) atAllPut: 0.\\n\\txTable at: 1 put: 0.\\n\\n\\t\\\"Read character forms and blt into tempGlyphs\\\"\\n\\tlastAscii _ -1.\\n\\t1 to: forms size do:\\n\\t\\t[:i | charForm _ forms at: i. width _ charForm width.\\n\\t\\tascii _ startAscii-1+i.\\n\\t\\tself displayChar: ascii form: charForm.\\n\\t\\tascii = 256\\n\\t\\t\\tifTrue: [missingForm _ charForm deepCopy]\\n\\t\\t\\tifFalse:\\n\\t\\t\\t[minAscii _ minAscii min: ascii.\\n\\t\\t\\tmaxAscii _ maxAscii max: ascii.\\n\\t\\t\\tlastAscii+1 to: ascii-1 do: [:as | xTable at: as+2 put: (xTable at: as+1)].\\n\\t\\t\\ttempGlyphs copy: ((xTable at: ascii+1)@0\\n\\t\\t\\t\\t\\t\\t\\t\\t\\textent: charForm extent)\\n\\t\\t\\t\\t\\t\\tfrom: 0@0 in: charForm rule: Form over.\\n\\t\\t\\txTable at: ascii+2 put: (xTable at: ascii+1) + width.\\n\\t\\t\\tlastAscii _ ascii]].\\n\\tlastAscii+1 to: maxAscii+1 do: [:as | xTable at: as+2 put: (xTable at: as+1)].\\n\\tmissingForm == nil ifFalse:\\n\\t\\t[tempGlyphs copy: missingForm boundingBox from: missingForm\\n\\t\\t\\t\\tto: (xTable at: maxAscii+2)@0 rule: Form over.\\n\\t\\txTable at: maxAscii+3 put: (xTable at: maxAscii+2) + missingForm width].\\n\\tglyphs _ Form extent: (xTable at: maxAscii+3) @ self height.\\n\\tglyphs copy: glyphs boundingBox from: 0@0 in: tempGlyphs rule: Form over.\\n\\txTable _ xTable copyFrom: 1 to: maxAscii+3.\\n\\tcharacterToGlyphMap _ nil.! !\\n\\n!StrikeFont methodsFor: 'file in/out'!\\ndisplayChar: ascii form: charForm\\n\\t\\\"Convenience utility used during conversion of BitFont files\\\"\\n\\t| m bigForm |\\n\\tDisplay fillBlack: (0@0 extent: 20@14).\\n\\tascii printString displayAt: 0@2.\\n\\tcharForm width > 0 ifTrue:\\n\\t\\t[m _ 5.\\n\\t\\tbigForm _ charForm magnify: charForm boundingBox by: m@m.\\n\\t\\tDisplay border: ((bigForm boundingBox expandBy: m) translateBy: 50@2) width: m.\\n\\t\\tbigForm displayAt: 50@2.\\n\\t\\tDisplay fillBlack: ((50@2)+((m*charForm width)@0) extent: 1@(m*self height))].! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'md 11/14/2003 17:25'!\\nnewFromStrike: fileName\\n\\t\\\"Build an instance from the strike font file name. The '.strike' extension\\n\\tis optional.\\\"\\n\\n\\t| strike startName raster16 |\\n\\tname _ fileName copyUpTo: $..\\t\\\"assumes extension (if any) is '.strike'\\\"\\n\\tstrike _ FileStream readOnlyFileNamed: name, '.strike.'.\\n\\tstrike binary.\\n\\n\\t\\\"strip off direcory name if any\\\"\\n\\tstartName _ name size.\\n\\t[startName > 0 and: [((name at: startName) ~= $>) & ((name at: startName) ~= $])]]\\n\\t\\twhileTrue: [startName _ startName - 1].\\n\\tname _ name copyFrom: startName+1 to: name size.\\n\\n\\ttype\\t\\t\\t_\\t\\tstrike nextWord.\\t\\t\\\"type is ignored now -- simplest\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tassumed. Kept here to make\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\twriting and consistency more\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tstraightforward.\\\"\\n\\tminAscii\\t\\t_\\t\\tstrike nextWord.\\n\\tmaxAscii\\t\\t_\\t\\tstrike nextWord.\\n\\tmaxWidth\\t\\t_\\t\\tstrike nextWord.\\n\\tstrikeLength\\t_\\t\\tstrike nextWord.\\n\\tascent\\t\\t\\t_\\t\\tstrike nextWord.\\n\\tdescent\\t\\t\\t_\\t\\tstrike nextWord.\\n\\t\\\"xOffset\\t\\t\\t_\\\"\\t\\tstrike nextWord. \\t\\n\\traster16\\t\\t\\t_\\t\\tstrike nextWord.\\t\\n\\tsuperscript\\t\\t_\\t\\tascent - descent // 3.\\t\\n\\tsubscript\\t\\t_\\t\\tdescent - ascent // 3.\\t\\n\\temphasis\\t\\t_\\t\\t0.\\n\\tglyphs\\t\\t\\t_\\tForm extent: (raster16 * 16) @ (self height) \\n\\t\\t\\t\\t\\t\\t\\toffset: 0@0.\\n\\t\\tglyphs bits fromByteStream: strike.\\n\\n\\txTable _ (Array new: maxAscii + 3) atAllPut: 0.\\n\\t(minAscii + 1 to: maxAscii + 3) do:\\n\\t\\t[:index | xTable at: index put: strike nextWord].\\n\\n\\t\\\"Set up space character\\\"\\n\\t((xTable at: (Space asciiValue + 2)) = 0 or:\\n\\t\\t\\t[(xTable at: (Space asciiValue + 2)) = (xTable at: (Space asciiValue + 1))])\\n\\t\\tifTrue:\\t[(Space asciiValue + 2) to: xTable size do:\\n\\t\\t\\t\\t\\t[:index | xTable at: index put: ((xTable at: index) + DefaultSpace)]].\\n\\tstrike close.\\n\\tcharacterToGlyphMap _ nil.! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'tk 9/28/2000 15:50'!\\nobjectForDataStream: refStrm\\n\\t| dp |\\n\\t\\\"I am about to be written on an object file. Write a reference to a known Font in the other system instead. \\\"\\n\\n\\t\\\"A path to me\\\"\\n\\t(TextConstants at: #forceFontWriting ifAbsent: [false]) ifTrue: [^ self].\\n\\t\\t\\\"special case for saving the default fonts on the disk. See collectionFromFileNamed:\\\"\\n\\n\\tdp _ DiskProxy global: #StrikeFont selector: #familyName:size:emphasized:\\n\\t\\t\\targs: (Array with: self familyName with: self height\\n\\t\\t\\t\\t\\twith: self emphasis).\\n\\trefStrm replace: self with: dp.\\n\\t^ dp! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'sma 6/1/2000 09:32'!\\nprintOn: aStream\\n\\tsuper printOn: aStream.\\n\\taStream\\n\\t\\tnextPut: $(;\\n\\t\\tnextPutAll: self name;\\n\\t\\tspace;\\n\\t\\tprint: self height;\\n\\t\\tnextPut: $)! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'ar 10/25/2005 00:21'!\\nreadBDFFromFile: fileName name: aString \\n\\t\\\"This builds a StrikeFont instance by reading the X11 Binary \\n\\tDistribution Format font source file. See the BDFFontReader class\\n\\tcomment.\\\"\\n\\n\\t\\\"StrikeFont new readBDFFromFile: 'helvR12' name: 'Helvetica12'.\\\"\\n\\n\\t| fontReader stream |\\n\\tfontReader := BDFFontReader openFileNamed: fileName.\\n\\tstream := ReadStream on: fontReader read.\\n\\txTable := stream next.\\n\\tglyphs := stream next.\\n\\tminAscii := stream next.\\n\\tmaxAscii := stream next.\\n\\tmaxWidth := stream next.\\n\\tascent := stream next.\\n\\tdescent := stream next.\\n\\tpointSize := stream next.\\n\\tname := aString.\\n\\\"\\txTable size <= 256 ifTrue: [self setStopConditions].\\\"\\n\\ttype := 0.\\t\\\"no one see this\\\"\\n\\tsuperscript := (ascent - descent) // 3.\\n\\tsubscript := (descent - ascent) // 3.\\n\\temphasis := 0.\\n\\tself reset! !\\n\\n!StrikeFont methodsFor: 'file in/out'!\\nreadBFHeaderFrom: f\\n\\tname _ self restOfLine: 'Font name = ' from: f.\\n\\tascent _ (self restOfLine: 'Ascent = ' from: f) asNumber.\\n\\tdescent _ (self restOfLine: 'Descent = ' from: f) asNumber.\\n\\tmaxWidth _ (self restOfLine: 'Maximum width = ' from: f) asNumber.\\n\\tpointSize _ (self restOfLine: 'Font size = ' from: f) asNumber.\\n\\tname _ (name copyWithout: Character space) ,\\n\\t\\t\\t\\t(pointSize < 10\\n\\t\\t\\t\\t\\tifTrue: ['0' , pointSize printString]\\n\\t\\t\\t\\t\\tifFalse: [pointSize printString]).\\n\\tminAscii _ 258.\\n\\tmaxAscii _ 0.\\n\\tsuperscript _ ascent - descent // 3.\\t\\n\\tsubscript _ descent - ascent // 3.\\t\\n\\temphasis _ 0.\\n\\ttype _ 0. \\\"ignored for now\\\"\\n! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'yo 11/30/2003 17:08'!\\nreadEFontBDFForJapaneseFromFile: fileName name: aString overrideWith: otherFileName\\n\\n\\t| fontReader stream |\\n\\tfontReader _ EFontBDFFontReaderForRanges readOnlyFileNamed: fileName.\\n\\tstream _ ReadStream on: (fontReader readRanges: fontReader rangesForJapanese overrideWith: otherFileName otherRanges: {Array with: 8481 with: 12320} additionalOverrideRange: fontReader additionalRangesForJapanese).\\n\\txTable _ stream next.\\n\\tglyphs _ stream next.\\n\\tminAscii _ stream next.\\n\\tmaxAscii _ stream next.\\n\\tmaxWidth _ stream next.\\n\\tascent _ stream next.\\n\\tdescent _ stream next.\\n\\tpointSize _ stream next.\\n\\tname _ aString.\\n\\ttype _ 0. \\\"no one see this\\\"\\n\\tsuperscript _ ascent - descent // 3.\\t\\n\\tsubscript _ descent - ascent // 3.\\t\\n\\temphasis _ 0.\\n\\tself reset.\\n! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'yo 1/15/2004 16:48'!\\nreadEFontBDFForKoreanFromFile: fileName name: aString overrideWith: otherFileName\\n\\n\\t| fontReader stream |\\n\\tfontReader _ EFontBDFFontReaderForRanges readOnlyFileNamed: fileName.\\n\\tstream _ ReadStream on: (fontReader readRanges: fontReader rangesForKorean overrideWith: otherFileName otherRanges: {Array with: 8481 with: 12320} additionalOverrideRange: fontReader additionalRangesForKorean).\\n\\txTable _ stream next.\\n\\tglyphs _ stream next.\\n\\tminAscii _ stream next.\\n\\tmaxAscii _ stream next.\\n\\tmaxWidth _ stream next.\\n\\tascent _ stream next.\\n\\tdescent _ stream next.\\n\\tpointSize _ stream next.\\n\\tname _ aString.\\n\\ttype _ 0. \\\"no one see this\\\"\\n\\tsuperscript _ ascent - descent // 3.\\t\\n\\tsubscript _ descent - ascent // 3.\\t\\n\\temphasis _ 0.\\n\\tself reset.\\n! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'yo 12/28/2002 21:02'!\\nreadEFontBDFFromFile: fileName name: aString rangeFrom: startRange to: endRange\\n\\n\\t| fontReader stream |\\n\\tfontReader _ EFontBDFFontReader readOnlyFileNamed: fileName.\\n\\tstream _ ReadStream on: (fontReader readFrom: startRange to: endRange).\\n\\txTable _ stream next.\\n\\tglyphs _ stream next.\\n\\tminAscii _ stream next.\\n\\tmaxAscii _ stream next.\\n\\tmaxWidth _ stream next.\\n\\tascent _ stream next.\\n\\tdescent _ stream next.\\n\\tpointSize _ stream next.\\n\\tname _ aString.\\n\\ttype _ 0. \\\"no one see this\\\"\\n\\tsuperscript _ ascent - descent // 3.\\t\\n\\tsubscript _ descent - ascent // 3.\\t\\n\\temphasis _ 0.\\n\\tself reset.\\n! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'yo 1/19/2005 11:22'!\\nreadEFontBDFFromFile: fileName name: aString ranges: ranges\\n\\n\\t| fontReader stream |\\n\\tfontReader _ EFontBDFFontReaderForRanges readOnlyFileNamed: fileName.\\n\\tstream _ ReadStream on: (fontReader readRanges: ranges).\\n\\txTable _ stream next.\\n\\tglyphs _ stream next.\\n\\tminAscii _ stream next.\\n\\tmaxAscii _ stream next.\\n\\tmaxWidth _ stream next.\\n\\tascent _ stream next.\\n\\tdescent _ stream next.\\n\\tpointSize _ stream next.\\n\\tname _ aString.\\n\\ttype _ 0. \\\"no one see this\\\"\\n\\tsuperscript _ ascent - descent // 3.\\t\\n\\tsubscript _ descent - ascent // 3.\\t\\n\\temphasis _ 0.\\n\\tself reset.\\n! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'yo 9/23/2002 16:30'!\\nreadF12FromStream: aStream\\n\\n\\t| box blt |\\n\\tminAscii _ 0.\\n\\tmaxAscii _ 94*94.\\n\\tascent _ 12.\\n\\tdescent _ 0.\\n\\tpointSize _ 12.\\n\\tsuperscript _ 0.\\n\\tsubscript _ 0.\\n\\temphasis _ 0.\\n\\tmaxWidth _ 12.\\n\\t\\n\\tbox _ Form extent: 12@12.\\n\\tglyphs _ Form extent: (94*94*12)@12.\\n\\tblt _ BitBlt toForm: glyphs. \\n\\txTable _ XTableForFixedFont new.\\n\\txTable maxAscii: maxAscii + 3.\\n\\txTable width: 12.\\n\\t1 to: 256 do: [:index | \\n\\t\\t1 to: 12 do: [:i |\\n\\t\\t\\taStream next.\\n\\t\\t].\\n\\t].\\n\\t(minAscii + 1 to: 94*94) do: [:index | \\n\\t\\tself readCharacter: (box bits) from: aStream.\\n\\t\\tblt copy: ((12*(index-1))@0 extent: 12@12) from: 0@0 in: box.\\n\\t].\\n! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'ar 5/23/2000 12:50'!\\nreadFromBitFont: fileName\\n\\t\\\"This builds a StrikeFont instance by reading the data file format\\n\\tproduced by BitFont, a widely available font conversion utility\\n\\twritten by Peter DiCamillo at Brown University\\\"\\n\\t\\\"StrikeFont new readFromBitFont: 'Palatino10.BF' \\\"\\n\\t| f lastAscii charLine width ascii charForm line missingForm tempGlyphs iRect p rectLine left tokens right |\\n\\tf _ FileStream readOnlyFileNamed: fileName.\\n\\tself readBFHeaderFrom: f.\\n\\n\\t\\\"NOTE: if font has been scaled (and in any case),\\n\\tthe REAL bitmap dimensions come after the header.\\\"\\n\\tself restOfLine: 'Extent information for entire font' from: f.\\n\\t\\\"Parse the following line (including mispelling!!)\\\"\\n\\t\\\"Image rectange: left = -2, right = 8, bottom = -2, top = 7\\\"\\n\\ttokens _ (f upTo: Character cr) findTokens: ' '.\\n\\tiRect _ Rectangle left: (tokens at: 5) asNumber right: (tokens at: 8) asNumber\\n\\t\\t\\t\\ttop: (tokens at: 14) asNumber bottom: (tokens at: 11) asNumber.\\n\\tascent _ iRect top.\\n\\tdescent _ iRect bottom negated.\\n\\t\\n\\ttempGlyphs _ Form extent: (maxWidth*257) @ self height.\\n\\txTable _ (Array new: 258) atAllPut: 0.\\n\\txTable at: 1 put: 0.\\n\\n\\t\\\"Read character forms and blt into tempGlyphs\\\"\\n\\tlastAscii _ -1.\\n\\t[charLine _ self restOfLine: 'Character: ' from: f.\\n\\tcharLine == nil ifFalse:\\n\\t\\t[p _ f position.\\n\\t\\trectLine _ f upTo: Character cr.\\n\\t\\t(rectLine beginsWith: 'Image rectange: left = ')\\n\\t\\t\\tifTrue: [tokens _ rectLine findTokens: ' '.\\n\\t\\t\\t\\t\\tleft _ (tokens at: 5) asNumber. right _ (tokens at: 8) asNumber]\\n\\t\\t\\tifFalse: [left _ right _ 0. f position: p].\\n\\t\\twidth_ (self restOfLine: 'Width (final pen position) = ' from: f) asNumber - left\\n\\t\\t\\t\\t\\tmax: (right-left+1).\\n\\t\\t(charLine beginsWith: 'Missing character') ifTrue: [ascii _ 256].\\n\\t\\t('x''*' match: charLine) ifTrue:\\n\\t\\t\\t[ascii _ Number readFrom: (charLine copyFrom: 3 to: 4) asUppercase base: 16].\\n\\t\\tcharForm _ Form extent: width@self height.\\n\\t\\t('*[all blank]' match: charLine) ifFalse:\\n\\t\\t\\t[self restOfLine: ' +' from: f.\\n\\t\\t\\t1 to: self height do:\\n\\t\\t\\t\\t[:y | line _ f upTo: Character cr.\\n\\t\\t\\t\\t4 to: (width + 3 min: line size + iRect left - left) do:\\n\\t\\t\\t\\t\\t[:x | (line at: x - iRect left + left) = $*\\n\\t\\t\\t\\t\\t\\tifTrue: [charForm pixelValueAt: (x-4)@(y-1) put: 1]]]]].\\n\\tcharLine == nil]\\n\\t\\twhileFalse:\\n\\t\\t\\t[self displayChar: ascii form: charForm.\\n\\t\\t\\tascii = 256\\n\\t\\t\\t\\tifTrue: [missingForm _ charForm deepCopy]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t[minAscii _ minAscii min: ascii.\\n\\t\\t\\t\\tmaxAscii _ maxAscii max: ascii.\\n\\t\\t\\t\\tlastAscii+1 to: ascii-1 do: [:a | xTable at: a+2 put: (xTable at: a+1)].\\n\\t\\t\\t\\ttempGlyphs copy: ((xTable at: ascii+1)@0\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\textent: charForm extent)\\n\\t\\t\\t\\t\\t\\t\\tfrom: 0@0 in: charForm rule: Form over.\\n\\t\\t\\t\\txTable at: ascii+2 put: (xTable at: ascii+1) + width.\\n\\t\\t\\t\\tlastAscii _ ascii]].\\n\\tf close.\\n\\tlastAscii+1 to: maxAscii+1 do: [:a | xTable at: a+2 put: (xTable at: a+1)].\\n\\tmissingForm == nil ifFalse:\\n\\t\\t[tempGlyphs copy: missingForm boundingBox from: missingForm\\n\\t\\t\\t\\tto: (xTable at: maxAscii+2)@0 rule: Form over.\\n\\t\\txTable at: maxAscii+3 put: (xTable at: maxAscii+2) + missingForm width].\\n\\tglyphs _ Form extent: (xTable at: maxAscii+3) @ self height.\\n\\tglyphs copy: glyphs boundingBox from: 0@0 in: tempGlyphs rule: Form over.\\n\\txTable _ xTable copyFrom: 1 to: maxAscii+3.\\n\\tcharacterToGlyphMap _ nil.! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'ar 5/23/2000 12:53'!\\nreadFromStrike2Stream: file \\n\\t\\\"Build an instance from the supplied binary stream on data in strike2 format\\\"\\n\\ttype _ file nextInt32. type = 2 ifFalse: [file close. self error: 'not strike2 format'].\\n\\tminAscii _ file nextInt32.\\n\\tmaxAscii _ file nextInt32.\\n\\tmaxWidth _ file nextInt32.\\n\\tascent _ file nextInt32.\\n\\tdescent _ file nextInt32.\\n\\tpointSize _ file nextInt32.\\n\\tsuperscript _ ascent - descent // 3.\\t\\n\\tsubscript _ descent - ascent // 3.\\t\\n\\temphasis _ file nextInt32.\\n\\txTable _ (Array new: maxAscii + 3) atAllPut: 0.\\n\\t(minAscii + 1 to: maxAscii + 3) do:\\n\\t\\t[:index | xTable at: index put: file nextInt32].\\n\\tglyphs _ Form new readFrom: file.\\n\\n\\t\\\"Set up space character\\\"\\n\\t((xTable at: (Space asciiValue + 2)) = 0 or:\\n\\t\\t\\t[(xTable at: (Space asciiValue + 2)) = (xTable at: (Space asciiValue + 1))])\\n\\t\\tifTrue:\\t[(Space asciiValue + 2) to: xTable size do:\\n\\t\\t\\t\\t\\t[:index | xTable at: index put: ((xTable at: index) + DefaultSpace)]].\\n\\tcharacterToGlyphMap _ nil.! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'sma 12/30/1999 14:20'!\\nreadFromStrike2: fileName \\\"StrikeFont new readFromStrike2: 'Palatino14.sf2'\\\"\\n\\t\\\"Build an instance from the strike font stored in strike2 format.\\n\\tfileName is of the form: <family name><pointSize>.sf2\\\"\\n\\t| file |\\n\\t('*.sf2' match: fileName) ifFalse: [self halt. \\\"likely incompatible\\\"].\\n\\tname _ fileName copyUpTo: $. . \\\"Drop filename extension\\\"\\n\\tfile _ FileStream readOnlyFileNamed: fileName.\\n\\tfile binary.\\n\\t[self readFromStrike2Stream: file] ensure: [file close]! !\\n\\n!StrikeFont methodsFor: 'file in/out'!\\nrestOfLine: leadString from: file\\n\\t\\\"Utility method to assist reading of BitFont data files\\\"\\n\\t| line |\\n\\t[line _ file upTo: Character cr.\\n\\tline size < leadString size or: [leadString ~= (line copyFrom: 1 to: leadString size)]]\\n\\twhileTrue: [file atEnd ifTrue: [^ nil]].\\n\\t^ line copyFrom: leadString size+1 to: line size! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'ls 4/11/2000 18:57'!\\nwriteAsStrike2named: fileName\\n\\t\\\"Write me onto a file in strike2 format.\\n\\tfileName should be of the form: <family name><pointSize>.sf2\\\"\\n\\t| file |\\n\\tfile _ FileStream fileNamed: fileName.\\n\\tself writeAsStrike2On: file.\\n\\tfile close.! !\\n\\n!StrikeFont methodsFor: 'file in/out' stamp: 'ls 3/27/2000 17:43'!\\nwriteAsStrike2On: file\\n\\t\\\"Write me onto a file in strike2 format.\\n\\tfileName should be of the form: <family name><pointSize>.sf2\\\"\\n\\tfile binary.\\n\\tfile nextInt32Put: 2.\\n\\tfile nextInt32Put: minAscii.\\n\\tfile nextInt32Put: maxAscii.\\n\\tfile nextInt32Put: maxWidth.\\n\\tfile nextInt32Put: ascent.\\n\\tfile nextInt32Put: descent.\\n\\tfile nextInt32Put: pointSize.\\n\\tsuperscript _ ascent - descent // 3.\\t\\n\\tsubscript _ descent - ascent // 3.\\t\\n\\tfile nextInt32Put: emphasis.\\n\\t(minAscii + 1 to: maxAscii + 3) do:\\n\\t\\t[:index | file nextInt32Put: (xTable at: index)].\\n\\tglyphs writeOn: file.\\n\\tfile close.\\n! !\\n\\n\\n!StrikeFont methodsFor: 'Mac reader'!\\naComment\\n\\t\\\"To read Mac font resources. \\n1) Use ResEdit in the Fonts folder in the System Folder. Open the file of the Font you want. (A screen font, not a TrueType outline font).\\n2) Open the FOND resource and scroll down to the list of sizes and resource numbers. Note the resource number of the size you want.\\n3) Open the NFNT resource. Click on the number you have noted.\\n4) Choose 'Open Using Hex Editor' from the resource editor.\\n5) Copy all of the hex numbers and paste into a text editor. Save the file into the Smalltalk folder under the name 'FontName 12 hex' (or other size).\\n6) Enter the fileName below and execute: \\n\\nTextStyle default fontAt: 8 put: (StrikeFont new readMacFontHex: 'fileName').\\n\\nSelect text and type Command-7 to change it to your new font.\\n\\n(There is some problem in the ParagraphEditor with the large size of Cairo 18. Its line heights are not the right.)\\n\\t\\\"! !\\n\\n!StrikeFont methodsFor: 'Mac reader'!\\nfixKerning: extraWidth\\n\\t\\\"Insert one pixel (extraWidth) between each character. And add the bits for the space character\\\"\\n\\t\\\"Create a space character Form. Estimate width by ascent / 2 - 1\\\"\\n\\t| characterForm char leftX |\\n\\tcharacterForm _ Form extent: (ascent//2 - 1) @ self height.\\n\\tself characterFormAt: $ put: characterForm.\\n\\n\\t\\\"Put one pixel of space after every character. Mac fonts have no space in the bitmap.\\\"\\n\\textraWidth <= 0 ifTrue: [^ self].\\n\\tminAscii to: maxAscii do: [:ascii |\\n\\t\\tchar _ Character value: ascii.\\n\\t\\tleftX _ xTable at: ascii + 1.\\n\\t\\tcharacterForm _ Form extent: \\n\\t\\t\\t((self widthOf: char) + extraWidth) @ self height.\\n\\t\\tcharacterForm \\n\\t\\t\\tcopy: (characterForm boundingBox extendBy: \\n\\t\\t\\t\\t(0-extraWidth@0))\\n\\t\\t\\tfrom: leftX@0 in: glyphs rule: Form over.\\n\\t\\tself characterFormAt: char put: characterForm.\\n\\t\\t].\\t! !\\n\\n!StrikeFont methodsFor: 'Mac reader' stamp: 'ar 5/23/2000 12:49'!\\nreadMacFontHex: fileName\\n\\t\\\"Read the hex version of a Mac FONT type resource. See the method aComment for how to prepare the input file. 4/26/96 tk\\\"\\n\\t| file hh fRectWidth |\\n\\tname _ fileName.\\t\\\"Palatino 12\\\"\\n\\tfile _ FileStream readOnlyFileNamed: fileName, ' hex'.\\n\\n\\t\\\"See Inside Macintosh page IV-42 for this record\\\"\\n\\t\\\"FontType _ \\\" Number readFrom: (file next: 4) base: 16.\\n\\temphasis\\t\\t_\\t\\t0.\\n\\tminAscii _ Number readFrom: (file next: 4) base: 16.\\n\\tmaxAscii _ Number readFrom: (file next: 4) base: 16.\\n\\tmaxWidth\\t\\t_ Number readFrom: (file next: 4) base: 16.\\n\\t\\\"kernMax _ \\\" Number readFrom: (file next: 4) base: 16.\\n\\t\\\"NDescent _ \\\" Number readFrom: (file next: 4) base: 16.\\n\\tfRectWidth _ Number readFrom: (file next: 4) base: 16.\\n\\thh _ Number readFrom: (file next: 4) base: 16.\\n\\t\\\"OWTLoc _ \\\" Number readFrom: (file next: 4) base: 16.\\n\\tascent\\t\\t\\t_ Number readFrom: (file next: 4) base: 16.\\n\\tdescent\\t\\t\\t_ Number readFrom: (file next: 4) base: 16.\\n\\t\\\"leading _ \\\" Number readFrom: (file next: 4) base: 16.\\n\\txOffset\\t\\t\\t_\\t\\t0. \\t\\n\\traster\\t\\t\\t_ Number readFrom: (file next: 4) base: 16.\\n\\n\\tstrikeLength\\t_\\t\\traster*16.\\n\\tsuperscript\\t\\t_\\t\\tascent - descent // 3.\\t\\n\\tsubscript\\t\\t_\\t\\tdescent - ascent // 3.\\t\\n\\tself strikeFromHex: file width: raster height: hh.\\n\\tself xTableFromHex: file.\\n\\tfile close.\\n\\n\\t\\\"Insert one pixel between each character. And add space character.\\\"\\n\\tself fixKerning: (fRectWidth - maxWidth).\\t\\n\\n\\t\\\"Recompute character to glyph mapping\\\"\\n\\tcharacterToGlyphMap _ nil.! !\\n\\n!StrikeFont methodsFor: 'Mac reader'!\\nstrikeFromHex: file width: w height: h\\n\\t\\\"read in just the raw strike bits from a hex file. No spaces or returns. W is in words (2 bytes), h in pixels.\\\" \\n\\t| newForm theBits offsetX offsetY str num cnt |\\n\\toffsetX _ 0.\\n\\toffsetY _ 0.\\n\\toffsetX > 32767 ifTrue: [offsetX _ offsetX - 65536]. \\\"stored two's-complement\\\"\\n\\toffsetY > 32767 ifTrue: [offsetY _ offsetY - 65536]. \\\"stored two's-complement\\\"\\n\\tnewForm _ Form extent: strikeLength @ h offset: offsetX @ offsetY.\\n\\ttheBits _ newForm bits.\\n\\tcnt _ 0.\\t\\t\\\"raster may be 16 bits, but theBits width is 32\\\" \\n\\t1 to: theBits size do: [:i | \\n\\t\\t(cnt _ cnt + 32) > strikeLength \\n\\t\\t ifTrue: [cnt _ 0.\\n\\t\\t\\tnum _ Number readFrom: (str _ file next: 4) base: 16]\\n\\t\\t ifFalse: [\\n\\t\\t\\tcnt = strikeLength ifTrue: [cnt _ 0].\\n\\t\\t\\tnum _ Number readFrom: (str _ file next: 8) base: 16].\\n\\t\\ttheBits at: i put: num].\\n\\tglyphs _ newForm.! !\\n\\n!StrikeFont methodsFor: 'Mac reader'!\\nxTableFromHex: file\\n\\n\\t| strike num str wid |\\n\\tstrike _ file.\\n\\txTable _ (Array new: maxAscii + 3) atAllPut: 0.\\n\\t(minAscii + 1 to: maxAscii + 3) do:\\n\\t\\t[:index | \\n\\t\\t\\tnum _ Number readFrom: (str _ strike next: 4) base: 16. \\n\\t\\t\\txTable at: index put: num].\\n\\n\\t1 to: xTable size - 1 do: [:ind |\\n\\t\\twid _ (xTable at: ind+1) - (xTable at: ind).\\n\\t\\t(wid < 0) | (wid > 40) ifTrue: [\\n\\t\\t\\tfile close.\\n\\t\\t\\tself error: 'illegal character width']].\\n! !\\n\\n\\n!StrikeFont methodsFor: 'make arrows' stamp: 'sps 10/15/2003 17:06'!\\nmakeAssignArrow\\n\\\"Replace the underline character with an arrow for this font\\\"\\n\\n\\t| arrowForm arrowCanvas arrowY arrowLeft arrowRight arrowHeadLength |\\n\\n\\tarrowForm _ (self characterFormAt: $_) copy.\\n\\tarrowCanvas _ arrowForm getCanvas.\\n\\tarrowCanvas fillColor: Color white.\\n\\tarrowY _ arrowForm height // 2.\\n\\tarrowLeft _ 0. \\n\\tarrowRight _ arrowForm width - 2.\\n\\tarrowHeadLength _ (arrowRight - arrowLeft) * 2 // 5.\\n\\t\\\"Draw the lines\\\"\\n\\tarrowCanvas line: (arrowLeft@arrowY) to: (arrowRight@arrowY) color: Color black.\\n\\tarrowCanvas \\n\\t\\tline: (arrowLeft@arrowY) \\n\\t\\tto: ((arrowLeft + arrowHeadLength)@(arrowY - arrowHeadLength)) \\n\\t\\tcolor: Color black.\\n\\tarrowCanvas \\n\\t\\tline: (arrowLeft@arrowY) \\n\\t\\tto: ((arrowLeft + arrowHeadLength)@(arrowY + arrowHeadLength)) \\n\\t\\tcolor: Color black.\\n\\n\\t\\\"Replace the glyph\\\"\\n\\tself characterFormAt: $_ put: arrowForm.\\n\\n! !\\n\\n!StrikeFont methodsFor: 'make arrows' stamp: 'sps 10/15/2003 17:06'!\\nmakeReturnArrow\\n\\\"Replace the caret character with an arrow\\\"\\n\\n\\t| arrowForm arrowCanvas arrowHeadLength arrowX arrowTop arrowBottom |\\n\\n\\tarrowForm _ (self characterFormAt: $^) copy.\\n\\tarrowCanvas _ arrowForm getCanvas.\\n\\tarrowCanvas fillColor: Color white.\\n\\n\\tarrowHeadLength _ ((arrowForm width - 2)// 2).\\n\\tarrowX _ (arrowHeadLength max: (arrowForm width // 2)).\\n\\tarrowTop _ arrowForm height // 4. \\n\\tarrowBottom _ (arrowTop + (arrowForm width * 4 // 5 )).\\n\\tarrowBottom _ (arrowBottom min: arrowForm height) max: (arrowForm height * 2 // 3).\\n\\n\\t\\\"Draw the lines\\\"\\n\\tarrowCanvas line: (arrowX@arrowTop) to: (arrowX@arrowBottom) color: Color black.\\n\\tarrowCanvas \\n\\t\\tline: (arrowX@arrowTop) \\n\\t\\tto: ((arrowX - arrowHeadLength)@(arrowTop + arrowHeadLength)) \\n\\t\\tcolor: Color black.\\n\\tarrowCanvas \\n\\t\\tline: (arrowX@arrowTop) \\n\\t\\tto: ((arrowX + arrowHeadLength)@(arrowTop + arrowHeadLength)) \\n\\t\\tcolor: Color black.\\n\\n\\t\\\"Replace the glyph\\\"\\n\\tself characterFormAt: $^ put: arrowForm.\\n\\n! !\\n\\n\\n!StrikeFont methodsFor: 'multibyte character methods' stamp: 'yo 3/18/2004 00:10'!\\nfixAccuISO8859From: aStrikeFont\\n\\n\\t| f |\\n\\tself reset.\\n\\txTable _ aStrikeFont xTable copy.\\n\\tglyphs _ Form extent: aStrikeFont glyphs extent.\\n\\tmaxAscii _ 255.\\n\\tminAscii _ 0.\\n\\t\\\"stopConditions _ nil.\\\"\\n\\n\\t0 to: 127 do: [:i |\\n\\t\\tf _ aStrikeFont characterFormAt: (Character value: i) isoToSqueak.\\n\\t\\tf width = 0 ifTrue: [f _ Form extent: 1@f height].\\n\\t\\t\\n\\t\\tself characterFormAt: (Character value: i) put: f.\\n\\t].\\n\\t128 to: 159 do: [:i |\\n\\t\\tf _ Form extent: 1@f height.\\n\\t\\tself characterFormAt: (Character value: i) put: f.\\n\\t].\\n\\t160 to: 255 do: [:i |\\n\\t\\tf _ aStrikeFont characterFormAt: (Character value: i) isoToSqueak.\\n\\t\\tf width = 0 ifTrue: [f _ Form extent: 1@f height].\\n\\t\\t\\n\\t\\tself characterFormAt: (Character value: i) put: f.\\n\\t].\\n\\t\\t\\n\\t^ self.\\t\\n! !\\n\\n!StrikeFont methodsFor: 'multibyte character methods' stamp: 'yo 11/12/2002 12:56'!\\nfixAscent: a andDescent: d head: h\\n\\n\\t| bb newGlyphs |\\n\\t\\\"(a + d) = (ascent + descent) ifTrue: [\\\"\\n\\t\\tascent _ a.\\n\\t\\tdescent _ d.\\n\\t\\tnewGlyphs _ Form extent: (glyphs width@(h + glyphs height)).\\n\\t\\tbb _ BitBlt toForm: newGlyphs.\\n\\t\\tbb copy: (0@h extent: (glyphs extent)) from: 0@0 in: glyphs\\n\\t\\t\\tfillColor: nil rule: Form over.\\n\\t\\tglyphs _ newGlyphs.\\n\\t\\\"].\\\"\\n! !\\n\\n!StrikeFont methodsFor: 'multibyte character methods' stamp: 'yo 9/16/2002 15:07'!\\nfixForISO8859From: aStrikeFont\\n\\n\\t| fixer m mappingTable |\\n\\tfixer _ StrikeFontFixer newOn: aStrikeFont.\\n\\tself reset.\\n\\txTable _ aStrikeFont xTable copy.\\n\\tglyphs _ Form extent: aStrikeFont glyphs extent.\\n\\tmaxAscii _ 255.\\n\\tminAscii _ 0.\\n\\tmappingTable _ fixer mappingTable.\\n\\t\\\"stopConditions _ nil.\\\"\\n\\n\\t0 to: 255 do: [:i |\\n\\t\\t(m _ mappingTable at: i+1) ~= nil ifTrue: [\\n\\t\\t\\tself characterFormAt: (Character value: i)\\n\\t\\t\\t\\tput: (aStrikeFont characterFormAt: (Character value: m)).\\n\\t\\t] ifFalse: [\\n\\t\\t\\tself characterFormAt: (Character value: i)\\n\\t\\t\\t\\tput: (aStrikeFont characterFormAt: (Character space)).\\n\\t\\t]\\n\\t].\\n\\t^self.\\t\\n! !\\n\\n!StrikeFont methodsFor: 'multibyte character methods' stamp: 'yo 8/28/2002 16:35'!\\nfixXTable\\n\\n\\t| newXTable val |\\n\\txTable size >= 258 ifTrue: [\\n\\t\\t^ self.\\n\\t].\\n\\n\\tnewXTable _ Array new: 258.\\n\\t1 to: xTable size do: [:i |\\n\\t\\tnewXTable at: i put: (xTable at: i).\\n\\t].\\n\\n\\tval _ xTable at: (xTable size).\\n\\t\\n\\txTable size + 1 to: 258 do: [:i |\\n\\t\\tnewXTable at: i put: val.\\n\\t].\\n\\tminAscii _ 0.\\n\\tmaxAscii _ 255.\\n\\txTable _ newXTable.\\n! !\\n\\n!StrikeFont methodsFor: 'multibyte character methods' stamp: 'yo 1/6/2005 04:18'!\\nhasGlyphOf: aCharacter\\n\\n\\t| code |\\n\\tcode _ aCharacter charCode.\\n\\t((code between: self minAscii and: self maxAscii) not) ifTrue: [\\n\\t\\t^ false.\\n\\t].\\n\\t(xTable at: code + 1) < 0 ifTrue: [\\n\\t\\t^ false.\\n\\t].\\n\\t^ true.\\n! !\\n\\n!StrikeFont methodsFor: 'multibyte character methods' stamp: 'yo 8/28/2002 16:37'!\\nreadCharacter: aBits from: aStream\\n\\n\\t| pos |\\n\\tpos _ 0.\\n\\t12 timesRepeat: [\\n\\t\\t1 to: 2 do: [ :w |\\n\\t\\t\\taBits byteAt: (pos+w) put: (aStream next ). \\n\\t\\t].\\n\\t\\tpos _ pos + 4.\\n\\t].\\n! !\\n\\n!StrikeFont methodsFor: 'multibyte character methods' stamp: 'yo 5/24/2004 23:11'!\\nsetupDefaultFallbackFont\\n\\n\\t| fonts f |\\n\\tfonts _ TextStyle default fontArray.\\n\\tf _ fonts first.\\n\\t1 to: fonts size do: [:i |\\n\\t\\tself height > (fonts at: i) height ifTrue: [f _ fonts at: i].\\n\\t].\\n\\tself fallbackFont: f.\\n\\tself reset.\\n\\n! !\\n\\n\\n!StrikeFont methodsFor: 'testing'!\\ncheckCharacter: character \\n\\t\\\"Answer a Character that is within the ascii range of the receiver--either \\n\\tcharacter or the last character in the receiver.\\\"\\n\\n\\t| ascii | \\n\\tascii _ character asciiValue.\\n\\t((ascii < minAscii) or: [ascii > maxAscii])\\n\\t\\t\\tifTrue: [^maxAscii asCharacter]\\n\\t\\t\\tifFalse:\\t[^character]\\n! !\\n\\n\\n!StrikeFont methodsFor: '*nebraska-file in/out' stamp: 'yo 12/17/2005 20:36'!\\nencodedForRemoteCanvas\\n\\n\\t| stream |\\n\\tstream := RWBinaryOrTextStream on: ''.\\n\\tstream nextPutAll: self familyName.\\n\\tstream nextPut: Character space.\\n\\tstream nextPutAll: self name.\\n\\tstream nextPut: Character space.\\n\\tstream nextPutAll: self height.\\n\\tstream nextPut: Character space.\\n\\tstream nextPutAll: self emphasis asString.\\n\\t^ stream contents asString.\\n! !\\n\\n\\n!StrikeFont methodsFor: 'private' stamp: 'yo 3/11/2005 07:38'!\\ncreateCharacterToGlyphMap\\n \\\"Private. Create the character to glyph mapping for a font that didn't have any before. This is basically equivalent to what the former setStopCondition did, only based on indexes.\\\"\\n\\n maxAscii < 256 ifTrue: [^ (1 to: 256) collect: [:i | i - 1]].\\n ^ nil.\\n! !\\n\\n!StrikeFont methodsFor: 'private' stamp: 'yo 5/20/2004 10:51'!\\nleftAndRighOrNilFor: char\\n\\n\\t| code leftX |\\n\\tcode _ char charCode.\\n\\t((code between: self minAscii and: self maxAscii) not) ifTrue: [\\n\\t\\tcode _ $? charCode.\\n\\t].\\n\\tleftX _ xTable at: code + 1.\\n\\tleftX < 0 ifTrue: [\\n\\t\\tcode _ $? charCode.\\n\\t\\tleftX _ xTable at: code + 1.\\n\\t].\\n\\t^ Array with: leftX with: (xTable at: code + 2).\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStrikeFont class\\n\\tinstanceVariableNames: ''!\\n\\n!StrikeFont class methodsFor: 'accessing' stamp: 'nk 9/1/2004 11:00'!\\nactualFamilyNames\\n\\t\\\"Answer a sorted list of actual family names, without the Default aliases\\\"\\n\\n\\t^(self familyNames copyWithoutAll: TextStyle defaultFamilyNames) asOrderedCollection! !\\n\\n!StrikeFont class methodsFor: 'accessing' stamp: 'ar 2/3/2002 23:04'!\\nfamilyName: aName pointSize: aSize\\n\\t\\\"Answer a font (or the default font if the name is unknown) in the specified size.\\\"\\n\\n\\t^ ((TextStyle named: aName asSymbol) ifNil: [TextStyle default]) fontOfPointSize: aSize! !\\n\\n!StrikeFont class methodsFor: 'accessing' stamp: 'ar 11/25/2004 15:19'!\\nfamilyName: aName size: aSize\\n\\t\\\"Answer a font (or the default font if the name is unknown) in the specified size.\\\"\\n\\t| style |\\n\\tstyle := TextStyle named: aName asSymbol.\\n\\tstyle ifNil: [^(FontSubstitutionDuringLoading forFamilyName: aName pixelSize: aSize)\\n\\t\\t\\tsignal: 'missing font' ].\\n\\t^style fontOfSize: aSize! !\\n\\n!StrikeFont class methodsFor: 'accessing' stamp: 'sma 12/30/1999 13:48'!\\nfamilyNames\\n\\t^ (TextConstants select: [:each | each isKindOf: TextStyle]) keys asSortedCollection! !\\n\\n!StrikeFont class methodsFor: 'accessing' stamp: 'tak 11/11/2004 21:14'!\\nsetupDefaultFallbackFont\\n\\\"\\n\\tStrikeFont setupDefaultFallbackFont\\n\\\"\\n\\n\\t(#(#Accuat #Accujen #Accula #Accumon #Accusf #Accushi #Accuve #Atlanta) collect: [:e | TextStyle named: e]) do: [:style |\\n\\t\\tstyle fontArray do: [:e |\\n\\t\\t\\te reset.\\n\\t\\t\\te setupDefaultFallbackFont.\\n\\t\\t].\\n\\t].\\n\\tTTCFont allSubInstances\\n\\t\\tdo: [:font | font reset.\\n\\t\\t\\tfont setupDefaultFallbackFont]\\n\\n! !\\n\\n\\n!StrikeFont class methodsFor: 'derivative font caching' stamp: 'tak 3/11/2005 16:27'!\\nshutDown \\\"StrikeFont shutDown\\\"\\n\\t\\\"Deallocate synthetically derived copies of base fonts to save space\\\"\\n\\tself allSubInstancesDo: [:sf | sf reset].\\n\\tStrikeFontSet allSubInstancesDo: [:sf | sf reset].\\n\\tDefaultStringScanner _ nil.\\n! !\\n\\n\\n!StrikeFont class methodsFor: 'examples'!\\nconvertFontsNamed: familyName \\\" StrikeFont convertFontsNamed: 'NewYork' \\\"\\n\\t\\\"This utility is for use after you have used BitFont to produce data files \\n\\tfor the fonts you wish to use. It will read the BitFont files and then \\n\\twrite them out in strike2 (*.sf2) format which is much more compact,\\n\\tand which can be read in again very quickly.\\\"\\n\\t\\\"For this utility to work as is, the BitFont data files must be named\\n\\t'familyNN.BF', and must reside in the same directory as the image.\\\"\\n\\t| f |\\n\\t(FileDirectory default fileNamesMatching: familyName , '*.BF') do:\\n\\t\\t[:fname | Transcript cr; show: fname.\\n\\t\\tf _ StrikeFont new readFromBitFont: fname.\\n\\t\\tf writeAsStrike2named: f name , '.sf2']! !\\n\\n!StrikeFont class methodsFor: 'examples'!\\nexample\\n\\t\\\"Displays a line of text on the display screen at the location of the cursor.\\n\\tExample depends on the strike font file, 'TimesRoman10.strike'. existing.\\\"\\n\\n\\t(StrikeFont new readFromStrike2: 'NewYork12.sf2')\\n\\t\\tdisplayLine: 'A line of 12-pt text in New York style' at: Sensor cursorPoint\\n\\t \\n\\t\\\"StrikeFont example.\\\"! !\\n\\n!StrikeFont class methodsFor: 'examples' stamp: 'tpr 6/10/2005 16:07'!\\nreadStrikeFont2Family: familyName \\n\\t\\\"StrikeFont readStrikeFont2Family: 'Lucida'\\\"\\n\\t^self readStrikeFont2Family: familyName fromDirectory: FileDirectory default! !\\n\\n!StrikeFont class methodsFor: 'examples' stamp: 'tpr 6/10/2005 16:07'!\\nreadStrikeFont2Family: familyName fromDirectory: aDirectory\\n\\t\\\"StrikeFont readStrikeFont2Family: 'Lucida' fromDirectory: FileDirectory default\\\"\\n\\t\\\"This utility reads all available .sf2 StrikeFont files for a given family from \\n\\tthe current directory. It returns an Array, sorted by size, suitable for handing \\n\\tto TextStyle newFontArray: .\\\"\\n\\t\\\"For this utility to work as is, the .sf2 files must be named 'familyNN.sf2'.\\\"\\n\\t| fileNames strikeFonts fontArray |\\n\\tfileNames _ aDirectory fileNamesMatching: familyName , '##.sf2'.\\n\\tstrikeFonts _ fileNames collect: [:fname | StrikeFont new readFromStrike2: fname].\\n\\tstrikeFonts do: [ :font | font reset ].\\n\\tstrikeFonts _ strikeFonts asSortedCollection: [:a :b | a height < b height].\\n\\tfontArray _ strikeFonts asArray.\\n\\t^ fontArray\\n\\n\\\"TextConstants at: #Lucida put: (TextStyle fontArray: (StrikeFont \\n\\treadStrikeFont2Family: 'Lucida')).\\\"! !\\n\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 22:27'!\\nfromHostFont: fontName size: fontSize flags: fontFlags weight: fontWeight\\n\\t\\\"\\n\\t\\t^StrikeFont fromHostFont: (StrikeFont hostFontFromUser)\\n\\t\\t\\t\\t\\tsize: 12 flags: 0 weight: 4.\\n\\t\\\"\\n\\t| fontHandle glyphs xTable xStart maxWidth w glyphForm ascent descent fontHeight |\\n\\tfontHandle _ self primitiveCreateFont: fontName size: fontSize flags: fontFlags weight: fontWeight.\\n\\tascent _ self primitiveFontAscent: fontHandle.\\n\\tdescent _ self primitiveFontDescent: fontHandle.\\n\\tfontHeight _ ascent + descent.\\n\\txTable _ Array new: 258.\\n\\txStart _ maxWidth _ 0.\\n\\t0 to: 255 do:[:i|\\n\\t\\txTable at: i+1 put: xStart.\\n\\t\\tw _ self primitiveFont: fontHandle widthOfChar: i.\\n\\t\\tw > maxWidth ifTrue:[maxWidth _ w].\\n\\t\\txStart _ xStart + w].\\n\\txTable at: 256 put: xStart.\\n\\txTable at: 257 put: xStart.\\n\\txTable at: 258 put: xStart.\\n\\tglyphs _ Form extent: xTable last @ fontHeight depth: 1.\\n\\tglyphForm _ Form extent: maxWidth @ fontHeight depth: 1.\\n\\t0 to: 255 do:[:i|\\n\\t\\tglyphForm fillWhite.\\n\\t\\tself primitiveFont: fontHandle glyphOfChar: i into: glyphForm.\\n\\t\\txStart _ xTable at: i+1.\\n\\t\\tglyphForm displayOn: glyphs at: xStart@0.\\n\\t\\tglyphForm displayOn: Display at: xStart@0.\\n\\t].\\n\\tself primitiveDestroyFont: fontHandle.\\n\\t^Array with: glyphs with: xTable! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'rbb 2/18/2005 13:21'!\\nhostFontFromUser\\n\\t\\\"StrikeFont hostFontFromUser\\\"\\n\\t| fontNames index labels |\\n\\tfontNames _ self listFontNames asSortedCollection.\\n\\tlabels _ WriteStream on: (String new: 100).\\n\\tfontNames do:[:fn| labels nextPutAll: fn] separatedBy:[labels cr].\\n\\tindex _ (UIManager default chooseFrom: (labels contents substrings) \\n\\t\\t\\t\\ttitle: 'Choose your font').\\n\\tindex = 0 ifTrue:[^nil].\\n\\t^fontNames at: index! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 21:12'!\\nlistFont: index\\n\\t<primitive:'primitiveListFont' module:'FontPlugin'>\\n\\t^nil! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 21:12'!\\nlistFontNames\\n\\t\\\"StrikeFont listFontNames\\\"\\n\\t\\\"List all the OS font names\\\"\\n\\t| font fontNames index |\\n\\tfontNames _ WriteStream on: Array new.\\n\\tindex _ 0.\\n\\t[font _ self listFont: index.\\n\\tfont == nil] whileFalse:[\\n\\t\\tfontNames nextPut: font.\\n\\t\\tindex _ index + 1].\\n\\t^fontNames contents! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'tak 8/3/2005 21:11'!\\nlocaleChanged\\n\\tself setupDefaultFallbackFont! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 21:13'!\\nprimitiveCreateFont: fontName size: fontSize flags: fontFlags weight: fontWeight\\n\\t<primitive:'primitiveCreateFont' module:'FontPlugin'>\\n\\t^self primitiveFailed! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 21:13'!\\nprimitiveDestroyFont: fontHandle\\n\\t<primitive:'primitiveDestroyFont' module:'FontPlugin'>\\n\\t^self primitiveFailed! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 21:14'!\\nprimitiveFont: fontHandle glyphOfChar: charIndex into: glyphForm\\n\\t<primitive:'primitiveFontGlyphOfChar' module:'FontPlugin'>\\n\\t^self primitiveFailed! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 21:15'!\\nprimitiveFont: fontHandle widthOfChar: charIndex\\n\\t<primitive:'primitiveFontWidthOfChar' module:'FontPlugin'>\\n\\t^self primitiveFailed! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 22:25'!\\nprimitiveFontAscent: fontHandle\\n\\t<primitive:'primitiveFontAscent' module:'FontPlugin'>\\n\\t^self primitiveFailed! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 22:25'!\\nprimitiveFontDescent: fontHandle\\n\\t<primitive:'primitiveFontDescent' module:'FontPlugin'>\\n\\t^self primitiveFailed! !\\n\\n!StrikeFont class methodsFor: 'font creation' stamp: 'ar 6/4/2000 21:14'!\\nprimitiveFontEncoding: fontHandle\\n\\t<primitive:'primitiveFontEncoding' module:'FontPlugin'>\\n\\t^self primitiveFailed! !\\n\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'ar 2/3/2002 23:06'!\\nfamilyName: aName pointSize: aSize emphasized: emphasisCode\\n\\t\\\"Create the font with this emphasis\\\"\\n\\n\\t^ (self familyName: aName pointSize: aSize) emphasized: emphasisCode! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'tk 1/28/1999 11:31'!\\nfamilyName: aName size: aSize emphasized: emphasisCode\\n\\t\\\"Create the font with this emphasis\\\"\\n\\n\\t^ (self familyName: aName size: aSize) emphasized: emphasisCode! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'yo 3/18/2004 00:10'!\\nfixAccuISO8859From: aStrikeFont\\n\\n\\t^aStrikeFont copy fixAccuISO8859From: aStrikeFont.\\n! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'yo 9/16/2002 15:55'!\\nfixForISO8859From: aStrikeFont\\n\\n\\t^aStrikeFont copy fixForISO8859From: aStrikeFont.\\n! !\\n\\n!StrikeFont class methodsFor: 'instance creation'!\\nfromStrike: fileName \\n\\t\\\"Read a font from disk in the old ST-80 'strike' format.\\n\\tNote: this is an old format; use strike2 format instead\\\"\\n\\n\\t^self new newFromStrike: fileName! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'ar 1/5/2002 21:41'!\\nfromUser\\n\\t\\\"StrikeFont fromUser\\\"\\n\\t^self fromUser: TextStyle defaultFont! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'nk 9/1/2004 14:29'!\\nfromUser: priorFont\\n\\t^self fromUser: priorFont allowKeyboard: true! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'nk 9/1/2004 14:28'!\\nfromUser: priorFont allowKeyboard: aBoolean\\n\\t\\\"rr 3/23/2004 10:02 : made the menu invoked modally, thus allowing\\n\\tkeyboard control\\\" \\n\\t\\\"StrikeFont fromUser\\\"\\n\\t\\\"Present a menu of available fonts, and if one is chosen, return it.\\n\\tOtherwise return nil.\\\"\\n\\n\\t| fontList fontMenu style active ptMenu label spec font |\\n\\tfontList _ StrikeFont actualFamilyNames.\\n\\tfontMenu _ MenuMorph new defaultTarget: self.\\n\\tfontList do: [:fontName |\\n\\t\\tstyle _ TextStyle named: fontName.\\n\\t\\tactive _ priorFont familyName sameAs: fontName.\\n\\t\\tptMenu _ MenuMorph new defaultTarget: self.\\n\\t\\tstyle pointSizes do: [:pt |\\n\\t\\t\\t(active and:[pt = priorFont pointSize]) \\n\\t\\t\\t\\tifTrue:[label _ '<on>'] \\n\\t\\t\\t\\tifFalse:[label _ '<off>'].\\n\\t\\t\\tlabel _ label, pt printString, ' pt'.\\n\\t\\t\\tptMenu add: label \\n\\t\\t\\t\\ttarget: fontMenu\\n\\t\\t\\t\\tselector: #modalSelection:\\n\\t\\t\\t\\targument: {fontName. pt}].\\n\\t\\tstyle isTTCStyle ifTrue: [\\n\\t\\t\\tptMenu add: 'new size'\\n\\t\\t\\t\\ttarget: style selector: #addNewFontSizeDialog: argument: {fontName. fontMenu}.\\n\\t\\t].\\n\\t\\tactive ifTrue:[label _ '<on>'] ifFalse:[label _ '<off>'].\\n\\t\\tlabel _ label, fontName.\\n\\t\\tfontMenu add: label subMenu: ptMenu].\\n\\tspec _ fontMenu invokeModalAt: ActiveHand position in: ActiveWorld allowKeyboard: aBoolean.\\n\\tspec ifNil: [^ nil].\\n\\tstyle _ TextStyle named: spec first.\\n\\tstyle ifNil: [^ self].\\n\\tfont _ style fonts detect: [:any | any pointSize = spec last] ifNone: [nil].\\n\\t^ font! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'yo 8/5/2003 13:11'!\\nnewForJapaneseFromEFontBDFFile: fileName name: aString overrideWith: otherFileName\\n\\n\\t| n |\\n\\tn _ self new.\\n\\tn readEFontBDFForJapaneseFromFile: fileName name: aString overrideWith: otherFileName.\\n\\t^ n.\\n! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'yo 1/15/2004 16:48'!\\nnewForKoreanFromEFontBDFFile: fileName name: aString overrideWith: otherFileName\\n\\n\\t| n |\\n\\tn _ self new.\\n\\tn readEFontBDFForKoreanFromFile: fileName name: aString overrideWith: otherFileName.\\n\\t^ n.\\n! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'nop 1/23/2000 19:21'!\\nnewFromBDFFile: aFileName name: aString \\\"StrikeFont newFromBDFFile: 'helvR12.bdf' name: 'Helvetica12'\\\"\\n\\t\\\"Read a font from disk in the X11 Bitmap Distribution Format.\\\"\\n\\n\\t| n |\\n\\tn _ self new.\\n\\tn readBDFFromFile: aFileName name: aString.\\n\\t^n.\\n\\n\\t\\\"TextConstants at: #Helvetica put: (TextStyle fontArray: {StrikeFont newFromBDFFile: 'helvR12.bdf' name: 'Helvetica12'})\\\"\\n\\t\\\"TextConstants at: #Lucida put: (TextStyle fontArray: {StrikeFont newFromBDFFile: 'luRS12.bdf' name: 'Lucida'})\\\"\\n\\t\\\"TextStyle default fontAt: 5 put: (StrikeFont new readFromStrike2: 'helv12.sf2').\\\"\\n\\n! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'yo 1/19/2005 11:22'!\\nnewFromEFontBDFFile: fileName name: aString ranges: ranges\\n\\n\\t| n |\\n\\tn _ self new.\\n\\tn readEFontBDFFromFile: fileName name: aString ranges: ranges.\\n\\t^ n.\\n! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'yo 12/27/2002 16:57'!\\nnewFromEFontBDFFile: aFileName name: aString startRange: start endRange: end\\n\\n\\t| n |\\n\\tn _ self new.\\n\\tn readEFontBDFFromFile: aFileName name: aString rangeFrom: start to: end.\\n\\t^n.\\n\\n\\t\\\"TextConstants at: #Helvetica put: (TextStyle fontArray: {StrikeFont newFromBDFFile: 'helvR12.bdf' name: 'Helvetica12'})\\\"\\n\\t\\\"TextConstants at: #Lucida put: (TextStyle fontArray: {StrikeFont newFromBDFFile: 'luRS12.bdf' name: 'Lucida'})\\\"\\n\\t\\\"TextStyle default fontAt: 5 put: (StrikeFont new readFromStrike2: 'helv12.sf2').\\\"\\n\\n! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'yo 9/23/2002 16:28'!\\nnewFromF12File: aFileName\\n\\t\\\"StrikeFont newFromF12File: 'kaname.f12'\\\"\\n\\n\\t| file n |\\n\\t('*.F12' match: aFileName) ifFalse: [\\\"self halt. \\\" \\\"likely incompatible\\\"].\\n\\tfile _ FileStream readOnlyFileNamed: aFileName.\\n\\tfile binary.\\n\\tn _ self new.\\n\\tn name: (FileDirectory baseNameFor: (FileDirectory localNameFor: aFileName)).\\n\\tn readF12FromStream: file.\\n\\t^ n.\\n! !\\n\\n!StrikeFont class methodsFor: 'instance creation' stamp: 'tak 12/20/2004 10:23'!\\npasswordFontSize: aSize \\n\\t^ FixedFaceFont new passwordFont fontSize: aSize! !\\n\\n\\n!StrikeFont class methodsFor: '*nebraska-instance creation' stamp: 'yo 12/17/2005 22:41'!\\ndecodedFromRemoteCanvas: aString\\n\\n\\t| array style base |\\n\\tarray _ aString findTokens: #($ ).\\n\\tstyle _ TextStyle named: (array at: 1) asSymbol.\\n\\tstyle ifNil: [^ TextStyle defaultFont].\\n\\t(style fontArray first name = style fontArray first name withoutTrailingDigits) ifTrue: [\\n\\t\\t\\t^ self familyName: (array at: 1) size: (array at: 3) asNumber emphasized: (array at: 4) asNumber].\\n\\tbase _ style fontArray detect: [:f | (array at: 2) beginsWith: f name].\\n\\t^ base emphasized: (array at: 4) asNumber.\\n\\n\\t\\\"^ self familyName: (array at: 1) size: (array at: 2) asNumber emphasized: (array at: 3) asNumber.\\\"\\n! !\\nObject subclass: #StrikeFontFixer\\n\\tinstanceVariableNames: 'strikeFont charForms newFont'\\n\\tclassVariableNames: 'MappingTable NoFontTable'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-Display'!\\n\\n!StrikeFontFixer methodsFor: 'as yet unclassified' stamp: 'yo 9/16/2002 15:03'!\\ncharacterFormAt: aCharacter at: aPoint\\n\\n\\t| f |\\n\\tf _ charForms at: aCharacter asciiValue + 1.\\n\\t(f magnifyBy: 3) displayAt: aPoint.\\n\\t^ f.\\n! !\\n\\n!StrikeFontFixer methodsFor: 'as yet unclassified' stamp: 'yo 9/16/2002 15:03'!\\ndisplayOn: aDisplayObject at: aPoint magnifyBy: aNumber\\n\\n\\t| form hStep vStep bb source nextPoint |\\n\\thStep _ (strikeFont maxWidth * aNumber * 1.2) asInteger.\\n\\tvStep _ (strikeFont height * aNumber * 1.2) asInteger.\\n\\t\\n\\tform _ Form extent: (hStep * 16)@(vStep * 16).\\n\\tbb _ BitBlt toForm: form.\\n\\t0 to: 15 do: [:i |\\n\\t\\t1 to: 16 do: [:j |\\n\\t\\t\\tsource _ ((charForms at: (i * 16 + j)) magnifyBy: aNumber).\\n\\t\\t\\tnextPoint _ (hStep * (j - 1)@(vStep * i)).\\n\\t\\t\\tbb copy: ((nextPoint+((hStep@vStep - source extent) // 2)) extent: source extent)\\n\\t\\t\\t\\tfrom: 0@0 in: source fillColor: Color black rule: Form over.\\n\\t\\t].\\n\\t].\\n\\tform displayOn: aDisplayObject at: aPoint.\\n! !\\n\\n!StrikeFontFixer methodsFor: 'as yet unclassified' stamp: 'yo 9/16/2002 15:03'!\\nfont: aStrikeFont\\n\\n\\tstrikeFont _ aStrikeFont.\\n\\tself forms.\\n! !\\n\\n!StrikeFontFixer methodsFor: 'as yet unclassified' stamp: 'yo 9/16/2002 15:04'!\\nforms\\n\\n\\t1 to: 256 do: [:i |\\n\\t\\tcharForms at: i put: (strikeFont characterFormAt: (Character value: (i - 1)))\\n\\t].\\n! !\\n\\n!StrikeFontFixer methodsFor: 'as yet unclassified' stamp: 'yo 9/16/2002 15:04'!\\ninitialize\\n\\n\\tcharForms _ Array new: 256.\\n! !\\n\\n!StrikeFontFixer methodsFor: 'as yet unclassified' stamp: 'yo 9/16/2002 15:04'!\\nmappingTable\\n\\n\\t^ MappingTable.\\n! !\\n\\n!StrikeFontFixer methodsFor: 'as yet unclassified' stamp: 'yo 9/16/2002 15:04'!\\nstoreEditedGlyphsOn: aStream\\n\\n\\t| n |\\n\\tNoFontTable do: [:i |\\n\\t\\tn _ strikeFont name.\\n\\t\\t(n beginsWith: 'NewYork') ifTrue: [n _ 'NewYork'].\\n\\t\\taStream nextPutAll: '((StrikeFont familyName: ''', n, ''' size: ',\\n\\t\\t\\tstrikeFont height asString, ')'.\\n\\t\\taStream nextPutAll: ' characterFormAt: '.\\n\\t\\taStream nextPutAll: '(Character value: ', i asString, ')'.\\n\\t\\taStream nextPutAll: ' put: '.\\n\\t\\t(strikeFont characterFormAt: (Character value: i)) storeOn: aStream base: 2.\\n\\t\\taStream nextPutAll: ')!!'.\\n\\t\\taStream nextPut: Character cr.\\n\\t\\taStream nextPut: Character cr.\\n\\t].\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStrikeFontFixer class\\n\\tinstanceVariableNames: ''!\\n\\n!StrikeFontFixer class methodsFor: 'as yet unclassified' stamp: 'yo 9/16/2002 15:06'!\\ninitialize\\n\\\"\\n\\tStrikeFontFixer initialize\\n\\\"\\n\\n\\t| d |\\n\\tself initializeNoFontTable.\\n\\td _ Array new: 256.\\n\\t0 to: 127 do: [:i | d at: i+1 put: i].\\n\\t16r80 to: 16r9F do: [:i | d at: i+1 put: nil].\\n\\td at: 16rA0+1 put: 16r20.\\n\\td at: 16rA1+1 put: 16rC1.\\n\\td at: 16rA2+1 put: 16rA2.\\n\\td at: 16rA3+1 put: 16rA3.\\n\\td at: 16rA4+1 put: 16rA9. \\\"CURRENCY SIGN\\\"\\n\\td at: 16rA5+1 put: 16rB4.\\n\\td at: 16rA6+1 put: 16r7C. \\\"BROKEN BAR\\\"\\n\\td at: 16rA7+1 put: 16rA4.\\n\\td at: 16rA8+1 put: 16r80. \\\"DIAERESIS\\\"\\n\\td at: 16rA9+1 put: 16rA9.\\n\\td at: 16rAA+1 put: 16rBB.\\n\\td at: 16rAB+1 put: 16rC7.\\n\\td at: 16rAC+1 put: 16rD1. \\\"NOT SIGN\\\"\\n\\td at: 16rAD+1 put: 16rD0.\\n\\td at: 16rAE+1 put: 16rA8.\\n\\td at: 16rAF+1 put: 16rD1. \\\"MACRON\\\"\\n\\td at: 16rB0+1 put: 16rA1.\\n\\td at: 16rB1+1 put: 16r2B. \\\"PLUS-MINUS SIGN\\\"\\n\\td at: 16rB2+1 put: 16rAB. \\\"SUPERSCRIPT TWO\\\"\\n\\td at: 16rB3+1 put: 16rAB. \\\"SUPERSCRIPT THREE\\\"\\n\\td at: 16rB4+1 put: 16rAB.\\n\\td at: 16rB5+1 put: 16r75. \\\"MICRO SIGN\\\"\\n\\td at: 16rB6+1 put: 16rA6.\\n\\td at: 16rB7+1 put: 16rA5.\\n\\td at: 16rB8+1 put: 16r82. \\\"CEDILLA\\\"\\n\\td at: 16rB9+1 put: 16rAB. \\\"SUPERSCRIPT ONE\\\"\\n\\td at: 16rBA+1 put: 16rBC.\\n\\td at: 16rBB+1 put: 16rC8.\\n\\td at: 16rBC+1 put: 16r4D. \\\"VULGAR FRACTION ONE QUARTER\\\"\\n\\td at: 16rBD+1 put: 16r4D. \\\"VULGAR FRACTIOIN ONE HALF\\\"\\n\\td at: 16rBE+1 put: 16r4D. \\\"VALGAR FRACTION THREE QUARTERS\\\"\\n\\td at: 16rBF+1 put: 16rC0.\\n\\td at: 16rC0+1 put: 16rCB.\\n\\td at: 16rC1+1 put: 16rCB. \\\"CAPITAL A WITH ACUTE\\\"\\n\\td at: 16rC2+1 put: 16rCB. \\\"CAPITAL A WITH CIRCUMFLEX\\\"\\n\\td at: 16rC3+1 put: 16rCC.\\n\\td at: 16rC4+1 put: 16r80.\\n\\td at: 16rC5+1 put: 16r81.\\n\\td at: 16rC6+1 put: 16rAE.\\n\\td at: 16rC7+1 put: 16r82.\\n\\td at: 16rC8+1 put: 16r83. \\\"CAPITAL E WITH GRAVE\\\"\\n\\td at: 16rC9+1 put: 16r83.\\n\\td at: 16rCA+1 put: 16r83. \\\"CAPITAL E WITH CIRCUMFLEX\\\"\\n\\td at: 16rCB+1 put: 16r83. \\\"CAPITAL E WITH DIAERESIS\\\"\\n\\td at: 16rCC+1 put: 16r49. \\\"CAPITAL I WITH GRAVE\\\"\\n\\td at: 16rCD+1 put: 16r49. \\\"CAPITAL I WITH ACUTE\\\"\\n\\td at: 16rCE+1 put: 16r49. \\\"CAPITAL I WITH CIRCUMFLEX\\\"\\n\\td at: 16rCF+1 put: 16r49. \\\"CAPITAL I WITH DIAERESIS\\\"\\n\\td at: 16rD0+1 put: 16r44. \\\"CAPITAL ETH\\\"\\n\\td at: 16rD1+1 put: 16r84.\\n\\td at: 16rD2+1 put: 16rCD. \\\"CAPITAL O WITH GRAVE\\\"\\n\\td at: 16rD3+1 put: 16rCD. \\\"CAPITAL O WITH ACUTE\\\"\\n\\td at: 16rD4+1 put: 16rCD. \\\"CAPITAL O WITH CIRCUMFLEX\\\"\\n\\td at: 16rD5+1 put: 16rCD.\\n\\td at: 16rD6+1 put: 16r85.\\n\\td at: 16rD7+1 put: 16r2B. \\\"MULTIPLICATION SIGN\\\"\\n\\td at: 16rD8+1 put: 16rBF.\\n\\td at: 16rD9+1 put: 16r86. \\\"CAPITAL U WITH GRAVE\\\"\\n\\td at: 16rDA+1 put: 16r86. \\\"CAPITAL U WITH ACUTE\\\"\\n\\td at: 16rDB+1 put: 16r86. \\\"CAPITAL U WITH CIRCUMFLEX\\\"\\n\\td at: 16rDC+1 put: 16r86. \\\"CAPTIAL U WITH DIAERESIS\\\"\\n\\td at: 16rDD+1 put: 16r59. \\\"CAPITAL Y WITH ACUTE\\\"\\n\\td at: 16rDE+1 put: 16r50. \\\"CAPITAL THORN\\\"\\n\\td at: 16rDF+1 put: 16rA7.\\n\\td at: 16rE0+1 put: 16r88.\\n\\td at: 16rE1+1 put: 16r87.\\n\\td at: 16rE2+1 put: 16r89.\\n\\td at: 16rE3+1 put: 16r8B.\\n\\td at: 16rE4+1 put: 16r8A.\\n\\td at: 16rE5+1 put: 16r8C.\\n\\td at: 16rE6+1 put: 16rBE.\\n\\td at: 16rE7+1 put: 16r8D.\\n\\td at: 16rE8+1 put: 16r8F.\\n\\td at: 16rE9+1 put: 16r8E.\\n\\td at: 16rEA+1 put: 16r90.\\n\\td at: 16rEB+1 put: 16r91.\\n\\td at: 16rEC+1 put: 16r93.\\n\\td at: 16rED+1 put: 16r92.\\n\\td at: 16rEE+1 put: 16r94.\\n\\td at: 16rEF+1 put: 16r95.\\n\\td at: 16rF0+1 put: 16r64. \\\"SMALL ETH\\\"\\n\\td at: 16rF1+1 put: 16r96.\\n\\td at: 16rF2+1 put: 16r98.\\n\\td at: 16rF3+1 put: 16r97.\\n\\td at: 16rF4+1 put: 16r99.\\n\\td at: 16rF5+1 put: 16r9B.\\n\\td at: 16rF6+1 put: 16r9A.\\n\\td at: 16rF7+1 put: 16r2D. \\\"DIVISION SIGN\\\"\\n\\td at: 16rF8+1 put: 16rBF.\\n\\td at: 16rF9+1 put: 16r9D.\\n\\td at: 16rFA+1 put: 16r9C.\\n\\td at: 16rFB+1 put: 16r9E.\\n\\td at: 16rFC+1 put: 16r9F.\\n\\td at: 16rFD+1 put: 16rD8. \\\"SMALL Y WITH ACUTE\\\"\\n\\td at: 16rFE+1 put: 16r70. \\\"SMALL THORN\\\"\\n\\td at: 16rFF+1 put: 16rD8.\\n\\n\\tMappingTable _ d.\\n! !\\n\\n!StrikeFontFixer class methodsFor: 'as yet unclassified' stamp: 'yo 9/16/2002 15:05'!\\ninitializeNoFontTable\\n\\n\\t| n |\\n\\tn _ #(\\n\\t16rA4 \\\"CURRENCY SIGN\\\"\\n\\t16rA6 \\\"BROKEN BAR\\\"\\n\\t16rA8 \\\"DIAERESIS\\\"\\n\\t16rAC \\\"NOT SIGN\\\"\\n\\t16rAF \\\"MACRON\\\"\\n\\t16rB1 \\\"PLUS-MINUS SIGN\\\"\\n\\t16rB2 \\\"SUPERSCRIPT TWO\\\"\\n\\t16rB3 \\\"SUPERSCRIPT THREE\\\"\\n\\t16rB5 \\\"MICRO SIGN\\\"\\n\\t16rB8 \\\"CEDILLA\\\"\\n\\t16rB9 \\\"SUPERSCRIPT ONE\\\"\\n\\t16rBC \\\"VULGAR FRACTION ONE QUARTER\\\"\\n\\t16rBD \\\"VULGAR FRACTIOIN ONE HALF\\\"\\n\\t16rBE \\\"VALGAR FRACTION THREE QUARTERS\\\"\\n\\t16rC1 \\\"CAPITAL A WITH ACUTE\\\"\\n\\t16rC2 \\\"CAPITAL A WITH CIRCUMFLEX\\\"\\n\\t16rC8 \\\"CAPITAL E WITH GRAVE\\\"\\n\\t16rCA \\\"CAPITAL E WITH CIRCUMFLEX\\\"\\n\\t16rCB \\\"CAPITAL E WITH DIAERESIS\\\"\\n\\t16rCC \\\"CAPITAL I WITH GRAVE\\\"\\n\\t16rCD \\\"CAPITAL I WITH ACUTE\\\"\\n\\t16rCE \\\"CAPITAL I WITH CIRCUMFLEX\\\"\\n\\t16rCF \\\"CAPITAL I WITH DIAERESIS\\\"\\n\\t16rD0 \\\"CAPITAL ETH\\\"\\n\\t16rD2 \\\"CAPITAL O WITH GRAVE\\\"\\n\\t16rD3 \\\"CAPITAL O WITH ACUTE\\\"\\n\\t16rD4 \\\"CAPITAL O WITH CIRCUMFLEX\\\"\\n\\t16rD7 \\\"MULTIPLICATION SIGN\\\"\\n\\t16rD9 \\\"CAPITAL U WITH GRAVE\\\"\\n\\t16rDA \\\"CAPITAL U WITH ACUTE\\\"\\n\\t16rDB \\\"CAPITAL U WITH CIRCUMFLEX\\\"\\n\\t16rDD \\\"CAPITAL Y WITH ACUTE\\\"\\n\\t16rDE \\\"CAPITAL THORN\\\"\\n\\t16rF0 \\\"SMALL ETH\\\"\\n\\t16rF7 \\\"DIVISION SIGN\\\"\\n\\t16rFD \\\"SMALL Y WITH ACUTE\\\"\\n\\t16rFE \\\"SMALL THORN\\\"\\n\\t).\\n\\tNoFontTable _ n.\\n\\n! !\\n\\n!StrikeFontFixer class methodsFor: 'as yet unclassified' stamp: 'nk 7/30/2004 18:09'!\\nnewOn: aStrikeFont \\n\\t^self new font: aStrikeFont! !\\nAbstractFont subclass: #StrikeFontSet\\n\\tinstanceVariableNames: 'fontArray emphasis derivativeFonts name rIndex'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-Display'!\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'ar 4/12/2005 17:14'!\\nascentOf: aCharacter\\n\\t^(self fontOf: aCharacter) ascent! !\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'ar 4/12/2005 17:15'!\\ndescentOf: aCharacter\\n\\t^(self fontOf: aCharacter) descent! !\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'yo 9/23/2002 20:08'!\\nfontArray\\n\\n\\t^ fontArray\\n! !\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'ar 4/12/2005 17:14'!\\nfontOf: aCharacter\\n\\t\\\"Answer the actual font to use for aCharacter\\\"\\n\\t^self fontOf: aCharacter ifAbsent:[fontArray at: 1]! !\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'ar 4/12/2005 17:14'!\\nfontOf: aCharacter ifAbsent: aBlock\\n\\t\\\"Answer the actual font to use for aCharacter\\\"\\n\\t| encoding font |\\n\\tencoding := aCharacter leadingChar + 1.\\n\\tencoding <= fontArray size \\n\\t\\tifTrue:[font := fontArray at: encoding].\\n\\tfont ifNil:[^aBlock value].\\n\\t^font\\n! !\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'ar 4/12/2005 17:15'!\\nheightOf: aCharacter\\n\\t^(self fontOf: aCharacter) height! !\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'tak 12/21/2004 16:43'!\\nlatin1\\n\\t\\\"Answer primary font\\\"\\n\\t^ fontArray at: 1! !\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'yo 11/15/2002 14:22'!\\nmaxAsciiFor: encoding\\n\\n\\t| f |\\n\\tf _ (fontArray at: encoding+1).\\n\\tf ifNotNil: [^ f maxAscii].\\n\\t^ 0.\\n! !\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'yo 8/5/2003 15:31'!\\ntextStyle\\n\\n\\t^ TextStyle actualTextStyles detect: [:aStyle | (aStyle fontArray collect: [:s | s name]) includes: self name]\\n\\t\\tifNone: [].\\n! !\\n\\n!StrikeFontSet methodsFor: 'accessing' stamp: 'ar 4/12/2005 17:15'!\\nwidthOf: aCharacter \\n\\t\\\"Answer the width of the argument as a character in the receiver.\\\"\\n\\t^(self fontOf: aCharacter) widthOf: aCharacter! !\\n\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 16:43'!\\nascent\\n\\n\\t^ fontArray first ascent.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 16:49'!\\nascentKern\\n\\n\\t^ fontArray first ascentKern.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 16:49'!\\nbaseKern\\n\\n\\t^ fontArray first baseKern.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 12/1/2003 18:00'!\\nbonk: glyphForm with: bonkForm at: j\\n\\t\\\"Bonking means to run through the glyphs clearing out black pixels\\n\\tbetween characters to prevent them from straying into an adjacent\\n\\tcharacter as a result of, eg, bolding or italicizing\\\"\\n\\t\\\"Uses the bonkForm to erase at every character boundary in glyphs.\\\"\\n\\n\\t| bb offset font x |\\n\\tfont _ (fontArray at: j).\\n\\toffset _ bonkForm offset x.\\n\\tbb _ BitBlt toForm: glyphForm.\\n\\tbb sourceForm: bonkForm; sourceRect: bonkForm boundingBox;\\n\\t\\tcombinationRule: Form erase; destY: 0.\\n\\tx _ font xTable.\\n\\t(x isMemberOf: SparseLargeTable) ifTrue: [\\n\\t\\tx base to: x size-1 do: [:i | bb destX: (x at: i) + offset; copyBits].\\n\\t] ifFalse: [\\n\\t\\t1 to: x size-1 do: [:i | bb destX: (x at: i) + offset; copyBits].\\n\\t].\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:15'!\\ncopy\\n\\n\\t| s a |\\n\\ts _ self class new.\\n\\ts name: self name.\\n\\ts emphasis: self emphasis.\\n\\ts reset.\\n\\ta _ Array new: fontArray size.\\n\\t1 to: a size do: [:i |\\n\\t\\ta at: i put: (fontArray at: i) copy.\\n\\t].\\n\\ts fontArray: a.\\n\\t^ s.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'nk 9/1/2004 12:06'!\\nderivativeFonts\\n\\t^derivativeFonts copyWithout: nil! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:02'!\\ndescent\\n\\n\\t^ fontArray first descent.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:02'!\\ndescentKern\\n\\n\\t^ fontArray first descentKern.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 5/19/2004 11:36'!\\ndisplayLine: aString at: aPoint \\n\\t\\\"Display the characters in aString, starting at position aPoint.\\\"\\n\\n\\tself characters: (1 to: aString size)\\n\\t\\tin: aString\\n\\t\\tdisplayAt: aPoint\\n\\t\\tclippedBy: Display boundingBox\\n\\t\\trule: Form over\\n\\t\\tfillColor: nil\\n\\t\\tkernDelta: 0\\n\\t\\ton: (BitBlt current toForm: Display).\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:06'!\\nemphasis\\n\\t\\\"Answer the integer code for synthetic bold, italic, underline, and \\n\\tstrike-out.\\\"\\n\\n\\t^ emphasis.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:07'!\\nemphasis: code \\n\\t\\\"Set the integer code for synthetic bold, itallic, underline, and strike-out, \\n\\twhere bold=1, italic=2, underlined=4, and struck out=8.\\\"\\n\\n\\temphasis _ code.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:15'!\\nemphasized: code \\n\\n\\t\\\"Answer a copy of the receiver with emphasis set to include code.\\\"\\n\\t| derivative addedEmphasis base safeCode |\\n\\tcode = 0 ifTrue: [^ self].\\n\\t(derivativeFonts == nil or: [derivativeFonts size = 0]) ifTrue: [^ self].\\n\\tderivative _ derivativeFonts at: (safeCode _ code min: derivativeFonts size).\\n\\tderivative == nil ifFalse: [^ derivative]. \\\"Already have this style\\\"\\n\\n\\t\\\"Dont have it -- derive from another with one with less emphasis\\\"\\n\\taddedEmphasis _ 1 bitShift: safeCode highBit - 1.\\n\\tbase _ self emphasized: safeCode - addedEmphasis. \\\"Order is Bold, Ital, Under, Narrow\\\"\\n\\taddedEmphasis = 1 ifTrue: \\\"Compute synthetic bold version of the font\\\"\\n\\t\\t[derivative _ (base copy name: base name , 'B') makeBoldGlyphs].\\n\\taddedEmphasis = 2 ifTrue: \\\"Compute synthetic italic version of the font\\\"\\n\\t\\t[ derivative _ (base copy name: base name , 'I') makeItalicGlyphs].\\n\\taddedEmphasis = 4 ifTrue: \\\"Compute underlined version of the font\\\"\\n\\t\\t[derivative _ (base copy name: base name , 'U') makeUnderlinedGlyphs].\\n\\taddedEmphasis = 8 ifTrue: \\\"Compute narrow version of the font\\\"\\n\\t\\t[derivative _ (base copy name: base name , 'N') makeCondensedGlyphs].\\n\\taddedEmphasis = 16 ifTrue: \\\"Compute struck-out version of the font\\\"\\n\\t\\t[derivative _ (base copy name: base name , 'X') makeStruckOutGlyphs].\\n\\tderivative emphasis: safeCode.\\n\\tderivativeFonts at: safeCode put: derivative.\\n\\t^ derivative\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 8/18/2003 20:59'!\\nfamilyName\\n\\n\\t^ fontArray first familyName.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:38'!\\nfamilySizeFace\\n\\n\\t^ Array\\n\\t\\twith: fontArray first name\\n\\t\\twith: self height\\n\\t\\twith: fontArray first emphasis\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:49'!\\nfontArray: anArray\\n\\n\\tfontArray _ anArray.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:49'!\\nfontNameWithPointSize\\n\\n\\t^ fontArray first fontNameWithPointSize.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:50'!\\nglyphs\\n\\n\\t^ fontArray first glyphs\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:50'!\\nglyphsEncoding: anInteger\\n\\n\\t^ (fontArray at: (anInteger+1)) glyphs.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:50'!\\nheight\\n\\n\\t^ fontArray first height.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'tak 12/16/2004 19:15'!\\ninitializeWithFontArray: anArray \\n\\t\\\"Initialize with given font array, the ascent of primary font is modified \\n\\tif another font has higher size\\\"\\n\\t| primaryFont maxHeight newFont |\\n\\tfontArray := anArray.\\n\\tprimaryFont := anArray first.\\n\\temphasis := 0.\\n\\tname := primaryFont name.\\n\\tmaxHeight := anArray\\n\\t\\t\\t\\tinject: 0\\n\\t\\t\\t\\tinto: [:theHeight :font | (font notNil\\n\\t\\t\\t\\t\\t\\t\\tand: [theHeight < font height])\\n\\t\\t\\t\\t\\t\\tifTrue: [font height]\\n\\t\\t\\t\\t\\t\\tifFalse: [theHeight]].\\n\\tprimaryFont height < maxHeight\\n\\t\\tifTrue: [newFont := primaryFont copy\\n\\t\\t\\t\\t\\t\\tfixAscent: primaryFont ascent + (maxHeight - primaryFont height)\\n\\t\\t\\t\\t\\t\\tandDescent: primaryFont descent\\n\\t\\t\\t\\t\\t\\thead: 0.\\n\\t\\t\\tfontArray at: 1 put: newFont].\\n\\tself reset! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 1/5/2005 13:59'!\\ninstallOn: aDisplayContext\\n\\n\\t^ aDisplayContext installStrikeFont: self.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:50'!\\ninstallOn: aDisplayContext foregroundColor: foregroundColor backgroundColor: backgroundColor \\n\\n\\t^ aDisplayContext\\n\\t\\tinstallStrikeFont: self\\n\\t\\tforegroundColor: foregroundColor\\n\\t\\tbackgroundColor: backgroundColor.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:50'!\\nlineGrid\\n\\n\\t| f |\\n\\tf _ fontArray first.\\n\\t^ f ascent + f descent.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:52'!\\nmaxEncoding\\n\\n\\t^ fontArray size.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 2/24/2005 15:45'!\\nmaxWidth\\n\\n\\t^ (fontArray at: 1) maxWidth.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:52'!\\nname\\n\\n\\t^ name\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:52'!\\nname: aString\\n\\n\\tname _ aString\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 8/18/2003 21:17'!\\nobjectForDataStream: refStrm\\n\\t| dp |\\n\\t\\\"I am about to be written on an object file. Write a reference to a known Font in the other system instead. \\\"\\n\\n\\t\\\"A path to me\\\"\\n\\t(TextConstants at: #forceFontWriting ifAbsent: [false]) ifTrue: [^ self].\\n\\t\\t\\\"special case for saving the default fonts on the disk. See collectionFromFileNamed:\\\"\\n\\n\\tdp _ DiskProxy global: #StrikeFontSet selector: #familyName:size:emphasized:\\n\\t\\t\\targs: (Array with: self familyName with: self pointSize\\n\\t\\t\\t\\t\\twith: self emphasis).\\n\\trefStrm replace: self with: dp.\\n\\t^ dp.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:53'!\\npointSize\\n\\n\\t^ fontArray first pointSize.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:53'!\\nprintOn: aStream\\n\\n\\tsuper printOn: aStream.\\n\\taStream nextPutAll: '(' , self name.\\n\\taStream space.\\n\\tself height printOn: aStream.\\n\\taStream nextPut: $).\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:53'!\\nreset\\n\\t\\\"Reset the cache of derivative emphasized fonts\\\"\\n\\n\\tderivativeFonts _ Array new: 32.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:53'!\\nsubscript\\n\\n\\t^ fontArray first subscript\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:53'!\\nsuperscript\\n\\n\\t^ fontArray first superscript\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'ar 4/10/2005 18:53'!\\nwidthOfString: aString\\n\\n\\taString ifNil:[^0].\\n\\t\\\"Optimizing\\\"\\n\\t(aString isByteString) ifTrue: [\\n\\t\\t^ self fontArray first widthOfString: aString from: 1 to: aString size].\\n\\t^ self widthOfString: aString from: 1 to: aString size.\\n\\\"\\n\\tTextStyle default defaultFont widthOfString: 'zort' 21\\n\\\"\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'tak 1/11/2005 17:59'!\\nwidthOfString: aString from: startIndex to: stopIndex\\n\\t\\\"Measure the length of the given string between start and stop index\\\"\\n\\n\\t| resultX |\\n\\tresultX _ 0.\\n\\tstartIndex to: stopIndex do:[:i | \\n\\t\\tresultX _ resultX + (self widthOf: (aString at: i))].\\n\\t^ resultX.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:56'!\\nxTable\\n\\t\\\"Answer an Array of the left x-coordinate of characters in glyphs.\\\"\\n\\n\\t^ fontArray first xTable.\\n! !\\n\\n!StrikeFontSet methodsFor: 'as yet unclassified' stamp: 'yo 9/17/2002 17:56'!\\nxTableEncoding: anInteger\\n\\t\\\"Answer an Array of the left x-coordinate of characters in glyphs.\\\"\\n\\n\\t^(fontArray at: anInteger + 1) xTable.\\n! !\\n\\n\\n!StrikeFontSet methodsFor: 'character shapes' stamp: 'yo 12/27/2002 04:35'!\\ncharacterFormAt: character \\n\\n\\t| encoding ascii xTable leftX rightX |\\n\\tencoding _ character leadingChar + 1.\\n\\tascii _ character charCode.\\n\\t(ascii < (fontArray at: encoding) minAscii or: [ascii > (fontArray at: encoding) maxAscii])\\n\\t\\tifTrue: [ascii _ (fontArray at: encoding) maxAscii].\\n\\txTable _ (fontArray at: encoding) xTable.\\n\\tleftX _ xTable at: ascii + 1.\\n\\trightX _ xTable at: ascii + 2.\\n\\t^ (fontArray at: encoding) glyphs copy: (leftX @ 0 corner: rightX @ self height).\\n! !\\n\\n!StrikeFontSet methodsFor: 'character shapes' stamp: 'yo 12/27/2002 04:35'!\\ncharacterFormAt: character put: characterForm \\n\\n\\t| ascii leftX rightX widthDif newGlyphs encoding xTable glyphs |\\n\\tencoding _ character leadingChar + 1.\\n\\tascii _ character charCode.\\n\\tascii < (fontArray at: encoding) minAscii ifTrue: [\\n\\t\\t^ self error: 'Cant store characters below min ascii'\\n\\t].\\n\\tascii > (fontArray at: encoding) maxAscii ifTrue: [\\n\\t\\t^ self error: 'No change made'\\n\\t].\\n\\txTable _ (fontArray at: encoding) xTable.\\n\\tleftX _ xTable at: ascii + 1.\\n\\trightX _ xTable at: ascii + 2.\\n\\tglyphs _ (fontArray at: encoding) glyphs.\\n\\twidthDif _ characterForm width - (rightX - leftX).\\n\\twidthDif ~= 0 ifTrue: [\\n\\t\\tnewGlyphs _ Form extent: glyphs width + widthDif @ glyphs height.\\n\\t\\tnewGlyphs copy: (0 @ 0 corner: leftX @ glyphs height) from: 0 @ 0\\n\\t\\t\\tin: glyphs rule: Form over.\\n\\t\\tnewGlyphs\\n\\t\\t\\t\\tcopy: (rightX + widthDif @ 0 corner: newGlyphs width @ glyphs height)\\n\\t\\t\\t\\tfrom: rightX @ 0 in: glyphs rule: Form over.\\n\\t\\tglyphs _ newGlyphs.\\n\\t\\t\\\"adjust further entries on xTable\\\"\\n\\t\\txTable _ xTable copy.\\n\\t\\tascii + 2 to: xTable size do: [:i |\\n\\t\\t\\txTable at: i put: (xTable at: i) + widthDif]].\\n\\tglyphs copy: (leftX @ 0 extent: characterForm extent) from: 0 @ 0 in: characterForm rule: Form over.\\n! !\\n\\n\\n!StrikeFontSet methodsFor: 'displaying' stamp: 'yo 5/19/2004 11:35'!\\ncharacters: anInterval in: sourceString displayAt: aPoint clippedBy: clippingRectangle rule: ruleInteger fillColor: aForm kernDelta: kernDelta on: aBitBlt\\n\\t\\\"Simple, slow, primitive method for displaying a line of characters.\\n\\tNo wrap-around is provided.\\\"\\n\\n\\t| ascii encoding destPoint leftX rightX sourceRect xTable noFont f |\\n\\tdestPoint _ aPoint.\\n\\tanInterval do: \\n\\t\\t[:i |\\n\\t\\tencoding _ (sourceString at: i) leadingChar + 1.\\n\\t\\tnoFont _ false.\\n\\t\\t[f _ fontArray at: encoding]\\n\\t\\t\\ton: Exception do: [:ex | noFont _ true. f _ fontArray at: 1].\\n\\t\\tf ifNil: [noFont _ true. f _ fontArray at: 1].\\n\\t\\tascii _ noFont ifTrue: [$?] ifFalse: [(sourceString at: i) charCode].\\n\\t\\t(ascii < f minAscii\\n\\t\\t\\tor: [ascii > f maxAscii])\\n\\t\\t\\tifTrue: [ascii _ f maxAscii].\\n\\t\\txTable _ f xTable.\\n\\t\\tleftX _ xTable at: ascii + 1.\\n\\t\\trightX _ xTable at: ascii + 2.\\n\\t\\tsourceRect _ leftX@0 extent: (rightX-leftX) @ self height.\\n\\t\\taBitBlt copyFrom: sourceRect in: f glyphs to: destPoint.\\n\\t\\tdestPoint _ destPoint + ((rightX-leftX+kernDelta)@0).\\n\\t\\t\\\"destPoint printString displayAt: 0@(i*20).\\\"\\n\\t].\\n\\t^ destPoint.\\n! !\\n\\n!StrikeFontSet methodsFor: 'displaying' stamp: 'efc 8/6/2005 11:45'!\\ndisplayMultiString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY\\n\\n\\t| destPoint leftX rightX glyphInfo g destY |\\n\\tdestPoint := aPoint.\\n\\tglyphInfo := Array new: 5.\\n\\tstartIndex to: stopIndex do: [:charIndex |\\n\\t\\tself glyphInfoOf: (aString at: charIndex) into: glyphInfo.\\n\\t\\tg := glyphInfo at:1.\\n\\t\\tleftX := glyphInfo at:2.\\n\\t\\trightX := glyphInfo at:3.\\n\\t\\t((glyphInfo at:5) ~= aBitBlt lastFont) ifTrue: [\\n\\t\\t\\t(glyphInfo at:5) installOn: aBitBlt.\\n\\t\\t].\\n\\t\\taBitBlt sourceForm: g.\\n\\t\\tdestY := baselineY - (glyphInfo at:4).\\n\\t\\taBitBlt destX: (destPoint x) destY: destY width: (rightX - leftX) height: (self height).\\n\\t\\taBitBlt sourceOrigin: leftX @ 0.\\n\\t\\taBitBlt copyBits.\\n\\t\\tdestPoint := destPoint + (rightX - leftX + kernDelta @ 0).\\n\\t].\\n\\t^ destPoint.! !\\n\\n!StrikeFontSet methodsFor: 'displaying' stamp: 'yo 12/27/2002 04:35'!\\ndisplayStringR2L: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta \\n\\n\\t| destPoint font |\\n\\tdestPoint _ aPoint.\\n\\tstartIndex to: stopIndex do: [:charIndex | \\n\\t\\t| encoding ascii xTable leftX rightX | \\n\\t\\tencoding _ (aString at: charIndex) leadingChar + 1.\\n\\t\\tascii _ (aString at: charIndex) charCode.\\n\\t\\tfont _ fontArray at: encoding.\\n\\t\\t((ascii between: font minAscii and: font maxAscii) not) ifTrue: [\\n\\t\\t\\tascii _ font maxAscii].\\n\\t\\txTable _ font xTable.\\n\\t\\tleftX _ xTable at: ascii + 1.\\n\\t\\trightX _ xTable at: ascii + 2.\\n\\t\\taBitBlt sourceForm: font glyphs.\\n\\t\\taBitBlt destX: destPoint x - (rightX - leftX).\\n\\t\\taBitBlt destY: destPoint y.\\n\\t\\taBitBlt sourceOrigin: leftX @ 0.\\n\\t\\taBitBlt width: rightX - leftX.\\n\\t\\taBitBlt height: self height.\\n\\t\\taBitBlt copyBits.\\n\\t\\tdestPoint _ destPoint - (rightX - leftX + kernDelta @ 0).\\n\\t].\\n! !\\n\\n!StrikeFontSet methodsFor: 'displaying' stamp: 'yo 1/7/2005 12:04'!\\ndisplayString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta \\n\\n\\t^ self displayString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: aPoint y + self ascent.\\n! !\\n\\n!StrikeFontSet methodsFor: 'displaying' stamp: 'efc 8/6/2005 13:35'!\\ndisplayString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY\\n\\t\\\"Draw the given string from startIndex to stopIndex \\n\\tat aPoint on the (already prepared) BitBlt.\\\"\\n\\t\\n\\t\\\"Assume this is a wide string\\\"\\n\\t| isMulti |\\n\\tisMulti _ true.\\n\\n\\t\\\"Look for an excuse to use the fast primitive\\\"\\n \\t(aString isKindOf: ByteString) \\n\\t\\tifTrue:[ isMulti _ false]\\n\\t\\tifFalse:[ (aString isKindOf: Text) \\n\\t\\t\\tifTrue:[ (aString string isKindOf: ByteString) \\n\\t\\t\\t\\tifTrue:[ isMulti _ false ] \\n\\t]].\\n\\n\\tisMulti ifTrue:[^ self displayMultiString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta baselineY: baselineY].\\n\\n\\t^ aBitBlt displayString: aString \\n\\t\\t\\tfrom: startIndex \\n\\t\\t\\tto: stopIndex \\n\\t\\t\\tat: aPoint \\n\\t\\t\\tstrikeFont: self\\n\\t\\t\\tkern: kernDelta! !\\n\\n!StrikeFontSet methodsFor: 'displaying' stamp: 'yo 1/7/2005 15:17'!\\ndisplayString: aString on: aBitBlt from: startIndex to: stopIndex at: aPoint kern: kernDelta from: fromFont baselineY: baselineY\\n\\n\\t| destPoint leftX rightX glyphInfo g tag char destY |\\n\\tdestPoint _ aPoint.\\n\\trIndex _ startIndex.\\n\\ttag _ (aString at: rIndex) leadingChar.\\n\\tglyphInfo _ Array new: 5.\\n\\t[rIndex <= stopIndex] whileTrue: [\\n\\t\\tchar _ aString at: rIndex.\\n\\t\\t((fromFont hasGlyphOf: char) or: [char leadingChar ~= tag]) ifTrue: [^ Array with: rIndex with: destPoint].\\n\\t\\tself glyphInfoOf: char into: glyphInfo.\\n\\t\\tg _ glyphInfo first.\\n\\t\\tleftX _ glyphInfo second.\\n\\t\\trightX _ glyphInfo third.\\n\\t\\t(glyphInfo fifth ~= aBitBlt lastFont) ifTrue: [\\n\\t\\t\\tglyphInfo fifth installOn: aBitBlt.\\n\\t\\t].\\n\\t\\taBitBlt sourceForm: g.\\n\\t\\tdestY _ baselineY - glyphInfo fourth. \\n\\t\\taBitBlt destX: destPoint x.\\n\\t\\taBitBlt destY: destY.\\n\\t\\taBitBlt sourceOrigin: leftX @ 0.\\n\\t\\taBitBlt width: rightX - leftX.\\n\\t\\taBitBlt height: self height.\\n\\t\\taBitBlt copyBits.\\n\\t\\tdestPoint _ destPoint + (rightX - leftX + kernDelta @ 0).\\n\\t\\trIndex _ rIndex + 1.\\n\\t].\\n\\t^ Array with: rIndex with: destPoint.\\n! !\\n\\n!StrikeFontSet methodsFor: 'displaying' stamp: 'BG 3/16/2005 08:27'!\\nfontDisplay\\n\\t\\\"TextStyle default defaultFont fontDisplay.\\\"\\n\\n\\tDisplay restoreAfter:\\n\\t\\t[(Form extent: 440@400) displayAt: 90@90.\\n\\t\\t 0 to: 15 do:\\n\\t\\t\\t[:i |\\n\\t\\t\\ti storeStringHex displayAt: 100 @ (20 * i + 100).\\n\\t\\t\\t0 to: 15 do:\\n\\t\\t\\t\\t[:j |\\n\\t\\t\\t\\t((16*i+j) between: 1 and: (self xTable size - 2)) ifTrue:\\n\\t\\t\\t\\t\\t[(self characterFormAt: (16 * i + j) asCharacter)\\n\\t\\t\\t\\t\\t\\tdisplayAt: (20 * j + 150) @ (20 * i + 100)]]].\\n\\t\\t\\t'Click to continue...' asDisplayText displayAt: 100@450]! !\\n\\n\\n!StrikeFontSet methodsFor: 'emphasis' stamp: 'yo 12/27/2002 13:52'!\\nmakeBoldGlyphs\\n\\t\\\"Make a bold set of glyphs with same widths by ORing 1 bit to the right\\n\\t\\t(requires at least 1 pixel of intercharacter space)\\\"\\n\\n\\t| g bonkForm font |\\n\\t1 to: fontArray size do: [:i |\\n\\t\\tfont _ fontArray at: i.\\n\\t\\tfont ifNotNil: [\\n\\t\\t\\tg _ font glyphs deepCopy.\\n\\t\\t\\tbonkForm _ (Form extent: 1@16) fillBlack offset: -1@0.\\n\\t\\t\\tself bonk: g with: bonkForm at: i.\\n\\t\\t\\tg copyBits: g boundingBox from: g at: (1@0)\\n\\t\\t\\t\\tclippingBox: g boundingBox rule: Form under fillColor: nil.\\n\\t\\t\\t(fontArray at: i) setGlyphs: g.\\n\\t\\t].\\n\\t].\\n! !\\n\\n!StrikeFontSet methodsFor: 'emphasis' stamp: 'yo 12/27/2002 13:51'!\\nmakeItalicGlyphs\\n\\t\\\"Make an italic set of glyphs with same widths by skewing left and right\\n\\t\\t(may require more intercharacter space)\\\"\\n\\n\\t| g bonkForm bc font |\\n\\t1 to: fontArray size do: [:j |\\n\\t\\tfont _ (fontArray at: j).\\n\\t\\tfont ifNotNil: [\\n\\t\\t\\tg _ font glyphs deepCopy.\\n\\t\\t\\t\\\"BonkForm will have bits where slanted characters overlap their neighbors.\\\"\\n\\t\\t\\tbonkForm _ Form extent: (self height//4+2) @ self height.\\n\\t\\t\\tbc _ font descent//4 + 1. \\\"Bonker x-coord corresponding to char boundary.\\\"\\n\\t\\t\\tbonkForm fill: (0 @ 0 corner: (bc+1) @ font ascent) fillColor: Color black.\\n\\t\\t\\t4 to: font ascent-1 by: 4 do:\\n\\t\\t\\t\\t[:y | \\t\\t\\\"Slide ascenders right...\\\"\\n\\t\\t\\t\\tg copy: (1@0 extent: g width @ (font ascent - y))\\n\\t\\t\\t\\t\\tfrom: 0@0 in: g rule: Form over.\\n\\t\\t\\t\\tbonkForm copy: (1@0 extent: bonkForm width @ (font ascent - y))\\n\\t\\t\\t\\t\\tfrom: 0@0 in: bonkForm rule: Form over].\\n\\t\\t\\tbonkForm fill: (0 @ 0 corner: (bc+1) @ font ascent) fillColor: Color white.\\n\\t\\t\\tbonkForm fill: (bc @ font ascent corner: bonkForm extent) fillColor: Color black.\\n\\t\\t\\tfont ascent to: font height-1 by: 4 do:\\n\\t\\t\\t\\t[:y | \\t\\t\\\"Slide descenders left...\\\"\\n\\t\\t\\t\\tg copy: (0@y extent: g width @ g height)\\n\\t\\t\\t\\t\\tfrom: 1@y in: g rule: Form over.\\n\\t\\t\\t\\tbonkForm copy: (0@0 extent: bonkForm width @ bonkForm height)\\n\\t\\t\\t\\t\\tfrom: 1@0 in: bonkForm rule: Form over].\\n\\t\\t\\tbonkForm fill: (bc @ font ascent corner: bonkForm extent) fillColor: Color white.\\n\\t\\t\\t\\\"Now use bonkForm to erase at every character boundary in glyphs.\\\"\\n\\t\\t\\tbonkForm offset: (0-bc) @ 0.\\n\\t\\t\\tfont bonk: g with: bonkForm.\\n\\t\\t\\tfont setGlyphs: g\\n\\t\\t].\\n\\t].\\n! !\\n\\n!StrikeFontSet methodsFor: 'emphasis' stamp: 'yo 12/27/2002 13:53'!\\nmakeStruckOutGlyphs\\n\\t\\\"Make a struck-out set of glyphs with same widths\\\"\\n\\n\\t| g font |\\n\\t1 to: fontArray size do: [:i |\\n\\t\\tfont _ (fontArray at: i).\\n\\t\\tfont ifNotNil: [\\n\\t\\t\\tg _ font glyphs deepCopy.\\n\\t\\t\\tg fillBlack: (0 @ (font ascent - (font ascent//3)) extent: g width @ 1).\\n\\t\\t\\tfont setGlyphs: g\\n\\t\\t].\\n\\t].\\n! !\\n\\n!StrikeFontSet methodsFor: 'emphasis' stamp: 'yo 12/27/2002 13:51'!\\nmakeUnderlinedGlyphs\\n\\t\\\"Make an underlined set of glyphs with same widths\\\"\\n\\n\\t| g font |\\n\\t1 to: fontArray size do: [:i |\\n\\t\\tfont _ (fontArray at: i).\\n\\t\\tfont ifNotNil: [\\n\\t\\t\\tg _ font glyphs deepCopy.\\n\\t\\t\\tg fillBlack: (0 @ (font ascent+1) extent: g width @ 1).\\n\\t\\t\\tfont setGlyphs: g\\n\\t\\t].\\n\\t].\\n! !\\n\\n\\n!StrikeFontSet methodsFor: '*nebraska-as yet unclassified' stamp: 'yo 12/17/2005 20:19'!\\nencodedForRemoteCanvas\\n\\n\\t| stream |\\n\\tstream := RWBinaryOrTextStream on: ''.\\n\\tstream nextPutAll: self familyName.\\n\\tstream nextPut: Character space.\\n\\tstream nextPutAll: self pointSize asString.\\n\\tstream nextPut: Character space.\\n\\tstream nextPutAll: self emphasis asString.\\n\\t^ stream contents asString.\\n! !\\n\\n\\n!StrikeFontSet methodsFor: 'private' stamp: 'yo 12/27/2002 13:39'!\\naddNewFont: aFont at: encodingIndex\\n\\n\\t| newArray |\\n\\tencodingIndex > fontArray size ifTrue: [\\n\\t\\tnewArray _ Array new: encodingIndex.\\n\\t\\tnewArray replaceFrom: 1 to: fontArray size with: fontArray startingAt: 1.\\n\\t] ifFalse: [\\n\\t\\tnewArray _ fontArray.\\n\\t].\\n\\n\\tnewArray at: encodingIndex put: aFont.\\n\\n\\tself initializeWithFontArray: newArray.\\n! !\\n\\n!StrikeFontSet methodsFor: 'private' stamp: 'yo 1/7/2005 11:16'!\\nglyphInfoOf: aCharacter into: glyphInfoArray\\n\\n\\t| index f code leftX |\\n\\tindex _ aCharacter leadingChar + 1.\\n\\tfontArray size < index ifTrue: [^ self questionGlyphInfoInto: glyphInfoArray].\\n\\t(f _ fontArray at: index) ifNil: [^ self questionGlyphInfoInto: glyphInfoArray].\\n\\n\\tcode _ aCharacter charCode.\\n\\t((code between: f minAscii and: f maxAscii) not) ifTrue: [\\n\\t\\t^ self questionGlyphInfoInto: glyphInfoArray.\\n\\t].\\n\\tleftX _ f xTable at: code + 1.\\n\\tleftX < 0 ifTrue: [\\n\\t\\t^ self questionGlyphInfoInto: glyphInfoArray.\\n\\t].\\n\\tglyphInfoArray at: 1 put: f glyphs;\\n\\t\\tat: 2 put: leftX;\\n\\t\\tat: 3 put: (f xTable at: code + 2);\\n\\t\\tat: 4 put: (f ascentOf: aCharacter);\\n\\t\\tat: 5 put: self.\\n\\t^ glyphInfoArray.\\n! !\\n\\n!StrikeFontSet methodsFor: 'private' stamp: 'yo 1/13/2005 16:43'!\\nquestionGlyphInfoInto: glyphInfoArray\\n\\n\\t| f ascii |\\n\\tf _ fontArray at: 1.\\n\\tascii _ $? asciiValue.\\n\\tglyphInfoArray at: 1 put: f glyphs;\\n\\t\\tat: 2 put: (f xTable at: ascii + 1);\\n\\t\\tat: 3 put: (f xTable at: ascii + 2);\\n\\t\\tat: 4 put: (self ascentOf: $?);\\n\\t\\tat: 5 put: self.\\n\\t^ glyphInfoArray.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStrikeFontSet class\\n\\tinstanceVariableNames: ''!\\n\\n!StrikeFontSet class methodsFor: 'as yet unclassified' stamp: 'yo 1/19/2005 11:25'!\\ncreateExternalFontFileForLatin2: fileName\\n\\\"\\n\\tStrikeFontSet createExternalFontFileForLatin2: 'latin2.out'.\\n\\\"\\n\\n\\t| file array f installDirectory |\\n\\tfile _ FileStream newFileNamed: fileName.\\n\\tinstallDirectory _ Smalltalk at: #M17nInstallDirectory ifAbsent: [].\\n\\tinstallDirectory _ installDirectory\\n\\t\\tifNil: [String new]\\n\\t\\tifNotNil: [installDirectory , FileDirectory pathNameDelimiter asString].\\n\\tarray _ Array\\n\\t\\t\\t\\twith: (StrikeFont newFromEFontBDFFile: installDirectory , 'b10.bdf' name: 'LatinTwo9' ranges: EFontBDFFontReaderForRanges rangesForLatin2)\\n\\t\\t\\t\\twith: (StrikeFont newFromEFontBDFFile: installDirectory , 'b12.bdf' name: 'LatinTwo10' ranges: EFontBDFFontReaderForRanges rangesForLatin2)\\n\\t\\t\\t\\twith: (StrikeFont newFromEFontBDFFile: installDirectory , 'b14.bdf' name: 'LatinTwo12' ranges: EFontBDFFontReaderForRanges rangesForLatin2)\\n\\t\\t\\t\\twith: (StrikeFont newFromEFontBDFFile: installDirectory , 'b16.bdf' name: 'LatingTwo14' ranges: EFontBDFFontReaderForRanges rangesForLatin2)\\n\\t\\t\\t\\twith: (StrikeFont newFromEFontBDFFile: installDirectory , 'b24.bdf' name: 'LatinTwo20' ranges: EFontBDFFontReaderForRanges rangesForLatin2).\\n\\tTextConstants at: #forceFontWriting put: true.\\n\\tf _ ReferenceStream on: file.\\n\\tf nextPut: array.\\n\\tfile close.\\n\\tTextConstants removeKey: #forceFontWriting.\\n! !\\n\\n!StrikeFontSet class methodsFor: 'as yet unclassified' stamp: 'yo 5/25/2004 11:05'!\\ncreateExternalFontFileForUnicodeJapanese: fileName\\n\\\"\\n\\tStrikeFontSet createExternalFontFileForUnicodeJapanese: 'uJapaneseFont.out'.\\n\\\"\\n\\n\\t| file array f installDirectory |\\n\\tfile _ FileStream newFileNamed: fileName.\\n\\tinstallDirectory _ Smalltalk at: #M17nInstallDirectory ifAbsent: [].\\n\\tinstallDirectory _ installDirectory\\n\\t\\tifNil: [String new]\\n\\t\\tifNotNil: [installDirectory , FileDirectory pathNameDelimiter asString].\\n\\tarray _ Array\\n\\t\\t\\t\\twith: (StrikeFont newForJapaneseFromEFontBDFFile: installDirectory , 'b12.bdf' name: 'Japanese10' overrideWith: 'shnmk12.bdf')\\n\\t\\t\\t\\twith: ((StrikeFont newForJapaneseFromEFontBDFFile: installDirectory , 'b14.bdf' name: 'Japanese12' overrideWith: 'shnmk14.bdf') \\\"fixAscent: 14 andDescent: 1 head: 1\\\")\\n\\t\\t\\t\\twith: ((StrikeFont newForJapaneseFromEFontBDFFile: 'b16.bdf' name: 'Japanese14' overrideWith: 'shnmk16.bdf') \\\"fixAscent: 16 andDescent: 4 head: 4\\\")\\n\\t\\t\\t\\twith: (StrikeFont newForJapaneseFromEFontBDFFile: installDirectory , 'b24.bdf' name: 'Japanese18' overrideWith: 'kanji24.bdf').\\n\\tTextConstants at: #forceFontWriting put: true.\\n\\tf _ ReferenceStream on: file.\\n\\tf nextPut: array.\\n\\tfile close.\\n\\tTextConstants removeKey: #forceFontWriting.\\n! !\\n\\n!StrikeFontSet class methodsFor: 'as yet unclassified' stamp: 'yo 1/15/2004 16:58'!\\ncreateExternalFontFileForUnicodeKorean: fileName\\n\\\"\\n\\tSmalltalk garbageCollect.\\n\\tStrikeFontSet createExternalFontFileForUnicodeKorean: 'uKoreanFont.out'.\\n\\\"\\n\\n\\t| file array f installDirectory |\\n\\tfile _ FileStream newFileNamed: fileName.\\n\\tinstallDirectory _ Smalltalk at: #M17nInstallDirectory ifAbsent: [].\\n\\tinstallDirectory _ installDirectory\\n\\t\\tifNil: [String new]\\n\\t\\tifNotNil: [installDirectory , FileDirectory pathNameDelimiter asString].\\n\\tarray _ Array\\n\\t\\t\\t\\twith: (StrikeFont newForKoreanFromEFontBDFFile: installDirectory , 'b12.bdf' name: 'Japanese10' overrideWith: 'shnmk12.bdf')\\n\\t\\t\\t\\twith: ((StrikeFont newForKoreanFromEFontBDFFile: installDirectory , 'b14.bdf' name: 'Japanese12' overrideWith: 'shnmk14.bdf') \\\"fixAscent: 14 andDescent: 1 head: 1\\\")\\n\\t\\t\\t\\twith: ((StrikeFont newForKoreanFromEFontBDFFile: installDirectory , 'b16.bdf' name: 'Japanese14' overrideWith: 'hanglg16.bdf') fixAscent: 16 andDescent: 4 head: 4)\\n\\t\\t\\t\\twith: (StrikeFont newForKoreanFromEFontBDFFile: installDirectory , 'b24.bdf' name: 'Japanese18' overrideWith: 'hanglm24.bdf').\\n\\tTextConstants at: #forceFontWriting put: true.\\n\\tf _ ReferenceStream on: file.\\n\\tf nextPut: array.\\n\\tfile close.\\n\\tTextConstants removeKey: #forceFontWriting.\\n! !\\n\\n!StrikeFontSet class methodsFor: 'as yet unclassified' stamp: 'yo 12/17/2005 22:42'!\\ndecodedFromRemoteCanvas: aString\\n\\n\\t| array |\\n\\tarray _ aString findTokens: #($ ).\\n\\t^ self familyName: (array at: 1) size: (array at: 2) asNumber emphasized: (array at: 3) asNumber.\\n! !\\n\\n!StrikeFontSet class methodsFor: 'as yet unclassified' stamp: 'yo 12/27/2002 14:08'!\\nduplicateArrayElementsForLeadingCharShift\\n\\\"\\n\\tself duplicateArrayElementsForLeadingCharShift\\n\\\"\\n\\t| array font |\\n\\tself allInstances do: [:s |\\n\\t\\ts emphasis = 0 ifTrue: [\\n\\t\\t\\tarray _ s fontArray.\\n\\t\\t\\t2 to: (4 min: array size) do: [:i |\\n\\t\\t\\t\\tfont _ array at: i.\\n\\t\\t\\t\\ts addNewFont: font at: ((i - 1) << 2) + 1.\\n\\t\\t\\t].\\n\\t\\t] ifFalse: [\\n\\t\\t\\ts reset\\n\\t\\t].\\n\\t].\\n! !\\n\\n!StrikeFontSet class methodsFor: 'as yet unclassified' stamp: 'yo 8/19/2003 13:04'!\\nfamilyName: aName size: aSize\\n\\t\\\"Answer a font (or the default font if the name is unknown) in the specified size.\\\"\\n\\n\\t| collection |\\n\\tcollection _ self allInstances select: [:inst | (inst name beginsWith: aName) and: [inst emphasis = 0]].\\n\\tcollection isEmpty ifTrue: [\\n\\t\\t(aName = 'DefaultMultiStyle') ifTrue: [\\n\\t\\t\\tcollection _ (TextConstants at: #DefaultMultiStyle) fontArray.\\n\\t\\t] ifFalse: [\\n\\t\\t\\t^ TextStyle defaultFont\\n\\t\\t]\\n\\t].\\n\\tcollection _ collection asSortedCollection: [:a :b | a pointSize <= b pointSize].\\n\\tcollection do: [:s | (s pointSize >= aSize) ifTrue: [^ s]].\\n\\t^ TextStyle defaultFont.\\n! !\\n\\n!StrikeFontSet class methodsFor: 'as yet unclassified' stamp: 'yo 8/18/2003 21:03'!\\nfamilyName: aName size: aSize emphasized: emphasisCode\\n\\t\\\"Create the font with this emphasis\\\"\\n\\n\\t^ (self familyName: aName size: aSize) emphasized: emphasisCode\\n! !\\n\\n!StrikeFontSet class methodsFor: 'as yet unclassified' stamp: 'yo 5/25/2004 14:32'!\\nfindMaximumLessThan: f in: array\\n\\n\\tarray size to: 1 by: -1 do: [:i |\\n\\t\\tf height >= (array at: i) height ifTrue: [^ array at: i].\\n\\t].\\n\\t^ array first.\\n! !\\n\\n!StrikeFontSet class methodsFor: 'as yet unclassified' stamp: 'yo 9/23/2002 16:32'!\\nnewFontArray: anArray\\n \\n\\t^super new initializeWithFontArray: anArray\\n! !\\n\\n\\n!StrikeFontSet class methodsFor: 'fileIn/Out' stamp: 'yo 1/18/2005 16:00'!\\ninstallExternalFontFileName6: fileName encoding: encoding encodingName: aString textStyleName: styleName\\n\\n\\t^ self installExternalFontFileName6: fileName inDir: FileDirectory default encoding: encoding encodingName: aString textStyleName: styleName.\\n\\n\\\"\\nStrikeFontSet createExternalFontFileForCyrillic: 'cyrillicFont.out'.\\n\\nStrikeFontSet installExternalFontFileName6: 'latin2.out' encoding: Latin2Environment leadingChar encodingName: #Latin2 textStyleName: #DefaultMultiStyle.\\nStrikeFontSet installExternalFontFileName6: 'uJapaneseFont.out' encoding: JapaneseEnvironment leadingChar encodingName: #Japanese textStyleName: #DefaultMultiStyle.\\n\\nStrikeFontSet installExternalFontFileName6: 'uKoreanFont.out' encoding: UnicodeKorean leadingChar encodingName: #Korean textStyleName: #DefaultMultiStyle.\\n\\nStrikeFontSet removeFontsForEncoding: 2 encodingName: #Gb2312.\\nself halt.\\nStrikeFontSet removeFontsForEncoding: 3 encodingName: #KsX1001.\\n\\\"\\n! !\\n\\n!StrikeFontSet class methodsFor: 'fileIn/Out' stamp: 'tak 8/3/2005 17:40'!\\ninstallExternalFontFileName6: fileName inDir: dir encoding: encoding encodingName: aString textStyleName: styleName \\n\\t| aStream |\\n\\taStream := dir readOnlyFileNamed: fileName.\\n\\t[self\\n\\t\\tinstallExternalFontOn: aStream\\n\\t\\tencoding: encoding\\n\\t\\tencodingName: aString\\n\\t\\ttextStyleName: styleName]\\n\\t\\tensure: [aStream close]! !\\n\\n!StrikeFontSet class methodsFor: 'fileIn/Out' stamp: 'yo 3/17/2004 10:32'!\\ninstallExternalFontFileName: fileName encoding: encoding encodingName: aString textStyleName: styleName\\n\\n\\t^ self installExternalFontFileName: fileName inDir: FileDirectory default encoding: encoding encodingName: aString textStyleName: styleName.\\n\\n\\\"\\nStrikeFontSet createExternalFontFileForCyrillic: 'cyrillicFont.out'.\\n\\nStrikeFontSet installExternalFontFileName: 'chineseFont.out' encoding: 2 encodingName: #Gb2312 textStyleName: #DefaultMultiStyle.\\nStrikeFontSet installExternalFontFileName: 'japaneseFont.out' encoding: 1 encodingName: #JisX0208 textStyleName: #DefaultMultiStyle.\\nStrikeFontSet installExternalFontFileName: 'defaultFont.out' encoding: 0 encodingName: #Latin1 textStyleName: #DefaultMultiStyle.\\nStrikeFontSet installExternalFontFileName: 'cyrillicFont.out' encoding: UnicodeCyrillic leadingChar encodingName: #Cyrillic textStyleName: #DefaultMultiStyle.\\nStrikeFontSet installExternalFontFileName: 'extendedLatinFont.out' encoding: UnicodeLatinExtendedAB leadingChar encodingName: #ExtendedLatin textStyleName: #DefaultMultiStyle.\\nStrikeFontSet installExternalFontFileName: 'ipaExtensionsFont.out' encoding: UnicodeIPA leadingChar encodingName: #IPAExtensions textStyleName: #DefaultMultiStyle.\\nStrikeFontSet installExternalFontFileName: 'armenianFont.out' encoding: UnicodeArmenian leadingChar encodingName: #Armenian textStyleName: #DefaultMultiStyle.\\nStrikeFontSet installExternalFontFileName: 'greekFont.out' encoding: UnicodeGreek leadingChar encodingName: #Greek textStyleName: #DefaultMultiStyle.\\n\\nStrikeFontSet installExternalFontFileName: 'arrowFont.out' encoding: UnicodeArrows leadingChar encodingName: #Arrow textStyleName: #DefaultMultiStyle.\\n\\nStrikeFontSet installExternalFontFileName: 'uJapaneseFont.out' indir: FileDirectory default encoding: JapaneseEnvironment leadingChar encodingName: #Japanese textStyleName: #DefaultMultiStyle.\\n\\nStrikeFontSet installExternalFontFileName: 'uKoreanFont.out' encoding: UnicodeKorean leadingChar encodingName: #Korean textStyleName: #DefaultMultiStyle.\\n\\nStrikeFontSet removeFontsForEncoding: 2 encodingName: #Gb2312.\\nself halt.\\nStrikeFontSet removeFontsForEncoding: 3 encodingName: #KsX1001.\\n\\\"\\n! !\\n\\n!StrikeFontSet class methodsFor: 'fileIn/Out' stamp: 'yo 8/19/2003 00:32'!\\ninstallExternalFontFileName: fileName inDir: dir encoding: encoding encodingName: aString textStyleName: styleName\\n\\n\\t| array arrayFour oldStyle arrayOfFS fs fonts newFonts |\\n\\tarray _ (ReferenceStream on: (dir readOnlyFileNamed: fileName)) next.\\n\\n\\tarrayFour _ Array new: 4 withAll: array last.\\n\\tarrayFour replaceFrom: 1 to: array size with: array startingAt: 1.\\n\\tTextConstants at: aString asSymbol put: arrayFour.\\n\\n\\toldStyle _ TextConstants at: styleName asSymbol.\\n\\tarrayOfFS _ oldStyle fontArray.\\n\\tarrayOfFS _ (1 to: 4) collect: [:i |\\n\\t\\tfs _ arrayOfFS at: i.\\n\\t\\tfonts _ fs fontArray.\\n\\t\\tencoding + 1 > fonts size ifTrue: [\\n\\t\\t\\tnewFonts _ Array new: encoding + 1.\\n\\t\\t\\tnewFonts replaceFrom: 1 to: fonts size with: fonts startingAt: 1.\\n\\t\\t\\tnewFonts at: encoding + 1 put: (arrayFour at: i).\\n\\t\\t\\tfs initializeWithFontArray: newFonts.\\n\\t\\t] ifFalse: [\\n\\t\\t\\tfonts at: encoding + 1 put: (arrayFour at: i).\\n\\t\\t].\\n\\t\\tfs.\\n\\t].\\n\\n\\tTextConstants at: styleName asSymbol put: (TextStyle fontArray: arrayOfFS).\\n\\toldStyle becomeForward: (TextConstants at: styleName asSymbol).\\n\\n! !\\n\\n!StrikeFontSet class methodsFor: 'fileIn/Out' stamp: 'tak 8/5/2005 10:34'!\\ninstallExternalFontOn: aStream encoding: encoding encodingName: aString textStyleName: styleName\\n\\n\\t| array fonts encodingIndex textStyle |\\n\\n\\tarray _ aStream\\n\\t\\tuntilEndWithFork: [(ReferenceStream on: aStream) next]\\n\\t\\tdisplayingProgress: 'Font reading...'. \\n\\t\\n\\tTextConstants at: aString asSymbol put: array.\\n\\n\\ttextStyle _ TextConstants at: styleName asSymbol.\\n\\tencodingIndex _ encoding + 1.\\n\\ttextStyle fontArray do: [:fs |\\n\\t\\tfonts _ fs fontArray.\\n\\t\\tencodingIndex > fonts size\\n\\t\\t\\tifTrue: [fonts _ (Array new: encodingIndex)\\n\\t\\t\\t\\treplaceFrom: 1 to: fonts size with: fonts startingAt: 1].\\n\\t\\tfonts at: encodingIndex put: (self findMaximumLessThan: fs fontArray first in: array).\\n\\t\\tfs initializeWithFontArray: fonts.\\n\\t].\\n! !\\n\\n!StrikeFontSet class methodsFor: 'fileIn/Out' stamp: 'tak 8/4/2005 11:03'!\\ninstallExternalFontOn: aStream forLocale: locale \\n\\tself\\n\\t\\tinstallExternalFontOn: aStream\\n\\t\\tencoding: locale languageEnvironment leadingChar\\n\\t\\tencodingName: locale languageEnvironment fontEncodingName\\n\\t\\ttextStyleName: #DefaultMultiStyle! !\\n\\n!StrikeFontSet class methodsFor: 'fileIn/Out' stamp: 'yo 1/15/2004 16:06'!\\ninstallNewFontAtIndex: newIndex fromOld: oldIndex\\n\\n\\t| fontArray newArray |\\n\\tself allInstances do: [:set |\\n\\t\\tfontArray _ set fontArray.\\n\\t\\tnewIndex + 1 > fontArray size ifTrue: [\\n\\t\\t\\tnewArray _ Array new: newIndex + 1.\\n\\t\\t\\tnewArray replaceFrom: 1 to: fontArray size with: fontArray startingAt: 1.\\n\\t\\t\\tnewArray at: newIndex + 1 put: (fontArray at: oldIndex + 1).\\n\\t\\t\\tset initializeWithFontArray: newArray.\\n\\t\\t] ifFalse: [\\n\\t\\t\\tfontArray at: newIndex + 1 put: (fontArray at: oldIndex + 1).\\n\\t\\t].\\n\\t].\\n\\n\\\"\\nStrikeFontSet installNewFontAtIndex: UnicodeSimplifiedChinese leadingChar fromOld: UnicodeJapanese leadingChar\\nStrikeFontSet installNewFontAtIndex: UnicodeKorean leadingChar fromOld: UnicodeJapanese leadingChar\\n\\\"\\n! !\\n\\n!StrikeFontSet class methodsFor: 'fileIn/Out' stamp: 'tak 8/4/2005 14:41'!\\nremoveFontsForEncoding: leadingChar encodingName: encodingSymbol\\n\\n\\t| insts fonts newFonts index |\\n\\tleadingChar = 0 ifTrue: [^ self error: 'you cannot delete the intrinsic fonts'].\\n\\tinsts _ self allInstances.\\n\\tinsts do: [:inst |\\n\\t\\tfonts _ inst fontArray.\\n\\t\\tfonts size >= (leadingChar + 1) ifTrue: [\\n\\t\\t\\tleadingChar + 1 = fonts size ifTrue: [\\n\\t\\t\\t\\tnewFonts _ fonts copyFrom: 1 to: fonts size - 1.\\n\\t\\t\\t\\tindex _ newFonts indexOf: nil.\\n\\t\\t\\t\\tindex > 0 ifTrue: [newFonts _ newFonts copyFrom: 1 to: index - 1].\\n\\t\\t\\t\\tinst initializeWithFontArray: newFonts.\\n\\t\\t\\t] ifFalse: [\\n\\t\\t\\t\\tfonts at: leadingChar + 1 put: nil.\\n\\t\\t\\t].\\n\\t\\t].\\n\\t].\\n\\n\\tTextConstants removeKey: encodingSymbol asSymbol ifAbsent: [].\\n! !\\nArrayedCollection subclass: #String\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'AsciiOrder CSLineEnders CSNonSeparators CSSeparators CaseInsensitiveOrder CaseSensitiveOrder HtmlEntities LowercasingTable Tokenish UppercasingTable'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Collections-Strings'!\\n!String commentStamp: '<historical>' prior: 0!\\nA String is an indexed collection of Characters. Class String provides the abstract super class for ByteString (that represents an array of 8-bit Characters) and WideString (that represents an array of 32-bit characters). In the similar manner of LargeInteger and SmallInteger, those subclasses are chosen accordingly for a string; namely as long as the system can figure out so, the String is used to represent the given string.\\n\\nStrings support a vast array of useful methods, which can best be learned by browsing and trying out examples as you find them in the code.\\n\\nHere are a few useful methods to look at...\\n\\tString match:\\n\\tString contractTo:\\n\\nString also inherits many useful methods from its hierarchy, such as\\n\\tSequenceableCollection ,\\n\\tSequenceableCollection copyReplaceAll:with:\\n!\\n]style[(55 376 188 13 2 18 72 24 2 44)f1,f2,f1,f1LString match:;,f1,f1LString contractTo:;,f1,f1LSequenceableCollection ,;,f1,f1LSequenceableCollection copyReplaceAll:with:;!\\n\\n\\n!String methodsFor: 'accessing' stamp: 'ar 4/12/2005 16:30'!\\nbyteAt: index\\n\\t^self subclassResponsibility! !\\n\\n!String methodsFor: 'accessing' stamp: 'ar 4/12/2005 16:30'!\\nbyteAt: index put: value\\n\\t^self subclassResponsibility! !\\n\\n!String methodsFor: 'accessing' stamp: 'ar 4/12/2005 16:30'!\\nbyteSize\\n\\t^self subclassResponsibility! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\ndo: aBlock toFieldNumber: aNumber\\n\\t\\\"Considering the receiver as a holder of tab-delimited fields, evaluate aBlock on behalf of a field in this string\\\"\\n\\n\\t| start end index |\\n\\tstart _ 1.\\n\\tindex _ 1.\\n\\t[start <= self size] whileTrue: \\n\\t\\t[end _ self indexOf: Character tab startingAt: start ifAbsent: [self size + 1].\\n\\t\\tend _ end - 1.\\n\\t\\taNumber = index ifTrue:\\n\\t\\t\\t[aBlock value: (self copyFrom: start to: end).\\n\\t\\t\\t^ self].\\n\\t\\tindex _ index + 1.\\n\\t\\tstart _ end + 2]\\n\\n\\\"\\n1 to: 6 do:\\n\\t[:aNumber |\\n\\t\\t'fred\\tcharlie\\telmo\\t\\twimpy\\tfriml' do:\\n\\t\\t\\t[:aField | Transcript cr; show: aField] toFieldNumber: aNumber]\\n\\\"! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nendsWithDigit\\n\\t\\\"Answer whether the receiver's final character represents a digit. 3/11/96 sw\\\"\\n\\n\\t^ self size > 0 and: [self last isDigit]! !\\n\\n!String methodsFor: 'accessing' stamp: 'ar 4/10/2005 17:12'!\\nfindAnySubStr: delimiters startingAt: start \\n\\t\\\"Answer the index of the character within the receiver, starting at start, that begins a substring matching one of the delimiters. delimiters is an Array of Strings (Characters are permitted also). If the receiver does not contain any of the delimiters, answer size + 1.\\\"\\n\\n\\t| min ind |\\n\\tmin _ self size + 1.\\n\\tdelimiters do: [:delim |\\t\\\"May be a char, a string of length 1, or a substring\\\"\\n\\t\\tdelim isCharacter \\n\\t\\t\\tifTrue: [ind _ self indexOfSubCollection: (String with: delim) \\n\\t\\t\\t\\t\\t\\tstartingAt: start ifAbsent: [min]]\\n\\t\\t\\tifFalse: [ind _ self indexOfSubCollection: delim \\n\\t\\t\\t\\t\\t\\tstartingAt: start ifAbsent: [min]].\\n\\t\\t\\tmin _ min min: ind].\\n\\t^ min! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nfindBetweenSubStrs: delimiters\\n\\t\\\"Answer the collection of String tokens that result from parsing self. Tokens are separated by 'delimiters', which can be a collection of Strings, or a collection of Characters. Several delimiters in a row are considered as just one separation.\\\"\\n\\n\\t| tokens keyStart keyStop |\\n\\ttokens _ OrderedCollection new.\\n\\tkeyStop _ 1.\\n\\t[keyStop <= self size] whileTrue:\\n\\t\\t[keyStart _ self skipAnySubStr: delimiters startingAt: keyStop.\\n\\t\\tkeyStop _ self findAnySubStr: delimiters startingAt: keyStart.\\n\\t\\tkeyStart < keyStop\\n\\t\\t\\tifTrue: [tokens add: (self copyFrom: keyStart to: (keyStop - 1))]].\\n\\t^tokens! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nfindCloseParenthesisFor: startIndex\\n\\t\\\"assume (self at: startIndex) is $(. Find the matching $), allowing parentheses to nest.\\\"\\n\\t\\\" '(1+(2-3))-3.14159' findCloseParenthesisFor: 1 \\\"\\n\\t\\\" '(1+(2-3))-3.14159' findCloseParenthesisFor: 4 \\\"\\n\\t| pos nestLevel |\\n\\tpos := startIndex+1.\\n\\tnestLevel := 1.\\n\\t[ pos <= self size ] whileTrue: [\\n\\t\\t(self at: pos) = $( ifTrue: [ nestLevel := nestLevel + 1 ].\\n\\t\\t(self at: pos) = $) ifTrue: [ nestLevel := nestLevel - 1 ].\\n\\t\\tnestLevel = 0 ifTrue: [ ^pos ].\\n\\t\\tpos := pos + 1.\\n\\t].\\n\\t^self size + 1! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nfindDelimiters: delimiters startingAt: start \\n\\t\\\"Answer the index of the character within the receiver, starting at start, that matches one of the delimiters. If the receiver does not contain any of the delimiters, answer size + 1.\\\"\\n\\n\\tstart to: self size do: [:i |\\n\\t\\tdelimiters do: [:delim | delim = (self at: i) ifTrue: [^ i]]].\\n\\t^ self size + 1! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 10/15/2003 15:32'!\\nfindLastOccuranceOfString: subString startingAt: start \\n\\t\\\"Answer the index of the last occurance of subString within the receiver, starting at start. If \\n\\tthe receiver does not contain subString, answer 0.\\\"\\n\\n\\t| last now |\\n\\tlast _ self findSubstring: subString in: self startingAt: start matchTable: CaseSensitiveOrder.\\n\\tlast = 0 ifTrue: [^ 0].\\n\\t[last > 0] whileTrue: [\\n\\t\\tnow _ last.\\n\\t\\tlast _ self findSubstring: subString in: self startingAt: last + subString size matchTable: CaseSensitiveOrder.\\n\\t].\\n\\n\\t^ now.\\n! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nfindString: subString\\n\\t\\\"Answer the index of subString within the receiver, starting at start. If \\n\\tthe receiver does not contain subString, answer 0.\\\"\\n\\t^self findString: subString startingAt: 1.! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nfindString: subString startingAt: start \\n\\t\\\"Answer the index of subString within the receiver, starting at start. If \\n\\tthe receiver does not contain subString, answer 0.\\\"\\n\\n\\t^ self findSubstring: subString in: self startingAt: start matchTable: CaseSensitiveOrder! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nfindString: key startingAt: start caseSensitive: caseSensitive\\n\\t\\\"Answer the index in this String at which the substring key first occurs, at or beyond start. The match can be case-sensitive or not. If no match is found, zero will be returned.\\\"\\n\\n\\tcaseSensitive\\n\\tifTrue: [^ self findSubstring: key in: self startingAt: start matchTable: CaseSensitiveOrder]\\n\\tifFalse: [^ self findSubstring: key in: self startingAt: start matchTable: CaseInsensitiveOrder]! !\\n\\n!String methodsFor: 'accessing' stamp: 'ar 4/10/2005 17:13'!\\nfindTokens: delimiters\\n\\t\\\"Answer the collection of tokens that result from parsing self. Return strings between the delimiters. Any character in the Collection delimiters marks a border. Several delimiters in a row are considered as just one separation. Also, allow delimiters to be a single character.\\\"\\n\\n\\t| tokens keyStart keyStop separators |\\n\\n\\ttokens _ OrderedCollection new.\\n\\tseparators _ delimiters isCharacter \\n\\t\\tifTrue: [Array with: delimiters]\\n\\t\\tifFalse: [delimiters].\\n\\tkeyStop _ 1.\\n\\t[keyStop <= self size] whileTrue:\\n\\t\\t[keyStart _ self skipDelimiters: separators startingAt: keyStop.\\n\\t\\tkeyStop _ self findDelimiters: separators startingAt: keyStart.\\n\\t\\tkeyStart < keyStop\\n\\t\\t\\tifTrue: [tokens add: (self copyFrom: keyStart to: (keyStop - 1))]].\\n\\t^tokens! !\\n\\n!String methodsFor: 'accessing' stamp: 'dtl 8/14/2004 11:27'!\\nfindTokens: delimiters escapedBy: quoteDelimiters \\n\\t\\\"Answer a collection of Strings separated by the delimiters, where \\n\\tdelimiters is a Character or collection of characters. Two delimiters in a \\n\\trow produce an empty string (compare this to #findTokens, which \\n\\ttreats sequential delimiters as one). \\n\\t \\n\\tThe characters in quoteDelimiters are treated as quote characters, such \\n\\tthat any delimiter within a pair of matching quoteDelimiter characters \\n\\tis treated literally, rather than as a delimiter. \\n\\t \\n\\tThe quoteDelimiter characters may be escaped within a quoted string. \\n\\tTwo sequential quote characters within a quoted string are treated as \\n\\ta single character. \\n\\t \\n\\tThis method is useful for parsing comma separated variable strings for \\n\\tspreadsheet import and export.\\\"\\n\\n\\t| tokens rs activeEscapeCharacter ts char token delimiterChars quoteChars |\\n\\tdelimiterChars _ (delimiters isNil\\n\\t\\t\\t\\tifTrue: ['']\\n\\t\\t\\t\\tifFalse: [delimiters]) asString.\\n\\tquoteChars _ (quoteDelimiters isNil\\n\\t\\t\\t\\tifTrue: ['']\\n\\t\\t\\t\\tifFalse: [quoteDelimiters]) asString.\\n\\ttokens _ OrderedCollection new.\\n\\trs _ ReadStream on: self.\\n\\tactiveEscapeCharacter _ nil.\\n\\tts _ WriteStream on: ''.\\n\\t[rs atEnd]\\n\\t\\twhileFalse: [char _ rs next.\\n\\t\\t\\tactiveEscapeCharacter isNil\\n\\t\\t\\t\\tifTrue: [(quoteChars includes: char)\\n\\t\\t\\t\\t\\t\\tifTrue: [activeEscapeCharacter _ char]\\n\\t\\t\\t\\t\\t\\tifFalse: [(delimiterChars includes: char)\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [token _ ts contents.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\ttokens add: token.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tts _ WriteStream on: '']\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [ts nextPut: char]]]\\n\\t\\t\\t\\tifFalse: [char == activeEscapeCharacter\\n\\t\\t\\t\\t\\t\\tifTrue: [rs peek == activeEscapeCharacter\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [ts nextPut: rs next]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [activeEscapeCharacter _ nil]]\\n\\t\\t\\t\\t\\t\\tifFalse: [ts nextPut: char]]].\\n\\ttoken _ ts contents.\\n\\t(tokens isEmpty and: [token isEmpty])\\n\\t\\tifFalse: [tokens add: token].\\n\\t^ tokens! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nfindTokens: delimiters includes: subString\\n\\t\\\"Divide self into pieces using delimiters. Return the piece that includes subString anywhere in it. Is case sensitive (say asLowercase to everything beforehand to make insensitive).\\\"\\n\\n^ (self findTokens: delimiters) \\n\\tdetect: [:str | (str includesSubString: subString)] \\n\\tifNone: [nil]! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nfindTokens: delimiters keep: keepers\\n\\t\\\"Answer the collection of tokens that result from parsing self. The tokens are seperated by delimiters, any of a string of characters. If a delimiter is also in keepers, make a token for it. (Very useful for carriage return. A sole return ends a line, but is also saved as a token so you can see where the line breaks were.)\\\"\\n\\n\\t| tokens keyStart keyStop |\\n\\ttokens _ OrderedCollection new.\\n\\tkeyStop _ 1.\\n\\t[keyStop <= self size] whileTrue:\\n\\t\\t[keyStart _ self skipDelimiters: delimiters startingAt: keyStop.\\n\\t\\tkeyStop to: keyStart-1 do: [:ii | \\n\\t\\t\\t(keepers includes: (self at: ii)) ifTrue: [\\n\\t\\t\\t\\ttokens add: (self copyFrom: ii to: ii)]].\\t\\\"Make this keeper be a token\\\"\\n\\t\\tkeyStop _ self findDelimiters: delimiters startingAt: keyStart.\\n\\t\\tkeyStart < keyStop\\n\\t\\t\\tifTrue: [tokens add: (self copyFrom: keyStart to: (keyStop - 1))]].\\n\\t^tokens! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nfindWordStart: key startingAt: start\\n\\t| ind |\\n\\t\\\"HyperCard style searching. Answer the index in self of the substring key, when that key is preceeded by a separator character. Must occur at or beyond start. The match is case-insensitive. If no match is found, zero will be returned.\\\"\\n\\n\\tind _ start.\\n\\t[ind _ self findSubstring: key in: self startingAt: ind matchTable: CaseInsensitiveOrder.\\n\\tind = 0 ifTrue: [^ 0].\\t\\\"not found\\\"\\n\\tind = 1 ifTrue: [^ 1].\\t\\\"First char is the start of a word\\\"\\n\\t(self at: ind-1) isSeparator] whileFalse: [ind _ ind + 1].\\n\\t^ ind\\t\\\"is a word start\\\"! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nincludesSubString: subString\\n\\t^ (self findString: subString startingAt: 1) > 0! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nincludesSubstring: aString caseSensitive: caseSensitive\\n\\t\\n\\t^ (self findString: aString startingAt: 1 caseSensitive: caseSensitive) > 0! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 8/28/2002 16:45'!\\nindexOf: aCharacter\\n\\n\\taCharacter isCharacter ifFalse: [^ 0].\\n\\t^ self class\\n\\t\\tindexOfAscii: aCharacter asciiValue\\n\\t\\tinString: self\\n\\t\\tstartingAt: 1.\\n! !\\n\\n!String methodsFor: 'accessing' stamp: 'ar 4/12/2005 16:31'!\\nindexOf: aCharacter startingAt: start\\n\\n\\t(aCharacter isCharacter) ifFalse: [^ 0].\\n\\t^ self class indexOfAscii: aCharacter asciiValue inString: self startingAt: start! !\\n\\n!String methodsFor: 'accessing' stamp: 'ar 4/12/2005 16:31'!\\nindexOf: aCharacter startingAt: start ifAbsent: aBlock\\n\\t| ans |\\n\\t(aCharacter isCharacter) ifFalse: [ ^ aBlock value ].\\n\\tans _ self class indexOfAscii: aCharacter asciiValue inString: self startingAt: start.\\n\\tans = 0\\n\\t\\tifTrue: [ ^ aBlock value ]\\n\\t\\tifFalse: [ ^ ans ]! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nindexOfAnyOf: aCharacterSet\\n\\t\\\"returns the index of the first character in the given set. Returns 0 if none are found\\\"\\n\\t^self indexOfAnyOf: aCharacterSet startingAt: 1! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nindexOfAnyOf: aCharacterSet ifAbsent: aBlock\\n\\t\\\"returns the index of the first character in the given set. Returns the evaluation of aBlock if none are found\\\"\\n\\t^self indexOfAnyOf: aCharacterSet startingAt: 1 ifAbsent: aBlock! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nindexOfAnyOf: aCharacterSet startingAt: start\\n\\t\\\"returns the index of the first character in the given set, starting from start. Returns 0 if none are found\\\"\\n\\t^self indexOfAnyOf: aCharacterSet startingAt: start ifAbsent: [ 0 ]! !\\n\\n!String methodsFor: 'accessing' stamp: 'ar 4/10/2005 16:22'!\\nindexOfAnyOf: aCharacterSet startingAt: start ifAbsent: aBlock\\n\\t\\\"returns the index of the first character in the given set, starting from start\\\"\\n\\n\\t| ans |\\n\\tans _ self class findFirstInString: self inSet: aCharacterSet byteArrayMap startingAt: start.\\n\\n\\tans = 0 \\n\\t\\tifTrue: [ ^aBlock value ]\\n\\t\\tifFalse: [ ^ans ]! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nindexOfSubCollection: sub \\n\\t#Collectn.\\n\\t\\\"Added 2000/04/08 For ANSI <sequenceReadableCollection> protocol.\\\"\\n\\t^ self\\n\\t\\tindexOfSubCollection: sub\\n\\t\\tstartingAt: 1\\n\\t\\tifAbsent: [0]! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nindexOfSubCollection: sub startingAt: start ifAbsent: exceptionBlock\\n\\t| index |\\n\\tindex _ self findSubstring: sub in: self startingAt: start matchTable: CaseSensitiveOrder.\\n\\tindex = 0 ifTrue: [^ exceptionBlock value].\\n\\t^ index! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nlastIndexOfPKSignature: aSignature\\n\\t\\\"Answer the last index in me where aSignature (4 bytes long) occurs, or 0 if not found\\\"\\n\\t| a b c d |\\n\\ta _ aSignature first.\\n\\tb _ aSignature second.\\n\\tc _ aSignature third.\\n\\td _ aSignature fourth.\\n\\t(self size - 3) to: 1 by: -1 do: [ :i |\\n\\t\\t(((self at: i) = a)\\n\\t\\t\\tand: [ ((self at: i + 1) = b)\\n\\t\\t\\t\\tand: [ ((self at: i + 2) = c)\\n\\t\\t\\t\\t\\tand: [ ((self at: i + 3) = d) ]]])\\n\\t\\t\\t\\t\\t\\tifTrue: [ ^i ]\\n\\t].\\n\\t^0! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 12/17/2002 16:56'!\\nleadingCharRunLengthAt: index\\n\\n\\t| leadingChar |\\n\\tleadingChar _ (self at: index) leadingChar.\\n\\tindex to: self size do: [:i |\\n\\t\\t(self at: i) leadingChar ~= leadingChar ifTrue: [^ i - index].\\n\\t].\\n\\t^ self size - index + 1.\\n! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 8/27/2002 14:33'!\\nlineCorrespondingToIndex: anIndex\\n\\t\\\"Answer a string containing the line at the given character position. 1/15/96 sw: Inefficient first stab at this\\\"\\n\\n\\t| cr aChar answer |\\n\\tcr _ Character cr.\\n\\tanswer _ ''.\\n\\t1 to: self size do:\\n\\t\\t[:i | \\n\\t\\t\\taChar _ self at: i.\\n\\t\\t\\taChar = cr\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[i > anIndex\\n\\t\\t\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t\\t\\t[^ answer]\\n\\t\\t\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t\\t\\t[answer _ '']]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[answer _ answer copyWith: aChar]].\\n\\t^ answer! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 8/27/2002 14:34'!\\nlineCount\\n\\t\\\"Answer the number of lines represented by the receiver, where every cr adds one line. 5/10/96 sw\\\"\\n\\n\\t| cr count |\\n\\tcr _ Character cr.\\n\\tcount _ 1 min: self size..\\n\\t1 to: self size do:\\n\\t\\t[:i | (self at: i) = cr ifTrue: [count _ count + 1]].\\n\\t^ count\\n\\n\\\"\\n'Fred\\nthe\\nBear' lineCount\\n\\\"! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 8/27/2002 14:34'!\\nlineNumber: anIndex\\n\\t\\\"Answer a string containing the characters in the given line number. 5/10/96 sw\\\"\\n\\n\\t| crString pos finalPos |\\n\\tcrString _ String with: Character cr.\\n\\tpos _ 0.\\n\\t1 to: anIndex - 1 do:\\n\\t\\t[:i | pos _ self findString: crString startingAt: pos + 1.\\n\\t\\t\\tpos = 0 ifTrue: [^ nil]].\\n\\tfinalPos _ self findString: crString startingAt: pos + 1.\\n\\tfinalPos = 0 ifTrue: [finalPos _ self size + 1].\\n\\t^ self copyFrom: pos + 1 to: finalPos - 1\\n\\n\\\"\\n'Fred\\nthe\\nBear' lineNumber: 3\\n\\\"! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nlinesDo: aBlock\\n\\t\\\"execute aBlock with each line in this string. The terminating CR's are not included in what is passed to aBlock\\\"\\n\\t| start end |\\n\\tstart _ 1.\\n\\t[ start <= self size ] whileTrue: [\\n\\t\\tend _ self indexOf: Character cr startingAt: start ifAbsent: [ self size + 1 ].\\n\\t\\tend _ end - 1.\\n\\n\\t\\taBlock value: (self copyFrom: start to: end).\\n\\t\\tstart _ end + 2. ].! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 8/28/2002 14:28'!\\nskipAnySubStr: delimiters startingAt: start \\n\\t\\\"Answer the index of the last character within the receiver, starting at start, that does NOT match one of the delimiters. delimiters is a Array of substrings (Characters also allowed). If the receiver is all delimiters, answer size + 1.\\\"\\n\\n\\t| any this ind ii |\\n\\tii _ start-1.\\n\\t[(ii _ ii + 1) <= self size] whileTrue: [ \\\"look for char that does not match\\\"\\n\\t\\tany _ false.\\n\\t\\tdelimiters do: [:delim |\\n\\t\\t\\tdelim isCharacter \\n\\t\\t\\t\\tifTrue: [(self at: ii) == delim ifTrue: [any _ true]]\\n\\t\\t\\t\\tifFalse: [\\\"a substring\\\"\\n\\t\\t\\t\\t\\tdelim size > (self size - ii + 1) ifFalse: \\\"Here's where the one-off error was.\\\"\\n\\t\\t\\t\\t\\t\\t[ind _ 0.\\n\\t\\t\\t\\t\\t\\tthis _ true.\\n\\t\\t\\t\\t\\t\\tdelim do: [:dd | \\n\\t\\t\\t\\t\\t\\t\\tdd == (self at: ii+ind) ifFalse: [this _ false].\\n\\t\\t\\t\\t\\t\\t\\tind _ ind + 1].\\n\\t\\t\\t\\t\\t\\tthis ifTrue: [ii _ ii + delim size - 1. any _ true]]\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [any _ false] \\\"if the delim is too big, it can't match\\\"]].\\n\\t\\tany ifFalse: [^ ii]].\\n\\t^ self size + 1! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nskipDelimiters: delimiters startingAt: start \\n\\t\\\"Answer the index of the character within the receiver, starting at start, that does NOT match one of the delimiters. If the receiver does not contain any of the delimiters, answer size + 1. Assumes the delimiters to be a non-empty string.\\\"\\n\\n\\tstart to: self size do: [:i |\\n\\t\\tdelimiters detect: [:delim | delim = (self at: i)]\\n\\t\\t\\t\\tifNone: [^ i]].\\n\\t^ self size + 1! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\nstartsWithDigit\\n\\t\\\"Answer whether the receiver's first character represents a digit\\\"\\n\\n\\t^ self size > 0 and: [self first isDigit]! !\\n\\n!String methodsFor: 'accessing' stamp: 'md 5/26/2005 13:35'!\\nstring\\n\\t^self! !\\n\\n!String methodsFor: 'accessing' stamp: 'yo 11/3/2004 19:24'!\\ntabDelimitedFieldsDo: aBlock\\n\\t\\\"Considering the receiver as a holder of tab-delimited fields, evaluate execute aBlock with each field in this string. The separatilng tabs are not included in what is passed to aBlock\\\"\\n\\n\\t| start end |\\n\\t\\\"No senders but was useful enough in earlier work that it's retained for the moment.\\\"\\n\\tstart _ 1.\\n\\t[start <= self size] whileTrue: \\n\\t\\t[end _ self indexOf: Character tab startingAt: start ifAbsent: [self size + 1].\\n\\t\\tend _ end - 1.\\n\\t\\taBlock value: (self copyFrom: start to: end).\\n\\t\\tstart _ end + 2]\\n\\n\\\"\\n'fred\\tcharlie\\telmo\\t\\t2' tabDelimitedFieldsDo: [:aField | Transcript cr; show: aField]\\n\\\"! !\\n\\n\\n!String methodsFor: 'arithmetic' stamp: 'yo 11/3/2004 19:24'!\\n* arg\\n\\n\\t^ arg adaptToString: self andSend: #*! !\\n\\n!String methodsFor: 'arithmetic' stamp: 'yo 11/3/2004 19:24'!\\n+ arg\\n\\n\\t^ arg adaptToString: self andSend: #+! !\\n\\n!String methodsFor: 'arithmetic' stamp: 'yo 11/3/2004 19:24'!\\n- arg\\n\\n\\t^ arg adaptToString: self andSend: #-! !\\n\\n!String methodsFor: 'arithmetic' stamp: 'yo 11/3/2004 19:24'!\\n/ arg\\n\\n\\t^ arg adaptToString: self andSend: #/! !\\n\\n!String methodsFor: 'arithmetic' stamp: 'yo 11/3/2004 19:24'!\\n// arg\\n\\n\\t^ arg adaptToString: self andSend: #//! !\\n\\n!String methodsFor: 'arithmetic' stamp: 'yo 11/3/2004 19:24'!\\n\\\\\\\\ arg\\n\\n\\t^ arg adaptToString: self andSend: #\\\\\\\\! !\\n\\n\\n!String methodsFor: 'comparing' stamp: 'lr 7/7/2006 11:19'!\\n< aString \\n\\t\\\"Answer whether the receiver sorts before aString.\\n\\tThe collation order is simple ascii (with case differences).\\\"\\n\\n\\t^ (self compare: self with: aString collated: AsciiOrder) = 1! !\\n\\n!String methodsFor: 'comparing' stamp: 'lr 7/7/2006 11:20'!\\n<= aString \\n\\t\\\"Answer whether the receiver sorts before or equal to aString.\\n\\tThe collation order is simple ascii (with case differences).\\\"\\n\\t\\n\\t^ (self compare: self with: aString collated: AsciiOrder) <= 2! !\\n\\n!String methodsFor: 'comparing' stamp: 'lr 7/7/2006 11:21'!\\n= aString \\n\\t\\\"Answer whether the receiver sorts equally as aString.\\n\\tThe collation order is simple ascii (with case differences).\\\"\\n\\t\\n\\taString isString ifFalse: [ ^ false ].\\n\\t^ (self compare: self with: aString collated: AsciiOrder) = 2! !\\n\\n!String methodsFor: 'comparing' stamp: 'lr 7/7/2006 11:21'!\\n> aString \\n\\t\\\"Answer whether the receiver sorts after aString.\\n\\tThe collation order is simple ascii (with case differences).\\\"\\n\\n\\t^ (self compare: self with: aString collated: AsciiOrder) = 3! !\\n\\n!String methodsFor: 'comparing' stamp: 'lr 7/7/2006 11:21'!\\n>= aString \\n\\t\\\"Answer whether the receiver sorts after or equal to aString.\\n\\tThe collation order is simple ascii (with case differences).\\\"\\n\\n\\t^ (self compare: self with: aString collated: AsciiOrder) >= 2! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 11/3/2004 19:24'!\\nalike: aString \\n\\t\\\"Answer some indication of how alike the receiver is to the argument, 0 is no match, twice aString size is best score. Case is ignored.\\\"\\n\\n\\t| i j k minSize bonus |\\n\\tminSize _ (j _ self size) min: (k _ aString size).\\n\\tbonus _ (j - k) abs < 2 ifTrue: [ 1 ] ifFalse: [ 0 ].\\n\\ti _ 1.\\n\\t[(i <= minSize) and: [((super at: i) bitAnd: 16rDF) = ((aString at: i) asciiValue bitAnd: 16rDF)]]\\n\\t\\twhileTrue: [ i _ i + 1 ].\\n\\t[(j > 0) and: [(k > 0) and:\\n\\t\\t[((super at: j) bitAnd: 16rDF) = ((aString at: k) asciiValue bitAnd: 16rDF)]]]\\n\\t\\t\\twhileTrue: [ j _ j - 1. k _ k - 1. ].\\n\\t^ i - 1 + self size - j + bonus. ! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 11/3/2004 19:24'!\\nbeginsWith: prefix\\n\\t\\\"Answer whether the receiver begins with the given prefix string.\\n\\tThe comparison is case-sensitive.\\\"\\n\\n\\tself size < prefix size ifTrue: [^ false].\\n\\t^ (self findSubstring: prefix in: self startingAt: 1\\n\\t\\t\\tmatchTable: CaseSensitiveOrder) = 1\\n! !\\n\\n!String methodsFor: 'comparing' stamp: 'ar 4/10/2005 16:39'!\\ncaseInsensitiveLessOrEqual: aString \\n\\t\\\"Answer whether the receiver sorts before or equal to aString.\\n\\tThe collation order is case insensitive.\\\"\\n\\t^(self compare: aString caseSensitive: false) <= 2! !\\n\\n!String methodsFor: 'comparing' stamp: 'ar 4/10/2005 16:39'!\\ncaseSensitiveLessOrEqual: aString \\n\\t\\\"Answer whether the receiver sorts before or equal to aString.\\n\\tThe collation order is case sensitive.\\\"\\n\\t^(self compare: aString caseSensitive: true) <= 2! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 8/27/2002 14:15'!\\ncharactersExactlyMatching: aString\\n\\t\\\"Do a character-by-character comparison between the receiver and aString. Return the index of the final character that matched exactly.\\\"\\n\\n\\t| count |\\n\\tcount _ self size min: aString size.\\n\\t1 to: count do: [:i | \\n\\t\\t(self at: i) = (aString at: i) ifFalse: [\\n\\t\\t\\t^ i - 1]].\\n\\t^ count! !\\n\\n!String methodsFor: 'comparing' stamp: 'ar 4/10/2005 16:38'!\\ncompare: aString \\n\\t\\\"Answer a comparison code telling how the receiver sorts relative to aString:\\n\\t\\t1 - before\\n\\t\\t2 - equal\\n\\t\\t3 - after.\\n\\tThe collation sequence is ascii with case differences ignored.\\n\\tTo get the effect of a <= b, but ignoring case, use (a compare: b) <= 2.\\\"\\n\\t^self compare: aString caseSensitive: false! !\\n\\n!String methodsFor: 'comparing' stamp: 'ar 4/10/2005 16:42'!\\ncompare: aString caseSensitive: aBool\\n\\t\\\"Answer a comparison code telling how the receiver sorts relative to aString:\\n\\t\\t1 - before\\n\\t\\t2 - equal\\n\\t\\t3 - after.\\n\\t\\\"\\n\\t| map |\\n\\tmap := aBool ifTrue:[CaseSensitiveOrder] ifFalse:[CaseInsensitiveOrder].\\n\\t^self compare: self with: aString collated: map! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 12/15/2005 14:28'!\\ncompare: string1 with: string2 collated: order\\n\\n\\t(string1 isByteString and: [string2 isByteString]) ifTrue: [\\n\\t\\t^ ByteString compare: string1 with: string2 collated: order\\n\\t].\\n \\\"Primitive does not fail properly right now\\\"\\n ^ String compare: string1 with: string2 collated: order\\n\\n\\\"\\nself assert: 'abc' = 'abc' asWideString.\\nself assert: 'abc' asWideString = 'abc'.\\nself assert: ((ByteArray with: 97 with: 0 with: 0 with: 0) asString ~= 'a000' asWideString).\\nself assert: ('a000' asWideString ~= (ByteArray with: 97 with: 0 with: 0 with: 0) asString).\\n\\nself assert: ('abc' sameAs: 'aBc' asWideString).\\nself assert: ('aBc' asWideString sameAs: 'abc').\\nself assert: ((ByteArray with: 97 with: 0 with: 0 with: 0) asString sameAs: 'Abcd' asWideString) not.\\nself assert: ('a000' asWideString sameAs: (ByteArray with: 97 with: 0 with: 0 with: 0) asString) not.\\n\\n\\\"! !\\n\\n!String methodsFor: 'comparing' stamp: 'ar 4/10/2005 17:27'!\\ncrc16\\n\\t\\\"Compute a 16 bit cyclic redundancy check.\\\"\\n\\n\\t| crc |\\n\\tcrc := 0.\\n\\t1 to: self byteSize do: [:i |\\n\\t\\tcrc := (crc bitShift: -8) bitXor: (\\n\\t\\t #(\\t16r0000\\t16rC0C1\\t16rC181\\t16r0140\\t16rC301\\t16r03C0\\t16r0280\\t16rC241\\n\\t\\t\\t16rC601\\t16r06C0\\t16r0780\\t16rC741\\t16r0500\\t16rC5C1\\t16rC481\\t16r0440\\n\\t\\t\\t16rCC01\\t16r0CC0\\t16r0D80\\t16rCD41\\t16r0F00\\t16rCFC1\\t16rCE81\\t16r0E40\\n\\t\\t\\t16r0A00\\t16rCAC1\\t16rCB81\\t16r0B40\\t16rC901\\t16r09C0\\t16r0880\\t16rC841\\n\\t\\t\\t16rD801\\t16r18C0\\t16r1980\\t16rD941\\t16r1B00\\t16rDBC1\\t16rDA81\\t16r1A40\\n\\t\\t\\t16r1E00\\t16rDEC1\\t16rDF81\\t16r1F40\\t16rDD01\\t16r1DC0\\t16r1C80\\t16rDC41\\n\\t\\t\\t16r1400\\t16rD4C1\\t16rD581\\t16r1540\\t16rD701\\t16r17C0\\t16r1680\\t16rD641\\n\\t\\t\\t16rD201\\t16r12C0\\t16r1380\\t16rD341\\t16r1100\\t16rD1C1\\t16rD081\\t16r1040\\n\\t\\t\\t16rF001\\t16r30C0\\t16r3180\\t16rF141\\t16r3300\\t16rF3C1\\t16rF281\\t16r3240\\n\\t\\t\\t16r3600\\t16rF6C1\\t16rF781\\t16r3740\\t16rF501\\t16r35C0\\t16r3480\\t16rF441\\n\\t\\t\\t16r3C00\\t16rFCC1\\t16rFD81\\t16r3D40\\t16rFF01\\t16r3FC0\\t16r3E80\\t16rFE41\\n\\t\\t\\t16rFA01\\t16r3AC0\\t16r3B80\\t16rFB41\\t16r3900\\t16rF9C1\\t16rF881\\t16r3840\\n\\t\\t\\t16r2800\\t16rE8C1\\t16rE981\\t16r2940\\t16rEB01\\t16r2BC0\\t16r2A80\\t16rEA41\\n\\t\\t\\t16rEE01\\t16r2EC0\\t16r2F80\\t16rEF41\\t16r2D00\\t16rEDC1\\t16rEC81\\t16r2C40\\n\\t\\t\\t16rE401\\t16r24C0\\t16r2580\\t16rE541\\t16r2700\\t16rE7C1\\t16rE681\\t16r2640\\n\\t\\t\\t16r2200\\t16rE2C1\\t16rE381\\t16r2340\\t16rE101\\t16r21C0\\t16r2080\\t16rE041\\n\\t\\t\\t16rA001\\t16r60C0\\t16r6180\\t16rA141\\t16r6300\\t16rA3C1\\t16rA281\\t16r6240\\n\\t\\t\\t16r6600\\t16rA6C1\\t16rA781\\t16r6740\\t16rA501\\t16r65C0\\t16r6480\\t16rA441\\n\\t\\t\\t16r6C00\\t16rACC1\\t16rAD81\\t16r6D40\\t16rAF01\\t16r6FC0\\t16r6E80\\t16rAE41\\n\\t\\t\\t16rAA01\\t16r6AC0\\t16r6B80\\t16rAB41\\t16r6900\\t16rA9C1\\t16rA881\\t16r6840\\n\\t\\t\\t16r7800\\t16rB8C1\\t16rB981\\t16r7940\\t16rBB01\\t16r7BC0\\t16r7A80\\t16rBA41\\n\\t\\t\\t16rBE01\\t16r7EC0\\t16r7F80\\t16rBF41\\t16r7D00\\t16rBDC1\\t16rBC81\\t16r7C40\\n\\t\\t\\t16rB401\\t16r74C0\\t16r7580\\t16rB541\\t16r7700\\t16rB7C1\\t16rB681\\t16r7640\\n\\t\\t\\t16r7200\\t16rB2C1\\t16rB381\\t16r7340\\t16rB101\\t16r71C0\\t16r7080\\t16rB041\\n\\t\\t\\t16r5000\\t16r90C1\\t16r9181\\t16r5140\\t16r9301\\t16r53C0\\t16r5280\\t16r9241\\n\\t\\t\\t16r9601\\t16r56C0\\t16r5780\\t16r9741\\t16r5500\\t16r95C1\\t16r9481\\t16r5440\\n\\t\\t\\t16r9C01\\t16r5CC0\\t16r5D80\\t16r9D41\\t16r5F00\\t16r9FC1\\t16r9E81\\t16r5E40\\n\\t\\t\\t16r5A00\\t16r9AC1\\t16r9B81\\t16r5B40\\t16r9901\\t16r59C0\\t16r5880\\t16r9841\\n\\t\\t\\t16r8801\\t16r48C0\\t16r4980\\t16r8941\\t16r4B00\\t16r8BC1\\t16r8A81\\t16r4A40\\n\\t\\t\\t16r4E00\\t16r8EC1\\t16r8F81\\t16r4F40\\t16r8D01\\t16r4DC0\\t16r4C80\\t16r8C41\\n\\t\\t\\t16r4400\\t16r84C1\\t16r8581\\t16r4540\\t16r8701\\t16r47C0\\t16r4680\\t16r8641\\n\\t\\t\\t16r8201\\t16r42C0\\t16r4380\\t16r8341\\t16r4100\\t16r81C1\\t16r8081\\t16r4040)\\n\\t\\t\\t at: ((crc bitXor: (self byteAt: i)) bitAnd: 16rFF) + 1) ].\\n\\t^crc! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 11/3/2004 19:24'!\\nendsWith: suffix\\n\\t\\\"Answer whether the tail end of the receiver is the same as suffix.\\n\\tThe comparison is case-sensitive.\\\"\\n\\t| extra |\\n\\t(extra _ self size - suffix size) < 0 ifTrue: [^ false].\\n\\t^ (self findSubstring: suffix in: self startingAt: extra + 1\\n\\t\\t\\tmatchTable: CaseSensitiveOrder) > 0\\n\\\"\\n 'Elvis' endsWith: 'vis'\\n\\\"! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 11/3/2004 19:24'!\\nendsWithAnyOf: aCollection\\n\\taCollection do:[:suffix|\\n\\t\\t(self endsWith: suffix) ifTrue:[^true].\\n\\t].\\n\\t^false! !\\n\\n!String methodsFor: 'comparing' stamp: 'md 2/16/2006 17:49'!\\nhash\\n\\t\\\"#hash is implemented, because #= is implemented\\\"\\n\\t\\\"ar 4/10/2005: I had to change this to use ByteString hash as initial \\n\\thash in order to avoid having to rehash everything and yet compute\\n\\tthe same hash for ByteString and WideString.\\n\\tmd 16/10/2006: use identityHash as initialHash, as behavior hash will \\n use String hash (name) to have a better hash soon\\\"\\n\\t^ self class stringHash: self initialHash: ByteString identityHash! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 11/3/2004 19:24'!\\nhashMappedBy: map\\n\\t\\\"My hash is independent of my oop.\\\"\\n\\n\\t^self hash! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 11/3/2004 19:24'!\\nhowManyMatch: string \\n\\t\\\"Count the number of characters that match up in self and aString.\\\"\\n\\t| count shorterLength |\\n\\t\\n\\tcount _ 0 .\\n\\tshorterLength _ ((self size ) min: (string size ) ) .\\n\\t(1 to: shorterLength do: [:index |\\n\\t\\t (((self at: index ) = (string at: index ) ) ifTrue: [count _ (count + 1 ) .\\n\\t\\t\\t] ).\\n\\t\\t] ).\\n\\t^ count \\n\\t\\n\\t! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 11/3/2004 19:24'!\\nmatch: text\\n\\t\\\"Answer whether text matches the pattern in this string.\\n\\tMatching ignores upper/lower case differences.\\n\\tWhere this string contains #, text may contain any character.\\n\\tWhere this string contains *, text may contain any sequence of characters.\\\"\\n\\n\\t^ self startingAt: 1 match: text startingAt: 1\\n\\\"\\n\\t'*'\\t\\t\\tmatch: 'zort' true\\n\\t'*baz'\\t\\tmatch: 'mobaz' true\\n\\t'*baz'\\t\\tmatch: 'mobazo' false\\n\\t'*baz*'\\t\\tmatch: 'mobazo' true\\n\\t'*baz*'\\t\\tmatch: 'mozo' false\\n\\t'foo*'\\t\\tmatch: 'foozo' true\\n\\t'foo*'\\t\\tmatch: 'bozo' false\\n\\t'foo*baz'\\tmatch: 'foo23baz' true\\n\\t'foo*baz'\\tmatch: 'foobaz' true\\n\\t'foo*baz'\\tmatch: 'foo23bazo' false\\n\\t'foo'\\t\\tmatch: 'Foo' true\\n\\t'foo*baz*zort' match: 'foobazort' false\\n\\t'foo*baz*zort' match: 'foobazzort' false\\n\\t'*foo#zort'\\tmatch: 'afoo3zortthenfoo3zort' true\\n\\t'*foo*zort'\\tmatch: 'afoodezortorfoo3zort' true\\n\\\"! !\\n\\n!String methodsFor: 'comparing' stamp: 'ar 4/10/2005 17:35'!\\nsameAs: aString \\n\\t\\\"Answer whether the receiver sorts equal to aString. The \\n\\tcollation sequence is ascii with case differences ignored.\\\"\\n\\t^(self compare: aString caseSensitive: false) = 2! !\\n\\n!String methodsFor: 'comparing' stamp: 'yo 11/3/2004 19:24'!\\nstartingAt: keyStart match: text startingAt: textStart\\n\\t\\\"Answer whether text matches the pattern in this string.\\n\\tMatching ignores upper/lower case differences.\\n\\tWhere this string contains #, text may contain any character.\\n\\tWhere this string contains *, text may contain any sequence of characters.\\\"\\n\\t| anyMatch matchStart matchEnd i matchStr j ii jj |\\n\\ti _ keyStart.\\n\\tj _ textStart.\\n\\n\\t\\\"Check for any #'s\\\"\\n\\t[i > self size ifTrue: [^ j > text size \\\"Empty key matches only empty string\\\"].\\n\\t(self at: i) = $#] whileTrue:\\n\\t\\t[\\\"# consumes one char of key and one char of text\\\"\\n\\t\\tj > text size ifTrue: [^ false \\\"no more text\\\"].\\n\\t\\ti _ i+1. j _ j+1].\\n\\n\\t\\\"Then check for *\\\"\\n\\t(self at: i) = $*\\n\\t\\tifTrue: [i = self size ifTrue:\\n\\t\\t\\t\\t\\t[^ true \\\"Terminal * matches all\\\"].\\n\\t\\t\\t\\t\\\"* means next match string can occur anywhere\\\"\\n\\t\\t\\t\\tanyMatch _ true.\\n\\t\\t\\t\\tmatchStart _ i + 1]\\n\\t\\tifFalse: [\\\"Otherwise match string must occur immediately\\\"\\n\\t\\t\\t\\tanyMatch _ false.\\n\\t\\t\\t\\tmatchStart _ i].\\n\\n\\t\\\"Now determine the match string\\\"\\n\\tmatchEnd _ self size.\\n\\t(ii _ self indexOf: $* startingAt: matchStart) > 0 ifTrue:\\n\\t\\t[ii = 1 ifTrue: [self error: '** not valid -- use * instead'].\\n\\t\\tmatchEnd _ ii-1].\\n\\t(ii _ self indexOf: $# startingAt: matchStart) > 0 ifTrue:\\n\\t\\t[ii = 1 ifTrue: [self error: '*# not valid -- use #* instead'].\\n\\t\\tmatchEnd _ matchEnd min: ii-1].\\n\\tmatchStr _ self copyFrom: matchStart to: matchEnd.\\n\\n\\t\\\"Now look for the match string\\\"\\n\\t[jj _ text findString: matchStr startingAt: j caseSensitive: false.\\n\\tanyMatch ifTrue: [jj > 0] ifFalse: [jj = j]]\\n\\t\\twhileTrue:\\n\\t\\t[\\\"Found matchStr at jj. See if the rest matches...\\\"\\n\\t\\t(self startingAt: matchEnd+1 match: text startingAt: jj + matchStr size) ifTrue:\\n\\t\\t\\t[^ true \\\"the rest matches -- success\\\"].\\n\\t\\t\\\"The rest did not match.\\\"\\n\\t\\tanyMatch ifFalse: [^ false].\\n\\t\\t\\\"Preceded by * -- try for a later match\\\"\\n\\t\\tj _ j+1].\\n\\t^ false \\\"Failed to find the match string\\\"! !\\n\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nadaptToCollection: rcvr andSend: selector\\n\\t\\\"If I am involved in arithmetic with a collection, convert me to a number.\\\"\\n\\n\\t^ rcvr perform: selector with: self asNumber! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nadaptToNumber: rcvr andSend: selector\\n\\t\\\"If I am involved in arithmetic with a number, convert me to a number.\\\"\\n\\n\\t^ rcvr perform: selector with: self asNumber! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nadaptToPoint: rcvr andSend: selector\\n\\t\\\"If I am involved in arithmetic with a point, convert me to a number.\\\"\\n\\n\\t^ rcvr perform: selector with: self asNumber! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nadaptToString: rcvr andSend: selector\\n\\t\\\"If I am involved in arithmetic with a string, convert us both to\\n\\tnumbers, and return the printString of the result.\\\"\\n\\n\\t^ (rcvr asNumber perform: selector with: self asNumber) printString! !\\n\\n!String methodsFor: 'converting' stamp: 'mw 1/30/2004 11:53'!\\nasAlphaNumeric: totalSize extraChars: additionallyAllowed mergeUID: minimalSizeOfRandomPart\\n\\t\\\"Generates a String with unique identifier ( UID ) qualities, the difference to a\\n\\t UUID is that its beginning is derived from the receiver, so that it has a meaning\\n\\t for a human reader.\\n\\n\\t Answers a String of totalSize, which consists of 3 parts\\n\\t 1.part: the beginning of the receiver only consisting of\\n\\t\\ta-z, A-Z, 0-9 and extraChars in Collection additionallyAllowed ( which can be nil )\\n\\t 2.part: a single _\\n\\t 3.part: a ( random ) UID of size >= minimalSizeOfRandomPart consisting of\\n\\t\\ta-z, A-Z, 0-9\\n\\n\\t Starting letters are capitalized. \\n\\t TotalSize must be at least 1.\\n\\t Exactly 1 occurrence of $_ is guaranteed ( unless additionallyAllowed includes $_ ).\\n\\t The random part has even for small sizes good UID qualitites for many practical purposes.\\n\\t If only lower- or uppercase letters are demanded, simply convert the answer with\\n\\t say #asLowercase. The probability of a duplicate will rise only moderately ( see below ).\\n\\n\\t Example: \\n\\t\\tsize of random part = 10\\n\\t\\tin n generated UIDs the chance p of having non-unique UIDs is\\n\\t\\t\\tn = 10000 -> p < 1e-10\\t\\tif answer is reduced to lowerCase: p < 1.4 e-8\\n\\t\\t\\tn = 100000 -> p < 1e-8\\n\\t\\tat the bottom is a snippet for your own calculations \\n\\t\\tNote: the calculated propabilites are theoretical,\\n\\t\\t\\tfor the actually used random generator they may be much worse\\\"\\n\\n\\t| stream out sizeOfFirstPart index ascii ch skip array random |\\n\\ttotalSize > minimalSizeOfRandomPart \\n\\t\\tifFalse: [ self errorOutOfBounds ].\\n\\tstream := ReadStream on: self.\\n\\tout := WriteStream on: ( String new: totalSize ).\\n\\tindex := 0.\\n\\tskip := true.\\n\\tsizeOfFirstPart := totalSize - minimalSizeOfRandomPart - 1.\\n\\t[ stream atEnd or: [ index >= sizeOfFirstPart ]]\\n\\twhileFalse: [\\n\\t\\t((( ascii := ( ch := stream next ) asciiValue ) >= 65 and: [ ascii <= 90 ]) or: [\\n\\t\\t\\t( ascii >= 97 and: [ ascii <= 122 ]) or: [\\t\\t\\t \\n\\t\\t\\tch isDigit or: [\\n\\t\\t\\tadditionallyAllowed notNil and: [ additionallyAllowed includes: ch ]]]])\\n\\t\\tifTrue: [\\n\\t\\t\\tskip\\n\\t\\t\\t\\tifTrue: [ out nextPut: ch asUppercase ]\\n\\t\\t\\t\\tifFalse: [ out nextPut: ch ].\\n\\t\\t\\tindex := index + 1.\\n\\t\\t\\tskip := false ]\\n\\t\\tifFalse: [ skip := true ]].\\n\\tout nextPut: $_.\\n\\tarray := Array new: 62.\\n\\t1 to: 26 do: [ :i |\\n\\t\\tarray at: i put: ( i + 64 ) asCharacter.\\n\\t\\tarray at: i + 26 put: ( i + 96 ) asCharacter ].\\n\\t53 to: 62 do: [ :i |\\n\\t\\tarray at: i put: ( i - 5 ) asCharacter ].\\n\\trandom := UUIDGenerator default randomGenerator. \\n\\ttotalSize - index - 1 timesRepeat: [\\n\\t\\tout nextPut: ( array atRandom: random )].\\n\\t^out contents\\n\\n\\t\\\"\\tcalculation of probability p for failure of uniqueness in n UIDs\\n\\t\\tNote: if answer will be converted to upper or lower case replace 62 with 36\\n\\t| n i p all |\\n\\tall := 62 raisedTo: sizeOfRandomPart.\\n\\ti := 1.\\n\\tp := 0.0 .\\n\\tn := 10000.\\n\\t[ i <= n ]\\n\\twhileTrue: [\\n\\t\\tp := p + (( i - 1 ) / all ).\\n\\t\\ti := i + 1 ].\\n\\tp \\n\\n\\tapproximation formula: n squared / ( 62.0 raisedTo: sizeOfRandomPart ) / 2 \\n\\t\\\" \\n\\n\\t\\\"'Crop SketchMorphs and Grab Screen Rect to JPG' \\n\\t\\t\\tasAlphaNumeric: 31 extraChars: nil mergeUID: 10 \\n\\t \\t\\t\\t'CropSketchMorphsAndG_iOw94jquN6'\\n\\t 'Monticello' \\n\\t\\t\\tasAlphaNumeric: 31 extraChars: nil mergeUID: 10 \\n\\t\\t\\t\\t'Monticello_kp6aV2l0IZK9uBULGOeG' \\n\\t 'version-', ( '1.1.2' replaceAll: $. with: $- )\\n\\t\\t\\tasAlphaNumeric: 31 extraChars: #( $- ) mergeUID: 10 \\n\\t\\t\\t\\t'Version-1-1-2_kuz2tMg2xX9iRLDVR'\\\"\\n\\t\\t! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/10/2005 17:18'!\\nasByteArray\\n\\t\\\"Convert to a ByteArray with the ascii values of the string.\\\"\\n\\t| b |\\n\\tb _ ByteArray new: self byteSize.\\n\\t1 to: self size * 4 do: [:i |\\n\\t\\tb at: i put: (self byteAt: i).\\n\\t].\\n\\t^ b.\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/10/2005 16:22'!\\nasByteString\\n\\t\\\"Convert the receiver into a ByteString\\\"\\n\\t^self asOctetString! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/10/2005 17:03'!\\nasCharacter\\n\\t\\\"Answer the receiver's first character, or '*' if none. Idiosyncratic, provisional.\\\"\\n\\n\\t^ self size > 0 ifTrue: [self first] ifFalse:[$\\U00b7]! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasDate\\n\\t\\\"Many allowed forms, see Date>>#readFrom:\\\"\\n\\n\\t^ Date fromString: self! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasDateAndTime\\n\\n\\n\\n\\t\\\"Convert from UTC format\\\" \\t^ DateAndTime fromString: self! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 10/22/2002 17:38'!\\nasDefaultDecodedString\\n\\n\\t^ self\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasDisplayText\\n\\t\\\"Answer a DisplayText whose text string is the receiver.\\\"\\n\\n\\t^DisplayText text: self asText! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasDuration\\n\\n\\t\\\"convert from [nnnd]hh:mm:ss[.nanos] format. [] implies optional elements\\\"\\n\\n\\n\\n\\t^ Duration fromString: self\\n\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/12/2005 13:55'!\\nasFileName\\n\\t\\\"Answer a String made up from the receiver that is an acceptable file \\n\\tname.\\\"\\n\\n\\t| string checkedString |\\n\\tstring _ FileDirectory checkName: self fixErrors: true.\\n\\tcheckedString _ (FilePath pathName: string) asVmPathName.\\n\\t^ (FilePath pathName: checkedString isEncoded: true) asSqueakPathName.\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 8/27/2002 14:38'!\\nasFourCode\\n\\n\\t| result |\\n\\tself size = 4 ifFalse: [^self error: 'must be exactly four characters'].\\n\\tresult _ self inject: 0 into: [:val :each | 256 * val + each asciiValue].\\n\\t(result bitAnd: 16r80000000) = 0 \\n\\t\\tifFalse: [self error: 'cannot resolve fourcode'].\\n\\t(result bitAnd: 16r40000000) = 0 ifFalse: [^result - 16r80000000].\\n\\t^ result\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 8/26/2002 23:06'!\\nasHex\\n\\t| stream |\\n\\tstream _ WriteStream on: (String new: self size * 4).\\n\\tself do: [ :ch | stream nextPutAll: ch hex ].\\n\\t^stream contents! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasHtml\\n\\t\\\"Do the basic character conversion for HTML. Leave all original return \\n\\tand tabs in place, so can conver back by simply removing bracked \\n\\tthings. 4/4/96 tk\\\"\\n\\t| temp |\\n\\ttemp _ self copyReplaceAll: '&' with: '&'.\\n\\tHtmlEntities keysAndValuesDo:\\n\\t\\t[:entity :char |\\n\\t\\tchar = $& ifFalse:\\n\\t\\t\\t[temp _ temp copyReplaceAll: char asString with: '&' , entity , ';']].\\n\\ttemp _ temp copyReplaceAll: '\\t' with: '\\t<IMG SRC=\\\"tab.gif\\\" ALT=\\\" \\\">'.\\n\\ttemp _ temp copyReplaceAll: '\\n' with: '\\n<BR>'.\\n\\t^ temp\\n\\n\\\"\\n\\t'A<&>B' asHtml\\n\\\"! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasIRCLowercase\\n\\t\\\"Answer a String made up from the receiver whose characters are all \\n\\tlowercase, where 'lowercase' is by IRC's definition\\\"\\n\\n\\t^self collect: [ :c | c asIRCLowercase ]! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasIdentifier: shouldBeCapitalized\\n\\t\\\"Return a legal identifier, with first character in upper case if shouldBeCapitalized is true, else lower case. This will always return a legal identifier, even for an empty string\\\"\\n\\n\\t| aString firstChar firstLetterPosition |\\n\\taString _ self select: [:el | el isAlphaNumeric].\\n\\tfirstLetterPosition _ aString findFirst: [:ch | ch isLetter].\\n\\taString _ firstLetterPosition == 0\\n\\t\\tifFalse:\\n\\t\\t\\t[aString copyFrom: firstLetterPosition to: aString size]\\n\\t\\tifTrue:\\n\\t\\t\\t['a', aString].\\n\\tfirstChar _ shouldBeCapitalized ifTrue: [aString first asUppercase] ifFalse: [aString first asLowercase].\\n\\n\\t^ firstChar asString, (aString copyFrom: 2 to: aString size)\\n\\\"\\n'234Fred987' asIdentifier: false\\n'235Fred987' asIdentifier: true\\n'' asIdentifier: true\\n'()87234' asIdentifier: false\\n'())z>=PPve889 U >' asIdentifier: false\\n\\n\\\"! !\\n\\n!String methodsFor: 'converting' stamp: 'laza 10/1/2004 09:55'!\\nasInteger \\n\\t^self asSignedInteger\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasLegalSelector\\n\\t| toUse |\\n\\ttoUse _ ''.\\n\\tself do:\\n\\t\\t[:char | char isAlphaNumeric ifTrue: [toUse _ toUse copyWith: char]].\\n\\t(self size == 0 or: [self first isLetter not])\\n\\t\\tifTrue:\\t\\t[toUse _ 'v', toUse].\\n\\n\\t^ toUse withFirstCharacterDownshifted\\n\\n\\\"'234znak 43 ) 2' asLegalSelector\\\"! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasLowercase\\n\\t\\\"Answer a String made up from the receiver whose characters are all \\n\\tlowercase.\\\"\\n\\n\\t^ self copy asString translateToLowercase! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasNumber \\n\\t\\\"Answer the Number created by interpreting the receiver as the string \\n\\trepresentation of a number.\\\"\\n\\n\\t^Number readFromString: self! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/10/2005 20:55'!\\nasOctetString\\n\\t\\\"Convert the receiver into an octet string\\\"\\n\\t| string |\\n\\tstring _ String new: self size.\\n\\t1 to: self size do: [:i | string at: i put: (self at: i)].\\n\\t^string! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 8/27/2002 14:39'!\\nasPacked\\n\\t\\\"Convert to a longinteger that describes the string\\\"\\n\\n\\t^ self inject: 0 into: [ :pack :next | pack _ pack * 256 + next asInteger ].! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasParagraph\\n\\t\\\"Answer a Paragraph whose text string is the receiver.\\\"\\n\\n\\t^Paragraph withText: self asText! !\\n\\n!String methodsFor: 'converting' stamp: 'dew 9/13/2001 01:17'!\\nasPluralBasedOn: aNumberOrCollection\\n\\t\\\"Append an 's' to this string based on whether aNumberOrCollection is 1 or of size 1.\\\"\\n\\n\\t^ (aNumberOrCollection = 1 or:\\n\\t\\t[aNumberOrCollection isCollection and: [aNumberOrCollection size = 1]])\\n\\t\\t\\tifTrue: [self]\\n\\t\\t\\tifFalse: [self, 's']\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'laza 10/1/2004 09:54'!\\nasSignedInteger \\n\\t\\\"Returns the first signed integer it can find or nil.\\\"\\n\\n\\t| start stream |\\n\\tstart := self findFirst: [:char | char isDigit].\\n\\tstart isZero ifTrue: [^nil].\\n\\tstream := (ReadStream on: self) position: start.\\n\\tstream back = $- ifTrue: [stream back].\\n\\t^Integer readFrom: stream! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasSmalltalkComment\\n\\t\\\"return this string, munged so that it can be treated as a comment in Smalltalk code. Quote marks are added to the beginning and end of the string, and whenever a solitary quote mark appears within the string, it is doubled\\\"\\n\\n\\t^String streamContents: [ :str |\\n\\t\\t| quoteCount first |\\n\\n\\t\\tstr nextPut: $\\\".\\n\\t\\n\\t\\tquoteCount := 0.\\n\\t\\tfirst := true.\\n\\t\\tself do: [ :char |\\n\\t\\t\\tchar = $\\\"\\n\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\tfirst ifFalse: [\\n\\t\\t\\t\\t\\t\\tstr nextPut: char.\\n\\t\\t\\t\\t\\t\\tquoteCount := quoteCount + 1 ] ]\\n\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\tquoteCount odd ifTrue: [\\n\\t\\t\\t\\t\\t\\t\\\"add a quote to even the number of quotes in a row\\\"\\n\\t\\t\\t\\t\\t\\tstr nextPut: $\\\" ].\\n\\t\\t\\t\\t\\tquoteCount := 0.\\n\\t\\t\\t\\t\\tstr nextPut: char ].\\n\\t\\t\\tfirst := false ]. \\n\\n\\t\\tquoteCount odd ifTrue: [\\n\\t\\t\\t\\\"check at the end\\\"\\n\\t\\t\\tstr nextPut: $\\\". ].\\n\\n\\t\\tstr nextPut: $\\\".\\n\\t].\\n\\t! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 12/19/2003 21:16'!\\nasSqueakPathName\\n\\n\\t^ self.\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasString\\n\\t\\\"Answer this string.\\\"\\n\\n\\t^ self\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasStringOrText\\n\\t\\\"Answer this string.\\\"\\n\\n\\t^ self\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/10/2005 19:24'!\\nasSymbol\\n\\t\\\"Answer the unique Symbol whose characters are the characters of the \\n\\tstring.\\\"\\n\\t^Symbol intern: self! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasText\\n\\t\\\"Answer a Text whose string is the receiver.\\\"\\n\\n\\t^Text fromString: self! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasTime\\n\\t\\\"Many allowed forms, see Time>>readFrom:\\\"\\n\\n\\t^ Time fromString: self.! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasTimeStamp\\n\\t\\\"Convert from obsolete TimeStamp format\\\"\\n\\n\\n\\t^ TimeStamp fromString: self! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/10/2005 17:05'!\\nasUnHtml\\n\\t\\\"Strip out all Html stuff (commands in angle brackets <>) and convert\\nthe characters &<> back to their real value. Leave actual cr and tab as\\nthey were in text.\\\"\\n\\t| in out char rest did |\\n\\tin _ ReadStream on: self.\\n\\tout _ WriteStream on: (String new: self size).\\n\\t[in atEnd] whileFalse:\\n\\t\\t[in peek = $<\\n\\t\\t\\tifTrue: [in unCommand] \\t\\\"Absorb <...><...>\\\"\\n\\t\\t\\tifFalse: [(char _ in next) = $&\\n\\t\\t\\t\\t\\t\\tifTrue: [rest _ in upTo: $;.\\n\\t\\t\\t\\t\\t\\t\\t\\tdid _ out position.\\n\\t\\t\\t\\t\\t\\t\\t\\trest = 'lt' ifTrue: [out nextPut: $<].\\n\\t\\t\\t\\t\\t\\t\\t\\trest = 'gt' ifTrue: [out nextPut: $>].\\n\\t\\t\\t\\t\\t\\t\\t\\trest = 'amp' ifTrue: [out nextPut: $&].\\n\\t\\t\\t\\t\\t\\t\\t\\trest = 'deg' ifTrue: [out nextPut: $\\U00b0].\\n\\t\\t\\t\\t\\t\\t\\t\\trest = 'quot' ifTrue: [out nextPut: $\\\"].\\n\\t\\t\\t\\t\\t\\t\\t\\tdid = out position ifTrue: [\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tself error: 'unknown encoded HTML char'.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\\"Please add it to this method\\\"]]\\n\\t\\t\\t\\t\\t\\tifFalse: [out nextPut: char]].\\n\\t\\t].\\n\\t^ out contents! !\\n\\n!String methodsFor: 'converting' stamp: 'laza 10/1/2004 10:02'!\\nasUnsignedInteger \\n\\t\\\"Returns the first integer it can find or nil.\\\"\\n\\n\\t| start stream |\\n\\tstart := self findFirst: [:char | char isDigit].\\n\\tstart isZero ifTrue: [^nil].\\n\\tstream := (ReadStream on: self) position: start - 1.\\n\\t^Integer readFrom: stream! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasUppercase\\n\\t\\\"Answer a String made up from the receiver whose characters are all \\n\\tuppercase.\\\"\\n\\n\\t^self copy asString translateToUppercase! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasUrl\\n\\t\\\"convert to a Url\\\"\\n\\t\\\"'http://www.cc.gatech.edu/' asUrl\\\"\\n\\t\\\"msw://chaos.resnet.gatech.edu:9000/' asUrl\\\"\\n\\t^Url absoluteFromText: self! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nasUrlRelativeTo: aUrl\\n\\t^aUrl newFromRelativeText: self! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 2/24/2005 18:33'!\\nasVmPathName\\n\\n\\t^ (FilePath pathName: self) asVmPathName.\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\naskIfAddStyle: priorMethod req: requestor\\n\\t^ self \\\"we are a string with no text style\\\"! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/12/2005 17:36'!\\nasWideString \\n\\tself isWideString\\n\\t\\tifTrue:[^self]\\n\\t\\tifFalse:[^WideString from: self]! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ncapitalized\\n\\t\\\"Return a copy with the first letter capitalized\\\"\\n\\t| cap |\\n\\tself isEmpty ifTrue: [ ^self copy ].\\n\\tcap _ self copy.\\n\\tcap at: 1 put: (cap at: 1) asUppercase.\\n\\t^ cap! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ncompressWithTable: tokens\\n\\t\\\"Return a string with all substrings that occur in tokens replaced\\n\\tby a character with ascii code = 127 + token index.\\n\\tThis will work best if tokens are sorted by size.\\n\\tAssumes this string contains no characters > 127, or that they\\n\\tare intentionally there and will not interfere with this process.\\\"\\n\\t| str null finalSize start result ri c ts |\\n\\tnull _ Character value: 0.\\n\\tstr _ self copyFrom: 1 to: self size. \\\"Working string will get altered\\\"\\n\\tfinalSize _ str size.\\n\\ttokens doWithIndex:\\n\\t\\t[:token :tIndex |\\n\\t\\tstart _ 1.\\n\\t\\t[(start _ str findString: token startingAt: start) > 0]\\n\\t\\t\\twhileTrue:\\n\\t\\t\\t[ts _ token size.\\n\\t\\t\\t((start + ts) <= str size\\n\\t\\t\\t\\tand: [(str at: start + ts) = $ and: [tIndex*2 <= 128]])\\n\\t\\t\\t\\tifTrue: [ts _ token size + 1. \\\"include training blank\\\"\\n\\t\\t\\t\\t\\t\\tstr at: start put: (Character value: tIndex*2 + 127)]\\n\\t\\t\\t\\tifFalse: [str at: start put: (Character value: tIndex + 127)].\\n\\t\\t\\tstr at: start put: (Character value: tIndex + 127).\\n\\t\\t\\t1 to: ts-1 do: [:i | str at: start+i put: null].\\n\\t\\t\\tfinalSize _ finalSize - (ts - 1).\\n\\t\\t\\tstart _ start + ts]].\\n\\tresult _ String new: finalSize.\\n\\tri _ 0.\\n\\t1 to: str size do:\\n\\t\\t[:i | (c _ str at: i) = null ifFalse: [result at: (ri _ ri+1) put: c]].\\n\\t^ result! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ncontractTo: smallSize\\n\\t\\\"return myself or a copy shortened by ellipsis to smallSize\\\"\\n\\t| leftSize |\\n\\tself size <= smallSize\\n\\t\\tifTrue: [^ self]. \\\"short enough\\\"\\n\\tsmallSize < 5\\n\\t\\tifTrue: [^ self copyFrom: 1 to: smallSize]. \\\"First N characters\\\"\\n\\tleftSize _ smallSize-2//2.\\n\\t^ self copyReplaceFrom: leftSize+1\\t\\t\\\"First N/2 ... last N/2\\\"\\n\\t\\tto: self size - (smallSize - leftSize - 3)\\n\\t\\twith: '...'\\n\\\"\\n\\t'A clear but rather long-winded summary' contractTo: 18\\n\\\"! !\\n\\n!String methodsFor: 'converting' stamp: 'KR 1/30/2006 21:47'!\\nconvertFromEncoding: encodingName\\n\\t^self convertFromWithConverter: (TextConverter newForEncoding: encodingName)! !\\n\\n!String methodsFor: 'converting' stamp: 'KR 1/30/2006 21:47'!\\nconvertFromSuperSwikiServerString\\n\\t^self convertFromEncoding: 'shift_jis'! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 7/8/2004 12:02'!\\nconvertFromWithConverter: converter\\n\\n\\t| readStream writeStream c |\\n\\treadStream _ self readStream.\\n\\twriteStream _ String new writeStream.\\n\\tconverter ifNil: [^ self].\\n\\t[readStream atEnd] whileFalse: [\\n\\t\\tc _ converter nextFromStream: readStream.\\n\\t\\tc ifNotNil: [writeStream nextPut: c] ifNil: [^ writeStream contents]\\n\\t].\\n\\t^ writeStream contents\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'KR 1/30/2006 21:49'!\\nconvertToEncoding: encodingName\\n\\t^self convertToWithConverter: (TextConverter newForEncoding: encodingName).! !\\n\\n!String methodsFor: 'converting' stamp: 'KR 1/30/2006 21:50'!\\nconvertToSuperSwikiServerString\\n\\t^self convertToEncoding: 'shift_jis'! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/12/2005 14:01'!\\nconvertToSystemString\\n\\n\\t| readStream writeStream converter |\\n\\treadStream _ self readStream.\\n\\twriteStream _ String new writeStream.\\n\\tconverter _ LanguageEnvironment defaultSystemConverter.\\n\\tconverter ifNil: [^ self].\\n\\t[readStream atEnd] whileFalse: [\\n\\t\\tconverter nextPut: readStream next toStream: writeStream\\n\\t].\\n\\tconverter emitSequenceToResetStateIfNeededOn: writeStream.\\n\\t^ writeStream contents.\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 7/8/2004 12:01'!\\nconvertToWithConverter: converter\\n\\n\\t| readStream writeStream |\\n\\treadStream _ self readStream.\\n\\twriteStream _ String new writeStream.\\n\\tconverter ifNil: [^ self].\\n\\t[readStream atEnd] whileFalse: [\\n\\t\\tconverter nextPut: readStream next toStream: writeStream\\n\\t].\\n\\tconverter emitSequenceToResetStateIfNeededOn: writeStream.\\n\\t^ writeStream contents.\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ncorrectAgainst: wordList\\n\\t\\\"Correct the receiver: assume it is a misspelled word and return the (maximum of five) nearest words in the wordList. Depends on the scoring scheme of alike:\\\"\\n\\t| results |\\n\\tresults _ self correctAgainst: wordList continuedFrom: nil.\\n\\tresults _ self correctAgainst: nil continuedFrom: results.\\n\\t^ results! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ncorrectAgainst: wordList continuedFrom: oldCollection\\n\\t\\\"Like correctAgainst:. Use when you want to correct against several lists, give nil as the first oldCollection, and nil as the last wordList.\\\"\\n\\n\\t^ wordList isNil\\n\\t\\tifTrue: [ self correctAgainstEnumerator: nil\\n\\t\\t\\t\\t\\tcontinuedFrom: oldCollection ]\\n\\t\\tifFalse: [ self correctAgainstEnumerator: [ :action | wordList do: action without: nil]\\n\\t\\t\\t\\t\\tcontinuedFrom: oldCollection ]! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ncorrectAgainstDictionary: wordDict continuedFrom: oldCollection\\n\\t\\\"Like correctAgainst:continuedFrom:. Use when you want to correct against a dictionary.\\\"\\n\\n\\t^ wordDict isNil\\n\\t\\tifTrue: [ self correctAgainstEnumerator: nil\\n\\t\\t\\t\\t\\tcontinuedFrom: oldCollection ]\\n\\t\\tifFalse: [ self correctAgainstEnumerator: [ :action | wordDict keysDo: action ]\\n\\t\\t\\t\\t\\tcontinuedFrom: oldCollection ]! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 7/29/2005 16:04'!\\nencodeForHTTP\\n\\t\\\"change dangerous characters to their %XX form, for use in HTTP transactions\\\"\\n\\n\\t^ self encodeForHTTPWithTextEncoding: 'utf-8' conditionBlock: [:c | c isSafeForHTTP].\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 7/29/2005 16:04'!\\nencodeForHTTPWithTextEncoding: encodingName\\n\\n\\t^ self encodeForHTTPWithTextEncoding: encodingName conditionBlock: [:c | c isSafeForHTTP].\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 7/29/2005 16:03'!\\nencodeForHTTPWithTextEncoding: encodingName conditionBlock: conditionBlock\\n\\t\\\"change dangerous characters to their %XX form, for use in HTTP transactions\\\"\\n\\n\\t| httpSafeStream encodedStream cont |\\n\\thttpSafeStream _ WriteStream on: (String new).\\n\\tencodedStream _ MultiByteBinaryOrTextStream on: (String new: 6).\\n\\tencodedStream converter: (TextConverter newForEncoding: encodingName).\\n\\tself do: [:c |\\n\\t\\t(conditionBlock value: c)\\n\\t\\t\\tifTrue: [httpSafeStream nextPut: (Character value: c charCode)]\\n\\t\\t\\tifFalse: [\\n\\t\\t\\t\\tencodedStream text; reset.\\n\\t\\t\\t\\tencodedStream nextPut: c.\\n\\t\\t\\t\\tencodedStream position: 0.\\n\\t\\t\\t\\tencodedStream binary.\\n\\t\\t\\t\\tcont _ encodedStream contents.\\n\\t\\t\\t\\tcont do: [:byte |\\n\\t\\t\\t\\t\\thttpSafeStream nextPut: $%.\\n\\t\\t\\t\\t\\thttpSafeStream nextPut: (byte // 16) asHexDigit.\\n\\t\\t\\t\\t\\thttpSafeStream nextPut: (byte \\\\\\\\ 16) asHexDigit.\\n\\t\\t\\t\\t].\\n\\t\\t\\t].\\n\\t].\\n\\t^ httpSafeStream contents.\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 7/5/2004 16:48'!\\nfindSelector\\n\\t\\\"Dan's code for hunting down selectors with keyword parts; while this doesn't give a true parse, in most cases it does what we want, in where it doesn't, we're none the worse for it.\\\"\\n\\t| sel possibleParens level n |\\n\\tsel _ self withBlanksTrimmed.\\n\\t(sel includes: $:) ifTrue:\\n\\t\\t[sel _ sel copyReplaceAll: ':' with: ': '.\\t\\\"for the style (aa max:bb) with no space\\\"\\n\\t\\tpossibleParens _ sel findTokens: Character separators.\\n\\t\\tsel _ self class streamContents:\\n\\t\\t\\t[:s | level _ 0.\\n\\t\\t\\tpossibleParens do:\\n\\t\\t\\t\\t[:token |\\n\\t\\t\\t\\t(level = 0 and: [token endsWith: ':'])\\n\\t\\t\\t\\t\\tifTrue: [s nextPutAll: token]\\n\\t\\t\\t\\t\\tifFalse: [(n _ token occurrencesOf: $( ) > 0 ifTrue: [level _ level + n].\\n\\t\\t\\t\\t\\t\\t\\t(n _ token occurrencesOf: $[ ) > 0 ifTrue: [level _ level + n].\\n\\t\\t\\t\\t\\t\\t\\t(n _ token occurrencesOf: $] ) > 0 ifTrue: [level _ level - n].\\n\\t\\t\\t\\t\\t\\t\\t(n _ token occurrencesOf: $) ) > 0 ifTrue: [level _ level - n]]]]].\\n\\n\\tsel isEmpty ifTrue: [^ nil].\\n\\tsel isOctetString ifTrue: [sel _ sel asOctetString].\\n\\tSymbol hasInterned: sel ifTrue:\\n\\t\\t[:aSymbol | ^ aSymbol].\\n\\t^ nil! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ninitialIntegerOrNil\\n\\t\\\"Answer the integer represented by the leading digits of the receiver, or nil if the receiver does not begin with a digit\\\"\\n\\t| firstNonDigit |\\n\\t(self size == 0 or: [self first isDigit not]) ifTrue: [^ nil].\\n\\tfirstNonDigit _ (self findFirst: [:m | m isDigit not]).\\n\\tfirstNonDigit = 0 ifTrue: [firstNonDigit _ self size + 1].\\n\\t^ (self copyFrom: 1 to: (firstNonDigit - 1)) asNumber\\n\\\"\\n'234Whoopie' initialIntegerOrNil\\n'wimpy' initialIntegerOrNil\\n'234' initialIntegerOrNil\\n'2N' initialIntegerOrNil\\n'2' initialIntegerOrNil\\n' 89Ten ' initialIntegerOrNil\\n'78 92' initialIntegerOrNil\\n\\\"\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nkeywords\\n\\t\\\"Answer an array of the keywords that compose the receiver.\\\"\\n\\t| kwd char keywords |\\n\\tkeywords _ Array streamContents:\\n\\t\\t[:kwds | kwd _ WriteStream on: (String new: 16).\\n\\t\\t1 to: self size do:\\n\\t\\t\\t[:i |\\n\\t\\t\\tkwd nextPut: (char _ self at: i).\\n\\t\\t\\tchar = $: ifTrue: \\n\\t\\t\\t\\t\\t[kwds nextPut: kwd contents.\\n\\t\\t\\t\\t\\tkwd reset]].\\n\\t\\tkwd isEmpty ifFalse: [kwds nextPut: kwd contents]].\\n\\t(keywords size >= 1 and: [(keywords at: 1) = ':']) ifTrue:\\n\\t\\t[\\\"Has an initial keyword, as in #:if:then:else:\\\"\\n\\t\\tkeywords _ keywords allButFirst].\\n\\t(keywords size >= 2 and: [(keywords at: keywords size - 1) = ':']) ifTrue:\\n\\t\\t[\\\"Has a final keyword, as in #nextPut::andCR\\\"\\n\\t\\tkeywords _ keywords copyReplaceFrom: keywords size - 1\\n\\t\\t\\t\\t\\t\\t\\t\\tto: keywords size with: {':' , keywords last}].\\n\\t^ keywords! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nnumericSuffix\\n\\t^ self stemAndNumericSuffix last\\n\\n\\\"\\n'abc98' numericSuffix\\n'98abc' numericSuffix\\n\\\"! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nonlyLetters\\n\\t\\\"answer the receiver with only letters\\\"\\n\\t^ self select:[:each | each isLetter]! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nromanNumber\\n\\t| value v1 v2 |\\n\\tvalue _ v1 _ v2 _ 0.\\n\\tself reverseDo:\\n\\t\\t[:each |\\n\\t\\tv1 _ #(1 5 10 50 100 500 1000) at: ('IVXLCDM' indexOf: each).\\n\\t\\tv1 >= v2\\n\\t\\t\\tifTrue: [value _ value + v1]\\n\\t\\t\\tifFalse: [value _ value - v1].\\n\\t\\tv2 _ v1].\\n\\t^ value! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nsansPeriodSuffix\\n\\t\\\"Return a copy of the receiver up to, but not including, the first period. If the receiver's *first* character is a period, then just return the entire receiver. \\\"\\n\\n\\t| likely |\\n\\tlikely _ self copyUpTo: $..\\n\\t^ likely size == 0\\n\\t\\tifTrue:\\t[self]\\n\\t\\tifFalse:\\t[likely]! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 8/27/2002 11:13'!\\nsplitInteger\\n\\t\\\"Answer an array that is a splitting of self into a string and an integer.\\n\\t'43Sam' ==> #(43 'Sam'). 'Try90' ==> #('Try' 90)\\n\\tBUT NOTE: 'Sam' ==> #('Sam' 0), and '90' ==> #('' 90) ie, (<string> <integer>).\\\"\\n\\n\\t| pos |\\n\\t(pos _ self findFirst: [:d | d isDigit not]) = 0 ifTrue: [^ Array with: '' with: self asNumber].\\n\\tself first isDigit ifTrue: [\\n\\t\\t^ Array with: (self copyFrom: 1 to: pos - 1) asNumber \\n\\t\\t\\t\\twith: (self copyFrom: pos to: self size)].\\n\\t(pos _ self findFirst: [:d | d isDigit]) = 0 ifTrue: [^ Array with: self with: 0].\\n\\t^ Array with: (self copyFrom: 1 to: pos - 1)\\n\\t\\t\\twith: (self copyFrom: pos to: self size) asNumber! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nstemAndNumericSuffix\\n\\t\\\"Parse the receiver into a string-valued stem and a numeric-valued suffix. 6/7/96 sw\\\"\\n\\n\\t| stem suffix position |\\n\\n\\tstem _ self.\\n\\tsuffix _ 0.\\n\\tposition _ 1.\\n\\t[stem endsWithDigit and: [stem size > 1]] whileTrue:\\n\\t\\t[suffix _ stem last digitValue * position + suffix.\\n\\t\\tposition _ position * 10.\\n\\t\\tstem _ stem copyFrom: 1 to: stem size - 1].\\n\\t^ Array with: stem with: suffix\\n\\n\\\"'Fred2305' stemAndNumericSuffix\\\"! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nsubStrings\\n\\t\\\"Answer an array of the substrings that compose the receiver.\\\"\\n\\t#Collectn.\\n\\t\\\"Added 2000/04/08 For ANSI <readableString> protocol.\\\"\\n\\t^ self substrings! !\\n\\n!String methodsFor: 'converting' stamp: 'ar 4/12/2005 16:32'!\\nsubStrings: separators \\n\\t\\\"Answer an array containing the substrings in the receiver separated \\n\\tby the elements of separators.\\\"\\n\\t| char result sourceStream subString |\\n\\t#Collectn.\\n\\t\\\"Changed 2000/04/08 For ANSI <readableString> protocol.\\\"\\n\\t(separators isString or:[separators allSatisfy: [:element | element isKindOf: Character]])\\n\\t\\tifFalse: [^ self error: 'separators must be Characters.'].\\n\\tsourceStream := ReadStream on: self.\\n\\tresult := OrderedCollection new.\\n\\tsubString := String new.\\n\\t[sourceStream atEnd]\\n\\t\\twhileFalse: \\n\\t\\t\\t[char := sourceStream next.\\n\\t\\t\\t(separators includes: char)\\n\\t\\t\\t\\tifTrue: [subString notEmpty\\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[result add: subString copy.\\n\\t\\t\\t\\t\\t\\t\\tsubString := String new]]\\n\\t\\t\\t\\tifFalse: [subString := subString , (String with: char)]].\\n\\tsubString notEmpty ifTrue: [result add: subString copy].\\n\\t^ result asArray! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nsubstrings\\n\\t\\\"Answer an array of the substrings that compose the receiver.\\\"\\n\\t| result end beginning |\\n\\n\\tresult _ WriteStream on: (Array new: 10).\\n\\n\\n\\n\\tend _ 0.\\n\\t\\\"find one substring each time through this loop\\\"\\n\\t[ \\n\\t\\t\\\"find the beginning of the next substring\\\"\\n\\t\\tbeginning _ self indexOfAnyOf: CSNonSeparators startingAt: end+1 ifAbsent: [ nil ].\\n\\t\\tbeginning ~~ nil ] \\n\\twhileTrue: [\\n\\t\\t\\\"find the end\\\"\\n\\t\\tend _ self indexOfAnyOf: CSSeparators startingAt: beginning ifAbsent: [ self size + 1 ].\\n\\t\\tend _ end - 1.\\n\\n\\t\\tresult nextPut: (self copyFrom: beginning to: end).\\n\\n\\t].\\n\\n\\n\\t^result contents! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nsurroundedBySingleQuotes\\n\\t\\\"Answer the receiver with leading and trailing quotes. \\\"\\n\\n\\t^ $' asString, self, $' asString! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 8/28/2002 15:14'!\\ntranslateFrom: start to: stop table: table\\n\\t\\\"translate the characters in the string by the given table, in place\\\"\\n\\tself class translate: self from: start to: stop table: table! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ntranslateToLowercase\\n\\t\\\"Translate all characters to lowercase, in place\\\"\\n\\n\\tself translateWith: LowercasingTable! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ntranslateToUppercase\\n\\t\\\"Translate all characters to lowercase, in place\\\"\\n\\n\\tself translateWith: UppercasingTable! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 8/28/2002 15:13'!\\ntranslateWith: table\\n\\t\\\"translate the characters in the string by the given table, in place\\\"\\n\\t^ self translateFrom: 1 to: self size table: table! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ntruncateTo: smallSize\\n\\t\\\"return myself or a copy shortened to smallSize. 1/18/96 sw\\\"\\n\\n\\t^ self size <= smallSize\\n\\t\\tifTrue:\\n\\t\\t\\t[self]\\n\\t\\tifFalse:\\n\\t\\t\\t[self copyFrom: 1 to: smallSize]! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\ntruncateWithElipsisTo: maxLength\\n\\t\\\"Return myself or a copy suitably shortened but with elipsis added\\\"\\n\\n\\t^ self size <= maxLength\\n\\t\\tifTrue:\\n\\t\\t\\t[self]\\n\\t\\tifFalse:\\n\\t\\t\\t[(self copyFrom: 1 to: (maxLength - 3)), '...']\\n\\n\\n\\t\\\"'truncateWithElipsisTo:' truncateWithElipsisTo: 20\\\"! !\\n\\n!String methodsFor: 'converting' stamp: 'KR 9/22/2005 23:06'!\\nunescapePercents\\n\\t\\\"decode %xx form. This is the opposite of #encodeForHTTP\\\"\\n\\t^ self unescapePercentsWithTextEncoding: 'utf-8'.! !\\n\\n!String methodsFor: 'converting' stamp: 'ky 7/8/2006 17:56'!\\nunescapePercentsWithTextEncoding: encodingName \\n\\t\\\"decode string including %XX form\\\"\\n\\t| unescaped char asciiVal specialChars oldPos pos converter |\\n\\tunescaped := ReadWriteStream on: String new.\\n\\tspecialChars := '+%' asCharacterSet.\\n\\toldPos := 1.\\n\\t[pos := self indexOfAnyOf: specialChars startingAt: oldPos.\\n\\tpos > 0]\\n\\t\\twhileTrue: [unescaped\\n\\t\\t\\t\\tnextPutAll: (self copyFrom: oldPos to: pos - 1).\\n\\t\\t\\tchar := self at: pos.\\n\\t\\t\\t(char = $%\\n\\t\\t\\t\\t\\tand: [pos + 2 <= self size])\\n\\t\\t\\t\\tifTrue: [asciiVal := (self at: pos + 1) asUppercase digitValue * 16 + (self at: pos + 2) asUppercase digitValue.\\n\\t\\t\\t\\t\\tasciiVal > 255\\n\\t\\t\\t\\t\\t\\tifTrue: [^ self].\\n\\t\\t\\t\\t\\tunescaped\\n\\t\\t\\t\\t\\t\\tnextPut: (Character value: asciiVal).\\n\\t\\t\\t\\t\\tpos := pos + 3.\\n\\t\\t\\t\\t\\tpos <= self size\\n\\t\\t\\t\\t\\t\\tifFalse: [char := nil].\\n\\t\\t\\t\\t\\toldPos := pos]\\n\\t\\t\\t\\tifFalse: [char = $+\\n\\t\\t\\t\\t\\t\\tifTrue: [unescaped nextPut: Character space]\\n\\t\\t\\t\\t\\t\\tifFalse: [unescaped nextPut: char].\\n\\t\\t\\t\\t\\toldPos := pos + 1]].\\n\\toldPos <= self size\\n\\t\\tifTrue: [unescaped\\n\\t\\t\\t\\tnextPutAll: (self copyFrom: oldPos to: self size)].\\n\\tconverter := (TextConverter newForEncoding: encodingName)\\n\\t\\t\\t\\tifNil: [TextConverter newForEncoding: nil].\\n\\t^ [unescaped contents convertFromWithConverter: converter]\\n\\t\\ton: Error\\n\\t\\tdo: [\\\"the contents may be squeak-encoded\\\"\\n\\t\\t\\tunescaped contents]! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 8/27/2002 11:20'!\\nunparenthetically\\n\\t\\\"If the receiver starts with (..( and ends with matching )..), strip them\\\"\\n\\n\\t| curr |\\n\\tcurr _ self.\\n\\t[((curr first = $() and: [curr last = $)])] whileTrue:\\n\\t\\t[curr _ curr copyFrom: 2 to: (curr size - 1)].\\n\\n\\t^ curr\\n\\n\\\"\\n\\n'((fred the bear))' unparenthetically\\n\\n\\\"\\n\\t\\t! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nunzipped\\n\\t| magic1 magic2 |\\n\\tmagic1 _ (self at: 1) asInteger.\\n\\tmagic2 _ (self at: 2) asInteger.\\n\\t(magic1 = 16r1F and:[magic2 = 16r8B]) ifFalse:[^self].\\n\\t^(GZipReadStream on: self) upToEnd! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nwithBlanksCondensed\\n\\t\\\"Return a copy of the receiver with leading/trailing blanks removed\\n\\t and consecutive white spaces condensed.\\\"\\n\\n\\t| trimmed lastBlank |\\n\\ttrimmed _ self withBlanksTrimmed.\\n\\t^String streamContents: [:stream |\\n\\t\\tlastBlank _ false.\\n\\t\\ttrimmed do: [:c | (c isSeparator and: [lastBlank]) ifFalse: [stream nextPut: c].\\n\\t\\t\\tlastBlank _ c isSeparator]].\\n\\n\\t\\\" ' abc d ' withBlanksCondensed\\\"\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 7/5/2004 16:43'!\\nwithBlanksTrimmed\\n\\t\\\"Return a copy of the receiver from which leading and trailing blanks have been trimmed.\\\"\\n\\n\\t| first result |\\n\\tfirst _ self findFirst: [:c | c isSeparator not].\\n\\tfirst = 0 ifTrue: [^ '']. \\\"no non-separator character\\\"\\n\\tresult _ self\\n\\t\\tcopyFrom: first\\n\\t\\tto: (self findLast: [:c | c isSeparator not]).\\n\\tresult isOctetString ifTrue: [^ result asOctetString] ifFalse: [^ result].\\n\\n\\t\\\" ' abc d ' withBlanksTrimmed\\\"\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'md 9/19/2004 15:19'!\\nwithFirstCharacterDownshifted\\n\\t\\\"Return a copy with the first letter downShifted\\\"\\n\\t\\n\\t| answer |\\n\\t\\n\\tself ifEmpty: [^ self copy].\\n\\tanswer _ self copy.\\n\\tanswer at: 1 put: (answer at: 1) asLowercase.\\n\\t^ answer. ! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nwithNoLineLongerThan: aNumber\\n\\t\\\"Answer a string with the same content as receiver, but rewrapped so that no line has more characters than the given number\\\"\\n\\t| listOfLines currentLast currentStart resultString putativeLast putativeLine crPosition |\\n\\taNumber isNumber not | (aNumber < 1) ifTrue: [self error: 'too narrow'].\\n\\tlistOfLines _ OrderedCollection new.\\n\\tcurrentLast _ 0.\\n\\t[currentLast < self size] whileTrue:\\n\\t\\t[currentStart _ currentLast + 1.\\n\\t\\tputativeLast _ (currentStart + aNumber - 1) min: self size.\\n\\t\\tputativeLine _ self copyFrom: currentStart to: putativeLast.\\n\\t\\t(crPosition _ putativeLine indexOf: Character cr) > 0 ifTrue:\\n\\t\\t\\t[putativeLast _ currentStart + crPosition - 1.\\n\\t\\t\\tputativeLine _ self copyFrom: currentStart to: putativeLast].\\n\\t\\tcurrentLast _ putativeLast == self size\\n\\t\\t\\tifTrue:\\n\\t\\t\\t\\t[putativeLast]\\n\\t\\t\\tifFalse:\\n\\t\\t\\t\\t[currentStart + putativeLine lastSpacePosition - 1].\\n\\t\\tcurrentLast <= currentStart ifTrue:\\n\\t\\t\\t[\\\"line has NO spaces; baleout!!\\\"\\n\\t\\t\\tcurrentLast _ putativeLast].\\n\\t\\tlistOfLines add: (self copyFrom: currentStart to: currentLast) withBlanksTrimmed].\\n\\n\\tlistOfLines size > 0 ifFalse: [^ ''].\\n\\tresultString _ listOfLines first.\\n\\t2 to: listOfLines size do:\\n\\t\\t[:i | resultString _ resultString, String cr, (listOfLines at: i)].\\n\\t^ resultString\\n\\n\\\"#(5 7 20) collect:\\n\\t[:i | 'Fred the bear went down to the brook to read his book in silence' withNoLineLongerThan: i]\\\"! !\\n\\n!String methodsFor: 'converting' stamp: 'md 10/5/2005 11:01'!\\nwithoutLeadingBlanks\\n\\t\\n\\t\\\"Return a copy of the receiver from which leading blanks have been\\ntrimmed.\\\"\\n\\n\\t\\n\\t| first |\\n\\t\\n\\tfirst := self findFirst: [:c | c isSeparator not ].\\n\\n\\tfirst = 0 ifTrue: [^ '']. \\n\\t\\n\\t\\\"no non-separator character\\\"\\n\\t\\n\\t^ self copyFrom: first to: self size\\n\\n\\t\\n\\t\\t\\n\\t\\\" ' abc d' withoutLeadingBlanks\\\"\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'tak 4/25/2004 12:57'!\\nwithSeparatorsCompacted\\n\\t\\\"replace each sequences of whitespace by a single space character\\\"\\n\\t\\\"' test ' withSeparatorsCompacted = ' test '\\\"\\n\\t\\\"' test test' withSeparatorsCompacted = ' test test'\\\"\\n\\t\\\"'test test\\t\\t' withSeparatorsCompacted = 'test test '\\\"\\n\\n\\t| out in next isSeparator |\\n\\tself isEmpty ifTrue: [^ self].\\n\\n\\tout _ WriteStream on: (String new: self size).\\n\\tin _ self readStream.\\n\\tisSeparator _ [:char | char asciiValue < 256\\n\\t\\t\\t\\tand: [CSSeparators includes: char]].\\n\\t[in atEnd] whileFalse: [\\n\\t\\tnext _ in next.\\n\\t\\t(isSeparator value: next)\\n\\t\\t\\tifTrue: [\\n\\t\\t\\t\\tout nextPut: $ .\\n\\t\\t\\t\\t[in atEnd or:\\n\\t\\t\\t\\t\\t[next _ in next.\\n\\t\\t\\t\\t\\t(isSeparator value: next)\\n\\t\\t\\t\\t\\t\\tifTrue: [false]\\n\\t\\t\\t\\t\\t\\tifFalse: [out nextPut: next. true]]] whileFalse]\\n\\t\\t\\tifFalse: [out nextPut: next]].\\n\\t^ out contents! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 8/27/2002 14:06'!\\nwithoutLeadingDigits\\n\\t\\\"Answer the portion of the receiver that follows any leading series of digits and blanks. If the receiver consists entirely of digits and blanks, return an empty string\\\"\\n\\t| firstNonDigit |\\n\\tfirstNonDigit _ (self findFirst: [:m | m isDigit not and: [m ~= $ ]]).\\n\\t^ firstNonDigit > 0\\n\\t\\tifTrue:\\n\\t\\t\\t[self copyFrom: firstNonDigit to: self size]\\n\\t\\tifFalse:\\n\\t\\t\\t['']\\n\\n\\\"\\n'234Whoopie' withoutLeadingDigits\\n' 4321 BlastOff!!' withoutLeadingDigits\\n'wimpy' withoutLeadingDigits\\n' 89Ten ' withoutLeadingDigits\\n'78 92' withoutLeadingDigits\\n\\\"\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 11/3/2004 19:24'!\\nwithoutTrailingBlanks\\n\\t\\\"Return a copy of the receiver from which trailing blanks have been trimmed.\\\"\\n\\n\\t| last |\\n\\tlast _ self findLast: [:c | c isSeparator not].\\n\\tlast = 0 ifTrue: [^ '']. \\\"no non-separator character\\\"\\n\\t^ self copyFrom: 1 to: last\\n\\n\\t\\\" ' abc d ' withoutTrailingBlanks\\\"\\n! !\\n\\n!String methodsFor: 'converting' stamp: 'yo 8/27/2002 14:06'!\\nwithoutTrailingDigits\\n\\t\\\"Answer the portion of the receiver that precedes any trailing series of digits and blanks. If the receiver consists entirely of digits and blanks, return an empty string\\\"\\n\\t| firstDigit |\\n\\tfirstDigit _ (self findFirst: [:m | m isDigit or: [m = $ ]]).\\n\\t^ firstDigit > 0\\n\\t\\tifTrue:\\n\\t\\t\\t[self copyFrom: 1 to: firstDigit-1]\\n\\t\\tifFalse:\\n\\t\\t\\t[self]\\n\\n\\\"\\n'Whoopie234' withoutTrailingDigits\\n' 4321 BlastOff!!' withoutLeadingDigits\\n'wimpy' withoutLeadingDigits\\n' 89Ten ' withoutLeadingDigits\\n'78 92' withoutLeadingDigits\\n\\\"\\n! !\\n\\n\\n!String methodsFor: 'copying' stamp: 'yo 11/3/2004 19:24'!\\ncopyReplaceTokens: oldSubstring with: newSubstring \\n\\t\\\"Replace all occurrences of oldSubstring that are surrounded\\n\\tby non-alphanumeric characters\\\"\\n\\t^ self copyReplaceAll: oldSubstring with: newSubstring asTokens: true\\n\\t\\\"'File asFile Files File''s File' copyReplaceTokens: 'File' with: 'Snick'\\\"! !\\n\\n!String methodsFor: 'copying' stamp: 'yo 11/3/2004 19:24'!\\ndeepCopy\\n\\t\\\"DeepCopy would otherwise mean make a copy of the character; since \\n\\tcharacters are unique, just return a shallowCopy.\\\"\\n\\n\\t^self shallowCopy! !\\n\\n!String methodsFor: 'copying' stamp: 'yo 11/3/2004 19:24'!\\npadded: leftOrRight to: length with: char\\n\\tleftOrRight = #left ifTrue:\\n\\t\\t[^ (String new: (length - self size max: 0) withAll: char) , self].\\n\\tleftOrRight = #right ifTrue:\\n\\t\\t[^ self , (String new: (length - self size max: 0) withAll: char)].! !\\n\\n\\n!String methodsFor: 'displaying' stamp: 'yo 11/3/2004 19:24'!\\ndisplayAt: aPoint \\n\\t\\\"Display the receiver as a DisplayText at aPoint on the display screen.\\\"\\n\\n\\tself displayOn: Display at: aPoint! !\\n\\n!String methodsFor: 'displaying' stamp: 'yo 11/3/2004 19:24'!\\ndisplayOn: aDisplayMedium\\n\\t\\\"Display the receiver on the given DisplayMedium. 5/16/96 sw\\\"\\n\\n\\tself displayOn: aDisplayMedium at: 0 @ 0! !\\n\\n!String methodsFor: 'displaying' stamp: 'yo 11/3/2004 19:24'!\\ndisplayOn: aDisplayMedium at: aPoint \\n\\t\\\"Show a representation of the receiver as a DisplayText at location aPoint on aDisplayMedium, using black-colored text.\\\"\\n\\n\\tself displayOn: aDisplayMedium at: aPoint textColor: Color black! !\\n\\n!String methodsFor: 'displaying' stamp: 'yo 11/3/2004 19:24'!\\ndisplayOn: aDisplayMedium at: aPoint textColor: aColor\\n\\t\\\"Show a representation of the receiver as a DisplayText at location aPoint on aDisplayMedium, rendering the text in the designated color\\\"\\n\\n\\t(self asDisplayText foregroundColor: (aColor ifNil: [Color black]) backgroundColor: Color white)\\n\\t\\tdisplayOn: aDisplayMedium at: aPoint! !\\n\\n!String methodsFor: 'displaying' stamp: 'yo 11/3/2004 19:24'!\\ndisplayProgressAt: aPoint from: minVal to: maxVal during: workBlock \\n\\t\\\"Display this string as a caption over a progress bar while workBlock is evaluated.\\n\\nEXAMPLE (Select next 6 lines and Do It)\\n'Now here''s some Real Progress'\\n\\tdisplayProgressAt: Sensor cursorPoint\\n\\tfrom: 0 to: 10\\n\\tduring: [:bar |\\n\\t1 to: 10 do: [:x | bar value: x.\\n\\t\\t\\t(Delay forMilliseconds: 500) wait]].\\n\\nHOW IT WORKS (Try this in any other language :-)\\nSince your code (the last 2 lines in the above example) is in a block,\\nthis method gets control to display its heading before, and clean up \\nthe screen after, its execution.\\nThe key, though, is that the block is supplied with an argument,\\nnamed 'bar' in the example, which will update the bar image every \\nit is sent the message value: x, where x is in the from:to: range.\\n\\\"\\n\\t^ProgressInitiationException \\n\\t\\tdisplay: self\\n\\t\\tat: aPoint \\n\\t\\tfrom: minVal \\n\\t\\tto: maxVal \\n\\t\\tduring: workBlock! !\\n\\n\\n!String methodsFor: 'encoding' stamp: 'ar 4/10/2005 17:16'!\\ngetInteger32: location\\n\\t| integer |\\n\\t<primitive: 'getInteger' module: 'IntegerPokerPlugin'>\\n\\t\\\"^IntegerPokerPlugin doPrimitive: #getInteger\\\"\\n\\n\\t\\\"the following is about 7x faster than interpreting the plugin if not compiled\\\"\\n\\n\\tinteger := \\n\\t\\t((self at: location) asInteger bitShift: 24) +\\n\\t\\t((self at: location+1) asInteger bitShift: 16) +\\n\\t\\t((self at: location+2) asInteger bitShift: 8) +\\n\\t\\t(self at: location+3) asInteger.\\n\\n\\tinteger > 1073741824 ifTrue: [^1073741824 - integer ].\\n\\t^integer\\n! !\\n\\n!String methodsFor: 'encoding' stamp: 'ar 4/10/2005 17:17'!\\nputInteger32: anInteger at: location\\n\\t| integer |\\n\\t<primitive: 'putInteger' module: 'IntegerPokerPlugin'>\\n\\t\\\"IntegerPokerPlugin doPrimitive: #putInteger\\\"\\n\\n\\t\\\"the following is close to 20x faster than the above if the primitive is not compiled\\\"\\n\\t\\\"PUTCOUNTER _ PUTCOUNTER + 1.\\\"\\n\\tinteger _ anInteger.\\n\\tinteger < 0 ifTrue: [integer := 1073741824 - integer. ].\\n\\tself at: location+3 put: (Character value: (integer \\\\\\\\ 256)).\\n\\tself at: location+2 put: (Character value: (integer bitShift: -8) \\\\\\\\ 256).\\n\\tself at: location+1 put: (Character value: (integer bitShift: -16) \\\\\\\\ 256).\\n\\tself at: location put: (Character value: (integer bitShift: -24) \\\\\\\\ 256).\\n\\n\\\"Smalltalk at: #PUTCOUNTER put: 0\\\"! !\\n\\n!String methodsFor: 'encoding' stamp: 'ar 4/10/2005 17:18'!\\nwriteLeadingCharRunsOn: stream\\n\\n\\t| runLength runValues runStart leadingChar |\\n\\tself isEmpty ifTrue: [^ self].\\n\\n\\trunLength _ OrderedCollection new.\\n\\trunValues _ OrderedCollection new.\\n\\trunStart _ 1.\\n\\tleadingChar _ (self at: runStart) leadingChar.\\n\\t2 to: self size do: [:index |\\n\\t\\t(self at: index) leadingChar = leadingChar ifFalse: [\\n\\t\\t\\trunValues add: leadingChar.\\n\\t\\t\\trunLength add: (index - runStart).\\n\\t\\t\\tleadingChar _ (self at: index) leadingChar.\\n\\t\\t\\trunStart _ index.\\n\\t\\t].\\n\\t].\\n\\trunValues add: (self last) leadingChar.\\n\\trunLength add: self size + 1 - runStart.\\n\\n\\tstream nextPut: $(.\\n\\trunLength do: [:rr | rr printOn: stream. stream space].\\n\\tstream skip: -1; nextPut: $).\\n\\trunValues do: [:vv | vv printOn: stream. stream nextPut: $,].\\n\\tstream skip: -1.\\n! !\\n\\n\\n!String methodsFor: 'filter streaming' stamp: 'yo 8/26/2002 22:31'!\\nbyteEncode:aStream\\n\\n\\t^aStream writeString: self.\\n! !\\n\\n!String methodsFor: 'filter streaming' stamp: 'yo 8/26/2002 22:31'!\\nputOn:aStream\\n\\n\\t^aStream nextPutAll: self.\\n! !\\n\\n\\n!String methodsFor: 'formatting' stamp: 'md 5/26/2005 13:34'!\\nexpandMacros\\n\\t^self expandMacrosWithArguments: #()! !\\n\\n!String methodsFor: 'formatting' stamp: 'md 5/26/2005 13:34'!\\nexpandMacrosWithArguments: anArray \\n\\t| newStream readStream char index |\\n\\tnewStream := WriteStream on: (String new: self size).\\n\\treadStream := ReadStream on: self.\\n\\t[readStream atEnd] whileFalse: \\n\\t\\t\\t[char := readStream next.\\n\\t\\t\\tchar == $< \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[| nextChar |\\n\\t\\t\\t\\t\\tnextChar := readStream next asUppercase.\\n\\t\\t\\t\\t\\tnextChar == $N ifTrue: [newStream cr].\\n\\t\\t\\t\\t\\tnextChar == $T ifTrue: [newStream tab].\\n\\t\\t\\t\\t\\tnextChar isDigit \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[index := nextChar digitValue.\\n\\t\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\t[readStream atEnd \\n\\t\\t\\t\\t\\t\\t\\t\\tor: [(nextChar := readStream next asUppercase) isDigit not]] \\n\\t\\t\\t\\t\\t\\t\\t\\t\\twhileFalse: [index := index * 10 + nextChar digitValue]].\\n\\t\\t\\t\\t\\tnextChar == $? \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[| trueString falseString |\\n\\t\\t\\t\\t\\t\\t\\ttrueString := readStream upTo: $:.\\n\\t\\t\\t\\t\\t\\t\\tfalseString := readStream upTo: $>.\\n\\t\\t\\t\\t\\t\\t\\treadStream position: readStream position - 1.\\n\\t\\t\\t\\t\\t\\t\\tnewStream \\n\\t\\t\\t\\t\\t\\t\\t\\tnextPutAll: ((anArray at: index) ifTrue: [trueString] ifFalse: [falseString])].\\n\\t\\t\\t\\t\\tnextChar == $P \\n\\t\\t\\t\\t\\t\\tifTrue: [newStream nextPutAll: (anArray at: index) printString].\\n\\t\\t\\t\\t\\tnextChar == $S ifTrue: [newStream nextPutAll: (anArray at: index)].\\n\\t\\t\\t\\t\\treadStream skipTo: $>]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[newStream nextPut: (char == $% ifTrue: [readStream next] ifFalse: [char])]].\\n\\t^newStream contents! !\\n\\n!String methodsFor: 'formatting' stamp: 'md 5/26/2005 13:34'!\\nexpandMacrosWith: anObject \\n\\t^self expandMacrosWithArguments: (Array with: anObject)! !\\n\\n!String methodsFor: 'formatting' stamp: 'md 5/26/2005 13:34'!\\nexpandMacrosWith: anObject with: anotherObject \\n\\t^self \\n\\t\\texpandMacrosWithArguments: (Array with: anObject with: anotherObject)! !\\n\\n!String methodsFor: 'formatting' stamp: 'md 5/26/2005 13:34'!\\nexpandMacrosWith: anObject with: anotherObject with: thirdObject \\n\\t^self expandMacrosWithArguments: (Array \\n\\t\\t\\t\\twith: anObject\\n\\t\\t\\t\\twith: anotherObject\\n\\t\\t\\t\\twith: thirdObject)! !\\n\\n!String methodsFor: 'formatting' stamp: 'md 5/26/2005 13:34'!\\nexpandMacrosWith: anObject with: anotherObject with: thirdObject with: fourthObject \\n\\t^self expandMacrosWithArguments: (Array \\n\\t\\t\\t\\twith: anObject\\n\\t\\t\\t\\twith: anotherObject\\n\\t\\t\\t\\twith: thirdObject\\n\\t\\t\\t\\twith: fourthObject)! !\\n\\n!String methodsFor: 'formatting' stamp: 'yo 11/3/2004 19:24'!\\nformat: aCollection \\n\\t\\\"format the receiver with aCollection \\n\\t \\n\\tsimplest example: \\n\\t'foo {1} bar' format: {Date today}.\\n\\t \\n\\tcomplete example: \\n\\t'\\\\{ \\\\} \\\\\\\\ foo {1} bar {2}' format: {12. 'string'}. \\n\\t\\\"\\n\\t| result stream |\\n\\tresult := String new writeStream.\\n\\tstream := self readStream.\\n\\n\\t[stream atEnd]\\n\\t\\twhileFalse: [| currentChar | \\n\\t\\t\\tcurrentChar := stream next.\\n\\t\\t\\tcurrentChar == ${\\n\\t\\t\\t\\tifTrue: [| expression | \\n\\t\\t\\t\\t\\texpression := self getEnclosedExpressionFrom: stream.\\n\\t\\t\\t\\t\\tresult\\n\\t\\t\\t\\t\\t\\tnextPutAll: (self evaluateExpression: expression parameters: aCollection)]\\n\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\tcurrentChar == $\\\\\\n\\t\\t\\t\\t\\t\\tifTrue: [stream atEnd\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [result nextPut: stream next]]\\n\\t\\t\\t\\t\\t\\tifFalse: [result nextPut: currentChar]]].\\n\\n\\t^ result contents! !\\n\\n!String methodsFor: 'formatting' stamp: 'yo 11/3/2004 19:24'!\\nwithCRs\\n\\t\\\"Return a copy of the receiver in which backslash (\\\\) characters have been replaced with carriage returns.\\\"\\n\\n\\t^ self collect: [ :c | c = $\\\\ ifTrue: [ Character cr ] ifFalse: [ c ]].! !\\n\\n\\n!String methodsFor: 'internet' stamp: 'yo 12/28/2003 01:17'!\\ndecodeMimeHeader\\n\\t\\\"See RFC 2047, MIME Part Three: Message Header Extension for Non-ASCII \\n\\tText. Text containing non-ASCII characters is encoded by the sequence \\n\\t=?character-set?encoding?encoded-text?= \\n\\tEncoding is Q (quoted printable) or B (Base64), handled by \\n\\tBase64MimeConverter / RFC2047MimeConverter.\\n\\n\\tThanks to Yokokawa-san, it works in m17n package. Try the following:\\n\\n\\t'=?ISO-2022-JP?B?U1dJS0lQT1AvGyRCPUJDKyVpJXMlQRsoQi8=?= =?ISO-2022-JP?B?GyRCJVElRiUjJSobKEIoUGF0aW8p?=' decodeMimeHeader.\\n\\\"\\n\\t| input output temp charset decoder encodedStream encoding pos |\\n\\tinput _ ReadStream on: self.\\n\\toutput _ WriteStream on: String new.\\n\\t[output\\n\\t\\tnextPutAll: (input upTo: $=).\\n\\t\\\"ASCII Text\\\"\\n\\tinput atEnd]\\n\\t\\twhileFalse: [(temp _ input next) = $?\\n\\t\\t\\t\\tifTrue: [charset _ input upTo: $?.\\n\\t\\t\\t\\t\\tencoding _ (input upTo: $?) asUppercase.\\n\\t\\t\\t\\t\\ttemp _ input upTo: $?.\\n\\t\\t\\t\\t\\tinput next.\\n\\t\\t\\t\\t\\t\\\"Skip final =\\\"\\n\\t\\t\\t\\t\\t(charset isNil or: [charset size = 0]) ifTrue: [charset _ 'LATIN-1'].\\n\\t\\t\\t\\t\\tencodedStream _ MultiByteBinaryOrTextStream on: String new encoding: charset.\\n\\t\\t\\t\\t\\tdecoder _ encoding = 'B'\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [Base64MimeConverter new]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [RFC2047MimeConverter new].\\n\\t\\t\\t\\t\\tdecoder\\n\\t\\t\\t\\t\\t\\tmimeStream: (ReadStream on: temp);\\n\\t\\t\\t\\t\\t\\t dataStream: encodedStream;\\n\\t\\t\\t\\t\\t\\t mimeDecode.\\n\\t\\t\\t\\t\\toutput nextPutAll: encodedStream reset contents.\\n\\t\\t\\t\\t\\tpos _ input position.\\n\\t\\t\\t\\t\\tinput skipSeparators.\\n\\t\\t\\t\\t\\t\\\"Delete spaces if followed by =\\\"\\n\\t\\t\\t\\t\\tinput peek = $=\\n\\t\\t\\t\\t\\t\\tifFalse: [input position: pos]]\\n\\t\\t\\t\\tifFalse: [output nextPut: $=;\\n\\t\\t\\t\\t\\t\\t nextPut: temp]].\\n\\t^ output contents! !\\n\\n!String methodsFor: 'internet' stamp: 'yo 11/3/2004 19:24'!\\ndecodeQuotedPrintable\\n\\t\\\"Assume receiver is in MIME 'quoted-printable' encoding, and decode it.\\\"\\n \\n\\t^QuotedPrintableMimeConverter mimeDecode: self as: self class! !\\n\\n!String methodsFor: 'internet' stamp: 'ar 4/9/2005 22:16'!\\nisoToSqueak\\n\\t^self \\\"no longer needed\\\"! !\\n\\n!String methodsFor: 'internet' stamp: 'yo 11/3/2004 19:24'!\\nisoToUtf8\\n\\t\\\"Convert ISO 8559-1 to UTF-8\\\"\\n\\t| s v |\\n\\ts _ WriteStream on: (String new: self size).\\n\\n\\tself do: [:c |\\n\\t\\tv _ c asciiValue.\\n\\t\\t(v > 128)\\n\\t\\t\\tifFalse: [s nextPut: c]\\n\\t\\t\\tifTrue: [\\n\\t\\t\\t\\ts nextPut: (192+(v >> 6)) asCharacter.\\n\\t\\t\\t\\ts nextPut: (128+(v bitAnd: 63)) asCharacter]].\\n\\t^s contents. \\n! !\\n\\n!String methodsFor: 'internet' stamp: 'ar 4/10/2005 15:58'!\\nmacToSqueak\\n\\t\\\"Convert the receiver from MacRoman to Squeak encoding\\\"\\n\\t^ self collect: [:each | each macToSqueak]! !\\n\\n!String methodsFor: 'internet' stamp: 'ar 4/9/2005 22:16'!\\nsqueakToIso\\n\\t^self \\\"no longer needed\\\"! !\\n\\n!String methodsFor: 'internet' stamp: 'ar 4/10/2005 15:55'!\\nsqueakToMac\\n\\t\\\"Convert the receiver from Squeak to MacRoman encoding\\\"\\n\\t^ self collect: [:each | each squeakToMac]! !\\n\\n!String methodsFor: 'internet' stamp: 'yo 11/3/2004 19:24'!\\nutf8ToIso\\n\\t\\\"Only UTF-8 characters that maps to 8-bit ISO-8559-1 values are converted. Others raises an error\\\"\\n\\t| s i c v c2 v2 |\\n\\ts _ WriteStream on: (String new: self size).\\n\\t\\n\\ti _ 1.\\n\\t[i <= self size] whileTrue: [\\n\\t\\tc _ self at: i. i_i+1.\\n\\t\\tv _ c asciiValue.\\n\\t\\t(v > 128)\\n\\t\\t\\tifFalse: [ s nextPut: c ]\\n\\t\\t\\tifTrue: [((v bitAnd: 252) == 192)\\n\\t\\t\\t\\tifFalse: [self error: 'illegal UTF-8 ISO character']\\n\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\t(i > self size) ifTrue: [ self error: 'illegal end-of-string, expected 2nd byte of UTF-8'].\\n\\t\\t\\t\\t\\tc2 _ self at: i. i_i+1.\\n\\t\\t\\t\\t\\tv2 _ c2 asciiValue.\\n\\t\\t\\t\\t\\t((v2 bitAnd: 192) = 128) ifFalse: [self error: 'illegal 2nd UTF-8 char']. \\n\\t\\t\\t\\t\\ts nextPut: ((v2 bitAnd: 63) bitOr: ((v << 6) bitAnd: 192)) asCharacter]]].\\n\\t^s contents. \\n! !\\n\\n!String methodsFor: 'internet' stamp: 'yo 11/3/2004 19:24'!\\nwithInternetLineEndings\\n\\t\\\"change line endings from CR's to CRLF's. This is probably in\\nprepration for sending a string over the Internet\\\"\\n\\t| cr lf |\\n\\tcr _ Character cr.\\n\\tlf _ Character linefeed.\\n\\t^self class streamContents: [ :stream |\\n\\t\\tself do: [ :c |\\n\\t\\t\\tstream nextPut: c.\\n\\t\\t\\tc = cr ifTrue:[ stream nextPut: lf ]. ] ].! !\\n\\n!String methodsFor: 'internet' stamp: 'yo 11/3/2004 19:24'!\\nwithSqueakLineEndings\\n\\t\\\"assume the string is textual, and that CR, LF, and CRLF are all \\n\\tvalid line endings. Replace each occurence with a single CR\\\"\\n\\t| cr lf input c crlf inPos outPos outString lineEndPos newOutPos |\\n\\tcr _ Character cr.\\n\\tlf _ Character linefeed.\\n\\tcrlf _ CharacterSet new.\\n\\tcrlf add: cr; add: lf.\\n\\n\\tinPos _ 1.\\n\\toutPos _ 1.\\n\\toutString _\\n String new: self size.\\n\\n\\t[ lineEndPos _ self indexOfAnyOf: crlf startingAt: inPos ifAbsent: [0].\\n\\t\\tlineEndPos ~= 0 ] whileTrue: [\\n\\t\\t\\tnewOutPos _ outPos + (lineEndPos - inPos + 1).\\n\\t\\t\\toutString replaceFrom: outPos to: newOutPos - 2 with: self startingAt: inPos.\\n\\t\\t\\toutString at: newOutPos-1 put: cr.\\n\\t\\t\\toutPos _ newOutPos.\\n\\n\\t\\t\\t((self at: lineEndPos) = cr and: [ lineEndPos < self size and: [ (self at: lineEndPos+1) = lf ] ]) ifTrue: [\\n\\t\\t\\t\\t\\\"CRLF ending\\\"\\n\\t\\t\\t\\tinPos _ lineEndPos + 2 ]\\n\\t\\t\\tifFalse: [ \\n\\t\\t\\t\\t\\\"CR or LF ending\\\"\\n\\t\\t\\t\\tinPos _ lineEndPos + 1 ]. ].\\n\\n\\t\\\"no more line endings. copy the rest\\\"\\n\\tnewOutPos _ outPos + (self size - inPos + 1).\\n\\toutString replaceFrom: outPos to: newOutPos-1 with: self startingAt: inPos.\\n\\n\\t^outString copyFrom: 1 to: newOutPos-1\\n\\t! !\\n\\n!String methodsFor: 'internet' stamp: 'yo 11/3/2004 19:24'!\\nwithoutQuoting\\n\\t\\\"remove the initial and final quote marks, if present\\\"\\n\\t\\\"'''h''' withoutQuoting\\\"\\n\\t| quote |\\n\\tself size < 2 ifTrue: [ ^self ].\\n\\tquote _ self first.\\n\\t(quote = $' or: [ quote = $\\\" ])\\n\\t\\tifTrue: [ ^self copyFrom: 2 to: self size - 1 ]\\n\\t\\tifFalse: [ ^self ].! !\\n\\n\\n!String methodsFor: 'paragraph support' stamp: 'yo 8/26/2002 22:19'!\\nindentationIfBlank: aBlock\\n\\t\\\"Answer the number of leading tabs in the receiver. If there are\\n\\t no visible characters, pass the number of tabs to aBlock and return its value.\\\"\\n\\n\\t| reader leadingTabs lastSeparator cr tab ch |\\n\\tcr _ Character cr.\\n\\ttab _ Character tab.\\n\\treader _ ReadStream on: self.\\n\\tleadingTabs _ 0.\\n\\t[reader atEnd not and: [(ch _ reader next) = tab]]\\n\\t\\twhileTrue: [leadingTabs _ leadingTabs + 1].\\n\\tlastSeparator _ leadingTabs + 1.\\n\\t[reader atEnd not and: [ch isSeparator and: [ch ~= cr]]]\\n\\t\\twhileTrue: [lastSeparator _ lastSeparator + 1. ch _ reader next].\\n\\tlastSeparator = self size | (ch = cr)\\n\\t\\tifTrue: [^aBlock value: leadingTabs].\\n\\t^ leadingTabs.\\n! !\\n\\n\\n!String methodsFor: 'printing' stamp: 'yo 11/3/2004 19:24'!\\nbasicType\\n\\t\\\"Answer a symbol representing the inherent type of the receiver\\\"\\n\\n\\t\\\"Number String Boolean player collection sound color etc\\\"\\n\\t^ #String! !\\n\\n!String methodsFor: 'printing' stamp: 'yo 8/26/2002 22:57'!\\nencodeDoublingQuoteOn: aStream \\n\\t\\\"Print inside string quotes, doubling inbedded quotes.\\\"\\n\\t| x |\\n\\taStream print: $'.\\n\\t1 to: self size do:\\n\\t\\t[:i |\\n\\t\\taStream print: (x _ self at: i).\\n\\t\\tx = $' ifTrue: [aStream print: x]].\\n\\taStream print: $'! !\\n\\n!String methodsFor: 'printing' stamp: 'yo 11/3/2004 19:24'!\\nisLiteral\\n\\n\\t^true! !\\n\\n!String methodsFor: 'printing' stamp: 'sd 7/8/2006 18:06'!\\nprintOn: aStream \\n\\t\\\"Print inside string quotes, doubling inbedded quotes.\\\"\\n \\n\\tself storeOn: aStream! !\\n\\n!String methodsFor: 'printing' stamp: 'yo 8/26/2002 22:58'!\\nstoreOn: aStream \\n\\t\\\"Print inside string quotes, doubling inbedded quotes.\\\"\\n\\t| x |\\n\\taStream nextPut: $'.\\n\\t1 to: self size do:\\n\\t\\t[:i |\\n\\t\\taStream nextPut: (x _ self at: i).\\n\\t\\tx = $' ifTrue: [aStream nextPut: x]].\\n\\taStream nextPut: $'! !\\n\\n!String methodsFor: 'printing' stamp: 'yo 11/3/2004 19:24'!\\nstringRepresentation\\n\\t\\\"Answer a string that represents the receiver. For most objects this is simply its printString, but for strings themselves, it's themselves, to avoid the superfluous extra pair of quotes. 6/12/96 sw\\\"\\n\\n\\t^ self ! !\\n\\n\\n!String methodsFor: 'system primitives' stamp: 'sw 10/20/2004 17:51'!\\nendsWithAColon \\n\\t\\\"Answer whether the final character of the receiver is a colon\\\"\\n\\n\\t^ self size > 0 and: [self last == $:]\\n\\n\\\"\\n#fred: endsWithAColon\\n'fred' endsWithAColon\\n\\\"! !\\n\\n!String methodsFor: 'system primitives' stamp: 'ar 4/10/2005 16:55'!\\nfindSubstring: key in: body startingAt: start matchTable: matchTable\\n\\t\\\"Answer the index in the string body at which the substring key first occurs, at or beyond start. The match is determined using matchTable, which can be used to effect, eg, case-insensitive matches. If no match is found, zero will be returned.\\\"\\n\\t| index c1 c2 |\\n\\tmatchTable == nil ifTrue: [\\n\\t\\tkey size = 0 ifTrue: [^ 0].\\n\\t\\tstart to: body size - key size + 1 do:\\n\\t\\t\\t[:startIndex |\\n\\t\\t\\tindex _ 1.\\n\\t\\t\\t\\t[(body at: startIndex+index-1)\\n\\t\\t\\t\\t\\t= (key at: index)]\\n\\t\\t\\t\\t\\twhileTrue:\\n\\t\\t\\t\\t\\t[index = key size ifTrue: [^ startIndex].\\n\\t\\t\\t\\t\\tindex _ index+1]].\\n\\t\\t^ 0\\n\\t].\\n\\n\\tkey size = 0 ifTrue: [^ 0].\\n\\tstart to: body size - key size + 1 do:\\n\\t\\t[:startIndex |\\n\\t\\tindex _ 1.\\n\\t\\t[c1 _ body at: startIndex+index-1.\\n\\t\\tc2 _ key at: index.\\n\\t\\t((c1 leadingChar = 0) ifTrue: [(matchTable at: c1 asciiValue + 1)]\\n\\t\\t\\t\\t\\t\\tifFalse: [c1 asciiValue + 1])\\n\\t\\t\\t= ((c2 leadingChar = 0) ifTrue: [(matchTable at: c2 asciiValue + 1)]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [c2 asciiValue + 1])]\\n\\t\\t\\twhileTrue:\\n\\t\\t\\t\\t[index = key size ifTrue: [^ startIndex].\\n\\t\\t\\t\\tindex _ index+1]].\\n\\t^ 0\\n! !\\n\\n!String methodsFor: 'system primitives' stamp: 'yo 11/3/2004 19:24'!\\nnumArgs \\n\\t\\\"Answer either the number of arguments that the receiver would take if considered a selector. Answer -1 if it couldn't be a selector. Note that currently this will answer -1 for anything begining with an uppercase letter even though the system will accept such symbols as selectors. It is intended mostly for the assistance of spelling correction.\\\"\\n\\n\\t| firstChar numColons excess start ix |\\n\\tself size = 0 ifTrue: [^ -1].\\n\\tfirstChar _ self at: 1.\\n\\t(firstChar isLetter or: [firstChar = $:]) ifTrue:\\n\\t\\t[\\\"Fast reject if any chars are non-alphanumeric\\\"\\n\\t\\t(self findSubstring: '~' in: self startingAt: 1 matchTable: Tokenish) > 0 ifTrue: [^ -1].\\n\\t\\t\\\"Fast colon count\\\"\\n\\t\\tnumColons _ 0. start _ 1.\\n\\t\\t[(ix _ self findSubstring: ':' in: self startingAt: start matchTable: CaseSensitiveOrder) > 0]\\n\\t\\t\\twhileTrue:\\n\\t\\t\\t\\t[numColons _ numColons + 1.\\n\\t\\t\\t\\tstart _ ix + 1].\\n\\t\\tnumColons = 0 ifTrue: [^ 0].\\n\\t\\tfirstChar = $:\\n\\t\\t\\tifTrue: [excess _ 2 \\\"Has an initial keyword, as #:if:then:else:\\\"]\\n\\t\\t\\tifFalse: [excess _ 0].\\n\\t\\tself last = $:\\n\\t\\t\\tifTrue: [^ numColons - excess]\\n\\t\\t\\tifFalse: [^ numColons - excess - 1 \\\"Has a final keywords as #nextPut::andCR\\\"]].\\n\\tfirstChar isSpecial ifTrue:\\n\\t\\t[self size = 1 ifTrue: [^ 1].\\n\\t\\t2 to: self size do: [:i | (self at: i) isSpecial ifFalse: [^ -1]].\\n\\t\\t^ 1].\\n\\t^ -1.! !\\n\\n\\n!String methodsFor: 'testing' stamp: 'yo 11/3/2004 19:24'!\\nhasContentsInExplorer\\n\\n\\t^false! !\\n\\n!String methodsFor: 'testing' stamp: 'ar 4/10/2005 16:49'!\\nincludesUnifiedCharacter\\n\\t^false! !\\n\\n!String methodsFor: 'testing' stamp: 'yo 11/3/2004 19:24'!\\nisAllDigits\\n\\t\\\"whether the receiver is composed entirely of digits\\\"\\n\\tself do: [:c | c isDigit ifFalse: [^ false]].\\n\\t^ true! !\\n\\n!String methodsFor: 'testing' stamp: 'yo 11/3/2004 19:24'!\\nisAllSeparators\\n\\t\\\"whether the receiver is composed entirely of separators\\\"\\n\\tself do: [ :c | c isSeparator ifFalse: [ ^false ] ].\\n\\t^true! !\\n\\n!String methodsFor: 'testing' stamp: 'yo 8/4/2003 12:26'!\\nisAsciiString\\n\\n\\t| c |\\n\\tc _ self detect: [:each | each asciiValue > 127] ifNone: [nil].\\n\\t^ c isNil.\\n! !\\n\\n!String methodsFor: 'testing' stamp: 'ar 4/10/2005 16:23'!\\nisByteString\\n\\t\\\"Answer whether the receiver is a ByteString\\\"\\n\\t^false! !\\n\\n!String methodsFor: 'testing' stamp: 'ar 4/10/2005 23:25'!\\nisOctetString\\n\\t\\\"Answer whether the receiver can be represented as a byte string. \\n\\tThis is different from asking whether the receiver *is* a ByteString \\n\\t(i.e., #isByteString)\\\"\\n\\t1 to: self size do: [:pos |\\n\\t\\t(self at: pos) asInteger >= 256 ifTrue: [^ false].\\n\\t].\\n\\t^ true.\\n! !\\n\\n!String methodsFor: 'testing' stamp: 'yo 11/3/2004 19:24'!\\nisString\\n\\t^ true! !\\n\\n!String methodsFor: 'testing' stamp: 'ar 4/12/2005 19:52'!\\nisWideString\\n\\t\\\"Answer whether the receiver is a WideString\\\"\\n\\t^false! !\\n\\n!String methodsFor: 'testing' stamp: 'yo 11/3/2004 19:24'!\\nlastSpacePosition\\n\\t\\\"Answer the character position of the final space or other separator character in the receiver, and 0 if none\\\"\\n\\tself size to: 1 by: -1 do:\\n\\t\\t[:i | ((self at: i) isSeparator) ifTrue: [^ i]].\\n\\t^ 0\\n\\n\\\"\\n'fred the bear' lastSpacePosition\\n'ziggie' lastSpacePosition\\n'elvis ' lastSpacePosition\\n'wimpy ' lastSpacePosition\\n'' lastSpacePosition\\n\\\"! !\\n\\n\\n!String methodsFor: 'translating' stamp: 'dgd 8/24/2004 19:42'!\\ntranslated\\n\\t\\\"answer the receiver translated to the default language\\\"\\n\\t^ NaturalLanguageTranslator current translate: self! !\\n\\n!String methodsFor: 'translating' stamp: 'dgd 8/27/2004 18:43'!\\ntranslatedIfCorresponds\\n\\t\\\"answer the receiver translated to the default language only if \\n\\tthe receiver begins and ends with an underscore (_)\\\"\\n\\t^ ('_*_' match: self)\\n\\t\\tifTrue: [(self copyFrom: 2 to: self size - 1) translated]\\n\\t\\tifFalse: [self]! !\\n\\n!String methodsFor: 'translating' stamp: 'dgd 8/24/2004 19:38'!\\ntranslatedTo: localeID \\n\\t\\\"answer the receiver translated to the given locale id\\\"\\n\\t^ localeID translator translate: self! !\\n\\n\\n!String methodsFor: 'user interface' stamp: 'md 7/28/2005 20:42'!\\nasExplorerString\\n\\n\\t^ self printString! !\\n\\n!String methodsFor: 'user interface' stamp: 'ar 9/27/2005 20:02'!\\nopenInWorkspaceWithTitle: aTitle\\n\\t\\\"Open up a workspace with the receiver as its contents, with the given title\\\"\\n\\tUIManager default edit: self label: aTitle! !\\n\\n\\n!String methodsFor: '*eToys-*Morphic' stamp: 'ar 4/10/2005 17:06'!\\nnewTileMorphRepresentative\\n\\t^ TileMorph new setLiteral: self;addSuffixIfCan! !\\n\\n\\n!String methodsFor: '*Morphic' stamp: 'ar 4/10/2005 17:07'!\\nasMorph \\n\\t\\\"Answer the receiver as a StringMorph\\\"\\n\\n\\t^ StringMorph contents: self\\n\\n\\\"'bugs black blood' asMorph openInHand\\\"! !\\n\\n!String methodsFor: '*Morphic' stamp: 'ar 4/10/2005 17:07'!\\nasStringMorph \\n\\t\\\"Answer the receiver as a StringMorph\\\"\\n\\n\\t^ StringMorph contents: self\\n\\n\\\"'bugs black blood' asStringMorph openInHand\\\"! !\\n\\n\\n!String methodsFor: '*MorphicExtras-*morphic-Postscript Canvases' stamp: 'yo 11/3/2004 19:24'!\\nasPostscript\\n\\n\\t| temp |\\n\\ttemp _ self asString copyReplaceAll: '(' with: '\\\\('.\\n\\ttemp _ temp copyReplaceAll: ')' with: '\\\\)'.\\n\\ttemp _ temp copyReplaceAll: '\\n' \\n\\t\\t\\twith: ''.\\n\\t^ PostscriptEncoder mapMacStringToPS: temp! !\\n\\n\\n!String methodsFor: '*Morphic-converting' stamp: 'yo 11/3/2004 19:24'!\\nopenAsMorph\\n\\t\\\"Open the receiver as a morph\\\"\\n\\n\\t^ self asMorph openInHand ! !\\n\\n\\n!String methodsFor: '*monticello' stamp: 'avi 2/4/2004 14:14'!\\nextractNumber\\n\\t^ ('0', self select: [:ea | ea isDigit]) asNumber! !\\n\\n\\n!String methodsFor: '*network-uri' stamp: 'mir 2/26/2002 14:59'!\\nasURI\\n\\t\\\"convert to a Url\\\"\\n\\t\\\"'http://www.cc.gatech.edu/' asURI\\\"\\n\\t\\\"'msw://chaos.resnet.gatech.edu:9000/' asURI\\\"\\n\\t^URI fromString: self! !\\n\\n\\n!String methodsFor: '*packageinfo-base' stamp: 'nk 8/30/2004 09:02'!\\nescapeEntities\\n\\t^ self species streamContents: [:s | self do: [:c | s nextPutAll: c escapeEntities]]\\n! !\\n\\n\\n!String methodsFor: '*services-base' stamp: 'rr 3/21/2006 12:00'!\\nservice\\n\\t^ self serviceOrNil ifNil: [ServiceCategory new id: self asSymbol]! !\\n\\n!String methodsFor: '*services-base' stamp: 'rr 3/21/2006 12:00'!\\nserviceOrNil\\n\\t^ ServiceRegistry current serviceWithId: self asSymbol! !\\n\\n\\n!String methodsFor: '*versionnumber' stamp: 'yo 11/3/2004 19:24'!\\nasVersion\\n\\n\\t\\\"Answer a VersionNumber\\\"\\n\\n\\n\\n\\t^VersionNumber fromString: self! !\\n\\n\\n!String methodsFor: 'private' stamp: 'yo 11/3/2004 19:24'!\\ncorrectAgainstEnumerator: wordBlock continuedFrom: oldCollection\\n\\t\\\"The guts of correction, instead of a wordList, there is a block that should take another block and enumerate over some list with it.\\\"\\n\\n\\t| choices scoreMin results score maxChoices |\\n\\tscoreMin _ self size // 2 min: 3.\\n\\tmaxChoices _ 10.\\n\\toldCollection isNil\\n\\t\\tifTrue: [ choices _ SortedCollection sortBlock: [ :x :y | x value > y value ] ]\\n\\t\\tifFalse: [ choices _ oldCollection ].\\n\\twordBlock isNil\\n\\t\\tifTrue:\\n\\t\\t\\t[ results _ OrderedCollection new.\\n\\t\\t\\t1 to: (maxChoices min: choices size) do: [ :i | results add: (choices at: i) key ] ]\\n\\t\\tifFalse:\\n\\t\\t\\t[ wordBlock value: [ :word |\\n\\t\\t\\t\\t(score _ self alike: word) >= scoreMin ifTrue:\\n\\t\\t\\t\\t\\t[ choices add: (Association key: word value: score).\\n\\t\\t\\t\\t\\t\\t(choices size >= maxChoices) ifTrue: [ scoreMin _ (choices at: maxChoices) value] ] ].\\n\\t\\t\\tresults _ choices ].\\n\\t^ results! !\\n\\n!String methodsFor: 'private' stamp: 'yo 11/3/2004 19:24'!\\nevaluateExpression: aString parameters: aCollection \\n\\t\\\"private - evaluate the expression aString with \\n\\taCollection as the parameters and answer the \\n\\tevaluation result as an string\\\"\\n\\t| index |\\n\\tindex := ('0' , aString) asNumber.\\n\\n\\tindex isZero\\n\\t\\tifTrue: [^ '[invalid subscript: {1}]' format: {aString}].\\n\\n\\tindex > aCollection size\\n\\t\\tifTrue: [^ '[subscript is out of bounds: {1}]' format: {aString}].\\n\\n\\t^ (aCollection at: index) asString! !\\n\\n!String methodsFor: 'private' stamp: 'yo 11/3/2004 19:24'!\\ngetEnclosedExpressionFrom: aStream \\n\\t\\\"private - get the expression enclosed between '{' and \\n\\t'}' and remove all the characters from the stream\\\"\\n\\t| result currentChar |\\n\\tresult := String new writeStream.\\n\\n\\t[aStream atEnd \\n\\t\\tor: [(currentChar := aStream next) == $}]]\\n\\t\\twhileFalse: [result nextPut: currentChar].\\n\\n\\t^ result contents withBlanksTrimmed! !\\n\\n!String methodsFor: 'private' stamp: 'yo 8/26/2002 22:53'!\\nreplaceFrom: start to: stop with: replacement startingAt: repStart \\n\\t\\\"Primitive. This destructively replaces elements from start to stop in the receiver starting at index, repStart, in the collection, replacement. Answer the receiver. Range checks are performed in the primitive only. Optional. See Object documentation whatIsAPrimitive.\\\"\\n\\t<primitive: 105>\\n\\tsuper replaceFrom: start to: stop with: replacement startingAt: repStart! !\\n\\n!String methodsFor: 'private' stamp: 'yo 8/28/2002 15:22'!\\nstringhash\\n\\n\\t^ self hash.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nString class\\n\\tinstanceVariableNames: ''!\\n\\n!String class methodsFor: 'examples' stamp: 'yo 11/3/2004 19:24'!\\nexample\\n\\t\\\"To see the string displayed at the cursor point, execute this expression\\n\\tand select a point by pressing a mouse button.\\\"\\n\\n\\t'this is some text' displayOn: Display at: Sensor waitButton! !\\n\\n\\n!String class methodsFor: 'formatting' stamp: 'md 6/5/2005 07:49'!\\nexpandMacro: macroType argument: argument withExpansions: expansions \\n\\tmacroType = $s ifTrue: [^expansions at: argument].\\n\\tmacroType = $p ifTrue: [^(expansions at: argument) printString].\\n\\tmacroType = $n ifTrue: [^String cr].\\n\\tmacroType = $t ifTrue: [^String tab].\\n\\tself error: 'unknown expansion type'! !\\n\\n\\n!String class methodsFor: 'initialization' stamp: 'ar 4/9/2005 22:37'!\\ninitialize \\\"self initialize\\\"\\n\\n\\t| order |\\n\\tAsciiOrder _ (0 to: 255) as: ByteArray.\\n\\n\\tCaseInsensitiveOrder _ AsciiOrder copy.\\n\\t($a to: $z) do:\\n\\t\\t[:c | CaseInsensitiveOrder at: c asciiValue + 1\\n\\t\\t\\t\\tput: (CaseInsensitiveOrder at: c asUppercase asciiValue +1)].\\n\\n\\t\\\"Case-sensitive compare sorts space, digits, letters, all the rest...\\\"\\n\\tCaseSensitiveOrder _ ByteArray new: 256 withAll: 255.\\n\\torder _ -1.\\n\\t' 0123456789' do: \\\"0..10\\\"\\n\\t\\t[:c | CaseSensitiveOrder at: c asciiValue + 1 put: (order _ order+1)].\\n\\t($a to: $z) do: \\\"11-64\\\"\\n\\t\\t[:c | CaseSensitiveOrder at: c asUppercase asciiValue + 1 put: (order _ order+1).\\n\\t\\tCaseSensitiveOrder at: c asciiValue + 1 put: (order _ order+1)].\\n\\t1 to: CaseSensitiveOrder size do:\\n\\t\\t[:i | (CaseSensitiveOrder at: i) = 255 ifTrue:\\n\\t\\t\\t[CaseSensitiveOrder at: i put: (order _ order+1)]].\\n\\torder = 255 ifFalse: [self error: 'order problem'].\\n\\n\\t\\\"a table for translating to lower case\\\"\\n\\tLowercasingTable _ String withAll: (Character allByteCharacters collect: [:c | c asLowercase]).\\n\\n\\t\\\"a table for translating to upper case\\\"\\n\\tUppercasingTable _ String withAll: (Character allByteCharacters collect: [:c | c asUppercase]).\\n\\n\\t\\\"a table for testing tokenish (for fast numArgs)\\\"\\n\\tTokenish _ String withAll: (Character allByteCharacters collect:\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[:c | c tokenish ifTrue: [c] ifFalse: [$~]]).\\n\\n\\t\\\"CR and LF--characters that terminate a line\\\"\\n\\tCSLineEnders _ CharacterSet empty.\\n\\tCSLineEnders add: Character cr.\\n\\tCSLineEnders add: Character lf.\\n\\n \\t\\\"separators and non-separators\\\"\\n\\tCSSeparators _ CharacterSet separators.\\n\\tCSNonSeparators _ CSSeparators complement.! !\\n\\n!String class methodsFor: 'initialization' stamp: 'yo 8/11/2003 21:11'!\\ninitializeHtmlEntities\\n\\t\\\"self initializeHtmlEntities\\\"\\n\\n\\tHtmlEntities _ (Dictionary new: 128)\\n\\t\\tat: 'amp'\\tput: $&;\\n\\t\\tat: 'lt'\\t\\tput: $<;\\n\\t\\tat: 'gt'\\t\\tput: $>;\\n\\t\\tat: 'quot'\\tput: $\\\";\\n\\t\\tat: 'euro'\\tput: Character euro;\\n\\t\\tyourself.\\n\\t#('nbsp' 'iexcl' 'cent' 'pound' 'curren' 'yen' 'brvbar' 'sect' 'uml' 'copy' 'ordf' 'laquo' 'not' 'shy' 'reg' 'hibar' 'deg' 'plusmn' 'sup2' 'sup3' 'acute' 'micro' 'para' 'middot' 'cedil' 'sup1' 'ordm' 'raquo' 'frac14' 'frac12' 'frac34' 'iquest' 'Agrave' 'Aacute' 'Acirc' 'Atilde' 'Auml' 'Aring' 'AElig' 'Ccedil' 'Egrave' 'Eacute' 'Ecirc' 'Euml' 'Igrave' 'Iacute' 'Icirc' 'Iuml' 'ETH' 'Ntilde' 'Ograve' 'Oacute' 'Ocirc' 'Otilde' 'Ouml' 'times' 'Oslash' 'Ugrave' 'Uacute' 'Ucirc' 'Uuml' 'Yacute' 'THORN' 'szlig' 'agrave' 'aacute' 'acirc' 'atilde' 'auml' 'aring' 'aelig' 'ccedil' 'egrave' 'eacute' 'ecirc' 'euml' 'igrave' 'iacute' 'icirc' 'iuml' 'eth' 'ntilde' 'ograve' 'oacute' 'ocirc' 'otilde' 'ouml' 'divide' 'oslash' 'ugrave' 'uacute' 'ucirc' 'uuml' 'yacute' 'thorn' 'yuml' ) withIndexDo: [:each :index | HtmlEntities at: each put: (index + 159) asCharacter]! !\\n\\n\\n!String class methodsFor: 'instance creation' stamp: 'yo 11/3/2004 19:24'!\\ncr\\n\\t\\\"Answer a string containing a single carriage return character.\\\"\\n\\n\\t^ self with: Character cr\\n! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'yo 11/3/2004 19:24'!\\ncrlf\\n\\t\\\"Answer a string containing a carriage return and a linefeed.\\\"\\n\\n\\t^ self with: Character cr with: Character lf\\n! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'yo 11/3/2004 19:24'!\\ncrlfcrlf\\n\\t^self crlf , self crlf.\\n! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'ar 4/10/2005 16:24'!\\nfromByteArray: aByteArray\\n\\n\\t^ aByteArray asString\\n! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'yo 11/3/2004 19:24'!\\nfromPacked: aLong\\n\\t\\\"Convert from a longinteger to a String of length 4.\\\"\\n\\n\\t| s |\\n\\ts _ self new: 4.\\n\\ts at: 1 put: (aLong digitAt: 4) asCharacter.\\n\\ts at: 2 put: (aLong digitAt: 3) asCharacter.\\n\\ts at: 3 put: (aLong digitAt: 2) asCharacter.\\n\\ts at: 4 put: (aLong digitAt: 1) asCharacter.\\n\\t^s\\n\\n\\\"String fromPacked: 'TEXT' asPacked\\\"\\n! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'yo 11/3/2004 19:24'!\\nfromString: aString \\n\\t\\\"Answer an instance of me that is a copy of the argument, aString.\\\"\\n\\t\\n\\t^ aString copyFrom: 1 to: aString size! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'yo 11/3/2004 19:24'!\\nlf\\n\\t\\\"Answer a string containing a single carriage return character.\\\"\\n\\n\\t^ self with: Character lf! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'ar 4/10/2005 23:26'!\\nnew: sizeRequested \\n\\t\\\"Answer an instance of this class with the number of indexable\\n\\tvariables specified by the argument, sizeRequested.\\\"\\n\\tself == String \\n\\t\\tifTrue:[^ByteString new: sizeRequested]\\n\\t\\tifFalse:[^self basicNew: sizeRequested].! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'yo 8/28/2002 13:27'!\\nreadFrom: inStream\\n\\t\\\"Answer an instance of me that is determined by reading the stream, \\n\\tinStream. Embedded double quotes become the quote Character.\\\"\\n\\n\\t| outStream char done |\\n\\toutStream _ WriteStream on: (self new: 16).\\n\\t\\\"go to first quote\\\"\\n\\tinStream skipTo: $'.\\n\\tdone _ false.\\n\\t[done or: [inStream atEnd]]\\n\\t\\twhileFalse: \\n\\t\\t\\t[char _ inStream next.\\n\\t\\t\\tchar = $'\\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[char _ inStream next.\\n\\t\\t\\t\\t\\tchar = $'\\n\\t\\t\\t\\t\\t\\tifTrue: [outStream nextPut: char]\\n\\t\\t\\t\\t\\t\\tifFalse: [done _ true]]\\n\\t\\t\\t\\tifFalse: [outStream nextPut: char]].\\n\\t^outStream contents! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'yo 11/3/2004 19:24'!\\ntab\\n\\t\\\"Answer a string containing a single tab character.\\\"\\n\\n\\t^ self with: Character tab\\n! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'yo 8/28/2002 13:29'!\\nvalue: anInteger\\n\\n\\t^ self with: (Character value: anInteger).\\n! !\\n\\n!String class methodsFor: 'instance creation' stamp: 'ar 4/12/2005 17:34'!\\nwith: aCharacter\\n\\t| newCollection |\\n\\taCharacter asInteger < 256\\n\\t\\tifTrue:[newCollection _ ByteString new: 1]\\n\\t\\tifFalse:[newCollection _ WideString new: 1].\\n\\tnewCollection at: 1 put: aCharacter.\\n\\t^newCollection! !\\n\\n\\n!String class methodsFor: 'primitives' stamp: 'yo 12/15/2005 13:41'!\\ncompare: string1 with: string2 collated: order\\n\\t\\\"Return 1, 2 or 3, if string1 is <, =, or > string2, with the collating order of characters given by the order array.\\\"\\n\\n\\t| len1 len2 c1 c2 |\\n\\torder == nil ifTrue: [\\n\\t\\tlen1 _ string1 size.\\n\\t\\tlen2 _ string2 size.\\n\\t\\t1 to: (len1 min: len2) do:[:i |\\n\\t\\t\\tc1 _ (string1 at: i) asInteger.\\n\\t\\t\\tc2 _ (string2 at: i) asInteger.\\n\\t\\t\\tc1 = c2 ifFalse: [c1 < c2 ifTrue: [^ 1] ifFalse: [^ 3]].\\n\\t\\t].\\n\\t\\tlen1 = len2 ifTrue: [^ 2].\\n\\t\\tlen1 < len2 ifTrue: [^ 1] ifFalse: [^ 3].\\n\\t].\\n\\tlen1 _ string1 size.\\n\\tlen2 _ string2 size.\\n\\t1 to: (len1 min: len2) do:[:i |\\n\\t\\tc1 _ (string1 at: i) asInteger.\\n\\t\\tc2 _ (string2 at: i) asInteger.\\n\\t\\tc1 < 256 ifTrue: [c1 _ order at: c1 + 1].\\n\\t\\tc2 < 256 ifTrue: [c2 _ order at: c2 + 1].\\n\\t\\tc1 = c2 ifFalse:[c1 < c2 ifTrue: [^ 1] ifFalse: [^ 3]].\\n\\t].\\n\\tlen1 = len2 ifTrue: [^ 2].\\n\\tlen1 < len2 ifTrue: [^ 1] ifFalse: [^ 3].\\n! !\\n\\n!String class methodsFor: 'primitives' stamp: 'ar 4/10/2005 16:36'!\\nfindFirstInString: aString inSet: inclusionMap startingAt: start\\n\\t\\\"Trivial, non-primitive version\\\"\\n\\t| i stringSize ascii more |\\n\\tinclusionMap size ~= 256 ifTrue: [^ 0].\\n\\tstringSize _ aString size.\\n\\tmore _ true.\\n\\ti _ start - 1.\\n\\t[more and: [i + 1 <= stringSize]] whileTrue: [\\n\\t\\ti _ i + 1.\\n\\t\\tascii _ (aString at: i) asciiValue.\\n\\t\\tmore _ ascii < 256 ifTrue: [(inclusionMap at: ascii + 1) = 0] ifFalse: [true].\\n\\t].\\n\\n\\ti + 1 > stringSize ifTrue: [^ 0].\\n\\t^ i! !\\n\\n!String class methodsFor: 'primitives' stamp: 'ar 4/10/2005 16:36'!\\nindexOfAscii: anInteger inString: aString startingAt: start\\n\\t\\\"Trivial, non-primitive version\\\"\\n\\t| stringSize |\\n\\tstringSize _ aString size.\\n\\tstart to: stringSize do: [:pos |\\n\\t\\t(aString at: pos) asInteger = anInteger ifTrue: [^ pos]].\\n\\t^ 0\\n! !\\n\\n!String class methodsFor: 'primitives' stamp: 'ar 4/10/2005 16:29'!\\nstringHash: aString initialHash: speciesHash\\n\\t| stringSize hash low |\\n\\tstringSize _ aString size.\\n\\thash _ speciesHash bitAnd: 16rFFFFFFF.\\n\\t1 to: stringSize do: [:pos |\\n\\t\\thash _ hash + (aString at: pos) asInteger.\\n\\t\\t\\\"Begin hashMultiply\\\"\\n\\t\\tlow _ hash bitAnd: 16383.\\n\\t\\thash _ (16r260D * low + ((16r260D * (hash bitShift: -14) + (16r0065 * low) bitAnd: 16383) * 16384)) bitAnd: 16r0FFFFFFF.\\n\\t].\\n\\t^ hash.\\n! !\\n\\n!String class methodsFor: 'primitives' stamp: 'ar 4/10/2005 16:36'!\\ntranslate: aString from: start to: stop table: table\\n\\t\\\"Trivial, non-primitive version\\\"\\n\\t| char |\\n\\tstart to: stop do: [:i |\\n\\t\\tchar _ (aString at: i) asInteger.\\n\\t\\tchar < 256 ifTrue: [aString at: i put: (table at: char+1)].\\n\\t].\\n! !\\nStringMorph subclass: #StringButtonMorph\\n\\tinstanceVariableNames: 'target actionSelector arguments actWhen oldColor'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'MorphicExtras-Widgets'!\\n\\n!StringButtonMorph methodsFor: 'accessing'!\\nactionSelector\\n\\n\\t^ actionSelector\\n! !\\n\\n!StringButtonMorph methodsFor: 'accessing'!\\nactionSelector: aSymbolOrString\\n\\n\\t(nil = aSymbolOrString or:\\n\\t ['nil' = aSymbolOrString or:\\n\\t [aSymbolOrString isEmpty]])\\n\\t\\tifTrue: [^ actionSelector _ nil].\\n\\n\\tactionSelector _ aSymbolOrString asSymbol.\\n! !\\n\\n!StringButtonMorph methodsFor: 'accessing'!\\narguments\\n\\n\\t^ arguments\\n! !\\n\\n!StringButtonMorph methodsFor: 'accessing'!\\narguments: aCollection\\n\\n\\targuments _ aCollection asArray copy.\\n! !\\n\\n!StringButtonMorph methodsFor: 'accessing'!\\ntarget\\n\\n\\t^ target\\n! !\\n\\n!StringButtonMorph methodsFor: 'accessing'!\\ntarget: anObject\\n\\n\\ttarget _ anObject\\n! !\\n\\n\\n!StringButtonMorph methodsFor: 'button' stamp: 'dgd 2/22/2003 18:45'!\\ndoButtonAction\\n\\t\\\"Perform the action of this button. Subclasses may override this method. The default behavior is to send the button's actionSelector to its target object with its arguments.\\\"\\n\\n\\t(target notNil and: [actionSelector notNil]) \\n\\t\\tifTrue: \\n\\t\\t\\t[Cursor normal \\n\\t\\t\\t\\tshowWhile: [target perform: actionSelector withArguments: arguments]]! !\\n\\n\\n!StringButtonMorph methodsFor: 'copying' stamp: 'jm 7/28/97 11:55'!\\nupdateReferencesUsing: aDictionary\\n\\t\\\"If the arguments array points at a morph we are copying, then point at the new copy. And also copies the array, which is important!!\\\"\\n\\n\\tsuper updateReferencesUsing: aDictionary.\\n\\targuments _ arguments collect:\\n\\t\\t[:old | aDictionary at: old ifAbsent: [old]].\\n! !\\n\\n!StringButtonMorph methodsFor: 'copying' stamp: 'tk 1/8/1999 09:47'!\\nveryDeepFixupWith: deepCopier\\n\\t\\\"If target and arguments fields were weakly copied, fix them here. If they were in the tree being copied, fix them up, otherwise point to the originals!!!!\\\"\\n\\nsuper veryDeepFixupWith: deepCopier.\\ntarget _ deepCopier references at: target ifAbsent: [target].\\narguments _ arguments collect: [:each |\\n\\tdeepCopier references at: each ifAbsent: [each]].\\n! !\\n\\n!StringButtonMorph methodsFor: 'copying' stamp: 'tk 1/8/1999 09:46'!\\nveryDeepInner: deepCopier\\n\\t\\\"Copy all of my instance variables. Some need to be not copied at all, but shared. \\tWarning!!!! Every instance variable defined in this class must be handled. We must also implement veryDeepFixupWith:. See DeepCopier class comment.\\\"\\n\\nsuper veryDeepInner: deepCopier.\\n\\\"target _ target.\\t\\tWeakly copied\\\"\\n\\\"actionSelector _ actionSelector.\\t\\ta Symbol\\\"\\n\\\"arguments _ arguments.\\t\\tAll weakly copied\\\"\\nactWhen _ actWhen veryDeepCopyWith: deepCopier.\\noldColor _ oldColor veryDeepCopyWith: deepCopier.! !\\n\\n\\n!StringButtonMorph methodsFor: 'event handling'!\\nhandlesMouseDown: evt\\n\\n\\t^ true\\n! !\\n\\n!StringButtonMorph methodsFor: 'event handling' stamp: 'ar 10/25/2000 18:14'!\\nhandlesMouseStillDown: evt\\n\\t^actWhen == #whilePressed! !\\n\\n!StringButtonMorph methodsFor: 'event handling'!\\nmouseDown: evt\\n\\n\\toldColor _ color.\\n\\tactWhen == #buttonDown\\n\\t\\tifTrue: [self doButtonAction].\\n! !\\n\\n!StringButtonMorph methodsFor: 'event handling' stamp: 'ar 10/25/2000 18:15'!\\nmouseMove: evt\\n\\tactWhen == #buttonDown ifTrue: [^ self].\\n\\t(self containsPoint: evt cursorPoint)\\n\\t\\tifTrue:[self color: (oldColor alphaMixed: 1/2 with: Color white)]\\n\\t\\tifFalse: [self color: oldColor].\\n! !\\n\\n!StringButtonMorph methodsFor: 'event handling' stamp: 'ar 10/25/2000 18:15'!\\nmouseStillDown: evt\\n\\tactWhen == #whilePressed ifFalse: [^ self].\\n\\t(self containsPoint: evt cursorPoint) ifTrue:[self doButtonAction].! !\\n\\n!StringButtonMorph methodsFor: 'event handling'!\\nmouseUp: evt\\n\\n\\tself color: oldColor.\\n\\t(actWhen == #buttonUp and: [self containsPoint: evt cursorPoint])\\n\\t\\tifTrue: [self doButtonAction].\\n! !\\n\\n\\n!StringButtonMorph methodsFor: 'e-toy support' stamp: 'ar 3/17/2001 20:17'!\\nadaptToWorld: aWorld\\n\\tsuper adaptToWorld: aWorld.\\n\\ttarget _ target adaptedToWorld: aWorld.! !\\n\\n\\n!StringButtonMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 20:44'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\ttarget _ nil.\\n\\tactionSelector _ #flash.\\n\\targuments _ EmptyArray.\\n\\tactWhen _ #buttonUp.\\n\\tself contents: 'Flash' ! !\\n\\n\\n!StringButtonMorph methodsFor: 'menu' stamp: 'wiz 1/16/2006 19:57'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\n\\tsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.\\n\\taCustomMenu add: 'change label' translated action: #setLabel.\\n\\taCustomMenu add: 'change action selector' translated action: #setActionSelector.\\n\\taCustomMenu add: 'change arguments' translated action: #setArguments.\\n\\taCustomMenu add: 'change when to act' translated action: #setActWhen.\\n\\tself addTargetingMenuItems: aCustomMenu hand: aHandMorph .! !\\n\\n!StringButtonMorph methodsFor: 'menu' stamp: 'wiz 1/16/2006 19:56'!\\naddTargetingMenuItems: aCustomMenu hand: aHandMorph \\n\\t\\\"Add targeting menu items\\\"\\n\\taCustomMenu addLine.\\n\\n\\taCustomMenu add: 'set target' translated action: #targetWith:.\\n\\taCustomMenu add: 'sight target' translated action: #sightTargets:.\\n\\ttarget\\n\\t\\tifNotNil: [aCustomMenu add: 'clear target' translated action: #clearTarget]! !\\n\\n!StringButtonMorph methodsFor: 'menu' stamp: 'wiz 1/16/2006 19:55'!\\nclearTarget\\n\\n\\ttarget _ nil.\\n! !\\n\\n!StringButtonMorph methodsFor: 'menu' stamp: 'yo 3/16/2005 21:02'!\\nsetActWhen\\n\\n\\t| selections |\\n\\tselections _ #(buttonDown buttonUp whilePressed).\\n\\tactWhen _ (SelectionMenu labelList: (selections collect: [:t | t translated]) selections: selections)\\n\\t\\tstartUpWithCaption: 'Choose one of the following conditions' translated.\\n! !\\n\\n!StringButtonMorph methodsFor: 'menu' stamp: 'yo 3/16/2005 20:54'!\\nsetActionSelector\\n\\n\\t| newSel |\\n\\tnewSel _ FillInTheBlank\\n\\t\\trequest:\\n'Please type the selector to be sent to\\nthe target when this button is pressed' translated\\n\\t\\tinitialAnswer: actionSelector.\\n\\tnewSel isEmpty ifFalse: [self actionSelector: newSel].\\n! !\\n\\n!StringButtonMorph methodsFor: 'menu' stamp: 'yo 3/14/2005 13:09'!\\nsetArguments\\n\\n\\t| s newArgs newArgsArray |\\n\\ts _ WriteStream on: ''.\\n\\targuments do: [:arg | arg printOn: s. s nextPutAll: '. '].\\n\\tnewArgs _ FillInTheBlank\\n\\t\\trequest:\\n'Please type the arguments to be sent to the target\\nwhen this button is pressed separated by periods' translated\\n\\t\\tinitialAnswer: s contents.\\n\\tnewArgs isEmpty ifFalse: [\\n\\t\\tnewArgsArray _ Compiler evaluate: '{', newArgs, '}' for: self logged: false.\\n\\t\\tself arguments: newArgsArray].\\n! !\\n\\n!StringButtonMorph methodsFor: 'menu'!\\nsetLabel\\n\\n\\t| newLabel |\\n\\tnewLabel _ FillInTheBlank\\n\\t\\trequest:\\n'Please type a new label for this button'\\n\\t\\tinitialAnswer: self contents.\\n\\tnewLabel isEmpty ifFalse: [self contents: newLabel].\\n! !\\n\\n!StringButtonMorph methodsFor: 'menu' stamp: 'dgd 2/22/2003 18:55'!\\nsetTarget: evt \\n\\t| rootMorphs |\\n\\trootMorphs _ self world rootMorphsAt: evt hand targetOffset.\\n\\ttarget _ rootMorphs size > 1\\n\\t\\tifTrue: [rootMorphs second]\\n\\t\\tifFalse: [nil]! !\\n\\n\\n!StringButtonMorph methodsFor: 'submorphs-add/remove'!\\nactWhen: aSymbol\\n\\t\\\"Set the condition under which to invoke my action to one of: #buttonDown, #buttonUp, and #whilePressed.\\\"\\n\\n\\tactWhen _ aSymbol.\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStringButtonMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!StringButtonMorph class methodsFor: 'printing' stamp: 'sw 2/16/98 03:02'!\\ndefaultNameStemForInstances\\n\\t^ 'SButton'! !\\nModel subclass: #StringHolder\\n\\tinstanceVariableNames: 'contents'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Kernel-Remnants'!\\n!StringHolder commentStamp: '<historical>' prior: 0!\\nI am a kind of Model that includes a piece of text. In some cases, the text can be edited, and in some the text is a method.\\n\\nCategories 'code pane menu' and 'message list menu' are messages that may be called by my menus when the text is a method, and when some pane is a list of methods. Other of my subclasses may ignore these two catagories altogether.!\\n\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'di 5/19/1998 15:34'!\\nacceptContents: aString \\n\\t\\\"Set aString to be the contents of the receiver. Return true cuz happy\\\"\\n\\n\\tself contents: aString.\\n\\t^ true! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'nk 4/29/2004 12:32'!\\nclassCommentIndicated\\n\\t\\\"Answer true iff we're viewing the class comment.\\\"\\n\\t^false! !\\n\\n!StringHolder methodsFor: 'accessing'!\\ncontents\\n\\t\\\"Answer the contents that the receiver is holding--presumably a string.\\\"\\n\\n\\t^contents! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'sw 1/12/1999 11:47'!\\ncontents: textOrString \\n\\t\\\"Set textOrString to be the contents of the receiver.\\\"\\n\\n\\tcontents _ textOrString \\\"asString\\\"! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'tk 4/3/98 22:50'!\\ncontentsSelection\\n\\t\\\"Return the interval of text in the code pane to select when I set the pane's contents\\\"\\n\\n\\t^ 1 to: 0 \\\"null selection\\\"! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'sw 12/9/2000 23:59'!\\nnoteAcceptanceOfCodeFor: aSelector\\n\\t\\\"A method has possibly been submitted for the receiver with aSelector as its selector; If the receiver wishes to take soem action here is a chance for it to do so\\\"\\n! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'sw 12/1/2000 11:04'!\\nreformulateList\\n\\t\\\"If the receiver has a way of reformulating its message list, here is a chance for it to do so\\\"! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'sw 12/6/2000 17:48'!\\nreformulateListNoting: newSelector\\n\\t\\\"A method has possibly been submitted for the receiver with newSelector as its selector; If the receiver has a way of reformulating its message list, here is a chance for it to do so\\\"\\n\\n\\t^ self reformulateList! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'tk 4/18/1998 14:59'!\\nselectedClassName\\n\\t\\\"I may know what class is currently selected\\\"\\n\\n\\tself selectedClass ifNotNil: [^ self selectedClass name].\\n\\t^ nil! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'tk 4/18/1998 15:01'!\\nselectedClassOrMetaClass\\n\\n\\t^ self selectedClass\\t\\\"I don't know any better\\\"! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'tk 4/18/1998 15:22'!\\nselectedMessageName\\n\\n\\t^ nil! !\\n\\n!StringHolder methodsFor: 'accessing' stamp: 'di 11/23/1998 15:21'!\\ntextContents: aStringOrText \\n\\t\\\"Set aStringOrText to be the contents of the receiver.\\\"\\n\\n\\tcontents _ aStringOrText! !\\n\\n\\n!StringHolder methodsFor: 'code pane menu' stamp: 'dgd 10/1/2004 13:43'!\\ncodePaneMenu: aMenu shifted: shifted \\n\\t\\\"Note that unless we override perform:orSendTo:, \\n\\tPluggableTextController will respond to all menu items in a \\n\\ttext pane\\\"\\n\\t| donorMenu |\\n\\tdonorMenu := shifted\\n\\t\\t\\t\\tifTrue: [ParagraphEditor shiftedYellowButtonMenu]\\n\\t\\t\\t\\tifFalse: [ParagraphEditor yellowButtonMenu].\\n\\t^ aMenu addAllFrom: donorMenu! !\\n\\n!StringHolder methodsFor: 'code pane menu' stamp: 'wod 5/29/1998 16:35'!\\nperform: selector orSendTo: otherTarget\\n\\t\\\"Selector was just chosen from a menu by a user. If can respond, then\\nperform it on myself. If not, send it to otherTarget, presumably the\\neditPane from which the menu was invoked.\\\"\\n\\n\\t(self respondsTo: selector)\\n\\t\\tifTrue: [^ self perform: selector]\\n\\t\\tifFalse: [^ otherTarget perform: selector]! !\\n\\n!StringHolder methodsFor: 'code pane menu' stamp: 'tk 4/6/98 11:43'!\\nshowBytecodes\\n\\t\\\"We don't know how to do this\\\"\\n\\n\\t^ self changed: #flash! !\\n\\n!StringHolder methodsFor: 'code pane menu' stamp: 'ar 9/27/2005 20:47'!\\nspawn: contentsString\\n\\n\\tUIManager default edit: contentsString label: 'Workspace'\\n! !\\n\\n\\n!StringHolder methodsFor: 'evaluation'!\\ndoItContext\\n\\t\\\"Answer the context in which a text selection can be evaluated.\\\"\\n\\n\\t^nil! !\\n\\n!StringHolder methodsFor: 'evaluation'!\\ndoItReceiver\\n\\t\\\"Answer the object that should be informed of the result of evaluating a \\n\\ttext selection.\\\"\\n\\n\\t^nil! !\\n\\n\\n!StringHolder methodsFor: 'initialize-release'!\\ndefaultContents\\n\\n\\t^''! !\\n\\n!StringHolder methodsFor: 'initialize-release' stamp: 'sw 10/16/1998 11:36'!\\nembeddedInMorphicWindowLabeled: labelString\\n\\t| window |\\n\\twindow _ (SystemWindow labelled: labelString) model: self.\\n\\twindow addMorph: (PluggableTextMorph on: self text: #contents accept: #acceptContents:\\n\\t\\t\\treadSelection: nil menu: #codePaneMenu:shifted:)\\n\\t\\tframe: (0@0 corner: 1@1).\\n\\t^ window! !\\n\\n!StringHolder methodsFor: 'initialize-release' stamp: 'jm 3/24/98 17:56'!\\ninitialize\\n\\t\\\"Initialize the state of the receiver with its default contents.\\\"\\n\\n\\tcontents _ self defaultContents.\\n! !\\n\\n!StringHolder methodsFor: 'initialize-release' stamp: 'sw 10/16/1998 11:37'!\\nopenAsMorphLabel: labelString \\n\\t\\\"Workspace new openAsMorphLabel: 'Workspace'\\\"\\n\\t(self embeddedInMorphicWindowLabeled: labelString) openInWorld! !\\n\\n!StringHolder methodsFor: 'initialize-release' stamp: 'sw 12/22/1998 00:16'!\\nopenLabel: aString \\n\\t\\\"Create a standard system view of the model, me, a StringHolder and open it. If in mvc, terminate the active controller so that the new window will immediately be activated.\\\"\\n\\tself openLabel: aString andTerminate: true! !\\n\\n!StringHolder methodsFor: 'initialize-release' stamp: 'sma 4/30/2000 10:15'!\\nopenLabel: aString andTerminate: terminateBoolean\\n\\t\\\"Create a standard system view of the model, me, a StringHolder and open it.; do not terminate the active process if in mvc\\\"\\n\\t| topView codeView |\\n\\n\\tSmalltalk isMorphic ifTrue: [^ self openAsMorphLabel: aString].\\n\\n\\ttopView _ (StandardSystemView new) model: self.\\n\\ttopView borderWidth: 1.\\n\\ttopView label: aString.\\n\\ttopView minimumSize: 100 @ 50.\\n\\n\\tcodeView _ PluggableTextView on: self \\n\\t\\t\\ttext: #contents accept: #acceptContents:\\n\\t\\t\\treadSelection: #contentsSelection menu: #codePaneMenu:shifted:.\\n\\tcodeView window: (0@0 extent: 200@200).\\n\\ttopView addSubView: codeView.\\n\\t\\\"self contents size > 0 ifTrue: [\\n\\t\\t\\tcodeView hasUnacceptedEdits: true]. Is it already saved or not??\\\"\\n\\tterminateBoolean\\n\\t\\tifTrue:\\n\\t\\t\\t[topView controller open]\\n\\t\\tifFalse:\\n\\t\\t\\t[topView controller openNoTerminate]! !\\n\\n\\n!StringHolder methodsFor: 'optional panes' stamp: 'sw 1/24/2001 21:25'!\\nwantsAnnotationPane\\n\\t\\\"Answer whether the receiver, seen in some browser window, would like to have the so-called annotationpane included. By default, various browsers defer to the global preference 'optionalButtons' -- but individual subclasses can insist to the contrary.\\\"\\n\\n\\t^ Preferences annotationPanes! !\\n\\n!StringHolder methodsFor: 'optional panes' stamp: 'sw 1/24/2001 18:57'!\\nwantsOptionalButtons\\n\\t\\\"Answer whether the receiver, seen in some browser window, would like to have the so-called optional button pane included. By default, various browsers defer to the global preference 'optionalButtons' -- but individual subclasses can insist to the contrary.\\\"\\n\\n\\t^ Preferences optionalButtons! !\\n\\n\\n!StringHolder methodsFor: 'tiles' stamp: 'di 11/4/2000 11:07'!\\nopenSyntaxView\\n\\t\\\"Open a syntax view on the current method\\\"\\n\\n\\t| class selector |\\n\\n\\t(selector _ self selectedMessageName) ifNotNil: [\\n\\t\\tclass _ self selectedClassOrMetaClass.\\n\\t\\tSyntaxMorph testClass: class andMethod: selector.\\n\\t]! !\\n\\n\\n!StringHolder methodsFor: 'toolbuilder' stamp: 'ar 2/11/2005 20:36'!\\nbuildWith: builder\\n\\t| windowSpec textSpec |\\n\\twindowSpec := builder pluggableWindowSpec new.\\n\\twindowSpec model: self.\\n\\twindowSpec label: 'Workspace'.\\n\\twindowSpec children: OrderedCollection new.\\n\\ttextSpec := builder pluggableTextSpec new.\\n\\ttextSpec \\n\\t\\tmodel: self;\\n\\t\\tgetText: #contents; \\n\\t\\tsetText: #acceptContents:; \\n\\t\\tselection: nil; \\n\\t\\tmenu: #codePaneMenu:shifted:;\\n\\t\\tframe: (0@0corner: 1@1).\\n\\twindowSpec children add: textSpec.\\n\\n\\t^builder build: windowSpec! !\\n\\n\\n!StringHolder methodsFor: 'user edits' stamp: 'di 4/21/1998 11:30'!\\nclearUserEditFlag\\n\\t\\\"Clear the hasUnacceptedEdits flag in all my dependent views.\\\"\\n\\n\\tself changed: #clearUserEdits! !\\n\\n!StringHolder methodsFor: 'user edits' stamp: 'tk 4/13/1998 23:07'!\\nokToChange\\n\\n\\tself canDiscardEdits ifTrue: [^ true].\\n\\tself changed: #wantToChange. \\\"Solicit cancel from view\\\"\\n\\t^ self canDiscardEdits\\n! !\\n\\n\\n!StringHolder methodsFor: '*services-base' stamp: 'rr 3/15/2004 09:17'!\\ncodeTextMorph\\n\\t^ self dependents\\n\\t\\tdetect: [:dep | (dep isKindOf: PluggableTextMorph)\\n\\t\\t\\t\\tand: [dep getTextSelector == #contents]]\\n\\t\\tifNone: []! !\\n\\n!StringHolder methodsFor: '*services-base' stamp: 'rr 6/9/2005 10:47'!\\nrequestor\\n\\t^ (TextRequestor new) model: self; yourself! !\\n\\n!StringHolder methodsFor: '*services-base' stamp: 'rr 3/15/2004 09:17'!\\nselectedInterval\\n\\t^self codeTextMorph selectionInterval! !\\n\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nbrowseAllMessages\\n\\t\\\"Create and schedule a message set browser on all implementors of all the messages sent by the current method.\\\"\\n\\n\\t| aClass aName method filteredList |\\n\\t(aName := self selectedMessageName) ifNotNil: [\\n\\t\\tmethod := (aClass := self selectedClassOrMetaClass) compiledMethodAt: aName.\\n\\t\\tfilteredList := method messages reject: \\n\\t\\t\\t[:each | #(new initialize = ) includes: each].\\n\\t\\tself systemNavigation browseAllImplementorsOfList: filteredList asSortedCollection\\n\\t\\t\\t title: 'All messages sent in ', aClass name, '.', aName]\\n! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'tk 4/18/1998 16:11'!\\nbrowseClass\\n\\t\\\"Open an class browser on this class and method\\\"\\n\\n\\tself selectedClassOrMetaClass ifNotNil: [\\n\\t\\tBrowser newOnClass: self selectedClassOrMetaClass \\n\\t\\t\\tselector: self selectedMessageName]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 4/16/2003 08:42'!\\nbrowseLocalImplementors\\n\\t\\\"Present a menu of all messages sent by the currently selected message. \\n\\tOpen a message set browser of all implementors of the message chosen in or below\\n\\tthe selected class.\\n\\tDo nothing if no message is chosen.\\\"\\n\\tself getSelectorAndSendQuery: #browseAllImplementorsOf:localTo:\\n\\t\\tto: self systemNavigation\\n\\t\\twith: { self selectedClass }! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 4/16/2003 20:41'!\\nbrowseLocalSendersOfMessages\\n\\t\\\"Present a menu of the currently selected message, as well as all\\n\\tmessages sent by it. Open a message set browser of all implementors\\n\\tof the message chosen in or below the selected class\\\"\\n\\n\\tself getSelectorAndSendQuery: #browseAllCallsOn:localTo:\\n\\t\\tto: self systemNavigation\\n\\t\\twith: { self selectedClass }! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 4/16/2003 08:45'!\\nbrowseMessages\\n\\t\\\"Present a menu of all messages sent by the currently selected message. \\n\\tOpen a message set browser of all implementors of the message chosen.\\\"\\n\\n\\tself getSelectorAndSendQuery: #browseAllImplementorsOf: to: self systemNavigation! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nbrowseMethodFull\\n\\t\\\"Create and schedule a full Browser and then select the current class and message.\\\"\\n\\n\\t| myClass |\\n\\t(myClass := self selectedClassOrMetaClass) ifNotNil:\\n\\t\\t[Browser fullOnClass: myClass selector: self selectedMessageName]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 4/16/2003 20:40'!\\nbrowseSendersOfMessages\\n\\t\\\"Present a menu of the currently selected message, as well as all messages sent by it. Open a message set browser of all senders of the selector chosen.\\\"\\n\\n\\tself getSelectorAndSendQuery: #browseAllCallsOn: to: self systemNavigation! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nbrowseUnusedMethods\\n\\t| classes unsent messageList cls |\\n\\t(cls := self selectedClass)\\n\\t\\tifNil: [^ self].\\n\\tclasses := Array with: cls with: cls class.\\n\\tunsent := Set new.\\n\\tclasses\\n\\t\\tdo: [:c | unsent addAll: c selectors].\\n\\tunsent := self systemNavigation allUnSentMessagesIn: unsent.\\n\\tmessageList := OrderedCollection new.\\n\\tclasses\\n\\t\\tdo: [:c | (c selectors\\n\\t\\t\\t\\tselect: [:s | unsent includes: s]) asSortedCollection\\n\\t\\t\\t\\tdo: [:sel | messageList add: c name , ' ' , sel]].\\n\\tself systemNavigation browseMessageList: messageList name: 'Unsent Methods in ' , cls name! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nbrowseVersions\\n\\t\\\"Create and schedule a Versions Browser, showing all versions of the \\n\\tcurrently selected message. Answer the browser or nil.\\\"\\n\\t| selector class | \\n\\tself classCommentIndicated\\n\\t\\tifTrue: [ ClassCommentVersionsBrowser browseCommentOf: self selectedClass.\\n\\t\\t\\t^nil ].\\n\\n\\t(selector := self selectedMessageName)\\n\\t\\tifNil:[ self inform: 'Sorry, only actual methods have retrievable versions.'. ^nil ]\\n\\t\\tifNotNil: [\\n\\t\\t\\tclass := self selectedClassOrMetaClass.\\n\\t\\t\\t^VersionsBrowser\\n\\t\\t\\t\\tbrowseVersionsOf: (class compiledMethodAt: selector)\\n\\t\\t\\t\\tclass: self selectedClass\\n\\t\\t\\t\\tmeta: class isMeta\\n\\t\\t\\t\\tcategory: (class organization categoryOfElement: selector)\\n\\t\\t\\t\\tselector: selector]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'tk 4/28/1998 19:14'!\\nbuildMessageBrowser\\n\\t\\\"Create and schedule a message browser.\\\"\\n\\n\\tself selectedMessageName ifNil: [^ self].\\n\\tBrowser openMessageBrowserForClass: self selectedClassOrMetaClass \\n\\t\\tselector: self selectedMessageName editString: nil! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 1/16/2004 21:14'!\\nclassHierarchy\\n\\t\\\"Create and schedule a class list browser on the receiver's hierarchy.\\\"\\n\\n\\tself systemNavigation\\n\\t\\tspawnHierarchyForClass: self selectedClassOrMetaClass \\\"OK if nil\\\"\\n\\t\\tselector: self selectedMessageName\\n! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sw 5/8/2000 02:16'!\\nclassListKey: aChar from: view \\n\\t\\\"Respond to a Command key. I am a model with a list of classes and a \\n\\tcode pane, and I also have a listView that has a list of methods. The \\n\\tview knows how to get the list and selection.\\\"\\n\\n\\taChar == $f ifTrue: [^ self findMethod].\\n\\taChar == $r ifTrue: [^ self recent].\\n\\taChar == $h ifTrue: [^ self spawnHierarchy].\\n\\taChar == $x ifTrue: [^ self removeClass].\\n\\t^ self messageListKey: aChar from: view! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\ncopyName\\n\\t\\\"Copy the current selector to the clipboard\\\"\\n\\t| selector |\\n\\t(selector := self selectedMessageName) ifNotNil:\\n\\t\\t[Clipboard clipboardText: selector asString asText]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\ncopySelector\\n\\t\\\"Copy the selected selector to the clipboard\\\"\\n\\n\\t| selector |\\n\\t(selector := self selectedMessageName) ifNotNil:\\n\\t\\t[Clipboard clipboardText: selector asString]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sw 7/1/2001 08:24'!\\nfileOutMessage\\n\\t\\\"Put a description of the selected message on a file\\\"\\n\\n\\tself selectedMessageName ifNotNil:\\n\\t\\t[Cursor write showWhile:\\n\\t\\t\\t[self selectedClassOrMetaClass fileOutMethod: self selectedMessageName]]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nfindMethodInChangeSets\\n\\t\\\"Find and open a changeSet containing the current method.\\\"\\n\\n\\t| aName |\\n\\t(aName := self selectedMessageName) ifNotNil: [\\n\\t\\tChangeSorter browseChangeSetsWithClass: self selectedClassOrMetaClass\\n\\t\\t\\t\\t\\tselector: aName]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\ninspectInstances\\n\\t\\\"Inspect all instances of the selected class.\\\"\\n\\n\\t| myClass |\\n\\t(myClass := self selectedClassOrMetaClass) ifNotNil:\\n\\t\\t[myClass theNonMetaClass inspectAllInstances]. \\n! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\ninspectSubInstances\\n\\t\\\"Inspect all instances of the selected class and all its subclasses\\\"\\n\\n\\t| aClass |\\n\\t(aClass := self selectedClassOrMetaClass) ifNotNil: [\\n\\t\\taClass theNonMetaClass inspectSubInstances].\\n! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nmakeIsolatedCodePane\\n\\t| msgName |\\n\\n\\t(msgName := self selectedMessageName) ifNil: [^ Beeper beep].\\n\\tMethodHolder makeIsolatedCodePaneForClass: self selectedClassOrMetaClass selector: msgName! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nmessageListKey: aChar from: view\\n\\t\\\"Respond to a Command key. I am a model with a code pane, and I also\\n\\thave a listView that has a list of methods. The view knows how to get\\n\\tthe list and selection.\\\"\\n\\n\\t| sel class |\\n\\taChar == $D ifTrue: [^ self toggleDiffing].\\n\\n\\tsel := self selectedMessageName.\\n\\taChar == $m ifTrue: \\\"These next two put up a type in if no message selected\\\"\\n\\t\\t[^ self useSelector: sel orGetSelectorAndSendQuery: #browseAllImplementorsOf: to: self systemNavigation].\\n\\taChar == $n ifTrue: \\n\\t\\t[^ self useSelector: sel orGetSelectorAndSendQuery: #browseAllCallsOn: to: self systemNavigation].\\n\\n\\t\\\"The following require a class selection\\\"\\n\\t(class := self selectedClassOrMetaClass) ifNil: [^ self arrowKey: aChar from: view].\\n\\taChar == $b ifTrue: [^ Browser fullOnClass: class selector: sel].\\n\\taChar == $N ifTrue: [^ self browseClassRefs].\\n\\taChar == $i ifTrue: [^ self methodHierarchy].\\n\\taChar == $h ifTrue: [^ self classHierarchy].\\n\\taChar == $p ifTrue: [^ self browseFullProtocol].\\n\\n\\t\\\"The following require a method selection\\\"\\n\\tsel ifNotNil: \\n\\t\\t[aChar == $o ifTrue: [^ self fileOutMessage].\\n\\t\\taChar == $c ifTrue: [^ self copySelector].\\n\\t\\taChar == $v ifTrue: [^ self browseVersions].\\n\\t\\taChar == $O ifTrue: [^ self openSingleMessageBrowser].\\n\\t\\taChar == $x ifTrue: [^ self removeMessage]].\\n\\n\\t^ self arrowKey: aChar from: view! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nmessageListSelectorTitle\\n\\t| selector aString aStamp aSize |\\n\\n\\t(selector := self selectedMessageName)\\n\\t\\tifNil:\\n\\t\\t\\t[aSize := self messageList size.\\n\\t\\t\\t^ (aSize == 0 ifTrue: ['no'] ifFalse: [aSize printString]), ' message', (aSize == 1 ifTrue: [''] ifFalse: ['s'])]\\n\\t\\tifNotNil:\\n\\t\\t\\t[Preferences timeStampsInMenuTitles\\n\\t\\t\\t\\tifFalse:\\t[^ nil].\\n\\t\\t\\taString := selector truncateWithElipsisTo: 28.\\n\\t\\t\\t^ (aStamp := self timeStamp) size > 0\\n\\t\\t\\t\\tifTrue:\\n\\t\\t\\t\\t\\t[aString, String cr, aStamp]\\n\\t\\t\\t\\tifFalse:\\n\\t\\t\\t\\t\\t[aString]]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 1/16/2004 21:10'!\\nmethodHierarchy\\n\\t\\\"Create and schedule a method browser on the hierarchy of implementors.\\\"\\n\\n\\tself systemNavigation \\n\\t\\t\\tmethodHierarchyBrowserForClass: self selectedClassOrMetaClass \\n\\t\\t\\tselector: self selectedMessageName\\n! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nofferDurableMenuFrom: menuRetriever shifted: aBoolean\\n\\t\\\"Pop up (morphic only) a menu whose target is the receiver and whose contents are provided by sending the menuRetriever to the receiver. The menuRetriever takes two arguments: a menu, and a boolean representing the shift state; put a stay-up item at the top of the menu.\\\"\\n\\n\\t| aMenu |\\n\\taMenu := MenuMorph new defaultTarget: self.\\n\\taMenu addStayUpItem.\\n\\tself perform: menuRetriever with: aMenu with: aBoolean.\\n\\t\\taMenu popUpInWorld! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nofferMenuFrom: menuRetriever shifted: aBoolean\\n\\t\\\"Pop up, in morphic or mvc as the case may be, a menu whose target is the receiver and whose contents are provided by sending the menuRetriever to the receiver. The menuRetriever takes two arguments: a menu, and a boolean representing the shift state.\\\"\\n\\n\\t| aMenu |\\n\\tSmalltalk isMorphic\\n\\t\\tifTrue:\\n\\t\\t\\t[aMenu := MenuMorph new defaultTarget: self.\\n\\t\\t\\tself perform: menuRetriever with: aMenu with: aBoolean.\\n\\t\\t\\taMenu popUpInWorld]\\n\\t\\tifFalse:\\n\\t\\t\\t[aMenu := CustomMenu new.\\n\\t\\t\\tself perform: menuRetriever with: aMenu with: aBoolean.\\n\\t\\t\\taMenu invokeOn: self]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nopenSingleMessageBrowser\\n\\t| msgName mr |\\n\\t\\\"Create and schedule a message list browser populated only by the currently selected message\\\"\\n\\n\\t(msgName := self selectedMessageName) ifNil: [^ self].\\n\\n\\tmr := MethodReference new\\n\\t\\tsetStandardClass: self selectedClassOrMetaClass\\n\\t\\tmethodSymbol: msgName.\\n\\n\\tself systemNavigation \\n\\t\\tbrowseMessageList: (Array with: mr)\\n\\t\\tname: mr asStringOrText\\n\\t\\tautoSelect: nil! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'RAA 12/10/1999 09:36'!\\npackageListKey: aChar from: view\\n\\t\\\"Respond to a Command key in the package pane in the PackageBrowser\\\"\\n\\taChar == $f ifTrue: [^ self findClass].\\n\\t^ self classListKey: aChar from: view\\n! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'tk 4/28/1998 18:16'!\\nprintOutMessage\\n\\t\\\"Write a file with the text of the selected message, for printing by a web browser\\\"\\n\\n\\tself selectedMessageName ifNotNil: [\\n\\t\\tself selectedClassOrMetaClass fileOutMethod: self selectedMessageName\\n\\t\\t\\t\\t\\t\\t\\tasHtml: true]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 5/23/2003 14:42'!\\nremoveFromCurrentChanges\\n\\t\\\"Tell the changes mgr to forget that the current msg was changed.\\\"\\n\\n\\tChangeSet current removeSelectorChanges: self selectedMessageName \\n\\t\\t\\tclass: self selectedClassOrMetaClass.\\n\\tself changed: #annotation! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sw 1/28/1999 12:34'!\\nrevertAndForget\\n\\t\\\"Revert to the previous version of the current method, and tell the changes mgr to forget that it was ever changed. Danger!! Use only if you really know what you're doing!!\\\"\\n\\n\\tself okToChange ifFalse: [^ self].\\n\\tself revertToPreviousVersion.\\n\\tself removeFromCurrentChanges.\\n\\tself contentsChanged\\n! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nrevertToPreviousVersion\\n\\t\\\"Revert to the previous version of the current method\\\"\\n\\t| aClass aSelector changeRecords |\\n\\tself okToChange ifFalse: [^ self].\\n\\taClass := self selectedClassOrMetaClass.\\n\\taClass ifNil: [^ self changed: #flash].\\n\\taSelector := self selectedMessageName.\\n\\tchangeRecords := aClass changeRecordsAt: aSelector.\\n\\t(changeRecords == nil or: [changeRecords size <= 1]) ifTrue: [self changed: #flash. ^ Beeper beep].\\n\\tchangeRecords second fileIn.\\n\\tself contentsChanged\\n! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nselectMessageAndEvaluate: aBlock\\n\\t\\\"Allow the user to choose one selector, chosen from the currently selected message's selector, as well as those of all messages sent by it, and evaluate aBlock on behalf of chosen selector. If there is only one possible choice, simply make it; if there are multiple choices, put up a menu, and evaluate aBlock on behalf of the the chosen selector, doing nothing if the user declines to choose any\\\"\\n\\n\\t| selector method messages |\\n\\t(selector := self selectedMessageName) ifNil: [^ self].\\n\\tmethod := (self selectedClassOrMetaClass ifNil: [^ self])\\n\\t\\tcompiledMethodAt: selector\\n\\t\\tifAbsent: [].\\n\\t(method isNil or: [(messages := method messages) size == 0])\\n\\t\\t ifTrue: [^ aBlock value: selector].\\n\\t(messages size == 1 and: [messages includes: selector])\\n\\t\\tifTrue:\\n\\t\\t\\t[^ aBlock value: selector]. \\\"If only one item, there is no choice\\\"\\n\\n\\tself systemNavigation \\n\\t\\tshowMenuOf: messages\\n\\t\\twithFirstItem: selector\\n\\t\\tifChosenDo: [:sel | aBlock value: sel]! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'nk 11/15/2002 12:23'!\\nsystemCatListKey: aChar from: view\\n\\t\\\"Respond to a Command key. I am a model with a code pane, and I also have a listView that has a list of methods. The view knows how to get the list and selection.\\\"\\n\\n\\taChar == $f ifTrue: [^ self findClass].\\n\\taChar == $x ifTrue: [^ self removeSystemCategory].\\n\\t^ self classListKey: aChar from: view! !\\n\\n!StringHolder methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\ntimeStamp\\n\\t\\\"Answer the time stamp for the chosen class and method, if any, else an empty string\\\"\\n\\n\\t| selector aMethod |\\n\\t(selector := self selectedMessageName) ifNotNil:\\n\\t\\t[self selectedClassOrMetaClass \\n\\t\\t\\tifNil:\\n\\t\\t\\t\\t[^ String new]\\n\\t\\t\\tifNotNil:\\n\\t\\t\\t\\t[aMethod := self selectedClassOrMetaClass compiledMethodAt: selector ifAbsent: [nil].\\n\\t\\t\\t\\taMethod ifNotNil: [^ Utilities timeStampForMethod: aMethod]]].\\n\\t^ String new! !\\n\\n\\n!StringHolder methodsFor: '*Tools-traits' stamp: 'al 12/6/2005 22:22'!\\nbrowseClassRefs\\n\\n\\t| cls |\\n\\tcls := self selectedClass.\\n\\t(cls notNil and: [cls isTrait not])\\n\\t\\tifTrue: [self systemNavigation browseAllCallsOnClass: cls theNonMetaClass]\\n! !\\n\\n!StringHolder methodsFor: '*Tools-traits' stamp: 'al 12/6/2005 22:22'!\\nbrowseClassVariables\\n\\t\\\"Browse the class variables of the selected class. 2/5/96 sw\\\"\\n\\t| cls |\\n\\tcls := self selectedClass.\\n\\t(cls notNil and: [cls isTrait not])\\n\\t\\tifTrue: [self systemNavigation browseClassVariables: cls]\\n! !\\n\\n!StringHolder methodsFor: '*Tools-traits' stamp: 'al 12/6/2005 22:23'!\\nbrowseClassVarRefs\\n\\t\\\"1/17/96 sw: devolve responsibility to the class, so that the code that does the real work can be shared\\\"\\n\\n\\t| cls |\\n\\tcls := self selectedClass.\\n\\t(cls notNil and: [cls isTrait not])\\n\\t\\tifTrue: [self systemNavigation browseClassVarRefs: cls]! !\\n\\n!StringHolder methodsFor: '*Tools-traits' stamp: 'al 12/6/2005 22:23'!\\nbrowseFullProtocol\\n\\t\\\"Open up a protocol-category browser on the value of the receiver's current selection. If in mvc, an old-style protocol browser is opened instead. Someone who still uses mvc might wish to make the protocol-category-browser work there too, thanks.\\\"\\n\\n\\t| aClass |\\n\\n\\t(Smalltalk isMorphic and: [Smalltalk includesKey: #Lexicon]) ifFalse: [^ self spawnFullProtocol].\\n\\t((aClass := self selectedClassOrMetaClass) notNil and: [aClass isTrait not]) ifTrue:\\n\\t\\t[(Smalltalk at: #Lexicon) new openOnClass: aClass inWorld: ActiveWorld showingSelector: self selectedMessageName]! !\\n\\n!StringHolder methodsFor: '*Tools-traits' stamp: 'al 12/6/2005 22:24'!\\nbrowseInstVarDefs \\n\\n\\t| cls |\\n\\tcls := self selectedClassOrMetaClass.\\n\\t(cls notNil and: [cls isTrait not])\\n\\t\\tifTrue: [self systemNavigation browseInstVarDefs: cls]! !\\n\\n!StringHolder methodsFor: '*Tools-traits' stamp: 'al 12/6/2005 22:24'!\\nbrowseInstVarRefs\\n\\t\\\"1/26/96 sw: real work moved to class, so it can be shared\\\"\\n\\t| cls |\\n\\tcls := self selectedClassOrMetaClass.\\n\\t(cls notNil and: [cls isTrait not])\\n\\t\\tifTrue: [self systemNavigation browseInstVarRefs: cls]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStringHolder class\\n\\tinstanceVariableNames: ''!\\n\\n!StringHolder class methodsFor: 'class initialization'!\\ninitialize\\n\\t\\\"The class variables were initialized once, and subsequently filled with\\n\\tinformation. Re-executing this method is therefore dangerous.\\\" \\n\\t \\n\\t\\\"workSpace _ StringHolder new\\\"\\n\\n\\t\\\"StringHolder initialize\\\"! !\\n\\n\\n!StringHolder class methodsFor: 'instance creation' stamp: 'ar 9/27/2005 20:48'!\\nopen\\n\\t(Smalltalk at: #Workspace ifAbsent:[self]) new openLabel: 'Workspace'\\n\\t\\t\\\"Not to be confused with our own class var 'Workspace'\\\"! !\\n\\n!StringHolder class methodsFor: 'instance creation' stamp: 'tk 5/4/1998 16:41'!\\nopenLabel: aString\\n\\n\\tself new openLabel: aString! !\\n\\n\\n!StringHolder class methodsFor: 'window color' stamp: 'sw 2/26/2002 14:44'!\\nwindowColorSpecification\\n\\t\\\"Answer a WindowColorSpec object that declares my preference\\\"\\n\\n\\t^ WindowColorSpec classSymbol: self name wording: 'Workspace' brightColor: #lightYellow pastelColor: #paleYellow helpMessage: 'A place for text in a window.'! !\\nParagraphEditor subclass: #StringHolderController\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'CodeYellowButtonMenu CodeYellowButtonMessages'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Support'!\\n!StringHolderController commentStamp: '<historical>' prior: 0!\\nI represent a ParagraphEditor for a single paragraph of text, omitting alignment commands. I provide items in the yellow button menu so that the text selection can be evaluated and so that the contents of the model can be stored or restored.\\n\\tdoIt\\tevaluate the text selection as an expression\\n\\tprintIt\\tsame as doIt but insert a description of the result after the selection\\n\\taccept\\tstore the contents of the StringHolder into the model\\n\\tcancel\\tstore the contents of the model into the StringHolder!\\n\\n\\n!StringHolderController methodsFor: 'accessing' stamp: 'di 6/21/2001 10:32'!\\nchangeText: aText\\n\\t\\\"The paragraph to be edited is changed to aText.\\\"\\n\\tparagraph text: aText.\\n\\tself resetState.\\n\\tself selectInvisiblyFrom: paragraph text size + 1 to: paragraph text size.\\n\\tself selectAndScroll.\\n\\tself deselect! !\\n\\n!StringHolderController methodsFor: 'accessing'!\\nmodel: aModel\\n\\n\\tsuper model: aModel.\\n\\tview displayContents == nil\\n\\t\\tifFalse: [self changeParagraph: view displayContents]! !\\n\\n\\n!StringHolderController methodsFor: 'compiler access'!\\nbindingOf: aString\\n\\t^model bindingOf: aString! !\\n\\n\\n!StringHolderController methodsFor: 'edit flag' stamp: 'di 10/9/1998 15:41'!\\nhasUnacceptedEdits: aBoolean\\n\\t^ view hasUnacceptedEdits: aBoolean! !\\n\\n!StringHolderController methodsFor: 'edit flag' stamp: 'tk 4/13/1998 23:09'!\\nuserHasEdited\\n\\t\\\"Note that the user has edited my text.\\\"\\n\\n\\tview hasUnacceptedEdits: true\\n! !\\n\\n!StringHolderController methodsFor: 'edit flag' stamp: 'tk 4/13/1998 23:08'!\\nuserHasNotEdited\\n\\t\\\"Note that my text is free of user edits.\\\"\\n\\n\\tmodel clearUserEditFlag\\n! !\\n\\n\\n!StringHolderController methodsFor: 'menu messages' stamp: 'jm 3/18/98 20:53'!\\naccept \\n\\t\\\"Refer to the comment in ParagraphEditor|accept.\\\"\\n\\n\\tsuper accept.\\n\\tmodel contents: paragraph string.\\n\\tself userHasNotEdited.\\n! !\\n\\n!StringHolderController methodsFor: 'menu messages' stamp: 'jm 3/18/98 20:54'!\\ncancel \\n\\t\\\"Refer to the comment in ParagraphEditor|cancel.\\\"\\n\\n\\tsuper cancel.\\n\\tself userHasNotEdited.\\n! !\\n\\n!StringHolderController methodsFor: 'menu messages' stamp: 'tk 4/13/1998 23:14'!\\nperformMenuMessage: aSelector\\n\\t\\\"Intercept #again so the model does not get locked by keying the search text.\\\"\\n\\n\\t| hadEdits |\\n\\thadEdits _ view canDiscardEdits not.\\n\\tsuper performMenuMessage: aSelector.\\n\\t(hadEdits not and:\\n\\t [aSelector == #again and:\\n\\t [(UndoMessage sends: #undoAgain:andReselect:typedKey:) and:\\n\\t [UndoMessage arguments at: 3]]])\\n\\t\\tifTrue: [self userHasNotEdited].\\n! !\\n\\n\\n!StringHolderController methodsFor: 'private' stamp: 'jm 3/18/98 20:43'!\\ncloseTypeIn\\n\\t\\\"Note edit if something actually was typed.\\\"\\n\\n\\tbeginTypeInBlock ~~ nil ifTrue: [self userHasEdited].\\n\\tsuper closeTypeIn.\\n! !\\n\\n!StringHolderController methodsFor: 'private' stamp: 'jm 3/18/98 20:45'!\\nzapSelectionWith: aText\\n\\t\\\"Note edit except during typeIn, which notes edits at close.\\\"\\n\\n\\tsuper zapSelectionWith: aText.\\n\\tbeginTypeInBlock == nil ifTrue: [self userHasEdited].\\n! !\\nView subclass: #StringHolderView\\n\\tinstanceVariableNames: 'displayContents hasUnacceptedEdits askBeforeDiscardingEdits'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Support'!\\n!StringHolderView commentStamp: '<historical>' prior: 0!\\nI am a View of a String that is an aspect of a more structured object. This String should not be changed by any editing unless the user issues the accept command. Thus my instances provide a working copy of the String. This copy is edited. When the user issues the accept command, the String is copied from the working version; or if the user issues the cancel command, the working version is restored from the String. StringHolderController is my default controller. It is initialized specially by passing the string viewed which is then converted to a Paragraph for editing.!\\n\\n\\n!StringHolderView methodsFor: 'controller access'!\\ndefaultController \\n\\t\\\"Refer to the comment in View|defaultController.\\\"\\n\\n\\t^self defaultControllerClass newParagraph: displayContents! !\\n\\n!StringHolderView methodsFor: 'controller access'!\\ndefaultControllerClass \\n\\t\\\"Refer to the comment in View|defaultControllerClass.\\\"\\n\\n\\t^StringHolderController! !\\n\\n!StringHolderView methodsFor: 'controller access'!\\ndisplayContents\\n\\n\\t^displayContents! !\\n\\n\\n!StringHolderView methodsFor: 'deEmphasizing'!\\ndeEmphasizeView \\n\\t\\\"Refer to the comment in View|deEmphasizeView.\\\"\\n\\n\\t(self controller isKindOf: ParagraphEditor)\\n\\t \\tifTrue: [controller deselect]! !\\n\\n\\n!StringHolderView methodsFor: 'displaying'!\\ndisplay \\n\\t\\\"Refer to the comment in View.display.\\\"\\n\\t(self isUnlocked and: [self insetDisplayBox ~= displayContents clippingRectangle])\\n\\t\\tifTrue: \\\"Recompose the text if the window changed\\\"\\n\\t\\t\\t\\t[self positionDisplayContents. \\n\\t\\t\\t\\t(self controller isKindOf: ParagraphEditor)\\n\\t\\t\\t\\t\\tifTrue: [controller recomputeSelection]].\\n\\tsuper display! !\\n\\n!StringHolderView methodsFor: 'displaying' stamp: 'hmm 6/18/2000 19:24'!\\ndisplayView \\n\\t\\\"Refer to the comment in View|displayView.\\\"\\n\\n\\tDisplay deferUpdatesIn: self displayBox while: [\\n\\t\\tself clearInside.\\n\\t\\t(self controller isKindOf: ParagraphEditor)\\n\\t\\t\\tifTrue: [controller display]\\n\\t\\t\\tifFalse: [displayContents display]]! !\\n\\n!StringHolderView methodsFor: 'displaying'!\\nlock\\n\\t\\\"Refer to the comment in view|lock. Must do at least what display would do to lock the view.\\\"\\n\\t(self isUnlocked and: [self insetDisplayBox ~= displayContents clippingRectangle])\\n\\t\\tifTrue: \\\"Recompose the text if the window changed\\\"\\n\\t\\t\\t\\t[self positionDisplayContents. \\n\\t\\t\\t\\t(self controller isKindOf: ParagraphEditor)\\n\\t\\t\\t\\t\\tifTrue: [controller recomputeSelection]].\\n\\tsuper lock! !\\n\\n!StringHolderView methodsFor: 'displaying'!\\npositionDisplayContents\\n\\t\\\"Presumably the text being displayed changed so that the wrapping box \\n\\tand clipping box should be reset.\\\"\\n\\n\\tdisplayContents \\n\\t\\twrappingBox: (self insetDisplayBox insetBy: 6 @ 0)\\n\\t\\tclippingBox: self insetDisplayBox! !\\n\\n\\n!StringHolderView methodsFor: 'initialize-release' stamp: 'jm 3/24/98 14:39'!\\ninitialize \\n\\t\\\"Refer to the comment in View|initialize.\\\"\\n\\n\\tsuper initialize.\\n\\tdisplayContents _ '' asParagraph.\\n\\thasUnacceptedEdits _ false.\\n\\taskBeforeDiscardingEdits _ true.\\n! !\\n\\n\\n!StringHolderView methodsFor: 'model access'!\\neditString: aString \\n\\t\\\"The paragraph to be displayed is created from the characters in aString.\\\"\\n\\n\\tdisplayContents _ Paragraph withText: aString asText\\n\\t\\tstyle: TextStyle default copy\\n\\t\\tcompositionRectangle: (self insetDisplayBox insetBy: 6 @ 0)\\n\\t\\tclippingRectangle: self insetDisplayBox\\n\\t\\tforeColor: self foregroundColor backColor: self backgroundColor.\\n\\t(self controller isKindOf: ParagraphEditor)\\n\\t\\tifTrue: [controller changeParagraph: displayContents]! !\\n\\n!StringHolderView methodsFor: 'model access' stamp: 'sma 5/28/2000 23:25'!\\ngetMenu: shiftKeyState\\n\\t^ nil! !\\n\\n!StringHolderView methodsFor: 'model access'!\\nmodel: aLockedModel \\n\\t\\\"Refer to the comment in View|model:.\\\"\\n \\n\\tsuper model: aLockedModel.\\n\\tself editString: model contents! !\\n\\n\\n!StringHolderView methodsFor: 'updating' stamp: 'jm 3/24/98 14:38'!\\naskBeforeDiscardingEdits: aBoolean\\n\\t\\\"Set the flag that determines whether the user should be asked before discarding unaccepted edits.\\\"\\n\\n\\taskBeforeDiscardingEdits _ aBoolean.\\n! !\\n\\n!StringHolderView methodsFor: 'updating' stamp: 'tk 4/13/1998 22:58'!\\ncanDiscardEdits\\n\\t\\\"Return true if this view either has no text changes or does not care.\\\"\\n\\n\\t^ (hasUnacceptedEdits & askBeforeDiscardingEdits) not\\n! !\\n\\n!StringHolderView methodsFor: 'updating' stamp: 'jm 3/24/98 17:49'!\\nhasUnacceptedEdits\\n\\t\\\"Return true if this view has unaccepted edits.\\\"\\n\\n\\t^ hasUnacceptedEdits\\n! !\\n\\n!StringHolderView methodsFor: 'updating' stamp: 'tk 4/13/1998 17:17'!\\nhasUnacceptedEdits: aBoolean\\n\\t\\\"Set the hasUnacceptedEdits flag to the given value.\\\"\\n\\n\\thasUnacceptedEdits _ aBoolean.\\n! !\\n\\n!StringHolderView methodsFor: 'updating' stamp: 'dgd 9/21/2003 17:42'!\\npromptForCancel\\n\\t\\\"Ask if it is OK to cancel changes to text\\\"\\n\\t| okToCancel stripes |\\n\\tself topView isCollapsed ifTrue:\\n\\t\\t[(self confirm: 'Changes have not been saved.\\nIs it OK to cancel those changes?' translated) ifTrue: [model clearUserEditFlag].\\n\\t\\t^ self].\\n\\tstripes _ (Form extent: 16@16 fromStipple: 16r36C9) bits.\\n\\tDisplay border: self insetDisplayBox width: 4\\n\\t\\t\\trule: Form reverse fillColor: stripes.\\n\\tokToCancel _ self confirm: 'Changes have not been saved.\\nIs it OK to cancel those changes?' translated.\\n\\tDisplay border: self insetDisplayBox width: 4\\n\\t\\t\\trule: Form reverse fillColor: stripes.\\n\\tokToCancel ifTrue:\\n\\t\\t[self updateDisplayContents.\\n\\t\\tmodel clearUserEditFlag].\\n! !\\n\\n!StringHolderView methodsFor: 'updating' stamp: 'di 4/21/1998 11:30'!\\nupdate: aSymbol\\n\\t\\\"Refer to the comment in View|update:.\\\"\\n\\taSymbol == #wantToChange ifTrue: [^ self promptForCancel].\\n\\taSymbol == #clearUserEdits ifTrue: [^ self hasUnacceptedEdits: false].\\n\\taSymbol == #flash ifTrue: [^ controller flash].\\n\\tself updateDisplayContents! !\\n\\n!StringHolderView methodsFor: 'updating'!\\nupdateDisplayContents\\n\\t\\\"Make the text that is displayed be the contents of the receiver's model.\\\"\\n\\n\\tself editString: model contents.\\n\\tself displayView! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStringHolderView class\\n\\tinstanceVariableNames: ''!\\n\\n!StringHolderView class methodsFor: 'instance creation'!\\ncontainer\\n\\t\\\"Answer an instance of me with a new instance of StringHolder as the \\n\\tmodel.\\\"\\n\\n\\t^self container: StringHolder new! !\\n\\n!StringHolderView class methodsFor: 'instance creation'!\\ncontainer: aContainer \\n\\t\\\"Answer an instance of me whose model is aContainer. Give it a 2-dot \\n\\tborder.\\\"\\n\\n\\t| aCodeView |\\n\\taCodeView _ self new model: aContainer.\\n\\taCodeView borderWidthLeft: 2 right: 2 top: 2 bottom: 2.\\n\\t^aCodeView! !\\n\\n!StringHolderView class methodsFor: 'instance creation' stamp: 'ar 9/27/2005 20:48'!\\nopen\\n\\t\\\"Create a standard system view of a workspace on the screen.\\\"\\n\\n\\tself open: StringHolder new label: 'Workspace'! !\\n\\n!StringHolderView class methodsFor: 'instance creation'!\\nopen: aStringHolder \\n\\t\\\"Create a standard system view of the argument, aStringHolder, as viewed \\n\\tby an instance of me. The view has label 'StringHolder'.\\\"\\n\\n\\tself open: aStringHolder label: 'StringHolder'! !\\n\\n!StringHolderView class methodsFor: 'instance creation' stamp: 'sma 4/30/2000 10:15'!\\nopen: aStringHolder label: labelString \\n\\t\\\"NOTE this should be in the model class, and all senders so redirected,\\n\\tin order that the view class can be discarded in a morphic world.\\\"\\n\\n\\t\\\"Create a standard system view of the model, aStringHolder, as viewed by \\n\\tan instance of me. The label of the view is aString.\\\"\\n\\t| aStringHolderView topView |\\n\\n\\tSmalltalk isMorphic ifTrue: [^ aStringHolder openAsMorphLabel: labelString].\\n\\n\\taStringHolderView _ self container: aStringHolder.\\n\\ttopView _ StandardSystemView new.\\n\\ttopView model: aStringHolderView model.\\n\\ttopView addSubView: aStringHolderView.\\n\\ttopView label: labelString.\\n\\ttopView minimumSize: 100 @ 50.\\n\\ttopView controller open! !\\nMorph subclass: #StringMorph\\n\\tinstanceVariableNames: 'font emphasis contents hasFocus'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Basic'!\\n!StringMorph commentStamp: 'efc 3/7/2003 17:34' prior: 0!\\nStringMorph is a \\\"lightweight\\\" Morph to display a String. It supports only a single font, color, and emphasis combination. For multiple text styles, use TextMorph.\\n\\nStructure:\\ninstance var \\tType Description \\nfont \\t\\t\\tStrikeFont \\t\\t(normally nil; then the accessor #font gives back TextStyle \\n\\t\\t\\t\\tor nil\\t\\t\\tdefaultFont) \\nemphasis \\t\\tSmallInteger\\tbitmask determining character attributes (underline, bold, \\t\\t\\t\\t\\t\\t\\t\\titalics, narrow, struckout) \\ncontents \\t\\tString \\t\\t\\tThe text that will be displayed. \\nhasFocus \\t\\tBoolean \\t\\tDo I have the keyboard focus or not? \\n\\nIf you shift-click on a StringMorph you can edit its string. This is accomplished the following way: StringMorph can launch a StringMorphEditor if it receives a #mouseDown event.\\n\\nA StringMorph may also be used like a SimpleButtonMorph to do an action when clicked. Use the menu 'extras' / 'add mouseUpAction'.\\n\\nThe following propery will be defined:\\naStringMorph valueOfProperty: #mouseUpCodeToRun!\\n]style[(11 20 5 14 6 97 9 14 47 9 10 53 9 40 12 108 6 49 7 168 17 75 17 163)f1LStringMorph Hierarchy;,f1,f1LMorph Comment;,f1,f1LString Comment;,f1,f1LTextMorph Comment;,f1,f1i,f1,f1LStrikeFont Comment;,f1,f1LTextStyle Comment;,f1,f1LSmallInteger Comment;,f1,f1LString Comment;,f1,f1LBoolean Comment;,f1,f1LStringMorphEditor Comment;,f1,f1LSimpleButtonMorph Comment;,f1!\\n\\n\\n!StringMorph methodsFor: 'accessing'!\\ncontents\\n\\n\\t^ contents! !\\n\\n!StringMorph methodsFor: 'accessing'!\\ncontentsClipped: aString\\n\\t\\\"Change my text, but do not change my size as a result\\\"\\n\\tcontents = aString ifTrue: [^ self]. \\\"No substantive change\\\"\\n\\tcontents _ aString.\\n\\tself changed! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'nk 2/26/2004 13:15'!\\ncontents: newContents \\n\\t| scanner |\\n\\tcontents := newContents isText\\n\\t\\t\\t\\tifTrue: [scanner := StringMorphAttributeScanner new initializeFromStringMorph: self.\\n\\t\\t\\t\\t\\t(newContents attributesAt: 1 forStyle: self font textStyle)\\n\\t\\t\\t\\t\\t\\tdo: [:attr | attr emphasizeScanner: scanner].\\n\\t\\t\\t\\t\\temphasis := scanner emphasis.\\n\\t\\t\\t\\t\\tfont := scanner font emphasis: emphasis.\\n\\t\\t\\t\\t\\tcolor := scanner textColor.\\n\\t\\t\\t\\t\\tnewContents string]\\n\\t\\t\\t\\tifFalse: [contents = newContents\\n\\t\\t\\t\\t\\t\\tifTrue: [^ self].\\n\\t\\t\\t\\t\\t\\\"no substantive change\\\"\\n\\t\\t\\t\\t\\tnewContents].\\n\\tself fitContents! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'ar 12/12/2001 02:44'!\\nfitContents\\n\\n\\t| newBounds boundsChanged |\\n\\tnewBounds _ self measureContents.\\n\\tboundsChanged _ bounds extent ~= newBounds.\\n\\tself extent: newBounds.\\t\\t\\\"default short-circuits if bounds not changed\\\"\\n\\tboundsChanged ifFalse: [self changed]! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'ar 1/31/2001 19:33'!\\nfont\\n\\t\\\"who came up with #fontToUse rather than font?!!\\\"\\n\\t^self fontToUse! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'tk 8/28/2000 13:59'!\\nfontName: fontName size: fontSize\\n\\n\\t^ self font: (StrikeFont familyName: fontName size: fontSize) \\n\\t\\t\\temphasis: 0! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'dgd 2/21/2003 23:07'!\\nfontToUse\\n\\t| fontToUse |\\n\\tfontToUse := font isNil ifTrue: [TextStyle defaultFont] ifFalse: [font].\\n\\t(emphasis isNil or: [emphasis = 0]) \\n\\t\\tifTrue: [^fontToUse]\\n\\t\\tifFalse: [^fontToUse emphasized: emphasis]! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'di 4/2/1999 16:11'!\\nfont: aFont emphasis: emphasisCode\\n\\tfont _ aFont.\\n\\temphasis _ emphasisCode.\\n\\tself fitContents.\\n\\\"\\nin inspector say,\\n\\t self font: (TextStyle default fontAt: 2) emphasis: 1\\n\\\"! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'sw 9/8/1999 11:10'!\\ninterimContents: aString\\n\\t\\\"The receiver is under edit and aString represents the string the user sees as she edits, which typically will not have been accepted and indeed may be abandoned\\\"\\n\\n\\tself contents: aString! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'ar 12/30/2001 20:45'!\\nmeasureContents\\n\\t| f |\\n\\tf _ self fontToUse.\\n\\t^(((f widthOfString: contents) max: self minimumWidth) @ f height).! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'sw 9/8/1999 13:44'!\\nminimumWidth\\n\\t\\\"Answer the minimum width that the receiver can have. A nonzero value here keeps the receiver from degenerating into something that cannot ever be seen or touched again!! Obeyed by fitContents.\\\"\\n\\n\\t^ 3! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'sw 12/6/1999 13:16'!\\nsetWidth: width\\n\\n\\tself extent: width @ (font ifNil: [TextStyle defaultFont]) height! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'tk 12/16/1998 11:55'!\\nuserString\\n\\t\\\"Do I have a text string to be searched on?\\\"\\n\\n\\t^ contents! !\\n\\n!StringMorph methodsFor: 'accessing' stamp: 'sw 9/16/1999 22:57'!\\nvalueFromContents\\n\\t\\\"Return a new value from the current contents string.\\\"\\n\\t^ contents! !\\n\\n\\n!StringMorph methodsFor: 'connectors-layout' stamp: 'dgd 2/16/2003 21:52'!\\nminHeight\\n\\\"answer the receiver's minHeight\\\"\\n\\t^ self fontToUse height! !\\n\\n\\n!StringMorph methodsFor: 'drawing' stamp: 'ar 12/31/2001 02:38'!\\ndrawOn: aCanvas\\n\\n\\taCanvas drawString: contents in: bounds font: self fontToUse color: color.! !\\n\\n!StringMorph methodsFor: 'drawing' stamp: 'tk 8/1/2001 14:15'!\\nlookTranslucent\\n\\n\\t\\\"keep the text the same color (black)\\\"! !\\n\\n\\n!StringMorph methodsFor: 'editing'!\\nacceptContents\\n\\t\\\"The message is sent when the user hits enter or Cmd-S. Accept the current contents and end editing. This default implementation does nothing.\\\"\\n! !\\n\\n!StringMorph methodsFor: 'editing' stamp: 'sw 9/8/1999 17:04'!\\nacceptValue: aValue\\n\\t| val |\\n\\tself contents: (val _ aValue asString).\\n\\t^ val! !\\n\\n!StringMorph methodsFor: 'editing' stamp: 'sw 9/17/1999 13:27'!\\ncancelEdits\\n\\n\\tself doneWithEdits! !\\n\\n!StringMorph methodsFor: 'editing' stamp: 'di 9/6/1999 22:44'!\\ndoneWithEdits\\n\\n\\thasFocus _ false! !\\n\\n!StringMorph methodsFor: 'editing' stamp: 'nk 2/24/2005 20:11'!\\nlaunchMiniEditor: evt\\n\\n\\t| textMorph |\\n\\thasFocus _ true. \\\"Really only means edit in progress for this morph\\\"\\n\\ttextMorph _ StringMorphEditor new contentsAsIs: contents.\\n\\ttextMorph beAllFont: self fontToUse.\\n\\ttextMorph bounds: (self bounds expandBy: 0@2).\\n\\tself addMorphFront: textMorph.\\n\\tevt hand newKeyboardFocus: textMorph.\\n\\ttextMorph editor selectFrom: 1 to: textMorph paragraph text string size! !\\n\\n!StringMorph methodsFor: 'editing' stamp: 'sw 9/8/1999 10:42'!\\nlostFocusWithoutAccepting\\n\\t\\\"The message is sent when the user, having been in an editing episode on the receiver, changes the keyboard focus -- typically by clicking on some editable text somewhere else -- without having accepted the current edits.\\\"\\n\\n\\tself acceptContents! !\\n\\n!StringMorph methodsFor: 'editing' stamp: 'sw 7/21/1999 14:59'!\\nwantsKeyboardFocusOnShiftClick\\n\\t^ owner topRendererOrSelf wantsKeyboardFocusFor: self\\n! !\\n\\n\\n!StringMorph methodsFor: 'event handling' stamp: 'ar 10/6/2000 00:16'!\\nhandlesMouseDown: evt\\n\\t^ (evt shiftPressed and: [self wantsKeyboardFocusOnShiftClick])\\n\\t\\tifTrue: [true]\\n\\t\\tifFalse: [super handlesMouseDown: evt].\\n! !\\n\\n!StringMorph methodsFor: 'event handling' stamp: 'sw 9/8/1999 11:26'!\\nhasFocus\\n\\t^ hasFocus! !\\n\\n!StringMorph methodsFor: 'event handling' stamp: 'di 9/5/1999 17:25'!\\nmouseDown: evt\\n\\t\\\"If the shift key is pressed, make this string the keyboard input focus.\\\"\\n\\n\\t(evt shiftPressed and: [self wantsKeyboardFocusOnShiftClick])\\n\\t\\tifTrue: [self launchMiniEditor: evt]\\n\\t\\tifFalse: [super mouseDown: evt].\\n! !\\n\\n!StringMorph methodsFor: 'event handling' stamp: 'sw 5/6/1998 15:45'!\\nwouldAcceptKeyboardFocus\\n\\t^ self isLocked not! !\\n\\n\\n!StringMorph methodsFor: 'font' stamp: 'efc 2/22/2003 21:35'!\\nemphasis: aNumber\\n\\t\\\"Set the receiver's emphasis as indicated. aNumber is a bitmask with the following format:\\n\\n\\tbit\\tattribute\\n\\t1\\tbold\\n\\t2\\titalic\\n\\t4\\tunderlined\\n\\t8\\tnarrow\\n\\t16\\tstruckOut\\\"\\n\\n\\t\\\"examples: 0 -> plain. \\n\\t1 -> bold. 2 -> italic. 3 -> bold italic. 4 -> underlined \\n\\t5 -> bold underlined. 6 -> italic underlined. 7 -> bold italic underlined \\n\\tetc...\\\"\\n\\n\\temphasis _ aNumber.\\n\\t^ self font: font emphasis: emphasis! !\\n\\n\\n!StringMorph methodsFor: 'halos and balloon help' stamp: 'sw 6/15/1998 15:34'!\\naddOptionalHandlesTo: aHalo box: box\\n\\tself flag: #deferred.\\n\\n\\t\\\"Eventually...\\n\\tself addFontHandlesTo: aHalo box: box\\\"! !\\n\\n!StringMorph methodsFor: 'halos and balloon help' stamp: 'sw 6/6/2001 13:34'!\\nboundsForBalloon\\n\\t\\\"Some morphs have bounds that are way too big. This is a contorted way of making things work okay in PluggableListMorphs, whose list elements historically have huge widths\\\"\\n\\n\\t| ownerOwner |\\n\\t^ ((owner notNil and: [(ownerOwner _ owner owner) notNil]) and:\\n\\t\\t\\t[ownerOwner isKindOf: PluggableListMorph])\\n\\t\\tifTrue:\\n\\t\\t\\t[self boundsInWorld intersect: ownerOwner boundsInWorld]\\n\\t\\tifFalse:\\n\\t\\t\\t[super boundsForBalloon]! !\\n\\n\\n!StringMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 22:31'!\\ndefaultColor\\n\\t\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color black! !\\n\\n!StringMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 20:42'!\\ninitialize\\n\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\\"\\\"\\n\\tfont _ nil.\\n\\temphasis _ 0.\\n\\thasFocus _ false! !\\n\\n!StringMorph methodsFor: 'initialization' stamp: 'dgd 2/14/2003 21:57'!\\ninitWithContents: aString font: aFont emphasis: emphasisCode \\n\\tsuper initialize.\\n\\t\\n\\tfont _ aFont.\\n\\temphasis _ emphasisCode.\\n\\thasFocus _ false.\\n\\tself contents: aString! !\\n\\n\\n!StringMorph methodsFor: 'layout' stamp: 'nk 5/11/2001 09:33'!\\nfullBounds\\n\\tself contents ifNil: [ self contents: 'String Morph' ].\\n\\t^super fullBounds! !\\n\\n\\n!StringMorph methodsFor: 'menu' stamp: 'dgd 8/30/2003 22:17'!\\naddCustomMenuItems: aCustomMenu hand: aHandMorph\\n\\n\\tsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.\\n\\taCustomMenu add: 'change font' translated action: #changeFont.\\n\\taCustomMenu add: 'change emphasis' translated action: #changeEmphasis.\\n! !\\n\\n!StringMorph methodsFor: 'menu' stamp: 'yo 3/14/2005 13:03'!\\nchangeEmphasis\\n\\n\\t| reply aList |\\n\\taList _ #(normal bold italic narrow underlined struckOut).\\n\\treply _ (SelectionMenu labelList: (aList collect: [:t | t translated]) selections: aList) startUp.\\n\\treply ifNotNil:[\\n\\t\\tself emphasis: (TextEmphasis perform: reply) emphasisCode.\\n\\t].\\n! !\\n\\n!StringMorph methodsFor: 'menu' stamp: 'ar 1/5/2002 21:45'!\\nchangeFont\\n\\t| newFont |\\n\\tnewFont _ StrikeFont fromUser: self fontToUse.\\n\\tnewFont ifNotNil:[self font: newFont].! !\\n\\n\\n!StringMorph methodsFor: 'objects from disk' stamp: 'tk 11/29/2004 16:52'!\\nfixUponLoad: aProject seg: anImageSegment\\n\\n\\t\\\"We are in an old project that is being loaded from disk.\\n\\nFix up conventions that have changed.\\\"\\n\\n\\n\\n\\t| substituteFont |\\n\\n\\tsubstituteFont _ aProject projectParameters at:\\n\\n#substitutedFont ifAbsent: [#none].\\n\\n\\t(substituteFont ~~ #none and: [self font == substituteFont])\\n\\n\\t\\t\\tifTrue: [ self fitContents ].\\n\\n\\n\\n\\t^ super fixUponLoad: aProject seg: anImageSegment! !\\n\\n\\n!StringMorph methodsFor: 'parts bin' stamp: 'dgd 2/14/2003 21:58'!\\ninitializeToStandAlone\\n\\tsuper initializeToStandAlone.\\n\\t\\n\\tfont _ nil.\\n\\temphasis _ 0.\\n\\thasFocus _ false.\\n\\tself contents: 'String: Shift-click on me to edit'! !\\n\\n\\n!StringMorph methodsFor: 'printing' stamp: 'efc 2/22/2003 21:35'!\\nfont: aFont \\n\\t\\\"Set the font my text will use. The emphasis remains unchanged.\\\"\\n\\n\\tfont _ aFont.\\n\\t^ self font: font emphasis: emphasis! !\\n\\n!StringMorph methodsFor: 'printing' stamp: 'jm 11/3/97 16:52'!\\nprintOn: aStream\\n\\n\\tsuper printOn: aStream.\\n\\taStream print: contents.\\n! !\\n\\n\\n!StringMorph methodsFor: '*MorphicExtras-accessing' stamp: 'sw 2/18/2003 02:55'!\\ngetCharacters\\n\\t\\\"obtain a string value from the receiver.\\\"\\n\\n\\t^ self contents! !\\n\\n!StringMorph methodsFor: '*MorphicExtras-accessing' stamp: 'sw 9/9/1999 18:09'!\\nhandsWithMeForKeyboardFocus\\n\\t| foc |\\n\\t\\\"Answer the hands that have me as their keyboard focus\\\"\\n\\n\\thasFocus ifFalse: [^ #()].\\n\\t^ self currentWorld hands select:\\n\\t\\t[:aHand | (foc _ aHand keyboardFocus) notNil and: [foc owner == self]]! !\\n\\n\\n!StringMorph methodsFor: '*MorphicExtras-printing'!\\nfullPrintOn: aStream\\n\\n\\taStream nextPutAll: '('.\\n\\tsuper fullPrintOn: aStream.\\n\\taStream nextPutAll: ') contents: '; print: contents! !\\n\\n\\n!StringMorph methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nballoonTextForClassAndMethodString\\n\\t\\\"Answer suitable balloon text for the receiver thought of as an encoding of the form\\n\\t\\t<className> [ class ] <selector>\\\"\\n\\n\\t| aComment |\\n\\tPreferences balloonHelpInMessageLists\\n\\t\\tifFalse: [^ nil].\\n\\tMessageSet parse: self contents asString toClassAndSelector:\\n\\t\\t[:aClass :aSelector |\\n\\t\\t\\t(aClass notNil and: [aSelector notNil]) ifTrue:\\n\\t\\t\\t\\t[aComment := aClass precodeCommentOrInheritedCommentFor: aSelector]].\\n\\t^ aComment\\n! !\\n\\n!StringMorph methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nballoonTextForLexiconString\\n\\t\\\"Answer suitable balloon text for the receiver thought of as an encoding (used in Lexicons) of the form\\n\\t\\t<selector> <spaces> (<className>>)\\\"\\n\\n\\t| aComment contentsString aSelector aClassName |\\n\\tPreferences balloonHelpInMessageLists\\n\\t\\tifFalse: [^ nil].\\n\\tcontentsString := self contents asString.\\n\\taSelector := contentsString upTo: $ .\\n\\taClassName := contentsString copyFrom: ((contentsString indexOf: $() + 1) to: ((contentsString indexOf: $)) - 1).\\n\\tMessageSet parse: (aClassName, ' dummy') toClassAndSelector:\\n\\t\\t[:cl :sel | cl ifNotNil:\\n\\t\\t\\t[aComment := cl precodeCommentOrInheritedCommentFor: aSelector]].\\n\\t^ aComment\\n! !\\n\\n!StringMorph methodsFor: '*Tools' stamp: 'sd 11/20/2005 21:26'!\\nballoonTextForMethodString\\n\\t\\\"Answer suitable balloon text for the receiver thought of as a method belonging to the currently-selected class of a browser tool.\\\"\\n\\n\\t| aWindow aCodeHolder aClass |\\n\\tPreferences balloonHelpInMessageLists\\n\\t\\tifFalse: [^ nil].\\n\\taWindow := self ownerThatIsA: SystemWindow.\\n\\t(aWindow isNil or: [((aCodeHolder := aWindow model) isKindOf: CodeHolder) not])\\n\\t\\tifTrue:\\t[^ nil].\\n\\t((aClass := aCodeHolder selectedClassOrMetaClass) isNil or:\\n\\t\\t[(aClass includesSelector: contents asSymbol) not])\\n\\t\\t\\tifTrue: [^ nil].\\n\\t^ aClass precodeCommentOrInheritedCommentFor: contents asSymbol\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStringMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!StringMorph class methodsFor: 'instance creation' stamp: 'sw 8/22/97 22:19'!\\ncontents: aString\\n\\t\\\" 'StringMorph contents: str' is faster than 'StringMorph new contents: str' \\\"\\n\\t^ self contents: aString font: nil! !\\n\\n!StringMorph class methodsFor: 'instance creation' stamp: 'di 4/1/1999 17:15'!\\ncontents: aString font: aFont\\n\\t^ self basicNew initWithContents: aString font: aFont emphasis: 0! !\\n\\n!StringMorph class methodsFor: 'instance creation' stamp: 'di 4/1/1999 17:15'!\\ncontents: aString font: aFont emphasis: emphasisCode\\n\\t^ self basicNew initWithContents: aString font: aFont emphasis: emphasisCode! !\\n\\n\\n!StringMorph class methodsFor: 'scripting' stamp: 'sw 5/6/1998 14:00'!\\nauthoringPrototype\\n\\t^ super authoringPrototype contents: 'String'! !\\n\\n\\n!StringMorph class methodsFor: 'testing' stamp: 'di 5/6/1998 21:07'!\\ntest\\n\\t\\\"Return a morph with lots of strings for testing display speed.\\\"\\n\\t| c |\\n\\tc _ AlignmentMorph newColumn.\\n\\tSystemOrganization categories do:\\n\\t\\t[:cat | c addMorph: (StringMorph new contents: cat)].\\n\\t^ c! !\\n\\n!StringMorph class methodsFor: 'testing' stamp: 'di 5/6/1998 21:08'!\\ntest2\\n\\t\\\"Return a morph with lots of strings for testing display speed.\\\"\\n\\t| c r |\\n\\tc _ AlignmentMorph newColumn.\\n\\tSystemOrganization categories reverseDo:\\n\\t\\t[:cat | c addMorph: (StringMorph new contents: cat)].\\n\\tr _ RectangleMorph new extent: c fullBounds extent.\\n\\tc submorphsDo: [:m | r addMorph: m].\\n\\t^ r\\n! !\\nObject subclass: #StringMorphAttributeScanner\\n\\tinstanceVariableNames: 'fontNumber textColor emphasis alignment actualFont indent kern'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Text Support'!\\n!StringMorphAttributeScanner commentStamp: '<historical>' prior: 0!\\nA StringMorphAttributeScanner provides the interface of a CharacterScanner so that text attributes may be collected from a Text and used elsewhere, like in setting the attributes of a StringMorph.\\n!\\n]style[(2 195)cblack;,f3cblack;!\\n\\n\\n!StringMorphAttributeScanner methodsFor: 'accessing' stamp: 'nk 2/26/2004 13:12'!\\nactualFont\\n\\t\\\"Answer the value of actualFont\\\"\\n\\n\\t^ actualFont ifNil: [ TextStyle defaultFont ]! !\\n\\n!StringMorphAttributeScanner methodsFor: 'accessing' stamp: 'nk 2/26/2004 12:34'!\\nalignment\\n\\t\\\"Answer the value of alignment\\\"\\n\\n\\t^ alignment! !\\n\\n!StringMorphAttributeScanner methodsFor: 'accessing' stamp: 'nk 2/26/2004 12:34'!\\nemphasis\\n\\t\\\"Answer the value of emphasis\\\"\\n\\n\\t^ emphasis! !\\n\\n!StringMorphAttributeScanner methodsFor: 'accessing' stamp: 'nk 2/26/2004 13:14'!\\nfont\\n\\t\\\"Answer the value of font\\\"\\n\\n\\t^self textStyle fontAt: self fontNumber! !\\n\\n!StringMorphAttributeScanner methodsFor: 'accessing' stamp: 'nk 2/26/2004 13:11'!\\nfontNumber\\n\\t\\\"Answer the value of font\\\"\\n\\n\\t^ fontNumber! !\\n\\n!StringMorphAttributeScanner methodsFor: 'accessing' stamp: 'nk 2/26/2004 12:34'!\\nindent\\n\\t\\\"Answer the value of indent\\\"\\n\\n\\t^ indent! !\\n\\n!StringMorphAttributeScanner methodsFor: 'accessing' stamp: 'nk 2/26/2004 12:34'!\\nkern\\n\\t\\\"Answer the value of kern\\\"\\n\\n\\t^ kern! !\\n\\n!StringMorphAttributeScanner methodsFor: 'accessing' stamp: 'nk 2/26/2004 12:34'!\\ntextColor\\n\\t\\\"Answer the value of textColor\\\"\\n\\n\\t^ textColor! !\\n\\n!StringMorphAttributeScanner methodsFor: 'accessing' stamp: 'nk 2/26/2004 13:12'!\\ntextStyle\\n\\t^self actualFont textStyle ifNil: [ TextStyle default ]! !\\n\\n\\n!StringMorphAttributeScanner methodsFor: 'initialize-release' stamp: 'nk 2/26/2004 13:10'!\\ninitialize\\n\\temphasis _ 0.\\n\\tindent _ 0.\\n\\tkern _ 0.\\n\\tfontNumber _ 1.\\n\\tactualFont _ TextStyle defaultFont! !\\n\\n\\n!StringMorphAttributeScanner methodsFor: 'scanning' stamp: 'nk 2/26/2004 12:40'!\\naddEmphasis: anInteger\\n\\t\\\"Set the value of emphasis\\\"\\n\\n\\temphasis _ emphasis bitOr: anInteger! !\\n\\n!StringMorphAttributeScanner methodsFor: 'scanning' stamp: 'nk 2/26/2004 12:41'!\\naddKern: kernDelta\\n\\t\\\"Set the current kern amount.\\\"\\n\\tkern _ kern + kernDelta! !\\n\\n!StringMorphAttributeScanner methodsFor: 'scanning' stamp: 'nk 2/26/2004 12:37'!\\nindentationLevel: anInteger\\n\\t\\\"Set the value of indent\\\"\\n\\n\\tindent _ anInteger! !\\n\\n!StringMorphAttributeScanner methodsFor: 'scanning' stamp: 'nk 2/26/2004 13:09'!\\nsetActualFont: aFont\\n\\t\\\"Set the value of actualFont, from a TextFontReference\\\"\\n\\n\\tactualFont _ aFont.\\n\\taFont textStyle ifNotNilDo: [ :ts | fontNumber _ ts fontIndexOf: aFont ]! !\\n\\n!StringMorphAttributeScanner methodsFor: 'scanning' stamp: 'nk 2/26/2004 12:39'!\\nsetAlignment: aSymbol\\n\\t\\\"Set the value of alignment\\\"\\n\\n\\talignment _ aSymbol! !\\n\\n!StringMorphAttributeScanner methodsFor: 'scanning' stamp: 'nk 2/26/2004 13:10'!\\nsetFont: fontNum\\n\\t\\\"Set the value of font\\\"\\n\\n\\tfontNumber _ fontNum! !\\n\\n!StringMorphAttributeScanner methodsFor: 'scanning' stamp: 'nk 2/26/2004 12:34'!\\ntextColor: anObject\\n\\t\\\"Set the value of textColor\\\"\\n\\n\\ttextColor _ anObject! !\\n\\n\\n!StringMorphAttributeScanner methodsFor: 'string morph' stamp: 'nk 2/26/2004 13:09'!\\ninitializeFromStringMorph: aStringMorph\\n\\t| style |\\n\\tactualFont _ aStringMorph font ifNil: [ TextStyle defaultFont ].\\n\\tstyle _ actualFont textStyle.\\n\\temphasis _ actualFont emphasis.\\n\\tfontNumber _ (style fontIndexOf: actualFont) ifNil: [ 1 ].\\n\\ttextColor _ aStringMorph color.\\n! !\\nTextMorph subclass: #StringMorphEditor\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Text Support'!\\n!StringMorphEditor commentStamp: '<historical>' prior: 0!\\nI am a textMorph used as a pop-up editor for StringMorphs. I present a yellow background and I go away when a CR is typed or when the user clicks elsewhere.!\\n\\n\\n!StringMorphEditor methodsFor: 'display' stamp: 'sw 4/20/2003 15:46'!\\ninitialize\\n\\n\\t\\\"Initialize the receiver. Give it a white background\\\"\\n\\n\\n\\n\\tsuper initialize.\\n\\n\\tself backgroundColor: Color white.\\n\\n\\tself color: Color red! !\\n\\n\\n!StringMorphEditor methodsFor: 'drawing' stamp: 'sw 9/7/1999 16:22'!\\ndrawOn: aCanvas\\n\\n\\taCanvas fillRectangle: self bounds color: Color yellow muchLighter.\\n\\t^ super drawOn: aCanvas! !\\n\\n\\n!StringMorphEditor methodsFor: 'event handling' stamp: 'nk 6/12/2004 22:07'!\\nkeyStroke: evt\\n\\t\\\"This is hugely inefficient, but it seems to work, and it's unlikely it will ever need\\n\\tto be any more efficient -- it's only intended to edit single-line strings.\\\"\\n\\n\\t| char priorEditor newSel |\\n\\t(((char _ evt keyCharacter) = Character enter) or: [(char = Character cr)\\n\\t\\t\\tor: [char = $s and: [evt commandKeyPressed]]])\\n\\t\\t\\t\\tifTrue: [owner doneWithEdits; acceptContents.\\n\\tself flag: #arNote. \\\"Probably unnecessary\\\"\\n\\t\\t\\t\\t\\t\\tevt hand releaseKeyboardFocus.\\n\\t\\t\\t\\t\\t\\t^ self delete].\\n\\t\\n\\t(char = $l and: [evt commandKeyPressed]) ifTrue: \\\"cancel\\\"\\n\\t\\t[owner cancelEdits.\\n\\t\\tevt hand releaseKeyboardFocus.\\n\\t\\t^ self delete].\\n\\n\\tsuper keyStroke: evt.\\n\\towner interimContents: self contents asString.\\n\\tnewSel _ self editor selectionInterval.\\n\\n\\tpriorEditor _ self editor. \\\"Save editor state\\\"\\n\\tself releaseParagraph. \\\"Release paragraph so it will grow with selection.\\\"\\n\\tself paragraph. \\\"Re-instantiate to set new bounds\\\"\\n\\tself installEditorToReplace: priorEditor. \\\"restore editor state\\\"\\n\\tself editor selectFrom: newSel first to: newSel last.\\n! !\\n\\n!StringMorphEditor methodsFor: 'event handling' stamp: 'nk 1/23/2004 13:18'!\\nkeyboardFocusChange: aBoolean\\n\\t| hadFocus |\\n\\towner ifNil: [ ^self ].\\n\\thadFocus _ owner hasFocus.\\n\\tsuper keyboardFocusChange: aBoolean.\\n\\taBoolean ifFalse:\\n\\t\\t[hadFocus ifTrue:\\n\\t\\t\\t[owner lostFocusWithoutAccepting; doneWithEdits].\\n\\t\\t^ self delete]! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStringMorphEditor class\\n\\tinstanceVariableNames: ''!\\n\\n!StringMorphEditor class methodsFor: 'new-morph participation' stamp: 'kfr 5/1/2000 13:41'!\\nincludeInNewMorphMenu\\n\\t\\\"Not to be instantiated from the menu\\\"\\n\\t^ false! !\\nTileMorph subclass: #StringReadoutTile\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting Tiles'!\\n\\n!StringReadoutTile methodsFor: 'accessing' stamp: 'sw 11/1/97 13:15'!\\nliteral: anObject\\n\\tliteral _ anObject.\\n\\tself updateLiteralLabel.\\n\\tsubmorphs last informTarget! !\\n\\n\\n!StringReadoutTile methodsFor: 'literal' stamp: 'sw 9/15/1999 15:14'!\\nsetLiteralTo: anObject width: w\\n\\t\\\"like literal:width: but does not inform the target\\\"\\n\\tliteral _ anObject.\\n\\tself updateLiteralLabel.\\n\\tsubmorphs last setWidth: w.\\n\\tself updateLiteralLabel! !\\n\\n\\n!StringReadoutTile methodsFor: 'misc' stamp: 'sw 9/17/1999 08:01'!\\nbasicWidth\\n\\t^ 26! !\\n\\n\\n!StringReadoutTile methodsFor: 'event handling' stamp: 'tak 8/2/2005 18:20'!\\nhandlesMouseDown: evt \\n\\t^ true! !\\n\\n!StringReadoutTile methodsFor: 'event handling' stamp: 'tak 8/2/2005 23:38'!\\nmouseStillDown: evt \\n\\t(self labelMorph notNil\\n\\t\\t\\tand: [self labelMorph containsPoint: evt cursorPoint])\\n\\t\\tifTrue: [^ self labelMorph mouseDown: evt].\\n\\t^ super mouseStillDown: evt! !\\nObjectSocket subclass: #StringSocket\\n\\tinstanceVariableNames: 'numStringsInNextArray stringsForNextArray nextStringSize files startTime stringCounter socketWriterProcess outputQueue bytesInOutputQueue extraUnsentBytes transmissionError readBuffer'\\n\\tclassVariableNames: 'MaxRatesSeen RecentSendHistory RunningSendCount'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Network-ObjectSocket'!\\n!StringSocket commentStamp: 'ls 8/4/2004 15:15' prior: 0!\\nThis is a socket which sends arrays of strings back and forth. This is less convenient than ObjectSockets, but it is more secure and it makes it easier to reason about updates to the protocol.\\n\\nAn array of strings is represented on the network as:\\n\\n\\t4-bytes\\t\\tnumber of strings in the array\\n\\t4-byte\\t\\tnumber of bytes in the first string\\n\\tn1-bytes\\t\\tcharacters in the first string\\n\\t4-bytes\\t\\tnumber of bytes in the second string\\n\\tn2-bytes\\tcharacters in the second string\\n\\t...\\n\\n!\\n\\n\\n!StringSocket methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\ndestroy\\n\\n\\tsocketWriterProcess ifNotNil: [socketWriterProcess terminate. socketWriterProcess := nil].\\n\\toutputQueue := nil.\\n\\tbytesInOutputQueue := 0.\\n\\tsocket ifNotNil: [socket destroy. socket := nil.].\\n! !\\n\\n!StringSocket methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\ninitialize: aSocket\\n\\n\\ttransmissionError := false.\\n\\tsuper initialize: aSocket.\\n\\toutputQueue := SharedQueue new.\\n\\textraUnsentBytes := bytesInOutputQueue := 0.\\n\\tsocketWriterProcess := [\\n\\t\\t[self transmitQueueNext] whileTrue.\\n\\t\\tsocketWriterProcess := nil.\\n\\t\\toutputQueue := nil.\\n\\t\\tbytesInOutputQueue := 0.\\n\\t] forkAt: Processor lowIOPriority.! !\\n\\n!StringSocket methodsFor: 'as yet unclassified' stamp: 'yo 10/10/2005 18:47'!\\nreadBuffer\\n\\n\\t^ readBuffer ifNil: [readBuffer _ String new: 20000].\\n! !\\n\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'yo 10/10/2005 18:49'!\\naddToInBuf: aString\\n\\n\\t| newAlloc |\\n\\tnewAlloc _ aString size * 2 max: 80000.\\n\\tinBuf ifNil: [\\n\\t\\tinBuf _ String new: newAlloc.\\n\\t\\tinBufIndex _ 1.\\n\\t\\tinBufLastIndex _ 0.\\n\\t].\\n\\taString size > (inBuf size - inBufLastIndex) ifTrue: [\\n\\t\\tinBuf _ inBuf , (String new: newAlloc)\\n\\t].\\n\\tinBuf \\n\\t\\treplaceFrom: inBufLastIndex + 1 \\n\\t\\tto: inBufLastIndex + aString size\\n\\t\\twith: aString \\n\\t\\tstartingAt: 1.\\n\\tinBufLastIndex _ inBufLastIndex + aString size.\\n! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\naddToOutBuf: arrayToWrite\\n\\n\\t| size newAlloc |\\n\\tsize := self spaceToEncode: arrayToWrite.\\n\\tnewAlloc := size * 2 max: 8000.\\t\\\"gives us room to grow\\\"\\n\\toutBuf ifNil: [\\n\\t\\toutBuf := String new: newAlloc.\\n\\t\\toutBufIndex := 1.\\n\\t].\\n\\toutBuf size - outBufIndex + 1 < size ifTrue: [\\n\\t\\toutBuf := outBuf , (String new: newAlloc).\\n\\t].\\n\\tCanvasEncoder at: 1 count: arrayToWrite size + 1.\\n\\toutBuf putInteger32: arrayToWrite size at: outBufIndex.\\n\\toutBufIndex := outBufIndex + 4.\\n\\tarrayToWrite do: [ :each |\\n\\t\\toutBuf putInteger32: each size at: outBufIndex.\\n\\t\\toutBufIndex := outBufIndex + 4.\\n\\t\\toutBuf \\n\\t\\t\\treplaceFrom: outBufIndex \\n\\t\\t\\tto: outBufIndex + each size - 1 \\n\\t\\t\\twith: each \\n\\t\\t\\tstartingAt: 1.\\n\\t\\toutBufIndex := outBufIndex + each size.\\n\\t].\\n\\t^size! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'RAA 12/13/2000 08:29'!\\nbacklog\\n\\n\\t^bytesInOutputQueue + extraUnsentBytes! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\ngotSomething\\n\\n\\tnumStringsInNextArray ifNil: [^self tryForNumStringsInNextArray ].\\n\\tnumStringsInNextArray = 0 ifTrue: [\\n\\t\\tinObjects add: #().\\n\\t\\tnumStringsInNextArray := nil.\\n\\t\\t^true ].\\n\\tnextStringSize ifNil: [^ self tryForNextStringSize ].\\n\\t^self tryForString\\n! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\ninBufNext: anInteger\\n\\t\\n\\t| answer |\\n\\tanswer := inBuf copyFrom: inBufIndex to: inBufIndex + anInteger - 1.\\n\\tinBufIndex := inBufIndex + anInteger.\\n\\t^answer! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'RAA 7/20/2000 15:55'!\\ninBufSize\\n\\n\\tinBuf ifNil: [^0].\\n\\t^inBufLastIndex - inBufIndex + 1! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'RAA 12/14/2000 09:54'!\\nisConnected\\n\\n\\t^super isConnected and: [socketWriterProcess notNil]! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'md 2/24/2006 19:51'!\\nnextPut: anObject\\n\\n\\tsocketWriterProcess ifNil: [^self].\\n\\toutObjects addLast: anObject.\\n\\t\\\"return the argument - added by kwl\\\"\\n\\t^ anObject! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'RAA 12/14/2000 09:46'!\\nprocessIO\\n\\t\\\"do some as much network IO as possible\\\"\\n\\n\\tsocketWriterProcess ifNil: [^self].\\n\\tself processOutput.\\n\\tself processInput.! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'yo 10/10/2005 18:47'!\\nprocessInput\\n\\t| totalReceived chunkOfData |\\n\\t\\\"do as much input as possible\\\"\\n\\n\\tself flag: #XXX. \\\"should have resource limits here--no more than X objects and Y bytes\\\"\\n\\n\\tchunkOfData _ socket receiveAvailableDataIntoBuffer: self readBuffer.\\n\\tself addToInBuf: chunkOfData.\\n\\ttotalReceived _ chunkOfData size.\\n\\n\\ttotalReceived > 0 ifTrue: [\\n\\t\\tNebraskaDebug at: #SendReceiveStats add: {'GET'. totalReceived}.\\n\\t].\\n\\n\\t[ self gotSomething ] whileTrue: [].\\t\\t\\\"decode as many string arrays as possible\\\"\\n\\n\\tself shrinkInBuf.! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\nprocessOutput\\n\\n\\t| arrayToWrite size bytesSent timeStartSending t itemsSent now timeSlot bucketAgeInMS bytesThisSlot |\\n\\n\\toutBufIndex := 1.\\n\\titemsSent := bytesSent := 0.\\n\\ttimeStartSending := Time millisecondClockValue.\\n\\t[outObjects isEmpty not and: [self isConnected]] whileTrue: [\\n\\t\\tarrayToWrite := outObjects removeFirst.\\n\\t\\tsize := self addToOutBuf: arrayToWrite.\\n\\t\\tbytesSent := bytesSent + size.\\n\\t\\titemsSent := itemsSent + 1.\\n\\t\\toutBufIndex > 10000 ifTrue: [self queueOutBufContents].\\n\\t].\\n\\toutBufIndex > 1 ifTrue: [self queueOutBufContents].\\n\\tbytesSent > 0 ifTrue: [\\n\\t\\tMaxRatesSeen ifNil: [MaxRatesSeen := Dictionary new].\\n\\t\\tnow := Time millisecondClockValue.\\n\\t\\tt := now - timeStartSending.\\n\\t\\ttimeSlot := now // 10000.\\t\\\"ten second buckets\\\"\\n\\t\\tbucketAgeInMS := now \\\\\\\\ 10.\\n\\t\\tbytesThisSlot := (MaxRatesSeen at: timeSlot ifAbsent: [0]) + bytesSent.\\n\\t\\tMaxRatesSeen \\n\\t\\t\\tat: timeSlot \\n\\t\\t\\tput: bytesThisSlot.\\n\\t\\tNebraskaDebug \\n\\t\\t\\tat: #SendReceiveStats \\n\\t\\t\\tadd: {'put'. bytesSent. t. itemsSent. bytesThisSlot // (bucketAgeInMS max: 100)}.\\n\\t].\\n! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\npurgeOutputQueue\\n\\n\\tbytesInOutputQueue := 0.\\n\\t[outputQueue nextOrNil notNil] whileTrue.! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\nqueueOutBufContents\\n\\n\\tbytesInOutputQueue := bytesInOutputQueue + outBufIndex - 1.\\n\\toutputQueue nextPut: {outBuf. outBufIndex - 1}.\\n\\tNebraskaDebug at: #queuedbufferSizes add: {outBufIndex - 1}.\\n\\toutBufIndex := 1.\\n\\toutBuf := String new: 11000.\\n\\t\\n! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\nsendDataCautiously: aStringOrByteArray bytesToSend: bytesToSend\\n\\t\\\"Send all of the data in the given array, even if it requires multiple calls to send it all. Return the number of bytes sent. Try not to send too much at once since this seemed to cause problems talking to a port on the same machine\\\"\\n\\n\\t| bytesSent count |\\n\\n\\tbytesSent := 0.\\n\\t[bytesSent < bytesToSend] whileTrue: [\\n\\t\\textraUnsentBytes := bytesToSend - bytesSent.\\n\\t\\tcount := socket \\n\\t\\t\\tsendSomeData: aStringOrByteArray \\n\\t\\t\\tstartIndex: bytesSent + 1 \\n\\t\\t\\tcount: (bytesToSend - bytesSent min: 6000).\\n\\t\\tbytesSent := bytesSent + count.\\n\\t\\t(Delay forMilliseconds: 1) wait.\\n\\t].\\n\\textraUnsentBytes := 0.\\n\\t^ bytesSent\\n! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\nshrinkInBuf\\n\\n\\tinBuf ifNil: [^self].\\n\\tinBufLastIndex < inBufIndex ifTrue: [\\n\\t\\tinBufLastIndex := 0.\\n\\t\\tinBufIndex := 1.\\n\\t\\tinBuf size > 20000 ifTrue: [inBuf := nil].\\t\\\"if really big, kill it\\\"\\n\\t\\t^self\\n\\t].\\n\\tinBuf := inBuf copyFrom: inBufIndex to: inBufLastIndex.\\n\\tinBufLastIndex := inBuf size.\\n\\tinBufIndex := 1.\\n\\n! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'ls 4/25/2000 18:36'!\\nspaceToEncode: anArray\\n\\t\\\"return the number of characters needed to encode the given string array\\\"\\n\\t^anArray inject: 4 into: [ :sum :array |\\n\\t\\tsum + (array size + 4) ].! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\ntransmitQueueNext\\n\\n\\t| bufTuple |\\n\\n\\tbufTuple := outputQueue next.\\n\\tbytesInOutputQueue := bytesInOutputQueue - bufTuple second max: 0.\\n\\t[\\n\\t\\tself \\n\\t\\t\\tsendDataCautiously: bufTuple first \\n\\t\\t\\tbytesToSend: bufTuple second.\\n\\t]\\n\\t\\ton: Error\\n\\t\\tdo: [ :ex |\\n\\t\\t\\ttransmissionError := true.\\n\\t\\t].\\n\\t^transmissionError not\\n\\n! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\ntryForNextStringSize\\n\\t\\\"grab the size of the next string, if it's available\\\"\\n\\n\\tself inBufSize >= 4 ifFalse: [^false].\\n\\n\\tnextStringSize := inBuf getInteger32: inBufIndex.\\n\\t\\\"nextStringSize > 100000 ifTrue: [self barf].\\\"\\n\\tinBufIndex := inBufIndex + 4.\\n\\t\\n\\tnextStringSize < 0 ifTrue: [\\n\\t\\tsocket disconnect.\\n\\t\\t^false ].\\n\\t\\n\\t^true\\n! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\ntryForNumStringsInNextArray\\n\\t\\\"input numStringsInNextARray, if 4 bytes are available\\\"\\n\\n\\tself inBufSize >= 4 ifFalse: [^false].\\n\\n\\tnumStringsInNextArray := inBuf getInteger32: inBufIndex.\\n\\t\\\"(numStringsInNextArray > 100 or: [numStringsInNextArray < 1]) ifTrue: [self barf].\\\"\\n\\tinBufIndex := inBufIndex + 4.\\n\\n\\tnumStringsInNextArray < 0 ifTrue: [\\n\\t\\tsocket disconnect.\\n\\t\\t^false ].\\n\\t\\n\\tstringsForNextArray := Array new: numStringsInNextArray.\\n\\tstringCounter := 0.\\n\\tnextStringSize := nil. \\n\\t^true! !\\n\\n!StringSocket methodsFor: 'private-IO' stamp: 'sd 11/20/2005 21:26'!\\ntryForString\\n\\t\\\"try to grab an actual string\\\"\\n\\n\\tself inBufSize >= nextStringSize ifFalse: [^false].\\n\\n\\tstringsForNextArray \\n\\t\\tat: (stringCounter := stringCounter + 1)\\n\\t\\tput: (self inBufNext: nextStringSize) asString.\\n\\n\\tstringCounter = numStringsInNextArray ifTrue: [\\t\\\"we have finished another array!!\\\"\\n\\t\\tinObjects addLast: stringsForNextArray.\\n\\t\\tstringCounter := stringsForNextArray := numStringsInNextArray := nextStringSize := nil.\\n\\t] ifFalse: [\\t\\\"still need more strings for this array\\\"\\n\\t\\tnextStringSize := nil.\\n\\t].\\n\\n\\t^true\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nStringSocket class\\n\\tinstanceVariableNames: ''!\\n\\n!StringSocket class methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\nclearRatesSeen\\n\\\"\\nStringSocket clearRatesSeen\\n\\\"\\n\\tMaxRatesSeen := nil ! !\\n\\n!StringSocket class methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\ncompareFiles\\n\\\"\\nStringSocket compareFiles\\n\\\"\\n\\t| data1 data2 |\\n\\n\\tdata1 := (FileStream fileNamed: 'Macintosh HD:bob:nebraska test:58984048.1')\\n\\t\\t\\tcontentsOfEntireFile.\\n\\tdata2 := (FileStream fileNamed: 'BobsG3:squeak:dsqueak:DSqueak2.7 folder:58795431.3')\\n\\t\\t\\tcontentsOfEntireFile.\\n\\t1 to: (data1 size min: data2 size) do: [ :i |\\n\\t\\t(data1 at: i) = (data2 at: i) ifFalse: [self halt].\\n\\t].\\n! !\\n\\n!StringSocket class methodsFor: 'as yet unclassified' stamp: 'sd 11/20/2005 21:26'!\\nshowRatesSeen\\n\\\"\\nStringSocket showRatesSeen\\n\\\"\\n\\t| answer |\\n\\n\\tMaxRatesSeen ifNil: [^Beeper beep].\\n\\tanswer := WriteStream on: String new.\\n\\tMaxRatesSeen keys asSortedCollection do: [ :key |\\n\\t\\tanswer nextPutAll: key printString,' ',((MaxRatesSeen at: key) // 10000) printString; cr\\n\\t].\\n\\tStringHolder new contents: answer contents; openLabel: 'send rates at 10 second intervals'.! !\\nTestCase subclass: #StringSocketTestCase\\n\\tinstanceVariableNames: 'socket1 socket2 end1 end2'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Nebraska-Network-ObjectSocket'!\\n\\n!StringSocketTestCase methodsFor: 'running' stamp: 'sd 11/20/2005 21:26'!\\nsetUp\\n\\t\\\"it would be nice to have an in-image loopback socket, so that the tests do not need the underlying platform's sockets to behave nicely\\\"\\n\\tsocket1 := Socket newTCP.\\n\\tsocket2 := Socket newTCP.\\n\\t\\n\\tsocket1 listenOn: 9999.\\n\\tsocket2 connectTo: (NetNameResolver localHostAddress) port: 9999.\\n\\n\\tsocket1 waitForConnectionFor: 60.\\t\\n\\tsocket2 waitForConnectionFor: 60.\\n\\t\\n\\tend1 := StringSocket on: socket1.\\n\\tend2 := StringSocket on: socket2.\\n\\t! !\\n\\n!StringSocketTestCase methodsFor: 'running' stamp: 'ls 8/4/2004 15:22'!\\ntearDown\\n\\tend1 destroy.\\n\\tend2 destroy.\\n\\t! !\\n\\n!StringSocketTestCase methodsFor: 'running' stamp: 'ls 8/4/2004 15:21'!\\ntestBasics\\n\\tend1 nextPut: #().\\n\\tend1 nextPut: #('').\\n\\tend1 nextPut: #('hello' 'world').\\n\\tend1 processIO.\\n\\t\\n\\tend2 processIO.\\n\\n\\tself should: [ end2 next = #() ].\\n\\tself should: [ end2 next = #('') ].\\n\\tself should: [ end2 next = #('hello' 'world') ].\\n\\t! !\\n\\n!StringSocketTestCase methodsFor: 'running' stamp: 'sd 11/20/2005 21:26'!\\ntestBogusInput1\\n\\t| negString |\\n\\tnegString := String new: 4.\\n\\tnegString putInteger32: -10 at: 1.\\n\\tsocket1 sendData: negString.\\n\\tend2 processIO.\\n\\t\\n\\tself should: [ end2 isConnected not ].\\n\\t! !\\n\\n!StringSocketTestCase methodsFor: 'running' stamp: 'sd 11/20/2005 21:26'!\\ntestBogusInput2\\n\\t| bogoString |\\n\\tbogoString := String new: 8.\\n\\tbogoString putInteger32: 2 at: 1.\\n\\tbogoString putInteger32: -10 at: 5.\\n\\tsocket1 sendData: bogoString.\\n\\tend2 processIO.\\n\\t\\n\\tself should: [ end2 isConnected not ].\\n\\t! !\\nClassTestCase subclass: #StringTest\\n\\tinstanceVariableNames: 'string'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'CollectionsTests-Text'!\\n!StringTest commentStamp: '<historical>' prior: 0!\\nThis is the unit test for the class String. Unit tests are a good way to exercise the functionality of your system in a repeatable and automatic manner. They are therefore recommended if you plan to release anything. For more information, see: \\n\\t- http://www.c2.com/cgi/wiki?UnitTest\\n\\t- http://minnow.cc.gatech.edu/squeak/1547\\n\\t- the sunit class category!\\n\\n\\n!StringTest methodsFor: 'initialize-release' stamp: 'md 4/18/2003 10:00'!\\nsetUp\\n\\tstring := 'Hi, I am a String'! !\\n\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy01\\n\\n\\t| tokens |\\n\\tstring := 'this, is, \\\"a, test\\\"'.\\n\\ttokens := string findTokens: ',' escapedBy: '\\\"'.\\n\\tself assert: tokens size == 3! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'fbs 2/13/2006 22:20'!\\ntestFindTokensEscapedBy02\\n\\n\\t| tokens |\\n\\tstring := ''.\\n\\ttokens := string findTokens: ',' escapedBy: '\\\"'.\\n\\tself assert: tokens isEmpty! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy03\\n\\n\\t| tokens |\\n\\tstring := 'this, is, a, test'.\\n\\ttokens := string findTokens: ',' escapedBy: '\\\"'.\\n\\tself assert: tokens size == 4! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy04\\n\\n\\t| tokens |\\n\\tstring := 'this, is, a\\\",\\\" test'.\\n\\ttokens := string findTokens: ',' escapedBy: '\\\"'.\\n\\tself assert: tokens size == 3.\\n\\tself assert: tokens third = ' a, test'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'fbs 2/13/2006 22:19'!\\ntestFindTokensEscapedBy05\\n\\n\\t| tokens |\\n\\tstring := 'this, /is, a\\\",\\\" test/'.\\n\\ttokens := string findTokens: ',#' escapedBy: '\\\"/'.\\n\\tself assert: tokens size = 2.\\n\\tself assert: tokens first = 'this'.\\n\\tself assert: tokens second = ' is, a\\\",\\\" test'.! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy06\\n\\n\\t| tokens |\\n\\tstring := 'this, is, \\\"a, test'.\\n\\ttokens := string findTokens: ',' escapedBy: '\\\"'.\\n\\tself assert: tokens size == 3.\\n\\tself assert: tokens third = ' a, test'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy07\\n\\n\\t| tokens |\\n\\tstring := 'a:b::c'.\\n\\ttokens := string findTokens: ':' escapedBy: '\\\"'.\\n\\tself assert: tokens size == 4.\\n\\tself assert: tokens first = 'a'.\\n\\tself assert: tokens second = 'b'.\\n\\tself assert: tokens third = ''.\\n\\tself assert: tokens fourth = 'c'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy08\\n\\n\\t| tokens |\\n\\tstring := 'this, is, ##a, test'.\\n\\ttokens := string findTokens: ',' escapedBy: '#'.\\n\\tself assert: tokens size == 4.\\n\\tself assert: tokens third = ' a'.\\n\\tself assert: tokens fourth = ' test'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy09\\n\\n\\t| tokens |\\n\\tstring := 'this, is, ###a, test#'.\\n\\ttokens := string findTokens: ',' escapedBy: '#'.\\n\\tself assert: tokens size == 3.\\n\\tself assert: tokens third = ' #a, test'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy10\\n\\n\\t| tokens |\\n\\tstring := 'this, is, ###a, test'.\\n\\ttokens := string findTokens: ',' escapedBy: '#'.\\n\\tself assert: tokens size == 3.\\n\\tself assert: tokens third = ' #a, test'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy11\\n\\n\\t| tokens |\\n\\tstring := 'this, is, \\\"\\\"\\\"a, test\\\"'.\\n\\ttokens := string findTokens: ',' escapedBy: '\\\"'.\\n\\tself assert: tokens size == 3.\\n\\tself assert: tokens third = ' \\\"a, test'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy12\\n\\n\\t| tokens |\\n\\tstring := 'one, two# three; four. five'.\\n\\ttokens := string findTokens: ',#;.' escapedBy: '\\\"'.\\n\\tself assert: tokens size == 5.\\n\\tself assert: tokens third = ' three'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy13\\n\\n\\t| tokens |\\n\\tstring := 'one, two# three; four. five'.\\n\\ttokens := string findTokens: ',#;.' escapedBy: nil.\\n\\tself assert: tokens size == 5.\\n\\tself assert: tokens third = ' three'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy14\\n\\n\\t| tokens |\\n\\tstring := 'one, \\\"two# three\\\"; &four. five&'.\\n\\ttokens := string findTokens: ',#;.' escapedBy: '\\\"&'.\\n\\tself assert: tokens size == 3.\\n\\tself assert: tokens second = ' two# three'.\\n\\tself assert: tokens third = ' four. five'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'fbs 2/13/2006 22:19'!\\ntestFindTokensEscapedBy15\\n\\n\\t| tokens |\\n\\tstring := 'one, \\\"two# three\\\"; &four. five&'.\\n\\ttokens := string findTokens: nil escapedBy: '\\\"&'.\\n\\tself assert: tokens size = 1.\\n\\tself assert: tokens first = 'one, two# three; four. five'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'fbs 2/13/2006 22:19'!\\ntestFindTokensEscapedBy16\\n\\n\\t| tokens |\\n\\tstring := 'one, \\\"two# three\\\"; &four. five&'.\\n\\ttokens := string findTokens: nil escapedBy: nil.\\n\\tself assert: tokens size = 1.\\n\\tself assert: tokens first = string! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy21\\n\\n\\t| tokens |\\n\\tstring := 'this, is, \\\"a, test\\\"'.\\n\\ttokens := string findTokens: $, escapedBy: $\\\".\\n\\tself assert: tokens size == 3! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'fbs 2/13/2006 22:19'!\\ntestFindTokensEscapedBy22\\n\\n\\t| tokens |\\n\\tstring := ''.\\n\\ttokens := string findTokens: $, escapedBy: $\\\".\\n\\tself assert: tokens size = 0! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy23\\n\\n\\t| tokens |\\n\\tstring := 'this, is, a, test'.\\n\\ttokens := string findTokens: $, escapedBy: $\\\".\\n\\tself assert: tokens size == 4! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy24\\n\\n\\t| tokens |\\n\\tstring := 'this, is, a\\\",\\\" test'.\\n\\ttokens := string findTokens: $, escapedBy: $\\\".\\n\\tself assert: tokens size == 3.\\n\\tself assert: tokens third = ' a, test'! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'fbs 2/13/2006 22:19'!\\ntestFindTokensEscapedBy25\\n\\n\\t| tokens |\\n\\tstring := 'this, /is, a\\\",\\\" test/'.\\n\\ttokens := string findTokens: $, escapedBy: $/.\\n\\tself assert: tokens size = 2.\\n\\tself assert: tokens first = 'this'.\\n\\tself assert: tokens second = ' is, a\\\",\\\" test'.! !\\n\\n!StringTest methodsFor: 'testing - tokenizing' stamp: 'stephaneducasse 2/4/2006 20:10'!\\ntestFindTokensEscapedBy26\\n\\n\\t| tokens |\\n\\tstring := 'this, is, \\\"a, test'.\\n\\ttokens := string findTokens: $, escapedBy: $\\\".\\n\\tself assert: tokens size == 3.\\n\\tself assert: tokens third = ' a, test'! !\\n\\n\\n!StringTest methodsFor: 'tests - accessing' stamp: 'sd 6/5/2005 09:27'!\\ntestAt\\n\\n\\tself assert: (string at: 1) = $H.! !\\n\\n\\n!StringTest methodsFor: 'tests - converting' stamp: 'sd 6/5/2005 09:26'!\\ntestAsInteger\\n\\n\\tself assert: '1796exportFixes-tkMX' asInteger = 1796.\\n\\tself assert: 'donald' asInteger isNil.\\n\\tself assert: 'abc234def567' asInteger = 234.\\n\\tself assert: '-94' asInteger = -94.\\n\\tself assert: 'foo-bar-92' asInteger = -92! !\\n\\n!StringTest methodsFor: 'tests - converting' stamp: 'sd 6/5/2005 09:27'!\\ntestAsSmalltalkComment\\n\\n\\t| exampleStrings |\\n\\texampleStrings := #(\\n\\t\\t''\\n\\t\\t' '\\n\\t\\t'\\\"'\\n\\t\\t'\\\"\\\"'\\n\\t\\t'\\\"\\\"\\\"'\\n\\t\\t'abc\\\"abc'\\n\\t\\t'abc\\\"\\\"abc'\\n\\t\\t'abc\\\"hello\\\"abc'\\n\\t\\t'abc\\\"'\\n\\t\\t'\\\"abc' ).\\n\\n\\t\\\"check that the result of scanning the comment is empty\\\"\\n\\texampleStrings do: [ :s |\\n\\t\\t| tokens |\\n\\t\\ttokens := Scanner new scanTokens: s asSmalltalkComment.\\n\\t\\tself assert: (tokens isEmpty) ].\\n\\n\\t\\\"check that the result has the same non-quote characters as the original\\\"\\n\\texampleStrings do: [ :s |\\n\\t\\tself assert: ( (s copyWithout: $\\\") = (s asSmalltalkComment copyWithout: $\\\"))].\\n\\n\\t\\\"finnaly, test for some common kinds of inputs\\\"\\n\\tself assert: ( 'abc' asSmalltalkComment = '\\\"abc\\\"').\\n\\tself assert: ( 'abc\\\"abc' asSmalltalkComment = '\\\"abc\\\"\\\"abc\\\"').\\n\\tself assert: ('abc\\\"\\\"abc' asSmalltalkComment = '\\\"abc\\\"\\\"abc\\\"' ).\\n\\t\\t! !\\n\\n!StringTest methodsFor: 'tests - converting' stamp: 'sd 6/5/2005 09:27'!\\ntestCapitalized\\n\\n\\t| uc lc empty |\\t\\t\\n\\tuc := 'MElViN'.\\n\\tlc := 'mElViN'.\\n\\tempty := ' '.\\n\\tself assert: lc capitalized = uc.\\n\\tself assert: uc capitalized = uc.\\n\\t\\\"the string gets copied\\\"\\n\\tself deny: uc capitalized == uc.\\n\\tself deny: empty capitalized == empty.! !\\n\\n!StringTest methodsFor: 'tests - converting' stamp: 'ky 7/8/2006 15:28'!\\ntestUnescapePercents\\n\\tself assert: '' unescapePercents = ''.\\n\\tself assert: 'x' unescapePercents = 'x'.\\n\\n\\tself assert: '+' unescapePercents = ' '.\\n\\tself assert: 'x+' unescapePercents = 'x '.\\n\\tself assert: '+x' unescapePercents = ' x'.\\n\\tself assert: 'x+x' unescapePercents = 'x x'.\\n\\n\\tself assert: '%' unescapePercents = '%'.\\n\\tself assert: '%3' unescapePercents = '%3'.\\n\\tself assert: '%3C' unescapePercents = '<'.\\n\\t\\n\\tself assert: '%3Cx%3E4%3C%2Fx%3E' unescapePercents = '<x>4</x>'.\\n\\t\\n\\tself assert: '!!@#$%25%5E&*()%7B%7D%5B%5D=:/;?+''%22' unescapePercents = '!!@#$%^&*(){}[]=:/;? ''\\\"'.\\n\\tself assert: '!!%40%23%24%25%5E%26*()%7B%7D%5B%5D%3D%3A%2F%3B%3F%2B''%22' unescapePercents = '!!@#$%^&*(){}[]=:/;?+''\\\"'.\\n\\tself assert: '%21@%23%24%25%5E%26*%28%29%7B%7D%5B%5D%3D%3A/%3B%3F+%27%22' unescapePercents = '!!@#$%^&*(){}[]=:/;? ''\\\"'! !\\n\\n!StringTest methodsFor: 'tests - converting' stamp: 'ky 7/8/2006 18:01'!\\ntestUnescapePercentsWithTextEncoding\\n\\t| leading kataTe kataSu kataTo |\\n\\tleading := JapaneseEnvironment leadingChar.\\n\\t\\\"Katakana letter Te\\\"\\n\\tkataTe := (Character leadingChar: leading code: 12486) asString.\\n\\t\\\"Katakana letter Su\\\"\\n\\tkataSu := (Character leadingChar: leading code: 12473) asString.\\n\\t\\\"Katakana letter To\\\"\\n\\tkataTo := (Character leadingChar: leading code: 12488) asString.\\n\\tself assert: ('%83e%83X%83g' unescapePercentsWithTextEncoding: 'shift_jis')\\n\\t\\t\\t= (kataTe , kataSu , kataTo).\\n\\tself assert: ('%83e%83X%83g%20and%20%83e%83X%83g' unescapePercentsWithTextEncoding: 'shift_jis')\\n\\t\\t\\t= (kataTe , kataSu , kataTo , ' and ' , kataTe , kataSu , kataTo)! !\\n\\n!StringTest methodsFor: 'tests - converting' stamp: 'sd 6/5/2005 09:27'!\\ntestWithFirstCharacterDownshifted\\n\\n\\t| uc lc empty |\\t\\t\\n\\tuc := 'MElViN'.\\n\\tlc := 'mElViN'.\\n\\tempty := ' '.\\n\\tself assert: uc withFirstCharacterDownshifted = lc.\\n\\tself assert: lc withFirstCharacterDownshifted = lc.\\n\\t\\\"the string gets copied\\\"\\n\\tself deny: lc withFirstCharacterDownshifted == lc.\\n\\tself deny: empty withFirstCharacterDownshifted == empty.! !\\n\\n\\n!StringTest methodsFor: 'as yet unclassified' stamp: 'md 3/16/2006 22:12'!\\ntestEquality\\n\\n\\tself assert: 'abc' = 'abc' asWideString.\\n\\tself assert: 'abc' asWideString = 'abc'.\\n\\tself assert: ((ByteArray with: 97 with: 0 with: 0 with: 0) asString ~= 'a000' asWideString).\\n\\tself assert: ('a000' asWideString ~= (ByteArray with: 97 with: 0 with: 0 with: 0) asString).\\n\\n\\tself assert: ('abc' sameAs: 'aBc' asWideString).\\n\\tself assert: ('aBc' asWideString sameAs: 'abc').\\n\\tself assert: ((ByteArray with: 97 with: 0 with: 0 with: 0) asString \\n\\t\\t\\t\\t\\t\\tsameAs: 'Abcd' asWideString) not.\\n\\tself assert: ('a000' asWideString sameAs: \\n\\t\\t\\t\\t\\t(ByteArray with: 97 with: 0 with: 0 with: 0) asString) not.! !\\n\\n\\n!StringTest methodsFor: 'test-comparing' stamp: 'lr 7/7/2006 11:32'!\\ntestComparing\\n\\tself assert: 'foo' < 'foo:'.\\n\\tself assert: 'foo' < 'fooBar'.\\n\\tself assert: 'foo' <= 'foo:'.\\n\\tself assert: 'foo' <= 'fooBar'.\\n\\tself assert: 'foo:' > 'foo'.\\n\\tself assert: 'fooBar' > 'foo'.\\n\\tself assert: 'foo:' >= 'foo'.\\n\\tself assert: 'fooBar' >= 'foo'! !\\n\\n\\n!StringTest methodsFor: 'testing - converting' stamp: 'KR 06/24/2005 11:21'!\\ntestPercentEncodingJa\\n\\t| leading hiraA hiraO hiraAO encodedHiraA encodedHiraO encodedHiraAO |\\n\\n \\\"Make Japanese String from unicode. see http://www.unicode.org/charts/PDF/U3040.pdf\\\"\\n leading _ JapaneseEnvironment leadingChar.\\n\\thiraA _ (Character leadingChar: leading code: 16r3042) asString. \\\"HIRAGANA LETTER A\\\"\\n\\thiraO _ (Character leadingChar: leading code: 16r304A) asString. \\\"HIRAGANA LETTER O\\\"\\n\\thiraAO _ hiraA, hiraO.\\n\\n\\t\\\"Percent Encoded Japanese String\\\"\\n\\tencodedHiraA _ hiraA encodeForHTTP.\\n\\tself assert: encodedHiraA = '%E3%81%82'.\\n\\tencodedHiraO _ hiraO encodeForHTTP.\\n\\tself assert: encodedHiraO = '%E3%81%8A'.\\n\\tencodedHiraAO _ hiraAO encodeForHTTP.\\n\\tself assert: encodedHiraAO = '%E3%81%82%E3%81%8A'.\\n\\n \\\"without percent encoded string\\\"\\n\\tself assert: '' unescapePercents = ''.\\n\\tself assert: 'abc' unescapePercents = 'abc'.\\t\\\"latin1 character\\\"\\n\\tself assert: hiraAO unescapePercents = hiraAO. \\\"multibyte character\\\"\\n\\n\\t\\\"encoded latin1 string\\\"\\n\\tself assert: '%61' unescapePercents = 'a'.\\n\\tself assert: '%61%62%63' unescapePercents = 'abc'.\\n\\n\\t\\\"encoded multibyte string\\\"\\n\\tLocale currentPlatform: (Locale isoLanguage: 'ja') during: [ \\n\\t\\tself assert: encodedHiraA unescapePercents = hiraA.\\n\\t\\tself assert: encodedHiraAO unescapePercents = hiraAO].\\n\\n\\t\\\"mixed string\\\"\\n\\tLocale currentPlatform: (Locale isoLanguage: 'ja') during: [ \\n\\t\\tself assert: (encodedHiraAO,'a') unescapePercents = (hiraAO, 'a').\\n\\t\\tself assert: ('a', encodedHiraA) unescapePercents = ('a', hiraA).\\n\\t\\tself assert: ('a', encodedHiraA, 'b') unescapePercents = ('a', hiraA, 'b').\\n\\t\\tself assert: ('a', encodedHiraA, 'b', encodedHiraO) unescapePercents = ('a', hiraA, 'b', hiraO).\\n\\t\\tself assert: (encodedHiraA, encodedHiraO, 'b', encodedHiraA) unescapePercents = (hiraA, hiraO, 'b', hiraA)].\\n\\n\\n\\t\\\"for Seaside\\\"\\n\\tLocale currentPlatform: (Locale isoLanguage: 'ja') during: [ \\n\\t\\tself assert: (encodedHiraA, '+', encodedHiraO) unescapePercents = (hiraA, ' ', hiraO)].\\n\\n! !\\n\\n\\n!StringTest methodsFor: 'tests - indexOf' stamp: 'nice 5/9/2006 23:55'!\\ntestIndexOf\\n\\t\\n\\t\\\"test for http://bugs.impara.de/view.php?id=3574\\\"\\n\\tself assert: ('abc-' asWideString indexOfAnyOf: (CharacterSet newFrom: ' -0123456789')) = 4.\\n\\tself assert: ('ab7' asWideString indexOfAnyOf: (CharacterSet newFrom: ' -0123456789')) = 3.\\n\\tself assert: ('a2c' asWideString indexOfAnyOf: (CharacterSet newFrom: ' -0123456789')) = 2.\\n\\tself assert: ('3bc' asWideString indexOfAnyOf: (CharacterSet newFrom: ' -0123456789')) = 1.\\n\\tself assert: ('abc' asWideString indexOfAnyOf: (CharacterSet newFrom: ' -0123456789')) = 0.\\n\\t\\n\\t\\\"extension to wide characters\\\"\\n\\tself assert: ((String with: 803 asCharacter with: 811 asCharacter) indexOfAnyOf: (CharacterSet newFrom: (String with: 811 asCharacter with: 812 asCharacter))) = 2.\\n\\t\\n\\tself assert: ('abc' indexOfAnyOf: (CharacterSet newFrom: (String with: 811 asCharacter with: 812 asCharacter))) = 0.\\n\\t\\n\\tself assert: ('abc' indexOfAnyOf: (CharacterSet newFrom: (String with: 811 asCharacter with: $c))) = 3.! !\\nDataType subclass: #StringType\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Protocols-Type Vocabularies'!\\n\\n!StringType methodsFor: 'initial value' stamp: 'sw 9/27/2001 17:29'!\\ninitialValueForASlotFor: aPlayer\\n\\t\\\"Answer the value to give initially to a newly created slot of the given type in the given player\\\"\\n\\n\\t^ 'abc'! !\\n\\n\\n!StringType methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:39'!\\ninitialize\\n\\t\\\"Initialize the receiver (automatically called when instances are created via 'new')\\\"\\n\\n\\t| aMethodCategory aMethodInterface |\\n\\tsuper initialize.\\n\\tself vocabularyName: #String.\\n\\n#((accessing \\t\\t\\t'The basic info'\\n\\t\\t(at: at:put: size endsWithDigit findString: findTokens: includesSubString: indexOf: indexOf:startingAt: indexOf:startingAt:ifAbsent: lineCorrespondingToIndex: lineCount lineNumber: startsWithDigit numArgs))\\n(#'more accessing' \\t\\t'More basic info'\\n\\t\\t(allButFirst allButFirst: allButLast allButLast: at:ifAbsent: atAllPut: atPin: atRandom: atWrap: atWrap:put: fifth first first: fourth from:to:put: last last: lastIndexOf: lastIndexOf:ifAbsent: middle replaceAll:with: replaceFrom:to:with: replaceFrom:to:with:startingAt: second sixth third))\\n(comparing\\t\\t\\t\\t'Determining which comes first alphabeticly'\\n\\t\\t(< <= = > >= beginsWith: endsWith: endsWithAnyOf: howManyMatch: match:))\\n(testing \\t\\t\\t\\t'Testing'\\n\\t\\t(includes: isEmpty ifNil: ifNotNil: isAllDigits isAllSeparators isString lastSpacePosition))\\n(converting \\t\\t\\t'Converting it to another form'\\n\\t\\t(asCharacter asDate asInteger asLowercase asNumber asString asStringOrText asSymbol asText asTime asUppercase asUrl capitalized keywords numericSuffix romanNumber reversed splitInteger surroundedBySingleQuotes withBlanksTrimmed withSeparatorsCompacted withoutTrailingBlanks withoutTrailingDigits asSortedCollection))\\n(copying \\t\\t\\t\\t'Make another one like me'\\n\\t\\t(copy copyFrom:to: copyUpTo: copyUpToLast: shuffled))\\n(enumerating\\t\\t'Passing over the letters'\\n\\t\\t(collect: collectWithIndex: do: from:to:do: reverseDo: select: withIndexDo: detect: detect:ifNone:))\\n) do: [:item | \\n\\t\\t\\taMethodCategory := ElementCategory new categoryName: item first.\\n\\t\\t\\taMethodCategory documentation: item second.\\n\\t\\t\\titem third do:\\n\\t\\t\\t\\t[:aSelector | \\n\\t\\t\\t\\t\\taMethodInterface := MethodInterface new initializeFor: aSelector.\\n\\t\\t\\t\\t\\tself atKey: aSelector putMethodInterface: aMethodInterface.\\n\\t\\t\\t\\t\\taMethodCategory elementAt: aSelector put: aMethodInterface].\\n\\t\\t\\tself addCategory: aMethodCategory].\\n! !\\n\\n\\n!StringType methodsFor: '*eToys-color' stamp: 'sw 9/27/2001 17:21'!\\ntypeColor\\n\\t\\\"Answer the color for tiles to be associated with objects of this type\\\"\\n\\n\\t^ self subduedColorFromTriplet: #(0.0 0.0 1.0)\\t! !\\n\\n\\n!StringType methodsFor: '*eToys-tiles' stamp: 'yo 3/14/2005 21:27'!\\ndefaultArgumentTile\\n \\\"Answer a tile to represent the type\\\"\\n\\n ^ 'abc' translated newTileMorphRepresentative typeColor: self typeColor! !\\n\\n!StringType methodsFor: '*eToys-tiles' stamp: 'sw 9/27/2001 17:33'!\\nsetFormatForDisplayer: aDisplayer\\n\\t\\\"Set up the displayer to have the right format characteristics\\\"\\n\\n\\taDisplayer useStringFormat\\n\\t! !\\n\\n!StringType methodsFor: '*eToys-tiles' stamp: 'sw 9/27/2001 17:33'!\\nwantsArrowsOnTiles\\n\\t\\\"Answer whether this data type wants up/down arrows on tiles representing its values\\\"\\n\\n\\t^ false! !\\nMorph subclass: #SubpaneDividerMorph\\n\\tinstanceVariableNames: 'resizingEdge'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Windows'!\\n!SubpaneDividerMorph commentStamp: '<historical>' prior: 0!\\nA morph which presents a visible separator between subpanes of a SystemWindow which have zero edgeWidth. Subpanes are submorphs of a SystemWindow's paneMorphs.\\n\\nA SubpaneDividerMorph may also initiate reframe handles for the subpanes. For resizing, it is expected that the main paneMorph has a ProportionalLayout LayoutPolicy, and that the subpanes to be resized have LayoutFrames with equal topFractions and bottomFractions, but different topOffsets and bottomOffsets. It is the offsets that are changed, and the change is propagated through sibling morphs up to the first resizable morph (with different nominal frame fractions).\\n\\nThe direction of propagation is determined by the value of resizingEdge, which is one of: nil (for non-adjustible subpane divisions), #bottom or #top (which acts a though the divider is the corresponding edge of the subpane directly above or below it). Does not currently support #left or #right binding, or subpanes in a TableLayout.\\n!\\n\\n\\n!SubpaneDividerMorph methodsFor: 'accessing' stamp: 'sw 5/18/2001 11:27'!\\nborderColor\\n\\t\\\"I behave like a border for the purpose of browser beautifying, so I obey this protocol, to advantage\\\"\\n\\n\\t^ self color! !\\n\\n!SubpaneDividerMorph methodsFor: 'accessing' stamp: 'sw 5/18/2001 11:26'!\\nborderColor: aColor\\n\\t\\\"I behave like a border for the purpose of browser beautifying, so I obey this protocol, to advantage\\\"\\n\\n\\tself color: aColor! !\\n\\n!SubpaneDividerMorph methodsFor: 'accessing' stamp: 'JW 2/3/2001 09:39'!\\nresizingEdge\\n\\n\\t^resizingEdge\\n! !\\n\\n\\n!SubpaneDividerMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:53'!\\ndefaultColor\\n\\\"answer the default color/fill style for the receiver\\\"\\n\\t^ Color black! !\\n\\n!SubpaneDividerMorph methodsFor: 'initialization' stamp: 'JW 2/3/2001 09:26'!\\nfirstEnter: evt\\n\\t\\\"The first time this divider is activated, find its window and redirect further interaction there.\\\"\\n\\t| window |\\n\\n\\twindow := self firstOwnerSuchThat: [:m | m respondsTo: #secondaryPaneTransition:divider:].\\n\\twindow ifNil: [ self suspendEventHandler. ^ self ]. \\\"not working out\\\"\\n\\twindow secondaryPaneTransition: evt divider: self.\\n\\tself on: #mouseEnter send: #secondaryPaneTransition:divider: to: window.\\n! !\\n\\n!SubpaneDividerMorph methodsFor: 'initialization' stamp: 'JW 2/3/2001 09:07'!\\nhorizontal\\n\\n\\tself hResizing: #spaceFill.! !\\n\\n!SubpaneDividerMorph methodsFor: 'initialization' stamp: 'dgd 3/7/2003 14:53'!\\ninitialize\\n\\t\\\"initialize the state of the receiver\\\"\\n\\tsuper initialize.\\n\\t\\\"\\\"\\n\\tself extent: 1 @ 1! !\\n\\n!SubpaneDividerMorph methodsFor: 'initialization' stamp: 'JW 2/3/2001 09:12'!\\nresizingEdge: edgeSymbol\\n\\n\\t(#(top bottom) includes: edgeSymbol) ifFalse:\\n\\t\\t[ self error: 'resizingEdge must be #top or #bottom' ].\\n\\tresizingEdge := edgeSymbol.\\n\\tself on: #mouseEnter send: #firstEnter: to: self.\\n! !\\n\\n!SubpaneDividerMorph methodsFor: 'initialization' stamp: 'JW 2/3/2001 09:07'!\\nvertical\\n\\n\\tself vResizing: #spaceFill.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSubpaneDividerMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!SubpaneDividerMorph class methodsFor: 'instance creation' stamp: 'JW 2/3/2001 09:35'!\\nforBottomEdge\\n\\t^self new horizontal resizingEdge: #bottom! !\\n\\n!SubpaneDividerMorph class methodsFor: 'instance creation' stamp: 'JW 2/3/2001 09:35'!\\nforTopEdge\\n\\t^self new horizontal resizingEdge: #top! !\\n\\n!SubpaneDividerMorph class methodsFor: 'instance creation' stamp: 'JW 2/3/2001 09:31'!\\nhorizontal\\n\\t^self new horizontal! !\\n\\n!SubpaneDividerMorph class methodsFor: 'instance creation' stamp: 'JW 2/3/2001 09:31'!\\nvertical\\n\\t^self new vertical! !\\nObject subclass: #SunAudioFileWriter\\n\\tinstanceVariableNames: 'stream headerStart'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Sound-Synthesis'!\\n!SunAudioFileWriter commentStamp: '<historical>' prior: 0!\\nI encode monophonic sampled sounds in Sun audio (.au) file format. Sun audio files have a very simple format but can store both compressed and uncompressed sample data. I can write this format either directly into a file or onto any writable binary stream.\\n!\\n\\n\\n!SunAudioFileWriter methodsFor: 'initialization' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nsetStream: aBinaryStream\\n\\t\\\"Initialize myself for writing on the given stream.\\\"\\n\\n\\tstream := aBinaryStream.\\n\\theaderStart := aBinaryStream position.\\n! !\\n\\n\\n!SunAudioFileWriter methodsFor: 'other' stamp: 'jm 11/16/2001 18:02'!\\nappendBytes: aByteArray\\n\\t\\\"Append the given sample data to my stream.\\\"\\n\\n\\tstream nextPutAll: aByteArray.\\n! !\\n\\n!SunAudioFileWriter methodsFor: 'other' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nappendSamples: aSoundBuffer\\n\\t\\\"Append the given SoundBuffer to my stream.\\\"\\n\\n\\t| swapBytes s |\\n\\t(stream isKindOf: StandardFileStream) ifTrue: [\\n\\t\\t\\\"optimization: write sound buffer directly to file\\\"\\n\\t\\tswapBytes := SmalltalkImage current isLittleEndian.\\n\\t\\tswapBytes ifTrue: [aSoundBuffer reverseEndianness]. \\\"make big endian\\\"\\n\\t\\tstream next: (aSoundBuffer size // 2) putAll: aSoundBuffer startingAt: 1. \\\"size in words\\\"\\n\\t\\tswapBytes ifTrue: [aSoundBuffer reverseEndianness]. \\\"revert to little endian\\\"\\n\\t\\t^ self].\\n\\n\\t\\\"for non-file streams:\\\"\\n\\ts := WriteStream on: (ByteArray new: 2 * aSoundBuffer monoSampleCount).\\n\\t1 to: aSoundBuffer monoSampleCount do: [:i | s int16: (aSoundBuffer at: i)].\\n\\tself appendBytes: s contents.\\n! !\\n\\n!SunAudioFileWriter methodsFor: 'other' stamp: 'jm 11/16/2001 22:09'!\\ncloseFile\\n\\t\\\"Update the Sun audio file header to reflect the final size of the sound data. If my stream is a file stream, close it and, on a Macintosh, set the file type and creator to that used by SoundApp for Sun Audio files. (This does nothing on other platforms.)\\\"\\n\\n\\tself ensureOpen.\\n\\tself updateHeaderDataSize.\\n\\t(stream isKindOf: StandardFileStream) ifTrue: [\\n\\t\\tstream close.\\n\\t\\tFileDirectory default setMacFileNamed: stream name type: 'ULAW' creator: 'SCPL'].\\n! !\\n\\n!SunAudioFileWriter methodsFor: 'other' stamp: 'sd 1/30/2004 15:23'!\\nensureOpen\\n\\t\\\"Ensure that my stream is open.\\\"\\n\\n\\tstream closed ifTrue: [stream reopen; binary].\\n! !\\n\\n!SunAudioFileWriter methodsFor: 'other' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nupdateHeaderDataSize\\n\\t\\\"Update the Sun audio file header to reflect the final size of the sound data.\\\"\\n\\n\\t| byteCount |\\n\\tbyteCount := stream position - (headerStart + 24).\\n\\tstream position: headerStart + 8.\\n\\tstream uint32: byteCount.\\n! !\\n\\n!SunAudioFileWriter methodsFor: 'other' stamp: 'jm 11/16/2001 17:55'!\\nwriteHeaderSamplingRate: samplingRate\\n\\t\\\"Write a Sun audio file header for 16-bit linear format.\\\"\\n\\n\\tself writeHeaderSamplingRate: samplingRate format: 3.\\n! !\\n\\n!SunAudioFileWriter methodsFor: 'other' stamp: 'jm 11/16/2001 22:10'!\\nwriteHeaderSamplingRate: samplingRate format: audioFormat\\n\\t\\\"Write a Sun audio file header for the given sampling rate and format. Currently, only monophonic files are supported.\\\"\\n\\n\\tself ensureOpen.\\n\\tstream position: headerStart.\\n\\tstream nextPutAll: '.snd' asByteArray.\\n\\tstream uint32: 24.\\t\\\"header size in bytes\\\"\\n\\tstream uint32: 0.\\t\\\"sample data size in bytes; fill in later\\\"\\n\\tstream uint32: audioFormat.\\n\\tstream uint32: samplingRate truncated.\\n\\tstream uint32: 1.\\t\\\"channel count\\\"\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSunAudioFileWriter class\\n\\tinstanceVariableNames: ''!\\n\\n!SunAudioFileWriter class methodsFor: 'instance creation' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nonFileNamed: fileName\\n\\t\\\"Answer an instance of me on a newly created file with the given name.\\\"\\n\\n\\t| file |\\n\\tfile := (FileStream newFileNamed: fileName) binary.\\n\\t^ self new setStream: file\\n! !\\n\\n!SunAudioFileWriter class methodsFor: 'instance creation' stamp: 'jm 11/16/2001 17:50'!\\nonStream: aBinaryStream\\n\\t\\\"Answer an instance of me on the given binary stream.\\\"\\n\\n\\t^ self new setStream: aBinaryStream\\n! !\\n\\n\\n!SunAudioFileWriter class methodsFor: 'sound storing' stamp: 'jm 11/21/2001 15:42'!\\ncodecForFormatCode: formatCode\\n\\t\\\"Answer the codec for the given Sun audio file format number.\\\"\\n\\n\\tformatCode = 1 ifTrue: [^ MuLawCodec new].\\n\\tformatCode = 3 ifTrue: [^ nil]. \\\"uncompressed\\\"\\n\\tformatCode = 23 ifTrue: [^ ADPCMCodec newBitsPerSample: 4].\\n\\tformatCode = 25 ifTrue: [^ ADPCMCodec newBitsPerSample: 3].\\n\\tformatCode = 26 ifTrue: [^ ADPCMCodec newBitsPerSample: 5].\\n\\tformatCode = 610 ifTrue: [^ GSMCodec new].\\n\\tself error: 'unsupported Sun audio format'\\n! !\\n\\n!SunAudioFileWriter class methodsFor: 'sound storing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nformatCodeForCompressionType: aString\\n\\t\\\"Answer the Sun audio file format number for the given compression type name.\\\"\\n\\n\\t| lowercase |\\n\\tlowercase := aString asLowercase.\\n\\t'mulaw' = lowercase ifTrue: [^ 1].\\n\\t'none' = lowercase ifTrue: [^ 3].\\n\\t'adpcm3' = lowercase ifTrue: [^ 25].\\n\\t'adpcm4' = lowercase ifTrue: [^ 23].\\n\\t'adpcm5' = lowercase ifTrue: [^ 26].\\n\\t'gsm' = lowercase ifTrue: [^ 610].\\n\\tself error: 'unknown compression style'\\n! !\\n\\n!SunAudioFileWriter class methodsFor: 'sound storing' stamp: 'stephaneducasse 2/4/2006 20:41'!\\nstoreSampledSound: aSampledSound onFileNamed: fileName compressionType: aString\\n\\t\\\"Store the samples of the given sampled sound on a file with the given name using the given type of compression. See formatCodeForCompressionType: for the list of compression types.\\\"\\n\\n\\t| fmt codec f compressed |\\n\\tfmt := self formatCodeForCompressionType: aString.\\n\\tcodec := self codecForFormatCode: fmt.\\n\\tf := self onFileNamed: fileName.\\n\\tf writeHeaderSamplingRate: aSampledSound originalSamplingRate format: fmt.\\n\\tcodec\\n\\t\\tifNil: [f appendSamples: aSampledSound samples]\\n\\t\\tifNotNil: [\\n\\t\\t\\tcompressed := codec encodeSoundBuffer: aSampledSound samples.\\n\\t\\t\\tf appendBytes: compressed].\\n\\tf closeFile.\\n! !\\nFileDirectoryWrapper subclass: #SuperSwikiDirectoryWrapper\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Morphic-Explorer'!\\n!SuperSwikiDirectoryWrapper commentStamp: '<historical>' prior: 0!\\nThe super swiki does not at present have subdirectories!\\n\\n\\n!SuperSwikiDirectoryWrapper methodsFor: 'as yet unclassified' stamp: 'RAA 2/2/2001 08:28'!\\ncontents\\n\\n\\t^#()\\t\\t\\\"we have no sundirectories\\\"! !\\n\\n!SuperSwikiDirectoryWrapper methodsFor: 'as yet unclassified' stamp: 'RAA 2/2/2001 08:28'!\\nhasContents\\n\\n\\t^false\\t\\t\\\"we have no sundirectories\\\"! !\\nProjectSwikiServer subclass: #SuperSwikiServer\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-RemoteDirectory'!\\n\\n!SuperSwikiServer methodsFor: 'accessing' stamp: 'KR 2/1/2006 13:07'!\\nencodingName\\n\\t(super encodingName) ifNil: [ ^SuperSwikiServer defaultEncodingName ] ifNotNil: [^super encodingName].! !\\n\\n!SuperSwikiServer methodsFor: 'accessing' stamp: 'mir 6/25/2001 17:17'!\\ntypeForPrefs\\n\\n\\t^'bss'! !\\n\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'mir 8/23/2001 22:15'!\\nallEntries\\n\\n\\t| answer |\\n\\n\\tanswer _ self sendToSwikiProjectServer: {\\n\\t\\t'action: listallprojects'.\\n\\t}.\\n\\t(answer beginsWith: 'OK') ifFalse: [^#()].\\n\\t^self parseListEntries: answer! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'ar 3/2/2001 14:36'!\\ndirectoryNames\\n\\n\\t^self entries select:[:each| each isDirectory] thenCollect: [ :each | each name]! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'RAA 2/2/2001 08:29'!\\ndirectoryWrapperClass\\n\\n\\t^SuperSwikiDirectoryWrapper! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'mir 8/23/2001 22:16'!\\nentries\\n\\n\\t^self allEntries! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'KR 1/30/2006 21:59'!\\nfastParseEntriesFrom: aString\\n\\n\\t| c first strm xEntryName xCreationTime xModificationTime xIsDirectory xFileSize ch |\\n\\n\\tc _ OrderedCollection new.\\n\\tfirst _ true.\\n\\taString linesDo: [ :x |\\n\\t\\tfirst ifFalse: [\\n\\t\\t\\tstrm _ ReadStream on: x.\\n\\t\\t\\t(strm upTo: $ ) = '(DirectoryEntry' ifFalse: [^nil].\\n\\t\\t\\t(strm upTo: $ ) = 'name:' ifFalse: [^nil].\\n\\t\\t\\txEntryName _ WriteStream on: String new.\\n\\t\\t\\tstrm next = $' ifFalse: [^nil].\\n\\t\\t\\t[\\n\\t\\t\\t\\tch _ strm next.\\n\\t\\t\\t\\tch = $' and: [(strm peekFor: $') not]\\n\\t\\t\\t] whileFalse: [\\n\\t\\t\\t\\txEntryName nextPut: ch.\\n\\t\\t\\t].\\n\\t\\t\\txEntryName _ xEntryName contents.\\n\\t\\t\\tstrm skipSeparators.\\n\\t\\t\\t(strm upTo: $ ) = 'creationTime:' ifFalse: [^nil].\\n\\t\\t\\txCreationTime _ (strm upTo: $ ) asNumber.\\n\\t\\t\\t(strm upTo: $ ) = 'modificationTime:' ifFalse: [^nil].\\n\\t\\t\\txModificationTime _ (strm upTo: $ ) asNumber.\\n\\t\\t\\t(strm upTo: $ ) = 'isDirectory:' ifFalse: [^nil].\\n\\t\\t\\txIsDirectory _ (strm upTo: $ ) = 'true'.\\n\\t\\t\\t(strm upTo: $ ) = 'fileSize:' ifFalse: [^nil].\\n\\t\\t\\txFileSize _ (strm upTo: $ ) asNumber.\\n\\n\\t\\t\\tc add: (DirectoryEntry \\n\\t\\t\\t\\tname: (xEntryName convertFromEncoding: self encodingName)\\n\\t\\t\\t\\tcreationTime: xCreationTime \\n\\t\\t\\t\\tmodificationTime: xModificationTime \\n\\t\\t\\t\\tisDirectory: xIsDirectory \\n\\t\\t\\t\\tfileSize: xFileSize\\n\\t\\t\\t)\\n\\t\\t].\\n\\t\\tfirst _ false.\\n\\t].\\n\\t^c\\n! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'ar 3/2/2001 14:36'!\\nfileNames\\n\\n\\t^self entries select:[:each| each isDirectory not] thenCollect: [ :each | each name]! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'RAA 10/17/2000 12:49'!\\ngetOnly: numberOfBytes from: aName\\n\\n\\t| answer |\\n\\n\\tanswer _ self sendToSwikiProjectServer: {\\n\\t\\t'action: readnamedfile'.\\n\\t\\t'projectname: ',aName.\\n\\t\\t'bytestoread: ',numberOfBytes printString.\\n\\t}.\\n\\t(answer beginsWith: 'OK') ifFalse: [ ^nil].\\n\\t^answer allButFirst: 3\\n! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'md 11/14/2003 17:28'!\\nmatchingEntries: criteria\\n\\t| result |\\n\\teToyUserListUrl ifNil:[^self entries].\\n\\tresult _ self sendToSwikiProjectServer: {\\n\\t\\t'action: listmatchingprojects'.\\n\\t} , criteria.\\n\\t(result beginsWith: 'OK')\\n\\t\\tifFalse: [^self entries]. \\\"If command not supported\\\"\\n\\t^self parseListEntries: result! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'KR 1/30/2006 22:02'!\\noldFileNamed: aName\\n\\n\\t| answer |\\n\\n\\tanswer _ self sendToSwikiProjectServer: {\\n\\t\\t'action: readnamedfile'.\\n\\t\\t'projectname: ',aName convertToEncoding: self encodingName.\\n\\t}.\\n\\t(answer beginsWith: 'OK') ifFalse: [ ^nil].\\n\\t^(SwikiPseudoFileStream with: (answer allButFirst: 3))\\n\\t\\treset;\\n\\t\\tdirectory: self;\\n\\t\\tlocalName: (aName convertToEncoding: self encodingName);\\n\\t\\tyourself\\n! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'RAA 10/17/2000 14:54'!\\noldFileOrNoneNamed: fullName\\n\\n\\t| answer aName |\\n\\n\\tself flag: #bob.\\t\\t\\\"fix this up for full names\\\"\\n\\n\\taName _ fullName.\\n\\tanswer _ self sendToSwikiProjectServer: {\\n\\t\\t'action: readnamedfile'.\\n\\t\\t'projectname: ',(self localNameFor: aName).\\n\\t}.\\n\\t(answer beginsWith: 'OK') ifFalse: [^nil].\\n\\t^(SwikiPseudoFileStream with: (answer allButFirst: 3))\\n\\t\\treset;\\n\\t\\tdirectory: self;\\n\\t\\tlocalName: aName;\\n\\t\\tyourself\\n! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'KR 1/30/2006 21:57'!\\nputFile: fileStream named: fileNameOnServer\\n\\n\\t\\n\\t^(\\n\\t\\tself sendToSwikiProjectServer: {\\n\\t\\t\\t'uploadproject: ',fileNameOnServer convertToEncoding: self encodingName.\\n\\t\\t\\t'password: ',ProjectPasswordNotification signal.\\n\\t\\t\\tfileStream contentsOfEntireFile.\\n\\t\\t}\\n\\t) beginsWith: 'OK'\\n! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'RAA 10/13/2000 16:53'!\\nreadOnlyFileNamed: aName\\n\\n\\t^self oldFileNamed: aName\\n! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'RAA 2/16/2001 18:22'!\\nsendToSwikiProjectServer: anArray\\n\\n\\t| argsDict answer buildStream |\\n\\n\\tbuildStream _ WriteStream on: String new.\\n\\tanArray do: [ :each | \\n\\t\\tbuildStream \\n\\t\\t\\tnextPutAll: each size printString;\\n\\t\\t\\tspace;\\n\\t\\t\\tnextPutAll: each\\n\\t].\\n\\t(argsDict _ Dictionary new)\\n\\t\\tat: 'swikicommands'\\n\\t\\tput: {buildStream contents}.\\n\\tanswer _ HTTPSocket \\n\\t\\thttpPostToSuperSwiki: self url\\n\\t\\targs: argsDict\\n\\t\\taccept: 'application/octet-stream' \\n\\t\\trequest: ''.\\n\\t^(answer isKindOf: MIMEDocument) ifTrue: [answer content] ifFalse: [answer]\\n! !\\n\\n!SuperSwikiServer methodsFor: 'for real' stamp: 'KR 2/20/2006 12:50'!\\nupdateProjectInfoFor: aProject\\n\\n\\t| data details projectLinks linkString uploader |\\n\\n\\tdata _ OrderedCollection new.\\n\\tdata add: 'action: updatepage'.\\n\\tdata add: 'password: ',ProjectPasswordNotification signal.\\n\\tdata add: 'projectimage: ', (aProject name convertToEncoding: self encodingName) , '.gif'.\\n\\tuploader _ Utilities authorNamePerSe.\\n\\tuploader isEmptyOrNil ifTrue: [uploader _ Utilities authorInitialsPerSe].\\n\\tuploader isEmptyOrNil ifFalse: [\\n\\t\\tdata add: ('submittedBy: ',uploader convertToEncoding: self encodingName).\\n\\t].\\n\\tprojectLinks _ Set new.\\n\\taProject world allMorphsDo: [ :each |\\n\\t\\t(each isKindOf: ProjectViewMorph) ifTrue: [\\n\\t\\t\\tprojectLinks add: each safeProjectName.\\n\\t\\t].\\n\\t].\\n\\tdetails _ aProject world valueOfProperty: #ProjectDetails ifAbsent: [Dictionary new].\\n\\tdetails at: 'projectname' ifAbsentPut: [aProject name].\\n\\tprojectLinks isEmpty ifTrue: [\\n\\t\\tdetails removeKey: 'projectlinks' ifAbsent: []\\n\\t] ifFalse: [\\n\\t\\tlinkString _ String streamContents: [ :strm |\\n\\t\\t\\tprojectLinks asSortedCollection do: [ :each |\\n\\t\\t\\t\\tstrm nextPutAll: each\\n\\t\\t\\t] separatedBy: [\\n\\t\\t\\t\\tstrm nextPut: $.\\n\\t\\t\\t].\\n\\t\\t].\\n\\t\\tdetails at: 'projectlinks' put: linkString\\n\\t].\\n\\tdetails keysAndValuesDo: [ :k :v |\\n\\t\\tdata add: k , ': ' , (v convertToEncoding: self encodingName). self flag: #yoFlag.\\n\\t].\\n\\t^self sendToSwikiProjectServer: data! !\\n\\n\\n\\n!SuperSwikiServer methodsFor: 'squeaklets' stamp: 'KR 1/30/2006 22:15'!\\nupLoadProject: projectName members: archiveMembers retry: aBool\\n\\t| answer |\\n\\tarchiveMembers do:[:entry|\\n\\t\\tProgressNotification signal: '4:uploadingFile' extra:'(uploading ' translated, entry fileName convertFromSystemString , '...)' translated.\\n\\t\\tanswer _ self sendToSwikiProjectServer: {\\n\\t\\t\\t'uploadproject2: ', entry fileName convertFromSystemString convertToEncoding: self encodingName.\\n\\t\\t\\t'password: ',ProjectPasswordNotification signal.\\n\\t\\t\\tentry contents.\\n\\t\\t}.\\n\\t\\tanswer = 'OK' ifFalse:[\\n\\t\\t\\tself inform:'Server responded ' translated, answer.\\n\\t\\t\\t^false].\\n\\t].\\n\\tProgressNotification signal: '4:uploadingFile' extra:''.\\n\\t^true! !\\n\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'mir 11/14/2001 16:25'!\\nisSearchable\\n\\t^true! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'ar 8/24/2001 15:12'!\\nparseQueryResult: resultStream\\n\\n\\t| projectInfos projectName downloadUrl |\\n\\tprojectInfos _ OrderedCollection new.\\n\\tdownloadUrl _ self downloadUrl.\\n\\tresultStream reset; nextLine.\\n\\t[resultStream atEnd] whileFalse: [\\n\\t\\tprojectName _ resultStream nextLine.\\n\\t\\tprojectInfos add: projectName.\\n\\t\\t\\\"Transcript show: projectName; cr.\\\"\\n\\t\\t].\\n\\t\\\"Transcript show: 'done'; cr.\\\"\\n\\t^projectInfos\\n! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'RAA 10/17/2000 16:10'!\\nqueryAllProjects\\n\\n\\\"answer a collection of DirectoryEntry objects for each file on server\\\"\\n\\n\\\"SuperSwikiServer testOnlySuperSwiki queryAllProjects\\\"\\n\\n\\t^self sendToSwikiProjectServer: {\\n\\t\\t'action: listallprojects'.\\n\\t}! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'md 11/14/2003 17:28'!\\nqueryProjects: criteria\\n\\t| result |\\n\\t\\\"SuperSwikiServer defaultSuperSwiki queryProjects: #('submittedBy: mir' )\\\"\\n\\tresult _ self sendToSwikiProjectServer: {\\n\\t\\t'action: findproject'.\\n\\t} , criteria.\\n\\t(result beginsWith: 'OK') ifFalse: [^self inform: result printString].\\n\\t^self parseQueryResult: (ReadStream on: result).\\n! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'RAA 10/17/2000 19:23'!\\nqueryProjectsAndShow\\n\\t| result |\\n\\\"SuperSwikiServer testOnlySuperSwiki queryProjectsAndShow\\\"\\n\\n\\tresult _ self sendToSwikiProjectServer: {\\n\\t\\t'action: findproject'.\\n\\t\\t\\\"'projectname: *proj*'.\\\"\\n\\t}.\\n\\t(result beginsWith: 'OK') ifFalse: [^self inform: result printString].\\n\\tself showQueryAsPVM: (ReadStream on: result).\\n! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'RAA 10/18/2000 12:23'!\\nqueryProjectsAndShow: thingsToSearchFor\\n\\t| result |\\n\\\"SuperSwikiServer testOnlySuperSwiki queryProjectsAndShow\\\"\\n\\n\\tresult _ self sendToSwikiProjectServer: {\\n\\t\\t'action: findproject'.\\n\\t}, thingsToSearchFor.\\n\\t(result beginsWith: 'OK') ifFalse: [^self inform: result printString].\\n\\tself showQueryAsPVM: (ReadStream on: result).\\n! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'RAA 10/12/2000 17:01'!\\nqueryPythagoras\\n\\\"SuperSwikiServer testOnlySuperSwiki queryPythagoras\\\"\\n\\n\\t^self sendToSwikiProjectServer: {\\n\\t\\t'action: findproject'.\\n\\t\\t'projectsubcategory: *geometry*'.\\n\\t\\t\\\"'projectname: *pythagoras*'.\\\"\\n\\t}! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'KR 1/30/2006 21:59'!\\nshowQueryAsPVM: resultStream\\n\\t| answer gif whatToShow projectName fileName firstURL wrapper currX currY maxX maxY rawProjectName |\\n\\\"SuperSwikiServer testOnlySuperSwiki queryProjectsAndShow\\\"\\n\\n\\tresultStream reset; nextLine.\\n\\tanswer _ RectangleMorph new\\n\\t\\tuseRoundedCorners;\\n\\t\\tborderWidth: 0;\\n\\t\\tborderColor: Color blue;\\n\\t\\tcolor: Color paleBlue.\\n\\tcurrX _ currY _ maxX _ maxY _ 10.\\n\\t[resultStream atEnd] whileFalse: [\\n\\t\\trawProjectName _ resultStream nextLine.\\n\\t\\tprojectName _ rawProjectName convertFromEncoding: self encodingName.\\n\\t\\tfileName _ resultStream nextLine convertFromEncoding: self encodingName.\\n\\t\\tgif _ self oldFileOrNoneNamed: rawProjectName,'.gif'.\\n\\t\\tgif ifNotNil: [gif _ GIFReadWriter formFromStream: gif].\\n\\t\\tcurrX > 600 ifTrue: [\\n\\t\\t\\tcurrX _ 10.\\n\\t\\t\\tcurrY _ maxY + 10.\\n\\t\\t].\\n\\t\\tgif ifNil: [\\n\\t\\t\\tgif _ AlignmentMorph newColumn\\n\\t\\t\\t\\thResizing: #shrinkWrap;\\n\\t\\t\\t\\tvResizing: #shrinkWrap;\\n\\t\\t\\t\\tborderWidth: 8;\\n\\t\\t\\t\\tborderColor: Color red;\\n\\t\\t\\t\\tcolor: Color lightRed;\\n\\t\\t\\t\\taddMorph: (StringMorph contents: 'No GIF for ',projectName);\\n\\t\\t\\t\\tfullBounds;\\n\\t\\t\\t\\timageForm\\n\\t\\t].\\n\\t\\tfirstURL _ self url.\\n\\t\\tfirstURL last == $/ ifFalse: [firstURL _ firstURL, '/'].\\n\\n\\t\\twhatToShow _ ProjectViewMorph new\\n\\t\\t\\timage: (gif asFormOfDepth: Display depth);\\n\\t\\t\\tlastProjectThumbnail: gif;\\n\\t\\t\\tsetProperty: #SafeProjectName toValue: projectName;\\n\\t\\t\\tproject: (DiskProxy \\n\\t\\t\\t\\tglobal: #Project \\n\\t\\t\\t\\tselector: #namedUrl: \\n\\t\\t\\t\\targs: {firstURL,fileName}\\n\\t\\t\\t).\\n\\n\\t\\tanswer addMorphBack: (whatToShow position: currX @ currY).\\n\\t\\tcurrX _ currX + whatToShow width + 10.\\n\\t\\tmaxX _ maxX max: currX.\\n\\t\\tmaxY _ maxY max: currY + whatToShow height.\\n\\t].\\n\\tmaxX = 10 ifTrue: [\\n\\t\\t^self inform: 'No projects found for your criteria'\\n\\t].\\n\\tanswer extent: (maxX @ maxY) + (0@10).\\n\\twrapper _ ScrollPane new extent: (answer width + 10) @ (answer height min: 400).\\n\\twrapper color: Color white.\\n\\twrapper scroller addMorph: answer.\\n\\twrapper \\n\\t\\tbecomeModal;\\n\\t\\topenCenteredInWorld;\\n\\t\\tuseRoundedCorners;\\n\\t\\tsetScrollDeltas.! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'RAA 10/25/2000 12:14'!\\nspeedTest1\\n\\n\\\"SuperSwikiServer testOnlySuperSwiki speedTest1\\\"\\n\\n\\t| answer t totalTime |\\n\\n\\ttotalTime _ [\\n\\t\\tanswer _ (1 to: 10) collect: [ :x |\\n\\t\\t\\tt _ [answer _ self sendToSwikiProjectServer: {\\n\\t\\t\\t\\t'action: readnamedfile'.\\n\\t\\t\\t\\t'projectname: xyz.002.pr'.\\n\\t\\t\\t}] timeToRun.\\n\\t\\t\\t{t. answer size}\\n\\t\\t].\\n\\t] timeToRun.\\n\\t^{totalTime. answer}\\n! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'ar 7/8/2001 17:06'!\\nspeedTest2\\n\\n\\\"SuperSwikiServer testOnlySuperSwiki speedTest2\\\"\\n\\n\\\"==observed results\\n10 forks of 10 reads of 88K in 12.7 seconds\\n100 * 88110 / 12.7 ===> 693779 bytes per second\\n---\\n10 forks of 10 reads of 88K in 10.7 seconds\\n100 * 88110 / 10.7 ===> 823457 bytes per second\\n---at priority 5\\n10 forks of 10 reads of 88K in 9.8 seconds\\n100 * 88110 / 9.8 ===> 899081 bytes per second\\n===\\\"\\n\\n\\t| answer bigAnswer tRealBegin tRealEnd |\\n\\n\\tbigAnswer _ SharedQueue new.\\n\\ttRealBegin _ tRealEnd _ Time millisecondClockValue.\\n\\t10 timesRepeat: [\\n\\t\\t[\\n\\t\\t\\tanswer _ SuperSwikiServer testOnlySuperSwiki speedTest1.\\n\\t\\t\\ttRealEnd _ Time millisecondClockValue.\\n\\t\\t\\tbigAnswer nextPut: {\\n\\t\\t\\t\\t{tRealBegin. tRealEnd. tRealEnd - tRealBegin}.\\n\\t\\t\\t\\tanswer\\n\\t\\t\\t}.\\n\\t\\t] forkAt: Processor userInterruptPriority.\\n\\t].\\n\\tbigAnswer inspect.\\n! !\\n\\n!SuperSwikiServer methodsFor: 'testing' stamp: 'RAA 10/7/2000 16:12'!\\ntest1\\n\\n\\t| localDirectory localFileName local resp |\\n\\n\\tlocalDirectory _ FileDirectory default.\\n\\tlocalFileName _ 'superTest1.07Oct1611.cs'.\\n\\tlocal _ localDirectory oldFileNamed: localFileName.\\n\\tresp _ self putFile: local named: localFileName retry: false.\\n\\tlocal close.\\n\\t^resp\\n! !\\n\\n\\n!SuperSwikiServer methodsFor: 'private' stamp: 'mir 8/23/2001 22:04'!\\nparseListEntries: listResult\\n\\n\\t| c first |\\n\\tc _ self fastParseEntriesFrom: listResult.\\n\\tc ifNotNil: [^c].\\n\\tc _ OrderedCollection new.\\n\\tfirst _ true.\\n\\tlistResult linesDo: [ :x |\\n\\t\\tfirst ifFalse: [c add: (Compiler evaluate: x)].\\n\\t\\tfirst _ false.\\n\\t].\\n\\t^c\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSuperSwikiServer class\\n\\tinstanceVariableNames: ''!\\n\\n!SuperSwikiServer class methodsFor: 'as yet unclassified' stamp: 'RAA 10/7/2000 17:47'!\\ncurrentSuperSwiki\\n\\n\\t\\\"make this return nil to disable SuperSwiki hack\\\"\\n\\n\\t^self defaultSuperSwiki\\n\\n! !\\n\\n!SuperSwikiServer class methodsFor: 'as yet unclassified' stamp: 'KR 2/1/2006 13:18'!\\ndefaultEncodingName\\n\\tLocale current isoLanguage = 'ja' ifTrue: [^'shift_jis' copy] ifFalse: [^'latin1' copy].\\n! !\\n\\n!SuperSwikiServer class methodsFor: 'as yet unclassified' stamp: 'RAA 10/17/2000 19:11'!\\ndefaultSuperSwiki\\n\\n\\t^SuperSwikiServer new \\n\\t\\ttype: #http;\\n\\t\\tserver: self defaultSuperSwikiIPAddress;\\n\\t\\tdirectory: '/super/SuperSwikiProj'\\n\\t\\n! !\\n\\n!SuperSwikiServer class methodsFor: 'as yet unclassified' stamp: 'RAA 10/19/2000 11:05'!\\ndefaultSuperSwikiIPAddress\\n\\n\\t^'209.143.91.36'\\n! !\\n\\n!SuperSwikiServer class methodsFor: 'as yet unclassified' stamp: 'RAA 10/17/2000 19:11'!\\ntestOnlySuperSwiki\\n\\n\\t^SuperSwikiServer new \\n\\t\\ttype: #http;\\n\\t\\tserver: self defaultSuperSwikiIPAddress;\\n\\t\\tdirectory: '/super/SuperSwikiProj'\\n\\t\\n! !\\nRWBinaryOrTextStream subclass: #SwikiPseudoFileStream\\n\\tinstanceVariableNames: 'directoryUrl localName directory'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Network-RemoteDirectory'!\\n\\n!SwikiPseudoFileStream methodsFor: 'as yet unclassified' stamp: 'RAA 10/17/2000 14:53'!\\ndirectory\\n\\n\\t^directory url! !\\n\\n!SwikiPseudoFileStream methodsFor: 'as yet unclassified' stamp: 'RAA 10/17/2000 14:53'!\\ndirectory: x\\n\\n\\tdirectory _ x! !\\n\\n!SwikiPseudoFileStream methodsFor: 'as yet unclassified' stamp: 'RAA 10/17/2000 15:00'!\\ndirectoryObject\\n\\n\\t^directory! !\\n\\n!SwikiPseudoFileStream methodsFor: 'as yet unclassified' stamp: 'RAA 10/17/2000 15:00'!\\ndirectoryUrl\\n\\n\\t^directory url! !\\n\\n!SwikiPseudoFileStream methodsFor: 'as yet unclassified' stamp: 'RAA 10/13/2000 11:50'!\\ndirectoryUrl: x\\n\\n\\tdirectoryUrl _ x! !\\n\\n!SwikiPseudoFileStream methodsFor: 'as yet unclassified' stamp: 'RAA 10/17/2000 13:59'!\\nfileName\\n\\n\\t^localName! !\\n\\n!SwikiPseudoFileStream methodsFor: 'as yet unclassified' stamp: 'RAA 10/17/2000 14:01'!\\nisTypeHTTP\\n\\n\\t^true! !\\n\\n!SwikiPseudoFileStream methodsFor: 'as yet unclassified' stamp: 'RAA 10/13/2000 11:50'!\\nlocalName\\n\\n\\t^localName! !\\n\\n!SwikiPseudoFileStream methodsFor: 'as yet unclassified' stamp: 'RAA 10/13/2000 11:50'!\\nlocalName: x\\n\\n\\tlocalName _ x! !\\nModel subclass: #Switch\\n\\tinstanceVariableNames: 'on onAction offAction'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'ST80-Menus'!\\n!Switch commentStamp: '<historical>' prior: 0!\\nI represent a selection setting and actions to take depending on a change in the setting. An instance has three attributes: state, which is either on or off; on action; and off action. The on and off actions are blocks of code that execute whenever the instance changes state. I am typically used as a menu item in conjunction with a SwitchView and a SwitchController.\\n1/24/96 sw: made this a subclass of Model, for faster dependents handling!\\n\\n\\n!Switch methodsFor: 'action'!\\ndoAction: anAction \\n\\t\\\"Execute anAction if it is non-nil.\\\"\\n\\n\\tanAction == nil ifFalse: [anAction value]! !\\n\\n!Switch methodsFor: 'action'!\\noffAction: anAction \\n\\t\\\"Set the off action of the receiver to anAction.\\\"\\n\\n\\toffAction _ anAction fixTemps! !\\n\\n!Switch methodsFor: 'action'!\\nonAction: anAction \\n\\t\\\"Set the on action of the receiver to anAction.\\\"\\n\\n\\tonAction _ anAction fixTemps! !\\n\\n\\n!Switch methodsFor: 'converting' stamp: 'md 9/18/2004 19:51'!\\nprintOn: aStream\\n\\tself isOn\\n\\t\\tifTrue: [aStream nextPutAll: 'ON-Switch']\\n\\t\\tifFalse: [aStream nextPutAll: 'OFF-Switch']! !\\n\\n\\n!Switch methodsFor: 'state'!\\nclear\\n\\t\\\"Set the state of the receiver to 'off'. If the state of the receiver was \\n\\tpreviously 'on', then 'self change' is sent. The receiver's off action is \\n\\tNOT executed.\\\"\\n\\n\\tself isOn\\n\\t\\tifTrue: \\n\\t\\t\\t[on _ false.\\n\\t\\t\\tself changed]! !\\n\\n!Switch methodsFor: 'state'!\\nisOff\\n\\t\\\"Answer whether the receiver is set off or not.\\\"\\n\\n\\t^on not! !\\n\\n!Switch methodsFor: 'state'!\\nisOn\\n\\t\\\"Answer whether the receiver is set on or not.\\\"\\n\\n\\t^on! !\\n\\n!Switch methodsFor: 'state'!\\nset\\n\\t\\\"Set the state of the receiver to 'on'. If the state of the receiver was \\n\\tpreviously 'off', then 'self change' is sent. The receiver's on action is \\n\\tNOT executed.\\\"\\n\\n\\tself isOff\\n\\t\\tifTrue: \\n\\t\\t\\t[on _ true.\\n\\t\\t\\tself changed]! !\\n\\n!Switch methodsFor: 'state'!\\nswitch\\n\\t\\\"Change the state of the receiver from 'on' to 'off' or from 'off' to 'on' (see \\n\\tSwitch|turnOn, Switch|turnOff).\\\"\\n\\n\\tself isOn\\n\\t\\tifTrue: [self turnOff]\\n\\t\\tifFalse: [self turnOn]! !\\n\\n!Switch methodsFor: 'state'!\\nturnOff\\n\\t\\\"Set the state of the receiver to 'off'. If the state of the receiver was \\n\\tpreviously 'on', then 'self change' is sent and the receiver's off action is \\n\\texecuted.\\\"\\n\\n\\tself isOn\\n\\t\\tifTrue: \\n\\t\\t\\t[on _ false.\\n\\t\\t\\tself changed.\\n\\t\\t\\tself doAction: offAction]! !\\n\\n!Switch methodsFor: 'state'!\\nturnOn\\n\\t\\\"Set the state of the receiver to 'on'. If the state of the receiver was \\n\\tpreviously 'off', then 'self change' is sent and the receiver's on action is \\n\\texecuted.\\\"\\n\\n\\tself isOff\\n\\t\\tifTrue: \\n\\t\\t\\t[on _ true.\\n\\t\\t\\tself changed.\\n\\t\\t\\tself doAction: onAction]! !\\n\\n\\n!Switch methodsFor: 'private'!\\ninitializeOff\\n\\n\\ton _ false. \\n\\tonAction _ nil.\\n\\toffAction _ nil! !\\n\\n!Switch methodsFor: 'private'!\\ninitializeOn\\n\\n\\ton _ true. \\n\\tonAction _ nil.\\n\\toffAction _ nil! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSwitch class\\n\\tinstanceVariableNames: ''!\\n\\n!Switch class methodsFor: 'instance creation'!\\nnew\\n\\t\\\"Answer an instance of me such that the on and off actions are set to nil\\n\\t('no action'), and the state is set to 'off'.\\\"\\n\\n\\t^self newOff! !\\n\\n!Switch class methodsFor: 'instance creation'!\\nnewOff\\n\\t\\\"Answer an instance of me such that the on and off actions are set to nil \\n\\t('no action'), and the state is set to 'off'.\\\"\\n\\n\\t^super new initializeOff! !\\n\\n!Switch class methodsFor: 'instance creation'!\\nnewOn\\n\\t\\\"Answer an instance of me such that the on and off actions are set to nil \\n\\t('no action'), and the state is set to 'on'.\\\"\\n\\n\\t^super new initializeOn! !\\nObject subclass: #Syllable\\n\\tinstanceVariableNames: 'phonemes accent events'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Speech-TTS'!\\n!Syllable commentStamp: '<historical>' prior: 0!\\nMy instances are syllables. They can carry a pitch accent: 'H*', 'L*', etc.!\\n\\n\\n!Syllable methodsFor: 'accessing' stamp: 'len 12/11/1999 13:03'!\\naccent\\n\\t^ accent! !\\n\\n!Syllable methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\naccent: aString\\n\\taccent := aString! !\\n\\n!Syllable methodsFor: 'accessing' stamp: 'len 12/8/1999 17:47'!\\naccept: anObject\\n\\tanObject syllable: self! !\\n\\n!Syllable methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nevents\\n\\t^ events ifNil: [events := CompositeEvent new addAll: (self phonemes collect: [ :each | PhoneticEvent new phoneme: each; duration: 0.080]); yourself]! !\\n\\n!Syllable methodsFor: 'accessing' stamp: 'len 12/8/1999 02:55'!\\nphonemes\\n\\t^ phonemes! !\\n\\n!Syllable methodsFor: 'accessing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nphonemes: aCollection\\n\\tphonemes := aCollection! !\\n\\n!Syllable methodsFor: 'accessing' stamp: 'len 12/8/1999 02:54'!\\nstress\\n\\tself phonemes do: [ :each | each stress > 0 ifTrue: [^ each stress]].\\n\\t^ 0! !\\n\\n\\n!Syllable methodsFor: 'enumarating' stamp: 'len 12/13/1999 01:20'!\\neventsDo: aBlock\\n\\tself events do: aBlock! !\\n\\n\\n!Syllable methodsFor: 'printing' stamp: 'stephaneducasse 2/3/2006 22:23'!\\nprintOn: aStream\\n\\t| first |\\n\\taStream nextPut: $[.\\n\\tfirst := true.\\n\\tself phonemes do: [ :each |\\n\\t\\tfirst ifFalse: [aStream space].\\n\\t\\taStream print: each.\\n\\t\\tfirst := false].\\n\\taStream nextPut: $]! !\\n\\n\\n!Syllable methodsFor: 'testing' stamp: 'len 12/8/1999 19:03'!\\nhasPrimaryStress\\n\\t^ self stress = 1! !\\n\\n!Syllable methodsFor: 'testing' stamp: 'len 12/8/1999 19:03'!\\nhasSecondaryStress\\n\\t^ self stress = 2! !\\n\\n!Syllable methodsFor: 'testing' stamp: 'len 12/11/1999 13:11'!\\nisAccented\\n\\t^ self accent notNil! !\\nString subclass: #Symbol\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: 'NewSymbols OneCharacterSymbols SymbolTable'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Collections-Strings'!\\n!Symbol commentStamp: '<historical>' prior: 0!\\nI represent Strings that are created uniquely. Thus, someString asSymbol == someString asSymbol.!\\n\\n\\n!Symbol methodsFor: 'accessing'!\\nat: anInteger put: anObject \\n\\t\\\"You cannot modify the receiver.\\\"\\n\\n\\tself errorNoModification! !\\n\\n!Symbol methodsFor: 'accessing' stamp: 'sma 2/5/2000 12:32'!\\nprecedence\\n\\t\\\"Answer the receiver's precedence, assuming it is a valid Smalltalk\\n\\tmessage selector or 0 otherwise. The numbers are 1 for unary,\\n\\t2 for binary and 3 for keyword selectors.\\\"\\n\\n\\tself size = 0 ifTrue: [^ 0].\\n\\tself first isLetter ifFalse: [^ 2].\\n\\tself last = $: ifTrue: [^ 3].\\n\\t^ 1! !\\n\\n!Symbol methodsFor: 'accessing'!\\nreplaceFrom: start to: stop with: replacement startingAt: repStart\\n\\n\\tself errorNoModification! !\\n\\n\\n!Symbol methodsFor: 'comparing' stamp: 'ar 4/10/2005 23:45'!\\n= aSymbol\\n\\t\\\"Compare the receiver and aSymbol.\\\" \\n\\tself == aSymbol ifTrue: [^ true].\\n\\tself class == aSymbol class ifTrue: [^ false].\\n\\t\\\"Use String comparison otherwise\\\"\\n\\t^ super = aSymbol! !\\n\\n\\n!Symbol methodsFor: 'converting' stamp: 'st 11/22/2004 17:26'!\\nasMutator\\n\\t\\\"Return a setter message from a getter message. For example,\\n\\t#name asMutator returns #name:\\\"\\n\\t^ (self copyWith: $:) asSymbol! !\\n\\n!Symbol methodsFor: 'converting' stamp: 'ar 4/10/2005 22:42'!\\nasString \\n\\t\\\"Refer to the comment in String|asString.\\\"\\n\\t| newString |\\n\\tnewString _ self species new: self size.\\n\\tnewString replaceFrom: 1 to: newString size with: self startingAt: 1.\\n\\t^newString! !\\n\\n!Symbol methodsFor: 'converting'!\\nasSymbol \\n\\t\\\"Refer to the comment in String|asSymbol.\\\"! !\\n\\n!Symbol methodsFor: 'converting' stamp: 'sw 1/28/98 18:18'!\\ncapitalized\\n\\t^ self asString capitalized asSymbol! !\\n\\n!Symbol methodsFor: 'converting' stamp: 'md 8/10/2004 10:54'!\\nwithFirstCharacterDownshifted\\n\\t\\\"Answer an object like the receiver but with first character downshifted if necesary\\\"\\n\\n\\t^self asString withFirstCharacterDownshifted asSymbol.! !\\n\\n\\n!Symbol methodsFor: 'copying' stamp: 'tk 6/26/1998 11:35'!\\nclone\\n\\t\\\"Answer with the receiver, because Symbols are unique.\\\"! !\\n\\n!Symbol methodsFor: 'copying'!\\ncopy\\n\\t\\\"Answer with the receiver, because Symbols are unique.\\\"! !\\n\\n!Symbol methodsFor: 'copying'!\\nshallowCopy\\n\\t\\\"Answer with the receiver, because Symbols are unique.\\\"! !\\n\\n!Symbol methodsFor: 'copying' stamp: 'tk 8/19/1998 16:05'!\\nveryDeepCopyWith: deepCopier\\n\\t\\\"Return self. I am immutable in the Morphic world. Do not record me.\\\"! !\\n\\n\\n!Symbol methodsFor: 'filter streaming' stamp: 'mpw 1/1/1901 00:20'!\\nbyteEncode:aStream\\n\\t^aStream writeSymbol:self.\\n! !\\n\\n\\n!Symbol methodsFor: 'printing' stamp: 'sw 8/19/1999 11:30'!\\nisOrientedFill\\n\\t\\\"Needs to be implemented here because symbols can occupy 'color' slots of morphs.\\\"\\n\\n\\t^ false! !\\n\\n!Symbol methodsFor: 'printing' stamp: 'di 4/25/2000 12:32'!\\nstoreOn: aStream \\n\\n\\taStream nextPut: $#.\\n\\t(Scanner isLiteralSymbol: self)\\n\\t\\tifTrue: [aStream nextPutAll: self]\\n\\t\\tifFalse: [super storeOn: aStream]! !\\n\\n\\n!Symbol methodsFor: 'system primitives' stamp: 'di 1/2/1999 17:00'!\\nflushCache\\n\\t\\\"Tell the interpreter to remove all entries with this symbol as a selector from its method lookup cache, if it has one. This primitive must be called whenever a method is defined or removed.\\n\\tNOTE: Only one of the two selective flush methods needs to be used.\\n\\tSqueak 2.3 and later uses 116 (See CompiledMethod flushCache).\\\"\\n\\n\\t<primitive: 119>\\n! !\\n\\n!Symbol methodsFor: 'system primitives' stamp: 'md 2/16/2006 17:17'!\\nnumArgs: n\\n\\t\\\"Answer a string that can be used as a selector with n arguments.\\n\\t TODO: need to be extended to support shrinking and for selectors like #+ \\\" \\n\\n\\t| selector numArgs aStream offs |\\n\\t\\n\\tselector := self.\\n\\t(numArgs := selector numArgs) >= n ifTrue: [^self].\\t\\n\\taStream := WriteStream on: (String new: 16).\\n\\taStream nextPutAll: self.\\n\\t\\n\\t(numArgs = 0) ifTrue: [aStream nextPutAll: ':'. offs := 0] ifFalse: [offs := 1].\\n\\t2 to: n - numArgs + offs do: [:i | aStream nextPutAll: 'with:'].\\t\\n\\t^aStream contents asSymbol\\n\\t\\n! !\\n\\n\\n!Symbol methodsFor: 'testing' stamp: 'md 1/20/2006 16:16'!\\nincludesKey: sym\\n\\t^self == sym.! !\\n\\n!Symbol methodsFor: 'testing' stamp: 'md 8/27/2005 16:33'!\\nisDoIt\\n\\n\\t^ (self == #DoIt) or: [self == #DoItIn:].! !\\n\\n!Symbol methodsFor: 'testing' stamp: 'sma 2/5/2000 12:32'!\\nisInfix\\n\\t\\\"Answer whether the receiver is an infix message selector.\\\"\\n\\n\\t^ self precedence == 2! !\\n\\n!Symbol methodsFor: 'testing' stamp: 'sma 2/5/2000 12:34'!\\nisKeyword\\n\\t\\\"Answer whether the receiver is a message keyword.\\\"\\n\\n\\t^ self precedence == 3! !\\n\\n!Symbol methodsFor: 'testing' stamp: 'di 4/25/2000 12:32'!\\nisLiteral\\n\\t\\\"Answer whether the receiver is a valid Smalltalk literal.\\\"\\n\\n\\t^ true! !\\n\\n!Symbol methodsFor: 'testing' stamp: 'sma 2/5/2000 12:13'!\\nisPvtSelector\\n\\t\\\"Answer whether the receiver is a private message selector, that is,\\n\\tbegins with 'pvt' followed by an uppercase letter, e.g. pvtStringhash.\\\"\\n\\n\\t^ (self beginsWith: 'pvt') and: [self size >= 4 and: [(self at: 4) isUppercase]]! !\\n\\n!Symbol methodsFor: 'testing' stamp: 'md 4/30/2003 15:31'!\\nisSymbol\\n\\t^ true ! !\\n\\n!Symbol methodsFor: 'testing' stamp: 'sma 2/5/2000 12:34'!\\nisUnary\\n\\t\\\"Answer whether the receiver is an unary message selector.\\\"\\n\\n\\t^ self precedence == 1! !\\n\\n\\n!Symbol methodsFor: 'user interface' stamp: 'sma 11/12/2000 11:46'!\\nasExplorerString\\n\\t^ self printString! !\\n\\n\\n!Symbol methodsFor: 'private'!\\nerrorNoModification\\n\\n\\tself error: 'symbols can not be modified.'! !\\n\\n!Symbol methodsFor: 'private'!\\nstring: aString\\n\\n\\t1 to: aString size do: [:j | super at: j put: (aString at: j)].\\n\\t^self ! !\\n\\n\\n!Symbol methodsFor: 'evaluating' stamp: 'md 3/24/2006 12:09'!\\nvalue: anObject \\n\\t^anObject perform: self.! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSymbol class\\n\\tinstanceVariableNames: ''!\\n\\n!Symbol class methodsFor: 'access' stamp: 'ar 4/10/2005 22:49'!\\nallSymbols\\n\\t\\\"Answer all interned symbols\\\"\\n\\t^Array streamContents:[:s|\\n\\t\\ts nextPutAll: NewSymbols.\\n\\t\\ts nextPutAll: OneCharacterSymbols.\\n\\t\\ts nextPutAll: SymbolTable.\\n\\t].\\n! !\\n\\n!Symbol class methodsFor: 'access' stamp: 'yo 11/3/2004 19:24'!\\nselectorsContaining: aString\\n\\t\\\"Answer a list of selectors that contain aString within them. Case-insensitive. Does return symbols that begin with a capital letter.\\\"\\n\\n\\t| size selectorList ascii |\\n\\n\\tselectorList _ OrderedCollection new.\\n\\t(size _ aString size) = 0 ifTrue: [^selectorList].\\n\\n\\taString size = 1 ifTrue:\\n\\t\\t[\\n\\t\\t\\tascii _ aString first asciiValue.\\n\\t\\t\\tascii < 128 ifTrue: [selectorList add: (OneCharacterSymbols at: ascii+1)]\\n\\t\\t].\\n\\n\\taString first isLetter ifFalse:\\n\\t\\t[\\n\\t\\t\\taString size == 2 ifTrue: \\n\\t\\t\\t\\t[Symbol hasInterned: aString ifTrue:\\n\\t\\t\\t\\t\\t[:s | selectorList add: s]].\\n\\t\\t\\t^selectorList\\n\\t\\t].\\n\\n\\tselectorList _ selectorList copyFrom: 2 to: selectorList size.\\n\\n\\tself allSymbolTablesDo: [:each |\\n\\t\\teach size >= size ifTrue:\\n\\t\\t\\t[(each findSubstring: aString in: each startingAt: 1 \\n\\t\\t\\t\\tmatchTable: CaseInsensitiveOrder) > 0\\n\\t\\t\\t\\t\\t\\tifTrue: [selectorList add: each]]].\\n\\n\\t^selectorList reject: [:each | \\\"reject non-selectors, but keep ones that begin with an uppercase\\\"\\n\\t\\teach numArgs < 0 and: [each asString withFirstCharacterDownshifted numArgs < 0]].\\n\\n\\\"Symbol selectorsContaining: 'scon'\\\"! !\\n\\n!Symbol class methodsFor: 'access' stamp: 'tween 9/13/2004 10:09'!\\nthatStartsCaseSensitive: leadingCharacters skipping: skipSym\\n\\t\\\"Same as thatStarts:skipping: but caseSensitive\\\"\\n\\t| size firstMatch key |\\n\\n\\tsize := leadingCharacters size.\\n\\tsize = 0 ifTrue: [^skipSym ifNil: [#''] ifNotNil: [nil]].\\n\\tfirstMatch := leadingCharacters at: 1.\\n\\tsize > 1 ifTrue: [key := leadingCharacters copyFrom: 2 to: size].\\n\\tself allSymbolTablesDo: [:each |\\n\\t\\t\\teach size >= size ifTrue:\\n\\t\\t\\t\\t[\\n\\t\\t\\t\\t\\t((each at: 1) == firstMatch and:\\n\\t\\t\\t\\t\\t\\t[key == nil or:\\n\\t\\t\\t\\t\\t\\t\\t[(each findString: key startingAt: 2 caseSensitive: true) = 2]])\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [^each]\\n\\t\\t\\t\\t]\\n\\t\\t] after: skipSym.\\n\\n\\t^nil\\n! !\\n\\n!Symbol class methodsFor: 'access' stamp: 'RAA 5/29/2001 14:35'!\\nthatStarts: leadingCharacters skipping: skipSym\\n\\t\\\"Answer a selector symbol that starts with leadingCharacters.\\n\\tSymbols beginning with a lower-case letter handled directly here.\\n\\tIgnore case after first char.\\n\\tIf skipSym is not nil, it is a previous answer; start searching after it.\\n\\tIf no symbols are found, answer nil.\\n\\tUsed by Alt-q (Command-q) routines\\\"\\n\\n\\t| size firstMatch key |\\n\\n\\tsize _ leadingCharacters size.\\n\\tsize = 0 ifTrue: [^skipSym ifNil: [#''] ifNotNil: [nil]].\\n\\n\\tfirstMatch _ leadingCharacters at: 1.\\n\\tsize > 1 ifTrue: [key _ leadingCharacters copyFrom: 2 to: size].\\n\\n\\tself allSymbolTablesDo: [:each |\\n\\t\\t\\teach size >= size ifTrue:\\n\\t\\t\\t\\t[\\n\\t\\t\\t\\t\\t((each at: 1) == firstMatch and:\\n\\t\\t\\t\\t\\t\\t[key == nil or:\\n\\t\\t\\t\\t\\t\\t\\t[(each findString: key startingAt: 2 caseSensitive: false) = 2]])\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [^each]\\n\\t\\t\\t\\t]\\n\\t\\t] after: skipSym.\\n\\n\\t^nil\\n\\n\\\"Symbol thatStarts: 'sf' skipping: nil\\\"\\n\\\"Symbol thatStarts: 'sf' skipping: #sfpGetFile:with:with:with:with:with:with:with:with:\\\"\\n\\\"Symbol thatStarts: 'candidate' skipping: nil\\\"\\n! !\\n\\n\\n!Symbol class methodsFor: 'class initialization' stamp: 'RAA 5/29/2001 08:21'!\\nallSymbolTablesDo: aBlock\\n\\n\\tNewSymbols do: aBlock.\\n\\tSymbolTable do: aBlock.! !\\n\\n!Symbol class methodsFor: 'class initialization' stamp: 'RAA 5/29/2001 14:35'!\\nallSymbolTablesDo: aBlock after: aSymbol\\n\\n\\tNewSymbols do: aBlock after: aSymbol.\\n\\tSymbolTable do: aBlock after: aSymbol.! !\\n\\n!Symbol class methodsFor: 'class initialization' stamp: 'RAA 12/17/2000 18:05'!\\ncompactSymbolTable\\n\\t\\\"Reduce the size of the symbol table so that it holds all existing symbols + 25% (changed from 1000 since sets like to have 25% free and the extra space would grow back in a hurry)\\\"\\n\\n\\t| oldSize |\\n\\n\\tSmalltalk garbageCollect.\\n\\toldSize _ SymbolTable array size.\\n\\tSymbolTable growTo: SymbolTable size * 4 // 3 + 100.\\n\\t^oldSize printString,' ',(oldSize - SymbolTable array size) printString, ' slot(s) reclaimed'! !\\n\\n!Symbol class methodsFor: 'class initialization' stamp: 'RAA 5/29/2001 09:04'!\\ninitialize\\n\\n\\t\\\"Symbol initialize\\\"\\n\\n\\tSymbol rehash.\\n\\tOneCharacterSymbols _ nil.\\n\\tOneCharacterSymbols _ (1 to: 256) collect: [ :i | (i - 1) asCharacter asSymbol].\\n\\tSmalltalk addToShutDownList: self.\\n! !\\n\\n\\n!Symbol class methodsFor: 'instance creation'!\\nfindInterned:aString\\n\\n\\tself hasInterned:aString ifTrue:[:symbol| ^symbol].\\n\\t^nil.! !\\n\\n!Symbol class methodsFor: 'instance creation' stamp: 'ar 4/10/2005 23:04'!\\ninternCharacter: aCharacter\\n\\taCharacter asciiValue > 256 ifTrue:[^self intern: aCharacter asString].\\n\\tOneCharacterSymbols ifNil: [^self intern: aCharacter asString].\\n\\t^OneCharacterSymbols at: aCharacter asciiValue + 1\\n! !\\n\\n!Symbol class methodsFor: 'instance creation' stamp: 'ar 4/12/2005 17:37'!\\nintern: aStringOrSymbol \\n\\n\\t^(self lookup: aStringOrSymbol) ifNil:[\\n\\t\\t| aClass aSymbol |\\n\\t\\taStringOrSymbol isSymbol ifTrue:[\\n\\t\\t\\taSymbol _ aStringOrSymbol.\\n\\t\\t] ifFalse:[\\n\\t\\t\\taClass := aStringOrSymbol isOctetString ifTrue:[ByteSymbol] ifFalse:[WideSymbol].\\n\\t\\t\\taSymbol := aClass new: aStringOrSymbol size.\\n\\t\\t\\taSymbol string: aStringOrSymbol.\\n\\t\\t].\\n\\t\\tNewSymbols add: aSymbol.\\n\\t\\taSymbol].! !\\n\\n!Symbol class methodsFor: 'instance creation' stamp: 'RAA 5/29/2001 08:09'!\\nlookup: aStringOrSymbol\\n\\n\\t^(SymbolTable like: aStringOrSymbol) ifNil: [\\n\\t\\tNewSymbols like: aStringOrSymbol\\n\\t]! !\\n\\n!Symbol class methodsFor: 'instance creation'!\\nnewFrom: aCollection \\n\\t\\\"Answer an instance of me containing the same elements as aCollection.\\\"\\n\\n\\t^ (aCollection as: String) asSymbol\\n\\n\\\"\\tSymbol newFrom: {$P. $e. $n}\\n\\t{$P. $e. $n} as: Symbol\\n\\\"! !\\n\\n!Symbol class methodsFor: 'instance creation' stamp: 'di 10/11/1999 00:02'!\\nreadFrom: strm \\\"Symbol readFromString: '#abc'\\\"\\n\\n\\tstrm peek = $# ifFalse: [self error: 'Symbols must be introduced by #'].\\n\\t^ (Scanner new scan: strm) advance \\\"Just do what the code scanner does\\\"! !\\n\\n\\n!Symbol class methodsFor: 'private' stamp: 'ar 4/10/2005 22:43'!\\nhasInterned: aString ifTrue: symBlock \\n\\t\\\"Answer with false if aString hasnt been interned (into a Symbol), \\n\\totherwise supply the symbol to symBlock and return true.\\\"\\n\\n\\t| symbol |\\n\\t^ (symbol _ self lookup: aString)\\n\\t\\tifNil: [false]\\n\\t\\tifNotNil: [symBlock value: symbol.\\n\\t\\t\\ttrue]! !\\n\\n!Symbol class methodsFor: 'private' stamp: 'RAA 5/29/2001 14:33'!\\npossibleSelectorsFor: misspelled \\n\\t\\\"Answer an ordered collection of possible corrections\\n\\tfor the misspelled selector in order of likelyhood\\\"\\n\\n\\t| numArgs candidates lookupString best binary short long first ss |\\n\\tlookupString _ misspelled asLowercase. \\\"correct uppercase selectors to lowercase\\\"\\n\\tnumArgs _ lookupString numArgs.\\n\\t(numArgs < 0 or: [lookupString size < 2]) ifTrue: [^ OrderedCollection new: 0].\\n\\tfirst _ lookupString first.\\n\\tshort _ lookupString size - (lookupString size // 4 max: 3) max: 2.\\n\\tlong _ lookupString size + (lookupString size // 4 max: 3).\\n\\n\\t\\\"First assemble candidates for detailed scoring\\\"\\n\\tcandidates _ OrderedCollection new.\\n\\tself allSymbolTablesDo: [:s | (((ss _ s size) >= short\\t\\\"not too short\\\"\\n\\t\\t\\tand: [ss <= long\\t\\t\\t\\\"not too long\\\"\\n\\t\\t\\t\\t\\tor: [(s at: 1) = first]])\\t\\\"well, any length OK if starts w/same letter\\\"\\n\\t\\t\\tand: [s numArgs = numArgs])\\t\\\"and numArgs is the same\\\"\\n\\t\\t\\tifTrue: [candidates add: s]].\\n\\n\\t\\\"Then further prune these by correctAgainst:\\\"\\n\\tbest _ lookupString correctAgainst: candidates.\\n\\t((misspelled last ~~ $:) and: [misspelled size > 1]) ifTrue: [\\n\\t\\tbinary _ misspelled, ':'.\\t\\t\\\"try for missing colon\\\"\\n\\t\\tSymbol hasInterned: binary ifTrue: [:him | best addFirst: him]].\\n\\t^ best! !\\n\\n!Symbol class methodsFor: 'private' stamp: 'ar 9/27/2005 20:01'!\\nrehash\\t\\t\\\"Symbol rehash\\\"\\n\\t\\\"Rebuild the hash table, reclaiming unreferenced Symbols.\\\"\\n\\n\\tSymbolTable := WeakSet withAll: self allSubInstances.\\n\\tNewSymbols := WeakSet new.! !\\n\\n!Symbol class methodsFor: 'private' stamp: 'RAA 5/29/2001 09:04'!\\nshutDown: aboutToQuit\\n\\n\\tSymbolTable addAll: NewSymbols.\\n\\tNewSymbols _ WeakSet new.! !\\nKeyboardInputInterpreter subclass: #SymbolInputInterpreter\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Multilingual-TextConversion'!\\n\\n!SymbolInputInterpreter methodsFor: 'as yet unclassified' stamp: 'ar 4/10/2005 16:10'!\\nnextCharFrom: sensor firstEvt: evtBuf\\n\\n\\t| keyValue |\\n\\tkeyValue := evtBuf third.\\n\\tevtBuf fifth > 1 ifTrue: [^ keyValue asCharacter macToSqueak].\\n\\t^ (self symbolKeyValueToUnicode: keyValue) asCharacter.\\n! !\\n\\n!SymbolInputInterpreter methodsFor: 'as yet unclassified' stamp: 'yo 11/8/2004 18:53'!\\nsymbolKeyValueToUnicode: keyValue\\n\\n\\tkeyValue = 127 ifTrue: [^ 127].\\n\\tkeyValue < 32 ifTrue: [^ keyValue].\\n\\tkeyValue > 255 ifTrue: [^ 0].\\n\\t^ #(0 0 0 0 0 0 0 0 0 61472 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61472 61473 61474 61475 61476 61477 61478 61479 61480 61481 61482 61483 61484 61485 61486 61487 61488 61489 61490 61491 61492 61493 61494 61495 61496 61497 61498 61499 61500 61501 61502 61503 61504 61505 61506 61507 61508 61509 61510 61511 61512 61513 61514 61515 61516 61517 61518 61519 61520 61521 61522 61523 61524 61525 61526 61527 61528 61529 61530 61531 61532 61533 61534 61535 61536 61537 61538 61539 61540 61541 61542 61543 61544 61545 61546 61547 61548 61549 61550 61551 61552 61553 61554 61555 61556 61557 61558 61559 61560 61561 61562 61563 61564 61565 61566 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61601 61602 61603 61604 61605 61606 61607 61608 61609 61610 61611 61612 61613 61614 61615 61616 61617 61618 61619 61620 61621 61622 61623 61624 61625 61626 61627 61628 61629 61630 61631 61632 61633 61634 61635 61636 61637 61638 61639 61640 61641 61642 61643 61644 61645 61646 61647 61648 61649 61650 61651 61652 61653 61654 61655 61656 61657 61658 61659 61660 61661 61662 61663 61664 61665 61666 61667 61668 61669 61670 61671 61672 61673 61674 61675 61676 61677 61678 61679 0 61681 61682 61683 61684 61685 61686 61687 61688 61689 61690 61691 61692 61693 61694 0) at: keyValue + 1.\\n! !\\nTileMorph subclass: #SymbolListTile\\n\\tinstanceVariableNames: 'choices dataType'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Scripting Tiles'!\\n!SymbolListTile commentStamp: '<historical>' prior: 0!\\nInstances of SymbolListTile are literal tiles whose literals are choosable from a finite list.!\\n\\n\\n!SymbolListTile methodsFor: 'accessing' stamp: 'yo 7/2/2004 21:27'!\\nliteral: anObject\\n\\t\\\"Set the receiver's literal as indicated\\\"\\n\\tself flag: #yo.\\n\\n\\tliteral _ anObject asSymbol.\\n\\tself updateLiteralLabel.\\n\\\"\\n\\tkey _ Vocabulary eToyVocabulary translationKeyFor: literal.\\n\\tkey isNil ifFalse: [literal _ key].\\n\\\"\\n\\tself flag: #deferred. \\\"The below formerly was necessary but now is problematical, leading to low-space condition etc. May need to revisit, since as I comment this out now I am uncertain what if anything this may break\\\"\\n\\t\\\"self labelMorph informTarget\\\"\\n\\n! !\\n\\n!SymbolListTile methodsFor: 'accessing' stamp: 'tak 12/6/2004 01:58'!\\noptions\\n\\t^ {self choices. self choices\\n\\t\\tcollect: [:each | ScriptingSystem helpStringForOperator: literal]}! !\\n\\n!SymbolListTile methodsFor: 'accessing' stamp: 'tak 12/7/2004 14:42'!\\nvalue: anObject \\n\\tself acceptNewLiteral: anObject! !\\n\\n\\n!SymbolListTile methodsFor: 'customevents-accessing' stamp: 'nk 7/21/2003 22:02'!\\ndataType\\n\\t^dataType! !\\n\\n\\n!SymbolListTile methodsFor: 'customevents-initialization' stamp: 'nk 7/21/2003 22:14'!\\nupdateChoices\\n\\tchoices _ (Vocabulary vocabularyNamed: dataType) choices.\\n\\t(choices includes: literal) ifFalse: [ literal _ choices first. self changed ]! !\\n\\n\\n!SymbolListTile methodsFor: 'event handling' stamp: 'sw 12/3/2001 21:30'!\\nhandlesMouseDown: evt\\n\\t\\\"Answer whether the receiver handles mouse-down\\\"\\n\\n\\t^ true! !\\n\\n!SymbolListTile methodsFor: 'event handling' stamp: 'sw 11/16/2001 07:31'!\\nwantsKeyboardFocusFor: aSubmorph\\n\\t\\\"Answer whether a plain mouse click on aSubmorph, a text-edit-capable thing, should result in a text selection there\\\"\\n\\n\\t^ false! !\\n\\n\\n!SymbolListTile methodsFor: 'events-processing' stamp: 'sw 12/3/2001 20:45'!\\nmouseDownPriority\\n\\t\\\"Higher-priority than parts donor, so that the tile can offer a popup even when it is in a larger structure, such as a PhraseTileMorph, that itself behaves as a parts donor\\\"\\n\\n\\t^ 75! !\\n\\n\\n!SymbolListTile methodsFor: 'initialization' stamp: 'sw 10/30/2000 09:04'!\\nchoices: choiceList dataType: aDataType\\n\\t\\\"Initialize the receiver with the given choice-list and data type\\\"\\n\\n\\tchoices _ choiceList.\\n\\tdataType _ aDataType.\\n\\tliteral _ choiceList first! !\\n\\n!SymbolListTile methodsFor: 'initialization' stamp: 'tak 12/6/2004 01:38'!\\ninitialize\\n\\tsuper initialize.\\n\\tliteral _ #nothing! !\\n\\n\\n!SymbolListTile methodsFor: 'misc' stamp: 'sw 11/6/2001 13:30'!\\nsetLiteralInitially: anObject\\n\\t\\\"Establish the initial literal. Get the label correct, but do *not* send the value back to the target via the setter (unlike #literal:)\\\"\\n\\n\\tliteral _ anObject ifNotNil: [anObject asSymbol].\\n\\tself updateLiteralLabel! !\\n\\n\\n!SymbolListTile methodsFor: 'player viewer' stamp: 'yo 1/12/2005 14:28'!\\nupdateLiteralLabel\\n\\t\\\"Update the wording emblazoned on the tile, if needed. Copied down, for jimmying, unfortunately\\\"\\n\\n\\t| myLabel |\\n\\t(myLabel _ self labelMorph) ifNil: [^ self].\\n\\tmyLabel useSymbolFormat.\\n\\tmyLabel acceptValue: literal asString.\\n\\tself changed.! !\\n\\n\\n!SymbolListTile methodsFor: 'user interface' stamp: 'yo 1/12/2005 14:38'!\\nacceptNewLiteral: aLiteral\\n\\t\\\"Accept the new literal\\\"\\n\\n\\tself labelMorph useSymbolFormat.\\n\\tself literal: aLiteral.\\n\\tself adjustHelpMessage.\\n\\tself acceptNewLiteral. \\\"so tile scriptor can recompile if necessary\\\"\\n\\tself labelMorph informTarget\\n! !\\n\\n!SymbolListTile methodsFor: 'user interface' stamp: 'sw 3/10/2004 23:24'!\\nadjustHelpMessage\\n\\t\\\"Adjust the help message to reflect the new literal\\\"\\n\\n\\t(ScriptingSystem helpStringOrNilForOperator: literal) ifNotNilDo:\\n\\t\\t[:aString |\\n\\t\\t\\tself labelMorph setBalloonText: aString]! !\\n\\n!SymbolListTile methodsFor: 'user interface' stamp: 'sw 12/21/2003 00:07'!\\nchoices\\n\\t\\\"Answer the list of current choices for the receiver's symbol\\\"\\n\\n\\tdataType == #ScriptName ifTrue: \\\"Backward compatibility with old tiles\\\"\\n\\t\\t[^ ActiveWorld presenter allKnownUnaryScriptSelectors].\\n\\t^ choices! !\\n\\n!SymbolListTile methodsFor: 'user interface' stamp: 'sw 1/4/2005 00:16'!\\nofferAllChoicesInAPopUp\\n\\t\\\"Retained in deference to pre-existing content that may have event handlers that send this message.\\\"\\n\\n\\t! !\\n\\n\\n!SymbolListTile methodsFor: 'private' stamp: 'yo 1/12/2005 14:28'!\\nline1: line1\\n\\t\\\"Emblazon the receiver with the requested label. If the receiver already has a label, make the new label be of the same class\\\"\\n\\n\\tsuper line1: line1.\\n\\tself labelMorph useSymbolFormat! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSymbolListTile class\\n\\tinstanceVariableNames: ''!\\n\\n!SymbolListTile class methodsFor: 'customevents-updating' stamp: 'nk 7/21/2003 22:16'!\\nupdateAllTilesForVocabularyNamed: aVocabularyName\\n\\t\\\"The choices in the Vocabulary named aVocabularyName may have changed.\\n\\tUpdate my subinstances if necessary to reflect the changes.\\\"\\n\\n\\t (self allSubInstances select: [ :ea | ea dataType = aVocabularyName ])\\n\\t\\tdo: [ :ea | ea updateChoices ] ! !\\nDataType subclass: #SymbolListType\\n\\tinstanceVariableNames: 'symbols'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Protocols-Type Vocabularies'!\\n!SymbolListType commentStamp: 'sw 1/6/2005 17:52' prior: 0!\\nA type whose values range across a finite set of symbols, which are held in the \\\"symbols\\\" instance variable.!\\n\\n\\n!SymbolListType methodsFor: 'initial value' stamp: 'sw 12/3/2001 19:27'!\\ninitialValueForASlotFor: aPlayer\\n\\t\\\"Answer the value to give initially to a newly created slot of the given type in the given player\\\"\\n\\n\\t^ self choices first! !\\n\\n\\n!SymbolListType methodsFor: 'tiles' stamp: 'sw 12/3/2001 19:14'!\\nchoices\\n\\t\\\"answer the list of choices to offer as variant values\\\"\\n\\n\\t^ symbols copy! !\\n\\n!SymbolListType methodsFor: 'tiles' stamp: 'sw 1/6/2005 17:24'!\\nrepresentsAType\\n\\t\\\"Answer whether this vocabulary represents an end-user-sensible data type\\\"\\n\\n\\t^ #(BorderStyle ButtonPhase TrailStyle) includes: vocabularyName! !\\n\\n!SymbolListType methodsFor: 'tiles' stamp: 'stephaneducasse 2/4/2006 20:39'!\\nsymbols: symbolList\\n\\t\\\"Set the receiver's list of symbols as indicated\\\"\\n\\n\\tsymbols := symbolList! !\\n\\n\\n!SymbolListType methodsFor: '*eToys-tiles' stamp: 'sw 1/12/2005 10:13'!\\naffordsCoercionToBoolean\\n\\t\\\"Answer true if a tile of this data type, when dropped into a pane that demands a boolean, could plausibly be expanded into a comparison (of the form frog < toad or frog = toad) to provide a boolean expression\\\"\\n\\n\\t\\\"Formerly this had been disabled (9/27/01) but from today's perspective I don't see any reason to disable it...\\\"\\n\\n\\t^ true! !\\n\\n!SymbolListType methodsFor: '*eToys-tiles' stamp: 'sw 12/3/2001 19:15'!\\ndefaultArgumentTile\\n\\t\\\"Answer a tile to represent the type\\\"\\n\\n\\t| aTile choices |\\n\\taTile _ SymbolListTile new choices: (choices _ self choices) dataType: self vocabularyName.\\n\\taTile addArrows.\\n\\taTile setLiteral: choices first.\\n\\t^ aTile! !\\n\\n!SymbolListType methodsFor: '*eToys-tiles' stamp: 'sw 12/3/2001 21:00'!\\nnewReadoutTile\\n\\t\\\"Answer a tile that can serve as a readout for data of this type\\\"\\n\\n\\t^ SymbolListTile new choices: self choices dataType: self vocabularyName\\n! !\\nClassTestCase subclass: #SymbolTest\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'CollectionsTests-Text'!\\n!SymbolTest commentStamp: '<historical>' prior: 0!\\nThis is the unit test for the class Symbol. Unit tests are a good way to exercise the functionality of your system in a repeatable and automatic manner. They are therefore recommended if you plan to release anything. For more information, see: \\n\\t- http://www.c2.com/cgi/wiki?UnitTest\\n\\t- http://minnow.cc.gatech.edu/squeak/1547\\n\\t- the sunit class category!\\n\\n\\n!SymbolTest methodsFor: 'tests' stamp: 'md 9/6/2005 20:02'!\\ntestAsMutator\\n\\n\\tself assert: #x asMutator = #x:.\\n\\tself assert: #x asMutator isSymbol! !\\n\\n!SymbolTest methodsFor: 'tests' stamp: 'sd 6/5/2005 09:29'!\\ntestCapitalized\\n\\n\\t| uc lc |\\t\\t\\n\\tuc := #MElViN.\\n\\tlc := #mElViN.\\n\\tself assert: lc capitalized = uc.\\n\\tself assert: uc capitalized = uc.\\n! !\\n\\n!SymbolTest methodsFor: 'tests' stamp: 'sd 6/5/2005 09:29'!\\ntestWithFirstCharacterDownshifted\\n\\n\\t| uc lc empty |\\t\\t\\n\\tuc := #MElViN.\\n\\tlc := #mElViN.\\n\\tempty := #' '.\\n\\tself assert: uc withFirstCharacterDownshifted = lc.\\n\\tself assert: lc withFirstCharacterDownshifted = lc.\\n\\t\\n! !\\n\\n\\n!SymbolTest methodsFor: 'as yet unclassified' stamp: 'md 2/16/2006 17:17'!\\ntestNumArgs2\\n \\\"TODO: need to be extended to support shrinking and for selectors like #+ \\\" \\n\\t\\n\\tself assert: (#test numArgs: 0) = #test.\\n\\tself assert: (#test numArgs: 1) = #test:.\\n\\tself assert: (#test numArgs: 2) = #test:with:.\\n\\tself assert: (#test numArgs: 3) = #test:with:with:.\\n\\t\\n\\n\\tself assert: (#test: numArgs: 0) = #test:.\\n\\tself assert: (#test: numArgs: 1) = #test:.\\n\\tself assert: (#test: numArgs: 2) = #test:with:.\\n\\tself assert: (#test: numArgs: 3) = #test:with:with:.\\n\\t\\n\\tself assert: (#test:with: numArgs: 0) = #test:with:.\\n\\tself assert: (#test:with: numArgs: 1) = #test:with:.\\n\\tself assert: (#test:with: numArgs: 2) = #test:with:.\\n\\tself assert: (#test:with: numArgs: 3) = #test:with:with:.\\n\\tself assert: (#test:with: numArgs: 4) = #test:with:with:with:.\\n\\t\\n\\tself assert: (#test:with:with: numArgs: 0) = #test:with:with:.\\n\\tself assert: (#test:with:with: numArgs: 1) = #test:with:with:.\\n\\tself assert: (#test:with:with: numArgs: 2) = #test:with:with:.\\n\\tself assert: (#test:with:with: numArgs: 3) = #test:with:with:.\\n\\tself assert: (#test:with:with: numArgs: 4) = #test:with:with:with:.! !\\nObject subclass: #SyntaxAttribute\\n\\tinstanceVariableNames: 'color emphasis attributeList'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Compiler-Support'!\\n!SyntaxAttribute commentStamp: '<historical>' prior: 0!\\nRepresents a color and possibly a style attribute to be applied to a syntactic element for pretty-printing. The attributeList inst var is a cache.!\\n\\n\\n!SyntaxAttribute methodsFor: 'accessing' stamp: 'sw 11/17/1999 15:04'!\\nattributeList\\n\\t\\\"Answer a list of text attributes that characterize the receiver\\\"\\n\\tattributeList ifNil:\\n\\t\\t[attributeList _ OrderedCollection new: 2.\\n\\t\\tcolor ifNotNil: [attributeList add: (TextColor color: color)].\\n\\t\\temphasis ifNotNil: [attributeList add: (TextEmphasis perform: emphasis)]].\\n\\t^ attributeList! !\\n\\n!SyntaxAttribute methodsFor: 'accessing' stamp: 'djp 11/7/1999 14:52'!\\ncolor\\n\\n\\t^ color! !\\n\\n!SyntaxAttribute methodsFor: 'accessing' stamp: 'sw 11/16/1999 16:21'!\\ncolor: aTextColor\\n\\tcolor _ aTextColor.\\n\\tattributeList _ nil! !\\n\\n!SyntaxAttribute methodsFor: 'accessing' stamp: 'djp 11/7/1999 14:52'!\\nemphasis\\n\\n\\t^ emphasis! !\\n\\n!SyntaxAttribute methodsFor: 'accessing' stamp: 'sw 11/16/1999 16:22'!\\nemphasis: aTextEmphasis\\n\\temphasis _ aTextEmphasis.\\n\\tattributeList _ nil! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSyntaxAttribute class\\n\\tinstanceVariableNames: ''!\\n\\n!SyntaxAttribute class methodsFor: 'as yet unclassified' stamp: 'sw 11/16/1999 12:01'!\\ncolor: aColor emphasis: anEmphasis\\n\\t^ self new color: aColor; emphasis: anEmphasis; yourself! !\\nStringHolder subclass: #SyntaxError\\n\\tinstanceVariableNames: 'class selector category debugger doitFlag'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tools-Debugger'!\\n!SyntaxError commentStamp: '<historical>' prior: 0!\\nI represent syntax error report for syntax errors encountered when filing in class descriptions from a non-interactive source such as an external file. As a StringHolder, the string to be viewed is the method code or expression containing the error.\\n\\nThe user may fix the error and accept the method to continue the fileIn.\\n!\\n\\n\\n!SyntaxError methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:27'!\\ncategory: aSymbol\\n\\t\\\"Record the message category of method being compiled. This is used when the user corrects the error and accepts.\\\"\\n\\n\\tcategory := aSymbol.\\n! !\\n\\n!SyntaxError methodsFor: 'initialization' stamp: 'sd 11/20/2005 21:30'!\\nsetClass: aClass code: aString debugger: aDebugger doitFlag: flag\\n\\n\\t| types printables badChar |\\n\\tclass := aClass.\\n\\tdebugger := aDebugger.\\n\\tselector := aClass parserClass new parseSelector: aString.\\n\\ttypes := Scanner classPool at: #TypeTable.\\t\\\"dictionary\\\"\\n\\tprintables := '!!@#$%&*-_=+<>{}?/\\\\,\\U00b7\\U00a3\\U00a2\\U00a7\\U00b6\\U00aa\\U00ba\\U0096\\U0097\\U0093\\U0091\\U0094\\U0092\\U0085\\U00da\\U00e6\\U00da\\U00af\\U00d7\\U00bf\\U00ab\\U00bb`~`' asSet.\\n\\tbadChar := aString detect: [:aChar | (types at: aChar asciiValue ifAbsent: [#xLetter]) == #xBinary and: [\\n\\t\\t\\t(printables includes: aChar) not]] ifNone: [nil].\\n\\tcontents := badChar \\n\\t\\tifNil: [aString]\\n\\t\\tifNotNil: ['<<<This string contains a character (ascii value ', \\n\\t\\t\\tbadChar asciiValue printString,\\n\\t\\t\\t') that is not normally used in code>>> ', aString].\\n\\tcategory ifNil: [category := aClass organization categoryOfElement: selector].\\n\\tcategory ifNil: [category := ClassOrganizer default].\\n\\tdoitFlag := flag! !\\n\\n\\n!SyntaxError methodsFor: 'menu' stamp: 'RAA 12/1/2000 14:24'!\\ndebug\\n\\t\\\"Show the stack of the process leading to this syntax editor, typically showing the stack of the compiler as called from fileIn.\\\"\\n\\n\\tdebugger openFullNoSuspendLabel: 'Stack of the Syntax Error'.\\n\\tSmalltalk isMorphic ifFalse: [Processor terminateActive].\\n! !\\n\\n!SyntaxError methodsFor: 'menu' stamp: 'jm 5/3/1998 14:22'!\\nlistMenu: aMenu\\n\\n\\t^ aMenu labels:\\n'proceed\\ndebug calling process\\nbrowse full'\\n\\tlines: #()\\n\\tselections: #(proceed debug browseMethodFull)\\n! !\\n\\n!SyntaxError methodsFor: 'menu' stamp: 'di 5/5/1998 00:06'!\\nproceed\\n\\t\\\"The user has has edited and presumably fixed the syntax error and the filein can now proceed.\\\"\\n\\n\\tdebugger proceed: self topView.\\n! !\\n\\n\\n!SyntaxError methodsFor: 'message list' stamp: 'tk 4/19/1999 08:08'!\\nlist\\n\\t\\\"Answer an array of one element made up of the class name, message category, and message selector in which the syntax error was found. This is the single item in the message list of a view/browser on the receiver.\\\"\\n\\n\\tselector ifNil: [^ Array with: (class name, ' ', category, ' ', '<none>')].\\n\\t^ Array with: (class name, ' ', category, ' ', selector)\\n! !\\n\\n!SyntaxError methodsFor: 'message list' stamp: 'jm 5/3/1998 13:48'!\\nlistIndex\\n\\t\\\"There is always exactly one element in my list and it is always selected.\\\"\\n\\n\\t^ 1\\n! !\\n\\n\\n!SyntaxError methodsFor: 'other' stamp: 'di 10/9/1998 16:36'!\\ncontents: aString notifying: aController\\n\\t\\\"Compile the code in aString and notify aController of any errors. If there are no errors, then automatically proceed.\\\"\\n\\n\\tdoitFlag\\n\\tifTrue: [Compiler new evaluate: aString in: nil to: nil\\n\\t\\t\\t\\t\\t\\tnotifying: aController ifFail: [^ false]]\\n\\tifFalse: [(class compile: aString classified: category\\n\\t\\t\\t\\t\\t\\tnotifying: aController) ifNil: [^ false]].\\n\\n\\taController hasUnacceptedEdits: false.\\n\\tself proceed! !\\n\\n!SyntaxError methodsFor: 'other' stamp: 'sd 11/20/2005 21:27'!\\nnotify: error at: location in: source\\n\\t\\\"Open a syntax error view, inserting the given error message into the given source at the given location. This message is sent to the 'requestor' when the parser or compiler finds a syntax error.\\\"\\n\\n\\t| aClass aString |\\n\\taClass := thisContext sender receiver encoder classEncoding.\\n\\taString :=\\n\\t\\tsource contents\\n\\t\\t\\tcopyReplaceFrom: location\\n\\t\\t\\tto: location - 1\\n\\t\\t\\twith: error.\\n\\tself setClass: aClass\\n\\t\\tcode: aString\\n\\t\\tdebugger: (Debugger context: thisContext)\\n\\t\\tdoitFlag: false.\\n\\tself class open: self.\\n! !\\n\\n\\n!SyntaxError methodsFor: 'text menu support' stamp: 'jm 5/3/1998 14:15'!\\nselectedClass\\n\\t\\\"Answer the class in which the syntax error occurred.\\\"\\n\\n\\t^ class\\n! !\\n\\n!SyntaxError methodsFor: 'text menu support' stamp: 'jm 5/3/1998 14:33'!\\nselectedClassOrMetaClass\\n\\t\\\"Answer the class of the method being compiled.\\\"\\n\\n\\t^ class\\n! !\\n\\n!SyntaxError methodsFor: 'text menu support' stamp: 'jm 5/3/1998 14:17'!\\nselectedMessageName\\n\\t\\\"Answer the selector of the method being compiled.\\\"\\n\\n\\t^ selector\\n! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSyntaxError class\\n\\tinstanceVariableNames: ''!\\n\\n!SyntaxError class methodsFor: 'instance creation' stamp: 'sd 11/20/2005 21:28'!\\nbuildMVCViewOn: aSyntaxError\\n\\t\\\"Answer an MVC view on the given SyntaxError.\\\"\\n\\n\\t| topView aListView aCodeView |\\n\\ttopView := StandardSystemView new\\n\\t\\tmodel: aSyntaxError;\\n\\t\\tlabel: 'Syntax Error';\\n\\t\\tminimumSize: 380@220.\\n\\n\\taListView := PluggableListView on: aSyntaxError\\n\\t\\tlist: #list\\n\\t\\tselected: #listIndex\\n\\t\\tchangeSelected: nil\\n\\t\\tmenu: #listMenu:.\\n\\taListView window: (0@0 extent: 380@20).\\n\\ttopView addSubView: aListView.\\n\\n\\taCodeView := PluggableTextView on: aSyntaxError\\n\\t\\ttext: #contents\\n\\t\\taccept: #contents:notifying:\\n\\t\\treadSelection: #contentsSelection\\n\\t\\tmenu: #codePaneMenu:shifted:.\\n\\taCodeView window: (0@0 extent: 380@200).\\n\\ttopView addSubView: aCodeView below: aListView.\\n\\n\\t^ topView\\n! !\\n\\n!SyntaxError class methodsFor: 'instance creation' stamp: 'sd 11/20/2005 21:28'!\\nbuildMorphicViewOn: aSyntaxError\\n\\t\\\"Answer an Morphic view on the given SyntaxError.\\\"\\n\\t| window |\\n\\twindow := (SystemWindow labelled: 'Syntax Error') model: aSyntaxError.\\n\\n\\twindow addMorph: (PluggableListMorph on: aSyntaxError list: #list\\n\\t\\t\\tselected: #listIndex changeSelected: nil menu: #listMenu:)\\n\\t\\tframe: (0@0 corner: 1@0.15).\\n\\n\\twindow addMorph: (PluggableTextMorph on: aSyntaxError text: #contents\\n\\t\\t\\taccept: #contents:notifying: readSelection: #contentsSelection\\n\\t\\t\\tmenu: #codePaneMenu:shifted:)\\n\\t\\tframe: (0@0.15 corner: 1@1).\\n\\n\\t^ window openInWorldExtent: 380@220! !\\n\\n!SyntaxError class methodsFor: 'instance creation' stamp: 'di 9/14/2001 07:46'!\\nerrorInClass: aClass withCode: codeString doitFlag: doit\\n\\t\\\"Open a view whose model is a syntax error. The error occurred when trying to add the given method code to the given class.\\\"\\n\\n\\tself open:\\n\\t\\t(self new setClass: aClass\\n\\t\\t\\tcode: codeString\\n\\t\\t\\tdebugger: (Debugger context: thisContext)\\n\\t\\t\\tdoitFlag: doit).\\n! !\\n\\n!SyntaxError class methodsFor: 'instance creation' stamp: 'sd 11/20/2005 21:28'!\\nopen: aSyntaxError\\n\\t\\\"Answer a standard system view whose model is an instance of me.\\\"\\n\\t| topView |\\n\\t<primitive: 19> \\\"Simulation guard\\\"\\n\\tSmalltalk isMorphic\\n\\t\\tifTrue:\\n\\t\\t\\t[self buildMorphicViewOn: aSyntaxError.\\n\\t\\t\\tProject spawnNewProcessIfThisIsUI: Processor activeProcess.\\n\\t\\t\\t^ Processor activeProcess suspend].\\n\\ttopView := self buildMVCViewOn: aSyntaxError.\\n\\ttopView controller openNoTerminateDisplayAt: Display extent // 2.\\n\\tCursor normal show.\\n\\tProcessor activeProcess suspend.\\n! !\\nNotification subclass: #SyntaxErrorNotification\\n\\tinstanceVariableNames: 'inClass code category doitFlag'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Exceptions-Extensions'!\\n\\n!SyntaxErrorNotification methodsFor: 'accessing' stamp: 'ar 9/27/2005 19:17'!\\ncategory\\n\\t^category! !\\n\\n!SyntaxErrorNotification methodsFor: 'accessing' stamp: 'ar 9/27/2005 19:11'!\\ndoitFlag\\n\\t^doitFlag! !\\n\\n!SyntaxErrorNotification methodsFor: 'accessing' stamp: 'ar 9/27/2005 19:10'!\\nerrorClass\\n\\t^inClass! !\\n\\n!SyntaxErrorNotification methodsFor: 'accessing' stamp: 'ar 9/27/2005 19:10'!\\nerrorCode\\n\\t^code! !\\n\\n!SyntaxErrorNotification methodsFor: 'accessing' stamp: 'ar 9/27/2005 19:14'!\\nmessageText\\n\\t^ super messageText\\n\\t\\tifNil: [messageText := code]! !\\n\\n!SyntaxErrorNotification methodsFor: 'accessing' stamp: 'ar 9/27/2005 19:15'!\\nsetClass: aClass category: aCategory code: codeString doitFlag: aBoolean\\n\\tinClass := aClass.\\n\\tcategory := aCategory.\\n\\tcode := codeString.\\n\\tdoitFlag := aBoolean ! !\\n\\n\\n!SyntaxErrorNotification methodsFor: 'exceptionDescription' stamp: 'ar 9/27/2005 19:13'!\\ndefaultAction\\n\\t^ToolSet debugSyntaxError: self! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSyntaxErrorNotification class\\n\\tinstanceVariableNames: ''!\\n\\n!SyntaxErrorNotification class methodsFor: 'exceptionInstantiator' stamp: 'ar 9/27/2005 19:15'!\\ninClass: aClass category: aCategory withCode: codeString doitFlag: doitFlag \\n\\t^ (self new\\n\\t\\tsetClass: aClass\\n\\t\\tcategory: aCategory \\n\\t\\tcode: codeString\\n\\t\\tdoitFlag: doitFlag) signal! !\\nAlignmentMorph subclass: #SyntaxMorph\\n\\tinstanceVariableNames: 'parseNode markerMorph'\\n\\tclassVariableNames: 'AllSpecs ContrastFactor DownRightArrow SelfTile SizeScaleFactor'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Tile Scriptors'!\\n!SyntaxMorph commentStamp: '<historical>' prior: 0!\\nA single class of morph that holds any piece of Smalltalk syntax, and allows it to be a tile. Tiles can be dragged in or out of a method. \\n\\nIn the message list pane of a Browser, choose 'tile scriptor'. Bring up a second one to steal parts from. If you use a Protocol Browser, and choose tiles, there will be two buttons that bring up menus with many tiles on them.\\n\\nClicking multiple times selects enclosing phrases of code. Dragging lets you take away a copy. Any tile may be replaced by dropping on it. Shift-click to edit the text of any tile. Change variable and message names, but do not change the part-of-speech (objects to selector).\\n\\nEach SyntaxMorph holds a ParseNode. After editing, the parseNode is only good as a part-of-speech indicator. Only the Class of a parseNode is important. It's state is not kept up to date with the tile edits (but maybe it should be). (For MessageNodes, whether the receiver slot is nil is significant.)\\n\\nThe correspondence between SyntaxMorphs and parseNodes in the real parse tree is not one-to-one. Several extra levels of SyntaxMorph were added as aligners to make the horizontal and vertical layout right. These sometimes have nil for the parseNode.\\n\\nWhen accept the method, we pass over the tree of SyntaxMorphs, gathering their printStrings and inserting punctuation. See (SyntaxMorph>>printOn:indent:). We send the result to the compiler. (We do not use the parse tree we already have.)\\n\\nTo turn on type checking: \\nPreferences enable: #eToyFriendly\\nor for testing: World project projectParameters at: #fullCheck put: true.\\n\\nColors of tiles: Each tile has a current color (inst car color) and a deselectedColor (a property). The deselectedColor may be governed by the part of speech, or not. (translateColor: is only used when a tile is created, to set deselectedColor.) From deselectedColor (set by #setDeselectedColor), the color changes to:\\n\\tlightBrown when selected (not the submorphs) in #select\\n\\ttranslucent when held in the hand (allMorphs) in #lookTranslucent\\n\\tgreen when a drop target (allMorphs) (change the owners back) #dropColor, \\n\\t\\t#trackDropZones \\ndeselectedColor is moderated by the darkness setting, #scaleColorByUserPref:. (as it is put into color in #color:)\\n\\nCode to produce an individual tile is: \\n\\t(SyntaxMorph new) attachTileForCode: '''abc''' nodeType: LiteralNode.\\nsee offerTilesMenuFor:in: for many other phrases that produce useful tiles.\\n\\nAssignmentNode: If three submorphs, is a statement, and is a noun. If one submorph, is just the left arrow. When dropped on a variable, it creates a new assignment statement. !\\n\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 8/21/2001 09:36'!\\nactualObject\\n\\t| sub |\\n\\t\\\"Who is self in these tiles? Usually a Player.\\\"\\n\\n\\n\\t(self nodeClassIs: LiteralVariableNode) ifTrue: [\\n\\t\\t(sub _ self findA: StringMorph) ifNil: [^ nil].\\n\\t\\t\\\"Need to decompile here for odd synonyms of 'self' ?\\\"\\n\\t\\t^ Compiler evaluate: sub contents for: Player logged: false].\\n\\n\\t(self nodeClassIs: VariableNode) ifTrue: [\\n\\t\\t(sub _ self findA: StringMorph) ifNil: [^ nil].\\n\\t\\t^ References at: (self cleanUpString: sub) asSymbol ifAbsent: [nil]].\\n\\n\\t(self nodeClassIs: LiteralNode) ifTrue: [\\n\\t\\t(sub _ self findA: StringMorph) ifNil: [^ nil].\\n\\t\\t^ Compiler evaluate: sub contents for: nil logged: false].\\n\\n\\t(sub _ self findA: SyntaxMorph) ifNil: [^ nil].\\n\\t^ sub actualObject\\t\\\"receiver\\\"! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 9/20/2001 13:21'!\\nargumentNodes\\n\\t\\\"Return a collection of this message's argument nodes. \\\"\\n\\n\\t| cls coll rec |\\n\\tparseNode ifNil: [^ #()].\\n\\tcls _ parseNode class.\\n\\tcls == SelectorNode ifTrue: [^ #()].\\n\\tcls == KeyWordNode ifTrue: [^ #()].\\n\\n\\tcoll _ OrderedCollection new.\\n\\trec _ self receiverNode.\\n\\tsubmorphs do: [:sub | \\n\\t\\t(sub isSyntaxMorph and: [sub ~~ rec]) ifTrue: [\\n\\t\\t\\tsub isNoun ifTrue: [coll addLast: sub]\\t\\\"complete arg\\\"\\n\\t\\t\\t\\tifFalse: [coll _ coll, sub argumentNodes]]].\\t\\\"MessagePartNode, MessageNode with no receiver\\\"\\n\\t^ coll! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'RAA 8/24/1999 17:57'!\\nballoonText\\n\\n\\t^(('Value: ',(self getCurrentValue ifNil: [^nil])) \\n\\t\\twithNoLineLongerThan: 35) truncateWithElipsisTo: 300! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'di 12/13/2000 15:25'!\\nborderColor: colorOrSymbolOrNil\\n\\n\\tborderColor = colorOrSymbolOrNil ifFalse: [\\n\\t\\tborderColor _ colorOrSymbolOrNil.\\n\\t\\tself bounds area < 40000\\n\\t\\t\\tifTrue: [self invalidRect: self bounds]\\n\\t\\t\\tifFalse: [(self bounds areasOutside: (self bounds insetBy: self borderWidth))\\n\\t\\t\\t\\t\\t\\tdo: [:r | self invalidRect: r]]].\\n! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'RAA 4/4/2001 12:36'!\\ncleanUpString: stringSubMorph\\n\\n\\t| style rawData |\\n\\t^ stringSubMorph \\n\\t\\tvalueOfProperty: #syntacticallyCorrectContents \\n\\t\\tifAbsent: [\\n\\t\\t\\tstyle _ stringSubMorph valueOfProperty: #syntacticReformatting.\\n\\t\\t\\trawData _ stringSubMorph contents.\\n\\t\\t\\t (#(unary tempVariableDeclaration blockarg2 methodHeader1 tempVariable variable) includes: style) ifTrue: [\\n\\t\\t\\t\\trawData _ self unSpaceAndUpShift: rawData appending: nil.\\n\\t\\t\\t].\\n\\t\\t\\tstyle == #keywordGetz ifTrue: [\\n\\t\\t\\t\\trawData _ self unSpaceAndUpShift: rawData appending: 'Getz:'.\\n\\t\\t\\t].\\n\\t\\t\\tstyle == #keywordSetter ifTrue: [\\n\\t\\t\\t\\trawData _ self unSpaceAndUpShift: 'set ',rawData appending: ':'.\\n\\t\\t\\t].\\n\\t\\t\\tstyle == #unaryGetter ifTrue: [\\n\\t\\t\\t\\trawData _ self unSpaceAndUpShift: 'get ',rawData appending: nil.\\n\\t\\t\\t].\\n\\t\\t\\t(#(keyword2 methodHeader2) includes: style) ifTrue: [\\n\\t\\t\\t\\trawData _ self unSpaceAndUpShift: rawData appending: ':'.\\n\\t\\t\\t].\\n\\t\\t\\trawData\\n\\t\\t]\\n! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 7/19/2001 20:04'!\\ncolor: aColorOrSymbol\\n\\n\\t| deselectedColor cc |\\n\\taColorOrSymbol isColor ifTrue: [\\n\\t\\tself valueOfProperty: #deselectedColor ifAbsent: [\\\"record my color the first time\\\"\\n\\t\\t\\tself setProperty: #deselectedColor toValue: aColorOrSymbol.\\n\\t\\t\\t^ super color: (self scaleColorByUserPref: aColorOrSymbol)].\\n\\t\\t^ super color: aColorOrSymbol].\\n\\n\\tdeselectedColor _ self valueOfProperty: #deselectedColor ifAbsent: [nil].\\n\\tdeselectedColor ifNotNil: [^ super color: (self scaleColorByUserPref: deselectedColor)].\\n\\n\\taColorOrSymbol == #comment ifTrue: [^ self color: Color blue lighter].\\n\\tSyntaxMorph noTileColor ifTrue: [\\t\\\"override\\\"\\n\\t\\t^ self color: Color transparent].\\t\\\"Fix this to be real color!!\\\"\\n\\n\\t(cc _ self class translateColor: aColorOrSymbol) isColor\\n\\t\\tifTrue: [^ self color: cc]\\n\\t\\tifFalse: [Transcript show: aColorOrSymbol, ' needs to be handled in translateColor:'; cr.\\n\\t\\t\\t^ self color: Color transparent].\\t\\\"help!!\\\"! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 9/20/2001 12:43'!\\ndissectMessage\\n\\t\\\"I am a MessageNode. Return {receiverNode or nil, selector, (keyword nodes), (argument nodes)}. Ignore all spacing morphs.\\\"\\n\\n\\t! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'sw 2/3/2001 01:40'!\\neditor\\n\\t\\\"In parallel with the interface for text morphs, we respond to this, but in our case we are our own editor\\\"\\n\\n\\t^ self! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 9/19/2001 15:39'!\\nenclosingPane\\n\\t\\\"The object that owns this script layout\\\"\\n\\n\\t| oo higher |\\n\\too _ self owner.\\n\\t[higher _ oo isSyntaxMorph.\\n\\thigher _ higher or: [oo class == TransformMorph].\\n\\thigher _ higher or: [oo class == TwoWayScrollPane].\\n\\thigher ifFalse: [^ oo].\\n\\thigher] whileTrue: [oo _ oo owner].\\n! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 9/7/2001 16:13'!\\ngetCurrentValue\\n\\n\\tparseNode ifNil: [^nil].\\n\\tparseNode class == Symbol ifTrue: [^nil].\\t\\\"special\\\"\\n\\t^parseNode currentValueIn: self hostContext! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'dgd 2/22/2003 18:48'!\\nmessageNode\\n\\t\\\"Return the enclosing messageNode that is the full message. It has a receiver.\\\"\\n\\n\\t^self orOwnerSuchThat: [:oo | oo receiverNode notNil]! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'RAA 8/15/1999 16:23'!\\nparseNode\\n\\t\\n\\t^parseNode\\n\\t\\t\\n\\t! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'RAA 8/15/1999 16:11'!\\nparseNode: x\\n\\t\\n\\tparseNode _ x\\n\\t\\t\\n\\t! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'di 11/17/2000 08:07'!\\nparsedInClass\\n\\n\\t^ self rootTile parseNode encoder classEncoding! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 11/15/2000 14:39'!\\nparsedInClass: x\\n\\n\\tself parsedInClass == x ifFalse: [self error: 'inconsistent value']! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 9/25/2001 11:28'!\\nreadOut\\n\\t\\\"Find and return an UpdatingStringMorph, possibly in a NumericReadoutTile\\\"\\n\\n\\t^ ((self findA: NumericReadoutTile) ifNil: [^ nil]) findA: UpdatingStringMorph! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 7/23/2001 18:04'!\\nreceiverNode\\n\\t\\\"If I am (have) a MessageNode, return the node of the receiver. Watch out for foolish noise words.\\\"\\n\\n\\tparseNode class == MessageNode ifFalse: [^ nil].\\n\\tparseNode receiver ifNil: [^ nil].\\n\\tsubmorphs do: [:ss | \\n\\t\\tss isSyntaxMorph ifTrue: [\\n\\t\\t\\tss parseNode ifNotNil: [\\\"not noise word\\\"\\n\\t\\t\\t\\tss isNoun ifTrue: [^ ss] \\n\\t\\t\\t\\t\\tifFalse: [^ nil \\\"found selector\\\"]]]].\\n\\t^ nil! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 9/23/2001 00:27'!\\nreceiverObject\\n\\t\\\"Return some object that could be the receiver to me (a selector). Either the actual object who is the receiver in this message, or a guy of the right class.\\\"\\n\\n\\t| rec value mm |\\n\\t(rec _ owner) isSyntaxMorph ifFalse: [^ nil].\\n\\trec _ rec receiverNode.\\n\\trec ifNil: [(rec _ owner owner) isSyntaxMorph ifFalse: [^ nil].\\n\\t\\t\\t\\trec _ rec receiverNode].\\t\\n\\trec ifNil: [(rec _ owner owner owner) isSyntaxMorph ifFalse: [^ nil].\\n\\t\\t\\t\\trec _ rec receiverNode].\\n\\trec isSelfTile ifTrue: [\\n\\t\\t^ ((mm _ self containingWindow model) respondsTo: #targetObject) \\n\\t\\t\\tifTrue: [mm targetObject]\\n\\t\\t\\tifFalse: [mm selectedClassOrMetaClass new]].\\n\\tvalue _ rec ifNotNil: [rec try].\\n\\tvalue class == Error ifTrue: [\\n\\t\\tvalue _ Vocabulary instanceWhoRespondsTo: self selector].\\n\\t^ value! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 1/13/2001 20:08'!\\nrename: newSelector\\n\\t| keywords mainSel list last |\\n\\t\\\"Attempt to change the name as listed in my tiles. Can change the number of argumtents. MethodNode (SelectorNode (SelectorNode (string))) or MethodNode (SelectorNode (SelectorNode (string) TempVarNode() SelectorNode (string) TempVarNode()))\\\"\\n\\n\\tself isMethodNode ifFalse: [\\n\\t\\tself rootTile == self ifTrue: [^ self]. \\\"not in a script\\\"\\n\\t\\t^ self rootTile rename: newSelector \\\"always do at the root\\\"].\\n\\n\\tkeywords _ newSelector keywords.\\n\\tmainSel _ self findA: SelectorNode.\\n\\tlist _ mainSel submorphs select: [:mm | \\n\\t\\tmm isSyntaxMorph and: [mm parseNode class == SelectorNode]].\\n\\t1 to: (list size min: keywords size) do: [:ind |\\n\\t\\t((list at: ind) findA: UpdatingStringMorph) contents: (keywords at: ind)].\\n\\tkeywords size + 1 to: list size do: [:ind | \\\"removing keywords\\\"\\n\\t\\t[last _ mainSel submorphs last.\\n\\t\\t (last isSyntaxMorph and: [last parseNode class == TempVariableNode])] whileFalse: [\\n\\t\\t\\t\\tlast delete].\\n\\t\\t[last _ mainSel submorphs last.\\n\\t\\t (last isSyntaxMorph and: [last parseNode class == SelectorNode])] whileFalse: [\\n\\t\\t\\t\\tlast delete].\\t\\\"the TempVariableNode and others\\\"\\n\\t\\tmainSel submorphs last delete.\\t\\\"the SelectorNode\\\"\\n\\t\\t].\\n\\tlist size + 1 to: keywords size do: [:ind | \\\"adding keywords\\\"\\n\\t\\t\\\"add a SelectorNode, add a spacer, add a TempVarNode\\\"\\n\\t\\tmainSel addToken: (keywords at: ind) type: #keyword1 \\n\\t\\t\\ton: (SelectorNode new key: (keywords at: ind) code: nil).\\n\\t\\tmainSel addMorphBack: (mainSel transparentSpacerOfSize: 4@4).\\n\\t\\t(TempVariableNode new name: 'arg', ind printString index: ind type: nil scope: nil)\\n\\t\\t\\t asMorphicSyntaxIn: mainSel].! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'dgd 2/22/2003 13:41'!\\nselector\\n\\t\\\"Find the selector I represent, or have inside of me. My parseNode is a SelectorNode or a MessageNode.\\\"\\n\\n\\t| sel cnt |\\n\\tparseNode class == SelectorNode \\n\\t\\tifTrue: [^self decompile asString asSymbol].\\n\\tparseNode class == KeyWordNode ifTrue: [^self decompile asString asSymbol].\\n\\tparseNode class == MessageNode | (parseNode class == MessagePartNode) \\n\\t\\tifFalse: [^nil].\\n\\t\\\"Must be one of those to have a selector\\\"\\n\\t\\\"Beware of messageParts. If MessagePartNode, only returns this one keyword.\\\"\\n\\tsel := ''.\\n\\tcnt := 0.\\n\\tsubmorphs do: \\n\\t\\t\\t[:mm | \\n\\t\\t\\tmm isSyntaxMorph \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[cnt := cnt + 1.\\n\\t\\t\\t\\t\\t(mm nodeClassIs: SelectorNode) ifTrue: [^mm selector].\\n\\t\\t\\t\\t\\t(mm nodeClassIs: MessagePartNode) ifTrue: [sel := sel , mm selector].\\n\\t\\t\\t\\t\\t(mm nodeClassIs: KeyWordNode) ifTrue: [sel := sel , mm decompile asString].\\n\\t\\t\\t\\t\\t(mm nodeClassIs: ReturnNode) ifTrue: [cnt := cnt - 1].\\n\\t\\t\\t\\t\\t(mm nodeClassIs: MessageNode) \\n\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t[parseNode receiver ifNil: [sel := mm selector].\\n\\t\\t\\t\\t\\t\\t\\tcnt = 2 & (sel isEmpty) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[\\\"not the receiver. Selector and arg\\\"\\n\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tsel := mm selector]]]].\\n\\tsel ifNil: [^nil].\\n\\tsel notEmpty ifTrue: [^sel asSymbol].\\n\\t^nil! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'aoy 2/15/2003 21:31'!\\nunSpaceAndUpShift: aString appending: extraChars \\n\\t| answer upShiftNext |\\n\\tanswer := WriteStream on: String new.\\n\\tupShiftNext := false.\\n\\taString do: \\n\\t\\t\\t[:ch | \\n\\t\\t\\tupShiftNext :=( ch == Character space) \\n\\t\\t\\t\\tifTrue: [ true]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[answer nextPut: (upShiftNext ifTrue: [ch asUppercase] ifFalse: [ch]).\\n\\t\\t\\t\\t\\t false]].\\n\\tanswer := answer contents.\\n\\textraChars isEmptyOrNil ifTrue: [^answer].\\n\\t(answer endsWith: extraChars) ifFalse: [answer := answer , extraChars].\\n\\t^answer! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 11/12/2000 14:42'!\\nuserScriptSelector\\n\\t\\\"user wrote this script\\\"\\n\\n\\t^ self valueOfProperty: #userScriptSelector! !\\n\\n!SyntaxMorph methodsFor: 'accessing' stamp: 'tk 11/12/2000 14:41'!\\nuserScriptSelector: sel\\n\\t\\\"user wrote this script\\\"\\n\\n\\tself setProperty: #userScriptSelector toValue: sel.! !\\n\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 16:03'!\\naSimpleStringMorphWith: aString\\n\\n\\tself alansTest1 ifTrue: [\\n\\t\\t^StringMorph contents: aString font: self alansCurrentFontPreference\\n\\t].\\n\\n\\t^StringMorph contents: aString! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 23:24'!\\nalansCurrentFontPreference\\n\\n\\t^nil\\t\\t\\\"StrikeFont familyName: 'ComicBold' size: 16\\\"! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 13:38'!\\nalansTemplateStyleFor: key\\n\\n\\t(#(ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue:) includes: key) ifTrue: [^1].\\n\\t(#(do: collect:) includes: key) ifTrue: [^2].\\n\\t(#(if:do:) includes: key) ifTrue: [^3].\\n\\t^0\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/28/2001 13:46'!\\nanUpdatingStringMorphWith: aString special: aBoolean\\n\\n\\tself alansTest1 ifTrue: [\\n\\t\\t^(aBoolean ifTrue: [SyntaxUpdatingStringMorph] ifFalse: [UpdatingStringMorph])\\n\\t\\t\\t contents: aString\\n\\t\\t\\tfont: self alansCurrentFontPreference\\n\\t].\\n\\t^UpdatingStringMorph contents: aString! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 13:39'!\\nconstructSelfVariant: receiver and: key\\n\\n\\t| wordy |\\n\\t(receiver isKindOf: VariableNode) ifFalse: [^nil].\\n\\treceiver name = 'self' ifFalse: [^nil].\\n\\t(wordy _ self translateFromWordySelfVariant: key) ifNil: [^nil].\\n\\t^wordy\\n\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 23:20'!\\ndarkerColor\\n\\n\\t^(Color r: 1.0 g: 0.839 b: 0.613)\\t\\\"Color lightBrown lighter lighter.\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 23:23'!\\nfontToUseForSpecialWord: aString\\n\\n\\t^(#('Yes' 'No' 'Test') includes: aString) ifTrue: [\\n\\t\\t(StrikeFont familyName: 'Helvetica' size: 14)\\n\\t] ifFalse: [\\n\\t\\tnil\\t\\\"(StrikeFont familyName: 'ComicBold' size: 16)\\\"\\n\\t]! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/28/2001 09:35'!\\nlighterColor\\n\\n\\t^Color gray: 0.9\\t\\t\\n\\\"(Color r: 0.935 g: 0.935 b: 0.935)\\\"\\n\\\"paleGreen lighter\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'tk 8/7/2001 23:15'!\\nnoiseBeforeBlockArg\\n\\n\\t^ self alansTest1 ifTrue: [' Use'] ifFalse: [' from']! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 3/25/2001 17:16'!\\nnoiseStringMorph: aNoiseString\\n\\n\\t| sMorph |\\n\\n\\tsMorph _ self aSimpleStringMorphWith: aNoiseString.\\n\\tsMorph \\n\\t\\tfont: (self fontToUseForSpecialWord: aNoiseString); \\n\\t\\tsetProperty: #noiseWord toValue: true.\\n\\n\\t^sMorph\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'tk 8/7/2001 23:12'!\\nnoiseWordBeforeVariableNode: aNode string: aString\\n\\n\\t(#('self' 'nil') includes: aString) ifFalse: [\\n\\t\\taNode code ifNil: [^'my'].\\n\\t\\taNode type < 4 ifTrue: [^'my']\\n\\t].\\n\\t^nil! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 22:50'!\\nsetConditionalPartStyle\\n\\n\\tself specialColor: self lighterColor andBorder: self darkerColor.\\n\\tself useRoundedCorners.\\n\\tself borderWidth: 1.\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/27/2001 07:34'!\\nsetSpecialOuterTestFormat\\n\\n\\tself \\n\\t\\tspecialColor: self darkerColor \\n\\t\\tandBorder: self lighterColor.\\n\\tself useRoundedCorners.\\n\\tself layoutInset: 1.\\n\\t\\\"self setProperty: #variableInsetSize toValue: 6.\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 22:50'!\\nsetSpecialTempDeclarationFormat1\\n\\n\\t\\\"the outer template for temp defs\\\"\\n\\n\\tself \\n\\t\\tspecialColor: self darkerColor \\n\\t\\tandBorder: self lighterColor.\\n\\t\\\"self \\n\\t\\tspecialColor: (Color lightYellow) \\n\\t\\tandBorder: (Color r: 0.581 g: 0.774 b: 0.903).\\\"\\n\\tself useRoundedCorners.\\n\\tself layoutInset: 1.\\n\\tself cellPositioning: #center.\\n\\t\\\"self setProperty: #variableInsetSize toValue: 6.\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 22:50'!\\nsetSpecialTempDeclarationFormat2\\n\\n\\t\\\"the inner template for temp defs\\\"\\n\\n\\tself \\n\\t\\tspecialColor: self lighterColor \\n\\t\\tandBorder: self darkerColor.\\n\\t\\\"self \\n\\t\\tspecialColor: (Color r: 1.0 g: 1.0 b: 0.548) \\n\\t\\tandBorder: (Color r: 0.581 g: 0.774 b: 0.903).\\\"\\n\\tself useRoundedCorners.\\n\\tself layoutInset: 1.\\n\\t\\\"self setProperty: #variableInsetSize toValue: 6.\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'tk 7/27/2001 16:53'!\\nshouldBeBrokenIntoWords: aSymbol\\n\\n\\t^#(methodHeader1 methodHeader2 keyword2 upArrow \\n\\t\\ttempVariable tempVariableDeclaration blockarg2 variable\\n\\t\\tkeywordGetz keywordSetter unaryGetter\\n\\t\\tassignmentArrow) includes: aSymbol! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 13:44'!\\nspecialColor: c1 andBorder: c2\\n\\n\\tself color: (self scaleColorByUserPref: c1).\\n\\tself setProperty: #deselectedColor toValue: c1.\\n\\tself borderColor: (self scaleColorByUserPref: c2).\\n\\tself setProperty: #deselectedBorderColor toValue: c2.\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'yo 11/11/2002 10:32'!\\nsplitAtCapsAndDownshifted: aString\\n\\n\\tself flag: #yoCharCases.\\n\\n\\t^String streamContents: [ :strm |\\n\\t\\taString do: [ :each | \\n\\t\\t\\teach = $: ifFalse: [\\n\\t\\t\\t\\teach isUppercase ifTrue: [strm nextPut: (Character value: 0); \\n\\t\\t\\t\\t\\t\\t \\tnextPut: (Character value: 0); \\n\\t\\t\\t\\t\\t\\t \\tnextPut: (Character value: 0); \\n\\t\\t\\t\\t\\t\\t\\tnextPut: each asLowercase]\\n\\t\\t\\t\\t\\tifFalse: [strm nextPut: each]\\n\\t\\t\\t].\\n\\t\\t]\\n\\t].! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 23:01'!\\nstandardCellPositioning\\n\\n\\t^ self alansTest1 ifTrue: [#leftCenter] ifFalse: [#topLeft]! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'tk 7/25/2001 17:33'!\\nstandardInset\\n\\n\\tparseNode class == BlockNode ifTrue: [^ 5@1].\\n\\t\\t\\\"allow pointing beside a line so can replace it\\\"\\n\\t^ self alansTest1 ifTrue: [1] ifFalse: [-1]! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 4/4/2001 13:12'!\\nsubstituteKeywordFor: aString\\n\\n\\taString isEmpty ifTrue: [^aString asString].\\n\\taString asString = '^ ' ifTrue: [^'answer'].\\n\\taString asString = 'ifTrue:' ifTrue: [^'Yes'].\\n\\taString asString = 'ifFalse:' ifTrue: [^'No'].\\n\\taString asString = 'self' ifTrue: [^'self'].\\n\\taString first isUppercase ifTrue: [^aString asString].\\n\\n\\t^self splitAtCapsAndDownshifted: aString! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/28/2001 15:03'!\\ntokenVerticalSeparator\\n\\n\\t^Morph new \\n\\t\\tcolor: Color transparent;\\n\\t\\textent: 3@3;\\n\\t\\tlock\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 13:45'!\\ntranslateFromWordySelfVariant: key\\n\\n\\t#selfWrittenAsMe == key ifTrue: [^'me'].\\n\\t#selfWrittenAsMy == key ifTrue: [^'my'].\\n\\t#selfWrittenAsIll == key ifTrue: [^'I''ll'].\\n\\t#selfWrittenAsIm == key ifTrue: [^'I''m'].\\n\\t#selfWrittenAsThis == key ifTrue: [^'this'].\\n\\t^nil\\n\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'tk 7/28/2001 09:05'!\\ntranslateToWordyGetter: key\\n\\t\\\" setBlob: becomes 's blob _ \\\"\\n\\n\\t^ '''s ', \\n\\t (self splitAtCapsAndDownshifted: (key asString allButFirst: 3) \\n\\t\\t\\twithFirstCharacterDownshifted)! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'RAA 2/26/2001 13:45'!\\ntranslateToWordySelfVariant: aString\\n\\n\\t| lc |\\n\\tlc _ aString asLowercase.\\n\\tlc = 'me' ifTrue: [^#selfWrittenAsMe].\\n\\tlc = 'my' ifTrue: [^#selfWrittenAsMy].\\n\\tlc = 'i''ll' ifTrue: [^#selfWrittenAsIll].\\n\\tlc = 'i''m' ifTrue: [^#selfWrittenAsIm].\\n\\tlc = 'this' ifTrue: [^#selfWrittenAsThis].\\n\\t^nil\\n\\n! !\\n\\n!SyntaxMorph methodsFor: 'alans styles' stamp: 'tk 7/27/2001 17:26'!\\ntranslateToWordySetter: key\\n\\t\\\" setBlob: becomes 's blob _ \\\"\\n\\n\\t^ '''s ', \\n\\t (self splitAtCapsAndDownshifted: (key asString allButFirst: 3) allButLast \\n\\t\\t\\twithFirstCharacterDownshifted), \\n\\t ' _'! !\\n\\n\\n!SyntaxMorph methodsFor: 'card in a stack' stamp: 'tk 9/25/2001 11:46'!\\ncouldHoldSeparateDataForEachInstance\\n\\t\\\"Answer whether this type of morph is inherently capable of holding separate data for each instance ('card data')\\\"\\n\\n\\t^ true! !\\n\\n\\n!SyntaxMorph methodsFor: 'card & stack' stamp: 'tk 9/25/2001 11:41'!\\nsetNewContentsFrom: stringOrNumberOrNil\\n\\t\\\"Using stringOrNumberOrNil as a guide, set the receiver's contents afresh. If the input parameter is nil, the a default value stored in a property of the receiver, if any, will supply the new initial content. This method is only called when a VariableDock is attempting to put a new value.\\\"\\n\\n\\t(self readOut ifNil: [^ self]) setNewContentsFrom: stringOrNumberOrNil.! !\\n\\n!SyntaxMorph methodsFor: 'card & stack' stamp: 'tk 11/4/2001 21:47'!\\nsetTarget: aPlayer\\n\\t\\\"Find my UpdatingStringMorph and set its getSelector, putSelector, and target\\\"\\n\\n\\t| updatingString |\\n\\t(updatingString _ self readOut) ifNil: [^ self].\\n\\tupdatingString putSelector: (Utilities setterSelectorFor: self knownName).\\n\\tupdatingString getSelector: (Utilities getterSelectorFor: self knownName).\\n\\tupdatingString target: aPlayer. ! !\\n\\n\\n!SyntaxMorph methodsFor: 'change reporting' stamp: 'tk 9/28/2001 13:36'!\\ncolorChangedForSubmorph: colorPatch\\n\\t| sel newSel cc ms phrase completeMsg |\\n\\t\\\"reporting a color change\\\"\\n\\n\\t(self nodeClassIs: MessageNode) ifFalse: [^ nil].\\n\\t(sel _ self selector) ifNil: [^ nil].\\n\\t(Color colorNames includes: sel) | (sel == #r:g:b:) ifFalse: [^ nil].\\n\\t\\t\\\"a standard color name\\\"\\n\\t\\\"replace self with new tiles from the color\\\"\\n\\t(newSel _ (cc _ colorPatch color) name) \\n\\t\\tifNil: [ms _ MessageSend receiver: Color selector: #r:g:b: arguments: \\n\\t\\t\\t\\t(Array with: cc red with: cc green with: cc blue).\\n\\t\\t\\tphrase _ ms asTilesIn: Color globalNames: true]\\n\\t\\tifNotNil: [ms _ MessageSend receiver: Color selector: newSel arguments: #().\\n\\t\\t\\tphrase _ ms asTilesIn: Color globalNames: true].\\n\\tself deletePopup.\\n\\tcompleteMsg _ self isNoun ifTrue: [self] ifFalse: [owner].\\n\\tcompleteMsg owner replaceSubmorph: completeMsg by: phrase.\\n\\t\\\"rec setSelection: {rec. nil. rec}.\\\"\\n\\tphrase acceptIfInScriptor.! !\\n\\n\\n!SyntaxMorph methodsFor: 'classification' stamp: 'di 11/2/2000 13:25'!\\nisSyntaxMorph\\n\\t^ true! !\\n\\n\\n!SyntaxMorph methodsFor: 'debugging' stamp: 'di 11/17/2000 07:59'!\\ndebugger\\n\\n\\t^ self rootTile valueOfProperty: #debugger! !\\n\\n!SyntaxMorph methodsFor: 'debugging' stamp: 'di 11/17/2000 07:59'!\\ndebugger: x\\n\\n\\tself rootTile setProperty: #debugger toValue: x! !\\n\\n!SyntaxMorph methodsFor: 'debugging' stamp: 'RAA 8/24/1999 12:35'!\\nhostContext\\n\\n\\t^nil\\t\\t\\\"we don't have one\\\"! !\\n\\n\\n!SyntaxMorph methodsFor: 'drawing' stamp: 'RAA 3/25/2001 16:16'!\\ndrawOn: aCanvas\\n\\n\\tsuper drawOn: aCanvas.\\n\\tself isBlockNode ifFalse: [^self].\\n\\tself alansTest1 ifTrue: [^self].\\n\\n\\tself immediatelyBelowTheMethodNode ifTrue: [\\n\\t\\taCanvas fillRectangle: (self topLeft + (0@-1) extent: self width@1) color: Color gray\\n\\t] ifFalse: [\\n\\t\\taCanvas fillRectangle: (self topLeft + (1@1) extent: 2@(self height-2)) color: Color gray.\\n\\t\\taCanvas fillRectangle: (self topLeft + (1@1) extent: 4@1) color: Color gray.\\n\\t\\taCanvas fillRectangle: (self bottomLeft + (1@-1) extent: 4@1) color: Color gray\\n\\t].\\n! !\\n\\n!SyntaxMorph methodsFor: 'drawing' stamp: 'tk 9/13/2001 15:13'!\\nlookTranslucent\\n\\n\\tself setDeselectedColor.\\n\\tsuper color: (self color alpha: 0.25).\\n\\tsubmorphs do: [:mm | (mm respondsTo: #lookTranslucent) \\n\\t\\tifTrue: [mm lookTranslucent]\\n\\t\\tifFalse: [\\\"mm color: color\\\"]].\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'dropping/grabbing' stamp: 'di 1/29/2001 16:23'!\\ncleanupAfterItDroppedOnMe\\n\\t\\\"A tile just dropped into me. Clean up\\\"\\n\\n\\tself layoutChanged. \\\"** Isn't this already implied by the addMorph: ?\\\"\\n\\t\\\"Auto-accept on drop if in a scriptor\\\"\\n\\tself acceptIfInScriptor.! !\\n\\n!SyntaxMorph methodsFor: 'dropping/grabbing' stamp: 'di 5/4/2001 13:16'!\\nhighlightForDrop: evt\\n\\n\\t(self wantsDroppedMorph: evt hand firstSubmorph event: evt)\\n\\t\\tifTrue: [self color: self dropColor].! !\\n\\n!SyntaxMorph methodsFor: 'dropping/grabbing' stamp: 'tk 7/19/2001 19:04'!\\njustDroppedInto: aMorph event: evt\\n\\taMorph isSyntaxMorph ifFalse:\\n\\t\\t[Preferences tileTranslucentDrag\\n\\t\\t\\tifTrue: [self setDeselectedColor]\\n\\t\\t\\tifFalse: [self align: self topLeft with: self topLeft - self cursorBaseOffset]].\\n\\tself removeProperty: #beScript.\\n\\t^ super justDroppedInto: aMorph event: evt! !\\n\\n!SyntaxMorph methodsFor: 'dropping/grabbing' stamp: 'tk 9/30/2001 11:09'!\\nmorphToDropInPasteUp: aPasteUp\\n\\t\\\"If property #beScript is true, create a scriptor around me.\\\"\\n\\n\\t| actualObject itsSelector aScriptor adjustment handy tw blk |\\n\\t(self valueOfProperty: #beScript ifAbsent: [false]) ifFalse: [^ self].\\n\\tself removeProperty: #beScript.\\n\\tactualObject _ self actualObject ifNil: [\\n\\t\\t\\t\\t\\tself valueOfProperty: #scriptedPlayer ifAbsent: [nil]].\\n\\tactualObject ifNil: [^ self].\\n\\tself removeProperty: #scriptedPlayer.\\n\\tactualObject assureUniClass.\\n\\n\\titsSelector _ self userScriptSelector.\\n\\taScriptor _ itsSelector isEmptyOrNil\\n\\t\\tifFalse:\\n\\t\\t\\t[adjustment _ 0@0.\\n\\t\\t\\tactualObject scriptEditorFor: itsSelector]\\n\\t\\tifTrue:\\n\\t\\t\\t[adjustment _ 60 @ 20.\\n\\t\\t\\tactualObject newScriptorAround: self].\\n\\taScriptor ifNil: [^self].\\n\\thandy _ aPasteUp primaryHand.\\n\\n\\taScriptor position: handy position - adjustment.\\n\\taPasteUp addMorphFront: aScriptor.\\t\\\"do this early so can find World\\\"\\n\\taScriptor showingMethodPane ifFalse: [\\n\\t\\t\\\"(tw _ aScriptor findA: TwoWayScrollPane) ifNil:\\n\\t\\t\\t[itsSelector ifNil: ['blank script'.\\n\\t\\t\\t\\ttw _ aScriptor findA: TwoWayScrollPane.\\n\\t\\t\\t\\tblk _ (tw scroller findA: SyntaxMorph \\\"\\\"MethodNode\\\"\\\") findA: BlockNode.\\n\\t\\t\\t\\tblk addMorphFront: self]].\\n\\t\\t\\\"\\n\\t\\tSyntaxMorph setSize: nil andMakeResizable: aScriptor.\\n\\t\\t].\\n\\t^ aScriptor\\n! !\\n\\n!SyntaxMorph methodsFor: 'dropping/grabbing' stamp: 'tk 9/24/2001 10:04'!\\nstructureMatchWith: aMorph\\n\\t| meNoun itNoun |\\n\\t\\\"Return true if the node types would allow aMorph to replace me. This tests the gross structure of the method only.\\\"\\n\\n\\tmeNoun _ self isNoun.\\n\\titNoun _ aMorph isNoun.\\n\\n\\t\\\"Consider these nouns to be equal: TempVariableNode, LiteralNode, VariableNode, (MessageNode with receiver), CascadeNode, AssignmentNode\\\"\\n\\tmeNoun & itNoun ifTrue: [^ true].\\n\\tmeNoun & aMorph isBlockNode ifTrue: [^ true].\\n\\n\\t\\\"If I am a BlockNode, and it is a TempVariableNode, add it into list\\\"\\n\\t\\\"If I am a BlockNode, and it is a noun, add it as a new line\\\"\\n\\tself isBlockNode ifTrue:\\n\\t\\t[itNoun ifTrue: [^ true].\\n\\t\\t(aMorph nodeClassIs: ReturnNode) ifTrue:\\n\\t\\t\\t[^ (self submorphs\\n\\t\\t\\t\\tdetect: [:mm | ((mm isSyntaxMorph) and: [mm nodeClassIs: ReturnNode])]\\n\\t\\t\\t\\tifNone: [nil]) isNil].\\t\\\"none already in this block\\\"\\n\\t\\t\\t\\t\\\"If I am a BlockNode, and it is a ReturnNode, add to end\\\"\\n\\t\\t(aMorph nodeClassIs: CommentNode) ifTrue: [^ true]].\\n\\n\\t(self isMethodNode) ifTrue: [^ false].\\t\\\"Later add args and keywords\\\"\\n\\t\\t\\\"Later allow comments to be dropped in\\\"\\n\\t\\t\\\"Add MethodTemps by dropping into the main block\\\"\\n\\n\\t(self nodeClassIs: ReturnNode) & (aMorph parseNode class == MessageNode) \\n\\t\\tifTrue: [^ true].\\t\\t\\\"Command replace Return\\\"\\n\\t(self nodeClassIs: MessageNode) & (aMorph parseNode class == ReturnNode) ifTrue: [\\n\\t\\t(owner submorphs select: [:ss | ss isSyntaxMorph]) last == self\\n\\t\\t\\tifTrue: [^ true]].\\t\\\"Return replace last command\\\"\\n\\n\\t(aMorph nodeClassIs: AssignmentNode) ifTrue: [\\n\\t\\titNoun ifFalse: [\\\"create a new assignment\\\"\\n\\t\\t\\t^ self isAVariable & self isDeclaration not]].\\t\\\"only assign to a variable\\\"\\n\\n\\t\\\"If nodes are of equal class, replace me with new one.\\\"\\n\\t(self nodeClassIs: aMorph parseNode class) ifTrue: [\\n\\t\\t(self nodeClassIs: MessageNode) \\n\\t\\t\\t\\tifFalse: [^ true]\\t\\\"normal match\\\"\\n\\t\\t\\t\\tifTrue: [^ self receiverNode == aMorph receiverNode]].\\t\\\"both nil\\\"\\n\\n\\t^ false \\\"otherwise reject\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'dropping/grabbing' stamp: 'gm 2/22/2003 12:49'!\\nwantsDroppedMorph: aMorph event: evt \\n\\t\\\"For the moment, you have to drop it the right place. We do not look at enclosing morphs\\\"\\n\\n\\t\\\"Two ways to do this: Must always destroy old node, then drag in new one.\\n\\t\\tOr, drop replaces what you drop on. Nasty with blocks.\\\"\\n\\n\\t(aMorph isSyntaxMorph) ifFalse: [^false].\\n\\t(self structureMatchWith: aMorph) ifFalse: [^false].\\t\\\"gross structure\\\"\\n\\n\\t\\\"Only look at types if NoviceMode -- building EToys\\\"\\n\\t^self okToBeReplacedBy: aMorph\\t\\\"test the types\\\"\\n\\n\\t\\\"^ true\\\"! !\\n\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'di 11/8/2000 22:05'!\\ncursorBaseOffset\\n\\n\\t^ 7@14\\n! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'di 11/6/2000 16:20'!\\nhandlesKeyboard: evt\\n\\t^ evt keyCharacter = Character backspace! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'dgd 2/22/2003 13:39'!\\nhandlesMouseDown: evt \\n\\tevt yellowButtonPressed ifTrue: [^true].\\n\\tparseNode isNil ifTrue: [^false].\\n\\towner isSyntaxMorph \\n\\t\\tifTrue: [(owner isMethodNode and: [self isBlockNode not]) ifTrue: [^false]].\\t\\\"Can only take block out of a MethodNode\\\"\\n\\t^true! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'tk 10/26/2000 16:58'!\\nhandlesMouseOver: evt\\n\\t\\\"Am I a tile that could be picked up?\\\"\\n\\n\\t^ true! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'di 11/6/2000 08:21'!\\nhandlesMouseOverDragging: evt\\n\\n\\t^ evt hand hasSubmorphs\\n\\t\\tand: [evt hand firstSubmorph isSyntaxMorph]\\n! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'di 11/17/2000 08:21'!\\nkeyStroke: evt\\n\\t\\\"Handle a keystroke event.\\\"\\n\\t| spacer |\\n\\tevt keyCharacter = Character backspace ifTrue:\\n\\t\\t[(owner notNil and: [owner isSyntaxMorph]) ifTrue:\\n\\t\\t\\t[owner isBlockNode ifTrue:\\n\\t\\t\\t\\t[\\\"Delete a statement.\\\"\\n\\t\\t\\t\\t(spacer _ self submorphAfter) class == AlignmentMorph\\n\\t\\t\\t\\t\\t\\tifTrue: [spacer delete].\\n\\t\\t\\t\\tself delete].\\n\\t\\t\\t]].\\n! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'tk 9/26/2001 05:56'!\\nmouseDown: evt \\n\\t| dup rootTile |\\n\\tevt yellowButtonPressed ifTrue: [^ self showMenu: evt].\\n\\t(rootTile _ self rootTile) isMethodNode ifTrue:\\n\\t\\t[self currentSelectionDo:\\n\\t\\t\\t[:innerMorph :mouseDownLoc :outerMorph |\\n\\t\\t\\t(outerMorph notNil and: [self == innerMorph])\\n\\t\\t\\t\\tifTrue: [\\\"Click on prior selection -- record click point.\\\"\\n\\t\\t\\t\\t\\t\\tself setSelection: {self. evt cursorPoint. outerMorph}]\\n\\t\\t\\t\\tifFalse: [\\\"A new selection sequence.\\\"\\n\\t\\t\\t\\t\\t\\tself setSelection: {self. evt cursorPoint. nil}]].\\n\\t\\t^ self].\\n\\n\\t\\\"Out in the world -- treat as a unit\\\"\\n\\trootTile isSticky ifTrue: [^ self].\\t\\\"later may allow to be selected\\\"\\n\\trootTile isPartsDonor \\n\\t\\tifTrue: [dup _ rootTile duplicate.\\n\\t\\t\\t\\tdup setProperty: #beScript toValue: true]\\n\\t\\tifFalse: [dup _ rootTile].\\n\\tevt hand attachMorph: dup.\\n\\tPreferences tileTranslucentDrag\\n\\t\\tifTrue: [^ dup lookTranslucent]\\n\\t\\tifFalse: [^ dup align: dup topLeft with: evt hand position + self cursorBaseOffset]\\n! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'tk 7/19/2001 20:21'!\\nmouseEnter: evt\\n\\t\\\"Highlight this level as a potential grab target\\\"\\n\\n\\\"Transcript cr; print: self; show: ' enter'.\\\"\\n\\tself rootTile isMethodNode ifFalse: [^ self]. \\t\\\"not in a script\\\"\\n\\tself unhighlightOwnerBorder.\\n\\tself highlightForGrab: evt.\\n\\tevt hand newKeyboardFocus: self.\\n! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'tk 7/25/2001 10:09'!\\nmouseEnterDragging: evt\\n\\t\\\"Highlight this level as a potential drop target\\\"\\n\\n\\\"self isBlockNode ifTrue: [Transcript cr; print: self; show: ' enterDragging'].\\\"\\n\\tself rootTile isMethodNode ifFalse: [^ self]. \\t\\\"not in a script\\\"\\n\\n\\tevt hand hasSubmorphs ifFalse: [^ self]. \\\"Don't react to empty hand\\\"\\n\\tself unhighlightOwnerBorder.\\n\\tself isBlockNode ifFalse: [self highlightForDrop: evt.\\n\\t\\t(self firstOwnerSuchThat: [:m | m isSyntaxMorph and: [m color = self dropColor]])\\n\\t\\t\\tifNotNilDo: [:m | m unhighlight]].\\n\\n\\tself isBlockNode ifTrue:\\n\\t\\t[(self firstOwnerSuchThat: [:m | m isSyntaxMorph and: [m isBlockNode]])\\n\\t\\t\\tifNotNilDo: [:m | \\\"Suspend outer block.\\\"\\n\\t\\t\\t\\t\\t\\tm stopStepping; removeDropZones].\\n\\t\\tself startStepping]\\n! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'dgd 2/22/2003 18:48'!\\nmouseLeave: evt \\n\\t\\\"Move grab highlight back out a level\\\"\\n\\n\\t\\\"Transcript cr; print: self; show: ' leave'.\\\"\\n\\n\\tself rootTile isMethodNode ifFalse: [^self].\\t\\\"not in a script\\\"\\n\\tself unhighlightBorder.\\n\\t(owner notNil and: [owner isSyntaxMorph]) \\n\\t\\tifTrue: [owner highlightForGrab: evt]! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'dgd 2/22/2003 18:48'!\\nmouseLeaveDragging: evt \\n\\t\\\"Transcript cr; print: self; show: ' leaveDragging'.\\\"\\n\\n\\tself rootTile isMethodNode ifFalse: [^self].\\t\\\"not in a script\\\"\\n\\tself isBlockNode \\n\\t\\tifTrue: \\n\\t\\t\\t[self\\n\\t\\t\\t\\tstopStepping;\\n\\t\\t\\t\\tremoveDropZones.\\n\\t\\t\\t(self firstOwnerSuchThat: [:m | m isSyntaxMorph and: [m isBlockNode]]) \\n\\t\\t\\t\\tifNotNilDo: [:m | m startStepping].\\t\\\"Activate outer block.\\\"\\n\\t\\t\\tself submorphs do: \\n\\t\\t\\t\\t\\t[:ss | \\n\\t\\t\\t\\t\\t\\\"cancel drop color in line beside mouse\\\"\\n\\n\\t\\t\\t\\t\\tss color = self dropColor ifTrue: [ss setDeselectedColor]]].\\n\\n\\t\\\"Move drop highlight back out a level\\\"\\n\\tself unhighlight.\\n\\t(owner notNil and: [owner isSyntaxMorph]) \\n\\t\\tifTrue: [owner isBlockNode ifFalse: [owner highlightForDrop: evt]]! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'tk 10/17/2001 13:41'!\\nmouseMove: evt\\n\\t| dup selection |\\n\\towner isSyntaxMorph ifFalse: [^ self].\\n\\nfalse ifTrue: [\\\"for now, do not drag off a tile\\\"\\n\\tself currentSelectionDo:\\n\\t\\t[:innerMorph :mouseDownLoc :outerMorph |\\n\\t\\tmouseDownLoc ifNotNil: [\\n\\t\\t\\t(evt cursorPoint dist: mouseDownLoc) > 4 ifTrue:\\n\\t\\t\\t\\t[\\\"If drag 5 pixels, then tear off a copy of outer selection.\\\"\\n\\t\\t\\t\\tselection _ outerMorph ifNil: [self].\\n\\t\\t\\t\\tselection deletePopup.\\n\\t\\t\\t\\tevt hand attachMorph: (dup _ selection duplicate).\\n\\t\\t\\t\\tPreferences tileTranslucentDrag\\n\\t\\t\\t\\t\\tifTrue: [dup lookTranslucent]\\n\\t\\t\\t\\t\\tifFalse: [dup align: dup topLeft\\n\\t\\t\\t\\t\\t\\t\\t\\twith: evt hand position + self cursorBaseOffset].\\n\\t\\t\\t\\tself setSelection: nil.\\t\\\"Why doesn't this deselect?\\\"\\n\\t\\t\\t\\t(self firstOwnerSuchThat: [:m | m isSyntaxMorph and: [m isBlockNode]])\\n\\t\\t\\t\\t\\tifNotNilDo: [:m | \\\"Activate enclosing block.\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\tm startStepping]]]].\\n\\t].! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'di 11/17/2000 08:13'!\\nmouseUp: evt\\n\\t| newSel |\\n\\tself rootTile isMethodNode ifFalse: [^ self].\\n\\tself currentSelectionDo:\\n\\t\\t[:innerMorph :mouseDownLoc :outerMorph |\\n\\t\\tnewSel _ outerMorph\\n\\t\\t\\tifNil: [self \\\"first click\\\"]\\n\\t\\t\\tifNotNil: [(outerMorph firstOwnerSuchThat:\\n\\t\\t\\t\\t\\t\\t\\t[:m | m isSyntaxMorph and: [m isSelectable]]) ifNil: [self]].\\n\\t\\tnewSel isMethodNode ifTrue: [^ self setSelection: nil].\\n\\t\\tself setSelection: {self. nil. newSel}]\\n! !\\n\\n!SyntaxMorph methodsFor: 'event handling' stamp: 'tk 12/1/2000 15:42'!\\nwantsKeyboardFocusFor: aSubmorph\\n\\t| doEdit |\\n\\t\\\"only let strings edit on shift-click. Editing on ordinary click defeats the brown selection and tile dragging.\\\"\\n\\n\\tdoEdit _ self world primaryHand lastEvent shiftPressed.\\n\\tdoEdit ifTrue: [\\\"remove the arrows during editing\\\"\\n\\t\\tself valueOfProperty: #myPopup ifPresentDo: [:panel |\\n\\t\\t\\tpanel delete. self removeProperty: #myPopup]].\\n\\t^ doEdit! !\\n\\n\\n!SyntaxMorph methodsFor: 'formatting options' stamp: 'di 2/21/2001 11:42'!\\nalansTest1\\n\\t\\n\\t| root |\\n\\n\\troot _ self rootTile ifNil: [self].\\n\\t^root valueOfProperty: #alansNewStyle ifAbsent: [self usingClassicTiles not]! !\\n\\n!SyntaxMorph methodsFor: 'formatting options' stamp: 'RAA 2/26/2001 09:02'!\\ncontrolContrast2: evt\\n\\n\\t| origin scale startingContrastX |\\n\\n\\tevt isMouseUp ifTrue: [\\n\\t\\t^self removeProperty: #startingPointForSomeAdjustment\\n\\t].\\n\\tevt isMouseDown ifTrue: [\\n\\t\\t^self setProperty: #startingPointForSomeAdjustment toValue: evt cursorPoint\\n\\t].\\n\\tContrastFactor ifNil: [ContrastFactor _ 0.5].\\n\\tscale _ 200.0.\\n\\tstartingContrastX _ ContrastFactor * scale.\\n\\torigin _ self valueOfProperty: #startingPointForSomeAdjustment.\\n\\tContrastFactor _ (evt cursorPoint x - origin x + startingContrastX) / scale min: 1.0 max: 0.0.\\n\\tself finalAppearanceTweaks.\\n! !\\n\\n!SyntaxMorph methodsFor: 'formatting options' stamp: 'RAA 2/26/2001 09:07'!\\ncontrolContrast: evt\\n\\n\\t\\\"old version. may be some scripts saved with me, so don't crash\\\"\\n\\t^self! !\\n\\n!SyntaxMorph methodsFor: 'formatting options' stamp: 'RAA 5/11/2001 07:41'!\\ncontrolSpacing2: evt\\n\\n\\t| origin scale startingContrastX |\\n\\n\\tevt isMouseUp ifTrue: [\\n\\t\\t^self removeProperty: #startingPointForSomeAdjustment\\n\\t].\\n\\tevt isMouseDown ifTrue: [\\n\\t\\t^self setProperty: #startingPointForSomeAdjustment toValue: evt cursorPoint\\n\\t].\\n\\tSizeScaleFactor ifNil: [SizeScaleFactor _ 0.15].\\n\\tscale _ 200.0.\\n\\tstartingContrastX _ SizeScaleFactor * scale.\\n\\torigin _ self valueOfProperty: #startingPointForSomeAdjustment.\\n\\tSizeScaleFactor _ (evt cursorPoint x - origin x + startingContrastX) / scale min: 1.0 max: 0.0.\\n\\tself finalAppearanceTweaks.\\n! !\\n\\n!SyntaxMorph methodsFor: 'formatting options' stamp: 'RAA 2/26/2001 09:07'!\\ncontrolSpacing: evt\\n\\n\\t\\\"old version. may be some scripts saved with me, so don't crash\\\"\\n\\t^self! !\\n\\n!SyntaxMorph methodsFor: 'formatting options' stamp: 'di 2/21/2001 12:30'!\\nlookClassic\\n\\tself isLeafTile ifTrue: [self layoutInset: 2@4]! !\\n\\n!SyntaxMorph methodsFor: 'formatting options' stamp: 'tk 7/18/2001 16:00'!\\nusingClassicTiles \\n\\n\\t^ Preferences uniTilesClassic! !\\n\\n\\n!SyntaxMorph methodsFor: 'highlighting' stamp: 'tk 7/30/2001 14:48'!\\ncompoundBorderColor \\n\\n\\t^ self valueOfProperty: #deselectedBorderColor ifAbsent: [Color veryLightGray]\\n! !\\n\\n!SyntaxMorph methodsFor: 'highlighting' stamp: 'di 11/5/2000 07:26'!\\ndropColor\\n\\t^ Color green darker! !\\n\\n!SyntaxMorph methodsFor: 'highlighting' stamp: 'tk 7/23/2001 18:28'!\\ngrabColor\\n\\n\\t\\\"Not the select color, but the mouseOver border color. Means it could be grabbed\\\"\\n\\t^ Color paleOrange mixed: 0.5 with: Color brown! !\\n\\n!SyntaxMorph methodsFor: 'highlighting' stamp: 'di 11/6/2000 09:22'!\\nhighlightForGrab: evt\\n\\n\\tself borderColor: self grabColor.! !\\n\\n!SyntaxMorph methodsFor: 'highlighting' stamp: 'tk 7/19/2001 19:09'!\\nstdBorderColor \\n\\n\\t\\\"put choices of how to do the border here\\\"\\n\\t^ self valueOfProperty: #deselectedBorderColor ifAbsent: [Color transparent]! !\\n\\n!SyntaxMorph methodsFor: 'highlighting' stamp: 'tk 7/19/2001 19:50'!\\nunhighlight\\n\\n\\tself setDeselectedColor.\\n\\n\\nfalse ifTrue: [\\n\\tself currentSelectionDo: [:innerMorph :mouseDownLoc :outerMorph |\\n\\t\\tself color: ( false\\n\\t\\t\\t\\\"(self == outerMorph or: [owner notNil and: [owner isSyntaxMorph not]])\\\"\\n\\t\\t\\t\\tifTrue: [self valueOfProperty: #deselectedBorderColor ifAbsent: [#raised]]\\n\\t\\t\\t\\tifFalse: [self color: Color transparent]\\n\\t\\t)\\n\\t]].\\n! !\\n\\n!SyntaxMorph methodsFor: 'highlighting' stamp: 'di 5/4/2001 13:21'!\\nunhighlightBorder\\n\\n\\tself currentSelectionDo: [:innerMorph :mouseDownLoc :outerMorph |\\n\\t\\tself borderColor: (\\n\\t\\t\\t(self == outerMorph or: [owner notNil and: [owner isSyntaxMorph not]])\\n\\t\\t\\t\\tifTrue: [self valueOfProperty: #deselectedBorderColor ifAbsent: [#raised]]\\n\\t\\t\\t\\tifFalse: [self stdBorderColor]\\n\\t\\t)\\n\\t]\\n! !\\n\\n!SyntaxMorph methodsFor: 'highlighting' stamp: 'dgd 2/22/2003 18:48'!\\nunhighlightOwner\\n\\t\\\"Unhighlight my owner\\\"\\n\\n\\t(owner notNil and: [owner isSyntaxMorph]) ifTrue: [owner unhighlight]! !\\n\\n!SyntaxMorph methodsFor: 'highlighting' stamp: 'dgd 2/22/2003 18:49'!\\nunhighlightOwnerBorder\\n\\t\\\"Unhighlight my owner's border\\\"\\n\\n\\t(owner notNil and: [owner isSyntaxMorph]) \\n\\t\\tifTrue: [owner unhighlightBorder]! !\\n\\n\\n!SyntaxMorph methodsFor: 'initialization' stamp: 'sw 3/6/2001 11:26'!\\ninAPluggableScrollPane\\n\\t\\\"Answer a PluggableTileScriptorMorph that holds the receiver\\\"\\n\\n\\t| widget |\\n\\twidget _ PluggableTileScriptorMorph new.\\n\\twidget extent: 10@10; borderWidth: 0.\\n\\twidget scroller addMorph: self.\\n\\twidget setScrollDeltas.\\n\\twidget hResizing: #spaceFill; vResizing: #spaceFill.\\n\\t^ widget\\n\\n! !\\n\\n!SyntaxMorph methodsFor: 'initialization' stamp: 'sw 6/26/2001 10:58'!\\ninAScrollPane\\n\\t\\\"Answer a scroll pane in which the receiver is scrollable\\\"\\n\\n\\t^ self inATwoWayScrollPane! !\\n\\n!SyntaxMorph methodsFor: 'initialization' stamp: 'di 1/31/2001 10:14'!\\nopenInWindow\\n\\n\\t| window widget sel |\\n\\tsel _ ''.\\n\\tself firstSubmorph allMorphs do: [:rr | \\n\\t\\t\\t(rr isKindOf: StringMorph) ifTrue: [sel _ sel, rr contents]].\\n\\twindow _ (SystemWindow labelled: 'Tiles for ', self parsedInClass printString, '>>',sel).\\n\\twidget _ self inAScrollPane.\\n\\twidget color: Color paleOrange.\\n\\twindow\\n\\t\\taddMorph: widget\\n\\t\\tframe: (0@0 extent: 1.0@1.0).\\n\\twindow openInWorldExtent: (\\n\\t\\tself extent + (20@40) min: (Display boundingBox extent * 0.8) rounded\\n\\t)\\n\\n! !\\n\\n!SyntaxMorph methodsFor: 'initialization' stamp: 'FBS 2/24/2004 14:21'!\\nreturnNode: aNode expression: expr\\n\\n\\t| row expMorph sMorph aNoiseString |\\n\\trow _ self addRow: #return on: aNode.\\n\\tself alansTest1 ifTrue: [\\n\\t\\trow setSpecialOuterTestFormat.\\n\\t\\taNoiseString _ ' Reply '.\\n\\t\\tsMorph _ self aSimpleStringMorphWith: aNoiseString.\\n\\t\\tsMorph \\n\\t\\t\\temphasis: TextEmphasis bold emphasisCode;\\n\\t\\t\\tsetProperty: #syntacticallyCorrectContents toValue: '^'.\\n\\n\\t\\trow addMorphBack: sMorph.\\n\\t] ifFalse: [\\n\\t\\trow addToken: '^ ' type: #upArrow on: aNode.\\n\\t].\\n\\texpMorph _ expr asMorphicSyntaxIn: row.\\n\\tself alansTest1 ifTrue: [\\n\\t\\t(expMorph hasProperty: #deselectedColor) ifFalse: [expMorph setConditionalPartStyle].\\n\\t].\\n\\texpr addCommentToMorph: row.\\n\\t^row\\n! !\\n\\n!SyntaxMorph methodsFor: 'initialization' stamp: 'tk 1/19/2001 13:29'!\\nsample: arg1\\n\\\"a comment\\\"\\n| temp1 |\\ntemp1 _ 5.\\ntemp1 yourself.\\ntemp1 min: arg1.! !\\n\\n\\n!SyntaxMorph methodsFor: 'insertion drop zones' stamp: 'di 1/30/2001 21:00'!\\nremoveDropZones\\n\\t\\\"Remove the insertion drop-zone morphs.\\\"\\n\\n\\tself submorphsDo:\\n\\t\\t[:mm | (mm isMemberOf: BorderedMorph) ifTrue: [mm delete]].\\n! !\\n\\n!SyntaxMorph methodsFor: 'insertion drop zones' stamp: 'tk 9/13/2001 15:24'!\\ntrackDropZones\\n\\t| hand i localPt insertion insHt ii prevBot nxtHt d c1 c2 ht2 spacer1 spacer2 wid ht1 dc each |\\n\\thand _ self primaryHand.\\n\\t(\\\"hand lastEvent redButtonPressed &\\\" hand hasSubmorphs\\n\\t\\tand: [(self hasOwner: hand) not]) ifFalse: [^ self].\\n\\n\\tinsertion _ hand firstSubmorph renderedMorph.\\n\\tinsertion isSyntaxMorph ifFalse: [^ self].\\n\\tinsertion isNoun ifFalse: [(insertion nodeClassIs: CommentNode) ifFalse: [^ self]].\\n\\tlocalPt _ self globalPointToLocal: hand position.\\n\\tinsHt _ insertion height. \\\"**just use standard line height here\\\"\\n\\tself removeDropZones. \\\"Maybe first check if in right place, then just tweak heights.\\\"\\n\\ti _ (ii _ self indexOfMorphAbove: localPt) min: submorphs size-1.\\n\\tprevBot _ i <= 0 ifTrue: [(self innerBounds) top]\\n\\t\\t\\t\\t\\tifFalse: [(self submorphs at: i) bottom].\\n\\tnxtHt _ (submorphs isEmpty\\n\\t\\tifTrue: [insertion]\\n\\t\\tifFalse: [self submorphs at: i+1]) height.\\n\\td _ ii > i ifTrue: [nxtHt \\\"for consistent behavior at bottom\\\"]\\n\\t\\t\\tifFalse: [0 max: (localPt y - prevBot min: nxtHt)].\\n\\n\\t\\\"Top and bottom spacer heights cause continuous motion...\\\"\\n\\tc1 _ Color transparent. c2 _ Color transparent.\\n\\tht2 _ d*insHt//nxtHt. ht1 _ insHt - ht2.\\n\\twid _ self width - (2*borderWidth) - (2*self layoutInset).\\n\\twid isPoint ifTrue: [wid _ wid x].\\n\\t(spacer1 _ BorderedMorph newBounds: (0@0 extent: wid@ht1)\\n\\t\\t\\t\\tcolor: (ht1 > (insHt//2) ifTrue: [c1] ifFalse: [c2]))\\n\\t\\t\\t\\t\\tborderWidth: 1; borderColor: spacer1 color.\\n\\tself privateAddMorph: spacer1 atIndex: (i+1 max: 1).\\n\\t(spacer2 _ BorderedMorph newBounds: (0@0 extent: wid@ht2)\\n\\t\\t\\t\\tcolor: (ht2 > (insHt//2+1) ifTrue: [c1] ifFalse: [c2]))\\n\\t\\t\\t\\t\\tborderWidth: 1; borderColor: spacer2 color.\\n\\tspacer1 setProperty: #dropZone toValue: true.\\n\\tspacer2 setProperty: #dropZone toValue: true.\\n\\tself privateAddMorph: spacer2 atIndex: (i+3 min: submorphs size+1).\\n\\tself fullBounds. \\\"Force layout prior to testing for cursor containment\\\"\\n\\n\\t\\\"Maintain the drop target highlight -- highlight spacer if hand is in it.\\\"\\n\\t{spacer1. spacer2} do:\\n\\t\\t[:spacer | (spacer containsPoint: localPt) ifTrue:\\n\\t\\t\\t[spacer color: self dropColor.\\n\\t\\t\\t\\\"Ignore border color. Maybe do it later.\\n\\t\\t\\tself borderColor = self dropColor\\n\\t\\t\\t\\tifTrue: [self borderColor: self stdBorderColor]\\\"]].\\n\\t\\\"If no submorph (incl spacers) highlighted, then re-highlight the block.\\\"\\n\\t\\\"Ignore border color. Maybe do it later.\\n\\t((self wantsDroppedMorph: insertion event: hand lastEvent) and:\\n\\t\\t[(self submorphs anySatisfy: [:m | m containsPoint: localPt]) not])\\n\\t\\t\\tifTrue: [self borderColor: self dropColor].\\n\\t\\\"\\n\\n\\t\\\"Dragging a tile within a Block, if beside a tile, color it a dropzone\\\"\\n\\t\\\"Transcript show: localPt y printString; space; show: submorphs first top \\n\\t\\tprintString; space; show: submorphs last top printString; cr.\\\"\\n\\tdc _ self dropColor.\\n\\t1 to: ((ii+4 min: submorphs size) max: 1) do: [:ind | \\n\\t\\teach _ submorphs at: ind.\\n\\t\\teach isSyntaxMorph ifTrue: [\\n\\t\\t\\tlocalPt y >= each top \\n\\t\\t\\t\\tifTrue: [\\\"in this one or beyond\\\"\\n\\t\\t\\t\\t\\t(localPt y < each bottom) \\n\\t\\t\\t\\t\\t\\tifTrue: [(each submorphs anySatisfy: [:m | \\n\\t\\t\\t\\t\\t\\t\\t\\tm containsPoint: localPt])\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [each setDeselectedColor]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [each color: dc]]\\n\\t\\t\\t\\t\\t\\tifFalse: [each color = dc ifTrue: [each setDeselectedColor]]]\\n\\t\\t\\t\\tifFalse: [each color = dc ifTrue: [each setDeselectedColor]]]].\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 9/13/2001 15:28'!\\nacceptDroppingMorph: aMorph event: evt\\n\\t| itNoun old |\\n\\t\\\"Two cases: 1) a phrase being dropped into a block. Add a new line.\\n\\t\\t2) aMorph is replacing self by dropping on it.\\n\\tFor the moment, you have to drop it the right place (the end of a tile if it is complex). We do not look at enclosing morphs\\\"\\n\\n\\titNoun _ aMorph isNoun.\\n\\tself withAllOwnersDo:\\n\\t\\t[:m | (m isSyntaxMorph and: [m isBlockNode])\\n\\t\\t\\t\\tifTrue: [m stopStepping; removeDropZones]].\\n\\tself isBlockNode & itNoun ifTrue:\\n\\t\\t[(aMorph nodeClassIs: TempVariableNode) ifTrue:\\n\\t\\t\\t\\t[\\\"If I am a BlockNode, and it is a TempVariableNode, add it into list\\\"\\n\\t\\t\\t\\t(self addBlockArg: aMorph)].\\n\\t\\t\\\"If I am a BlockNode and it is a noun add it as a new line\\\"\\n\\t\\t^ self addToBlock: aMorph event: evt].\\n\\t\\t\\t\\t\\n\\tself isBlockNode ifTrue: [\\n\\t\\t (aMorph nodeClassIs: CommentNode) ifTrue: [^ self addToBlock: aMorph event: evt].\\n\\t\\t (aMorph nodeClassIs: ReturnNode) ifTrue: [^ self addToBlock: aMorph event: evt]].\\n\\n\\t\\\"Later add args and keywords. later allow comments to be dropped\\\"\\n\\n\\t\\\"Can't put statement, literal, assignment, or cascade into left side of assignment\\\"\\n\\t(owner isSyntaxMorph) ifTrue:\\n\\t\\t[(owner nodeClassIs: AssignmentNode) ifTrue:\\n\\t\\t\\t[(owner submorphIndexOf: self) = 1 ifTrue:\\n\\t\\t\\t\\t[aMorph isAVariable ifFalse: [ ^ self]]]].\\n\\n\\t(aMorph nodeClassIs: AssignmentNode) ifTrue: [\\n\\t\\titNoun ifFalse: [\\\"create a new assignment\\\"\\n\\t\\t\\tself isAVariable ifTrue: [^ self newAssignment]\\n\\t\\t\\t\\t\\tifFalse: [^ self]]].\\t\\\"only assign to a variable\\\"\\n\\n\\taMorph deselect.\\n\\t(old _ owner) replaceSubmorph: self by: aMorph.\\t\\\"do the normal replacement\\\"\\n\\t(old isSyntaxMorph) ifTrue: [old cleanupAfterItDroppedOnMe].\\t\\\"now owned by no one\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'FBS 2/24/2004 14:24'!\\naddBlockArg: aMorph\\n\\t\\\"Add a temporary to a block or the method. Return true if succeed\\\"\\n\\t\\\"(aMorph nodeClassIs: TempVariableNode) is known to be true.\\\"\\n\\t\\\"***NOTE: This method should be combined with addTempVar:\\\"\\n\\n\\t| tempHolder tt var nn |\\n\\towner isMethodNode ifTrue: [\\n\\t\\t^ (self addTempVar: aMorph)].\\t\\\"Node for them is not inside the block\\\"\\n\\t\\t\\\"If exists, drop the temp in this block and let user extend it.\\\"\\n\\tnn _ aMorph decompile string.\\t\\\"name\\\"\\n\\t(self isKnownVarName: nn) ifTrue: [^ false].\\t\\\"already defined\\\"\\n\\n\\ttt _ self firstSubmorph.\\n\\ttempHolder _ tt firstSubmorph isSyntaxMorph \\n\\t\\t\\t\\tifTrue: [(tt nodeClassIs: BlockArgsNode) \\n\\t\\t\\t\\t\\t\\t\\tifTrue: [tt] ifFalse: [nil]]\\n\\t\\t\\t\\tifFalse: [nil].\\n\\n\\ttempHolder ifNil: [\\\"make new row\\\"\\n\\t\\ttempHolder _ self addRow: #blockarg1 on: (BlockArgsNode new).\\n\\t\\ttempHolder addNoiseString: self noiseBeforeBlockArg.\\n\\t\\ttempHolder submorphs last firstSubmorph emphasis: TextEmphasis bold emphasisCode.\\n\\t\\ttempHolder useRoundedCorners.\\n\\n\\t\\tself addMorphFront: tempHolder.\\n\\t\\taMorph parseNode name: nn key: nn code: nil.\\n\\t\\taMorph parseNode asMorphicSyntaxIn: tempHolder.\\n\\t\\ttempHolder cleanupAfterItDroppedOnMe.\\n\\t\\t^ true].\\n\\n\\t\\\"Know this variable is not present, so add it\\\"\\n\\n\\taMorph parseNode name: nn key: nn code: nil.\\n\\ttempHolder addMorphBack: (tempHolder transparentSpacerOfSize: 4@4).\\n\\tvar _ tempHolder addRow: #tempVariable on: aMorph parseNode.\\n\\tvar layoutInset: 1.\\n\\tvar addMorphBack: (self aSimpleStringMorphWith: nn).\\n\\tvar cleanupAfterItDroppedOnMe.\\n\\t^ true\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'RAA 3/25/2001 16:15'!\\naddColumn: aColorOrSymbol on: aNode\\n\\t| col |\\n\\tself addMorphBack: (col _ self class column: aColorOrSymbol on: aNode).\\n\\n\\\"col setProperty: #howCreated toValue: thisContext longStack.\\\"\\n\\n\\tself alansTest1 ifTrue: [\\n\\t\\t(aColorOrSymbol == #block and: [self isMethodNode not]) ifTrue: [\\n\\t\\t\\tcol setConditionalPartStyle.\\n\\t\\t].\\n\\t].\\n\\t^ col\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'FBS 2/24/2004 14:44'!\\naddNoiseString: aNoiseString\\n\\n\\t^self addNoiseString: aNoiseString emphasis: TextEmphasis normal emphasisCode.\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'RAA 3/25/2001 16:17'!\\naddNoiseString: aNoiseString emphasis: anInteger\\n\\n\\tself alansTest1 ifFalse: [^self].\\n\\t^(self addColumn: #keyword1 on: nil)\\n\\t\\tlayoutInset: 1;\\n\\t\\taddMorphBack: ((self noiseStringMorph: aNoiseString) emphasis: anInteger)\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'RAA 2/15/2001 19:22'!\\naddRow: aColorOrSymbol on: aNode\\n\\n\\t| row |\\n\\tself addMorphBack: (row _ self class row: aColorOrSymbol on: aNode).\\n\\n\\\"row setProperty: #howCreated toValue: thisContext longStack.\\\"\\n\\n\\t^row\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 8/24/2001 15:15'!\\naddSingleKeywordRow: aStringLikeItem\\n\\n\\t| row sMorph modifiedString |\\n\\n\\t(row _ self class row: #text on: nil) borderWidth: 1.\\n\\n\\tmodifiedString _ self substituteKeywordFor: aStringLikeItem.\\n\\tsMorph _ self addString: modifiedString special: true.\\n\\tsMorph font: (self fontToUseForSpecialWord: modifiedString).\\n\\tmodifiedString = aStringLikeItem ifFalse: [\\n\\t\\tsMorph setProperty: #syntacticallyCorrectContents toValue: aStringLikeItem].\\n\\n\\trow addMorph: sMorph.\\n\\tself addMorphBack: row.\\n\\t^row! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'RAA 4/4/2001 13:15'!\\naddString: literalOrVarName special: aBoolean\\n\\n\\t| answer |\\n\\t\\\"Create and return an UpdatingStringMorph containing the value. Use an UpdatingStringMorph, so it can inform its owner when it has been edited. Keep the getSelector being nil\\\"\\n\\n\\tanswer _ (self anUpdatingStringMorphWith: literalOrVarName special: aBoolean)\\n\\t\\ttarget: self;\\n\\t\\tputSelector: #acceptIgnoring:;\\n\\t\\tuseStringFormat.\\n\\n\\t^answer\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'FBS 2/24/2004 14:23'!\\naddTempVar: aMorph \\n\\t\\\"know we are a block inside a MethodNode\\\" \\n\\t\\\"(aMorph nodeClassIs: TempVariableNode) is known to be true.\\\"\\n\\t| tempHolder ii tt var nn |\\n\\tnn _ aMorph decompile string.\\t\\\"name\\\"\\n\\t(self isKnownVarName: nn) ifTrue: [^ false].\\t\\\"already defined\\\"\\n\\n\\ttempHolder _ nil.\\n\\t(ii _ owner submorphIndexOf: self) = 1 ifFalse: [\\n\\t\\ttt _ owner submorphs at: ii - 1.\\n\\t\\ttt isSyntaxMorph ifTrue: [\\n\\t\\t\\t(tt nodeClassIs: MethodTempsNode) ifTrue: [tempHolder _ tt].\\n\\t\\t\\t(tt nodeClassIs: UndefinedObject) ifTrue: [tempHolder _ tt findA: MethodTempsNode]]].\\n\\n\\ttempHolder ifNil: [\\n\\t\\ttempHolder _ owner addRow: #tempVariable on: MethodTempsNode new.\\n\\t\\ttempHolder addNoiseString: self noiseBeforeBlockArg.\\n\\t\\ttempHolder submorphs last firstSubmorph emphasis: TextEmphasis bold emphasisCode.\\n\\t\\ttempHolder useRoundedCorners.\\n\\n\\t\\towner addMorph: tempHolder inFrontOf: self.\\n\\t\\taMorph parseNode name: nn key: nn code: nil.\\n\\t\\taMorph parseNode asMorphicSyntaxIn: tempHolder.\\n\\t\\ttempHolder cleanupAfterItDroppedOnMe.\\n\\t\\t^ true].\\n\\n\\taMorph parseNode name: nn key: nn code: nil.\\n\\ttempHolder addMorphBack: (tempHolder transparentSpacerOfSize: 4@4).\\n\\tvar _ tempHolder addRow: #tempVariable on: aMorph parseNode.\\n\\tvar layoutInset: 1.\\n\\tvar addMorphBack: (self addString: nn special: false).\\n\\tvar cleanupAfterItDroppedOnMe.\\n\\t^ true! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 8/10/2001 09:57'!\\naddTextRow: aStringLikeItem\\n\\n\\t| row tt |\\n\\t(row _ self class row: #text on: nil) borderWidth: 1.\\n\\t(tt _ TextMorph new) contents: aStringLikeItem.\\n\\trow addMorph: tt.\\n\\t\\\"row addMorph: (self addString: (aStringLikeItem copyWithout: Character cr) special: false).\\\"\\n\\tself addMorphBack: row.\\n\\t^row! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 7/25/2001 10:01'!\\naddToBlock: aMorph event: evt\\n\\t\\\"Insert a new line of code. Figure out who it goes before. If evt Y is within an existing line (to the right of a tile), then replace that tile.\\\"\\n\\n\\t| whereDropped dropBefore replace |\\n\\twhereDropped _ \\\"self pointFromWorld:\\\" evt cursorPoint.\\n\\tdropBefore _ self submorphs \\n\\t\\tdetect: [:each | each isSyntaxMorph ifTrue: [\\n\\t\\t\\twhereDropped y < each top ifTrue: [true]\\t\\\"before this one\\\"\\n\\t\\t\\t\\tifFalse: [whereDropped y < each bottom \\n\\t\\t\\t\\t\\t\\t\\tifTrue: [replace _ true]\\t\\\"replace this one\\\"\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [false]]]] \\\"try next line\\\"\\n\\t\\tifNone: [nil].\\n\\t(aMorph nodeClassIs: ReturnNode) ifTrue: [dropBefore _ nil].\\n\\t\\t\\\"Returns are always at the end. (Watch out for comments)\\\"\\n\\n\\tdropBefore \\n\\t\\tifNil: [self addMorphBack: aMorph]\\n\\t\\tifNotNil: [\\n\\t\\t\\treplace ifNotNil: [aMorph deselect.\\n\\t\\t\\t\\tself replaceSubmorph: dropBefore by: aMorph.\\t\\\"replace it!!\\\"\\n\\t\\t\\t\\t^ dropBefore cleanupAfterItDroppedOnMe].\\t\\\"now owned by no one\\\"\\n\\t\\t\\tself addMorph: aMorph inFrontOf: dropBefore].\\n\\tself cleanupAfterItDroppedOnMe.\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'FBS 2/24/2004 14:22'!\\naddToken: aString type: aColorOrSymbol on: aNode\\n\\n\\t| sMorph modifiedString noiseWord row |\\n\\n\\trow _ (self addRow: aColorOrSymbol on: aNode) layoutInset: 1.\\n\\tself alansTest1 ifFalse: [\\n\\t\\tsMorph _ self addString: aString special: false.\\n\\t\\trow addMorphBack: sMorph.\\n\\t\\t^row\\n\\t].\\n\\n\\tnoiseWord _ [ :w |\\n\\t\\tw ifNotNil: [\\n\\t\\t\\trow \\n\\t\\t\\t\\taddMorphBack: (self noiseStringMorph: w);\\n\\t\\t\\t\\taddMorphBack: (self tokenVerticalSeparator)\\n\\t\\t].\\n\\t].\\n\\t(self shouldBeBrokenIntoWords: aColorOrSymbol) ifTrue: [\\n\\t\\tmodifiedString _ self substituteKeywordFor: aString.\\n\\t\\tsMorph _ self addString: modifiedString special: (aColorOrSymbol ~= #assignmentArrow).\\n\\t\\t\\t\\\"(#(unary keywordGetz keywordSetter unaryGetter) includes: aColorOrSymbol)\\\"\\n\\t\\tmodifiedString = aString ifFalse: [\\n\\t\\t\\tsMorph setProperty: #syntacticallyCorrectContents toValue: aString].\\n\\t\\tsMorph setProperty: #syntacticReformatting toValue: aColorOrSymbol;\\n\\t\\t\\tcontents: modifiedString.\\n\\t] ifFalse: [\\n\\t\\tsMorph _ self addString: (modifiedString _ aString) special: false.\\n\\t].\\n\\t(#(keyword2 upArrow) includes: aColorOrSymbol) ifTrue: [\\n\\t\\tsMorph \\n\\t\\t\\tfont: (self fontToUseForSpecialWord: modifiedString).\\n\\t].\\n\\t(#(keyword2 unary assignmentArrow methodHeader1 methodHeader2) includes: aColorOrSymbol) ifTrue: [\\n\\t\\tsMorph emphasis: TextEmphasis bold emphasisCode.\\n\\t].\\n\\taColorOrSymbol == #blockarg1 ifTrue: [\\n\\t].\\n\\t(aColorOrSymbol == #variable or: [aColorOrSymbol == #tempVariable]) ifTrue: [\\n\\t\\taString = 'self' ifTrue: [\\n\\t\\t\\tsMorph setProperty: #wordyVariantOfSelf toValue: true.\\n\\t\\t].\\n\\t\\tnoiseWord value: (self noiseWordBeforeVariableNode: aNode string: aString).\\n\\t].\\n\\n\\trow addMorphBack: sMorph.\\n\\t^row! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'RAA 3/25/2001 17:22'!\\naddTokenSpecialCase: aString type: aColorOrSymbol on: aNode\\n\\n\\t| sMorph modifiedString noiseWord col |\\n\\n\\tnoiseWord _ nil.\\n\\tsMorph _ self addString: aString special: false.\\n\\t(aColorOrSymbol == #keyword2) ifTrue: [\\n\\t\\tmodifiedString _ aString = 'if:' ifTrue: ['Test'] ifFalse: ['Yes'].\\n\\t\\tsMorph \\n\\t\\t\\tfont: (self fontToUseForSpecialWord: modifiedString); \\n\\t\\t\\tsetProperty: #syntacticallyCorrectContents toValue: aString;\\n\\t\\t\\tcontents: modifiedString.\\n\\t].\\n\\n\\tcol _ (self addRow: aColorOrSymbol on: aNode) layoutInset: 1.\\n\\tnoiseWord ifNotNil: [\\n\\t\\tcol \\n\\t\\t\\taddMorphBack: (self noiseStringMorph: noiseWord);\\n\\t\\t\\taddMorphBack: (self transparentSpacerOfSize: 3@1)\\n\\t].\\n\\tcol addMorphBack: sMorph.\\n\\t^col! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 8/24/2001 15:21'!\\naddUnaryRow: aStringLikeItem style: aSymbol\\n\\n\\t| row sMorph modifiedString fontToUse |\\n\\n\\t(row _ self class row: #text on: nil) borderWidth: 1.\\n\\tmodifiedString _ self substituteKeywordFor: aStringLikeItem.\\n\\tsMorph _ self addString: modifiedString special: true.\\n\\tfontToUse _ self fontToUseForSpecialWord: modifiedString.\\n\\n\\tsMorph \\n\\t\\tfont: fontToUse emphasis: 1;\\n\\t\\tsetProperty: #syntacticReformatting toValue: #unary.\\n\\tmodifiedString = aStringLikeItem ifFalse: [\\n\\t\\tsMorph setProperty: #syntacticallyCorrectContents toValue: aStringLikeItem].\\n\\trow addMorph: sMorph.\\n\\tself addMorphBack: row.\\n\\t^row! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'RAA 2/15/2001 19:43'!\\nfoldMessage\\n\\t\\\"I am a message whose receiver is wide, and whose message part is a column.\\n\\tRearrange me so that the message part appears indented under the receiver part.\\\"\\n\\t| messageRow node2 |\\n\\tnode2 _ parseNode copy receiver: nil.\\n\\tmessageRow _ SyntaxMorph row: #keyword1 on: node2.\\n\\n\\tmessageRow \\n\\t\\taddMorph: (self transparentSpacerOfSize: 20@10);\\n\\t\\taddMorphBack: submorphs last.\\t\\t\\\"<<handle noise words better\\\"\\n\\tself listDirection: #topToBottom;\\n\\t\\twrapCentering: #topLeft;\\n\\t\\taddMorphBack: (self transparentSpacerOfSize: 4@4);\\n\\t\\taddMorphBack: messageRow.\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 1/15/2001 11:15'!\\nfoldMessageOneArg\\n\\t\\\"I am a message that is wide, a row with receiver and a row with selector and arg.\\n\\tRearrange me so that the message part appears indented under the receiver part.\\\"\\n\\t| messageRow node2 |\\n\\tnode2 _ parseNode copy receiver: nil.\\n\\tmessageRow _ SyntaxMorph row: #keyword1 on: node2.\\n\\tmessageRow addMorph: (self transparentSpacerOfSize: 20@10);\\n\\t\\t\\taddMorphBack: submorphs second;\\n\\t\\t\\taddMorphBack: submorphs second. \\\"was the third\\\"\\n\\tself listDirection: #topToBottom;\\n\\t\\twrapCentering: #topLeft;\\n\\t\\taddMorphBack: messageRow.\\n! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 8/22/2001 16:30'!\\nisKnownVarName: newVarName\\n\\t\\\"Return true if this variable is already known, as an argument, temp var, block temp, or instance variable.\\\"\\n\\n\\t| syntLevel |\\n\\t(self parsedInClass allInstVarNames includes: newVarName) ifTrue: [^ true].\\n\\tsyntLevel _ self.\\n\\t[syntLevel tempVarNodesDo: [:node | \\n\\t\\tnode decompile string = newVarName ifTrue: [^ true]].\\n\\t (syntLevel _ syntLevel owner) isSyntaxMorph] whileTrue.\\n\\t^ false! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 8/1/2001 13:06'!\\nremoveReturnNode\\n\\t| blk |\\n\\t\\\"If last line is ^ self, remove it. I am a methodNode. Keep if no other tiles in the block.\\\"\\n\\n\\tblk _ self findA: BlockNode.\\n\\tblk submorphs last decompile string = '^self ' ifTrue: [\\n\\t\\t(blk submorphs count: [:ss | ss isSyntaxMorph]) > 1 ifTrue: [\\n\\t\\t\\tblk submorphs last delete]].! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 8/22/2001 16:35'!\\ntempVarNodesDo: aBlock\\n\\t\\\"Execute the block for any block temporary variables, method temps, or method args we have\\\"\\n\\n\\t| tempHolder argsHolder |\\n\\t((self parseNode class == MethodNode) or: [self parseNode class == BlockNode]) ifTrue: [\\n\\t\\tself submorphsDoIfSyntax: [:sub | \\n\\t\\t\\t\\t(sub nodeClassIs: MethodTempsNode) ifTrue: [tempHolder _ sub].\\n\\t\\t\\t\\t((sub nodeClassIs: UndefinedObject) and: [tempHolder isNil]) ifTrue: [\\n\\t\\t\\t\\t\\ttempHolder _ sub findA: MethodTempsNode].\\n\\t\\t\\t\\t(sub nodeClassIs: BlockArgsNode) ifTrue: [tempHolder _ sub].\\n\\t\\t\\t\\t(sub nodeClassIs: SelectorNode) ifTrue: [argsHolder _ sub].\\n\\t\\t\\t\\t]\\n\\t\\t\\tifString: [:sub | ].\\n\\t\\ttempHolder ifNotNil: [\\\"Temp variables\\\"\\n\\t\\t\\ttempHolder submorphsDoIfSyntax: [:sm | \\n\\t\\t\\t\\t\\t(sm nodeClassIs: TempVariableNode) ifTrue: [aBlock value: sm]]\\n\\t\\t\\t\\tifString: [:sm | ]].\\n\\t\\targsHolder ifNotNil: [\\\"arguments\\\"\\n\\t\\t\\targsHolder submorphsDoIfSyntax: [:sm | \\n\\t\\t\\t\\t\\t(sm nodeClassIs: TempVariableNode) ifTrue: [aBlock value: sm]]\\n\\t\\t\\t\\tifString: [:sm | ]].\\n\\t\\t].\\n\\t\\\"otherwise do nothing\\\"! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'tk 2/12/2001 14:39'!\\ntry\\n\\t\\\"Evaluate me once\\\"\\n\\n\\t(#(MessageNode LiteralNode VariableNode) includes: parseNode class name) \\n\\t\\tifFalse: [^ Error new].\\n\\t^ [Compiler evaluate: self decompile\\n\\t\\t\\t\\tfor: self actualObject\\n\\t\\t\\t\\tlogged: false.\\t\\\"should do something to the player\\\"\\n\\t\\t] ifError: [ :a :b | Error new].! !\\n\\n!SyntaxMorph methodsFor: 'layout' stamp: 'ar 8/10/2003 18:19'!\\nunfoldMessage\\n\\t\\\"I am a message whose message part is a column.\\n\\tRearrange me so that the entire message is one row.\\\"\\n\\t| messageRow |\\n\\tmessageRow _ self submorphs last.\\n\\tself removeMorph: messageRow.\\n\\tmessageRow submorphs do: [:m | self addMorphBack: m].\\n\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'macpal' stamp: 'sw 6/4/2001 19:26'!\\ncurrentVocabulary\\n\\t\\\"Answer the current vocabulary associated with the receiver. If none is yet set, determine an appropriate vocabulary and cache it within my properties dictionary.\\\"\\n\\n\\t| aVocab aSym |\\n\\taSym _ self valueOfProperty: #currentVocabularySymbol ifAbsent: [nil].\\n\\taSym ifNil:\\n\\t\\t[aVocab _ self valueOfProperty: #currentVocabulary ifAbsent: [nil].\\n\\t\\taVocab ifNotNil:\\n\\t\\t\\t[aSym _ aVocab vocabularyName.\\n\\t\\t\\tself removeProperty: #currentVocabulary.\\n\\t\\t\\tself setProperty: #currentVocabularySymbol toValue: aSym]].\\n\\n\\taSym ifNotNil:\\n\\t\\t[^ Vocabulary vocabularyNamed: aSym].\\n\\taVocab _ super currentVocabulary.\\n\\tself setProperty: #currentVocabularySymbol toValue: aVocab vocabularyName.\\n\\t^ aVocab! !\\n\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'tk 9/27/2001 19:09'!\\naccept\\n\\t\\\"Turn my current state into the text of a method. Compile it in my class.\\\"\\n\\n\\t^ self acceptInCategory: ClassOrganizer default! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'tk 11/21/2000 16:35'!\\nacceptIfInScriptor\\n\\t| root |\\n\\t\\\"If I am in a ScriptEditorMorph, tell my root to accept the new changes.\\\"\\n\\n\\t(self ownerThatIsA: ScriptEditorMorph) ifNotNil: [\\n\\t\\troot _ self rootTile.\\n\\t\\troot ifNotNil: [root accept]]. ! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'RAA 2/14/2001 15:40'!\\nacceptIgnoring: aString\\n\\t\\\"If I am inside a ScriptEditorMorph, tell my root to accept the new changes. Ignore the argument, which is the string whose conents just changed.\\\"\\n\\n\\tthisContext sender receiver removeProperty: #syntacticallyCorrectContents.\\n\\tself acceptIfInScriptor! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'tk 9/27/2001 17:15'!\\nacceptInCategory: categoryString\\n\\t\\\"Turn my current state into the text of a method. Compile it in my class.\\\"\\n\\t| cls sc sel |\\n\\tself isMethodNode ifFalse: [\\n\\t\\tself rootTile == self ifTrue: [^ self]. \\\"not in a script\\\"\\n\\t\\t^ self rootTile accept \\\"always accept at the root\\\"].\\n\\t(cls _ self parsedInClass) ifNil: [^ self].\\n\\tsel _ cls compile: self decompile classified: categoryString.\\n\\t(sc _ self firstOwnerSuchThat: [:mm | mm class == ScriptEditorMorph]) \\n\\t\\tifNotNil: [sc hibernate; unhibernate].\\t\\\"rebuild the tiles\\\"\\n\\t^ sel! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'tk 9/27/2001 19:12'!\\nacceptSilently\\n\\t\\\"Turn my current state into the text of a method.\\n\\tCompile it in my class. Don't rebuild the tiles.\\\"\\n\\t| cls |\\n\\tself isMethodNode ifFalse: [\\n\\t\\tself rootTile == self ifTrue: [^ false]. \\\"not in a script\\\"\\n\\t\\t^ self rootTile acceptSilently \\\"always accept at the root\\\"].\\n\\t(self ownerThatIsA: ScriptEditorMorph) ifNil: [^ false].\\n\\t(cls _ self parsedInClass) ifNil: [^ false].\\n\\tcls compile: self decompile classified: 'scripts'.\\n\\t^ true! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'di 5/4/2001 12:14'!\\nacceptUnlogged\\n\\t\\\"This is an exact copy of acceptSilently, except it does not log to the source file.\\n\\tUsed for all but the last of scrolling number changes.\\\"\\n\\t| cls |\\n\\tself isMethodNode ifFalse:\\n\\t\\t[self rootTile == self ifTrue: [^ self]. \\\"not in a script\\\"\\n\\t\\t^ self rootTile acceptUnlogged \\\"always accept at the root\\\"].\\n\\t(self ownerThatIsA: ScriptEditorMorph) ifNil: [^ self].\\n\\t(cls _ self parsedInClass) ifNil: [^ self].\\n\\tcls compile: self decompile\\n\\t\\tclassified: ClassOrganizer default\\n\\t\\twithStamp: nil\\n\\t\\tnotifying: nil\\n\\t\\tlogSource: false.\\n! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'md 8/15/2005 11:02'!\\ndecompile\\n\\t| stream |\\n\\t\\\"Produce Smalltalk code. We have a tree of SyntaxMorphs, but not a tree of ParseNodes. The user has dragged in many SyntaxMorphs, each with its own parseNode, but those nodes are not sewn together in a tree. The only data we get from a ParseNode is its class.\\n\\tWe produce really ugly code. But we compile it and decompile (prettyPrint) again for user to see.\\\"\\n\\n\\tstream _ ColoredCodeStream on: (Text new: 400).\\n\\tself printOn: stream indent: 1.\\t\\\"Tree walk and produce text of the code\\\"\\n\\t^ stream contents! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'di 11/13/2000 20:23'!\\ngetMenuBlock\\n\\n\\t^ nil! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'tk 9/23/2001 02:05'!\\nofferTilesMenuFor: aReceiver in: aLexiconModel\\n\\t\\\"Offer a menu of tiles for assignment and constants\\\"\\n\\n\\t| menu |\\n\\tmenu _ MenuMorph new addTitle: 'Hand me a tile for...'.\\n\\tmenu addLine.\\n\\tmenu add: '(accept method now)' target: aLexiconModel selector: #acceptTiles.\\n\\tmenu submorphs last color: Color red darker.\\n\\tmenu addLine.\\n\\n\\tmenu add: 'me, by name' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'<me by name>'. aReceiver}.\\n\\tmenu add: 'self' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'self'. VariableNode}.\\n\\tmenu add: '_ (assignment)' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'<assignment>'. nil}.\\n\\tmenu add: '\\\"a Comment\\\"' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'\\\"a comment\\\"\\\\' withCRs. CommentNode}.\\n\\tmenu submorphs last color: Color blue.\\n\\tmenu add: 'a Number' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'5'. LiteralNode}.\\n\\tmenu add: 'a Character' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'$z'. LiteralNode}.\\n\\tmenu add: '''abc''' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'''abc'''. LiteralNode}.\\n\\tmenu add: 'a Symbol constant' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'#next'. LiteralNode}.\\n\\tmenu add: 'true' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'true'. VariableNode}.\\n\\tmenu add: 'a Test' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'true ifTrue: [self] ifFalse: [self]'. MessageNode}.\\n\\tmenu add: 'a Loop' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'1 to: 10 do: [:index | self]'. MessageNode}.\\n\\tmenu add: 'a Block' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'[self]'. BlockNode}.\\n\\tmenu add: 'a Class or Global' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'Character'. LiteralVariableNode}.\\n\\tmenu add: 'a Reply' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'| temp | temp'. ReturnNode}.\\n\\tmenu popUpAt: ActiveHand position forHand: ActiveHand in: World.\\n! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'tk 9/17/2001 13:38'!\\nofferVarsMenuFor: aReceiver in: aLexiconModel\\n\\t\\\"Offer a menu of tiles for assignment and constants\\\"\\n\\n\\t| menu instVarList cls |\\n\\tmenu _ MenuMorph new addTitle: 'Hand me a tile for...'.\\n\\tmenu addLine.\\n\\tmenu add: '(accept method now)' target: aLexiconModel selector: #acceptTiles.\\n\\tmenu submorphs last color: Color red darker.\\n\\tmenu addLine.\\n\\tmenu add: 'new temp variable' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\targumentList: {'| temp | temp'. TempVariableNode}.\\n\\n\\tinstVarList _ OrderedCollection new.\\n\\tcls _ aReceiver class.\\n\\t[instVarList addAllFirst: cls instVarNames.\\n\\t cls == aLexiconModel limitClass] whileFalse: [cls _ cls superclass].\\n\\tinstVarList do: [:nn |\\n\\t\\tmenu add: nn target: self selector: #instVarTile: argument: nn].\\n\\tmenu popUpAt: ActiveHand position forHand: ActiveHand in: World.\\n\\n! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'tk 12/14/2001 11:58'!\\nputOnBackground\\n\\t\\\"Place the receiver, formerly private to its card, onto the shared background. If the receiver needs data carried on its behalf by the card, such data will be represented on every card.\\\"\\n\\n\\t| updStr |\\n\\t(updStr _ self readOut) ifNotNil: [\\\"If has a place to put per-card data, set that up.\\\"\\n\\t\\tupdStr getSelector ifNotNil: [\\n\\t\\t\\tself setProperty: #holdsSeparateDataForEachInstance toValue: true]].\\n\\tsuper putOnBackground.! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'di 11/17/2000 09:00'!\\nshowCode\\n\\t\\\"Turn my current state into the text of a method. Put it in a window.\\\"\\n\\n\\t(Workspace new contents: self rootTile decompile) openLabel: self printString,' code'\\n\\n\\t\\n! !\\n\\n!SyntaxMorph methodsFor: 'menus' stamp: 'tk 12/10/2001 17:48'!\\nshowMenu: evt\\n\\t| menu |\\n\\tmenu _ MenuMorph new.\\n\\tself rootTile isMethodNode ifTrue:\\n\\t\\t[menu add: 'accept method' target: self selector: #accept.\\n\\t\\tmenu addLine.\\n\\n\\t\\tmenu add: 'new temp variable' target: self selector: #attachTileForCode:nodeType: \\n\\t\\t\\t\\t\\targumentList: {'| temp | temp'. TempVariableNode}.\\n\\t\\tmenu addLine.\\n\\n\\t\\tself parsedInClass allInstVarNames do: [:nn |\\n\\t\\t\\tmenu add: nn,' tile' target: self selector: #instVarTile: argument: nn].\\n\\t\\tmenu addLine.\\n\\n\\t\\tmenu add: 'show code' target: self selector: #showCode.\\n\\t\\tmenu add: 'try out' target: self selector: #try.\\n\\t\\tmenu popUpAt: evt hand position forHand: evt hand in: World].\\n\\n\\n\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'new tiles' stamp: 'FBS 2/24/2004 14:32'!\\nattachTileForCode: expression nodeType: nodeClass\\n\\t| nn master tile |\\n\\t\\\"create a new tile for a part of speech, and put it into the hand\\\"\\n\\n\\t\\\"a few special cases\\\"\\n\\texpression = 'self' ifTrue: [\\n\\t\\t^ (((self string: expression toTilesIn: Object) \\n\\t\\t\\t\\tfindA: ReturnNode) findA: nodeClass) attachToHand].\\n\\n\\texpression = '<me by name>' ifTrue: [\\\"Tile for the variable in References\\\"\\n\\t\\tnn _ nodeClass knownName ifNil: [#+].\\n\\t\\t(References at: nn asSymbol ifAbsent: [nil]) == nodeClass ifTrue: [\\n\\t\\t\\t^ self attachTileForCode: nn nodeType: LiteralVariableNode].\\n\\t\\t\\\"otherwise just give a tile for self\\\"\\n\\t\\t^ self attachTileForCode: 'self' nodeType: VariableNode].\\n\\n\\texpression = '<assignment>' ifTrue: [\\\"do something really special\\\"\\n\\t\\tmaster _ self class new.\\n\\t\\tmaster addNoiseString: ' _ ' emphasis: TextEmphasis bold emphasisCode.\\n\\t\\ttile _ master firstSubmorph.\\n\\t\\t^ (tile parseNode: AssignmentNode new) attachToHand].\\t\\\"special marker\\\"\\n\\t\\t\\\"When this is dropped on a variable, enclose it in \\n\\t\\t\\ta new assignment statement\\\"\\n\\n\\t\\\"general case -- a tile for a whole line of code is returned\\\"\\n\\t^ ((self string: expression toTilesIn: Object) \\n\\t\\t\\t\\tfindA: nodeClass) attachToHand.! !\\n\\n!SyntaxMorph methodsFor: 'new tiles' stamp: 'tk 9/7/2001 11:21'!\\nattachToHand\\n\\t\\\"Adjust my look and attach me to the hand\\\"\\n\\n\\tself roundedCorners.\\n\\tActiveHand attachMorph: self.\\n\\tPreferences tileTranslucentDrag\\n\\t\\tifTrue: [self lookTranslucent.\\n\\t\\t\\tself align: self center with: ActiveHand position \\\"+ self cursorBaseOffset\\\"]\\n\\t\\tifFalse: [self align: self topLeft with: ActiveHand position + self cursorBaseOffset]\\n! !\\n\\n!SyntaxMorph methodsFor: 'new tiles' stamp: 'tk 8/30/2001 06:22'!\\ninstVarTile: aName\\n\\t\\\"Make and put into hand a tile for an instance variable\\\"\\n\\n\\t| sm |\\n\\tsm _ ((VariableNode new\\n\\t\\t\\t\\t\\tname: aName\\n\\t\\t\\t\\t\\tindex: 1\\n\\t\\t\\t\\t\\ttype: 1 \\\"LdInstType\\\") asMorphicSyntaxIn: SyntaxMorph new).\\n\\tsm roundedCorners.\\n\\tActiveHand attachMorph: sm.\\n\\tPreferences tileTranslucentDrag\\n\\t\\tifTrue: [sm lookTranslucent.\\n\\t\\t\\tsm align: sm center with: ActiveHand position \\\"+ self cursorBaseOffset\\\"]\\n\\t\\tifFalse: [sm align: sm topLeft with: ActiveHand position + self cursorBaseOffset]\\n! !\\n\\n!SyntaxMorph methodsFor: 'new tiles' stamp: 'tk 9/13/2001 13:44'!\\nstring: anExpression toTilesIn: playerClass\\n\\t| code tree methodNode |\\n\\t\\\"Construct SyntaxMorph tiles for some code. Returns the main BlockNode of a doIt.\\\"\\n\\n\\t\\\"This is really cheating!! Make a true parse tree later. -tk\\\"\\n\\tcode _ String streamContents: [:strm | \\n\\t\\tstrm nextPutAll: 'doIt'; cr; tab; nextPutAll: anExpression].\\n\\t\\\"decompile to tiles\\\"\\n\\ttree _ Compiler new \\n\\t\\tparse: code \\n\\t\\tin: playerClass\\n\\t\\tnotifying: nil.\\n\\tmethodNode _ tree asMorphicSyntaxUsing: SyntaxMorph.\\n\\tanExpression first == $\\\" ifTrue: [\\\"a comment\\\" \\n\\t\\t\\\"(methodNode findA: CommentNode) firstSubmorph color: Color blue.\\\"\\n\\t\\t^ methodNode].\\n\\t^ methodNode submorphs detect: [:mm | \\n\\t\\t(mm respondsTo: #parseNode) \\n\\t\\t\\tifTrue: [mm parseNode class == BlockNode] \\n\\t\\t\\tifFalse: [false]].\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'FBS 2/24/2004 14:23'!\\naddTemporaries: temporaries \\n\\t| tempMorph outerMorph w2 |\\n\\ttemporaries notEmpty ifFalse: [^self].\\n\\tself alansTest1 \\n\\t\\tifFalse: \\n\\t\\t\\t[tempMorph := self addRow: #tempVariable on: MethodTempsNode new.\\n\\t\\t\\ttemporaries do: [:temp | temp asMorphicSyntaxIn: tempMorph]\\n\\t\\t\\t\\tseparatedBy: \\n\\t\\t\\t\\t\\t[tempMorph addMorphBack: (tempMorph transparentSpacerOfSize: 4 @ 4)].\\n\\t\\t\\t^self].\\n\\touterMorph := self addRow: #tempVariable on: nil.\\n\\touterMorph setSpecialTempDeclarationFormat1.\\n\\touterMorph \\n\\t\\taddMorphBack: (w2 := self noiseStringMorph: self noiseBeforeBlockArg).\\n\\tw2 emphasis: TextEmphasis bold emphasisCode.\\n\\ttempMorph := outerMorph addRow: #tempVariable on: MethodTempsNode new.\\n\\ttempMorph setSpecialTempDeclarationFormat2.\\n\\ttemporaries do: \\n\\t\\t\\t[:temp | \\n\\t\\t\\ttempMorph \\n\\t\\t\\t\\taddToken: temp name\\n\\t\\t\\t\\ttype: #tempVariableDeclaration\\n\\t\\t\\t\\ton: temp]\\n\\t\\tseparatedBy: [tempMorph addMorphBack: self tokenVerticalSeparator]! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'tk 7/31/2001 17:27'!\\naddTemporaryControls\\n\\n\\t| row stdSize |\\n\\t\\n\\tstdSize _ 8@8.\\n\\trow _ AlignmentMorph newRow\\n\\t\\tcolor: Color transparent;\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #shrinkWrap.\\n\\tself addMorphBack: row.\\n\\n\\t{\\n\\t\\tMorph new\\n\\t\\t\\textent: stdSize; \\n\\t\\t\\tcolor: Color paleBlue darker;\\n\\t\\t\\tsetBalloonText: 'Change the contrast';\\n\\t\\t\\ton: #mouseUp send: #controlContrast2: to: self;\\n\\t\\t\\ton: #mouseMove send: #controlContrast2: to: self;\\n\\t\\t\\ton: #mouseDown send: #controlContrast2: to: self.\\n\\n\\t\\\"Removed because it's default is giant tiles, which no one wants. --tk\\n\\t\\tMorph new\\n\\t\\t\\textent: stdSize; \\n\\t\\t\\tcolor: Color green;\\n\\t\\t\\tsetBalloonText: 'Change basic spacing';\\n\\t\\t\\ton: #mouseUp send: #controlSpacing2: to: self;\\n\\t\\t\\ton: #mouseMove send: #controlSpacing2: to: self;\\n\\t\\t\\ton: #mouseDown send: #controlSpacing2: to: self.\\n\\t\\\"\\n\\n\\t\\tMorph new\\n\\t\\t\\textent: stdSize; \\n\\t\\t\\tcolor: Color lightRed;\\n\\t\\t\\tsetBalloonText: 'Change basic style';\\n\\t\\t\\ton: #mouseUp send: #changeBasicStyle to: self.\\n\\n\\t} do: [ :each |\\n\\t\\trow addMorphBack: each.\\n\\t\\trow addMorphBack: (self transparentSpacerOfSize: stdSize).\\n\\t].\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'yo 12/3/2004 17:01'!\\nalanBinaryPostRcvr: aNode key: key args: args\\n\\n\\t| nodeWithNilReceiver row |\\n\\n\\\"==\\nRepeat for collection [ collect ( from foo. blah blah foo blah) ]\\nRepeat for 1 to 50 [ do ( from i. blah blab i blah ) ]\\n==\\\"\\n\\n\\tnodeWithNilReceiver _ aNode copy receiver: nil.\\n\\t(row _ self addRow: #keyword2 on: nodeWithNilReceiver)\\n\\t\\tborderWidth: 1;\\n\\t\\tparseNode: (nodeWithNilReceiver as: MessageNode);\\n\\t\\tborderColor: row stdBorderColor.\\n\\trow addToken: key asString\\n\\t\\ttype: #binary\\n\\t\\ton: (SelectorNode new key: key asString code: nil \\\"fill this in?\\\").\\n\\targs first asMorphicSyntaxIn: row.\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'tk 7/30/2001 14:52'!\\nalanKeywordMessage: aNode isAConditional: template key: key args: args\\n\\n\\t| nodeWithNilReceiver column keywords row onlyOne |\\n\\n\\t(key == #collect: and: [args first isKindOf: BlockNode]) ifTrue: [\\n\\t\\t^self\\n\\t\\t\\talanKwdCollect: aNode \\n\\t\\t\\tisAConditional: template \\n\\t\\t\\tkey: key \\n\\t\\t\\targs: args\\n\\t].\\n\\tkey == #repeatFor:doing: ifTrue: [\\n\\t\\t^self\\n\\t\\t\\talanKwdRepeatForDoing: aNode \\n\\t\\t\\tisAConditional: template \\n\\t\\t\\tkey: key \\n\\t\\t\\targs: args\\n\\t].\\n\\tkey == #if:do: ifTrue: [\\n\\t\\t^self\\n\\t\\t\\talanKwdIfDo: aNode \\n\\t\\t\\tisAConditional: template \\n\\t\\t\\tkey: key \\n\\t\\t\\targs: args\\n\\t].\\n\\t(args size = 1 and: [key endsWith: 'Getz:']) ifTrue: [\\n\\t\\t^self\\n\\t\\t\\talanKwdSetter: aNode \\n\\t\\t\\tisAConditional: 0 \\n\\t\\t\\tkey: key \\n\\t\\t\\targs: args\\n\\t].\\n\\t(args size = 1 and: [self isStandardSetterKeyword: key]) ifTrue: [\\n\\t\\t^self\\n\\t\\t\\talanKwdSetter2: aNode \\n\\t\\t\\tisAConditional: 0 \\n\\t\\t\\tkey: key \\n\\t\\t\\targs: args\\n\\t].\\n\\tnodeWithNilReceiver _ aNode copy receiver: nil.\\n\\ttemplate = 1 ifTrue: [\\n\\t\\tself listDirection: #topToBottom.\\n\\t].\\n\\tcolumn _ self addColumn: #keyword1 on: nodeWithNilReceiver.\\n\\tkeywords _ key keywords.\\n\\tonlyOne _ args size = 1.\\n\\tonlyOne ifFalse: [\\\"necessary for three keyword messages!!\\\"\\n\\t\\tcolumn setProperty: #deselectedBorderColor toValue: column compoundBorderColor].\\n\\tkeywords\\n\\t\\twith: (args first: keywords size)\\n\\t\\tdo: [:kwd :arg |\\n\\t\\t\\ttemplate = 1 ifTrue: [\\n\\t\\t\\t\\tcolumn addMorphBack: (column transparentSpacerOfSize: 3@3).\\n\\t\\t\\t].\\n\\t\\t\\t(row _ column addRow: #keyword2 on: nodeWithNilReceiver)\\n\\t\\t\\t\\tparseNode: (nodeWithNilReceiver as: \\n\\t\\t\\t\\t\\t\\t(onlyOne ifTrue: [MessageNode] ifFalse: [MessagePartNode]));\\n\\t\\t\\t\\tborderColor: row stdBorderColor.\\n\\t\\t\\ttemplate = 1 ifTrue: [row addMorphBack: (row transparentSpacerOfSize: 20@6)].\\n\\t\\t\\trow addToken: kwd\\n\\t\\t\\t\\ttype: #keyword2\\n\\t\\t\\t\\ton: (onlyOne ifTrue: [SelectorNode new key: kwd code: nil \\\"fill this in?\\\"]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [KeyWordNode new]).\\n\\t\\t\\t(arg asMorphicSyntaxIn: row) setConditionalPartStyle.\\n\\t\\t].\\n\\tonlyOne ifTrue: [\\n\\t\\tself replaceSubmorph: column by: row.\\n\\t\\tcolumn _ row.\\n\\t].\\n\\t\\t\\t\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'RAA 3/25/2001 16:31'!\\nalanKwdCollect: aNode isAConditional: template key: key args: args\\n\\n\\t| nodeWithNilReceiver row kwdHolder |\\n\\n\\tnodeWithNilReceiver _ aNode copy receiver: nil.\\n\\t(row _ self addRow: #keyword2 on: nodeWithNilReceiver)\\n\\t\\tborderWidth: 1;\\n\\t\\tparseNode: (nodeWithNilReceiver as: MessageNode);\\n\\t\\tborderColor: row stdBorderColor.\\n\\tkwdHolder _ row\\n\\t\\taddToken: key\\n\\t\\ttype: #keyword2\\n\\t\\ton: (SelectorNode new key: key code: nil \\\"fill this in?\\\").\\n\\tkwdHolder firstSubmorph \\n\\t\\tsetProperty: #syntacticallyCorrectContents toValue: key asString;\\n\\t\\tcontents: ''.\\n\\n\\targs first asMorphicCollectSyntaxIn: row.\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'tk 7/30/2001 14:52'!\\nalanKwdIfDo: aNode isAConditional: template key: key args: args\\n\\t\\\"(know it has more than one arg)\\\"\\n\\t| nodeWithNilReceiver column keywords row |\\n\\n\\tnodeWithNilReceiver _ aNode copy receiver: nil.\\n\\tcolumn _ self addColumn: #keyword1 on: nodeWithNilReceiver.\\n\\t\\\"column borderColor: column compoundBorderColor.\\\"\\n\\tkeywords _ key keywords.\\n\\tkeywords\\n\\t\\twith: (args first: keywords size)\\n\\t\\tdo: [:kwd :arg |\\n\\t\\t\\t(row _ column addRow: #keyword2 on: nodeWithNilReceiver)\\n\\t\\t\\t\\tparseNode: (nodeWithNilReceiver as: MessagePartNode).\\n\\t\\t\\tkwd = 'do:' ifTrue: [\\n\\t\\t\\t\\trow addMorphBack: (row transparentSpacerOfSize: 26@6).\\n\\t\\t\\t] ifFalse: [\\n\\t\\t\\t\\trow addMorphBack: (row transparentSpacerOfSize: 10@6).\\n\\t\\t\\t].\\n\\t\\t\\trow addTokenSpecialCase: kwd\\n\\t\\t\\t\\ttype: #keyword2\\n\\t\\t\\t\\ton: KeyWordNode new.\\n\\t\\t\\t(arg asMorphicSyntaxIn: row) setConditionalPartStyle.\\n\\t\\t].\\n\\t\\t\\t\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'RAA 2/28/2001 10:16'!\\nalanKwdRepeatForDoing: aNode isAConditional: template key: key args: args\\n\\n\\t| nodeWithNilReceiver row column keywords |\\n\\n\\tnodeWithNilReceiver _ aNode copy receiver: nil.\\n\\tcolumn _ self addColumn: #keyword1 on: nodeWithNilReceiver.\\n\\tkeywords _ key keywords.\\n\\tkeywords\\n\\t\\twith: (args first: keywords size)\\n\\t\\tdo: [:kwd :arg |\\n\\t\\t\\t(row _ column addRow: #keyword2 on: nodeWithNilReceiver)\\n\\t\\t\\t\\tparseNode: (nodeWithNilReceiver as: MessagePartNode).\\n\\t\\t\\trow addToken: kwd\\n\\t\\t\\t\\ttype: #keyword2\\n\\t\\t\\t\\ton: KeyWordNode new.\\n\\t\\t\\t(arg asMorphicSyntaxIn: row) setConditionalPartStyle.\\n\\t\\t].\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'FBS 2/24/2004 14:22'!\\nalanKwdSetter2: aNode isAConditional: template key: key args: args\\n\\t\\\"translates\\n\\t\\tfoo setHeading: 0\\n\\tto\\n\\t\\tfoo's heading _ 0\\n\\t\\\"\\n\\t| kwdHolder wordy |\\n\\tkwdHolder _ self\\n\\t\\taddToken: key\\n\\t\\ttype: #keywordSetter\\n\\t\\ton: (SelectorNode new key: key code: nil \\\"fill this in?\\\").\\n\\twordy _ self translateToWordySetter: key.\\n\\tkwdHolder firstSubmorph \\n\\t\\tsetProperty: #syntacticReformatting toValue: #keywordSetter;\\n\\t\\tcontents: wordy;\\n\\t\\temphasis: TextEmphasis bold emphasisCode.\\n\\twordy = key asString ifFalse: [\\n\\t\\tkwdHolder firstSubmorph \\n\\t\\t\\tsetProperty: #syntacticallyCorrectContents toValue: key asString].\\n\\n\\t(args first asMorphicSyntaxIn: self) setConditionalPartStyle\\n\\t\\t\\t\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'FBS 2/24/2004 14:22'!\\nalanKwdSetter: aNode isAConditional: template key: key args: args\\n\\n\\t| nodeWithNilReceiver row kwdHolder |\\n\\n\\tnodeWithNilReceiver _ aNode copy receiver: nil.\\n\\t(row _ self addRow: #keyword2 on: nodeWithNilReceiver)\\n\\t\\tborderWidth: 1;\\n\\t\\tparseNode: (nodeWithNilReceiver as: MessageNode);\\n\\t\\tborderColor: row stdBorderColor.\\n\\trow addNoiseString: '''s' emphasis: TextEmphasis bold emphasisCode.\\n\\tkwdHolder _ row\\n\\t\\taddToken: key\\n\\t\\ttype: #keywordGetz\\n\\t\\ton: (SelectorNode new key: key code: nil \\\"fill this in?\\\").\\n\\tkwdHolder firstSubmorph \\n\\t\\tsetProperty: #syntacticReformatting toValue: #keywordGetz;\\n\\t\\tsetProperty: #syntacticallyCorrectContents toValue: key asString;\\n\\t\\tcontents: (self splitAtCapsAndDownshifted: (key asString allButLast: 5));\\n\\t\\temphasis: TextEmphasis bold emphasisCode.\\n\\trow addNoiseString: '_' emphasis: TextEmphasis bold emphasisCode.\\n\\n\\t(args first asMorphicSyntaxIn: row) setConditionalPartStyle\\n\\t\\t\\t\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'FBS 2/24/2004 14:21'!\\nalanUnaryGetter: aNode key: key\\n\\t\\\"I am a MessageNode. Fill me with a SelectorNode {getX} whose string is {'s x}. All on one level.\\\"\\n\\n\\t| selSyn usm wordy |\\n\\tselSyn _ self\\n\\t\\taddToken: key\\n\\t\\ttype: #unaryGetter\\n\\t\\ton: (SelectorNode new key: key code: nil \\\"fill this in?\\\").\\n\\tusm _ selSyn firstSubmorph.\\n\\tusm setProperty: #syntacticReformatting toValue: #unaryGetter.\\n\\twordy _ self translateToWordyGetter: key.\\n\\twordy = key asString ifFalse: [\\n\\t\\tusm setProperty: #syntacticallyCorrectContents toValue: key asString].\\n\\tusm contents: wordy; emphasis: TextEmphasis bold emphasisCode.\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'RAA 4/4/2001 12:49'!\\nalanUnaryPostRcvr: aNode key: key selector: selector\\n\\n\\t| row |\\n\\n\\t(self isStandardGetterSelector: key) ifTrue: [\\n\\t\\t^self alanUnaryGetter: aNode key: key\\n\\t].\\n\\trow _ (self addUnaryRow: key style: #unary) layoutInset: 1.\\n\\t^ row parseNode: selector\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'dgd 2/22/2003 13:38'!\\nalansMessageNode: aNode receiver: receiver selector: selector keywords: key arguments: args \\n\\t| receiverMorph testAndReceiver anotherSelf wordyMorph template |\\n\\ttemplate := self alansTemplateStyleFor: key.\\n\\treceiver ifNotNil: \\n\\t\\t\\t[\\\"i.e. not a cascade\\\"\\n\\n\\t\\t\\tanotherSelf := self constructSelfVariant: receiver and: key.\\n\\t\\t\\tanotherSelf ifNotNil: \\n\\t\\t\\t\\t\\t[wordyMorph := self addString: anotherSelf special: false.\\n\\t\\t\\t\\t\\twordyMorph setProperty: #wordyVariantOfSelf toValue: true.\\n\\t\\t\\t\\t\\tself addMorph: wordyMorph.\\n\\t\\t\\t\\t\\tself layoutInset: 1.\\n\\t\\t\\t\\t\\t^self].\\n\\t\\t\\ttestAndReceiver := self.\\n\\t\\t\\ttemplate = 1 \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[testAndReceiver := self addRow: #keyword1 on: nil.\\n\\t\\t\\t\\t\\tself setSpecialOuterTestFormat.\\n\\t\\t\\t\\t\\ttestAndReceiver addNoiseString: 'Test'].\\n\\t\\t\\tfalse \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[\\\"template = 2\\\"\\n\\n\\t\\t\\t\\t\\ttestAndReceiver := self addRow: #keyword1 on: nil.\\n\\t\\t\\t\\t\\t\\\"self setSpecialOuterTestFormat.\\\"\\n\\t\\t\\t\\t\\ttestAndReceiver addNoiseString: 'Repeat for'].\\n\\t\\t\\treceiverMorph := receiver asMorphicSyntaxIn: testAndReceiver.\\n\\t\\t\\ttemplate = 1 ifTrue: [receiverMorph setConditionalPartStyle]].\\n\\n\\t\\\"unary messages\\\"\\n\\targs isEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[^self \\n\\t\\t\\t\\talanUnaryPostRcvr: aNode\\n\\t\\t\\t\\tkey: key\\n\\t\\t\\t\\tselector: selector].\\n\\n\\t\\\"binary messages\\\"\\n\\tkey last = $: \\n\\t\\tifFalse: \\n\\t\\t\\t[^self \\n\\t\\t\\t\\talanBinaryPostRcvr: aNode\\n\\t\\t\\t\\tkey: key\\n\\t\\t\\t\\targs: args].\\n\\n\\t\\\"keyword messages\\\"\\n\\treceiverMorph ifNotNil: [receiverMorph setConditionalPartStyle].\\n\\tself setSpecialOuterTestFormat.\\n\\tself \\n\\t\\talanKeywordMessage: aNode\\n\\t\\tisAConditional: template\\n\\t\\tkey: key\\n\\t\\targs: args! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'RAA 2/27/2001 14:19'!\\nassignmentNode: aNode variable: variable value: value\\n\\n\\t| row v expMorph |\\n\\n\\trow _ self addRow: #assignment on: aNode.\\n\\tv _ variable asMorphicSyntaxIn: row.\\n\\tself alansTest1 ifTrue: [v setConditionalPartStyle; layoutInset: 2].\\n\\trow addToken: ' _ ' type: #assignmentArrow on: aNode.\\n\\texpMorph _ value asMorphicSyntaxIn: row.\\n\\tself alansTest1 ifTrue: [\\n\\t\\trow setSpecialOuterTestFormat.\\n\\t\\t(expMorph hasProperty: #deselectedColor) ifFalse: [expMorph setConditionalPartStyle].\\n\\t].\\n\\t^row\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'dgd 2/22/2003 13:39'!\\nblockNode: aNode arguments: arguments statements: statements \\n\\t| row column |\\n\\tcolumn := self addColumn: #block on: aNode.\\n\\tself alansTest1 ifFalse: [column layoutInset: 5 @ -1].\\n\\tself alansTest1 \\n\\t\\tifTrue: \\n\\t\\t\\t[column setProperty: #deselectedBorderColor toValue: self lighterColor].\\n\\taNode addCommentToMorph: column.\\n\\targuments notEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[row := column addRow: #blockarg1 on: BlockArgsNode new.\\n\\t\\t\\trow addNoiseString: self noiseBeforeBlockArg.\\n\\t\\t\\targuments do: \\n\\t\\t\\t\\t\\t[:arg | \\n\\t\\t\\t\\t\\trow \\n\\t\\t\\t\\t\\t\\taddToken: arg name\\n\\t\\t\\t\\t\\t\\ttype: #blockarg2\\n\\t\\t\\t\\t\\t\\ton: arg]].\\n\\tstatements do: \\n\\t\\t\\t[:each | \\n\\t\\t\\t(row := each asMorphicSyntaxIn: column) borderWidth: 1.\\n\\t\\t\\tself alansTest1 ifTrue: [row setSpecialOuterTestFormat].\\n\\t\\t\\teach addCommentToMorph: column].\\n\\t^column! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'FBS 2/24/2004 14:32'!\\nblockNodeCollect: aNode arguments: arguments statements: statements \\n\\t| row column c2 r2 r3 |\\n\\tcolumn := self addColumn: #blockCollectOnly on: aNode.\\n\\tself alansTest1 ifFalse: [column layoutInset: 5 @ -1].\\n\\taNode addCommentToMorph: column.\\n\\targuments notEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[row := column addRow: #blockarg1 on: BlockArgsNode new.\\n\\t\\t\\trow addNoiseString: 'collect using' emphasis: TextEmphasis bold emphasisCode.\\n\\t\\t\\tr3 := row addRow: #blockarg1b on: nil.\\t\\\"aNode\\\"\\n\\t\\t\\tr3 setConditionalPartStyle.\\n\\t\\t\\targuments do: \\n\\t\\t\\t\\t\\t[:arg | \\n\\t\\t\\t\\t\\tr3 \\n\\t\\t\\t\\t\\t\\taddToken: arg name\\n\\t\\t\\t\\t\\t\\ttype: #blockarg2\\n\\t\\t\\t\\t\\t\\ton: arg]].\\n\\tr2 := column addRow: #block on: aNode.\\n\\tr2 setProperty: #ignoreNodeWhenPrinting toValue: true.\\n\\tr2 addNoiseString: self noiseBeforeBlockArg emphasis: TextEmphasis bold emphasisCode.\\n\\tc2 := r2 addColumn: #block on: aNode.\\n\\tc2 setProperty: #ignoreNodeWhenPrinting toValue: true.\\n\\tstatements do: \\n\\t\\t\\t[:each | \\n\\t\\t\\t(each asMorphicSyntaxIn: c2) borderWidth: 1.\\n\\t\\t\\teach addCommentToMorph: c2].\\n\\t^column! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'RAA 2/22/2001 17:00'!\\ncascadeNode: aNode receiver: receiver messages: messages\\n\\t| row |\\n\\n\\tself alansTest1 ifTrue: [\\n\\t\\trow _ self addColumn: #cascade on: aNode.\\n\\t\\trow setSpecialOuterTestFormat.\\n\\t] ifFalse: [\\n\\t\\trow _ self addRow: #cascade on: aNode\\n\\t].\\n\\treceiver asMorphicSyntaxIn: row.\\n\\tmessages do: [:m | m asMorphicSyntaxIn: row].\\n\\t^ row\\n\\n\\\"\\t(node2 _ aNode copy) receiver: nil messages: messages.\\n\\tcascadeMorph _ row addColumn: #cascade2 on: node2.\\n\\tmessages do: [ :m | m asMorphicSyntaxIn: cascadeMorph].\\n\\t^row\\n\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'RAA 2/16/2001 16:34'!\\nchangeBasicStyle\\n\\n\\tself removeAllMorphs.\\n\\tself setProperty: #alansNewStyle toValue: self alansTest1 not.\\n\\tself methodNodeOuter: parseNode\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'gm 2/22/2003 13:42'!\\nfinalAppearanceTweaks\\n\\t| deletes lw |\\n\\tSizeScaleFactor ifNil: [SizeScaleFactor := 0.15].\\n\\tSizeScaleFactor := 0.0.\\t\\\"disable this feature. Default was for giant tiles\\\"\\n\\tself usingClassicTiles \\n\\t\\tifTrue: \\n\\t\\t\\t[self \\n\\t\\t\\t\\tallMorphsDo: [:each | (each isSyntaxMorph) ifTrue: [each lookClassic]].\\n\\t\\t\\t^self].\\n\\tdeletes := OrderedCollection new.\\n\\tself allMorphsDo: \\n\\t\\t\\t[:each | \\n\\t\\t\\t(each respondsTo: #setDeselectedColor) ifTrue: [each setDeselectedColor].\\n\\t\\t\\t\\\"(each hasProperty: #variableInsetSize) ifTrue: [\\n\\t\\t\\teach layoutInset: \\n\\t\\t\\t\\t((each valueOfProperty: #variableInsetSize) * SizeScaleFactor) rounded].\\\"\\n\\t\\t\\teach isSyntaxMorph \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[lw := each layoutInset.\\n\\t\\t\\t\\t\\tlw isPoint ifTrue: [lw := lw x].\\n\\t\\t\\t\\t\\teach layoutInset: lw @ 0\\t\\\"(6 * SizeScaleFactor) rounded\\\"]].\\n\\tdeletes do: [:each | each delete]! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'yo 11/11/2002 10:30'!\\nisStandardGetterSelector: key\\n\\n\\tself flag: #yoCharCases.\\n\\n\\tkey size > 3 ifFalse: [^false].\\n\\t(key beginsWith: 'get') ifFalse: [^false].\\n\\tkey fourth isUppercase ifFalse: [^false].\\n\\t^true\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'yo 11/11/2002 10:31'!\\nisStandardSetterKeyword: key\\n\\n\\tself flag: #yoCharCases.\\n\\n\\tkey size > 4 ifFalse: [^false].\\n\\t(key endsWith: ':') ifFalse: [^false].\\n\\t(key beginsWith: 'set') ifFalse: [^false].\\n\\tkey fourth isUppercase ifFalse: [^false].\\n\\t^true\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'dgd 2/22/2003 13:39'!\\nmessageNode: aNode receiver: receiver selector: selector keywords: key arguments: args \\n\\t| keywords column row receiverMorph receiverWidth messageWidth onlyOne nodeWithNilReceiver isAConditional |\\n\\tself alansTest1 \\n\\t\\tifTrue: \\n\\t\\t\\t[^self \\n\\t\\t\\t\\talansMessageNode: aNode\\n\\t\\t\\t\\treceiver: receiver\\n\\t\\t\\t\\tselector: selector\\n\\t\\t\\t\\tkeywords: key\\n\\t\\t\\t\\targuments: args].\\n\\tisAConditional := #(#ifTrue: #ifFalse: #ifTrue:ifFalse: #ifFalse:ifTrue:) \\n\\t\\t\\t\\tincludes: key.\\n\\treceiver ifNotNil: \\n\\t\\t\\t[\\\"i.e. not a cascade\\\"\\n\\n\\t\\t\\treceiverMorph := receiver asMorphicSyntaxIn: self].\\n\\tkeywords := key keywords.\\n\\targs isEmpty \\n\\t\\tifTrue: \\n\\t\\t\\t[row := (self addSingleKeywordRow: key) layoutInset: 1.\\n\\t\\t\\t^row parseNode: selector].\\n\\treceiverWidth := receiver ifNil: [0]\\n\\t\\t\\t\\tifNotNil: [receiverMorph fullBounds width].\\n\\tonlyOne := args size = 1.\\n\\t(receiverWidth <= 80 and: [onlyOne]) \\n\\t\\tifTrue: \\n\\t\\t\\t[self \\n\\t\\t\\t\\tmessageOneArg: key\\n\\t\\t\\t\\treceiver: receiver\\n\\t\\t\\t\\tselector: selector\\n\\t\\t\\t\\targs: args.\\n\\t\\t\\t^self].\\n\\tnodeWithNilReceiver := aNode copy receiver: nil.\\n\\tcolumn := self addColumn: #keyword1 on: nodeWithNilReceiver.\\n\\t\\\"onlyOne ifTrue: [column parseNode: nil].\\tis a spacer\\\"\\n\\tmessageWidth := 0.\\n\\tkeywords with: (args copyFrom: 1 to: keywords size)\\n\\t\\tdo: \\n\\t\\t\\t[:kwd :arg | \\n\\t\\t\\tisAConditional \\n\\t\\t\\t\\tifTrue: [column addMorphBack: (column transparentSpacerOfSize: 3 @ 3)].\\n\\t\\t\\t(row := column addRow: #keyword2 on: nodeWithNilReceiver)\\n\\t\\t\\t\\tborderWidth: 1;\\n\\t\\t\\t\\tparseNode: (nodeWithNilReceiver \\n\\t\\t\\t\\t\\t\\t\\tas: (onlyOne ifTrue: [MessageNode] ifFalse: [MessagePartNode]));\\n\\t\\t\\t\\tborderColor: row stdBorderColor.\\n\\t\\t\\tisAConditional \\n\\t\\t\\t\\tifTrue: [row addMorphBack: (row transparentSpacerOfSize: 20 @ 6)].\\n\\t\\t\\trow \\n\\t\\t\\t\\taddToken: kwd\\n\\t\\t\\t\\ttype: #keyword2\\n\\t\\t\\t\\ton: (onlyOne \\n\\t\\t\\t\\t\\t\\tifTrue: [SelectorNode new key: kwd code: nil\\t\\\"fill this in?\\\"]\\n\\t\\t\\t\\t\\t\\tifFalse: [KeyWordNode new]).\\n\\t\\t\\targ asMorphicSyntaxIn: row.\\n\\t\\t\\tmessageWidth := messageWidth + row fullBounds width].\\n\\tonlyOne \\n\\t\\tifTrue: \\n\\t\\t\\t[self replaceSubmorph: column by: row.\\n\\t\\t\\tcolumn := row].\\n\\treceiverMorph ifNil: [^self].\\n\\treceiverWidth + messageWidth < 350 \\n\\t\\tifTrue: \\n\\t\\t\\t[isAConditional ifFalse: [self unfoldMessage].\\n\\t\\t\\t^self].\\n\\t((receiverWidth > 200 \\n\\t\\tor: [receiverWidth > 80 and: [column fullBounds height > 20]]) or: \\n\\t\\t\\t\\t[receiverMorph fullBounds width > 30 \\n\\t\\t\\t\\t\\tand: [column fullBounds height > 100 or: [column fullBounds width > 250]]]) \\n\\t\\tifTrue: [^self foldMessage]! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'RAA 2/26/2001 14:04'!\\nmessageOneArg: key receiver: receiver selector: selector args: args\\n\\n\\t| row firstArgMorph |\\n\\n\\trow _ (self addSingleKeywordRow: key) layoutInset: 1.\\n\\trow parseNode: selector.\\n\\tfirstArgMorph _ args first asMorphicSyntaxIn: self.\\n\\treceiver ifNil: [^ self].\\n\\t(firstArgMorph fullBounds height > 100\\n\\t\\t\\tor: [firstArgMorph fullBounds width > 250])\\n\\t\\tifTrue: [self foldMessageOneArg].\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'RAA 2/26/2001 17:12'!\\nmethodNodeInner: aNode selectorOrFalse: selectorOrFalse precedence: precedence arguments: arguments temporaries: temporaries primitive: primitive block: block\\n\\t| header selNode |\\n\\n\\tselNode _ selectorOrFalse class == SelectorNode \\n\\t\\tifTrue: [selectorOrFalse] \\n\\t\\tifFalse: [SelectorNode new key: selectorOrFalse code: nil].\\n\\theader _ self addRow: Color white on: selNode.\\n\\tprecedence = 1\\n\\t\\tifTrue: [header addToken: aNode selector type: #methodHeader1 on: selNode]\\n\\t\\tifFalse: [aNode selector keywords with: arguments do:\\n\\t\\t\\t\\t\\t[:kwd :arg | \\n\\t\\t\\t\\t\\theader addToken: kwd type: #methodHeader2 on: selNode.\\n\\t\\t\\t\\t\\t(arg asMorphicSyntaxIn: header) color: #blockarg2]].\\n\\taNode addCommentToMorph: self.\\n\\tself addTemporaries: temporaries.\\n\\t(primitive > 0 and: [(primitive between: 255 and: 519) not]) ifTrue:\\n\\t\\t[\\\"Dont decompile <prim> for, eg, ^ self \\\"\\n\\t\\tself addTextRow: (String streamContents: [ :strm | aNode printPrimitiveOn: strm])].\\n\\tblock asMorphicSyntaxIn: self.\\n\\t^ self\\n! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'tk 7/31/2001 17:37'!\\nmethodNodeOuter: aNode\\n\\n\\t| block |\\n\\t\\n\\tself borderWidth: 0.\\n\\taNode asMorphicSyntaxIn: self.\\n\\tself alansTest1 ifTrue: [self addTemporaryControls].\\n\\tself finalAppearanceTweaks.\\n\\t\\t\\\"self setProperty: #deselectedColor toValue: Color transparent.\\\"\\n\\tblock _ self findA: BlockNode.\\n\\t\\t\\\"block setProperty: #deselectedColor toValue: Color transparent.\\\"\\n\\tblock submorphs size = 1 ifTrue: [^ self].\\t\\\"keep '^ self' if that is the only thing in method\\\"\\n\\tblock submorphs last decompile string = '^ self ' ifTrue: [\\n\\t\\tblock submorphs last delete].\\n\\t^ self! !\\n\\n!SyntaxMorph methodsFor: 'node to morph' stamp: 'RAA 2/15/2001 19:49'!\\nvanillaMessageNode: aNode receiver: receiver selector: selector arguments: arguments\\n\\n\\t| substitute row sel |\\n\\tsel _ #message.\\n\\t((self nodeClassIs: CascadeNode) and: [self parseNode receiver ~~ aNode]) ifTrue: [\\n\\t\\tsel _ #keyword2.\\n\\t\\treceiver ifNotNil: [self inform: 'receiver should be nil']].\\n\\trow _ self addRow: sel on: aNode.\\n\\tsubstitute _ aNode as: TileMessageNode.\\n\\t(aNode macroPrinter == #printCaseOn:indent:) ifTrue: [\\n\\t\\taNode asMorphicCaseOn: row indent: nil.\\n\\t\\t^ self].\\n\\taNode macroPrinter\\n\\t\\tifNotNil: \\n\\t\\t\\t[substitute perform: aNode macroPrinter with: row with: nil]\\n\\t\\tifNil: \\n\\t\\t\\t[substitute \\n\\t\\t\\t\\tprintKeywords: selector key\\n\\t\\t\\t\\targuments: arguments\\n\\t\\t\\t\\ton: row\\n\\t\\t\\t\\tindent: nil].\\n\\t^ row addTransparentSpacerOfSize: 3@0.\\t\\\"horizontal spacing only\\\"\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'RAA 2/14/2001 20:34'!\\nimmediatelyBelowTheMethodNode\\n\\n\\t^(owner respondsTo: #isMethodNode) and: [owner isMethodNode]! !\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'tk 8/24/2001 15:41'!\\nisAVariable\\n\\t\\\"There are three kinds of variable nodes\\\"\\n\\n\\t((parseNode class == TempVariableNode) or: [\\n\\t\\t(parseNode class == LiteralVariableNode) or: [\\n\\t\\t\\tparseNode class == VariableNode]]) ifFalse: [^ false].\\n\\t^ (ClassBuilder new reservedNames includes: \\n\\t\\t\\tself decompile string withoutTrailingBlanks) not! !\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'di 11/17/2000 08:31'!\\nisBlockNode\\n\\t^ parseNode class == BlockNode! !\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'tk 9/26/2001 05:50'!\\nisDeclaration\\n\\t\\\"Return true if I am a TempVarNode inside a declaration of some kind, including a method arg\\\"\\n\\n\\t| opc |\\n\\towner isSyntaxMorph ifFalse: [^ false].\\n\\topc _ owner parseNode class.\\n\\topc == BlockArgsNode ifTrue: [^ true].\\n\\topc == MethodTempsNode ifTrue: [^ true].\\n\\topc == SelectorNode ifTrue: [^ true].\\n\\t^ false! !\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'gm 2/22/2003 12:30'!\\nisLeafTile\\n\\tself hasSubmorphs ifFalse: [^false].\\n\\t(self firstSubmorph isSyntaxMorph) ifTrue: [^false].\\n\\t(self firstSubmorph isMemberOf: Morph) ifTrue: [^false].\\n\\t^true! !\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'di 11/17/2000 08:31'!\\nisMethodNode\\n\\t^ parseNode class == MethodNode! !\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'tk 9/13/2001 15:28'!\\nisNoun\\n\\t\\\"Consider these to be nouns: MessageNode with receiver, CascadeNode with receiver, AssignmentNode, TempVariableNode, LiteralNode, VariableNode, LiteralVariableNode.\\\"\\n\\n\\t(#(TempVariableNode LiteralNode VariableNode LiteralVariableNode) includes:\\n\\t\\t(parseNode class name)) ifTrue: [^ true].\\n\\n\\t(self nodeClassIs: MessageNode) ifTrue: [^ parseNode receiver notNil].\\n\\t(self nodeClassIs: CascadeNode) ifTrue: [^ parseNode receiver notNil].\\n\\t(self nodeClassIs: AssignmentNode) ifTrue: [^ submorphs size >= 3].\\n\\n\\t^ false! !\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'tk 9/23/2001 00:17'!\\nisSelfTile\\n\\n\\t^ parseNode class == VariableNode and: [self decompile asString = 'self ']\\n\\t! !\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'di 11/6/2000 15:26'!\\nnodeClassIs: aParseNodeClass\\n\\t\\\"Test the class of my parseNode\\\"\\n\\n\\t^ parseNode class == aParseNodeClass! !\\n\\n!SyntaxMorph methodsFor: 'node types' stamp: 'dgd 2/22/2003 13:40'!\\nrootTile\\n\\t^self \\n\\t\\torOwnerSuchThat: [:m | m owner isNil or: [m owner isSyntaxMorph not]]! !\\n\\n\\n!SyntaxMorph methodsFor: 'player' stamp: 'tk 9/26/2001 06:05'!\\ncurrentDataValue\\n\\t\\\"Answer the current data value held by the receiver\\\"\\n\\n\\t^ self readOut valueFromContents! !\\n\\n!SyntaxMorph methodsFor: 'player' stamp: 'tk 2/15/2002 13:03'!\\nvariableDocks\\n\\t\\\"Answer a list of VariableDock objects for docking up my data with an instance held in my containing playfield. For a numeric-readout tile.\\\"\\n\\n\\t\\\"Is CardPlayer class holding my variableDock, or should I be using the caching mechanism in Morph>>variableDocks?\\\"\\n\\t| updatingString lab nn aGetter |\\n\\t(updatingString _ self readOut) ifNil: [^ #()].\\n\\tupdatingString getSelector ifNil: [\\n\\t\\tlab _ self submorphNamed: 'label' ifNone: [self defaultName].\\n\\t\\tnn _ lab contents asString.\\n\\t\\t\\\"nn at: 1 put: nn first asUppercase.\\\"\\n\\t\\tupdatingString getSelector: (aGetter _ 'get',nn) asSymbol;\\n\\t\\t\\tputSelector: (ScriptingSystem setterSelectorForGetter: aGetter).\\n\\t\\t].\\n\\t^ Array with: (VariableDock new \\n\\t\\t\\tvariableName: (updatingString getSelector allButFirst: 3) withFirstCharacterDownshifted \\n\\t\\t\\ttype: #number \\n\\t\\t\\tdefiningMorph: updatingString \\n\\t\\t\\tmorphGetSelector: #valueFromContents \\n\\t\\t\\tmorphPutSelector: #acceptValue:)! !\\n\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'aoy 2/15/2003 21:30'!\\naddArg: index \\n\\t\\\"I rep a SelectorNode. My string has been replaced. Append an argument to my owner.\\\"\\n\\n\\t\\\"See if any sample args are recorded\\\"\\n\\n\\t| sel rec aVocabulary mi sample descrip mthNode tiles |\\n\\tsel := self decompile asString asSymbol.\\n\\trec := self receiverObject.\\n\\tsample := rec class == Error \\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[aVocabulary := self vocabularyToUseWith: rec.\\n\\t\\t\\t\\t\\tmi := aVocabulary methodInterfaceAt: sel ifAbsent: [nil].\\n\\t\\t\\t\\t\\tmi ifNil: [5]\\n\\t\\t\\t\\t\\t\\tifNotNil: \\n\\t\\t\\t\\t\\t\\t\\t[descrip := mi argumentVariables at: index.\\n\\t\\t\\t\\t\\t\\t\\tdescrip sample]]\\n\\t\\t\\t\\tifTrue: [5]. \\n\\tmthNode := self string: sample storeString toTilesIn: sample class.\\n\\ttiles := mthNode submorphs at: mthNode submorphs size - 1.\\t\\\"before the ^ self\\\"\\n\\tself owner addMorphBack: tiles! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 8/24/2001 13:24'!\\nassignmentArrow\\n\\t\\\"Offer to embed this variable in a new assignment statement. (Don't confuse this with upDownAssignment:, which runs the up and down arrows that rotate among assignment types.)\\\"\\n\\t| rr |\\n\\n\\tself isAVariable ifFalse: [^ nil].\\n\\tself isDeclaration ifTrue: [^ nil].\\n\\t^ (rr _ RectangleMorph new)\\n\\t\\textent: 11@13; borderWidth: 1; color: Color lightGreen;\\n\\t\\tborderColor: Color gray;\\n\\t\\taddMorph: ((self noiseStringMorph: '_') topLeft: rr topLeft + (3@0));\\n\\t\\ton: #mouseUp send: #newAssignment to: self\\n! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'gk 2/23/2004 21:08'!\\nchangeSound: upDown\\n\\t| ind arg st soundChoices index it current |\\n\\t\\\"move in the list of sounds. Adjust arg tile after me\\\"\\n\\n\\tind _ owner submorphs indexOf: self.\\n\\targ _ owner submorphs atWrap: ind+1.\\n\\targ isSyntaxMorph ifFalse: [^ self].\\n\\tst _ arg submorphs detect: [:mm | mm isKindOf: StringMorph] ifNone: [^ self].\\n\\tsoundChoices _ SoundService default sampledSoundChoices.\\n\\tcurrent _ st contents copyFrom: 2 to: st contents size-1.\\t\\\"remove string quotes\\\"\\n\\tindex _ soundChoices indexOf: current.\\n\\tindex > 0 ifTrue:\\n\\t\\t[st contents: (it _ soundChoices atWrap: index + upDown) printString.\\n\\t\\tself playSoundNamed: it].\\n! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 8/26/2001 14:31'!\\ncolorPatch\\n\\t\\\"Return a color patch button that lets the user choose a color and modifies the code\\\"\\n\\t| cc patch sel completeMsg |\\n\\t\\n\\t\\n\\t((self nodeClassIs: MessageNode) \\\"or: [self nodeClassIs: SelectorNode]\\\") ifFalse: [^ nil].\\n\\t(sel _ self selector) ifNil: [^ nil].\\n\\t(Color colorNames includes: sel) | (sel == #r:g:b:) ifFalse: [^ nil].\\n\\t\\t\\\"a standard color name\\\"\\n\\tcompleteMsg _ self isNoun ifTrue: [self] \\n\\t\\t\\t\\tifFalse: [owner isNoun ifTrue: [owner] ifFalse: [owner owner]].\\n\\n\\t(cc _ completeMsg try) class == Color ifFalse: [^ nil].\\n\\tpatch _ ColorTileMorph new colorSwatchColor: cc.\\n\\t\\t\\\"sends colorChangedForSubmorph: to the messageNode\\\"\\n\\tpatch color: Color transparent; borderWidth: 0. patch submorphs last delete.\\n\\t^ patch! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 2/21/2001 16:37'!\\ndeleteLine\\n\\t| temp |\\n\\ttemp _ owner.\\n\\tself deletePopup.\\n\\tself delete.\\n\\ttemp setSelection: nil.\\n\\ttemp acceptIfInScriptor.! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'di 12/13/2000 13:05'!\\ndeletePopup\\n\\n\\tself valueOfProperty: #myPopup ifPresentDo:\\n\\t\\t[:panel | panel delete. self removeProperty: #myPopup]! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 2/21/2001 13:09'!\\ndismisser\\n\\t\\\"Return the icon to delete this line of tiles. I am an entire line in a block.\\\"\\n\\t| handle handleSpec colorToUse iconName form |\\n\\n\\t(owner isSyntaxMorph and: [owner nodeClassIs: BlockNode]) ifFalse: [^ nil].\\n\\thandleSpec _ Preferences haloSpecifications fourth.\\t\\\"dismiss\\\"\\n\\thandle _ EllipseMorph\\n\\t\\t\\tnewBounds: (Rectangle center: 10@10 extent: 16 asPoint)\\n\\t\\t\\tcolor: (colorToUse _ Color colorFrom: handleSpec color).\\n\\ticonName _ handleSpec iconSymbol.\\n\\tform _ ScriptingSystem formAtKey: iconName.\\t\\\"#'Halo-Dismiss'\\\"\\n\\thandle addMorphCentered: (ImageMorph new\\n\\t\\t\\t\\timage: form; \\n\\t\\t\\t\\tcolor: colorToUse makeForegroundColor;\\n\\t\\t\\t\\tlock).\\n\\thandle on: #mouseDown send: #deleteLine to: self.\\n\\t^ handle! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 10/17/2001 13:38'!\\ndupTile: evt\\n\\n\\t| dup |\\n\\tself deletePopup.\\n\\t\\\"self deselect.\\\"\\n\\tdup _ self duplicateMorph: evt.\\n\\tPreferences tileTranslucentDrag\\n\\t\\tifTrue: [dup align: dup center with: evt hand position.\\n\\t\\t\\t\\tdup lookTranslucent]\\n\\t\\tifFalse: [dup align: dup topLeft\\n\\t\\t\\t\\t\\twith: evt hand position + self cursorBaseOffset].\\n! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 10/17/2001 13:29'!\\nduplicator\\n\\t\\\"Return the icon to duplicate this tile.\\\"\\n\\t| handle handleSpec colorToUse iconName form |\\n\\n\\thandleSpec _ Preferences haloSpecifications at: 11.\\t\\\"duplicate\\\"\\n\\thandle _ EllipseMorph\\n\\t\\t\\tnewBounds: (Rectangle center: 10@10 extent: 16 asPoint)\\n\\t\\t\\tcolor: (colorToUse _ Color colorFrom: handleSpec color).\\n\\ticonName _ handleSpec iconSymbol.\\n\\tform _ ScriptingSystem formAtKey: iconName.\\t\\\"#'Halo-Dup'\\\"\\n\\thandle addMorphCentered: (ImageMorph new\\n\\t\\t\\t\\timage: form; \\n\\t\\t\\t\\tcolor: colorToUse makeForegroundColor;\\n\\t\\t\\t\\tlock).\\n\\thandle on: #mouseDown send: #dupTile: to: self.\\n\\t^ handle! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'ar 3/18/2001 17:28'!\\nevent: arg1 arrow: arg2 upDown: arg3\\n\\t\\\"Reorder the arguments for existing event handlers\\\"\\n\\t(arg3 isMorph and:[arg3 eventHandler notNil]) ifTrue:[arg3 eventHandler fixReversedValueMessages].\\n\\t^self upDown: arg1 event: arg2 arrow: arg3! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 9/28/2001 13:38'!\\nextend\\n\\t| messageNodeMorph first |\\n\\t\\\"replace this noun with a new message like (arg + 1). If type is not known, ask the user to type in a selector. Use nil as arg. Let user drag something to it afterwards.\\\"\\n\\n\\t\\\"Later do evaluation of self to see what type and offer right selector\\\"\\n\\tself deselect.\\n\\tmessageNodeMorph _ (MessageSend receiver: 1 selector: #+ arguments: #(1))\\n\\t\\t\\t\\t\\t\\t\\t\\tasTilesIn: Player globalNames: false.\\n\\towner replaceSubmorph: self by: messageNodeMorph.\\n\\tfirst _ messageNodeMorph submorphs detect: [:mm | mm isSyntaxMorph].\\n\\tmessageNodeMorph replaceSubmorph: first by: self.\\n\\tself acceptIfInScriptor.! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 8/24/2001 13:14'!\\nextendArrow\\n\\t\\\"Return the extend arrow button. It replaces the argument with a new message.\\n\\tI am a number or getter messageNode.\\\"\\n\\t| patch |\\n\\t\\n\\tself isNoun ifFalse: [^ nil].\\n\\tself isDeclaration ifTrue: [^ nil].\\n\\tpatch _ (ImageMorph new image: (TileMorph classPool at: #SuffixPicture)).\\n\\tpatch on: #mouseDown send: #extend to: self.\\n\\t^ patch! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 9/28/2001 11:35'!\\nnewAssignment\\n\\t\\\"I am a variableNode. Place me inside an assignment statement.\\\"\\n\\n\\t| new old |\\n\\tparseNode name: self decompile.\\t\\\"in case user changed name\\\"\\n\\tnew _ owner assignmentNode: AssignmentNode new variable: parseNode \\n\\t\\t\\t\\t\\tvalue: parseNode copy.\\n\\tself deselect.\\n\\t(old _ owner) replaceSubmorph: self by: new.\\t\\\"do the normal replacement\\\"\\n\\t(old isSyntaxMorph) ifTrue: [old cleanupAfterItDroppedOnMe].\\t\\\"now owned by no one\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'dgd 2/22/2003 13:40'!\\nofferPopUp\\n\\t\\\"Put up a halo to allow user to change\\n\\t\\tLiterals (Integer, true),\\n\\t\\tSelector (beep: sound, +,-,*,//,\\\\\\\\, r:g:b:, setX: incX: decX: for any X,),\\n\\t\\tVariable (Color),\\n\\t\\tnot AssignmentNode (_ inc dec),\\n\\tExtend arrows on each literal, variable, and message, (block that is by itself).\\n\\tRetract arrows on each literal or variable, or message or block that is an argument.\\n\\tAny literal can be changed by Shift-clicking and typing.\\\"\\n\\n\\t| panel any upDown retract extend colorPatch edge dismiss rr duplicate |\\n\\t(self hasProperty: #myPopup) ifTrue: [^self].\\t\\\"already has one\\\"\\n\\tany := false.\\n\\t(upDown := self upDownArrows) ifNotNil: [any := true].\\t\\\"includes menu of selectors\\\"\\n\\t(retract := self retractArrow) ifNotNil: [any := true].\\n\\t(extend := self extendArrow) ifNotNil: [any := true].\\n\\t(dismiss := self dismisser) ifNotNil: [any := true].\\n\\t(duplicate := self duplicator) ifNotNil: [any := true].\\n\\t\\\"(assign _ self assignmentArrow) ifNotNil: [any _ true].\\n\\t\\t\\tget from menu or any other assignment\\\"\\n\\tsubmorphs last class == ColorTileMorph \\n\\t\\tifFalse: [(colorPatch := self colorPatch) ifNotNil: [any := true]].\\n\\tany ifFalse: [^self].\\n\\t\\\"Transcript cr; print: parseNode class; space; \\n\\t\\tprint: (self hasProperty: #myPopup); endEntry.\\\"\\n\\tpanel := (RectangleMorph new)\\n\\t\\t\\t\\tcolor: Color transparent;\\n\\t\\t\\t\\tborderWidth: 0.\\n\\tupDown ifNotNil: \\n\\t\\t\\t[panel addMorphBack: upDown first.\\n\\t\\t\\tupDown first align: upDown first topLeft with: panel topLeft + (0 @ 0).\\n\\t\\t\\tpanel addMorphBack: upDown second.\\n\\t\\t\\tupDown second align: upDown second topLeft\\n\\t\\t\\t\\twith: upDown first bottomLeft + (0 @ 1).\\n\\t\\t\\tupDown size > 2 \\n\\t\\t\\t\\tifTrue: \\n\\t\\t\\t\\t\\t[panel addMorphBack: upDown third.\\n\\t\\t\\t\\t\\tupDown third align: upDown third topLeft\\n\\t\\t\\t\\t\\t\\twith: upDown first topRight + (2 @ 3)]].\\n\\trr := self right.\\n\\tcolorPatch ifNotNil: \\n\\t\\t\\t[rr := rr + colorPatch submorphs first width + 1.\\n\\t\\t\\tself addMorphBack: colorPatch\\t\\\"always in tile\\\"\\n\\t\\t\\t\\\"colorPatch align: colorPatch topLeft \\n\\t\\t\\t\\t\\twith: panel topLeft + (1@1)\\\"].\\n\\tretract ifNotNil: \\n\\t\\t\\t[edge := panel submorphs isEmpty \\n\\t\\t\\t\\t\\t\\tifTrue: [panel left]\\n\\t\\t\\t\\t\\t\\tifFalse: [panel submorphs last right].\\n\\t\\t\\tpanel addMorphBack: retract.\\n\\t\\t\\tretract align: retract topLeft with: (edge + 2) @ (panel top + 3)].\\n\\textend ifNotNil: \\n\\t\\t\\t[edge := panel submorphs isEmpty \\n\\t\\t\\t\\t\\t\\tifTrue: [panel left]\\n\\t\\t\\t\\t\\t\\tifFalse: [panel submorphs last right].\\n\\t\\t\\tpanel addMorphBack: extend.\\n\\t\\t\\textend align: extend topLeft with: (edge + 2) @ (panel top + 3)].\\n\\tduplicate ifNotNil: \\n\\t\\t\\t[edge := panel submorphs isEmpty \\n\\t\\t\\t\\t\\t\\tifTrue: [panel left]\\n\\t\\t\\t\\t\\t\\tifFalse: [panel submorphs last right].\\n\\t\\t\\tpanel addMorphBack: duplicate.\\n\\t\\t\\tduplicate align: duplicate topLeft with: (edge + 2) @ (panel top + 1)].\\n\\tdismiss ifNotNil: \\n\\t\\t\\t[edge := panel submorphs isEmpty \\n\\t\\t\\t\\t\\t\\tifTrue: [panel left]\\n\\t\\t\\t\\t\\t\\tifFalse: [panel submorphs last right].\\n\\t\\t\\tpanel addMorphBack: dismiss.\\n\\t\\t\\tdismiss align: dismiss topLeft with: (edge + 2) @ (panel top + 1)].\\n\\t\\\"\\tassign ifNotNil: [\\n\\t\\tedge _ panel submorphs isEmpty \\n\\t\\t\\tifTrue: [panel left] \\n\\t\\t\\tifFalse: [panel submorphs last right].\\n\\t\\tpanel addMorphBack: assign.\\n\\t\\tassign align: assign topLeft with: (edge+2) @ (panel top + 2)].\\n\\\"\\n\\tpanel align: panel topLeft with: rr @ (self top - 2).\\n\\tpanel extent: panel submorphs last bottomRight - panel topLeft.\\n\\tself setProperty: #myPopup toValue: panel.\\n\\tself addMorphBack: panel\\t\\\"Any reason ever to have panel below?\\\"\\n\\t\\\"(owner listDirection = #topToBottom and: [self listDirection = #leftToRight])\\n\\t\\tifTrue: [self addMorphBack: panel]\\n\\t\\tifFalse: [owner addMorph: panel after: self].\\\"! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 9/28/2001 13:39'!\\nreplaceKeyWord: evt menuItem: stringMorph\\n\\t\\\"Replace my entire message (which may be multi-part) with the one specified. Preserve all argument tiles, either in the new message or in the world outside the scriptor. I am a SelectorNode or KeyWordNode.\\\"\\n\\n\\t| menu new news newSel mm newTree newRec newArgs top oldArgNodes share ctrY |\\n\\t(menu _ stringMorph owner owner) class == RectangleMorph ifTrue: [\\n\\t\\tmenu delete].\\n\\tnew _ stringMorph contents.\\n\\tnew first = $( ifTrue: [^ self].\\t\\\"Cancel\\\"\\n\\tnew first = $ ifTrue: [^ self].\\t\\\"nothing\\\"\\n\\tnews _ String streamContents: [:strm | \\\"remove fake args\\\"\\n\\t\\t(new findBetweenSubStrs: #(' 5' $ )) do: [:part | strm nextPutAll: part]].\\n\\tnewSel _ stringMorph valueOfProperty: #syntacticallyCorrectContents.\\n\\tnewSel ifNil: [newSel _ news].\\n\\tmm _ MessageSend receiver: 5 selector: newSel \\n\\t\\t\\targuments: ((Array new: newSel numArgs) atAllPut: 5).\\n\\tnewTree _ mm asTilesIn: Object globalNames: false.\\n\\tnewRec _ newTree receiverNode.\\n\\tnewArgs _ newTree argumentNodes.\\n\\tctrY _ self fullBoundsInWorld center y.\\n\\ttop _ self messageNode.\\n\\tnewRec owner replaceSubmorph: newRec by: top receiverNode.\\n\\toldArgNodes _ top argumentNodes.\\n\\tshare _ newArgs size min: oldArgNodes size.\\n\\t(newArgs first: share) with: (oldArgNodes first: share) do: [:newNode :oldNode | \\n\\t\\tnewNode owner replaceSubmorph: newNode by: oldNode].\\n\\t\\\"later get nodes for objects of the right type for new extra args\\\"\\n\\n\\ttop owner replaceSubmorph: top by: newTree.\\n\\n\\t\\\"Deposit extra args in the World\\\"\\n\\t(oldArgNodes copyFrom: share+1 to: oldArgNodes size) do: [:leftOver |\\n\\t\\t(leftOver parseNode class == LiteralNode and: [leftOver decompile asString = '5']) \\n\\t\\t\\tifFalse: [newTree pasteUpMorph addMorphFront: leftOver.\\n\\t\\t\\t\\tleftOver position: newTree enclosingPane fullBoundsInWorld right - 20 @ ctrY.\\n\\t\\t\\t\\tctrY _ ctrY + 26]\\n\\t\\t\\tifTrue: [leftOver delete]].\\n\\tnewTree acceptIfInScriptor.! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 9/19/2001 21:32'!\\nreplaceSel: evt menuItem: stringMorph\\n\\t\\\"I rep a SelectorNode. Replace my selector with new one that was just chosen from a menu\\\"\\n\\n\\t| menu new old newSel ms oa na case news |\\n\\t(menu _ stringMorph owner owner) class == RectangleMorph ifTrue: [\\n\\t\\tmenu delete].\\n\\tnew _ stringMorph contents.\\n\\tnew first = $( ifTrue: [^ self].\\t\\\"Cancel\\\"\\n\\tnew first = $ ifTrue: [^ self].\\t\\\"nothing\\\"\\n\\tnews _ String streamContents: [:strm | \\\"remove fake args\\\"\\n\\t\\t(new findBetweenSubStrs: #(' 5' $ )) do: [:part | strm nextPutAll: part]].\\n\\tnewSel _ stringMorph valueOfProperty: #syntacticallyCorrectContents.\\n\\tnewSel ifNil: [newSel _ news].\\n\\told _ (ms _ self findA: StringMorph) valueOfProperty: #syntacticallyCorrectContents.\\n\\told ifNil: [old _ (self findA: StringMorph) contents].\\n\\toa _ old numArgs. na _ newSel numArgs. case _ 5.\\n\\t(oa = 1) & (na = 1) ifTrue: [case _ 1]. \\n\\t(oa = 0) & (na = 0) ifTrue: [case _ 2].\\n\\t(oa = 1) & (na = 0) ifTrue: [case _ 3].\\n\\t(oa = 0) & (na = 1) ifTrue: [case _ 4].\\n\\tcase <= 4 ifTrue: [\\\"replace the selector\\\"\\n\\t\\tms contents: news.\\t\\\"not multi-part\\\"\\n\\t\\tms setProperty: #syntacticallyCorrectContents toValue: newSel].\\n\\tcase = 3 ifTrue: [owner tossOutArg: 1].\\n\\tcase = 4 ifTrue: [self addArg: 1].\\n\\t\\\"more cases here. Rebuild the entire MessageNode\\\"\\n\\t\\n\\tself acceptIfInScriptor.! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 9/28/2001 10:06'!\\nretract\\n\\t\\\"replace this message with its receiver. I am the message node.\\\"\\n\\t| rec cascade msg |\\n\\t(self nodeClassIs: CascadeNode) ifTrue:\\n\\t\\t[\\\"This is a piece of a cascaded message -- just delete it\\\"\\n\\t\\tself deletePopup.\\n\\t\\tcascade _ owner.\\n\\t\\tself delete.\\n\\t\\tcascade setSelection: {cascade. nil. cascade}.\\n\\t\\t^ cascade acceptIfInScriptor].\\n\\tself deletePopup.\\n\\t(rec _ self receiverNode)\\n\\t\\tifNil: [msg _ owner.\\n\\t\\t\\trec _ owner receiverNode.\\n\\t\\t\\tmsg owner replaceSubmorph: msg by: rec]\\n\\t\\tifNotNil: [owner replaceSubmorph: self by: rec].\\n\\trec setSelection: {rec. nil. rec}.\\n\\trec acceptIfInScriptor.! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'di 12/13/2000 12:57'!\\nretractArrow\\n\\t\\\"Return the retract arrow button. It replaces the current message with its receiver.\\n\\tI am in a MessageNode whose first subnode is not a MessagePartNode. I did not encounter a block on the way up to it. I am the last subnode in every owner up to it.\\\"\\n\\t| patch |\\n\\n\\t(self nodeClassIs: MessageNode) ifFalse: [^ nil].\\n\\t(owner isSyntaxMorph and: [owner parseNode == parseNode]) ifTrue: [^ nil].\\n\\n\\tpatch _ (ImageMorph new image: (TileMorph classPool at: #RetractPicture)).\\n\\tpatch on: #mouseDown send: #retract to: self.\\n\\t^ patch! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 9/18/2001 16:27'!\\nselectorMenu\\n\\t\\\"Put up a menu of all selectors that my receiver could be sent. Replace me with the one chosen. (If fewer args, put the tiles for the extra arg to the side, in script's owner (world?).)\\n\\tGo ahead and eval receiver to find out its type. Later, mark selectors for side effects, and don't eval those.\\n\\tPut up a table. Each column is a viewer category.\\\"\\n\\n\\t| cats value catNames interfaces list setter wording all words ind aVocabulary limitClass |\\n\\tcats _ #().\\n\\tall _ Set new.\\n\\tvalue _ self receiverObject.\\n\\tvalue class == Error ifTrue: [^ nil].\\n\\t\\n\\taVocabulary _ self vocabularyToUseWith: value.\\n\\tlimitClass _ self limitClassToUseWith: value vocabulary: aVocabulary.\\n\\tcatNames _ value categoriesForVocabulary: aVocabulary limitClass: limitClass.\\n\\tcats _ catNames collect: [:nn | \\n\\t\\tlist _ OrderedCollection new.\\n\\t\\tinterfaces _ value methodInterfacesForCategory: nn \\n\\t\\t\\t\\t\\t\\tinVocabulary: aVocabulary limitClass: limitClass.\\n\\t\\tinterfaces do: [:mi | \\n\\t\\t\\t(all includes: mi selector) ifFalse: [\\n\\t\\t\\t\\t\\\"list add: (self aSimpleStringMorphWith: mi elementWording). Expensive\\\"\\n\\t\\t\\t\\twords _ mi selector.\\n\\t\\t\\t\\t(words beginsWith: 'get ') ifTrue: [words _ words allButFirst: 4].\\n\\t\\t\\t\\tmi selector last == $: ifTrue: [\\n\\t\\t\\t\\t\\twords _ String streamContents: [:strm | \\\"add fake args\\\"\\n\\t\\t\\t\\t\\t\\t(words findTokens: $:) do: [:part | strm nextPutAll: part; nextPutAll: ' 5 ']].\\n\\t\\t\\t\\t\\twords _ words allButLast].\\n\\t\\t\\t\\tmi selector isInfix ifTrue: [words _ words, ' 5'].\\n\\t\\t\\t\\twords _ self splitAtCapsAndDownshifted: words.\\t\\n\\t\\t\\t\\tlist add: (self anUpdatingStringMorphWith: words special: true).\\n\\t\\t\\t\\twords = mi selector ifFalse: [\\n\\t\\t\\t\\t\\tlist last setProperty: #syntacticallyCorrectContents toValue: mi selector].\\n\\t\\t\\t\\tall add: mi selector].\\n\\t\\t\\tsetter _ mi companionSetterSelector asString.\\n\\t\\t\\t(setter = 'nil') | (all includes: setter) ifFalse: [\\\"need setters also\\\"\\n\\t\\t\\t\\twording _ (self translateToWordySetter: setter).\\n\\t\\t\\t\\tlist add: (self aSimpleStringMorphWith: wording, ' 5').\\n\\t\\t\\t\\twording = setter ifFalse: [\\n\\t\\t\\t\\t\\tlist last setProperty: #syntacticallyCorrectContents \\n\\t\\t\\t\\t\\t\\ttoValue: setter].\\n\\t\\t\\t\\tall add: setter]].\\n\\t\\tlist].\\n\\t(ind _ catNames indexOf: 'scripts') > 0 ifTrue: [\\n\\t\\t(cats at: ind) first contents = 'empty script' ifTrue: [(cats at: ind) removeFirst]].\\n\\tcats first addFirst: (self aSimpleStringMorphWith: ' ').\\t\\\"spacer\\\"\\n\\tcats first addFirst: (self aSimpleStringMorphWith: '( from ', value class name, ' )').\\n\\tcats first first color: (Color green mixed: 0.25 with: Color black).\\n\\tself selectorMenuAsk: cats.\\t\\\"The method replaceSel:menuItem: does the work. \\n\\t\\tand replaces the selector.\\\"\\n\\t! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 9/20/2001 16:04'!\\nselectorMenuAsk: listOfLists\\n\\t\\\"I represent a SelectorNode to be replaced by one of the selectors in one of the category lists. Each list has pre-built StringMorphs in it.\\\"\\n\\n\\t| menu col |\\n\\tlistOfLists isEmpty ifTrue: [^ nil].\\n\\tlistOfLists first addFirst: (self aSimpleStringMorphWith: '( Cancel )').\\n\\tlistOfLists first first color: Color red.\\n\\tmenu _ RectangleMorph new.\\n\\tmenu listDirection: #leftToRight; layoutInset: 3; cellInset: 1@0.\\n\\tmenu layoutPolicy: TableLayout new; hResizing: #shrinkWrap; \\n\\t\\tvResizing: #shrinkWrap; color: (Color r: 0.767 g: 1.0 b: 0.767);\\n\\t\\tuseRoundedCorners; cellPositioning: #topLeft.\\n\\tlistOfLists do: [:ll |\\n\\t\\tcol _ Morph new.\\n\\t \\tcol listDirection: #topToBottom; layoutInset: 0; cellInset: 0@0.\\n\\t\\tcol layoutPolicy: TableLayout new; hResizing: #shrinkWrap.\\n\\t\\tcol color: Color transparent; vResizing: #shrinkWrap.\\n\\t\\tmenu addMorphBack: col.\\n\\t\\tll do: [:ss | \\n\\t\\t\\tcol addMorphBack: ss.\\n\\t\\t\\tss on: #mouseUp send: #replaceKeyWord:menuItem: to: self]\\n\\t\\t].\\n\\tself world addMorph: menu.\\n\\tmenu setConstrainedPosition: (owner localPointToGlobal: self topRight) + (10@-30) \\n\\t\\t\\thangOut: false.\\n! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'sw 3/18/2004 00:35'!\\nsetSelector: stringLike in: stringMorph\\n\\t\\\"Store the new selector and accept method.\\\"\\n\\n\\t| aSymbol myType str |\\n\\taSymbol _ stringLike asSymbol.\\n\\t(ScriptingSystem helpStringOrNilFor: aSymbol) ifNotNilDo:\\n\\t\\t[:aString |\\n\\t\\t\\tself setBalloonText: aString translated].\\n\\tmyType _ stringMorph valueOfProperty: #syntacticReformatting ifAbsent: [#none].\\n\\tstr _ aSymbol.\\n\\t(self isStandardSetterKeyword: str) ifTrue: [str _ self translateToWordySetter: str].\\n\\t(self isStandardGetterSelector: str) ifTrue: [str _ self translateToWordyGetter: str].\\n\\t(self shouldBeBrokenIntoWords: myType) \\n\\t\\tifTrue: [str _ self substituteKeywordFor: str].\\n\\tstringMorph contents: str.\\n\\t\\\"parseNode key: aSymbol code: nil.\\\"\\n\\tstr = stringLike ifFalse:\\n\\t\\t[stringMorph setProperty: #syntacticallyCorrectContents toValue: aSymbol].\\n\\tself acceptSilently! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 9/19/2001 15:47'!\\ntossOutArg: extras\\n\\n\\t\\\"Remove the tiles for the last N keywords and arguments. Place the tiles beside the current window. I am a SyntaxMorph for a MessageNode.\\\"\\n\\n\\t| cnt ctr |\\n\\tcnt _ 0.\\n\\t submorphs copy reverseDo: [:sub |\\n\\t\\tctr _ sub fullBoundsInWorld center.\\n\\t\\tsub delete.\\n\\t\\t(sub isSyntaxMorph and: [sub parseNode notNil]) ifTrue: [\\n\\t\\t\\tsub isNoun ifTrue: [\\n\\t\\t\\t\\tself pasteUpMorph addMorphFront: sub.\\n\\t\\t\\t\\tsub position: self enclosingPane fullBoundsInWorld right - 20 @ ctr y].\\n\\t\\t\\t(cnt _ cnt + 1) >= extras ifTrue: [^ self]]].! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 8/24/2001 13:35'!\\nupDown: delta event: evt arrow: arrowMorph\\n\\n\\t| st |\\n\\tst _ submorphs detect: [:mm | mm isKindOf: StringMorph] ifNone: [^ self].\\n\\t(self nodeClassIs: LiteralNode) ifTrue:\\n\\t\\t[ \\\"+/- 1\\\"\\n\\t\\tst contents: (self decompile asNumber + delta) printString.\\n\\t\\t^ self acceptUnlogged].\\n\\t(self nodeClassIs: VariableNode) ifTrue:\\n\\t\\t[ \\\"true/false\\\"\\n\\t\\tst contents: (self decompile string = 'true') not printString.\\n\\t\\t^ self acceptSilently ifFalse: [self changed].\\n\\t\\t\\t\\\"maybe set parseNode's key\\\"].\\n\\n\\t(self upDownArithOp: delta) ifTrue: [^ self].\\t\\\"+ - // * < > <= = beep:\\\"\\n\\n\\t(self upDownAssignment: delta) ifTrue: [^ self].\\n\\t\\t\\\"Handle assignment -- increaseBy: <- multiplyBy:\\\"\\n! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 7/24/2001 17:54'!\\nupDownArithOp: delta\\n\\t\\\"Change a + into a -. Also do sounds (change the arg to the beep:).\\\"\\n\\n\\t| aList index st |\\n\\tst _ submorphs detect: [:mm | mm isKindOf: StringMorph] ifNone: [^ self].\\n\\t(self nodeClassIs: SelectorNode) ifTrue:\\n\\t\\t[aList _ #(+ - * / // \\\\\\\\ min: max:).\\n\\t\\t(index _ aList indexOf: self decompile asString) > 0 ifTrue:\\n\\t\\t\\t[self setSelector: (aList atWrap: index + delta) in: st. ^ true].\\n\\n\\t\\taList _ #(= ~= > >= isDivisibleBy: < <=).\\n\\t\\t(index _ aList indexOf: self decompile asString) > 0 ifTrue:\\n\\t\\t\\t[self setSelector: (aList atWrap: index + delta) in: st. ^ true].\\n\\n\\t\\taList _ #(== ~~).\\n\\t\\t(index _ aList indexOf: self decompile asString) > 0 ifTrue:\\n\\t\\t\\t[self setSelector: (aList atWrap: index + delta) in: st. ^ true].\\n\\n\\t\\t'beep:' = self decompile asString ifTrue:\\n\\t\\t\\t[\\\"replace sound arg\\\"\\n\\t\\t\\tself changeSound: delta.\\n\\t\\t\\tself acceptSilently. ^ true].\\n\\t\\t].\\n\\t^ false! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 9/20/2001 16:33'!\\nupDownArrows\\n\\t\\\"Return an array of two up/down arrow buttons.\\n\\tIt replaces the selector or arg with a new one.\\n\\tI am a number or boolean or a selector (beep:, +,-,*,//,\\\\\\\\, or setX: incX: decX: for any X.\\\"\\n\\t| patch any noMenu |\\n\\tany _ (self nodeClassIs: LiteralNode) and: [parseNode key isNumber].\\n\\tany _ any or: [(self nodeClassIs: VariableNode) and:\\n\\t\\t\\t\\t\\t\\t[(#('true' 'false') includes: self decompile asString)]].\\n\\tnoMenu _ any.\\n\\n\\tany _ any or: [self nodeClassIs: SelectorNode].\\t\\\"arrows and menu of selectors\\\"\\n\\tany _ any or: [self nodeClassIs: KeyWordNode].\\n\\tany ifFalse: [^ nil].\\n\\n\\tpatch _ {(ImageMorph new image: TileMorph upPicture)\\n\\t\\t\\t\\ton: #mouseDown send: #upDown:event:arrow: to: self withValue: 1;\\n\\t\\t\\t\\ton: #mouseStillDown send: #upDownMore:event:arrow: \\n\\t\\t\\t\\t\\tto: self withValue: 1;\\n\\t\\t\\t\\ton: #mouseUp send: #upDownDone to: self.\\n\\t\\t\\t(ImageMorph new image: TileMorph downPicture)\\n\\t\\t\\t\\ton: #mouseDown send: #upDown:event:arrow: to: self withValue: -1;\\n\\t\\t\\t\\ton: #mouseStillDown send: #upDownMore:event:arrow: \\n\\t\\t\\t\\t\\tto: self withValue: -1;\\n\\t\\t\\t\\ton: #mouseUp send: #upDownDone to: self}.\\n\\tnoMenu ifFalse: [patch _ patch, {(RectangleMorph new)\\n\\t\\t\\t\\t\\t\\textent: 6@10; borderWidth: 1;\\n\\t\\t\\t\\t\\t\\tborderColor: Color gray;\\n\\t\\t\\t\\t\\t\\ton: #mouseUp send: #selectorMenu to: self}.\\n\\t\\t\\t\\t\\tpatch last color: ((self nodeClassIs: SelectorNode) \\n\\t\\t\\t\\t\\t\\tifTrue: [Color lightGreen] ifFalse: [Color red darker])].\\n\\t^ patch! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'tk 8/24/2001 12:33'!\\nupDownAssignment: delta\\n\\t\\\"Rotate between increaseBy: decreaseBy: _ multiplyBy:\\\"\\n\\n\\t| st now want instVar |\\n\\tst _ submorphs detect: [:mm | mm isKindOf: StringMorph] ifNone: [^ self].\\n\\t(self nodeClassIs: SelectorNode) ifTrue:\\n\\t\\t[\\\"kinds of assignment\\\"\\n\\t\\t((now _ self decompile asString) beginsWith: 'set') ifTrue:\\n\\t\\t\\t[\\\"a setX: 3\\\"\\n\\t\\t\\twant _ 1+delta. instVar _ (now allButFirst: 3) allButLast].\\n\\t\\t(now endsWith: 'IncreaseBy:') ifTrue:\\n\\t\\t\\t[\\\"a xIncreaseBy: 3 a setX: (a getX +3).\\\"\\n\\t\\t\\twant _ 2+delta. instVar _ now allButLast: 11].\\n\\t\\t(now endsWith: 'DecreaseBy:') ifTrue:\\n\\t\\t\\t[\\\"a xDecreaseBy: 3 a setX: (a getX -3).\\\"\\n\\t\\t\\twant _ 3+delta. instVar _ now allButLast: 11].\\n\\t\\t(now endsWith: 'MultiplyBy:') ifTrue:\\n\\t\\t\\t[\\\"a xMultiplyBy: 3 a setX: (a getX *3).\\\"\\n\\t\\t\\twant _ 4+delta. instVar _ now allButLast: 11].\\n\\t\\twant ifNil: [^ false].\\n\\t\\tinstVar _ instVar asLowercase.\\n\\t\\twant _ #(1 2 3 4) atWrap: want.\\n\\t\\twant = 1 ifTrue:\\n\\t\\t\\t[\\\"setter method is present\\\"\\n\\t\\t\\tself setSelector: ('set', instVar capitalized, ':') in: st. ^ true].\\n\\t\\twant = 2 ifTrue:\\n\\t\\t\\t[\\\"notUnderstood will create the method if needed\\\"\\n\\t\\t\\tself setSelector: instVar, 'IncreaseBy:' in: st. ^ true].\\n\\t\\twant = 3 ifTrue:\\n\\t\\t\\t[\\\"notUnderstood will create the method if needed\\\"\\n\\t\\t\\tself setSelector: instVar, 'DecreaseBy:' in: st. ^ true].\\n\\t\\twant = 4 ifTrue:\\n\\t\\t\\t[\\\"notUnderstood will create the method if needed\\\"\\n\\t\\t\\tself setSelector: instVar, 'MultiplyBy:' in: st. ^ true].\\n\\t\\t].\\n\\t^ false\\n! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'di 5/4/2001 11:49'!\\nupDownDone\\n\\n\\t(self nodeClassIs: LiteralNode) ifTrue:\\n\\t\\t[self acceptSilently. \\\"Final compilation logs source\\\"\\n\\t\\tself removeProperty: #timeOfLastTick;\\n\\t\\t\\tremoveProperty: #currentDelay].\\n! !\\n\\n!SyntaxMorph methodsFor: 'pop ups' stamp: 'di 5/4/2001 12:26'!\\nupDownMore: delta event: evt arrow: arrowMorph\\n\\n\\t| st delay1 delay2 now timeOfLastTick currentDelay |\\n\\t(self nodeClassIs: LiteralNode) ifFalse: [^ self].\\n\\tst _ submorphs detect: [:mm | mm isKindOf: StringMorph] ifNone: [^ self].\\n\\tdelay1 _ 300. \\\"ms\\\"\\n\\tdelay2 _ 50. \\\"ms\\\"\\n\\tnow _ Time millisecondClockValue.\\n\\ttimeOfLastTick _ (self valueOfProperty: #timeOfLastTick) ifNil: [now - delay1].\\n\\tcurrentDelay _ (self valueOfProperty: #currentDelay) ifNil: [delay1].\\n\\tnow >= (timeOfLastTick + currentDelay) ifTrue:\\n\\t\\t[self setProperty: #timeOfLastTick toValue: now.\\n\\t\\t\\\"decrease the delay\\\"\\n\\t\\tself setProperty: #currentDelay toValue: (currentDelay*8//10 max: delay2).\\n\\t\\tst contents: (self decompile asNumber + delta) printString.\\n\\t\\t^ self acceptUnlogged].\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'tk 9/23/2001 01:33'!\\ngetHeader: strm\\n\\t| se |\\n\\t\\\"We are in an EToy scriptor and the method header line has been removed. Try to recover the method name. Fail if method has args (deal with this later).\\\"\\n\\n\\t(se _ self ownerThatIsA: ScriptEditorMorph) ifNotNil: [\\n\\t\\tse scriptName numArgs > 0 ifTrue: [^ false].\\t\\\"abort\\\"\\n\\t\\tstrm nextPutAll: se scriptName].\\n\\t^ true! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'dgd 2/22/2003 13:40'!\\nownerPrecedence\\n\\t\\\"Return the selector precedence of my owner. 1 for unary (asInteger), 2 for binary arithmetic (+), and 3 for keyword selectors (from:to:). Subtract 0.5 if self is an arg, not the receiver (the case of a + (b + c))\\\"\\n\\n\\t| oo below sel pp |\\n\\too := owner.\\n\\tbelow := self.\\n\\t\\n\\t[oo isSyntaxMorph ifFalse: [^10].\\t\\\"I do not need parens\\\"\\n\\too parseNode isNil] \\n\\t\\t\\twhileTrue: \\n\\t\\t\\t\\t[below := oo.\\n\\t\\t\\t\\too := oo owner].\\n\\t(sel := oo selector) ifNil: [^10].\\n\\t(pp := sel precedence) = 3 ifTrue: [^2.5].\\t\\\"keyword messages need parens\\\"\\n\\t^oo receiverNode == below ifTrue: [pp] ifFalse: [pp - 0.5]! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'tk 9/23/2001 02:11'!\\nprintAssignmentNodeOn: strm indent: level\\n\\t\\\"sometimes an assignment is in parens\\\"\\n\\t| parens above |\\n\\n\\tparens _ submorphs size >= 3.\\n\\tparens ifTrue: [\\n\\t\\tabove _ self ownerPrecedence.\\t\\\"high if not in an expression\\\"\\n\\t\\tparens _ above <= 3].\\t\\\"assignment is a noun inside a message\\\"\\n\\tparens ifTrue: [strm nextPut: $( ].\\n\\tself\\n\\t\\tsubmorphsDoIfSyntax: [ :sub |\\n\\t\\t\\tsub printOn: strm indent: level.\\n\\t\\t\\tstrm ensureASpace.\\n\\t\\t]\\n\\t\\tifString: [ :sub |\\n\\t\\t\\tstrm ensureNoSpace. \\t\\\"_ will have a leading space\\\"\\n\\t\\t\\tself printSimpleStringMorph: sub on: strm\\n\\t\\t].\\n\\tparens ifTrue: [strm ensureNoSpace; nextPut: $) ].\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'RAA 3/4/2001 12:19'!\\nprintBlockArgsNodeOn: strm indent: level\\n\\n\\t| argString |\\n\\n\\tself\\n\\t\\tsubmorphsDoIfSyntax: [ :sub |\\n\\t\\t\\t(argString _ sub decompile) isEmpty ifFalse: [\\n\\t\\t\\t\\tstrm \\n\\t\\t\\t\\t\\tnextPut: $:;\\n\\t\\t\\t\\t\\tnextPutAll: argString;\\n\\t\\t\\t\\t\\tspace\\n\\t\\t\\t].\\n\\t\\t] \\n\\t\\tifString: [ :sub |\\n\\t\\t\\t\\\"self printSimpleStringMorph: sub on: strm\\t<<<< do we need this??\\\"\\n\\t\\t].\\n\\tstrm nextPut: $|; crtab: level.\\n\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'tk 9/23/2001 01:17'!\\nprintBlockNodeOn: strm indent: level\\n\\n\\t| lev inASyntaxButNotOutermost subNodeClass |\\n\\n\\tlev _ level.\\n\\tinASyntaxButNotOutermost _ owner isSyntaxMorph and: [ owner isMethodNode not].\\n\\tinASyntaxButNotOutermost ifTrue: [strm nextPut: $[. lev _ lev+1].\\n\\tself\\n\\t\\tsubmorphsDoIfSyntax: [ :sub |\\n\\t\\t\\tsub printOn: strm indent: lev.\\n\\t\\t\\tsubNodeClass _ sub parseNode class.\\n\\t\\t\\t(#(BlockArgsNode ReturnNode CommentNode) includes: subNodeClass name) ifFalse: [\\n\\t\\t\\t\\tstrm ensureNoSpace; nextPut: $.].\\n\\t\\t\\tsubNodeClass == BlockArgsNode\\n\\t\\t\\t\\tifTrue: [strm space]\\n\\t\\t\\t\\tifFalse: [strm crtab: lev].\\n\\t\\t] \\n\\t\\tifString: [ :sub |\\n\\t\\t\\tself printSimpleStringMorph: sub on: strm\\n\\t\\t].\\n\\tinASyntaxButNotOutermost ifTrue: [strm nextPut: $] ].\\n\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'tk 9/23/2001 01:19'!\\nprintCascadeNodeOn: strm indent: level\\n\\n\\t| parens cnt me above |\\n\\n\\tparens _ parseNode receiver notNil.\\n\\tparens ifTrue: [me _ self selector precedence.\\n\\t\\tabove _ self ownerPrecedence.\\t\\\"high if not in an expression\\\"\\n\\t\\tparens _ me > above].\\n\\tparens ifTrue: [strm nextPut: $( ].\\n\\tcnt _ 0.\\n\\tself\\n\\t\\tsubmorphsDoIfSyntax: [ :sub |\\n\\t\\t\\tcnt _ cnt + 1.\\n\\t\\t\\t\\\"maybe we want to test sub isCascadePart for the following???\\\"\\n\\t\\t\\tcnt > 2 ifTrue: [strm nextPutAll: '; '].\\n\\t\\t\\tsub printOn: strm indent: level.\\n\\t\\t\\tstrm ensureASpace.\\n\\t\\t]\\n\\t\\tifString: [ :sub |\\n\\t\\t\\tself printSimpleStringMorph: sub on: strm\\n\\t\\t].\\n\\tparens ifTrue: [strm ensureNoSpace; nextPut: $) ].\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'tk 9/23/2001 01:17'!\\nprintMessageNodeOn: strm indent: level\\n\\n\\t| parens me above |\\n\\n\\tparens _ parseNode receiver notNil.\\n\\tparens ifTrue: [me _ self selector precedence.\\n\\t\\tabove _ self ownerPrecedence.\\t\\\"high if not in an expression\\\"\\n\\t\\tparens _ me > above].\\n\\tparens ifTrue: [strm nextPut: $( ].\\n\\tself\\n\\t\\tsubmorphsDoIfSyntax: [ :sub |\\n\\t\\t\\tsub printOn: strm indent: level.\\n\\t\\t\\tstrm ensureASpace.\\n\\t\\t]\\n\\t\\tifString: [ :sub |\\n\\t\\t\\tself printSimpleStringMorph: sub on: strm\\n\\t\\t].\\n\\tparens ifTrue: [strm ensureNoSpace; nextPut: $) ].\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'tk 9/23/2001 02:12'!\\nprintMethodNodeOn: strm indent: level\\n\\n\\t(self findA: SelectorNode) ifNil: [\\n\\t\\t(self getHeader: strm) ifFalse: [^ self].\\t\\t\\\"might fail\\\"\\n\\t\\tstrm crtab: level].\\n\\tself \\n\\t\\tsubmorphsDoIfSyntax: [ :sub |\\n\\t\\t\\tsub printOn: strm indent: level.\\n\\t\\t\\tstrm crtab: level.\\n\\t\\t]\\n\\t\\tifString: [ :sub |\\n\\t\\t\\tself printSimpleStringMorph: sub on: strm\\n\\t\\t]. \\n\\tstrm last == $. ifTrue: [strm skip: -1]. \\\"ugh!! erase duplicate final period\\\"! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'RAA 3/4/2001 12:08'!\\nprintMethodTempsNodeOn: strm indent: level\\n\\n\\tstrm nextPut: $|; space.\\n\\tself\\n\\t\\tsubmorphsDoIfSyntax: [ :sub |\\n\\t\\t\\tsub printOn: strm indent: level.\\n\\t\\t\\tstrm space.\\n\\t\\t]\\n\\t\\tifString: [ :sub |\\n\\t\\t\\tself printSimpleStringMorph: sub on: strm\\n\\t\\t].\\n\\tstrm nextPut: $|; crtab: level.\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'tk 10/22/2000 20:43'!\\nprintOn: strm\\n\\n\\tsuper printOn: strm.\\n\\tstrm space; nextPutAll: parseNode class name.! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'tk 9/14/2001 13:52'!\\nprintOn: strm indent: level\\n\\n\\t| nodeClass |\\n\\n\\t(self hasProperty: #ignoreNodeWhenPrinting) ifFalse: [\\n\\t\\tnodeClass _ parseNode class.\\n\\t\\tnodeClass == VariableNode ifTrue: [^self printVariableNodeOn: strm indent: level].\\n\\t\\tnodeClass == LiteralVariableNode ifTrue: [^self printVariableNodeOn: strm indent: level].\\n\\t\\tnodeClass == MessageNode ifTrue: [^self printMessageNodeOn: strm indent: level].\\n\\t\\tnodeClass == BlockNode ifTrue: [^self printBlockNodeOn: strm indent: level].\\n\\t\\tnodeClass == BlockArgsNode ifTrue: [^self printBlockArgsNodeOn: strm indent: level].\\n\\t\\tnodeClass == MethodNode ifTrue: [^self printMethodNodeOn: strm indent: level].\\n\\t\\tnodeClass == MethodTempsNode ifTrue: [^self printMethodTempsNodeOn: strm indent: level].\\n\\t\\tnodeClass == CascadeNode ifTrue: [^self printCascadeNodeOn: strm indent: level].\\n\\t\\tnodeClass == AssignmentNode ifTrue: [^self printAssignmentNodeOn: strm indent: level].\\n\\t].\\n\\tself\\n\\t\\tsubmorphsDoIfSyntax: [ :sub |\\n\\t\\t\\tsub printOn: strm indent: level.\\n\\t\\t\\tstrm ensureASpace.\\n\\t\\t]\\n\\t\\tifString: [ :sub |\\n\\t\\t\\tself printSimpleStringMorph: sub on: strm\\n\\t\\t].\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'RAA 2/16/2001 18:16'!\\nprintSimpleStringMorph: aMorph on: strm\\n\\n\\t| trialContents |\\n\\n\\t(aMorph hasProperty: #wordyVariantOfSelf) ifTrue: [\\n\\t\\tstrm nextPutAll: 'self '.\\n\\t\\tstrm nextPutAll: ((self translateToWordySelfVariant: aMorph contents) ifNil: [^self]).\\n\\t\\t^self\\n\\t].\\n\\t(aMorph hasProperty: #noiseWord) ifFalse: [\\n\\t\\ttrialContents _ self cleanUpString: aMorph.\\n\\t\\tstrm nextPutAll: trialContents\\n\\t].\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'RAA 2/13/2001 23:10'!\\nprintStatementsOn: aStream indent: indent\\n\\n\\t\\\"seemed to be necessary to see top node in explorer\\\"\\n\\n\\t^parseNode printStatementsOn: aStream indent: indent! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'ar 8/16/2001 13:29'!\\nprintVariableNodeOn: strm indent: level\\n\\n\\t\\\"nil out any old association\\\"\\n\\tparseNode key isVariableBinding ifTrue: [\\n\\t\\tparseNode \\n\\t\\t\\tname: parseNode name \\n\\t\\t\\tkey: nil \\n\\t\\t\\tcode: parseNode code\\n\\t].\\n\\tself\\n\\t\\tsubmorphsDoIfSyntax: [ :sub |\\n\\t\\t\\tsub printOn: strm indent: level.\\n\\t\\t\\tstrm ensureASpace.\\n\\t\\t]\\n\\t\\tifString: [ :sub |\\n\\t\\t\\tself printSimpleStringMorph: sub on: strm\\n\\t\\t].\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'di 11/13/2000 07:43'!\\nstructure\\n\\t\\\"Print my structure from inner to outer.\\\"\\n\\t^ String streamContents: [:s |\\n\\t\\tself withAllOwnersDo:\\n\\t\\t\\t[:m | m isSyntaxMorph ifTrue:\\n\\t\\t\\t\\t[s cr; print: m parseNode class.\\n\\t\\t\\t\\t((m nodeClassIs: MessageNode) or: [m nodeClassIs: TileMessageNode]) ifTrue:\\n\\t\\t\\t\\t\\t[s space; nextPutAll: m parseNode selector key]]]]! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'RAA 3/4/2001 11:55'!\\nsubmorphsDoIfSyntax: block1 ifString: block2 \\n\\n\\t^self submorphsDoIfSyntax: block1 ifString: block2 otherwise: [ :sub | ]\\n! !\\n\\n!SyntaxMorph methodsFor: 'printing' stamp: 'gm 2/22/2003 12:34'!\\nsubmorphsDoIfSyntax: block1 ifString: block2 otherwise: block3 \\n\\tsubmorphs do: \\n\\t\\t\\t[:sub | \\n\\t\\t\\tsub isSyntaxMorph \\n\\t\\t\\t\\tifTrue: [block1 value: sub]\\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[(sub isKindOf: StringMorph) \\n\\t\\t\\t\\t\\t\\tifTrue: [block2 value: sub]\\n\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t[(sub isTextMorph) \\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [block2 value: sub]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [block3 value: sub]]]]! !\\n\\n\\n!SyntaxMorph methodsFor: 'scripting' stamp: 'tk 9/26/2001 06:01'!\\ntearOffTile\\n\\t\\\"For a SyntaxMorph, this means give a copy of me\\\"\\n\\n\\t| dup |\\n\\tdup _ self duplicate.\\n\\tActiveHand attachMorph: dup.\\n\\tPreferences tileTranslucentDrag\\n\\t\\tifTrue: [^ dup lookTranslucent]\\n\\t\\tifFalse: [^ dup align: dup topLeft with: ActiveHand position + self cursorBaseOffset]\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'selection' stamp: 'di 11/17/2000 08:10'!\\ncurrentSelectionDo: blockForSelection\\n\\t| rootTile |\\n\\t(rootTile _ self rootTile) isMethodNode ifFalse:\\n\\t\\t [^ blockForSelection value: nil value: nil value: nil].\\n\\trootTile valueOfProperty: #selectionSpec ifPresentDo:\\n\\t\\t[:selectionSpec | ^ blockForSelection\\n\\t\\t\\t\\t\\t\\t\\tvalue: selectionSpec first\\n\\t\\t\\t\\t\\t\\t\\tvalue: selectionSpec second\\n\\t\\t\\t\\t\\t\\t\\tvalue: selectionSpec third].\\n\\t^ blockForSelection value: nil value: nil value: nil! !\\n\\n!SyntaxMorph methodsFor: 'selection' stamp: 'RAA 2/14/2001 11:33'!\\ndeselect\\n\\tself allMorphsDo:\\n\\t\\t[:m | m isSyntaxMorph ifTrue: [m setDeselectedColor]].\\n\\n\\t\\\"Note following is wasteful because we do a deselect before each select, and it is often the same morph.\\\"\\n\\tself deletePopup! !\\n\\n!SyntaxMorph methodsFor: 'selection' stamp: 'tk 1/17/2001 15:07'!\\nisSelectable\\n\\t| ss |\\n\\t\\\"Spacer morphs enclose other morphs with the same parseNode\\\"\\n\\tself submorphs size > 1 ifTrue: [\\n\\t\\tss _ self submorphs second.\\n\\t\\tss isSyntaxMorph ifTrue: [\\n\\t\\t\\tss parseNode == parseNode ifTrue: [\\n\\t\\t\\t\\t^ self submorphs first class ~~ Morph]]].\\n\\t\\t\\n\\\"\\t(self nodeClassIs: SelectorNode) ifTrue: [^ false].\\n\\t(self nodeClassIs: KeyWordNode) ifTrue: [^ false].\\n\\\"\\n\\tself isMethodNode ifTrue: [^ false].\\n\\tparseNode ifNil: [^ false].\\n\\t^ true! !\\n\\n!SyntaxMorph methodsFor: 'selection' stamp: 'tk 7/31/2001 17:18'!\\nscaleColorByUserPref: aColor\\n\\t\\n\\t| myRoot underLyingColor |\\n\\n\\tmyRoot _ self rootTile.\\n\\tunderLyingColor _ myRoot ifNil: [Color transparent] ifNotNil: [myRoot color].\\n\\t[underLyingColor isTransparent and: [(myRoot _ myRoot owner) notNil]] whileTrue: [\\n\\t\\tunderLyingColor _ myRoot color.\\n\\t].\\n\\t\\n\\t\\\"rude hack to get the desired effect before we have an owner\\\"\\n\\n\\tunderLyingColor isTransparent ifTrue: [underLyingColor _ Color r: 0.903 g: 1.0 b: 0.903].\\n\\t^aColor mixed: (ContrastFactor ifNil: [0.3]) with: underLyingColor\\n\\n\\\"Would like to be able to make MethodNode and outer Block be transparent. This method does not allow that. Consider (^ myRoot color) inside the whileTrue. Consider setting underLyingColor to (myRoot valueOfProperty: #deselectedBorderColor ifAbsent: [myRoot color]) in second line.\\\"! !\\n\\n!SyntaxMorph methodsFor: 'selection' stamp: 'tk 7/23/2001 18:31'!\\nselect\\n\\tself deselect.\\n\\t\\\"Outer block is not colored and has no popup\\\"\\n\\t(owner isSyntaxMorph and: [owner nodeClassIs: MethodNode]) \\n\\t\\tifTrue: [self setDeselectedColor \\\"normal\\\"]\\n\\t\\tifFalse: [self color: Color lightBrown].\\n\\tself borderColor: #raised.\\n\\tself offerPopUp.! !\\n\\n!SyntaxMorph methodsFor: 'selection' stamp: 'tk 7/19/2001 17:52'!\\nsetDeselectedColor\\n\\t\\\"The normal color of the tile, stored with the tile\\\"\\n\\t| deselectedColor deselectedBorderColor |\\n\\n\\tdeselectedColor _ self valueOfProperty: #deselectedColor ifAbsent: [nil].\\n\\tdeselectedBorderColor _ self valueOfProperty: #deselectedBorderColor ifAbsent: [nil].\\n\\tdeselectedColor ifNotNil: [\\n\\t\\tdeselectedColor _ self scaleColorByUserPref: deselectedColor].\\n\\tdeselectedBorderColor ifNotNil: [\\n\\t\\tdeselectedBorderColor _ self scaleColorByUserPref: deselectedBorderColor].\\n\\tself \\n\\t\\tcolor: (deselectedColor ifNil: [Color transparent]);\\n\\t\\tborderColor: (deselectedBorderColor ifNil: [Color transparent])! !\\n\\n!SyntaxMorph methodsFor: 'selection' stamp: 'dgd 2/22/2003 13:41'!\\nsetSelection: newSpec \\n\\t\\\"A selectionSpec is {Inner morph. Where clicked. Outer morph}.\\n\\tFirst mouseDown starts a selection (with outerMorph isNil).\\n\\tDragging more than 4 pixels means to grab a copy of the current outer selection.\\n\\t\\tThe current selection is the outerMorph, or the inner if it is nil.\\n\\tEach mouseUp extends the selection to the next outer morph that is selectable.\\n\\t\\tExcept if this is the first click.\\\"\\n\\n\\t| rootTile |\\n\\t(rootTile := self rootTile) valueOfProperty: #selectionSpec\\n\\t\\tifPresentDo: [:oldSpec | oldSpec third ifNotNilDo: [:m | m deselect]].\\n\\t(newSpec isNil or: [newSpec third isNil and: [self isMethodNode]]) \\n\\t\\tifTrue: \\n\\t\\t\\t[self deselect.\\n\\t\\t\\t^rootTile removeProperty: #selectionSpec].\\n\\n\\t\\\"Select outer morph of the new selection\\\"\\n\\tnewSpec third isNil \\n\\t\\tifTrue: [self select\\t\\\"first click down\\\"]\\n\\t\\tifFalse: [newSpec third select\\t\\\"subsequent clicks\\\"].\\n\\trootTile setProperty: #selectionSpec toValue: newSpec! !\\n\\n\\n!SyntaxMorph methodsFor: 'stepping and presenter' stamp: 'tk 7/25/2001 11:26'!\\nstep\\n\\tsuper step.\\n\\tself isBlockNode ifTrue: [self trackDropZones].\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'submorphs-accessing' stamp: 'tk 1/13/2001 20:41'!\\nfindA: aClass\\n\\t| ans |\\n\\t\\\"Allow finding on the class of the parseNode\\\"\\n\\n\\t(ans _ super findA: aClass) ifNotNil: [^ ans].\\n\\tsubmorphs do: [:ss | \\n\\t\\tss isSyntaxMorph ifTrue: [\\n\\t\\t\\tss parseNode class == aClass ifTrue: [^ ss]]].\\n\\t^ nil! !\\n\\n\\n!SyntaxMorph methodsFor: 'testing' stamp: 'di 11/3/2000 08:03'!\\nstepTime\\n\\n\\t^ 50! !\\n\\n!SyntaxMorph methodsFor: 'testing' stamp: 'di 1/30/2001 11:22'!\\nwantsSteps\\n\\t\\\"Only step this morph if we explicitly send startStepping\\\"\\n\\n\\t^ false! !\\n\\n\\n!SyntaxMorph methodsFor: 'tests' stamp: 'di 11/6/2000 10:47'!\\ntest\\n\\t3 > 4 ifTrue: [].\\n\\t^ self! !\\n\\n!SyntaxMorph methodsFor: 'tests' stamp: 'gm 2/22/2003 12:35'!\\ntestForNode: targetNode andDo: aBlock \\n\\ttargetNode == parseNode ifTrue: [aBlock value: self].\\n\\tself submorphsDo: \\n\\t\\t\\t[:each | \\n\\t\\t\\t(each isSyntaxMorph) \\n\\t\\t\\t\\tifTrue: [each testForNode: targetNode andDo: aBlock]]! !\\n\\n!SyntaxMorph methodsFor: 'tests' stamp: 'di 11/14/2000 14:54'!\\ntoDo\\n\\\"\\nBiggies...\\n[ ]\\tIntegrate with EToy scriptors\\n\\treleaseCachedState can discard all morphic structure.\\n\\n[ ]\\tOptions:\\n\\tShow / hide syntax markers (like [], (), ., :, ;, etc)\\n\\tNo color / color-in-focus / full color\\n\\tTiles / textiles / text\\n\\n[ ]\\tParsedTextMorph -- looks like text but has all same substructure\\n\\n[ ]\\tIntroduce notion of an UnParsedNode -- maybe a flag in ParseNode\\n\\tText -> UnParsed -> Parsed -> CodeGen\\n\\n[ ]\\tNeed DnD evaluator, or some sort of '!!' button on any entity (halo?)\\n\\tAlso inspector / browser\\n\\n[ ]\\tAll the type help we can get\\n\\nDetails ...\\n[ ]\\tOpen up the parse of BraceNodes\\n\\n[ ]\\tVerify that all pastes are OK\\n\\n[ ]\\tColors not yet right for colored version.\\n\\n[ ]\\tStart work on show / hide of syntax markers -- (), [], etc.\\n\\n[ ]\\tStart work on textiles (grabable entites in 'normal' text)\\n\\n[ ]\\tNeed autoscroll during drag for drop\\n\\n[ ]\\tUse, eg, shift-drag to move, del to delete\\n\\n[ ]\\tWhat about invalid drops -- stick on cursor?\\n\\nSystem...\\n[ ]\\tOnly keep history 7 deep; option to clear on quit\\n\\tclear command above spaceLeft\\n\\n[ ]\\tCompute each page of prefs viewer on demand instead of as now.\\n\\n[ ]\\tOffer a search command that will gather up all preferences that match a given string (name or help string)\\n\\nPreferences enable: #noTileColor.\\nPreferences disable: #noTileColor.\\nSmalltalk browseAllSelect: [:cm | cm size > 600]\\nSyntaxMorph testAll\\n\\\"! !\\n\\n\\n!SyntaxMorph methodsFor: 'type checking' stamp: 'sw 2/23/2001 23:40'!\\nargTypeFor: aSelector\\n\\t\\\"Answer the type of the argument of this selector. Return #unknown if not found.\\\"\\n\\n\\t| itsInterface |\\n\\taSelector numArgs = 0 \\n\\t\\tifTrue: [self inform: aSelector, ' does not take an argument'. ^ #error \\\"7\\\"].\\n\\titsInterface _ self currentVocabulary methodInterfaceAt: aSelector ifAbsent:\\n\\t\\t[^ #unknown].\\n\\t^ itsInterface typeForArgumentNumber: 1! !\\n\\n!SyntaxMorph methodsFor: 'type checking' stamp: 'sw 2/15/2001 14:25'!\\nokToBeReplacedBy: aSyntaxMorph\\n\\t\\\"Return true if it is OK to replace me with aSyntaxMorph. Enforce the type rules in the old EToy green tiles.\\\"\\n\\n\\t| itsType myType |\\n\\t(Preferences eToyFriendly or: [Preferences typeCheckingInTileScripting])\\n\\t\\tifFalse: [^ true].\\t\\\"not checking unless one of those prefs is true\\\"\\n\\t(parseNode class == BlockNode and: [aSyntaxMorph parseNode class == BlockNode]) \\n\\t\\tifTrue: [^ true].\\n\\t(parseNode class == ReturnNode and: [aSyntaxMorph parseNode class == ReturnNode]) \\n\\t\\tifTrue: [^ true].\\n\\tparseNode class == KeyWordNode ifTrue: [^ false].\\n\\taSyntaxMorph parseNode class == KeyWordNode ifTrue: [^ false].\\n\\tparseNode class == SelectorNode ifTrue: [^ false].\\n\\taSyntaxMorph parseNode class == SelectorNode ifTrue: [^ false].\\n\\towner isSyntaxMorph ifFalse: [^ true].\\t\\\"only within a script\\\"\\n\\t\\t\\\"Transcript show: aSyntaxMorph resultType printString, ' dropped on ', \\n\\t\\t\\tself receiverOrArgType printString; cr.\\n\\t\\t\\\"\\n\\t(itsType _ aSyntaxMorph resultType) == #unknown ifTrue: [^ true].\\n\\t(myType _ self receiverOrArgType) == #unknown ifTrue: [^ true].\\n\\t\\t\\\"my type in enclosing message\\\"\\n\\t^ myType = itsType! !\\n\\n!SyntaxMorph methodsFor: 'type checking' stamp: 'tk 2/9/2001 15:56'!\\nreceiverOrArgType\\n\\t| ty |\\n\\t\\\"Return my type in my role as a receiver or as an argument. Ask my enclosing message first, then ask myself. (If owner accepts any #object, and I am a #point, do return #object.)\\\"\\n\\n\\t^ (ty _ self receiverOrArgTypeAbove) == #unknown\\n\\t\\tifTrue: [self resultType]\\n\\t\\tifFalse: [ty]! !\\n\\n!SyntaxMorph methodsFor: 'type checking' stamp: 'dgd 2/22/2003 18:48'!\\nreceiverOrArgTypeAbove\\n\\t\\\"Return the type for me according to the message that encloses me.\\\"\\n\\n\\t| enclosing sub list |\\n\\t(self nodeClassIs: BlockNode) ifTrue: [^#command].\\n\\tenclosing := owner.\\n\\tsub := self.\\n\\t\\n\\t[enclosing isSyntaxMorph ifFalse: [^#unknown].\\n\\t(enclosing nodeClassIs: MessageNode) \\n\\t\\tifTrue: \\n\\t\\t\\t[list := enclosing submorphs \\n\\t\\t\\t\\t\\t\\tselect: [:ss | ss isSyntaxMorph and: [ss parseNode notNil]].\\n\\t\\t\\tlist size = 1 \\n\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t[^(list indexOf: sub) = 1 \\n\\t\\t\\t\\t\\t\\tifTrue: [enclosing receiverTypeFor: enclosing selector]\\n\\t\\t\\t\\t\\t\\tifFalse: [enclosing argTypeFor: enclosing selector]]].\\n\\t(enclosing nodeClassIs: BlockNode) ifTrue: [^#command].\\n\\tsub := enclosing.\\n\\tenclosing := enclosing owner.\\n\\ttrue] \\n\\t\\t\\twhileTrue! !\\n\\n!SyntaxMorph methodsFor: 'type checking' stamp: 'sw 2/27/2001 09:11'!\\nreceiverTypeFor: aSelector\\n\\t\\\"Answer the type of the receiver of this selector. Return #unknown if not found.\\\"\\n\\n\\t| itsInterface |\\n\\n\\taSelector ifNil: [^ #unknown].\\n\\titsInterface _ self currentVocabulary methodInterfaceAt: aSelector ifAbsent:\\n\\t\\t[^ #unknown].\\n\\t^ itsInterface receiverType! !\\n\\n!SyntaxMorph methodsFor: 'type checking' stamp: 'yo 7/22/2005 16:43'!\\nresultType\\n\\t\\\"Look up my result type. If I am a constant, use that class. If I am a message, look up the selector.\\\"\\n\\n\\t| list value soundChoices |\\n\\tparseNode class == BlockNode ifTrue: [^#blockContext].\\n\\tparseNode class == AssignmentNode ifTrue: [^#command].\\n\\tparseNode class == ReturnNode ifTrue: [^#command].\\t\\\"Need more restriction than this\\\"\\n\\tlist := submorphs \\n\\t\\t\\t\\tselect: [:ss | ss isSyntaxMorph and: [ss parseNode notNil]].\\n\\tlist size > 1 ifTrue: [^self resultTypeFor: self selector].\\n\\tlist size = 1 \\n\\t\\tifTrue: \\n\\t\\t\\t[\\\"test for levels that are just for spacing in layout\\\"\\n\\n\\t\\t\\t(list first isSyntaxMorph and: [list first nodeClassIs: MessageNode]) \\n\\t\\t\\t\\tifTrue: [^list first resultType]].\\t\\\"go down one level\\\"\\n\\tvalue := self try.\\n\\tvalue class == Error ifTrue: [^#unknown].\\n\\t(value isNumber) ifTrue: [^#Number].\\n\\t(value isKindOf: Boolean) ifTrue: [^#Boolean].\\n\\t(value isForm) ifTrue: [^#Graphic].\\n\\t(value isPlayerLike and: [value costume renderedMorph isMemberOf: KedamaPatchMorph]) ifTrue: [^#Patch].\\n\\tvalue isString\\n\\t\\tifTrue: \\n\\t\\t\\t[soundChoices := #('silence').\\t\\\"default, if no SampledSound class\\\"\\n\\t\\t\\tSmalltalk at: #SampledSound\\n\\t\\t\\t\\tifPresent: [:sampledSound | soundChoices := sampledSound soundNames].\\n\\t\\t\\t(soundChoices includes: value) ifTrue: [^#Sound]].\\n\\t(value isPlayerLike) ifTrue: [^#Player].\\n\\t^value class name asLowercase\\t\\\"asSymbol (not needed)\\\"! !\\n\\n!SyntaxMorph methodsFor: 'type checking' stamp: 'sw 2/24/2001 12:13'!\\nresultTypeFor: aSelector\\n\\t\\\"Answer the result type of selector. Return #unknown if not found.\\\"\\n\\n\\t| itsInterface |\\n\\taSelector ifNil: [self inform: 'Please tell Ted how you caused this'.\\n\\t\\t^ #abs \\\"a bogus type\\\"].\\n\\titsInterface _ self currentVocabulary methodInterfaceAt: aSelector ifAbsent:\\n\\t\\t[^ #unknown].\\n\\t^ itsInterface resultType! !\\n\\n\\n!SyntaxMorph methodsFor: 'updating' stamp: 'di 11/13/2000 20:30'!\\nupdate: aSymbol\\n\\n\\t| bingo saveOwner newMorph db |\\n\\n\\t(db _ self debugger) ifNil: [^super update: aSymbol].\\n\\taSymbol == #contents ifTrue: [\\n\\t\\tsaveOwner _ owner.\\n\\t\\tdb removeDependent: self.\\n\\t\\tmarkerMorph ifNotNil: [markerMorph delete. markerMorph _ nil].\\n\\t\\tnewMorph _ db createSyntaxMorph.\\n\\t\\tself delete.\\n\\t\\tsaveOwner addMorph: newMorph.\\n\\t\\tsaveOwner owner setScrollDeltas.\\n\\t\\tnewMorph update: #contentsSelection.\\n\\t].\\n\\taSymbol == #contentsSelection ifTrue: [\\n\\t\\tmarkerMorph ifNil: [\\n\\t\\t\\tmarkerMorph _ RectangleMorph new.\\n\\t\\t\\tmarkerMorph\\n\\t\\t\\t\\tcolor: Color transparent;\\n\\t\\t\\t\\tborderWidth: 2;\\n\\t\\t\\t\\tborderColor: Color red;\\n\\t\\t\\t\\tlock.\\n\\t\\t\\towner addMorphFront: markerMorph.\\n\\t\\t].\\n\\t\\tbingo _ parseNode rawSourceRanges keyAtValue: db pcRange ifAbsent: [nil].\\n\\t\\tself testForNode: bingo andDo: [ :foundMorph | \\n\\t\\t\\tmarkerMorph\\n\\t\\t\\t\\tposition: foundMorph position;\\n\\t\\t\\t\\textent: foundMorph extent.\\n\\t\\t\\towner owner scrollIntoView: foundMorph bounds extra: 0.5.\\n\\t\\t\\t^self\\n\\t\\t].\\n\\t].\\n\\tsuper update: aSymbol! !\\n\\n\\n!SyntaxMorph methodsFor: 'viewer' stamp: 'tk 11/5/2001 08:32'!\\nexternalName\\n\\n\\t^ self knownName ifNil: [\\n\\t\\tparseNode ifNil: ['Syntax -- (extra layer)']\\n\\t\\t\\t\\tifNotNil: [self parseNode class printString]]! !\\n\\n\\n!SyntaxMorph methodsFor: 'visual properties' stamp: 'tk 7/31/2001 16:53'!\\nfillStyle: aFillStyle\\n\\n\\taFillStyle isColor \\n\\t\\tifTrue: [self color: aFillStyle]\\t\\\"so we will process it\\\"\\n\\t\\tifFalse: [super fillStyle: aFillStyle].\\n! !\\n\\n\\n!SyntaxMorph methodsFor: 'vocabulary' stamp: 'gm 2/22/2003 12:31'!\\nlimitClassToUseWith: aValue vocabulary: aVocabulary \\n\\t\\\"Answer the most generic whose method should be shown in a selector pop-up in the receiver that is put up on behalf of aValue\\\"\\n\\n\\t(aValue isNumber) ifTrue: [^Number].\\n\\t\\\"Ted: This hook allows you to intervene as suits your purposes here if you don't like the defaults.\\\"\\n\\t^aValue defaultLimitClassForVocabulary: aVocabulary! !\\n\\n!SyntaxMorph methodsFor: 'vocabulary' stamp: 'gm 2/22/2003 12:48'!\\nvocabularyToUseWith: aValue \\n\\t\\\"Answer a vocabulary to use with the given value\\\"\\n\\n\\t(aValue isNumber) ifTrue: [^Vocabulary numberVocabulary].\\n\\t(aValue isKindOf: Time) ifTrue: [^Vocabulary vocabularyForClass: Time].\\n\\t(aValue isString) ifTrue: [^Vocabulary vocabularyForClass: String].\\n\\taValue class isUniClass ifTrue: [^Vocabulary eToyVocabulary].\\n\\t^self currentVocabulary! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSyntaxMorph class\\n\\tinstanceVariableNames: ''!\\n\\n!SyntaxMorph class methodsFor: 'accessing' stamp: 'tk 9/18/2001 16:10'!\\nsourceCodeTemplate\\n\\t\\\"Return the default tile method template\\\"\\n\\n\\t^ 'anEmpty: input1 method: input2\\n\\t\\\"Edit the name above and the code below to make your own method\\\"\\n\\t3 + 4.\\n\\t\\\"Drag tiles in here. Use the ''tiles'' and ''vars'' menus to get new tiles\\\"\\n\\t^ ''this is a statement'' sort' \\n! !\\n\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'RAA 2/26/2001 22:59'!\\ncolumn: aColor on: aParseNode\\n\\n\\t| c color |\\n\\tcolor _ self translateColor: aColor.\\n\\t(c _ self newColumn)\\n\\t\\tparseNode: aParseNode;\\n\\t\\tlayoutInset: c standardInset;\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tcolor: color;\\n\\t\\tborderWidth: 1;\\n\\t\\tborderColor: c stdBorderColor;\\n\\t\\twrapCentering: #topLeft;\\n\\t\\tcellPositioning: c standardCellPositioning.\\n\\t^c\\n! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'RAA 2/16/2001 15:37'!\\nmethodNodeOuter: aNode\\n\\n\\t^(self column: #method on: aNode) methodNodeOuter: aNode\\n! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'di 11/13/2000 21:12'!\\nnoTileColor\\n\\n\\t^ true! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'RAA 2/26/2001 23:00'!\\nrow: aColor on: aParseNode\\n\\n\\t| r color |\\n\\tcolor _ self translateColor: aColor.\\n\\t(r _ self newRow)\\n\\t\\tparseNode: aParseNode;\\n\\t\\tlayoutInset: r standardInset;\\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tcolor: color;\\n\\t\\tborderWidth: 1;\\n\\t\\tborderColor: r stdBorderColor;\\n\\t\\twrapCentering: #topLeft;\\n\\t\\tcellPositioning: r standardCellPositioning.\\n\\t^r! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'di 5/2/2001 09:59'!\\nsetSize: oldExtent andMakeResizable: outerMorph\\n\\t| tw |\\n\\t(tw _ outerMorph findA: TwoWayScrollPane) ifNil: [^self].\\n\\ttw hResizing: #spaceFill;\\n\\t\\tvResizing: #spaceFill;\\n\\t\\tcolor: Color transparent;\\n\\t\\tsetProperty: #hideUnneededScrollbars toValue: true.\\n\\touterMorph \\n\\t\\thResizing: #shrinkWrap;\\n\\t\\tvResizing: #shrinkWrap;\\n\\t\\tcellPositioning: #topLeft.\\n\\touterMorph fullBounds.\\n! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'RAA 2/26/2001 22:56'!\\nstandardInset\\n\\n\\t^ self alansTest1 ifTrue: [1] ifFalse: [-1@-1]! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'RAA 8/24/1999 11:59'!\\ntest\\n\\n\\\"\\nSyntaxMorph test\\n\\\"\\n\\tself testClass: MessageNode andMethod: #asMorphicSyntaxIn:.\\n\\t\\\"self testClass: MethodNode andMethod: #asMorphicSyntaxIn:.\\\"\\n\\n! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'dvf 8/23/2003 12:20'!\\ntestAll\\n\\n\\t| source tree total count systNav|\\n\\\"\\nSyntaxMorph testAll\\n\\\"\\n\\tsystNav _ self systemNavigation.\\n\\tcount _ total _ 0.\\n\\tsystNav allBehaviorsDo: [ :aClass | total _ total + 1].\\n'Testing all behaviors'\\n\\tdisplayProgressAt: Sensor cursorPoint\\n\\tfrom: 0 to: total\\n\\tduring: [ :bar |\\n\\t\\tsystNav allBehaviorsDo: [ :aClass |\\n\\t\\t\\tbar value: (count _ count + 1).\\n\\t\\t\\taClass selectors do: [ :aSelector |\\n\\t\\t\\t\\tsource _ (aClass compiledMethodAt: aSelector) getSourceFromFile.\\n\\t\\t\\t\\ttree _ Compiler new \\n\\t\\t\\t\\t\\tparse: source \\n\\t\\t\\t\\t\\tin: aClass \\n\\t\\t\\t\\t\\tnotifying: nil.\\n\\t\\t\\t\\ttree asMorphicSyntaxUsing: SyntaxMorph.\\n\\t\\t\\t].\\n\\t\\t].\\t].\\n\\n\\n! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'dvf 8/23/2003 12:20'!\\ntestAllMethodsOver: methodSize \\n\\t\\\"MessageTally spyOn: [SyntaxMorph testAllMethodsOver: 600]\\\"\\n\\t\\\"Add up the total layout area for syntax morphs representing all \\n\\tmethods over the given size. This is a stress-test for SyntaxMorph \\n\\tlayout. A small value for the total area is also a figure of merit in the \\n\\tpresentation of Squeak source code in general.\\\"\\n\\t\\\"Results: \\n\\t#(69 600 180820874 103700) 11/4 \\n\\t70% build morphs, 12% get source, 9% layout, 8% parse, 1% roundoff \\n\\tFolded wide receivers, don't center keywords any more. \\n\\t#(68 600 160033784 127727) 11/9 \\n\\t76% build morphs, 8% get source, 8% layout, 8% parse, 0% roundoff \\n\\tFolded more messages, dropped extra vertical spacing in blocks. \\n\\t#(68 600 109141704 137308) 11/10 \\n\\t79% build morphs, 6% get source, 8% layout, 7% parse \\n\\tFolded more messages, dropped extra horizontal spacing. \\n\\t#(68 600 106912968 132171) 11/10 \\n\\t80% build morphs, ??% get source, 11% layout, 7% parse \\n\\tUnfolded keyword messages that will fit on one line. \\n\\t#(68 600 96497372 132153) 11/10 \\n\\t81% build morphs, ??% get source, 8% layout, 8% parse \\n\\tAfter alignment rewrite... \\n\\t#(74 600 101082316 244799) 11/12 \\n\\t76% build morphs, 4% get source, 15% layout, 5% parse \\n\\tAfter alignment rewrite... \\n\\t#(74 600 101250620 204972) 11/15 \\n\\t74% build morphs, 6% get source, 13% layout, 7% parse \\n\\t\\\"\\n\\t| tree source biggies morph stats time area |\\n\\tbiggies _ self systemNavigation \\n\\t\\t\\t\\tallMethodsSelect: [:cm | cm size > methodSize].\\n\\tstats _ OrderedCollection new.\\n\\t'Laying out all ' , biggies size printString , ' methods over ' , methodSize printString , ' bytes...'\\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 1\\n\\t\\tto: biggies size\\n\\t\\tduring: [:bar | biggies\\n\\t\\t\\t\\twithIndexDo: [:methodRef :i | \\n\\t\\t\\t\\t\\tbar value: i.\\n\\t\\t\\t\\t\\tUtilities\\n\\t\\t\\t\\t\\t\\tsetClassAndSelectorFrom: methodRef\\n\\t\\t\\t\\t\\t\\tin: [:aClass :aSelector | \\n\\t\\t\\t\\t\\t\\t\\tsource _ (aClass compiledMethodAt: aSelector) getSourceFromFile.\\n\\t\\t\\t\\t\\t\\t\\ttime _ Time\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tmillisecondsToRun: [tree _ Compiler new\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tparse: source\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tin: aClass\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tnotifying: nil.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tmorph _ tree asMorphicSyntaxUsing: SyntaxMorph.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tarea _ morph fullBounds area]].\\n\\t\\t\\t\\t\\tstats add: {methodRef. area. time}]].\\n\\t^ {{biggies size. methodSize. stats\\n\\t\\tdetectSum: [:a | a second]. stats\\n\\t\\tdetectSum: [:a | a third]}. (stats\\n\\t\\tasSortedCollection: [:x :y | x third >= y third]) asArray}! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'di 7/30/2001 16:29'!\\ntestClass: aClass andMethod: aSelector\\n\\t| tree |\\n\\ttree _ Compiler new \\n\\t\\tparse: (aClass sourceCodeAt: aSelector) \\n\\t\\tin: aClass \\n\\t\\tnotifying: nil.\\n\\t(tree asMorphicSyntaxUsing: SyntaxMorph)\\n\\t\\tparsedInClass: aClass;\\n\\t\\topenInWindow! !\\n\\n!SyntaxMorph class methodsFor: 'as yet unclassified' stamp: 'tk 7/19/2001 20:06'!\\ntranslateColor: aColorOrSymbol\\n\\n\\taColorOrSymbol isColor ifTrue: [^ aColorOrSymbol].\\n\\taColorOrSymbol == #comment ifTrue: [^ Color blue lighter].\\n\\taColorOrSymbol == #block ifTrue: [^ Color r: 0.903 g: 1.0 b: 0.903].\\n\\taColorOrSymbol == #method ifTrue: [^ Color r: 0.903 g: 1.0 b: 0.903].\\n\\taColorOrSymbol == #text ifTrue: [^ Color r: 0.9 g: 0.9 b: 0.9].\\n\\n\\tself noTileColor ifTrue: [^ Color r: 1.0 g: 0.839 b: 0.613].\\t\\\"override\\\"\\n\\n\\taColorOrSymbol == #assignment ifTrue: [^ Color paleGreen].\\n\\taColorOrSymbol == #keyword1 ifTrue: [^ Color paleBuff].\\t\\\"binary\\\"\\n\\taColorOrSymbol == #keyword2 ifTrue: [^ Color paleBuff lighter].\\t\\\"multipart\\\" \\n\\taColorOrSymbol == #cascade ifTrue: [^ Color paleYellow darker].\\t\\\"has receiver\\\"\\n\\taColorOrSymbol == #cascade2 ifTrue: [^ Color paleOrange].\\t\\\"one send in the cascade\\\"\\n\\taColorOrSymbol == #literal ifTrue: [^ Color paleMagenta].\\n\\taColorOrSymbol == #message ifTrue: [^ Color paleYellow].\\n\\taColorOrSymbol == #method ifTrue: [^ Color white].\\n\\taColorOrSymbol == #error ifTrue: [^ Color red].\\n\\taColorOrSymbol == #return ifTrue: [^ Color lightGray].\\n\\taColorOrSymbol == #variable ifTrue: [^ Color paleTan].\\n\\taColorOrSymbol == #brace ifTrue: [^ Color paleOrange].\\n\\taColorOrSymbol == #tempVariable ifTrue: [^ Color paleYellow mixed: 0.75 with: Color paleGreen\\n\\t\\t\\\"Color yellow lighter lighter\\\"].\\n\\taColorOrSymbol == #blockarg2 ifTrue: [\\n\\t\\t\\t^ Color paleYellow mixed: 0.75 with: Color paleGreen].\\t\\\"arg itself\\\"\\n\\taColorOrSymbol == #blockarg1 ifTrue: [^ Color paleRed].\\t\\\"container\\\"\\n\\t\\t\\\"yellow mixed: 0.5 with: Color white\\\"\\n\\n\\t^ Color tan\\t\\\"has to be something!!\\\"! !\\n\\n\\n!SyntaxMorph class methodsFor: '*flexibleVocabularies-flexiblevocabularies-accessing' stamp: 'stephaneducasse 2/4/2006 20:33'!\\nallSpecs\\n\\t\\\"Return all specs that the Viewer knows about. Cache them.\\\"\\n\\t\\\"SyntaxMorph allSpecs\\\"\\n\\n\\t^AllSpecs ifNil: [\\n\\t\\tAllSpecs := Dictionary new.\\n\\t\\t(EToyVocabulary morphClassesDeclaringViewerAdditions)\\n\\t\\t\\tdo: [:cls | cls allAdditionsToViewerCategories keysAndValuesDo: [ :k :v | \\n\\t\\t\\t\\t(AllSpecs at: k ifAbsentPut: [ OrderedCollection new ]) addAll: v ] ].\\n\\t\\tAllSpecs\\n\\t]! !\\n\\n!SyntaxMorph class methodsFor: '*flexibleVocabularies-flexiblevocabularies-accessing' stamp: 'stephaneducasse 2/4/2006 20:33'!\\nclearAllSpecs\\n\\t\\\"Clear the specs that the Viewer knows about.\\\"\\n\\t\\\"SyntaxMorph clearAllSpecs\\\"\\n\\n\\tAllSpecs := nil.! !\\nUpdatingStringMorph subclass: #SyntaxUpdatingStringMorph\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'EToys-Tile Scriptors'!\\n\\n!SyntaxUpdatingStringMorph methodsFor: 'drawing' stamp: 'tk 1/31/2002 09:53'!\\ndrawOn: aCanvas\\n\\n\\t| tempForm strm where chars wid spaceWidth putLigature topOfLigature sizeOfLigature colorOfLigature dots charZero canvas f |\\n\\n\\ttempForm _ Form extent: self extent depth: aCanvas depth.\\n\\tcanvas _ tempForm getCanvas.\\n\\tf _ self fontToUse.\\n\\tspaceWidth _ f widthOf: Character space.\\n\\tstrm _ ReadStream on: contents.\\n\\tcharZero _ Character value: 0.\\t\\\"a marker for center dot \\U00b7\\\"\\n\\twhere _ 0@0.\\n\\ttopOfLigature _ self height // 2 - 1.\\n\\tsizeOfLigature _ (spaceWidth-2)@(spaceWidth-2).\\n\\tcolorOfLigature _ Color black alpha: 0.45\\t\\\"veryLightGray\\\".\\n\\tdots _ OrderedCollection new.\\n\\tputLigature _ [\\n\\t\\tdots add: ((where x + 1) @ topOfLigature extent: sizeOfLigature).\\n\\t\\twhere _ where + (spaceWidth@0)].\\n\\tstrm peek = charZero ifTrue: [\\n\\t\\tstrm next.\\n\\t\\tputLigature value].\\n\\t[strm peek = charZero] whileTrue: [strm next].\\n\\t[strm atEnd] whileFalse: [\\n\\t\\tchars _ strm upTo: charZero.\\n\\t\\twid _ f widthOfString: chars.\\n\\t\\tcanvas drawString: chars at: where.\\n\\t\\twhere _ where + (wid@0).\\n\\t\\tstrm atEnd ifFalse: [putLigature value.\\n\\t\\t\\t[strm peek = charZero] whileTrue: [strm next]].\\n\\t].\\n\\taCanvas paintImage: tempForm at: self topLeft.\\n\\tdots do: [ :each |\\n\\t\\taCanvas \\n\\t\\t\\tfillRectangle: (each translateBy: self topLeft) \\n\\t\\t\\tfillStyle: colorOfLigature.\\n\\t].\\n! !\\nAppRegistry subclass: #SystemBrowser\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'Tools-Base'!\\n!SystemBrowser commentStamp: '<historical>' prior: 0!\\nThis is the AppRegistry class for class browsing!\\n\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSystemBrowser class\\n\\tinstanceVariableNames: ''!\\n\\n!SystemBrowser class methodsFor: 'class initialization' stamp: 'sd 11/20/2005 21:28'!\\ninitialize\\n\\t| pref |\\n\\tpref := Preferences preferenceAt: #browserShowsPackagePane.\\n\\tPreferences\\n\\t\\taddPreference: #browserShowsPackagePane\\n\\t\\tcategories: pref categoryList\\n\\t\\tdefault: pref defaultValue\\n\\t\\tballoonHelp: pref helpString\\n\\t\\tprojectLocal: pref localToProject\\n\\t\\tchangeInformee: self\\n\\t\\tchangeSelector: #packagePanePreferenceChanged\\n\\t\\t! !\\n\\n\\n!SystemBrowser class methodsFor: 'events' stamp: 'sd 11/20/2005 21:28'!\\npackagePanePreferenceChanged\\n\\t| theOtherOne |\\n\\tself registeredClasses size = 2\\n\\t\\tifTrue: [theOtherOne := (self registeredClasses copyWithout: PackagePaneBrowser) first]\\n\\t\\tifFalse: [theOtherOne := nil].\\n\\t(Preferences valueOfFlag: #browserShowsPackagePane ifAbsent: [false])\\n\\t\\tifTrue: [self default: PackagePaneBrowser]\\n\\t\\tifFalse: [self default: theOtherOne].\\n\\tSystemNavigation default browserClass: self default.! !\\n\\n\\n!SystemBrowser class methodsFor: 'initialize-release' stamp: 'sd 11/20/2005 21:28'!\\nunload\\n\\t| pref |\\n\\tpref := Preferences preferenceAt: #browserShowsPackagePane.\\n\\tPreferences\\n\\t\\taddPreference: #browserShowsPackagePane\\n\\t\\tcategories: pref categoryList\\n\\t\\tdefault: pref defaultValue\\n\\t\\tballoonHelp: pref helpString\\n\\t\\tprojectLocal: pref localToProject\\n\\t\\tchangeInformee: nil\\n\\t\\tchangeSelector: nil\\n\\t\\t! !\\n\\n\\n!SystemBrowser class methodsFor: 'instance creation' stamp: 'hpt 8/5/2004 20:27'!\\ndefaultOpenBrowser\\n\\t^self default openBrowser! !\\n\\n\\n!SystemBrowser class methodsFor: 'registration' stamp: 'hpt 9/30/2004 20:53'!\\naddRegistryMenuItemsTo: aMenu inAccountOf: aBrowser \\n\\t\\\"Add some useful options related Browser registry to the\\n\\tbrowsers windows menu\\\"\\n\\taMenu addLine;\\n\\t\\tadd: 'Register this Browser as default'\\n\\t\\ttarget: [self default: aBrowser class]\\n\\t\\taction: #value;\\n\\t\\tadd: 'Choose new default Browser'\\n\\t\\ttarget: self\\n\\t\\taction: #askForDefault! !\\nSystemChangeTestRoot subclass: #SystemChangeErrorHandling\\n\\tinstanceVariableNames: 'capturedEvents'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'SystemChangeNotification-Tests'!\\n!SystemChangeErrorHandling commentStamp: 'rw 4/3/2006 17:21' prior: 0!\\nThis class tests the error handing of the notification mechanism to ensure that one client that receives a system change cannot lock up the complete system.\\\"!\\n\\n\\n!SystemChangeErrorHandling methodsFor: 'Event Notifications' stamp: 'rw 4/3/2006 17:57'!\\nhandleEventWithError: event\\n\\n\\tself error: 'Example of event handling code that throws an error.'! !\\n\\n!SystemChangeErrorHandling methodsFor: 'Event Notifications' stamp: 'rw 4/3/2006 18:07'!\\nhandleEventWithHalt: event\\n\\n\\tself halt: 'Example of event handling code that contains a halt.'! !\\n\\n!SystemChangeErrorHandling methodsFor: 'Event Notifications' stamp: 'rw 4/3/2006 17:57'!\\nstoreEvent1: anEvent\\n\\n\\tcapturedEvents add: anEvent! !\\n\\n!SystemChangeErrorHandling methodsFor: 'Event Notifications' stamp: 'rw 4/3/2006 17:57'!\\nstoreEvent2: anEvent\\n\\n\\tcapturedEvents add: anEvent! !\\n\\n!SystemChangeErrorHandling methodsFor: 'Event Notifications' stamp: 'rw 4/3/2006 17:57'!\\nstoreEvent3: anEvent\\n\\n\\tcapturedEvents add: anEvent! !\\n\\n\\n!SystemChangeErrorHandling methodsFor: 'Running' stamp: 'rw 4/3/2006 17:51'!\\nsetUp\\n\\n\\tsuper setUp.\\n\\tcapturedEvents := OrderedCollection new! !\\n\\n!SystemChangeErrorHandling methodsFor: 'Running' stamp: 'rw 4/3/2006 17:56'!\\ntearDown\\n\\n\\tcapturedEvents := nil.\\n\\tsuper tearDown! !\\n\\n\\n!SystemChangeErrorHandling methodsFor: 'Testing' stamp: 'rw 4/5/2006 17:24'!\\ntestErrorOperation\\n\\n\\t| notifier wasCaptured |\\n\\tnotifier := self systemChangeNotifier.\\n\\twasCaptured := false.\\n\\tnotifier notify: self ofSystemChangesOfItem: #class change: #Added using: #storeEvent1:.\\n\\tnotifier notify: self ofSystemChangesOfItem: #class change: #Added using: #storeEvent2:.\\n\\tnotifier notify: self ofSystemChangesOfItem: #class change: #Added using: #handleEventWithError:.\\n\\tnotifier notify: self ofSystemChangesOfItem: #class change: #Added using: #storeEvent3:.\\n\\t[notifier classAdded: self class inCategory: #FooCat] on: Error do: [:exc |\\n\\t\\twasCaptured := true.\\n\\t\\tself assert: (capturedEvents size = 3)].\\n\\tself assert: wasCaptured.! !\\n\\n!SystemChangeErrorHandling methodsFor: 'Testing' stamp: 'rw 4/5/2006 17:24'!\\ntestHaltOperation\\n\\t\\n\\t| notifier wasCaptured |\\n\\tnotifier := self systemChangeNotifier.\\n\\twasCaptured := false.\\n\\tnotifier notify: self ofAllSystemChangesUsing: #storeEvent1:.\\n\\tnotifier notify: self ofAllSystemChangesUsing: #storeEvent2:.\\n\\tnotifier notify: self ofAllSystemChangesUsing: #handleEventWithHalt:.\\n\\tnotifier notify: self ofAllSystemChangesUsing: #storeEvent3:.\\n\\t[notifier classAdded: self class inCategory: #FooCat] on: Halt do: [:exc |\\n\\t\\twasCaptured := true.\\n\\t\\tself assert: (capturedEvents size = 3)].\\n\\tself assert: wasCaptured.! !\\n\\n!SystemChangeErrorHandling methodsFor: 'Testing' stamp: 'rw 4/5/2006 17:24'!\\ntestUnhandledEventOperation\\n\\n\\t| notifier wasCaptured |\\n\\tnotifier := self systemChangeNotifier.\\n\\twasCaptured := false.\\n\\tnotifier notify: self ofSystemChangesOfItem: #class change: #Added using: #storeEvent1:.\\n\\tnotifier notify: self ofSystemChangesOfItem: #class change: #Added using: #storeEvent2:.\\n\\tnotifier notify: self ofSystemChangesOfItem: #class change: #Added using: #zork:.\\n\\tnotifier notify: self ofSystemChangesOfItem: #class change: #Added using: #storeEvent3:.\\n\\t[notifier classAdded: self class inCategory: #FooCat] on: MessageNotUnderstood do: [:exc |\\n\\t\\twasCaptured := true.\\n\\t\\tself assert: (capturedEvents size = 3)].\\n\\tself assert: wasCaptured.! !\\nObject subclass: #SystemChangeNotifier\\n\\tinstanceVariableNames: 'eventSource silenceLevel'\\n\\tclassVariableNames: 'UniqueInstance'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Change Notification'!\\n\\n!SystemChangeNotifier methodsFor: 'initialize' stamp: 'NS 1/26/2004 20:41'!\\ninitialize\\n\\n\\teventSource := SystemEventManager new.\\n\\tsilenceLevel _ 0.! !\\n\\n\\n!SystemChangeNotifier methodsFor: 'public' stamp: 'NS 1/28/2004 11:29'!\\ndoSilently: aBlock\\n\\t\\\"Perform the block, and ensure that no system notification are broadcasted while doing so.\\\"\\n\\n\\t| result |\\n\\tsilenceLevel := silenceLevel + 1.\\n\\t[result := aBlock value] ensure: [silenceLevel > 0 ifTrue: [silenceLevel := silenceLevel - 1]].\\n\\t^ result.! !\\n\\n!SystemChangeNotifier methodsFor: 'public' stamp: 'NS 1/26/2004 20:41'!\\nisBroadcasting\\n\\n\\t^ silenceLevel = 0! !\\n\\n!SystemChangeNotifier methodsFor: 'public' stamp: 'rw 7/29/2003 17:01'!\\nnoMoreNotificationsFor: anObject\\n\\t\\\"Stop sending system notifications to an object.\\\"\\n\\n\\teventSource removeActionsWithReceiver: anObject! !\\n\\n!SystemChangeNotifier methodsFor: 'public' stamp: 'rw 7/10/2003 12:00'!\\nnotify: anObject ofAllSystemChangesUsing: oneArgumentSelector \\n\\t\\\"Notifies an object of any system changes.\\\"\\n\\n\\tself \\n\\t\\tnotify: anObject\\n\\t\\tofEvents: self allSystemEvents\\n\\t\\tusing: oneArgumentSelector! !\\n\\n!SystemChangeNotifier methodsFor: 'public' stamp: 'bvs 7/20/2004 12:13'!\\nnotify: anObject ofSystemChangesOfChange: changeKind using: oneArgumentSelector \\n\\t\\\"Notifies an object of system changes of the specified changeKind (#added, #removed, ...). Evaluate 'AbstractEvent allChangeKinds' to get the complete list.\\\"\\n\\n\\tself \\n\\t\\tnotify: anObject\\n\\t\\tofEvents: (self systemEventsForChange: changeKind)\\n\\t\\tusing: oneArgumentSelector! !\\n\\n!SystemChangeNotifier methodsFor: 'public' stamp: 'bvs 7/20/2004 12:13'!\\nnotify: anObject ofSystemChangesOfItem: itemKind change: changeKind using: oneArgumentSelector \\n\\t\\\"Notifies an object of system changes of the specified itemKind (#class, #category, ...) and changeKind (#added, #removed, ...). This is the finest granularity possible.\\n\\tEvaluate 'AbstractEvent allChangeKinds' to get the complete list of change kinds, and 'AbstractEvent allItemKinds to get all the possible item kinds supported.\\\"\\n\\n\\tself \\n\\t\\tnotify: anObject\\n\\t\\tofEvents: (Bag with: (self systemEventsForItem: itemKind change: changeKind))\\n\\t\\tusing: oneArgumentSelector! !\\n\\n!SystemChangeNotifier methodsFor: 'public' stamp: 'bvs 7/20/2004 12:13'!\\nnotify: anObject ofSystemChangesOfItem: itemKind using: oneArgumentSelector \\n\\t\\\"Notifies an object of system changes of the specified itemKind (#class, #method, #protocol, ...). Evaluate 'AbstractEvent allItemKinds' to get the complete list.\\\"\\n\\n\\tself \\n\\t\\tnotify: anObject\\n\\t\\tofEvents: (self systemEventsForItem: itemKind)\\n\\t\\tusing: oneArgumentSelector! !\\n\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'ab 2/10/2005 16:32'!\\nclassCategoryAdded: aClassCategoryName\\n\\n\\tself trigger: (AddedEvent\\n\\t\\t\\t\\t\\tclassCategory: aClassCategoryName)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'ab 2/10/2005 16:35'!\\nclassCategoryRemoved: aClassCategoryName\\n\\n\\tself trigger: (RemovedEvent\\n\\t\\t\\t\\t\\tclassCategory: aClassCategoryName)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'ab 2/10/2005 16:44'!\\nclassCategoryRenamedFrom: anOldClassCategoryName to: aNewClassCategoryName\\n\\n\\tself trigger: (RenamedEvent\\n\\t\\t\\t\\t\\tclassCategoryRenamedFrom: anOldClassCategoryName \\n\\t\\t\\t\\t\\tto: aNewClassCategoryName)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'rw 7/29/2003 15:12'!\\nclass: aClass recategorizedFrom: oldCategory to: newCategory \\n\\tself trigger: (RecategorizedEvent \\n\\t\\t\\t\\tclass: aClass\\n\\t\\t\\t\\tcategory: newCategory\\n\\t\\t\\t\\toldCategory: oldCategory)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'rw 7/29/2003 15:11'!\\nclassAdded: aClass inCategory: aCategoryName \\n\\tself trigger: (AddedEvent class: aClass category: aCategoryName)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/26/2004 09:37'!\\nclassCommented: aClass\\n\\t\\\"A class with the given name was commented in the system.\\\"\\n\\n\\tself trigger: (CommentedEvent class: aClass)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'rw 7/29/2003 15:11'!\\nclassCommented: aClass inCategory: aCategoryName \\n\\t\\\"A class with the given name was commented in the system.\\\"\\n\\n\\tself trigger: (CommentedEvent class: aClass category: aCategoryName)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/20/2004 19:37'!\\nclassDefinitionChangedFrom: oldClass to: newClass\\n\\tself trigger: (ModifiedClassDefinitionEvent classDefinitionChangedFrom: oldClass to: newClass)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/16/2004 15:10'!\\nclassRemoved: aClass fromCategory: aCategoryName \\n\\tself trigger: (RemovedEvent class: aClass category: aCategoryName)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/27/2004 12:19'!\\nclassRenamed: aClass from: oldClassName to: newClassName inCategory: aCategoryName \\n\\tself trigger: (RenamedEvent \\n\\t\\t\\t\\tclass: aClass\\n\\t\\t\\t\\tcategory: aCategoryName\\n\\t\\t\\t\\toldName: oldClassName\\n\\t\\t\\t\\tnewName: newClassName)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/27/2004 12:48'!\\nclassReorganized: aClass\\n\\tself trigger: (ReorganizedEvent class: aClass)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/19/2004 09:48'!\\nevaluated: textOrStream\\n\\t^ self evaluated: textOrStream context: nil.! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/19/2004 09:47'!\\nevaluated: expression context: aContext\\n\\tself trigger: (DoItEvent \\n\\t\\t\\t\\texpression: expression\\n\\t\\t\\t\\tcontext: aContext)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/27/2004 11:24'!\\nmethodAdded: aMethod selector: aSymbol inClass: aClass \\n\\t\\\"A method with the given selector was added to aClass, but not put in a protocol.\\\"\\n\\n\\tself trigger: (AddedEvent\\n\\t\\t\\t\\tmethod: aMethod \\n\\t\\t\\t\\tselector: aSymbol\\n\\t\\t\\t\\tclass: aClass)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/27/2004 11:24'!\\nmethodAdded: aMethod selector: aSymbol inClass: aClass requestor: requestor\\n\\t\\\"A method with the given selector was added to aClass, but not put in a protocol.\\\"\\n\\n\\tself trigger: (AddedEvent\\n\\t\\t\\t\\tmethod: aMethod \\n\\t\\t\\t\\tselector: aSymbol\\n\\t\\t\\t\\tclass: aClass\\n\\t\\t\\t\\trequestor: requestor)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/27/2004 11:24'!\\nmethodAdded: aMethod selector: aSymbol inProtocol: aCategoryName class: aClass \\n\\t\\\"A method with the given selector was added to aClass in protocol aCategoryName.\\\"\\n\\n\\tself trigger: (AddedEvent\\n\\t\\t\\t\\tmethod: aMethod\\n\\t\\t\\t\\tselector: aSymbol\\n\\t\\t\\t\\tprotocol: aCategoryName\\n\\t\\t\\t\\tclass: aClass)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/27/2004 11:24'!\\nmethodAdded: aMethod selector: aSymbol inProtocol: aCategoryName class: aClass requestor: requestor\\n\\t\\\"A method with the given selector was added to aClass in protocol aCategoryName.\\\"\\n\\n\\tself trigger: (AddedEvent\\n\\t\\t\\t\\tmethod: aMethod\\n\\t\\t\\t\\tselector: aSymbol\\n\\t\\t\\t\\tprotocol: aCategoryName\\n\\t\\t\\t\\tclass: aClass\\n\\t\\t\\t\\trequestor: requestor)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/27/2004 11:41'!\\nmethodChangedFrom: oldMethod to: newMethod selector: aSymbol inClass: aClass\\n\\tself trigger: (ModifiedEvent\\n\\t\\t\\t\\t\\tmethodChangedFrom: oldMethod\\n\\t\\t\\t\\t\\tto: newMethod\\n\\t\\t\\t\\t\\tselector: aSymbol \\n\\t\\t\\t\\t\\tinClass: aClass)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/27/2004 11:41'!\\nmethodChangedFrom: oldMethod to: newMethod selector: aSymbol inClass: aClass requestor: requestor\\n\\tself trigger: (ModifiedEvent\\n\\t\\t\\t\\t\\tmethodChangedFrom: oldMethod\\n\\t\\t\\t\\t\\tto: newMethod\\n\\t\\t\\t\\t\\tselector: aSymbol \\n\\t\\t\\t\\t\\tinClass: aClass\\n\\t\\t\\t\\t\\trequestor: requestor)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/28/2004 11:12'!\\nmethodRemoved: aMethod selector: aSymbol class: aClass \\n\\t\\\"A method with the given selector was removed from the class.\\\"\\n\\n\\tself trigger: (RemovedEvent\\n\\t\\t\\t\\tmethod: aMethod \\n\\t\\t\\t\\tselector: aSymbol\\n\\t\\t\\t\\tclass: aClass)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 1/28/2004 11:11'!\\nmethodRemoved: aMethod selector: aSymbol inProtocol: protocol class: aClass \\n\\t\\\"A method with the given selector was removed from the class.\\\"\\n\\n\\tself trigger: (RemovedEvent\\n\\t\\t\\t\\tmethod: aMethod \\n\\t\\t\\t\\tselector: aSymbol\\n\\t\\t\\t\\tprotocol: protocol\\n\\t\\t\\t\\tclass: aClass)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'NS 4/7/2004 13:35'!\\nselector: selector recategorizedFrom: oldCategory to: newCategory inClass: aClass\\n\\n\\tself trigger: (RecategorizedEvent \\n\\t\\t\\t\\tmethod: (aClass compiledMethodAt: selector ifAbsent: [nil])\\n\\t\\t\\t\\tprotocol: newCategory\\n\\t\\t\\t\\tclass: aClass\\n\\t\\t\\t\\toldProtocol: oldCategory)! !\\n\\n!SystemChangeNotifier methodsFor: 'system triggers' stamp: 'al 7/18/2004 10:48'!\\ntraitDefinitionChangedFrom: oldTrait to: newTrait\\n\\tself trigger: (ModifiedTraitDefinitionEvent traitDefinitionChangedFrom: oldTrait to: newTrait)! !\\n\\n\\n\\n!SystemChangeNotifier methodsFor: 'private' stamp: 'rw 7/10/2003 15:15'!\\nnotify: anObject ofEvents: eventsCollection using: oneArgumentSelector\\n\\t\\\"Notifies an object of any events in the eventsCollection. Send it back a message #oneArgumentSelector, with as argument the particular system event instance.\\\"\\n\\n\\teventsCollection do: [:eachEvent |\\n\\t\\teventSource when: eachEvent send: oneArgumentSelector to: anObject]! !\\n\\n!SystemChangeNotifier methodsFor: 'private' stamp: 'rw 7/29/2003 17:05'!\\nreleaseAll\\n\\t\\\"Release all the dependents so that nobody receives notifications anymore.\\\"\\n\\n\\t\\\"Done for cleaning up the system.\\\"\\n\\t\\\"self uniqueInstance releaseAll\\\"\\n\\n\\teventSource releaseActionMap! !\\n\\n!SystemChangeNotifier methodsFor: 'private' stamp: 'NS 1/26/2004 20:43'!\\nsetBroadcasting\\n\\tsilenceLevel := 0.! !\\n\\n!SystemChangeNotifier methodsFor: 'private' stamp: 'NS 1/26/2004 20:41'!\\ntrigger: event\\n\\n\\tself isBroadcasting ifTrue: [event trigger: eventSource]\\n\\n\\\"\\t| caughtExceptions |\\n\\tcaughtExceptions := OrderedCollection new.\\n\\tself isBroadcasting ifTrue: [\\n\\t\\t[(eventSource actionForEvent: event eventSelector) valueWithArguments: (Array with: event)] on: Exception do: [:exc | caughtExceptions add: exc]].\\n\\tcaughtExceptions do: [:exc | exc resignalAs: exc class new]\\\"! !\\n\\n\\n!SystemChangeNotifier methodsFor: 'private-event lists' stamp: 'rw 7/29/2003 15:14'!\\nallSystemEvents\\n\\t^AbstractEvent systemEvents! !\\n\\n!SystemChangeNotifier methodsFor: 'private-event lists' stamp: 'rw 7/29/2003 15:14'!\\nsystemEventsForChange: changeKind \\n\\t| selectorBlock |\\n\\tselectorBlock := AbstractEvent eventSelectorBlock.\\n\\t^AbstractEvent allItemKinds \\n\\t\\tcollect: [:itemKind | selectorBlock value: itemKind value: changeKind]! !\\n\\n!SystemChangeNotifier methodsFor: 'private-event lists' stamp: 'rw 7/29/2003 15:14'!\\nsystemEventsForItem: itemKind \\n\\t| selectorBlock |\\n\\tselectorBlock := AbstractEvent eventSelectorBlock.\\n\\t^AbstractEvent allChangeKinds \\n\\t\\tcollect: [:changeKind | selectorBlock value: itemKind value: changeKind]! !\\n\\n!SystemChangeNotifier methodsFor: 'private-event lists' stamp: 'rw 7/29/2003 15:14'!\\nsystemEventsForItem: itemKind change: changeKind \\n\\t^AbstractEvent eventSelectorBlock value: itemKind value: changeKind! !\\n\\n\\\"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \\\"!\\n\\nSystemChangeNotifier class\\n\\tinstanceVariableNames: ''!\\n\\n!SystemChangeNotifier class methodsFor: 'instance creation' stamp: 'rw 6/28/2003 09:41'!\\nnew\\n\\n\\t^self error: self instanceCreationErrorString! !\\n\\n\\n!SystemChangeNotifier class methodsFor: 'item kinds' stamp: 'NS 1/21/2004 09:31'!\\ncategoryKind\\n\\n\\t^ AbstractEvent categoryKind! !\\n\\n!SystemChangeNotifier class methodsFor: 'item kinds' stamp: 'NS 1/21/2004 09:31'!\\nclassKind\\n\\n\\t^ AbstractEvent classKind! !\\n\\n!SystemChangeNotifier class methodsFor: 'item kinds' stamp: 'NS 1/21/2004 09:32'!\\nexpressionKind\\n\\t^ AbstractEvent expressionKind! !\\n\\n!SystemChangeNotifier class methodsFor: 'item kinds' stamp: 'NS 1/21/2004 09:31'!\\nmethodKind\\n\\n\\t^ AbstractEvent methodKind! !\\n\\n!SystemChangeNotifier class methodsFor: 'item kinds' stamp: 'NS 1/21/2004 09:32'!\\nprotocolKind\\n\\t^ AbstractEvent protocolKind! !\\n\\n\\n!SystemChangeNotifier class methodsFor: 'public' stamp: 'NS 1/27/2004 16:23'!\\nuniqueInstance\\n\\n\\tUniqueInstance ifNil: [UniqueInstance := self createInstance].\\n\\t^UniqueInstance! !\\n\\n\\n!SystemChangeNotifier class methodsFor: 'private' stamp: 'NS 1/27/2004 16:23'!\\ncreateInstance\\n\\n\\t^self basicNew initialize! !\\n\\n!SystemChangeNotifier class methodsFor: 'private' stamp: 'rw 6/28/2003 09:41'!\\ninstanceCreationErrorString\\n\\n\\t^'This is a singleton implementation, so you are not allowed to create instances yourself. Use #uniqueInstance to access the instance.'! !\\n\\n!SystemChangeNotifier class methodsFor: 'private' stamp: 'rw 7/11/2003 14:36'!\\nresetUniqueInstance\\n\\t\\\"self resetUniqueInstance\\\"\\n\\n\\tUniqueInstance\\n\\t\\tifNotNilDo: [:u | UniqueInstance releaseAll.\\n\\t\\t\\tUniqueInstance _ nil]! !\\nSystemChangeTestRoot subclass: #SystemChangeNotifierTest\\n\\tinstanceVariableNames: 'capturedEvent'\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'SystemChangeNotification-Tests'!\\n!SystemChangeNotifierTest commentStamp: 'rw 4/3/2006 17:19' prior: 0!\\nA SystemChangeNotifierTest is a test class that tests whether the triggering of changes indeed results in the intended changes to be sent to registered object. The basic mechanism for each test is fairly simple:\\n\\t- register the receiver as the one to get the change notifier.\\n\\t- manually trigger a change (so the system is not polluted just to see whether we get the needed event).\\n\\t- the method #event: is invoked and remembers the change event.\\n\\t- the change event is checked to see whether it was the intended one.\\n\\nInstance Variables\\n\\tcapturedEvent:\\t\\tRemembers the captured event!\\n\\n\\n!SystemChangeNotifierTest methodsFor: 'Private' stamp: 'rw 4/3/2006 16:34'!\\ncapturedEvent: eventOrNil\\n\\t\\\"Remember the event being sent.\\\"\\n\\n\\tcapturedEvent := eventOrNil! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Private' stamp: 'rw 4/3/2006 16:36'!\\ncheckEventForClass: aClass category: cat change: changeKind \\n\\n\\tself assert: (capturedEvent perform: ('is' , changeKind) asSymbol).\\n\\tself assert: capturedEvent item = aClass.\\n\\tself assert: capturedEvent itemKind = AbstractEvent classKind.\\n\\tself assert: capturedEvent itemClass = aClass.\\n\\tself assert: capturedEvent itemCategory = cat! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Private' stamp: 'rw 4/3/2006 16:43'!\\ncheckEventForMethod: aMethod protocol: prot change: changeKind \\n\\n\\tself assert: (capturedEvent perform: ('is' , changeKind) asSymbol).\\n\\tself assert: capturedEvent item = aMethod.\\n\\tself assert: capturedEvent itemKind = AbstractEvent methodKind.\\n\\tself assert: capturedEvent itemClass = self class.\\n\\tself assert: capturedEvent itemMethod = aMethod.\\n\\tself assert: capturedEvent itemProtocol = prot! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Private' stamp: 'rw 4/3/2006 16:43'!\\ncheckEventForMethod: aMethod protocol: prot change: changeKind oldMethod: oldMethod\\n\\n\\tself checkEventForMethod: aMethod protocol: prot change: changeKind.\\n\\tself assert: capturedEvent oldItem == oldMethod\\n\\t! !\\n\\n\\n!SystemChangeNotifierTest methodsFor: 'Event Notifications' stamp: 'rw 4/3/2006 17:50'!\\nevent: event\\n\\t\\\"The notification message being sent to me when an event is captured. Remember it.\\\"\\n\\n\\\"\\tcapturedEvent isNil ifTrue: [\\tself capturedEvent: event] ifFalse: [self assert: false]\\\"\\n\\n\\tself capturedEvent: event! !\\n\\n\\n!SystemChangeNotifierTest methodsFor: 'Running' stamp: 'rw 4/3/2006 17:55'!\\ntearDown\\n\\n\\tself capturedEvent: nil.\\n\\tsuper tearDown! !\\n\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:24'!\\ntestClassAddedEvent\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier classAdded: self class inCategory: #FooCat.\\n\\tself\\n\\t\\tcheckEventForClass: self class\\n\\t\\tcategory: #FooCat\\n\\t\\tchange: #Added! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:24'!\\ntestClassAddedEvent2\\n\\n\\tself systemChangeNotifier notify: self ofSystemChangesOfItem: #class change: #Added using: #event:.\\n\\tself systemChangeNotifier classAdded: self class inCategory: #FooCat.\\n\\tself\\n\\t\\tcheckEventForClass: self class\\n\\t\\tcategory: #FooCat\\n\\t\\tchange: #Added! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:24'!\\ntestClassCommentedEvent\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier classCommented: self class inCategory: #FooCat.\\n\\tself\\n\\t\\tcheckEventForClass: self class\\n\\t\\tcategory: #FooCat\\n\\t\\tchange: #Commented! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:24'!\\ntestClassRecategorizedEvent\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier \\n\\t\\tclass: self class\\n\\t\\trecategorizedFrom: #FooCat\\n\\t\\tto: #FooBar.\\n\\tself\\n\\t\\tcheckEventForClass: self class\\n\\t\\tcategory: #FooBar\\n\\t\\tchange: #Recategorized.\\n\\tself assert: capturedEvent oldCategory = #FooCat! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:24'!\\ntestClassRemovedEvent\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier classRemoved: self class fromCategory: #FooCat.\\n\\tself\\n\\t\\tcheckEventForClass: self class\\n\\t\\tcategory: #FooCat\\n\\t\\tchange: #Removed! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:24'!\\ntestClassRenamedEvent\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier \\n\\t\\tclassRenamed: self class\\n\\t\\tfrom: #OldFooClass\\n\\t\\tto: #NewFooClass\\n\\t\\tinCategory: #FooCat.\\n\\tself\\n\\t\\tcheckEventForClass: self class\\n\\t\\tcategory: #FooCat\\n\\t\\tchange: #Renamed.\\n\\\"\\tself assert: capturedEvent oldName = #OldFooClass.\\n\\tself assert: capturedEvent newName = #NewFooClass\\\"! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:25'!\\ntestDoItEvent\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier \\n\\t\\tevaluated: '1 + 2'\\n\\t\\tcontext: self.\\n\\tself assert: capturedEvent isDoIt.\\n\\tself assert: capturedEvent item = '1 + 2'.\\n\\tself assert: capturedEvent itemKind = AbstractEvent expressionKind.\\n\\tself assert: capturedEvent itemClass = nil.\\n\\tself assert: capturedEvent itemMethod = nil.\\n\\tself assert: capturedEvent itemProtocol = nil.\\n\\tself assert: capturedEvent itemExpression = '1 + 2'.\\n\\tself assert: capturedEvent context = self.! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:25'!\\ntestMethodAddedEvent1\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier \\n\\t\\tmethodAdded: self class >> #testMethodAddedEvent1\\n\\t\\tselector: #testMethodAddedEvent1\\n\\t\\tinProtocol: #FooCat\\n\\t\\tclass: self class.\\n\\tself \\n\\t\\tcheckEventForMethod: self class >> #testMethodAddedEvent1\\n\\t\\tprotocol: #FooCat\\n\\t\\tchange: #Added! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:25'!\\ntestMethodAddedEvent2\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier \\n\\t\\tmethodAdded: self class >> #testMethodAddedEvent1\\n\\t\\tselector: #testMethodAddedEvent1\\n\\t\\tinClass: self class.\\n\\tself \\n\\t\\tcheckEventForMethod: self class >> #testMethodAddedEvent1\\n\\t\\tprotocol: nil\\n\\t\\tchange: #Added! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:25'!\\ntestMethodAddedEvent3\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier \\n\\t\\tmethodChangedFrom: self class >> #testMethodAddedEvent1\\n\\t\\tto: self class >> #testMethodAddedEvent2\\n\\t\\tselector: #testMethodAddedEvent2\\n\\t\\tinClass: self class.\\n\\tself \\n\\t\\tcheckEventForMethod: self class >> #testMethodAddedEvent2\\n\\t\\tprotocol: nil\\n\\t\\tchange: #Modified\\n\\t\\toldMethod: self class >> #testMethodAddedEvent1.! !\\n\\n!SystemChangeNotifierTest methodsFor: 'Testing-system triggers' stamp: 'rw 4/5/2006 17:25'!\\ntestMethodRemovedEvent\\n\\n\\tself systemChangeNotifier notify: self ofAllSystemChangesUsing: #event:.\\n\\tself systemChangeNotifier \\n\\t\\tmethodRemoved: self class>> #testMethodRemovedEvent\\n\\t\\tselector: #testMethodRemovedEvent\\n\\t\\tinProtocol: #FooCat\\n\\t\\tclass: self class.\\n\\tself\\n\\t\\tcheckEventForMethod: self class>> #testMethodRemovedEvent\\n\\t\\tprotocol: #FooCat\\n\\t\\tchange: #Removed.! !\\nTestCase subclass: #SystemChangeTestRoot\\n\\tinstanceVariableNames: ''\\n\\tclassVariableNames: ''\\n\\tpoolDictionaries: ''\\n\\tcategory: 'SystemChangeNotification-Tests'!\\n!SystemChangeTestRoot commentStamp: 'rw 4/5/2006 17:28' prior: 0!\\nThe Root test class for the System Change Notification tests.!\\n\\n\\n!SystemChangeTestRoot methodsFor: 'Private' stamp: 'rw 4/3/2006 17:48'!\\nsystemChangeNotifier\\n\\t\\\"The notifier to use. Use the one for the system.\\\"\\n\\n\\t^SystemChangeNotifier uniqueInstance! !\\n\\n\\n!SystemChangeTestRoot methodsFor: 'Running' stamp: 'rw 4/3/2006 17:59'!\\ntearDown\\n\\n\\tself unhook.\\n\\tsuper tearDown! !\\n\\n!SystemChangeTestRoot methodsFor: 'Running' stamp: 'rw 4/3/2006 17:23'!\\nunhook\\n\\n\\tself systemChangeNotifier noMoreNotificationsFor: self! !\\nIdentityDictionary subclass: #SystemDictionary\\n\\tinstanceVariableNames: 'cachedClassNames'\\n\\tclassVariableNames: 'LastImageName LastQuitLogPosition LowSpaceProcess LowSpaceSemaphore MemoryHogs ShutDownList SpecialSelectors StartUpList StartupStamp SystemChanges'\\n\\tpoolDictionaries: ''\\n\\tcategory: 'System-Support'!\\n!SystemDictionary commentStamp: '<historical>' prior: 0!\\nI represent a special dictionary that supports protocol for asking questions about the structure of the system. Other than class names, I contain (print this)...\\n\\tSmalltalk keys select: [:k | ((Smalltalk at: k) isKindOf: Class) not]\\n\\t\\t\\tthenCollect: [:k | k -> (Smalltalk at: k) class]\\n!\\n\\n\\n!SystemDictionary methodsFor: 'accessing' stamp: 'ar 7/11/1999 21:56'!\\norganization\\n\\t\\\"Return the organizer for the receiver\\\"\\n\\t^SystemOrganization! !\\n\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'al 1/12/2006 23:59'!\\nallClassesAndTraits\\n\\t\\\"Return all the classes and traits defined in the Smalltalk SystemDictionary\\\"\\n\\n\\t^ self classNames , self traitNames collect: [:each | self at: each]! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'al 1/13/2006 00:15'!\\nallClassesAndTraitsDo: aBlock\\n\\t^self allClassesAndTraits do: aBlock! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'al 1/12/2006 23:57'!\\nclassNamed: className \\n\\t^self classOrTraitNamed: className.! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'al 1/13/2006 00:51'!\\nclassNames\\n\\t\\\"Answer a SortedCollection of all class names.\\\"\\n\\t| names |\\n\\tcachedClassNames == nil ifTrue:\\n\\t\\t[names _ OrderedCollection new: self size.\\n\\t\\tself do: \\n\\t\\t\\t[:cl | (cl isInMemory\\n\\t\\t\\t\\tand: [(cl isKindOf: Class)\\n\\t\\t\\t\\t\\tand: [(cl name beginsWith: 'AnObsolete') not]])\\n\\t\\t\\t\\tifTrue: [names add: cl name]].\\n\\t\\tcachedClassNames _ names asSortedCollection].\\n\\t^ cachedClassNames! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'al 1/12/2006 23:56'!\\nclassOrTraitNamed: aString \\n\\t\\\"aString is either a class or trait name or a class or trait name followed by ' class' or 'classTrait' respectively.\\n\\tAnswer the class or metaclass it names.\\\"\\n\\n\\t| meta baseName baseClass |\\n\\t(aString endsWith: ' class')\\n\\t\\tifTrue: [meta _ true.\\n\\t\\t\\t\\tbaseName _ aString copyFrom: 1 to: aString size - 6]\\n\\t\\tifFalse: [\\n\\t\\t\\t(aString endsWith: ' classTrait')\\n\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\tmeta _ true.\\n\\t\\t\\t\\t\\tbaseName _ aString copyFrom: 1 to: aString size - 11]\\n\\t\\t\\t\\tifFalse: [\\n\\t\\t\\t\\t\\tmeta _ false.\\n\\t\\t\\t\\t\\tbaseName _ aString]].\\n\\tbaseClass _ Smalltalk at: baseName asSymbol ifAbsent: [^ nil].\\n\\tmeta\\n\\t\\tifTrue: [^ baseClass classSide]\\n\\t\\tifFalse: [^ baseClass]! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'di 2/16/2000 10:28'!\\nflushClassNameCache\\n\\t\\\"Smalltalk flushClassNameCache\\\"\\n\\t\\\"Forse recomputation of the cached list of class names.\\\"\\n\\n\\tcachedClassNames _ nil! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'NS 1/27/2004 12:08'!\\nforgetClass: aClass logged: aBool \\n\\t\\\"Delete the class, aClass, from the system.\\n\\tNote that this doesn't do everything required to dispose of a class - to do that use Class>>removeFromSystem.\\\"\\n\\n\\taBool ifTrue: [SystemChangeNotifier uniqueInstance classRemoved: aClass fromCategory: aClass category].\\t\\t\\n\\tSystemOrganization removeElement: aClass name.\\n\\tself removeFromStartUpList: aClass.\\n\\tself removeFromShutDownList: aClass.\\n\\tself removeKey: aClass name ifAbsent: [].\\n\\tself flushClassNameCache! !\\n\\n!SystemDictionary methodsFor: 'class and trait names'!\\nhasClassNamed: aString\\n\\t\\\"Answer whether there is a class of the given name, but don't intern aString if it's not alrady interned. 4/29/96 sw\\\"\\n\\n\\tSymbol hasInterned: aString ifTrue: \\n\\t\\t[:aSymbol | ^ (self at: aSymbol ifAbsent: [nil]) isKindOf: Class].\\n\\t^ false! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'sw 9/5/97 18:30'!\\nremoveClassNamed: aName\\n\\t\\\"Invoked from fileouts: if there is currently a class in the system named aName, then remove it. If anything untoward happens, report it in the Transcript. \\\"\\n\\n\\t| oldClass |\\n\\t(oldClass _ self at: aName asSymbol ifAbsent: [nil]) == nil\\n\\t\\tifTrue:\\n\\t\\t\\t[Transcript cr; show: 'Removal of class named ', aName, ' ignored because ', aName, ' does not exist.'.\\n\\t\\t\\t^ self].\\n\\n\\toldClass removeFromSystem! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'sw 10/28/96'!\\nrenameClassNamed: oldName as: newName\\n\\t\\\"Invoked from fileouts: if there is currently a class in the system named oldName, then rename it to newName. If anything untoward happens, report it in the Transcript. \\\"\\n\\n\\t| oldClass |\\n\\t(oldClass _ self at: oldName asSymbol ifAbsent: [nil]) == nil\\n\\t\\tifTrue:\\n\\t\\t\\t[Transcript cr; show: 'Class-rename for ', oldName, ' ignored because ', oldName, ' does not exist.'.\\n\\t\\t\\t^ self].\\n\\n\\toldClass rename: newName! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'rr 3/11/2004 15:18'!\\nrenameClass: aClass as: newName \\n\\t\\\"Rename the class, aClass, to have the title newName.\\\"\\n\\t| oldref i oldName category |\\n\\toldName := aClass name.\\n\\tcategory := aClass category.\\n\\tSystemOrganization classify: newName under: aClass category.\\n\\tSystemOrganization removeElement: aClass name.\\n\\toldref _ self associationAt: aClass name.\\n\\tself removeKey: aClass name.\\n\\toldref key: newName.\\n\\tself add: oldref. \\\"Old association preserves old refs\\\"\\n\\t(Array with: StartUpList with: ShutDownList) do:\\n\\t\\t[:list | i _ list indexOf: aClass name ifAbsent: [0].\\n\\t\\ti > 0 ifTrue: [list at: i put: newName]].\\n\\tself flushClassNameCache.\\n\\tSystemChangeNotifier uniqueInstance classRenamed: aClass from: oldName to: newName inCategory: category! !\\n\\n!SystemDictionary methodsFor: 'class and trait names' stamp: 'al 1/12/2006 23:54'!\\ntraitNames\\n\\t\\\"Answer a SortedCollection of all traits (not including class-traits) names.\\\"\\n\\t| names |\\n\\tnames := OrderedCollection new.\\n\\tself do: \\n\\t\\t[:cl | (cl isInMemory\\n\\t\\t\\tand: [(cl isKindOf: Trait)\\n\\t\\t\\tand: [(cl name beginsWith: 'AnObsolete') not]])\\n\\t\\t\\t\\tifTrue: [names add: cl name]].\\n\\t^ names! !\\n\\n\\n!SystemDictionary methodsFor: 'copying' stamp: 'tk 10/20/2000 11:35'!\\nveryDeepCopyWith: deepCopier\\n\\t\\\"Return self. I can't be copied. Do not record me.\\\"! !\\n\\n\\n!SystemDictionary methodsFor: 'dictionary access' stamp: 'md 3/2/2006 22:01'!\\nassociationOrUndeclaredAt: key \\n\\t\\\"return an association or install in undeclared. Used for mating up ImageSegments.\\\"\\n\\n\\t^ self associationAt: key ifAbsent: [\\n\\t\\tUndeclared at: key put: nil.\\n\\t\\tUndeclared associationAt: key]! !\\n\\n!SystemDictionary methodsFor: 'dictionary access'!\\nat: aKey put: anObject \\n\\t\\\"Override from Dictionary to check Undeclared and fix up\\n\\treferences to undeclared variables.\\\"\\n\\t| index element |\\n\\t(self includesKey: aKey) ifFalse: \\n\\t\\t[self declare: aKey from: Undeclared.\\n\\t\\tself flushClassNameCache].\\n\\tsuper at: aKey put: anObject.\\n\\t^ anObject! !\\n\\n\\n!SystemDictionary methodsFor: 'housekeeping'!\\ncleanOutUndeclared \\n\\tUndeclared removeUnreferencedKeys! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'md 1/5/2004 18:05'!\\ncompressSources\\t\\n\\t\\\"Copy all the source file to a compressed file. Usually preceded by Smalltalk condenseSources.\\\"\\n\\t\\\"The new file will be created in the default directory, and the code in openSources\\n\\twill try to open it if it is there, otherwise it will look for normal sources.\\\"\\n\\t\\\"Smalltalk compressSources\\\"\\n\\n\\t| f cfName cf |\\n\\tf _ SourceFiles first.\\n\\t(SmalltalkImage current sourcesName endsWith: 'sources')\\n\\t\\tifTrue: [cfName _ (SmalltalkImage current sourcesName allButLast: 7) , 'stc']\\n\\t\\tifFalse: [self error: 'Hey, I thought the sources name ended with ''.sources''.'].\\n\\tcf _ (CompressedSourceStream on: (FileStream newFileNamed: cfName))\\n\\t\\t\\t\\tsegmentSize: 20000 maxSize: f size.\\n\\n\\t\\\"Copy the sources\\\"\\n'Compressing Sources File...'\\n\\tdisplayProgressAt: Sensor cursorPoint\\n\\tfrom: 0 to: f size\\n\\tduring:\\n\\t\\t[:bar | f position: 0.\\n\\t\\t[f atEnd] whileFalse:\\n\\t\\t\\t[cf nextPutAll: (f next: 20000).\\n\\t\\t\\tbar value: f position]].\\n\\tcf close.\\n\\tself setMacFileInfoOn: cfName.\\n\\tself inform: 'You now have a compressed sources file!!\\nSqueak will use it the next time you start.'! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'al 1/13/2006 00:17'!\\ncondenseChanges\\n\\t\\\"Move all the changes onto a compacted sources file.\\\"\\n\\t\\\"Smalltalk condenseChanges\\\"\\n\\t| f oldChanges count |\\n\\tf := FileStream fileNamed: 'ST80.temp'.\\n\\tf header; timeStamp.\\n\\t'Condensing Changes File...'\\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0\\n\\t\\tto: self classNames size + self traitNames size\\n\\t\\tduring: [:bar | \\n\\t\\t\\tcount := 0.\\n\\t\\t\\tself\\n\\t\\t\\t\\tallClassesAndTraitsDo: [:classOrTrait | \\n\\t\\t\\t\\t\\tbar value: (count := count + 1).\\n\\t\\t\\t\\t\\tclassOrTrait moveChangesTo: f.\\n\\t\\t\\t\\t\\tclassOrTrait putClassCommentToCondensedChangesFile: f.\\n\\t\\t\\t\\t\\tclassOrTrait classSide moveChangesTo: f]].\\n\\tSmalltalkImage current lastQuitLogPosition: f position.\\n\\tf trailer; close.\\n\\toldChanges := SourceFiles at: 2.\\n\\toldChanges close.\\n\\tFileDirectory default deleteFileNamed: oldChanges name , '.old';\\n\\t\\t rename: oldChanges name toBe: oldChanges name , '.old';\\n\\t\\t rename: f name toBe: oldChanges name.\\n\\tself setMacFileInfoOn: oldChanges name.\\n\\tSourceFiles\\n\\t\\tat: 2\\n\\t\\tput: (StandardFileStream oldFileNamed: oldChanges name)! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'md 3/1/2006 00:02'!\\ncondenseSources\\t\\n\\t\\\"Move all the changes onto a compacted sources file.\\\"\\n\\t\\\"Smalltalk condenseSources\\\"\\n\\n\\t| f dir newVersionString count |\\n\\tUtilities fixUpProblemsWithAllCategory.\\n\\t\\\"The above removes any concrete, spurious '-- all --' categories, which mess up the process.\\\"\\n\\tdir := FileDirectory default.\\n\\tnewVersionString := UIManager default request: 'Please designate the version\\nfor the new source code file...' initialAnswer: SmalltalkImage current sourceFileVersionString.\\n\\tnewVersionString ifNil: [^ self].\\n\\tnewVersionString = SmalltalkImage current sourceFileVersionString ifTrue:\\n\\t\\t[^ self error: 'The new source file must not be the same as the old.'].\\n\\tSmalltalkImage current sourceFileVersionString: newVersionString.\\n\\n\\t\\\"Write all sources with fileIndex 1\\\"\\n\\tf := FileStream newFileNamed: SmalltalkImage current sourcesName.\\n\\tf header; timeStamp.\\n'Condensing Sources File...'\\n\\tdisplayProgressAt: Sensor cursorPoint\\n\\tfrom: 0 to: self classNames size + self traitNames size\\n\\tduring:\\n\\t\\t[:bar | count := 0.\\n\\t\\tSmalltalk allClassesAndTraitsDo:\\n\\t\\t\\t[:classOrTrait | bar value: (count := count + 1).\\n\\t\\t\\tclassOrTrait fileOutOn: f moveSource: true toFile: 1]].\\n\\tf trailer; close.\\n\\n\\t\\\"Make a new empty changes file\\\"\\n\\tSmalltalkImage current closeSourceFiles.\\n\\tdir rename: SmalltalkImage current changesName\\n\\t\\ttoBe: SmalltalkImage current changesName , '.old'.\\n\\t(FileStream newFileNamed: SmalltalkImage current changesName)\\n\\t\\theader; timeStamp; close.\\n\\tSmalltalkImage current lastQuitLogPosition: 0.\\n\\n\\tself setMacFileInfoOn: SmalltalkImage current changesName.\\n\\tself setMacFileInfoOn: SmalltalkImage current sourcesName.\\n\\tSmalltalkImage current openSourceFiles.\\n\\tself inform: 'Source files have been rewritten!!\\nCheck that all is well,\\nand then save/quit.'! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'sd 4/17/2003 20:59'!\\nforgetDoIts\\t\\n\\t\\\"Smalltalk forgetDoIts\\\"\\n\\t \\\"get rid of old DoIt methods\\\"\\n\\n\\tself systemNavigation allBehaviorsDo:\\n\\t\\t[:cl | cl forgetDoIts]\\n\\n! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'ar 9/27/2005 21:45'!\\nmakeExternalRelease\\n\\t\\\"Smalltalk makeExternalRelease\\\"\\n\\t(self confirm: SystemVersion current version , '\\nIs this the correct version designation?\\nIf not, choose no, and fix it.')\\n\\t\\tifFalse: [^ self].\\n\\t\\\"Object classPool at: #DependentsFields\\\"\\n\\tself reclaimDependents.\\n\\tPreferences enable: #mvcProjectsAllowed.\\n\\tPreferences enable: #fastDragWindowForMorphic.\\n\\tSmalltalk at: #Browser ifPresent:[:br| br initialize].\\n\\tUndeclared isEmpty\\n\\t\\tifFalse: [self halt].\\n\\tScriptingSystem deletePrivateGraphics.\\n\\t#(#Helvetica #Palatino #Courier )\\n\\t\\tdo: [:n | TextConstants\\n\\t\\t\\t\\tremoveKey: n\\n\\t\\t\\t\\tifAbsent: []].\\n\\t(Utilities classPool at: #UpdateUrlLists) copy\\n\\t\\tdo: [:pair | (pair first includesSubstring: 'Disney' caseSensitive: false)\\n\\t\\t\\t\\tifTrue: [(Utilities classPool at: #UpdateUrlLists)\\n\\t\\t\\t\\t\\t\\tremove: pair]].\\n\\t(ServerDirectory serverNames copyWithoutAll: #('UCSBCreateArchive' 'UIUCArchive' 'UpdatesExtUIUC' 'UpdatesExtWebPage' ))\\n\\t\\tdo: [:sn | ServerDirectory removeServerNamed: sn].\\n\\tself garbageCollect.\\n\\tself obsoleteClasses isEmpty\\n\\t\\tifFalse: [self halt].\\n\\tSymbol rehash.\\n\\tself halt: 'Ready to condense changes or sources'! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'ar 9/27/2005 21:45'!\\nmakeInternalRelease\\n\\t\\\"Smalltalk makeInternalRelease\\\"\\n\\t(self confirm: SystemVersion current version , '\\nIs this the correct version designation?\\nIf not, choose no, and fix it.')\\n\\t\\tifFalse: [^ self].\\n\\t(Object classPool at: #DependentsFields) size > 1\\n\\t\\tifTrue: [self halt].\\n\\tSmalltalk at: #Browser ifPresent:[:br| br initialize].\\n\\tUndeclared isEmpty\\n\\t\\tifFalse: [self halt].\\n\\tself garbageCollect.\\n\\tself obsoleteClasses isEmpty\\n\\t\\tifFalse: [self halt].\\n\\tSymbol rehash.\\n\\tself halt: 'Ready to condense changes'.\\n\\tself condenseChanges! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'sd 9/29/2004 18:15'!\\nreclaimDependents\\n\\t\\\"No-opped due to weak dictionary in use\\\"\\n\\tself garbageCollect! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'al 1/13/2006 00:19'!\\nreconstructChanges\\t\\n\\t\\\"Move all the changes and its histories onto another sources file.\\\"\\n\\t\\\"Smalltalk reconstructChanges\\\"\\n\\n\\t| f oldChanges classCount |\\n\\tf _ FileStream fileNamed: 'ST80.temp'.\\n\\tf header; timeStamp.\\n'Condensing Changes File...'\\n\\tdisplayProgressAt: Sensor cursorPoint\\n\\tfrom: 0 to: self classNames size + self traitNames size\\n\\tduring:\\n\\t\\t[:bar | classCount _ 0.\\n\\t\\tSmalltalk allClassesAndTraitsDo:\\n\\t\\t\\t[:classOrTrait | bar value: (classCount _ classCount + 1).\\n\\t\\t\\tclassOrTrait moveChangesWithVersionsTo: f.\\n\\t\\t\\tclassOrTrait putClassCommentToCondensedChangesFile: f.\\n\\t\\t\\tclassOrTrait classSide moveChangesWithVersionsTo: f]].\\n\\tSmalltalkImage current lastQuitLogPosition: f position.\\n\\tf trailer; close.\\n\\toldChanges _ SourceFiles at: 2.\\n\\toldChanges close.\\n\\tFileDirectory default \\n\\t\\tdeleteFileNamed: oldChanges name , '.old';\\n\\t\\trename: oldChanges name toBe: oldChanges name , '.old';\\n\\t\\trename: f name toBe: oldChanges name.\\n\\tself setMacFileInfoOn: oldChanges name.\\n\\tSourceFiles at: 2\\n\\t\\t\\tput: (FileStream oldFileNamed: oldChanges name)! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'yo 2/24/2005 18:01'!\\nreformatChangesToUTF8\\n\\t\\\"Smalltalk reformatChangesToUTF8\\\"\\n\\n\\t| f oldChanges classCount |\\n\\tf _ FileStream fileNamed: 'ST80.temp'.\\n\\tf converter: (UTF8TextConverter new).\\n\\tf header; timeStamp.\\n'Condensing Changes File...'\\n\\tdisplayProgressAt: Sensor cursorPoint\\n\\tfrom: 0 to: Smalltalk classNames size\\n\\tduring:\\n\\t\\t[:bar | classCount _ 0.\\n\\t\\tSmalltalk allClassesDo:\\n\\t\\t\\t[:class | bar value: (classCount _ classCount + 1).\\n\\t\\t\\tclass moveChangesTo: f.\\n\\t\\t\\tclass putClassCommentToCondensedChangesFile: f.\\n\\t\\t\\tclass class moveChangesTo: f]].\\n\\tSmalltalkImage current lastQuitLogPosition: f position.\\n\\tf trailer; close.\\n\\toldChanges _ SourceFiles at: 2.\\n\\toldChanges close.\\n\\tFileDirectory default \\n\\t\\tdeleteFileNamed: oldChanges name , '.old';\\n\\t\\trename: oldChanges name toBe: oldChanges name , '.old';\\n\\t\\trename: f name toBe: oldChanges name.\\n\\tself setMacFileInfoOn: oldChanges name.\\n\\tSourceFiles at: 2\\n\\t\\t\\tput: (FileStream oldFileNamed: oldChanges name).\\n\\tMultiByteFileStream codeConverterClass: UTF8TextConverter.\\n\\t(SourceFiles at: 2) converter: (UTF8TextConverter new).\\n! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'nk 6/2/2006 10:22'!\\nremoveAllLineFeeds\\n\\t\\\"Smalltalk removeAllLineFeeds\\\"\\n\\t\\\"Scan all methods for source code with lineFeeds.\\n\\tReplaces all occurrences of <CR><LF> or <LF> by <CR>.\\n\\tWhen done, offers to display an Inspector containing the message\\n\\tnames grouped by author initials.\\n\\tIn this dictionary, the key 'OK' contains the methods that had literals that contained <LF> characters.\\\"\\n\\t| n authors totalStripped totalOK |\\n\\t'Scanning sources for LineFeeds.\\nThis will take a few minutes...'\\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0\\n\\t\\tto: CompiledMethod instanceCount\\n\\t\\tduring: [:bar | \\n\\t\\t\\tn _ 0.\\n\\t\\t\\tauthors _ self\\n\\t\\t\\t\\t\\t\\tremoveAllLineFeedsQuietlyCalling: [:cls :sel | (n _ n + 1) \\\\\\\\ 100 = 0\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [bar value: n]]].\\n\\ttotalStripped _ authors\\n\\t\\t\\t\\tinject: 1\\n\\t\\t\\t\\tinto: [:sum :set | sum + set size].\\n\\ttotalOK _ (authors at: 'OK') size.\\n\\ttotalStripped _ totalStripped - totalOK.\\n\\tTranscript cr; show: totalStripped printString , ' methods stripped of LFs.'.\\n\\tTranscript cr; show: totalOK printString , ' methods still correctly contain LFs.'.\\n\\t(self confirm: 'Do you want to see the affected methods?')\\n\\t\\tifTrue: [authors inspect]! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'nk 6/2/2006 08:35'!\\nremoveAllLineFeedsQuietly\\n\\t\\\"Smalltalk removeAllLineFeedsQuietly\\\"\\n\\t\\\"Scan all methods for source code with lineFeeds.\\n\\tReplaces all occurrences of <CR><LF> or <LF> by <CR>.\\n\\tAnswer a Dictionary keyed by author name containing sets of affected method names,\\n\\tas well as (at the key 'OK') a list of methods that still contain LF characters inside literal strings or characters.\\\"\\n\\t^self removeAllLineFeedsQuietlyCalling: [ :cls :sel | ].! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'nk 6/2/2006 09:22'!\\nremoveAllLineFeedsQuietlyCalling: aBlock\\n\\t\\\"Smalltalk removeAllLineFeedsQuietly\\\"\\n\\t\\\"Scan all methods for source code with lineFeeds.\\n\\tReplaces all occurrences of <CR><LF> or <LF> by <CR>.\\n\\tAnswer a Dictionary keyed by author name containing sets of affected method names,\\n\\tas well as (at the key 'OK') a list of methods that still contain LF characters inside literal strings or characters.\\n\\tEvaluate aBlock for each method so that status can be updated.\\\"\\n\\t| oldCodeString newCodeString oldStamp oldCategory authors nameString |\\n\\tself forgetDoIts.\\n\\tauthors _ Dictionary new.\\n\\tauthors at: 'OK' put: Set new.\\n\\tself systemNavigation\\n\\t\\tallBehaviorsDo: [:cls | cls selectors\\n\\t\\t\\t\\tdo: [:selector | \\n\\t\\t\\t\\t\\taBlock value: cls value: selector.\\n\\t\\t\\t\\t\\toldCodeString _ cls sourceCodeAt: selector.\\n\\t\\t\\t\\t\\t(oldCodeString includes: Character lf)\\n\\t\\t\\t\\t\\t\\tifTrue: [\\n\\t\\t\\t\\t\\t\\t\\tnewCodeString _ oldCodeString withSqueakLineEndings.\\n\\t\\t\\t\\t\\t\\t\\tnameString _ cls name , '>>' , selector.\\n\\t\\t\\t\\t\\t\\t\\t((cls compiledMethodAt: selector) hasLiteralSuchThat: [ :lit | lit asString includes: Character lf ])\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [(authors at: 'OK')\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tadd: nameString]\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: [oldStamp _ (Utilities\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\ttimeStampForMethod: (cls compiledMethodAt: selector))\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcopy replaceAll: Character cr\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\twith: Character space.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t(authors\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tat: (oldStamp copyFrom: 1 to: (oldStamp findFirst: [ :c | c isAlphaNumeric not ]))\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifAbsentPut: [Set new])\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tadd: nameString.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\toldCategory _ cls whichCategoryIncludesSelector: selector.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tcls\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcompile: newCodeString\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tclassified: oldCategory\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\twithStamp: oldStamp\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tnotifying: nil ]]]].\\n\\t^ authors! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'sd 9/29/2004 18:15'!\\nremoveEmptyMessageCategories\\n\\t\\\"Smalltalk removeEmptyMessageCategories\\\"\\n\\tself garbageCollect.\\n\\t(ClassOrganizer allInstances copyWith: SystemOrganization)\\n\\t\\tdo: [:org | org removeEmptyCategories]! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'nk 2/23/2005 18:00'!\\ntestFormatter\\n\\t\\\"Smalltalk testFormatter\\\"\\n\\n\\t\\\"Reformats the source for every method in the system, and\\n\\tthen compiles that source and verifies that it generates\\n\\tidentical code. The formatting used will be either classic\\n\\tmonochrome or fancy polychrome, depending on the setting\\n\\tof the preference #colorWhenPrettyPrinting.\\\"\\n\\n\\t| newCodeString methodNode oldMethod newMethod badOnes n |\\n\\tbadOnes := OrderedCollection new.\\n\\tself forgetDoIts.\\n\\t'Formatting all classes...' \\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0\\n\\t\\tto: CompiledMethod instanceCount\\n\\t\\tduring: \\n\\t\\t\\t[:bar | \\n\\t\\t\\tn := 0.\\n\\t\\t\\tself systemNavigation allBehaviorsDo: \\n\\t\\t\\t\\t\\t[:cls | \\n\\t\\t\\t\\t\\t\\\"Transcript cr; show: cls name.\\\"\\n\\n\\t\\t\\t\\t\\tcls selectors do: \\n\\t\\t\\t\\t\\t\\t\\t[:selector | \\n\\t\\t\\t\\t\\t\\t\\t(n := n + 1) \\\\\\\\ 100 = 0 ifTrue: [bar value: n].\\n\\t\\t\\t\\t\\t\\t\\tnewCodeString := cls prettyPrinterClass \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tformat: (cls sourceCodeAt: selector)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tin: cls\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tnotifying: nil\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tdecorated: Preferences colorWhenPrettyPrinting.\\n\\t\\t\\t\\t\\t\\t\\tmethodNode := cls compilerClass new \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcompile: newCodeString\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tin: cls\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tnotifying: nil\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tifFail: [].\\n\\t\\t\\t\\t\\t\\t\\tnewMethod := methodNode generate: #(0 0 0 0).\\n\\t\\t\\t\\t\\t\\t\\toldMethod := cls compiledMethodAt: selector.\\n\\t\\t\\t\\t\\t\\t\\toldMethod = newMethod \\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[Transcript\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcr;\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tshow: '***' , cls name , ' ' , selector.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbadOnes add: cls name , ' ' , selector]]]].\\n\\tself systemNavigation browseMessageList: badOnes asSortedCollection\\n\\t\\tname: 'Formatter Discrepancies'! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'nk 2/23/2005 18:00'!\\ntestFormatter2\\n\\t\\\"Smalltalk testFormatter2\\\"\\n\\n\\t\\\"Reformats the source for every method in the system, and\\n\\tthen verifies that the order of source tokens is unchanged.\\n\\tThe formatting used will be either classic monochrome or\\n\\tfancy polychrome, depending on the setting of the preference\\n\\t#colorWhenPrettyPrinting. \\\"\\n\\n\\t| newCodeString badOnes n oldCodeString oldTokens newTokens |\\n\\tbadOnes := OrderedCollection new.\\n\\tself forgetDoIts.\\n\\t'Formatting all classes...' \\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0\\n\\t\\tto: CompiledMethod instanceCount\\n\\t\\tduring: \\n\\t\\t\\t[:bar | \\n\\t\\t\\tn := 0.\\n\\t\\t\\tself systemNavigation allBehaviorsDo: \\n\\t\\t\\t\\t\\t[:cls | \\n\\t\\t\\t\\t\\t\\\"Transcript cr; show: cls name.\\\"\\n\\n\\t\\t\\t\\t\\tcls selectors do: \\n\\t\\t\\t\\t\\t\\t\\t[:selector | \\n\\t\\t\\t\\t\\t\\t\\t(n := n + 1) \\\\\\\\ 100 = 0 ifTrue: [bar value: n].\\n\\t\\t\\t\\t\\t\\t\\toldCodeString := (cls sourceCodeAt: selector) asString.\\n\\t\\t\\t\\t\\t\\t\\tnewCodeString := cls prettyPrinterClass \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tformat: oldCodeString\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tin: cls\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tnotifying: nil\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tdecorated: Preferences colorWhenPrettyPrinting.\\n\\t\\t\\t\\t\\t\\t\\toldTokens := oldCodeString findTokens: Character separators.\\n\\t\\t\\t\\t\\t\\t\\tnewTokens := newCodeString findTokens: Character separators.\\n\\t\\t\\t\\t\\t\\t\\toldTokens = newTokens \\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t[Transcript\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tcr;\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tshow: '***' , cls name , ' ' , selector.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tbadOnes add: cls name , ' ' , selector]]]].\\n\\tself systemNavigation browseMessageList: badOnes asSortedCollection\\n\\t\\tname: 'Formatter Discrepancies'! !\\n\\n!SystemDictionary methodsFor: 'housekeeping' stamp: 'sd 4/17/2003 21:01'!\\nverifyChanges\\t\\t\\\"Smalltalk verifyChanges\\\"\\n\\t\\\"Recompile all methods in the changes file.\\\"\\n\\tself systemNavigation allBehaviorsDo: [:class | class recompileChanges].\\n! !\\n\\n\\n!SystemDictionary methodsFor: 'image, changes name' stamp: 'yo 3/29/2004 09:36'!\\nprimImageName\\n\\t\\\"Answer the full path name for the current image.\\\"\\n\\t\\\"Smalltalk imageName\\\"\\n\\n\\t<primitive: 121>\\n\\tself primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'image, changes name' stamp: 'yo 3/29/2004 09:36'!\\nprimImageName: newName\\n\\t\\\"Set the the full path name for the current image. All further snapshots will use this.\\\"\\n\\n\\t<primitive: 121>\\n\\t^ self primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'image, changes name' stamp: 'yo 3/29/2004 09:36'!\\nprimVmPath\\n\\t\\\"Answer the path for the directory containing the Smalltalk virtual machine. Return the empty string if this primitive is not implemented.\\\"\\n\\t\\\"Smalltalk vmPath\\\"\\n\\n\\t<primitive: 142>\\n\\t^ ''! !\\n\\n\\n!SystemDictionary methodsFor: 'memory space'!\\nbytesLeft\\n\\t\\\"Answer the number of bytes of space available. Does a full garbage collection.\\\"\\n\\n\\t^ self garbageCollect\\n! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'ar 2/25/2001 18:00'!\\nbytesLeftString\\n\\t\\\"Return a string describing the amount of memory available\\\"\\n\\t| availInternal availPhysical availTotal |\\n\\tself garbageCollect.\\n\\tavailInternal _ self primBytesLeft.\\n\\tavailPhysical _ self bytesLeft: false.\\n\\tavailTotal _ self bytesLeft: true.\\n\\t(availTotal > (availInternal + 10000)) \\\"compensate for mini allocations inbetween\\\"\\n\\t\\tifFalse:[^availInternal asStringWithCommas, ' bytes available'].\\n\\t^String streamContents:[:s|\\n\\t\\ts nextPutAll: availInternal asStringWithCommas, \\t' bytes (internal) '; cr.\\n\\t\\ts nextPutAll: availPhysical asStringWithCommas,\\t' bytes (physical) '; cr.\\n\\t\\ts nextPutAll: availTotal asStringWithCommas, \\t' bytes (total) '].! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'ar 2/25/2001 17:55'!\\nbytesLeft: aBool\\n\\t\\\"Return the amount of available space. If aBool is true, include possibly available swap space. If aBool is false, include possibly available physical memory. For a report on the largest free block currently availabe within Squeak memory but not counting extra memory use #primBytesLeft.\\\"\\n\\t<primitive: 112>\\n\\t^self primBytesLeft! !\\n\\n!SystemDictionary methodsFor: 'memory space'!\\ncreateStackOverflow\\n\\t\\\"For testing the low space handler...\\\"\\n\\t\\\"Smalltalk installLowSpaceWatcher; createStackOverflow\\\"\\n\\n\\tself createStackOverflow. \\\"infinite recursion\\\"! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'JMM 1/27/2005 13:23'!\\nforceTenure\\n\\t\\\"Primitive. Tell the GC logic to force a tenure on the next increment GC.\\\"\\n\\t<primitive: 'primitiveForceTenure'>\\n\\t^self primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'ar 2/11/2001 02:36'!\\ngarbageCollect\\n\\t\\\"Primitive. Reclaims all garbage and answers the number of bytes of available space.\\\"\\n\\tObject flushDependents.\\n\\tObject flushEvents.\\n\\t^self primitiveGarbageCollect! !\\n\\n!SystemDictionary methodsFor: 'memory space'!\\ngarbageCollectMost\\n\\t\\\"Primitive. Reclaims recently created garbage (which is usually most of it) fairly quickly and answers the number of bytes of available space.\\\"\\n\\n\\t<primitive: 131>\\n\\t^ self primBytesLeft! !\\n\\n!SystemDictionary methodsFor: 'memory space'!\\ninstallLowSpaceWatcher\\n\\t\\\"Start a process to watch for low-space conditions.\\\"\\n\\t\\\"Smalltalk installLowSpaceWatcher\\\"\\n\\n\\tself primSignalAtBytesLeft: 0. \\\"disable low-space interrupts\\\"\\n\\tLowSpaceProcess == nil ifFalse: [LowSpaceProcess terminate].\\n\\tLowSpaceProcess _ [self lowSpaceWatcher] newProcess.\\n\\tLowSpaceProcess priority: Processor lowIOPriority.\\n\\tLowSpaceProcess resume.\\n\\n! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'ar 1/18/2005 16:46'!\\nisRoot: oop\\n\\t\\\"Primitive. Answer whether the object is currently a root for youngSpace.\\\"\\n\\t<primitive: 'primitiveIsRoot'>\\n\\t^self primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'ar 1/18/2005 16:47'!\\nisYoung: oop\\n\\t\\\"Primitive. Answer whether the object currently resides in youngSpace.\\\"\\n\\t<primitive: 'primitiveIsYoung'>\\n\\t^self primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'di 8/18/2000 16:49'!\\nlowSpaceThreshold \\n\\t\\\"Return the low space threshold. When the amount of free memory (after garbage collection) falls below this limit, the system is in serious danger of completely exhausting memory and crashing. This limit should be made high enough to allow the user open a debugger to diagnose a problem or to save the image.\\\"\\n\\n\\tthisContext isPseudoContext\\n\\t\\tifTrue: [^ 400000 \\\"Enough for JIT compiler\\\"]\\n\\t\\tifFalse: [^ 200000 \\\"Enough for interpreter\\\"]! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'dtl 10/3/2005 06:12'!\\nlowSpaceWatcher\\n\\t\\\"Wait until the low space semaphore is signalled, then take appropriate actions.\\\"\\n\\n\\t| free preemptedProcess |\\n\\tself garbageCollectMost <= self lowSpaceThreshold\\n\\t\\tifTrue: [self garbageCollect <= self lowSpaceThreshold\\n\\t\\t\\t\\tifTrue: [\\\"free space must be above threshold before\\n\\t\\t\\t\\t\\tstarting low space watcher\\\"\\n\\t\\t\\t\\t\\t^ Beeper beep]].\\n\\n\\tSmalltalk specialObjectsArray at: 23 put: nil. \\\"process causing low space will be saved here\\\"\\n\\tLowSpaceSemaphore _ Semaphore new.\\n\\tself primLowSpaceSemaphore: LowSpaceSemaphore.\\n\\tself primSignalAtBytesLeft: self lowSpaceThreshold. \\\"enable low space interrupts\\\"\\n\\n\\tLowSpaceSemaphore wait. \\\"wait for a low space condition...\\\"\\n\\n\\tself primSignalAtBytesLeft: 0. \\\"disable low space interrupts\\\"\\n\\tself primLowSpaceSemaphore: nil.\\n\\tLowSpaceProcess _ nil.\\n\\n\\t\\\"The process that was active at the time of the low space interrupt.\\\"\\n\\tpreemptedProcess _ Smalltalk specialObjectsArray at: 23.\\n\\tSmalltalk specialObjectsArray at: 23 put: nil.\\n\\n\\t\\\"Note: user now unprotected until the low space watcher is re-installed\\\"\\n\\n\\tself memoryHogs isEmpty\\n\\t\\tifFalse: [free := self bytesLeft.\\n\\t\\t\\tself memoryHogs\\n\\t\\t\\t\\tdo: [ :hog | hog freeSomeSpace ].\\n\\t\\t\\tself bytesLeft > free\\n\\t\\t\\t\\tifTrue: [ ^ self installLowSpaceWatcher ]].\\n\\tself isMorphic\\n\\t\\tifTrue: [CurrentProjectRefactoring\\n\\t\\t\\t\\tcurrentInterruptName: 'Space is low'\\n\\t\\t\\t\\tpreemptedProcess: preemptedProcess]\\n\\t\\tifFalse: [ScheduledControllers\\n\\t\\t\\t\\tinterruptName: 'Space is low'\\n\\t\\t\\t\\tpreemptedProcess: preemptedProcess]\\n! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'nk 10/28/2000 20:37'!\\nlowSpaceWatcherProcess\\n\\t^LowSpaceProcess! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'sma 4/22/2000 19:03'!\\nmemoryHogs\\n\\t\\\"Answer the list of objects to notify with #freeSomeSpace if memory gets full.\\\"\\n\\n\\t^ MemoryHogs ifNil: [MemoryHogs _ OrderedCollection new]! !\\n\\n!SystemDictionary methodsFor: 'memory space'!\\nokayToProceedEvenIfSpaceIsLow\\n\\t\\\"Return true if either there is enough memory to do so safely or if the user gives permission after being given fair warning.\\\"\\n\\n\\tself garbageCollectMost > self lowSpaceThreshold ifTrue: [^ true]. \\\"quick\\\"\\n\\tself garbageCollect > self lowSpaceThreshold ifTrue: [^ true]. \\\"work harder\\\"\\n\\n\\t^ self confirm:\\n'WARNING: There is not enough space to start the low space watcher.\\nIf you proceed, you will not be warned again, and the system may\\nrun out of memory and crash. If you do proceed, you can start the\\nlow space notifier when more space becomes available simply by\\nopening and then closing a debugger (e.g., by hitting Cmd-period.)\\nDo you want to proceed?'\\n! !\\n\\n!SystemDictionary methodsFor: 'memory space'!\\nprimBytesLeft\\n\\t\\\"Primitive. Answer the number of bytes available for new object data.\\n\\tNot accurate unless preceded by\\n\\t\\tSmalltalk garbageCollectMost (for reasonable accuracy), or\\n\\t\\tSmalltalk garbageCollect (for real accuracy).\\n\\tSee Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 112>\\n\\t^ 0! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'ar 2/11/2001 02:16'!\\nprimitiveGarbageCollect\\n\\t\\\"Primitive. Reclaims all garbage and answers the number of bytes of available space.\\\"\\n\\n\\t<primitive: 130>\\n\\t^ self primBytesLeft! !\\n\\n!SystemDictionary methodsFor: 'memory space'!\\nprimLowSpaceSemaphore: aSemaphore\\n\\t\\\"Primitive. Register the given Semaphore to be signalled when the\\n\\tnumber of free bytes drops below some threshold. Disable low-space\\n\\tinterrupts if the argument is nil.\\\"\\n\\n\\t<primitive: 124>\\n\\tself primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'memory space'!\\nprimSignalAtBytesLeft: numBytes\\n\\t\\\"Tell the interpreter the low-space threshold in bytes. When the free\\n\\tspace falls below this threshold, the interpreter will signal the low-space\\n\\tsemaphore, if one has been registered. Disable low-space interrupts if the\\n\\targument is zero. Fail if numBytes is not an Integer.\\\"\\n\\n\\t<primitive: 125>\\n\\tself primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'ar 1/18/2005 16:48'!\\nrootTable\\n\\t\\\"Primitive. Answer a snapshot of the VMs root table. \\n\\tKeep in mind that the primitive may itself cause GC.\\\"\\n\\t<primitive: 'primitiveRootTable'>\\n\\t^self primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'ar 1/18/2005 16:49'!\\nrootTableAt: index\\n\\t\\\"Primitive. Answer the nth element of the VMs root table\\\"\\n\\t<primitive: 'primitiveRootTableAt'>\\n\\t^nil! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'JMM 1/27/2005 12:27'!\\nsetGCBiasToGrowGCLimit: aNumber\\n\\t\\\"Primitive. Indicate that the bias to grow logic should do a GC after aNumber Bytes\\\"\\n\\t<primitive: 'primitiveSetGCBiasToGrowGCLimit'>\\n\\t^self primitiveFailed\\n\\\"Example:\\n\\tSmalltalk setGCBiasToGrowGCLimit: 16*1024*1024.\\n\\\"! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'JMM 1/27/2005 13:12'!\\nsetGCBiasToGrow: aNumber\\n\\t\\\"Primitive. Indicate that the GC logic should be bias to grow\\\"\\n\\t<primitive: 'primitiveSetGCBiasToGrow'>\\n\\t^self primitiveFailed\\n\\\"Example:\\n\\tSmalltalk setGCBiasToGrowGCLimit: 16*1024*1024.\\n\\tSmalltalk setGCBiasToGrow: 1.\\n\\\"! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'ar 1/18/2005 16:54'!\\nsetGCSemaphore: semaIndex\\n\\t\\\"Primitive. Indicate the GC semaphore index to be signaled on GC occurance.\\\"\\n\\t<primitive: 'primitiveSetGCSemaphore'>\\n\\t^self primitiveFailed\\n\\\"Example:\\n\\n\\t| index sema process |\\n\\tsema := Semaphore new.\\n\\tindex := Smalltalk registerExternalObject: sema.\\n\\tSmalltalk setGCSemaphore: index.\\n\\tprocess := [\\n\\t\\t[[true] whileTrue:[\\n\\t\\t\\tsema wait.\\n\\t\\t\\tSmalltalk beep.\\n\\t\\t]] ensure:[\\n\\t\\t\\tSmalltalk setGCSemaphore: 0.\\n\\t\\t\\tSmalltalk unregisterExternalObject: sema.\\n\\t\\t].\\n\\t] fork.\\n\\tprocess inspect.\\n\\\"! !\\n\\n!SystemDictionary methodsFor: 'memory space'!\\nsignalLowSpace\\n\\t\\\"Signal the low-space semaphore to alert the user that space is running low.\\\"\\n\\n\\tLowSpaceSemaphore signal.! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'apb 10/3/2000 16:40'!\\nuseUpMemory\\n\\t\\\"For testing the low space handler...\\\"\\n\\t\\\"Smalltalk installLowSpaceWatcher; useUpMemory\\\"\\n\\n\\t| lst |\\n\\tlst _ nil.\\n\\t[true] whileTrue: [\\n\\t\\tlst _ Link nextLink: lst.\\n\\t].! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'di 8/18/2000 21:15'!\\nuseUpMemoryWithArrays \\n\\t\\\"For testing the low space handler...\\\"\\n\\t\\\"Smalltalk installLowSpaceWatcher; useUpMemoryWithArrays\\\"\\n\\n\\t| b | \\\"First use up most of memory.\\\"\\n\\tb _ String new: self bytesLeft - self lowSpaceThreshold - 100000.\\n\\tb _ b. \\\"Avoid unused value warning\\\"\\n\\t(1 to: 10000) collect: [:i | Array new: 10000]! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'di 8/18/2000 16:49'!\\nuseUpMemoryWithContexts \\n\\t\\\"For testing the low space handler...\\\"\\n\\t\\\"Smalltalk installLowSpaceWatcher; useUpMemoryWithContexts\\\"\\n\\n\\tself useUpMemoryWithContexts! !\\n\\n!SystemDictionary methodsFor: 'memory space' stamp: 'di 8/18/2000 16:50'!\\nuseUpMemoryWithTinyObjects \\n\\t\\\"For testing the low space handler...\\\"\\n\\t\\\"Smalltalk installLowSpaceWatcher; useUpMemoryWithTinyObjects\\\"\\n\\n\\t| b | \\\"First use up most of memory.\\\"\\n\\tb _ String new: self bytesLeft - self lowSpaceThreshold - 100000.\\n\\tb _ b. \\\"Avoid unused value warning\\\"\\n\\t(1 to: 10000) collect: [:i | BitBlt new]! !\\n\\n\\n!SystemDictionary methodsFor: 'miscellaneous'!\\nexitToDebugger\\n\\t\\\"Primitive. Enter the machine language debugger, if one exists. Essential.\\n\\tSee Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 114>\\n\\tself primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'miscellaneous' stamp: 'dao 10/1/2004 13:33'!\\nhandleUserInterrupt\\n\\tPreferences cmdDotEnabled ifTrue:\\n\\t\\t[Smalltalk isMorphic\\n\\t\\t\\tifTrue: [[Project interruptName: 'User Interrupt'] fork]\\n\\t\\t\\tifFalse: [[ScheduledControllers interruptName: 'User Interrupt'] fork]]! !\\n\\n!SystemDictionary methodsFor: 'miscellaneous' stamp: 'sd 9/29/2004 18:17'!\\nhasMorphic\\n\\t\\\"Answer whether the Morphic classes are available in the\\n\\tsystem (they may have been stripped, such as by a call to\\n\\tSmalltalk removeMorphic\\\"\\n\\t^ (self\\n\\t\\tat: #Morph\\n\\t\\tifAbsent: [])\\n\\t\\tisKindOf: Class! !\\n\\n!SystemDictionary methodsFor: 'miscellaneous' stamp: 'tk 10/16/2001 19:24'!\\nlogError: errMsg inContext: aContext to: aFilename\\n\\t\\\"Log the error message and a stack trace to the given file.\\\"\\n\\n\\t| ff |\\n\\tFileDirectory default deleteFileNamed: aFilename ifAbsent: [].\\n\\t(ff _ FileStream fileNamed: aFilename) ifNil: [^ self \\\"avoid recursive errors\\\"].\\n\\n \\tff nextPutAll: errMsg; cr.\\n\\taContext errorReportOn: ff.\\n\\tff close.! !\\n\\n!SystemDictionary methodsFor: 'miscellaneous' stamp: 'yo 7/2/2004 13:32'!\\nm17nVersion\\n\\n\\t^ 'M17n 5.0' copy\\n! !\\n\\n!SystemDictionary methodsFor: 'miscellaneous' stamp: 'yo 7/2/2004 13:32'!\\nnihongoVersion\\n\\n\\t^ 'Nihongo7.0' copy\\n! !\\n\\n!SystemDictionary methodsFor: 'miscellaneous' stamp: 'MPH 10/24/2000 14:27'!\\nsetMacFileInfoOn: aString\\n\\t\\\"On Mac, set the file type and creator (noop on other platforms)\\\"\\n\\tFileDirectory default\\n\\t\\tsetMacFileNamed: aString\\n\\t\\ttype: 'STch'\\n\\t\\tcreator: 'FAST'.! !\\n\\n!SystemDictionary methodsFor: 'miscellaneous' stamp: 'nb 6/17/2003 12:25'!\\nverifyMorphicAvailability\\n\\t\\\"If Morphic is available, return true; if not, put up an informer and return false\\\"\\n\\tself hasMorphic ifFalse:\\n\\t\\t[Beeper beep.\\n\\t\\tself inform: 'Sorry, Morphic must\\nbe present to use this feature'.\\n\\t\\t^ false].\\n\\t^ true! !\\n\\n\\n!SystemDictionary methodsFor: 'objects from disk' stamp: 'tk 9/28/2000 15:50'!\\nobjectForDataStream: refStrm\\n\\t| dp |\\n\\t\\\"I am about to be written on an object file. Write a reference to Smalltalk instead.\\\"\\n\\n\\tdp _ DiskProxy global: #Smalltalk selector: #yourself\\n\\t\\t\\targs: #().\\n\\trefStrm replace: self with: dp.\\n\\t^ dp! !\\n\\n!SystemDictionary methodsFor: 'objects from disk' stamp: 'tk 3/7/2000 18:40'!\\nstoreDataOn: aDataStream\\n\\t\\\"I don't get stored. Use a DiskProxy\\\"\\n\\n\\tself error: 'use a DiskProxy to store me'! !\\n\\n\\n!SystemDictionary methodsFor: 'printing' stamp: 'sma 6/1/2000 09:53'!\\nprintElementsOn: aStream\\n\\taStream nextPutAll:'(lots of globals)'! !\\n\\n\\n!SystemDictionary methodsFor: 'retrieving' stamp: 'sd 4/17/2003 21:15'!\\nallClasses \\n\\t\\\"Return all the class defines in the Smalltalk SystemDictionary\\\"\\n\\t\\\"Smalltalk allClasses\\\"\\n\\n\\t^ self classNames collect: [:name | self at: name]! !\\n\\n!SystemDictionary methodsFor: 'retrieving' stamp: 'sd 4/17/2003 21:18'!\\nallClassesDo: aBlock\\n\\t\\\"Evaluate the argument, aBlock, for each class in the system.\\\"\\n\\n\\t(self classNames collect: [:name | self at: name]) do: aBlock! !\\n\\n!SystemDictionary methodsFor: 'retrieving' stamp: 'al 2/23/2006 21:39'!\\nallTraits\\n\\t\\\"Return all traits defined in the Smalltalk SystemDictionary\\\"\\n\\n\\t^ self traitNames collect: [:each | self at: each]! !\\n\\n!SystemDictionary methodsFor: 'retrieving' stamp: 'sd 9/29/2004 18:17'!\\npoolUsers\\n\\t\\\"Answer a dictionary of pool name -> classes that refer to it.\\n\\tAlso includes any globally know dictionaries (such as\\n\\tSmalltalk, Undeclared etc) which although not strictly\\n\\taccurate is potentially useful information\\\"\\n\\t\\\"Smalltalk poolUsers\\\"\\n\\t| poolUsers pool refs |\\n\\tpoolUsers := Dictionary new.\\n\\tself keys\\n\\t\\tdo: [:k | \\\"yes, using isKindOf: is tacky but for reflective code like\\n\\t\\t\\tthis it is very useful. If you really object you can:-\\n\\t\\t\\ta) go boil your head.\\n\\t\\t\\tb) provide a better answer.\\n\\t\\t\\tyour choice.\\\"\\n\\t\\t\\t(((pool := self at: k) isKindOf: Dictionary)\\n\\t\\t\\t\\t\\tor: [pool isKindOf: SharedPool class])\\n\\t\\t\\t\\tifTrue: [refs := self systemNavigation allClasses\\n\\t\\t\\t\\t\\t\\t\\t\\tselect: [:c | c sharedPools identityIncludes: pool]\\n\\t\\t\\t\\t\\t\\t\\t\\tthenCollect: [:c | c name].\\n\\t\\t\\t\\t\\trefs\\n\\t\\t\\t\\t\\t\\tadd: (self systemNavigation\\n\\t\\t\\t\\t\\t\\t\\t\\tallCallsOn: (self associationAt: k)).\\n\\t\\t\\t\\t\\tpoolUsers at: k put: refs]].\\n\\t^ poolUsers! !\\n\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:18'!\\nabandonSources\\n\\t\\\"Smalltalk abandonSources\\\"\\n\\t\\\"Replaces every method by a copy with the 4-byte source\\n\\tpointer \\n\\treplaced by a string of all arg and temp names, followed by its\\n\\tlength. These names can then be used to inform the\\n\\tdecompiler. See stats below\\\"\\n\\t\\\"wod 11/3/1998: zap the organization before rather than after\\n\\tcondensing changes.\\\"\\n\\t| oldCodeString argsAndTemps oldMethods newMethods m bTotal bCount |\\n\\t(self confirm: 'This method will preserve most temp names\\n(up to about 400 characters) while allowing\\nthe sources file to be discarded.\\n-- CAUTION --\\nIf you have backed up your system and\\nare prepared to face the consequences of\\nabandoning source code files, choose Yes.\\nIf you have any doubts, you may choose No\\nto back out with no harm done.')\\n\\t\\t\\t== true\\n\\t\\tifFalse: [^ self inform: 'Okay - no harm done'].\\n\\tself forgetDoIts.\\n\\toldMethods := OrderedCollection new: CompiledMethod instanceCount.\\n\\tnewMethods := OrderedCollection new: CompiledMethod instanceCount.\\n\\tbTotal := 0.\\n\\tbCount := 0.\\n\\tself systemNavigation\\n\\t\\tallBehaviorsDo: [:b | bTotal := bTotal + 1].\\n\\t'Saving temp names for better decompilation...'\\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0\\n\\t\\tto: bTotal\\n\\t\\tduring: [:bar | self systemNavigation\\n\\t\\t\\t\\tallBehaviorsDo: [:cl | \\n\\t\\t\\t\\t\\t\\\"for test: (Array with: Arc with: Arc class) do:\\\"\\n\\t\\t\\t\\t\\tbar value: (bCount := bCount + 1).\\n\\t\\t\\t\\t\\tcl selectors\\n\\t\\t\\t\\t\\t\\tdo: [:selector | \\n\\t\\t\\t\\t\\t\\t\\tm := cl compiledMethodAt: selector.\\n\\t\\t\\t\\t\\t\\t\\tm fileIndex > 0\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [oldCodeString := cl sourceCodeAt: selector.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\targsAndTemps := (cl compilerClass new\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tparse: oldCodeString\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tin: cl\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tnotifying: nil) tempNames.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\toldMethods addLast: m.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tnewMethods\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\taddLast: (m copyWithTempNames: argsAndTemps)]]]].\\n\\toldMethods asArray elementsExchangeIdentityWith: newMethods asArray.\\n\\tself systemNavigation\\n\\t\\tallBehaviorsDo: [:b | b zapOrganization].\\n\\tself condenseChanges.\\n\\tPreferences disable: #warnIfNoSourcesFile! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:18'!\\nabandonTempNames\\n\\t\\\"Replaces every method by a copy with no source pointer or\\n\\tencoded temp names.\\\"\\n\\t\\\"Smalltalk abandonTempNames\\\"\\n\\t| continue oldMethods newMethods n m |\\n\\tcontinue := self confirm: '-- CAUTION --\\nIf you have backed up your system and\\nare prepared to face the consequences of\\nabandoning all source code, hit Yes.\\nIf you have any doubts, hit No,\\nto back out with no harm done.'.\\n\\tcontinue\\n\\t\\tifFalse: [^ self inform: 'Okay - no harm done'].\\n\\tself forgetDoIts; garbageCollect.\\n\\toldMethods := OrderedCollection new.\\n\\tnewMethods := OrderedCollection new.\\n\\tn := 0.\\n\\t'Removing temp names to save space...'\\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0\\n\\t\\tto: CompiledMethod instanceCount\\n\\t\\tduring: [:bar | self systemNavigation\\n\\t\\t\\t\\tallBehaviorsDo: [:cl | cl selectors\\n\\t\\t\\t\\t\\t\\tdo: [:sel | \\n\\t\\t\\t\\t\\t\\t\\tbar value: (n := n + 1).\\n\\t\\t\\t\\t\\t\\t\\tm := cl compiledMethodAt: sel.\\n\\t\\t\\t\\t\\t\\t\\toldMethods addLast: m.\\n\\t\\t\\t\\t\\t\\t\\tnewMethods\\n\\t\\t\\t\\t\\t\\t\\t\\taddLast: (m copyWithTrailerBytes: #(0 ))]]].\\n\\toldMethods asArray elementsExchangeIdentityWith: newMethods asArray.\\n\\tSmalltalkImage current closeSourceFiles.\\n\\tself flag: #shouldUseAEnsureBlockToBeSureThatTheFileIsClosed.\\n\\t\\\"sd: 17 April 2003\\\"\\n\\tPreferences disable: #warnIfNoChangesFile.\\n\\tPreferences disable: #warnIfNoSourcesFile! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'di 3/3/2001 08:31'!\\ncleanUpUndoCommands\\n\\t\\\"Smalltalk cleanUpUndoCommands\\\" \\\"<== print this to get classes involved\\\"\\n\\n\\t| classes i p |\\n\\tclasses _ Bag new.\\n\\t'Ferreting out obsolete undo commands'\\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0 to: Morph withAllSubclasses size\\n\\t\\tduring:\\n\\t[:bar | i _ 0.\\n\\tMorph withAllSubclassesDo:\\n\\t\\t[:c | bar value: (i _ i+1).\\n\\t\\tc allInstancesDo:\\n\\t\\t\\t[:m | (p _ m otherProperties) ifNotNil:\\n\\t\\t\\t\\t[p keys do:\\n\\t\\t\\t\\t\\t[:k | (p at: k) class == Command ifTrue:\\n\\t\\t\\t\\t\\t\\t[classes add: c name.\\n\\t\\t\\t\\t\\t\\tm removeProperty: k]]]]]].\\n\\t^ classes! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:40'!\\ncomputeImageSegmentation\\n\\t\\\"Smalltalk computeImageSegmentation\\\"\\n\\t\\\"Here's how the segmentation works:\\n\\tFor each partition, we collect the classes involved, and also all\\n\\tmessages no longer used in the absence of this partition. We\\n\\tstart by computing a 'Miscellaneous' segment of all the\\n\\tunused classes in the system as is.\\\"\\n\\t| partitions unusedCandM newClasses expandedCandM |\\n\\tpartitions := Dictionary new.\\n\\tunusedCandM := self unusedClassesAndMethodsWithout: {{}. {}}.\\n\\tpartitions at: 'Miscellaneous' put: unusedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'VMConstruction-*')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'VMConstruction' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'ST80-*')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'ST80' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'Morphic-Games')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Games' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'Morphic-Remote')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Nebraska' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | ((SystemOrganization categoriesMatching: 'Network-*')\\n\\t\\t\\t\\t\\t\\tcopyWithoutAll: #('Network-Kernel' 'Network-Url' 'Network-Protocols' 'Network-ObjectSocket' ))\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := Smalltalk unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Network' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'Balloon3D-*')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Balloon3D' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'FFI-*')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'FFI' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'Genie-*')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Genie' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'Speech-*')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Speech' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | #('Morphic-Components' )\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\tnewClasses := newClasses copyWithoutAll: #(#ComponentLikeModel ).\\n\\texpandedCandM := Smalltalk unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Components' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | #('Sound-Scores' 'Sound-Interface' )\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\tnewClasses := newClasses , #(#WaveletCodec #Sonogram #FWT #AIFFFileReader ).\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Sound' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | ((SystemOrganization categoriesMatching: 'Tools-*')\\n\\t\\t\\t\\t\\t\\tcopyWithout: 'Tools-Menus')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\tnewClasses := newClasses copyWithoutAll: #(#Debugger #Inspector #ContextVariablesInspector #SyntaxError #ChangeSet #ChangeRecord #ClassChangeRecord #ChangeList #VersionsBrowser ).\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Tools' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'Balloon-MMFlash*')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\tnewClasses := newClasses , #(#ADPCMCodec ).\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'Flash' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'Balloon-TrueType*')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'TrueType' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\tnewClasses := Array\\n\\t\\t\\t\\tstreamContents: [:s | (SystemOrganization categoriesMatching: 'Graphics-Files')\\n\\t\\t\\t\\t\\t\\tdo: [:cat | (SystemOrganization superclassOrder: cat)\\n\\t\\t\\t\\t\\t\\t\\t\\tdo: [:c | s nextPut: c name]]].\\n\\texpandedCandM := self unusedClassesAndMethodsWithout: {unusedCandM first asArray , newClasses. unusedCandM second}.\\n\\tpartitions at: 'GraphicFiles' put: {(expandedCandM first copyWithoutAll: unusedCandM first) addAll: newClasses;\\n\\t\\t\\t yourself. expandedCandM second copyWithoutAll: unusedCandM second}.\\n\\tunusedCandM := expandedCandM.\\n\\t#(#AliceConstants 'Balloon3D' #B3DEngineConstants 'Balloon3D' #WonderlandConstants 'Balloon3D' #FFIConstants 'FFI' #KlattResonatorIndices 'Speech' )\\n\\t\\tpairsDo: [:poolName :part | (partitions at: part) first add: poolName].\\n\\tpartitions\\n\\t\\tkeysDo: [:k | k = 'Miscellaneous'\\n\\t\\t\\t\\tifFalse: [(partitions at: 'Miscellaneous') first removeAllFoundIn: (partitions at: k) first]].\\n\\t^ partitions! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sma 6/18/2000 12:32'!\\ndiscardDiscards\\n\\t\\\"Discard all discard* methods - including this one.\\\"\\n\\n\\t(self class selectors select: [:each | each beginsWith: 'discard']) \\n\\t\\tdo: [:each | self class removeSelector: each].\\n\\t#(lastRemoval majorShrink zapMVCprojects)\\n\\t\\tdo: [:each | self class removeSelector: each]! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:20'!\\ndiscardFFI\\n\\t\\\"Discard the complete foreign function interface.\\n\\tNOTE: Recreates specialObjectsArray to prevent obsolete\\n\\treferences. Has to specially remove external structure\\n\\thierarchy before ExternalType\\\"\\n\\tself\\n\\t\\tat: #ExternalStructure\\n\\t\\tifPresent: [:cls | (ChangeSet superclassOrder: cls withAllSubclasses asArray)\\n\\t\\t\\t\\treverseDo: [:c | c removeFromSystem]].\\n\\tSystemOrganization removeCategoriesMatching: 'FFI-*'.\\n\\tself recreateSpecialObjectsArray.\\n\\t\\\"Remove obsolete refs\\\"\\n\\tByteArray removeSelector: #asExternalPointer.\\n\\tByteArray removeSelector: #pointerAt:! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'TPR 8/5/2000 01:32'!\\ndiscardFlash\\n\\t\\\"Discard Flash support.\\\"\\n\\n\\tSystemOrganization removeCategoriesMatching: 'Balloon-MMFlash*'\\n! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'RAA 12/17/2000 16:50'!\\ndiscardMIDI\\n\\n\\t\\\"this seems to have gone away\\\"! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:21'!\\ndiscardMorphic\\n\\t\\\"Discard Morphic.\\n\\tUpdated for 2.8 TPR\\\"\\n\\t\\\"Smalltalk discardMorphic\\\"\\n\\t\\\"Check that we are in an MVC Project and that there are no\\n\\tMorphic Projects\\n\\tor WorldMorphViews.\\\"\\n\\t| subs |\\n\\tFlaps clobberFlapTabList.\\n\\tself discardFlash.\\n\\tself discardTrueType.\\n\\tsubs := OrderedCollection new.\\n\\tMorph\\n\\t\\tallSubclassesWithLevelDo: [:c :i | subs addFirst: c]\\n\\t\\tstartingLevel: 0.\\n\\tsubs\\n\\t\\tdo: [:c | c removeFromSystem].\\n\\tself removeClassNamed: #CornerRounder.\\n\\tself\\n\\t\\tremoveKey: #BalloonEngineConstants\\n\\t\\tifAbsent: [].\\n\\tSystemOrganization removeCategoriesMatching: 'Balloon-*'.\\n\\tSystemOrganization removeCategoriesMatching: 'Morphic-*'.\\n\\tSystemOrganization removeSystemCategory: 'Graphics-Transformations'.\\n\\tSystemOrganization removeSystemCategory: 'ST80-Morphic'.\\n\\tScriptingSystem := nil! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:21'!\\ndiscardMVC\\n\\t\\\"After suitable checks, strip out much of MVC from the system\\\"\\n\\t\\\"Smalltalk discardMVC\\\"\\n\\t| keepers |\\n\\tself flag: #bob.\\n\\t\\\"zapping projects\\\"\\n\\tself isMorphic\\n\\t\\tifFalse: [self inform: 'You must be in a Morphic project to discard MVC.'.\\n\\t\\t\\t^ self].\\n\\t\\\"Check that there are no MVC Projects\\\"\\n\\t(Project allProjects\\n\\t\\t\\tallSatisfy: [:proj | proj isMorphic])\\n\\t\\tifFalse: [(self confirm: 'Would you like a chance to remove your\\nMVC projects in an orderly manner?')\\n\\t\\t\\t\\tifTrue: [^ self].\\n\\t\\t\\t(self confirm: 'If you wish, I can remove all MVC projects,\\nmake this project be the top project, and place\\nall orphaned sub-projects of MVC parents here.\\nWould you like be to do this\\nand proceed to discard all MVC classes?')\\n\\t\\t\\t\\tifTrue: [self zapMVCprojects]\\n\\t\\t\\t\\tifFalse: [^ self]].\\n\\tself reclaimDependents.\\n\\t\\\"Remove old Paragraph classes and View classes.\\\"\\n\\tself\\n\\t\\tat: #Paragraph\\n\\t\\tifPresent: [:paraClass | (ChangeSet superclassOrder: paraClass withAllSubclasses asArray)\\n\\t\\t\\t\\treverseDo: [:c | c removeFromSystem]].\\n\\tself\\n\\t\\tat: #View\\n\\t\\tifPresent: [:viewClass | (ChangeSet superclassOrder: viewClass withAllSubclasses asArray)\\n\\t\\t\\t\\treverseDo: [:c | c removeFromSystem]].\\n\\t\\\"Get rid of ParagraphEditor's ScrollController dependence\\\"\\n\\t#(#markerDelta #viewDelta #scrollAmount #scrollBar #computeMarkerRegion )\\n\\t\\tdo: [:sel | ParagraphEditor removeSelector: sel].\\n\\tParagraphEditor compile: 'updateMarker'.\\n\\t\\\"Reshape to MouseMenuController\\\"\\n\\tCompiler\\n\\t\\tevaluate: (ParagraphEditor definition copyReplaceAll: 'ScrollController' with: 'MouseMenuController').\\n\\t\\\"Get rid of all Controller classes not needed by\\n\\tParagraphEditor and ScreenController\\\"\\n\\tkeepers := TextMorphEditor withAllSuperclasses copyWith: ScreenController.\\n\\t(ChangeSet superclassOrder: Controller withAllSubclasses asArray)\\n\\t\\treverseDo: [:c | (keepers includes: c)\\n\\t\\t\\t\\tifFalse: [c removeFromSystem]].\\n\\tSystemOrganization removeCategoriesMatching: 'ST80-Paths'.\\n\\tSystemOrganization removeCategoriesMatching: 'ST80-Symbols'.\\n\\tSystemOrganization removeCategoriesMatching: 'ST80-Pluggable Views'.\\n\\tself removeClassNamed: 'FormButtonCache'.\\n\\tself removeClassNamed: 'WindowingTransformation'.\\n\\tself removeClassNamed: 'ControlManager'.\\n\\tself removeClassNamed: 'DisplayTextView'.\\n\\tScheduledControllers := nil.\\n\\tUndeclared removeUnreferencedKeys.\\n\\tSystemOrganization removeEmptyCategories.\\n\\tSymbol rehash! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'cwp 11/8/2002 13:38'!\\ndiscardNetworking\\n\\t\\\"Discard the support for TCP/IP networking.\\\"\\n\\n\\tSystemOrganization removeCategoriesMatching: 'Network-*'.\\n\\n! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'md 7/29/2005 16:00'!\\ndiscardOddsAndEnds\\n\\t\\\"This method throws out lots of classes that are not frequently\\n\\tused.\\\"\\n\\t\\\"Smalltalk discardOddsAndEnds\\\"\\n\\tself organization removeSystemCategory: 'System-Serial Port'.\\n\\tself organization removeSystemCategory: 'ST80-Symbols'.\\n\\tself organization removeSystemCategory: 'Tools-File Contents Browser'.\\n\\tself organization removeSystemCategory: 'System-Compression'.\\n\\tself organization removeSystemCategory: 'Tools-Explorer'.\\n\\tself organization removeSystemCategory: 'System-Digital Signatures'.\\n\\tForm removeSelector: #edit.\\n\\tself\\n\\t\\tat: #FormView\\n\\t\\tifPresent: [:c | c compile: 'defaultControllerClass ^ NoController' classified: 'controller access'].\\n\\tself removeClassNamed: #FormEditorView.\\n\\tself removeClassNamed: #FormEditor.\\n\\tself organization removeSystemCategory: 'ST80-Paths'.\\n\\t\\\"bit editor (remove Form editor first):\\\"\\n\\tForm removeSelector: #bitEdit.\\n\\tForm removeSelector: #bitEditAt:scale:.\\n\\tStrikeFont removeSelector: #edit:.\\n\\tself removeClassNamed: #FormButtonCache.\\n\\tself removeClassNamed: #FormMenuController.\\n\\tself removeClassNamed: #FormMenuView.\\n\\tself removeClassNamed: #BitEditor.\\n\\t\\\"inspector for Dictionaries of Forms\\\"\\n\\tDictionary removeSelector: #inspectFormsWithLabel:.\\n\\tSystemDictionary removeSelector: #viewImageImports.\\n\\tScreenController removeSelector: #viewImageImports.\\n\\tself removeClassNamed: #FormHolderView.\\n\\tself removeClassNamed: #FormInspectView.\\n\\t\\\"experimental updating object viewer:\\\"\\n\\tObject removeSelector: #evaluate:wheneverChangeIn:.\\n\\tself removeClassNamed: #ObjectViewer.\\n\\tself removeClassNamed: #ObjectTracer.\\n\\t\\\"miscellaneous classes:\\\"\\n\\tself removeClassNamed: #Array2D.\\n\\tself removeClassNamed: #DriveACar.\\n\\tself removeClassNamed: #EventRecorder.\\n\\tself removeClassNamed: #FindTheLight.\\n\\tself removeClassNamed: #PluggableTest.\\n\\tself removeClassNamed: #SystemMonitor.\\n\\tself removeClassNamed: #ProtocolBrowser.\\n\\tself removeClassNamed: #ObjectExplorerWrapper.\\n\\tself removeClassNamed: #HierarchyBrowser.\\n\\tself removeClassNamed: #LinkedMessageSet.\\n\\tself removeClassNamed: #ObjectExplorer.\\n\\tself removeClassNamed: #PackageBrowser.\\n\\tself removeClassNamed: #AbstractHierarchicalList.\\n\\tself removeClassNamed: #ChangeList.\\n\\tself removeClassNamed: #VersionsBrowser.\\n\\tself removeClassNamed: #ChangeRecord.\\n\\tself removeClassNamed: #SelectorBrowser.\\n\\tself removeClassNamed: #HtmlFileStream.\\n\\tself removeClassNamed: #CrLfFileStream.\\n\\tself removeClassNamed: #FXGrafPort.\\n\\tself removeClassNamed: #FXBlt.\\n\\tself\\n\\t\\tat: #SampledSound\\n\\t\\tifPresent: [:c | c initialize].\\n\\t#(#Helvetica #Palatino #Courier #ComicBold #ComicPlain )\\n\\t\\tdo: [:k | TextConstants\\n\\t\\t\\t\\tremoveKey: k\\n\\t\\t\\t\\tifAbsent: []].\\n\\tPreferences\\n\\t\\tsetButtonFontTo: (StrikeFont familyName: #NewYork size: 12).\\n\\tPreferences\\n\\t\\tsetFlapsFontTo: (StrikeFont familyName: #NewYork size: 12).\\n\\t#(#GZipConstants #ZipConstants #KlattResonatorIndices )\\n\\t\\tdo: [:k | self\\n\\t\\t\\t\\tremoveKey: k\\n\\t\\t\\t\\tifAbsent: []]! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:23'!\\ndiscardSoundSynthesis\\n\\t\\\"Discard the sound synthesis facilities, and the methods and\\n\\tclasses that use it. This also discards MIDI.\\\"\\n\\tself discardMIDI.\\n\\tself discardSpeech.\\n\\tSystemOrganization removeCategoriesMatching: 'Sound-Interface'.\\n\\tself\\n\\t\\tat: #GraphMorph\\n\\t\\tifPresent: [:graphMorph | #(#playOnce #readDataFromFile )\\n\\t\\t\\t\\tdo: [:sel | graphMorph removeSelector: sel]].\\n\\tself\\n\\t\\tat: #TrashCanMorph\\n\\t\\tifPresent: [:trashMorph | \\n\\t\\t\\ttrashMorph class removeSelector: #samplesForDelete.\\n\\t\\t\\ttrashMorph class removeSelector: #samplesForMouseEnter.\\n\\t\\t\\ttrashMorph class removeSelector: #samplesForMouseLeave].\\n\\tSystemOrganization removeCategoriesMatching: 'Sound-Synthesis'.\\n\\tSystemOrganization removeCategoriesMatching: 'Sound-Scores'! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'TPR 8/3/2000 19:21'!\\ndiscardSpeech\\n\\t\\\"Discard support for speech synthesis\\\"\\n\\n\\tSystemOrganization removeCategoriesMatching: 'Speech*'.\\n! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:23'!\\ndiscardSUnit\\n\\t\\\"Smalltalk discardSUnit\\\"\\n\\t| oc |\\n\\toc := OrderedCollection new.\\n\\t(self\\n\\t\\tat: #TestCase\\n\\t\\tifAbsent: [^ self])\\n\\t\\tallSubclassesWithLevelDo: [:c :i | oc addFirst: c]\\n\\t\\tstartingLevel: 0.\\n\\toc\\n\\t\\tdo: [:c | c removeFromSystem].\\n\\tSystemOrganization removeCategoriesMatching: 'SUnit-*'! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'TPR 8/5/2000 01:32'!\\ndiscardTrueType\\n\\t\\\"Discard TrueType support.\\\"\\n\\n\\tSystemOrganization removeCategoriesMatching: 'Balloon-TrueType*'.\\n\\n! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:24'!\\nlastRemoval\\n\\t\\\"Smalltalk lastRemoval\\\"\\n\\t\\\"Some explicit removals - add unwanted methods keeping\\n\\tother methods.\\\"\\n\\t| oldDicts newDicts |\\n\\t#(#abandonSources )\\n\\t\\tdo: [:each | self class removeSelector: each].\\n\\t\\\"Get rid of all unsent methods.\\\"\\n\\t[self removeAllUnSentMessages > 0] whileTrue.\\n\\t\\\"Shrink method dictionaries.\\\"\\n\\tself garbageCollect.\\n\\toldDicts := MethodDictionary allInstances.\\n\\tnewDicts := Array new: oldDicts size.\\n\\toldDicts\\n\\t\\twithIndexDo: [:d :index | newDicts at: index put: d rehashWithoutBecome].\\n\\toldDicts elementsExchangeIdentityWith: newDicts.\\n\\toldDicts := newDicts := nil.\\n\\tself\\n\\t\\tallClassesDo: [:c | c zapOrganization].\\n\\tSystemOrganization := nil.\\n\\tChangeSet current initialize! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'md 2/24/2006 15:42'!\\nmajorShrink\\n\\t\\\"Undertake a major shrinkage of the image.\\n\\tThis method throws out lots of the system that is not needed\\n\\tfor, eg, operation in a hand-held PC. majorShrink produces a\\n\\t999k image in Squeak 2.8\\n\\tSmalltalk majorShrink; abandonSources; lastRemoval\\\"\\n\\t| oldDicts newDicts |\\n\\tself isMorphic\\n\\t\\tifTrue: [^ self error: 'You can only run majorShrink in MVC'].\\n\\tProject current isTopProject\\n\\t\\tifFalse: [^ self error: 'You can only run majorShrink in the top project'].\\n\\t(self confirm: 'All sub-projects will be deleted from this image.\\nYou should already have made a backup copy,\\nor you must save with a different name after shrinking.\\nShall we proceed to discard most of the content in this image?')\\n\\t\\tifFalse: [^ self inform: 'No changes have been made.'].\\n\\t\\\"Remove all projects but the current one. - saves 522k\\\"\\n\\tProjectView\\n\\t\\tallInstancesDo: [:pv | pv controller closeAndUnscheduleNoTerminate].\\n\\tProject current setParent: Project current.\\n\\tMorphWorldView\\n\\t\\tallInstancesDo: [:pv | pv topView controller closeAndUnscheduleNoTerminate].\\n\\tself\\n\\t\\tat: #Wonderland\\n\\t\\tifPresent: [:cls | cls removeActorPrototypesFromSystem].\\n\\tPlayer freeUnreferencedSubclasses.\\n\\tMorphicModel removeUninstantiatedModels.\\n\\tUtilities classPool at: #ScrapsBook put: nil.\\n\\tUtilities zapUpdateDownloader.\\n\\tProjectHistory currentHistory initialize.\\n\\tProject rebuildAllProjects.\\n\\t\\\"Smalltalk discardVMConstruction.\\\"\\n\\t\\\"755k\\\"\\n\\tself discardSoundSynthesis.\\n\\t\\\"544k\\\"\\n\\tself discardOddsAndEnds.\\n\\t\\\"227k\\\"\\n\\tself discardNetworking.\\n\\t\\\"234k\\\"\\n\\t\\\"Smalltalk discard3D.\\\"\\n\\t\\\"407k\\\"\\n\\tself discardFFI.\\n\\t\\\"33k\\\"\\n\\tself discardMorphic.\\n\\t\\\"1372k\\\"\\n\\tSymbol rehash.\\n\\t\\\"40k\\\"\\n\\t\\\"Above by itself saves about 4,238k\\\"\\n\\t\\\"Remove references to a few classes to be deleted, so that they\\n\\twon't leave obsolete versions around.\\\"\\n\\tChangeSet class compile: 'defaultName\\n\\t\\t^ ''Changes'' ' classified: 'initialization'.\\n\\tScreenController removeSelector: #openChangeManager.\\n\\tScreenController removeSelector: #exitProject.\\n\\tScreenController removeSelector: #openProject.\\n\\tScreenController removeSelector: #viewImageImports.\\n\\t\\\"Now delete various other classes..\\\"\\n\\tSystemOrganization removeSystemCategory: 'Graphics-Files'.\\n\\tSystemOrganization removeSystemCategory: 'System-Object Storage'.\\n\\tself removeClassNamed: #ProjectController.\\n\\tself removeClassNamed: #ProjectView.\\n\\t\\\"Smalltalk removeClassNamed: #Project.\\\"\\n\\tself removeClassNamed: #Component1.\\n\\tself removeClassNamed: #FormSetFont.\\n\\tself removeClassNamed: #FontSet.\\n\\tself removeClassNamed: #InstructionPrinter.\\n\\tself removeClassNamed: #ChangeSorter.\\n\\tself removeClassNamed: #DualChangeSorter.\\n\\tself removeClassNamed: #EmphasizedMenu.\\n\\tself removeClassNamed: #MessageTally.\\n\\tStringHolder class removeSelector: #originalWorkspaceContents.\\n\\tCompiledMethod removeSelector: #symbolic.\\n\\tRemoteString removeSelector: #makeNewTextAttVersion.\\n\\tUtilities class removeSelector: #absorbUpdatesFromServer.\\n\\tself removeClassNamed: #PenPointRecorder.\\n\\tself removeClassNamed: #Path.\\n\\tself removeClassNamed: #Base64MimeConverter.\\n\\t\\\"Smalltalk removeClassNamed: #EToySystem. Dont bother - its\\n\\tvery small and used for timestamps etc\\\"\\n\\tself removeClassNamed: #RWBinaryOrTextStream.\\n\\tself removeClassNamed: #AttributedTextStream.\\n\\tself removeClassNamed: #WordNet.\\n\\tself removeClassNamed: #SelectorBrowser.\\n\\tTextStyle\\n\\t\\tallSubInstancesDo: [:ts | ts\\n\\t\\t\\t\\tnewFontArray: (ts fontArray\\n\\t\\t\\t\\t\\t\\tcopyFrom: 1\\n\\t\\t\\t\\t\\t\\tto: (2 min: ts fontArray size))].\\n\\tListParagraph initialize.\\n\\tPopUpMenu initialize.\\n\\tStandardSystemView initialize.\\n\\tChangeSet noChanges.\\n\\tChangeSet classPool\\n\\t\\tat: #AllChangeSets\\n\\t\\tput: (OrderedCollection with: ChangeSet current).\\n\\tSystemDictionary removeSelector: #majorShrink.\\n\\t[self removeAllUnSentMessages > 0]\\n\\t\\twhileTrue: [Smalltalk unusedClasses\\n\\t\\t\\t\\tdo: [:c | (Smalltalk at: c) removeFromSystem]].\\n\\tSystemOrganization removeEmptyCategories.\\n\\tself\\n\\t\\tallClassesDo: [:c | c zapOrganization].\\n\\tself garbageCollect.\\n\\t'Rehashing method dictionaries . . .'\\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0\\n\\t\\tto: MethodDictionary instanceCount\\n\\t\\tduring: [:bar | \\n\\t\\t\\toldDicts := MethodDictionary allInstances.\\n\\t\\t\\tnewDicts := Array new: oldDicts size.\\n\\t\\t\\toldDicts\\n\\t\\t\\t\\twithIndexDo: [:d :index | \\n\\t\\t\\t\\t\\tbar value: index.\\n\\t\\t\\t\\t\\tnewDicts at: index put: d rehashWithoutBecome].\\n\\t\\t\\toldDicts elementsExchangeIdentityWith: newDicts].\\n\\toldDicts := newDicts := nil.\\n\\tProject rebuildAllProjects.\\n\\tChangeSet current initialize.\\n\\t\\\"seems to take more than one try to gc all the weak refs in\\n\\tSymbolTable \\\"\\n\\t3\\n\\t\\ttimesRepeat: [self garbageCollect.\\n\\t\\t\\tSymbol compactSymbolTable]! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'nk 4/28/2004 10:24'!\\npresumedSentMessages | sent |\\n\\\"Smalltalk presumedSentMessages\\\"\\n\\n\\t\\\"The following should be preserved for doIts, etc\\\"\\n\\tsent _ IdentitySet new.\\n\\t#( rehashWithoutBecome compactSymbolTable rebuildAllProjects\\n\\t\\tbrowseAllSelect: lastRemoval\\n\\t\\tscrollBarValue: vScrollBarValue: scrollBarMenuButtonPressed: \\n\\t\\twithSelectionFrom: to: removeClassNamed:\\n\\t\\tdragon: hilberts: mandala: web test3 factorial tinyBenchmarks benchFib\\n\\t\\tnewDepth: restoreAfter: forgetDoIts zapAllMethods obsoleteClasses\\n\\t\\tremoveAllUnSentMessages abandonSources removeUnreferencedKeys\\n\\t\\treclaimDependents zapOrganization condenseChanges browseObsoleteReferences\\n\\t\\tsubclass:instanceVariableNames:classVariableNames:poolDictionaries:category:\\n\\t\\tmethodsFor:stamp: methodsFor:stamp:prior: instanceVariableNames:\\n\\t\\tstartTimerInterruptWatcher unusedClasses) do:\\n\\t\\t[:sel | sent add: sel].\\n\\t\\\"The following may be sent by perform: in dispatchOnChar...\\\"\\n\\t(ParagraphEditor classPool at: #CmdActions) asSet do:\\n\\t\\t[:sel | sent add: sel].\\n\\t(ParagraphEditor classPool at: #ShiftCmdActions) asSet do:\\n\\t\\t[:sel | sent add: sel].\\n\\t^ sent! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'nk 4/28/2004 10:24'!\\nremoveAllUnSentMessages\\n\\t\\\"Smalltalk removeAllUnSentMessages\\\"\\n\\t\\\"[Smalltalk unusedClasses do: [:c | (Smalltalk at: c) removeFromSystem]. \\n\\tSmalltalk removeAllUnSentMessages > 0] whileTrue.\\\"\\n\\t\\\"Remove all implementations of unsent messages.\\\"\\n\\t| sels n |\\n\\tsels _ self systemNavigation allUnSentMessages.\\n\\t\\\"The following should be preserved for doIts, etc\\\"\\n\\t\\\"needed even after #majorShrink is pulled\\\"\\n\\t#(#rehashWithoutBecome #compactSymbolTable #rebuildAllProjects #browseAllSelect: #lastRemoval #scrollBarValue: vScrollBarValue: #scrollBarMenuButtonPressed: #withSelectionFrom: #to: #removeClassNamed: #dragon: #hilberts: #mandala: #web #test3 #factorial #tinyBenchmarks #benchFib #newDepth: #restoreAfter: #forgetDoIts #zapAllMethods #obsoleteClasses #removeAllUnSentMessages #abandonSources #removeUnreferencedKeys #reclaimDependents #zapOrganization #condenseChanges #browseObsoleteReferences #subclass:instanceVariableNames:classVariableNames:poolDictionaries:category: #methodsFor:stamp: #methodsFor:stamp:prior: #instanceVariableNames: #startTimerInterruptWatcher #unusedClasses )\\n\\t\\tdo: [:sel | sels\\n\\t\\t\\t\\tremove: sel\\n\\t\\t\\t\\tifAbsent: []].\\n\\t\\\"The following may be sent by perform: in dispatchOnChar...\\\"\\n\\t(ParagraphEditor classPool at: #CmdActions) asSet\\n\\t\\tdo: [:sel | sels\\n\\t\\t\\t\\tremove: sel\\n\\t\\t\\t\\tifAbsent: []].\\n\\t(ParagraphEditor classPool at: #ShiftCmdActions) asSet\\n\\t\\tdo: [:sel | sels\\n\\t\\t\\t\\tremove: sel\\n\\t\\t\\t\\tifAbsent: []].\\n\\tsels size = 0\\n\\t\\tifTrue: [^ 0].\\n\\tn _ 0.\\n\\tself systemNavigation\\n\\t\\tallBehaviorsDo: [:x | n _ n + 1].\\n\\t'Removing ' , sels size printString , ' messages . . .'\\n\\t\\tdisplayProgressAt: Sensor cursorPoint\\n\\t\\tfrom: 0\\n\\t\\tto: n\\n\\t\\tduring: [:bar | \\n\\t\\t\\tn _ 0.\\n\\t\\t\\tself systemNavigation\\n\\t\\t\\t\\tallBehaviorsDo: [:class | \\n\\t\\t\\t\\t\\tbar value: (n _ n + 1).\\n\\t\\t\\t\\t\\tsels\\n\\t\\t\\t\\t\\t\\tdo: [:sel | class basicRemoveSelector: sel]]].\\n\\t^ sels size! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:26'!\\nremoveNormalCruft\\n\\t\\\"Remove various graphics, uniclasses, references. Caution: see\\n\\tcomment at bottom of method\\\"\\n\\t\\\"Smalltalk removeNormalCruft\\\"\\n\\tScriptingSystem stripGraphicsForExternalRelease.\\n\\tScriptingSystem spaceReclaimed.\\n\\tReferences keys\\n\\t\\tdo: [:k | References removeKey: k].\\n\\tself classNames\\n\\t\\tdo: [:cName | #('Player' 'CardPlayer' 'Component' 'WonderlandActor' 'MorphicModel' 'PlayWithMe' )\\n\\t\\t\\t\\tdo: [:superName | ((cName ~= superName\\n\\t\\t\\t\\t\\t\\t\\t\\tand: [cName beginsWith: superName])\\n\\t\\t\\t\\t\\t\\t\\tand: [(cName allButFirst: superName size)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tallSatisfy: [:ch | ch isDigit]])\\n\\t\\t\\t\\t\\t\\tifTrue: [self removeClassNamed: cName]]].\\n\\tself\\n\\t\\tat: #Wonderland\\n\\t\\tifPresent: [:cls | cls removeActorPrototypesFromSystem].\\n\\tChangeSet current clear\\n\\t\\\"Caution: if any worlds in the image happen to have uniclass\\n\\tplayers associated with them, running this method would\\n\\tlikely compromise their functioning and could cause errors,\\n\\tespecially if the uniclass player of the current world had any\\n\\tscripts set to ticking. If that happens to you somehow, you will\\n\\tprobably want to find a way to reset the offending world's\\n\\tplayer to be an UnscriptedCardPlayer, or perhaps nil\\\"! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 9/29/2004 18:26'!\\nremoveSelector: descriptor \\n\\t\\\"Safely remove a selector from a class (or metaclass). If the\\n\\tclass or the method doesn't exist anymore, never mind and\\n\\tanswer nil.\\n\\tThis method should be used instead of 'Class removeSelector:\\n\\t#method' to omit global class references.\\\"\\n\\t| class sel |\\n\\tclass := self\\n\\t\\t\\t\\tat: descriptor first\\n\\t\\t\\t\\tifAbsent: [^ nil].\\n\\t(descriptor size > 2\\n\\t\\t\\tand: [descriptor second == #class])\\n\\t\\tifTrue: [class := class class.\\n\\t\\t\\tsel := descriptor third]\\n\\t\\tifFalse: [sel := descriptor second].\\n\\t^ class removeSelector: sel! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'di 2/25/2001 22:34'!\\nreportClassAndMethodRemovalsFor: collectionOfClassNames\\n\\t| initialClassesAndMethods finalClassesAndMethods |\\n\\t\\\"Smalltalk reportClassAndMethodRemovalsFor: #(Celeste Scamper MailMessage)\\\"\\n\\n\\tinitialClassesAndMethods _ self unusedClassesAndMethodsWithout: {{}. {}}.\\n\\tfinalClassesAndMethods _ self unusedClassesAndMethodsWithout: {collectionOfClassNames. {}}.\\n\\t^ {finalClassesAndMethods first copyWithoutAll: initialClassesAndMethods first.\\n\\t\\tfinalClassesAndMethods second copyWithoutAll: initialClassesAndMethods second}! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'sd 4/29/2003 19:06'!\\nunusedClasses\\n\\t\\\"Enumerates all classes in the system and returns a list of those that are \\n\\tapparently unused. A class is considered in use if it (a) has subclasses \\n\\tor (b) is referred to by some method or (c) has its name in use as a \\n\\tliteral. \\\"\\n\\t\\\"Smalltalk unusedClasses asSortedCollection\\\"\\n\\t^ self systemNavigation allUnusedClassesWithout: {{}. {}}! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'edc 11/8/2005 10:11'!\\nunusedClassesAndMethodsWithout: classesAndMessagesPair \\n\\t\\\"Accepts and returns a pair: {set of class names. set of selectors}. \\n\\tIt is expected these results will be diff'd with the normally unused \\n\\tresults. \\\"\\n\\t| classRemovals messageRemovals nClasses nMessages |\\n\\t(classRemovals _ IdentitySet new) addAll: classesAndMessagesPair first.\\n\\t(messageRemovals _ IdentitySet new) addAll: classesAndMessagesPair second.\\n\\tnClasses _ nMessages _ -1.\\n\\t[\\\"As long as we keep making progress...\\\"\\n\\tclassRemovals size > nClasses\\n\\t\\tor: [messageRemovals size > nMessages]]\\n\\t\\twhileTrue: [\\\"...keep trying for bigger sets of unused classes and selectors.\\\"\\n\\t\\t\\tnClasses _ classRemovals size.\\n\\t\\t\\tnMessages _ messageRemovals size.\\n\\t\\t\\tUtilities\\n\\t\\t\\t\\tinformUser: 'Iterating removals '\\n\\t\\t\\t\\t\\t\\t, (classesAndMessagesPair first isEmpty\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: ['for baseline...']\\n\\t\\t\\t\\t\\t\\t\\t\\tifFalse: ['for ' , classesAndMessagesPair first first , ' etc...']) , Character cr asString , nClasses printString , ' classes, ' , nMessages printString , ' messages.\\n|\\n|'\\n\\t\\t\\t\\tduring: [\\\"spacers move menu off cursor\\\"\\n\\t\\t\\t\\t\\tclassRemovals\\n\\t\\t\\t\\t\\t\\taddAll: (self systemNavigation allUnusedClassesWithout: {classRemovals. messageRemovals}).\\n\\t\\t\\t\\t\\tmessageRemovals\\n\\t\\t\\t\\t\\t\\taddAll: (self systemNavigation allUnSentMessagesWithout: {classRemovals. messageRemovals})]].\\n\\t^ {classRemovals. self systemNavigation allUnSentMessagesWithout: {classRemovals. messageRemovals}}! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'dao 10/1/2004 13:51'!\\nwriteImageSegmentsFrom: segmentDictionary withKernel: kernel\\n\\t\\\"segmentDictionary is associates segmentName -> {classNames. methodNames},\\n\\tand kernel is another set of classNames determined to be essential.\\n\\tAdd a partition, 'Secondary' with everything not in partitions and not in the kernel.\\n\\tThen write segments based on this partitioning of classes.\\\"\\n\\n\\t| metas secondary dups segDict overlaps classes n symbolHolder |\\n\\t\\\"First, put all classes that are in no other partition, and not in kernel into a new partition called 'Secondary'. Also remove any classes in kernel from putative partitions.\\\"\\n\\tsecondary _ Smalltalk classNames asIdentitySet.\\n\\tsegmentDictionary keysDo:\\n\\t\\t[:segName |\\n\\t\\tsecondary removeAllFoundIn: (segmentDictionary at: segName) first.\\n\\t\\t(segmentDictionary at: segName) first removeAllFoundIn: kernel].\\n\\tsecondary removeAllFoundIn: kernel.\\n\\tsecondary removeAllFoundIn: #(PseudoContext TranslatedMethod Utilities Preferences OutOfScopeNotification FakeClassPool BlockCannotReturn FormSetFont ExternalSemaphoreTable NetNameResolver ScreenController InterpreterPlugin Command WeakSet).\\n\\tFileDirectory allSubclassesDo: [:c | secondary remove: c name ifAbsent: []].\\n\\tsegmentDictionary at: 'Secondary' put: {secondary. {}}.\\n\\n\\t\\\"Now build segDict giving className -> segName, and report any duplicates.\\\"\\n\\tdups _ Dictionary new.\\n\\tsegDict _ IdentityDictionary new: 3000.\\n\\tsegmentDictionary keysDo:\\n\\t\\t[:segName | (segmentDictionary at: segName) first do:\\n\\t\\t\\t[:className |\\n\\t\\t\\t(segDict includesKey: className) ifTrue:\\n\\t\\t\\t\\t[(dups includesKey: className) ifFalse: [dups at: className put: Array new].\\n\\t\\t\\t\\tdups at: className put: (dups at: className) , {segName}].\\n\\t\\t\\tsegDict at: className put: segName]].\\n\\tdups size > 0 ifTrue: [dups inspect. ^ self error: 'Duplicate entries'].\\n\\n\\t\\\"Then for every class in every partition, make sure that neither it\\n\\tnor any of its superclasses are in any other partition. If they are,\\n\\tenter them in a dictionary of overlaps.\\n\\tIf the dictionary is not empty, then stop and report it.\\\"\\n\\toverlaps _ Dictionary new.\\n\\tsegmentDictionary keysDo:\\n\\t\\t[:segName | \\n\\t\\tclasses _ (segmentDictionary at: segName) first asArray collect: [:k | Smalltalk at: k].\\n\\t\\tclasses do:\\n\\t\\t\\t[:c | (c isKindOf: Class) ifTrue:\\n\\t\\t\\t\\t[c withAllSuperclasses do:\\n\\t\\t\\t\\t\\t[:sc | n _ segDict at: sc name ifAbsent: [segName].\\n\\t\\t\\t\\t\\tn ~= segName ifTrue:\\n\\t\\t\\t\\t\\t\\t[n = 'Secondary'\\n\\t\\t\\t\\t\\t\\t\\tifTrue: [(segmentDictionary at: 'Secondary') first\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tremove: sc name ifAbsent: []]\\n\\t\\t\\t\\t\\t\\t\\tifFalse: [overlaps at: c name put: \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t(c withAllSuperclasses collect: [:cc | segDict associationAt: cc name ifAbsent: [cc name -> 'Kernel']])]]]]]].\\n\\toverlaps size > 0 ifTrue: [overlaps inspect. ^ self error: 'Superclasses in separate segments'].\\n\\n\\t\\\"If there are no overlaps, then proceed to write the partitioned classes.\\\"\\n\\tsymbolHolder _ Symbol allInstances.\\t\\\"Hold onto Symbols with strong pointers, \\n\\t\\tso they will be in outPointers\\\"\\n\\tsegmentDictionary keysDo:\\n\\t\\t[:segName | Utilities informUser: segName during:\\n\\t\\t\\t[classes _ (segmentDictionary at: segName) first asArray collect: [:k | Smalltalk at: k].\\n\\t\\t\\tmetas _ classes select: [:c | c isKindOf: Class] thenCollect: [:c | c class].\\n\\t\\t\\t(ImageSegment new copyFromRoots: classes , metas sizeHint: 0) extract; \\n\\t\\t\\t\\t\\twriteToFile: segName]].\\n\\tsymbolHolder. \\\"Keep compiler for getting uppity.\\\"! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'ar 9/27/2005 20:12'!\\nzapAllOtherProjects \\n\\t\\\"Smalltalk zapAllOtherProjects\\\"\\n\\\"Note: as of this writing, the only reliable way to get rid of all but the current project is te execute the following, one line at a time...\\n\\t\\tSmalltalk zapAllOtherProjects.\\n\\t\\tProjectHistory currentHistory initialize.\\n\\t\\tSmalltalk garbageCollect.\\n\\t\\tProject rebuildAllProjects.\\n\\\"\\n\\n\\t\\n\\tProject allInstancesDo: [:p | p setParent: nil].\\n\\tProject current setParent: Project current.\\n\\tProject current isMorphic ifTrue: [ScheduledControllers := nil].\\n\\tTheWorldMenu allInstancesDo: [:m | 1 to: m class instSize do: [:i | m instVarAt: i put: nil]].\\n\\tChangeSet classPool at: #AllChangeSets put: nil.\\n\\tProject classPool at: #AllProjects put: nil.\\n\\tProjectHistory currentHistory initialize.\\n\\tChangeSet initialize.\\n\\tProject rebuildAllProjects. \\\"Does a GC\\\"\\n\\tProject allProjects size > 1 ifTrue: [Project allProjects inspect]! !\\n\\n!SystemDictionary methodsFor: 'shrinking' stamp: 'dao 10/1/2004 13:30'!\\nzapMVCprojects\\n\\t\\\"Smalltalk zapMVCprojects\\\"\\n\\t| window |\\n\\n\\tself flag: #bob. \\\"zapping projects\\\"\\n\\n\\tSmalltalk garbageCollect.\\n\\t\\\"So allInstances is precise\\\"\\n\\tProject\\n\\t\\tallSubInstancesDo: [:proj | proj isTopProject\\n\\t\\t\\t\\tifTrue: [proj isMorphic\\n\\t\\t\\t\\t\\t\\tifFalse: [\\\"Root project is MVC -- we must become the root\\\"\\n\\t\\t\\t\\t\\t\\t\\tProject current setParent: Project current.]]\\n\\t\\t\\t\\tifFalse: [proj parent isMorphic\\n\\t\\t\\t\\t\\t\\tifFalse: [proj isMorphic\\n\\t\\t\\t\\t\\t\\t\\t\\tifTrue: [\\\"Remove Morphic projects from MVC \\n\\t\\t\\t\\t\\t\\t\\t\\t\\tviews \\\"\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\\"... and add them back here.\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\t\\twindow _ (SystemWindow labelled: proj name)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tmodel: proj.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\twindow\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\taddMorph: (ProjectViewMorph on: proj)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tframe: (0 @ 0 corner: 1.0 @ 1.0).\\n\\t\\t\\t\\t\\t\\t\\t\\t\\twindow openInWorld.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\tproj setParent: Project current]].\\n\\t\\t\\t\\t\\tproj isMorphic\\n\\t\\t\\t\\t\\t\\tifFalse: [\\\"Remove MVC projects from Morphic views\\\"\\n\\t\\t\\t\\t\\t\\t\\tProject deletingProject: proj]]]! !\\n\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'di 2/4/1999 15:38'!\\naddToShutDownList: aClass\\n\\t\\\"This will add a ref to this class at the BEGINNING of the shutDown list.\\\"\\n\\n\\tself addToShutDownList: aClass after: nil! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'di 2/3/1999 22:04'!\\naddToShutDownList: aClass after: predecessor\\n\\n\\tself add: aClass toList: ShutDownList after: predecessor! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'di 2/4/1999 15:37'!\\naddToStartUpList: aClass\\n\\t\\\"This will add a ref to this class at the END of the startUp list.\\\"\\n\\n\\tself addToStartUpList: aClass after: nil! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'di 2/3/1999 22:04'!\\naddToStartUpList: aClass after: predecessor\\n\\n\\tself add: aClass toList: StartUpList after: predecessor! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'ar 11/19/1999 22:36'!\\nadd: aClass toList: startUpOrShutDownList after: predecessor\\n\\t\\\"Add the name of aClass to the startUp or shutDown list.\\n\\tAdd it after the name of predecessor, or at the end if predecessor is nil.\\\"\\n\\n\\t| name earlierName |\\n\\tname _ aClass name.\\n\\t(self at: name ifAbsent: [nil]) == aClass ifFalse:\\n\\t\\t[self error: name , ' cannot be found in Smalltalk dictionary.'].\\n\\tpredecessor == nil\\n\\t\\tifTrue: [\\\"No-op if alredy in the list.\\\"\\n\\t\\t\\t\\t(startUpOrShutDownList includes: name) ifFalse:\\n\\t\\t\\t\\t\\t[startUpOrShutDownList == StartUpList\\n\\t\\t\\t\\t\\t\\tifTrue: [\\\"Add to end of startUp list\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\tstartUpOrShutDownList addLast: name]\\n\\t\\t\\t\\t\\t\\tifFalse: [\\\"Add to front of shutDown list\\\"\\n\\t\\t\\t\\t\\t\\t\\t\\tstartUpOrShutDownList addFirst: name]]]\\n\\t\\tifFalse: [\\\"Add after predecessor, moving it if already there.\\\"\\n\\t\\t\\t\\tearlierName _ predecessor name.\\n\\t\\t\\t\\t(self at: earlierName) == predecessor ifFalse:\\n\\t\\t\\t\\t\\t[self error: earlierName , ' cannot be found in Smalltalk dictionary.'].\\n\\t\\t\\t\\t(startUpOrShutDownList includes: earlierName) ifFalse:\\n\\t\\t\\t\\t\\t[self error: earlierName , ' cannot be found in the list.'].\\n\\t\\t\\t\\tstartUpOrShutDownList remove: name ifAbsent:[].\\n\\t\\t\\t\\tstartUpOrShutDownList add: name after: earlierName]! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'RAA 6/14/2000 17:21'!\\nisMorphic\\n \\\"Answer true if the user interface is running in Morphic rathern than \\n MVC. By convention the gloabl variable World is set to nil when MVC is \\n running. ScheduledControllers could be set to nil when Morphic is \\n running, but this symmetry is not yet in effect.\\\"\\n\\n ^ World ~~ nil \\\"or: [RequestCurrentWorldNotification signal notNil]\\\"! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'ar 11/16/1999 20:12'!\\nprocessShutDownList: quitting\\n\\t\\\"Send #shutDown to each class that needs to wrap up before a snapshot.\\\"\\n\\n\\tself send: #shutDown: toClassesNamedIn: ShutDownList with: quitting.\\n! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'ar 11/16/1999 20:12'!\\nprocessStartUpList: resuming\\n\\t\\\"Send #startUp to each class that needs to run initialization after a snapshot.\\\"\\n\\n\\tself send: #startUp: toClassesNamedIn: StartUpList with: resuming.\\n! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit'!\\nquitPrimitive\\n\\t\\\"Primitive. Exit to another operating system on the host machine, if one\\n\\texists. All state changes in the object space since the last snapshot are lost.\\n\\tEssential. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 113>\\n\\tself primitiveFailed! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'di 2/3/1999 22:22'!\\nremoveFromShutDownList: aClass\\n\\n\\tShutDownList remove: aClass name ifAbsent: []! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'di 2/3/1999 22:22'!\\nremoveFromStartUpList: aClass\\n\\n\\tStartUpList remove: aClass name ifAbsent: []! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'di 3/7/2001 01:26'!\\nsend: startUpOrShutDown toClassesNamedIn: startUpOrShutDownList with: argument\\n\\t\\\"Send the message #startUp: or #shutDown: to each class named in the list.\\n\\tThe argument indicates if the system is about to quit (for #shutDown:) or if\\n\\tthe image is resuming (for #startUp:).\\n\\tIf any name cannot be found, then remove it from the list.\\\"\\n\\n\\t| removals class |\\n\\tremovals _ OrderedCollection new.\\n\\tstartUpOrShutDownList do:\\n\\t\\t[:name |\\n\\t\\tclass _ self at: name ifAbsent: [nil].\\n\\t\\tclass == nil\\n\\t\\t\\tifTrue: [removals add: name]\\n\\t\\t\\tifFalse: [class isInMemory ifTrue:\\n\\t\\t\\t\\t\\t\\t[class perform: startUpOrShutDown with: argument]]].\\n\\n\\t\\\"Remove any obsolete entries, but after the iteration\\\"\\n\\tstartUpOrShutDownList removeAll: removals! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'sd 9/30/2003 13:47'!\\nsetGCParameters\\n\\t\\\"Adjust the VM's default GC parameters to avoid premature tenuring.\\\"\\n\\n\\tSmalltalkImage current vmParameterAt: 5 put: 4000. \\\"do an incremental GC after this many allocations\\\"\\n\\tSmalltalkImage current vmParameterAt: 6 put: 2000. \\\"tenure when more than this many objects survive the GC\\\"\\n! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'sd 11/16/2003 13:14'!\\nshutDown\\n\\t^ SmalltalkImage current closeSourceFiles! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'gk 2/23/2004 20:51'!\\nshutDownSound\\n\\t\\\"No longer used in the release, but retained for backward compatibility.\\\"\\n\\n\\tSoundService default shutDown\\n! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'JMM 11/21/2000 21:02'!\\nsnapshotEmbeddedPrimitive\\n\\t<primitive: 247>\\n\\t^nil \\\"indicates error writing embedded image file\\\"! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'ar 7/22/2000 14:34'!\\nsnapshotPrimitive\\n\\t\\\"Primitive. Write the current state of the object memory on a file in the\\n\\tsame format as the Smalltalk-80 release. The file can later be resumed,\\n\\treturning you to this exact state. Return normally after writing the file.\\n\\tEssential. See Object documentation whatIsAPrimitive.\\\"\\n\\n\\t<primitive: 97>\\n\\t^nil \\\"indicates error writing image file\\\"! !\\n\\n!SystemDictionary methodsFor: 'snapshot and quit' stamp: 'nk 11/12/2003 10:32'!\\nunbindExternalPrimitives\\n\\t\\\"Primitive. Force all external primitives to be looked up again afterwards. Since external primitives that have not found are bound for fast failure this method will force the lookup of all primitives again so that after adding some plugin the primitives may be found.\\\"\\n\\t^ self deprecated: 'Use SmalltalkImage unbindExternalPrimitives'\\n\\t\\tblock: [SmalltalkImage unbindExternalPrimitives].\\n\\t\\\"Do nothing if the primitive fails for compatibility with older VMs\\\"! !\\n\\n\\n!SystemDictionary methodsFor: 'sources, change log'!\\ncopyright\\n\\t\\\"The Smalltalk copyright.\\\"\\n\\n\\t^'Copyright (c) Xerox Corp. 1981, 1982 All rights reserved.\\nCopyright (c) Apple Computer, Inc. 1985-1996 All rights reserved.'! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'em 3/31/2005 11:48'!\\ncurrentChangeSetString\\n\\t\\\"Smalltalk currentChangeSetString\\\"\\n\\t^ 'Current Change Set: ' translated, ChangeSet current name! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'sd 9/29/2004 18:27'!\\ncurrentProjectDo: aBlock \\n\\t\\\"So that code can work after removal of Projects\\\"\\n\\tself\\n\\t\\tat: #Project\\n\\t\\tifPresent: [:projClass | aBlock value: projClass current]! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'sd 11/16/2003 12:55'!\\nexternalizeSources \\n\\t\\\"Write the sources and changes streams onto external files.\\\"\\n \\t\\\"Smalltalk externalizeSources\\\"\\n\\t\\\"the logic of this method is complex because it uses changesName and self changesName\\n\\tmay be this is normal - sd\\\"\\n\\t\\n\\t| sourcesName changesName aFile |\\n\\tsourcesName _ SmalltalkImage current sourcesName.\\n\\t(FileDirectory default fileExists: sourcesName)\\n\\t\\tifTrue: [^ self inform:\\n'Sorry, you must first move or remove the\\nfile named ', sourcesName].\\n\\tchangesName _ SmalltalkImage current changesName.\\n\\t(FileDirectory default fileExists: changesName)\\n\\t\\tifTrue: [^ self inform:\\n'Sorry, you must first move or remove the\\nfile named ', changesName].\\n\\n\\taFile _ FileStream newFileNamed: sourcesName.\\n\\taFile nextPutAll: SourceFiles first originalContents.\\n\\taFile close.\\n\\tself setMacFileInfoOn: sourcesName.\\n\\tSourceFiles at: 1 put: (FileStream readOnlyFileNamed: sourcesName).\\n\\n\\taFile _ FileStream newFileNamed: SmalltalkImage current changesName.\\n\\taFile nextPutAll: SourceFiles last contents.\\n\\taFile close.\\n\\t\\\"On Mac, set the file type and creator (noop on other platforms)\\\"\\n\\tFileDirectory default\\n\\t\\tsetMacFileNamed: SmalltalkImage current changesName\\n\\t\\ttype: 'STch'\\n\\t\\tcreator: 'FAST'.\\n\\tSourceFiles at: 2 put: (FileStream oldFileNamed: changesName).\\n\\n\\tself inform: 'Sources successfully externalized'.\\n! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'ar 2/6/2001 18:42'!\\nforceChangesToDisk\\n\\t\\\"Ensure that the changes file has been fully written to disk by closing and re-opening it. This makes the system more robust in the face of a power failure or hard-reboot.\\\"\\n\\n\\t| changesFile |\\n\\tchangesFile _ SourceFiles at: 2.\\n\\t(changesFile isKindOf: FileStream) ifTrue: [\\n\\t\\tchangesFile flush.\\n\\t\\tSecurityManager default hasFileAccess ifTrue:[\\n\\t\\t\\tchangesFile close.\\n\\t\\t\\tchangesFile open: changesFile name forWrite: true].\\n\\t\\tchangesFile setToEnd.\\n\\t].\\n! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'sd 11/16/2003 12:55'!\\ninternalizeChangeLog \\n\\t\\t\\\"Smalltalk internalizeChangeLog\\\"\\n\\t\\\"Bring the changes file into a memory-resident filestream, for faster access and freedom from external file system. 1/31/96 sw\\\"\\n\\n\\t| reply aName aFile |\\n\\treply _ self confirm: 'CAUTION -- do not undertake this lightly!!\\nIf you have backed up your system and\\nare prepared to face the consequences of\\nthe requested internalization of sources,\\nhit Yes. If you have any doubts, hit No\\nto back out with no harm done.'.\\n\\n\\t(reply == true) ifFalse:\\n\\t\\t[^ self inform: 'Okay - abandoned'].\\n\\n\\taName _ SmalltalkImage current changesName.\\n\\t(aFile _ SourceFiles last) == nil ifTrue:\\n\\t\\t[(FileDirectory default fileExists: aName)\\n\\t\\t\\tifFalse: [^ self halt: 'Cannot locate ', aName, ' so cannot proceed.'].\\n\\t\\taFile _ FileStream readOnlyFileNamed: aName].\\n\\tSourceFiles at: 2 put: (ReadWriteStream with: aFile contentsOfEntireFile).\\n\\n\\tself inform: 'Okay, changes file internalized'! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'sd 11/16/2003 12:55'!\\ninternalizeSources \\n\\t\\t\\\"Smalltalk internalizeSources\\\"\\n\\t\\\"Bring the sources and changes files into memory-resident filestreams, for faster access and freedom from file-system interface. 1/29/96 sw\\\"\\n\\n\\t| reply aName aFile |\\n\\treply _ self confirm: 'CAUTION -- do not undertake this lightly!!\\nIf you have backed up your system and\\nare prepared to face the consequences of\\nthe requested internalization of sources,\\nhit Yes. If you have any doubts, hit No\\nto back out with no harm done.'.\\n\\n\\t(reply == true) ifFalse:\\n\\t\\t[^ self inform: 'Okay - abandoned'].\\n\\n\\taName _ SmalltalkImage current sourcesName.\\n\\t(aFile _ SourceFiles first) == nil ifTrue:\\n\\t\\t[(FileDirectory default fileExists: aName)\\n\\t\\t\\tifFalse: [^ self halt: 'Cannot locate ', aName, ' so cannot proceed.'].\\n\\t\\taFile _ FileStream readOnlyFileNamed: aName].\\n\\tSourceFiles at: 1 put: (ReadWriteStream with: aFile contentsOfEntireFile).\\n\\n\\taName _ SmalltalkImage current changesName.\\n\\t(aFile _ SourceFiles last) == nil ifTrue:\\n\\t\\t[(FileDirectory default fileExists: aName)\\n\\t\\t\\tifFalse: [^ self halt: 'Cannot locate ', aName, ' so cannot proceed.'].\\n\\t\\taFile _ FileStream readOnlyFileNamed: aName].\\n\\tSourceFiles at: 2 put: (ReadWriteStream with: aFile contentsOfEntireFile).\\n\\n\\tself inform: 'Okay, sources internalized'! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'sw 2/3/2000 15:59'!\\nrecover: nCharacters\\n\\t\\\"Schedule an editable text view on the last n characters of changes.\\\"\\n\\tself writeRecentCharacters: nCharacters toFileNamed: 'st80.recent'! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'md 5/16/2006 12:34'!\\nversion\\n\\t\\\"Answer the version of this release.\\\"\\n\\n\\t^SystemVersion current version! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'JMM 4/13/2005 20:35'!\\nwordSize\\n\\t\\\"Answer the size (in bytes) of an object pointer.\\\"\\n\\t\\\"Smalltalk wordSize\\\"\\n\\n\\t^[SmalltalkImage current vmParameterAt: 40] on: Error do: [4]! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'nk 8/21/2004 15:55'!\\nwriteRecentCharacters: nCharacters toFileNamed: aFilename\\n\\t\\\"Schedule an editable text view on the last n characters of changes.\\\"\\n\\t| changes |\\n\\tchanges _ SourceFiles at: 2.\\n\\tchanges setToEnd; skip: nCharacters negated.\\n\\t(StandardFileStream newFileNamed: aFilename) nextPutAll: (changes next: nCharacters); close; open; edit! !\\n\\n!SystemDictionary methodsFor: 'sources, change log' stamp: 'ar 9/27/2005 22:38'!\\nwriteRecentToFile\\n\\t\\\"Smalltalk writeRecentToFile\\\"\\n\\t| numChars aDirectory aFileName |\\n\\taDirectory := FileDirectory default.\\n\\taFileName := Utilities\\n\\t\\t\\t\\tkeyLike: 'squeak-recent.01'\\n\\t\\t\\t\\twithTrailing: '.log'\\n\\t\\t\\t\\tsatisfying: [:aKey | (aDirectory includesKey: aKey) not].\\n\\tnumChars := ChangeSet getRecentLocatorWithPrompt: 'copy logged source as far back as...'.\\n\\tnumChars\\n\\t\\tifNotNil: [self writeRecentCharacters: numChars toFileNamed: aFileName]! !\\n\\n\\n!SystemDictionary methodsFor: 'special objects' stamp: 'JMM 6/6/2000 20:36'!\\nclearExternalObjects\\n\\t\\\"Clear the array of objects that have been registered for use in non-Smalltalk code.\\\"\\n\\t\\\"Smalltalk clearExternalObjects\\\"\\n\\n\\tExternalSemaphoreTable clearExternalObjects\\n! !\\n\\n!SystemDictionary methodsFor: 'special objects' stamp: 'sd 9/29/2004 18:30'!\\ncompactClassesArray\\n\\t\\\"Smalltalk compactClassesArray\\\"\\n\\t\\\"Return the array of 31 classes whose instances may be\\n\\trepresented compactly\\\"\\n\\t^ self specialObjectsArray at: 29! !\\n\\n!SystemDictionary methodsFor: 'special objects' stamp: 'JMM 6/6/2000 21:01'!\\nexternalObjects\\n\\t\\\"Return an array of objects that have been registered for use in non-Smalltalk code. Smalltalk objects should be referrenced by external code only via indirection through this array, thus allowing the objects to move during compaction. This array can be cleared when the VM re-starts, since variables in external code do not survive snapshots. Note that external code should not attempt to access a Smalltalk object, even via this mechanism, while garbage collection is in progress.\\\"\\n\\t\\\"Smalltalk externalObjects\\\"\\n\\n\\t^ ExternalSemaphoreTable externalObjects\\n! !\\n\\n!SystemDictionary methodsFor: 'special objects'!\\nhasSpecialSelector: aLiteral ifTrueSetByte: aBlock\\n\\n\\t1 to: self specialSelectorSize do:\\n\\t\\t[:index | \\n\\t\\t(self specialSelectorAt: index) == aLiteral\\n\\t\\t\\tifTrue: [aBlock value: index + 16rAF. ^true]].\\n\\t^false! !\\n\\n!SystemDictionary methodsFor: 'special objects' stamp: 'dtl 10/3/2005 05:56'!\\nrecreateSpecialObjectsArray\\n\\t\\\"Smalltalk recreateSpecialObjectsArray\\\"\\n\\t\\\"The Special Objects Array is an array of object pointers used\\n\\tby the\\n\\tSqueak virtual machine. Its contents are critical and\\n\\tunchecked, so don't even think of playing here unless you\\n\\tknow what you are doing.\\\"\\n\\t| newArray |\\n\\tnewArray := Array new: 50.\\n\\t\\\"Nil false and true get used throughout the interpreter\\\"\\n\\tnewArray at: 1 put: nil.\\n\\tnewArray at: 2 put: false.\\n\\tnewArray at: 3 put: true.\\n\\t\\\"This association holds the active process (a ProcessScheduler)\\\"\\n\\tnewArray\\n\\t\\tat: 4\\n\\t\\tput: (self associationAt: #Processor).\\n\\t\\\"Numerous classes below used for type checking and\\n\\tinstantiation\\\"\\n\\tnewArray at: 5 put: Bitmap.\\n\\tnewArray at: 6 put: SmallInteger.\\n\\tnewArray at: 7 put: ByteString.\\n\\tnewArray at: 8 put: Array.\\n\\tnewArray at: 9 put: Smalltalk.\\n\\tnewArray at: 10 put: Float.\\n\\tnewArray at: 11 put: MethodContext.\\n\\tnewArray at: 12 put: BlockContext.\\n\\tnewArray at: 13 put: Point.\\n\\tnewArray at: 14 put: LargePositiveInteger.\\n\\tnewArray at: 15 put: Display.\\n\\tnewArray at: 16 put: Message.\\n\\tnewArray at: 17 put: CompiledMethod.\\n\\tnewArray\\n\\t\\tat: 18\\n\\t\\tput: (self specialObjectsArray at: 18).\\n\\t\\\"(low space Semaphore)\\\"\\n\\tnewArray at: 19 put: Semaphore.\\n\\tnewArray at: 20 put: Character.\\n\\tnewArray at: 21 put: #doesNotUnderstand:.\\n\\tnewArray at: 22 put: #cannotReturn:.\\n\\t\\\"The process that signaled the low space semaphore.\\\"\\n\\tnewArray at: 23 put: nil.\\n\\t\\\"An array of the 32 selectors that are compiled as special\\n\\tbytecodes, paired alternately with the number of arguments\\n\\teach takes.\\\"\\n\\tnewArray at: 24 put: #(#+ 1 #- 1 #< 1 \";\n r = \"{13490630, 1448950}\";\n s = 1;\n }\n );\n r = \"{0, 17583493}\";\n s = 0;\n}";
7842
sepNavIntBoundsRect = "{{0, 0}, {3988, 3.06823e+06}}";
7843
sepNavSelRange = "{1340, 0}";
7844
sepNavVisRange = "{0, 2724}";