'From Squeak3.0 of 4 February 2001 [latest update: #3545] on 18 February 2001 at 1:11:38 am'! !AsynchFilePlugin methodsFor: 'primitives' stamp: 'ar 2/6/2001 14:03'! primitiveAsyncFileOpen: fileName forWrite: writeFlag semaIndex: semaIndex | fileNameSize fOop f | self var: #f declareC: 'AsyncFile *f'. self primitive: 'primitiveAsyncFileOpen' parameters: #(String Boolean SmallInteger ). fileNameSize _ interpreterProxy slotSizeOf: (fileName asOop: String). (self ioCanOpenAsyncFile: fileName OfSize: fileNameSize Writable: writeFlag) ifFalse:[^interpreterProxy primitiveFail]. fOop _ interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: (self cCode: 'sizeof(AsyncFile)'). f _ self asyncFileValueOf: fOop. interpreterProxy failed ifFalse: [self cCode: 'asyncFileOpen(f, (int)fileName, fileNameSize, writeFlag, semaIndex)']. ^ fOop! ! !AsynchFilePlugin class methodsFor: 'translation' stamp: 'ar 2/6/2001 14:04'! headerFile ^'/* Header file for AsynchFile plugin */ /* module initialization/shutdown */ int asyncFileInit(void); int asyncFileShutdown(void); /*** Experimental Asynchronous File I/O ***/ typedef struct { int sessionID; void *state; } AsyncFile; int asyncFileClose(AsyncFile *f); int asyncFileOpen(AsyncFile *f, int fileNamePtr, int fileNameSize, int writeFlag, int semaIndex); int asyncFileRecordSize(); int asyncFileReadResult(AsyncFile *f, int bufferPtr, int bufferSize); int asyncFileReadStart(AsyncFile *f, int fPosition, int count); int asyncFileWriteResult(AsyncFile *f); int asyncFileWriteStart(AsyncFile *f, int fPosition, int bufferPtr, int bufferSize); /*** security traps ***/ /* following is equivalent ioCanOpenFileOfSize() and should really be handled from there */ int ioCanOpenAsyncFileOfSizeWritable(char* fileNameIndex, int fileNameSize, int writeFlag); #ifdef DISABLE_SECURITY #define ioCanOpenAsyncFileOfSizeWritable(index, size, flag) 1 #endif '! ! !AutoStart class methodsFor: 'class initialization' stamp: 'ar 2/6/2001 17:12'! initialize "AutoStart initialize" Smalltalk addToStartUpList: AutoStart after: SecurityManager.! ! I am a conversion utility for reading X11 Bitmap Distribution Format fonts. My code is derived from the multilingual Squeak changeset written by OHSHIMA Yoshiki (ohshima@is.titech.ac.jp), although all support for fonts with more than 256 glyphs has been ripped out. See http://www.is.titech.ac.jp/~ohshima/squeak/squeak-multilingual-e.html . My class methods contain tools for fetching BDF source files from a well-known archive site, batch conversion to Squeak's .sf2 format, and installation of these fonts as TextStyles. Also, the legal notices for the standard 75dpi fonts I process this way are included as "x11FontLegalNotices'.! !BDFFontReader methodsFor: 'as yet unclassified' stamp: 'nop 1/18/2000 19:45'! errorFileFormat self error: 'malformed bdf format'! ! !BDFFontReader methodsFor: 'as yet unclassified' stamp: 'nop 1/18/2000 19:46'! errorUnsupported self error: 'unsupported bdf'! ! !BDFFontReader methodsFor: 'as yet unclassified' stamp: 'nop 1/18/2000 19:43'! getLine ^self upTo: Character cr.! ! !BDFFontReader methodsFor: 'as yet unclassified' stamp: 'nop 1/18/2000 19:44'! initialize properties _ Dictionary new.! ! !BDFFontReader methodsFor: 'as yet unclassified' stamp: 'nop 1/23/2000 18:58'! read | xTable strikeWidth glyphs ascent descent minAscii maxAscii maxWidth chars charsNum height form encoding bbx array width blt lastAscii pointSize ret dwidth cell cellBlt | form _ encoding _ bbx _ nil. self initialize. self readAttributes. height _ Integer readFromString: ((properties at: #FONTBOUNDINGBOX) at: 2). ascent _ Integer readFromString: (properties at: 'FONT_ASCENT' asSymbol) first. descent _ Integer readFromString: (properties at: 'FONT_DESCENT' asSymbol) first. pointSize _ (Integer readFromString: (properties at: 'POINT_SIZE' asSymbol) first) // 10. maxWidth _ 0. minAscii _ 9999. strikeWidth _ 0. maxAscii _ 0. charsNum _ Integer readFromString: (properties at: #CHARS) first. chars _ Set new: charsNum. 1 to: charsNum do: [:i | array _ self readOneCharacter. form _ array at: 1. encoding _ array at: 2. bbx _ array at: 3. dwidth _ array at: 4. "form isNil ifFalse: [form morphEdit]." "self halt." form ifNotNil: [ dwidth _ dwidth - 1. width _ dwidth max: (bbx at: 1). maxWidth _ maxWidth max: width. minAscii _ minAscii min: encoding. maxAscii _ maxAscii max: encoding. strikeWidth _ strikeWidth + width. chars add: array. ]. ]. chars _ chars asSortedCollection: [:x :y | (x at: 2) <= (y at: 2)]. charsNum _ chars size. "undefined encodings make this different" xTable _ (Array new: 258) atAllPut: 0. glyphs _ Form extent: strikeWidth@height. blt _ BitBlt toForm: glyphs. lastAscii _ 0. 1 to: charsNum do: [:i | | unspliceArray | unspliceArray _ chars at: i. form _ unspliceArray at: 1. encoding _ unspliceArray at: 2. bbx _ unspliceArray at: 3. dwidth _ (unspliceArray at: 4). width _ dwidth max: (bbx at: 1). lastAscii+1 to: encoding-1 do: [:a | xTable at: a+2 put: (xTable at: a+1)]. "I should be able to do all of this in one blit, but I'm too confused. Create a Form of the proper size for this glyph, render the BDF bitmap into it, then stamp it into the StrikeFont glyphs form." cell _ Form extent: width@height. cellBlt _ BitBlt toForm: cell. cellBlt copy: ((bbx at: 3)@((ascent - (bbx at: 2) - (bbx at: 4))) extent: (bbx at: 1)@(bbx at: 2)) from: 0@0 in: form. blt copyForm: cell to: (xTable at: encoding+1)@0 rule: Form over. "blt copy: (( ((xTable at: encoding+1)+(bbx at: 3))@(ascent - (bbx at: 2) - (bbx at: 4))) extent: (bbx at: 1)@(bbx at: 2)) from: 0@0 in: form." xTable at: encoding+2 put: (xTable at: encoding+1)+(width). lastAscii _ encoding. ]. ret _ Array new: 8. ret at: 1 put: xTable. ret at: 2 put: glyphs. ret at: 3 put: minAscii. ret at: 4 put: maxAscii. ret at: 5 put: maxWidth. ret at: 6 put: ascent. ret at: 7 put: descent. ret at: 8 put: pointSize. ^ret. " ^{xTable. glyphs. minAscii. maxAscii. maxWidth. ascent. descent. pointSize}"! ! !BDFFontReader methodsFor: 'as yet unclassified' stamp: 'nop 1/18/2000 19:44'! readAttributes | str a | "I don't handle double-quotes correctly, but it works" self reset. [self atEnd] whileFalse: [ str _ self getLine. (str beginsWith: 'STARTCHAR') ifTrue: [self skip: (0 - str size - 1). ^self]. a _ str substrings. properties at: a first asSymbol put: a allButFirst. ]. self error: 'file seems corrupted'.! ! !BDFFontReader methodsFor: 'as yet unclassified' stamp: 'nop 1/22/2000 23:33'! readOneCharacter | str a encoding bbx form bits hi low pos char dwidth | ((str _ self getLine) beginsWith: 'STARTCHAR') ifFalse: [self errorFileFormat]. char _ str substrings second. ((str _ self getLine) beginsWith: 'ENCODING') ifFalse: [self errorFileFormat]. encoding _ Integer readFromString: str substrings second. (self getLine beginsWith: 'SWIDTH') ifFalse: [self errorFileFormat]. ((str _ self getLine) beginsWith: 'DWIDTH') ifFalse: [self errorFileFormat]. dwidth _ Integer readFromString: str substrings second. ((str _ self getLine) beginsWith: 'BBX') ifFalse: [self errorFileFormat]. a _ str substrings. bbx _ (2 to: 5) collect: [:i | Integer readFromString: (a at: i)]. ((str _ self getLine) beginsWith: 'ATTRIBUTES') ifTrue: [str _ self getLine]. (str beginsWith: 'BITMAP') ifFalse: [self errorFileFormat]. form _ Form extent: (bbx at: 1)@(bbx at: 2). bits _ form bits. pos _ 0. 1 to: (bbx at: 2) do: [:t | 1 to: (((bbx at: 1) - 1) // 8 + 1) do: [:i | hi _ (('0123456789ABCDEF' indexOf: (self next asUppercase)) - 1) bitShift: 4. low _ ('0123456789ABCDEF' indexOf: (self next asUppercase)) - 1. bits byteAt: (pos+i) put: (hi+low). ]. self next ~= Character cr ifTrue: [self errorFileFormat]. pos _ pos + ((((bbx at: 1) + 31) // 32) * 4). ]. (self getLine beginsWith: 'ENDCHAR') ifFalse: [self errorFileFormat]. encoding < 0 ifTrue: [^{nil. nil. nil. nil}]. ^{form. encoding. bbx. dwidth}. ! ! !BDFFontReader class methodsFor: 'file creation' stamp: 'nop 1/23/2000 19:00'! convertFilesNamed: fileName toFamilyNamed: familyName inDirectoryNamed: dirName "BDFFontReader convertFilesNamed: 'helvR' toFamilyNamed: 'Helvetica' inDirectoryNamed: '' " "This utility converts X11 BDF font files to Squeak .sf2 StrikeFont files." "For this utility to work as is, the BDF files must be named 'familyNN.bdf', and must reside in the directory named by dirName (use '' for the current directory). The output StrikeFont files will be named familyNN.sf2, and will be placed in the current directory." | f allFontNames sizeChars dir | "Check for matching file names." dir _ dirName isEmpty ifTrue: [FileDirectory default] ifFalse: [FileDirectory default directoryNamed: dirName]. allFontNames _ dir fileNamesMatching: fileName , '##.bdf'. allFontNames isEmpty ifTrue: [^ self error: 'No files found like ' , fileName , 'NN.bdf']. Utilities informUserDuring: [:info | allFontNames do: [:fname | info value: 'Converting ', familyName, ' BDF file ', fname, ' to SF2 format'. sizeChars _ (fname copyFrom: fileName size + 1 to: fname size) copyUpTo: $. . f _ StrikeFont new readBDFFromFile: (dir fullNameFor: fname) name: familyName, sizeChars. f writeAsStrike2named: familyName, sizeChars, '.sf2'. ]. ]! ! !BDFFontReader class methodsFor: 'resource download' stamp: 'nop 1/23/2000 18:43'! convertX11FontsToStrike2 "BDFFontReader convertX11FontsToStrike2" "Given a set of standard X11 BDF font files (probably downloaded via BDFFontReader downloadFonts), produce .sf2 format fonts. The source and destination directory is the current directory." "Charter currently tickles a bug in the BDF parser. Skip it for now." "self convertFilesNamed: 'charR' toFamilyNamed: 'Charter' inDirectoryNamed: ''." self convertFilesNamed: 'courR' toFamilyNamed: 'Courier' inDirectoryNamed: ''. self convertFilesNamed: 'helvR' toFamilyNamed: 'Helvetica' inDirectoryNamed: ''. self convertFilesNamed: 'lubR' toFamilyNamed: 'LucidaBright' inDirectoryNamed: ''. self convertFilesNamed: 'luRS' toFamilyNamed: 'Lucida' inDirectoryNamed: ''. self convertFilesNamed: 'lutRS' toFamilyNamed: 'LucidaTypewriter' inDirectoryNamed: ''. self convertFilesNamed: 'ncenR' toFamilyNamed: 'NewCenturySchoolbook' inDirectoryNamed: ''. self convertFilesNamed: 'timR' toFamilyNamed: 'TimesRoman' inDirectoryNamed: ''.! ! !BDFFontReader class methodsFor: 'resource download' stamp: 'nop 2/11/2001 00:24'! downloadFonts "BDFFontReader downloadFonts" "Download a standard set of BDF sources from x.org. The combined size of these source files is around 1.2M; after conversion to .sf2 format they may be deleted." | heads tails filenames baseUrl basePath newUrl newPath document f | heads _ #( 'charR' 'courR' 'helvR' 'lubR' 'luRS' 'lutRS' 'ncenR' 'timR' ). tails _ #( '08' '10' '12' '14' '18' '24'). filenames _ OrderedCollection new. heads do: [:head | filenames addAll: (tails collect: [:tail | head , tail , '.bdf']) ]. baseUrl _ Url absoluteFromText: 'http://ftp.x.org/pub/R6.4/xc/fonts/bdf/75dpi/'. basePath _ baseUrl path. filenames do: [:filename | newUrl _ baseUrl clone. newPath _ OrderedCollection newFrom: basePath. newPath addLast: filename. newUrl path: newPath. Utilities informUser: 'Fetching ' , filename during: [document _ newUrl retrieveContents]. f _ CrLfFileStream newFileNamed: filename. f nextPutAll: document content. f close. ]. ! ! !BDFFontReader class methodsFor: 'resource download' stamp: 'nop 1/23/2000 18:44'! installX11Fonts "BDFFontReader installX11Fonts" "Installs previously-converted .sf2 fonts into the TextConstants dictionary. This makes them available as TextStyles everywhere in the image." | families fontArray textStyle | families _ #( 'Courier' 'Helvetica' 'LucidaBright' 'Lucida' 'LucidaTypewriter' 'NewCenturySchoolbook' 'TimesRoman' ). families do: [:family | fontArray _ StrikeFont readStrikeFont2Family: family. textStyle _ TextStyle fontArray: fontArray. TextConstants at: family asSymbol put: textStyle. ]. ! ! !BDFFontReader class methodsFor: 'documentation' stamp: 'nop 2/11/2001 00:22'! gettingAndInstallingTheFonts "Download the 1.3M of BDF font source files from x.org: BDFFontReader downloadFonts. Convert them to .sf2 StrikeFont files: BDFFontReader convertX11FontsToStrike2. Install them into the system as TextStyles: BDFFontReader installX11Fonts. Read the legal notices in 'BDFFontReader x11FontLegalNotices' before redistributing images containing these fonts."! ! !BDFFontReader class methodsFor: 'documentation' stamp: 'nop 1/23/2000 18:30'! x11FontLegalNotices ^ 'The X11 BDF fonts contain copyright and license information as comments in the font source code. For the font family files "cour" (Courier), "helv" (Helvetica), "ncen" (New Century Schoolbook), and "tim" (Times Roman) the notice reads: COMMENT Copyright 1984-1989, 1994 Adobe Systems Incorporated. COMMENT Copyright 1988, 1994 Digital Equipment Corporation. COMMENT COMMENT Adobe is a trademark of Adobe Systems Incorporated which may be COMMENT registered in certain jurisdictions. COMMENT Permission to use these trademarks is hereby granted only in COMMENT association with the images described in this file. COMMENT COMMENT Permission to use, copy, modify, distribute and sell this software COMMENT and its documentation for any purpose and without fee is hereby COMMENT granted, provided that the above copyright notices appear in all COMMENT copies and that both those copyright notices and this permission COMMENT notice appear in supporting documentation, and that the names of COMMENT Adobe Systems and Digital Equipment Corporation not be used in COMMENT advertising or publicity pertaining to distribution of the software COMMENT without specific, written prior permission. Adobe Systems and COMMENT Digital Equipment Corporation make no representations about the COMMENT suitability of this software for any purpose. It is provided "as COMMENT is" without express or implied warranty. For the font family files "char" (Charter), the notice reads: COMMENT Copyright 1988 Bitstream, Inc., Cambridge, Massachusetts, USA COMMENT Bitstream and Charter are registered trademarks of Bitstream, Inc. COMMENT COMMENT The names "Bitstream" and "Charter" are registered trademarks of COMMENT Bitstream, Inc. Permission to use these trademarks is hereby COMMENT granted only in association with the images described in this file. COMMENT COMMENT Permission to use, copy, modify, and distribute this software and COMMENT its documentation for any purpose and without fee is hereby COMMENT granted, provided that the above copyright notice appear in all COMMENT copies and that both that copyright notice and this permission COMMENT notice appear in supporting documentation, and that the name of COMMENT Bitstream not be used in advertising or publicity pertaining to COMMENT distribution of the software without specific, written prior COMMENT permission. Bitstream makes no representations about the COMMENT suitability of this software for any purpose. It is provided "as COMMENT is" without express or implied warranty. COMMENT COMMENT BITSTREAM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, COMMENT INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN COMMENT NO EVENT SHALL BITSTREAM BE LIABLE FOR ANY SPECIAL, INDIRECT OR COMMENT CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS COMMENT OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, COMMENT NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN COMMENT CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. For the font family files "lu" (Lucida), "lub" (Lucida Bright), and "lut" (Lucida Typewriter), the notice reads: COMMENT (c) Copyright Bigelow & Holmes 1986, 1985. Lucida is a registered COMMENT trademark of Bigelow & Holmes. See LEGAL NOTICE file for terms COMMENT of the license. The LEGAL NOTICE contains: This is the LEGAL NOTICE pertaining to the Lucida fonts from Bigelow & Holmes: NOTICE TO USER: The source code, including the glyphs or icons forming a par of the OPEN LOOK TM Graphic User Interface, on this tape and in these files is copyrighted under U.S. and international laws. Sun Microsystems, Inc. of Mountain View, California owns the copyright and has design patents pending on many of the icons. AT&T is the owner of the OPEN LOOK trademark associated with the materials on this tape. Users and possessors of this source code are hereby granted a nonexclusive, royalty-free copyright and design patent license to use this code in individual and commercial software. A royalty-free, nonexclusive trademark license to refer to the code and output as "OPEN LOOK" compatible is available from AT&T if, and only if, the appearance of the icons or glyphs is not changed in any manner except as absolutely necessary to accommodate the standard resolution of the screen or other output device, the code and output is not changed except as authorized herein, and the code and output is validated by AT&T. Bigelow & Holmes is the owner of the Lucida (R) trademark for the fonts and bit-mapped images associated with the materials on this tape. Users are granted a royalty-free, nonexclusive license to use the trademark only to identify the fonts and bit-mapped images if, and only if, the fonts and bit-mapped images are not modified in any way by the user. Any use of this source code must include, in the user documentation and internal comments to the code, notices to the end user as follows: (c) Copyright 1989 Sun Microsystems, Inc. Sun design patents pending in the U.S. and foreign countries. OPEN LOOK is a trademark of AT&T. Used by written permission of the owners. (c) Copyright Bigelow & Holmes 1986, 1985. Lucida is a registered trademark of Bigelow & Holmes. Permission to use the Lucida trademark is hereby granted only in association with the images and fonts described in this file. SUN MICROSYSTEMS, INC., AT&T, AND BIGELOW & HOLMES MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. SUN MICROSYSTEMS, INC., AT&T AND BIGELOW & HOLMES, SEVERALLY AND INDIVIDUALLY, DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN MICROSYSTEMS, INC., AT&T OR BIGELOW & HOLMES BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. '. ! ! !Base64MimeConverter methodsFor: 'conversion' stamp: 'ls 2/10/2001 13:26'! mimeEncode "Convert from data to 6 bit characters." | phase1 phase2 raw nib lineLength | phase1 _ phase2 _ false. lineLength := 0. [dataStream atEnd] whileFalse: [ lineLength >= 70 ifTrue: [ mimeStream cr. lineLength := 0. ]. data _ raw _ dataStream next asInteger. nib _ (data bitAnd: 16rFC) bitShift: -2. mimeStream nextPut: (ToCharTable at: nib+1). (raw _ dataStream next) ifNil: [raw _ 0. phase1 _ true]. data _ ((data bitAnd: 3) bitShift: 8) + raw asInteger. nib _ (data bitAnd: 16r3F0) bitShift: -4. mimeStream nextPut: (ToCharTable at: nib+1). (raw _ dataStream next) ifNil: [raw _ 0. phase2 _ true]. data _ ((data bitAnd: 16rF) bitShift: 8) + (raw asInteger). nib _ (data bitAnd: 16rFC0) bitShift: -6. mimeStream nextPut: (ToCharTable at: nib+1). nib _ (data bitAnd: 16r3F). mimeStream nextPut: (ToCharTable at: nib+1). lineLength := lineLength + 4.]. phase1 ifTrue: [mimeStream skip: -2; nextPut: $=; nextPut: $=. ^ mimeStream]. phase2 ifTrue: [mimeStream skip: -1; nextPut: $=. ^ mimeStream]. ! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'hg 2/2/2001 15:23'! partitionedMul: word1 with: word2 nBits: nBits nPartitions: nParts "Multiply word1 with word2 as nParts partitions of nBits each. This is useful for packed pixels, or packed colors. Bug in loop version when non-white background" | sMask product result dMask | sMask _ maskTable at: nBits. "partition mask starts at the right" dMask _ sMask << nBits. result _ (((word1 bitAnd: sMask)+1) * ((word2 bitAnd: sMask)+1) - 1 bitAnd: dMask) >> nBits. "optimized first step" product _ (((word1>>nBits bitAnd: sMask)+1) * ((word2>>nBits bitAnd: sMask)+1) - 1 bitAnd: dMask). result _ result bitOr: (product bitAnd: dMask). product _ (((word1>>(2*nBits) bitAnd: sMask)+1) * ((word2>>(2*nBits) bitAnd: sMask)+1) - 1 bitAnd: dMask). result _ result bitOr: (product bitAnd: dMask) << nBits. ^ result " | sMask product result dMask | sMask _ maskTable at: nBits. 'partition mask starts at the right' dMask _ sMask << nBits. result _ (((word1 bitAnd: sMask)+1) * ((word2 bitAnd: sMask)+1) - 1 bitAnd: dMask) >> nBits. 'optimized first step' nBits to: nBits * (nParts-1) by: nBits do: [:ofs | product _ (((word1>>ofs bitAnd: sMask)+1) * ((word2>>ofs bitAnd: sMask)+1) - 1 bitAnd: dMask). result _ result bitOr: (product bitAnd: dMask) << (ofs-nBits)]. ^ result"! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'hg 8/24/2000 14:41'! rgbMul: sourceWord with: destinationWord self inline: false. destPixSize < 16 ifTrue: ["Mul each pixel separately" ^ self partitionedMul: sourceWord with: destinationWord nBits: destPixSize nPartitions: pixPerWord]. destPixSize = 16 ifTrue: ["Mul RGB components of each pixel separately" ^ (self partitionedMul: sourceWord with: destinationWord nBits: 5 nPartitions: 3) + ((self partitionedMul: sourceWord>>16 with: destinationWord>>16 nBits: 5 nPartitions: 3) << 16)] ifFalse: ["Mul RGB components of the pixel separately" ^ self partitionedMul: sourceWord with: destinationWord nBits: 8 nPartitions: 3] " | scanner | Display repaintMorphicDisplay. scanner _ DisplayScanner quickPrintOn: Display. MessageTally time: [0 to: 760 by: 4 do: [:y |scanner drawString: 'qwrepoiuasfd=)(/&()=#!!¡lkjzxv.,mn124+09857907QROIYTOAFDJZXNBNB,M-.,Mqwrepoiuasfd=)(/&()=#!!¡lkjzxv.,mn124+09857907QROIYTOAFDJZXNBNB,M-.,M1234124356785678' at: 0@y]]. "! ! !BitBltSimulation methodsFor: 'translation support' stamp: 'hg 1/29/2001 17:03'! initBBOpTable self cCode: 'opTable[0+1] = (int)clearWordwith'. self cCode: 'opTable[1+1] = (int)bitAndwith'. self cCode: 'opTable[2+1] = (int)bitAndInvertwith'. self cCode: 'opTable[3+1] = (int)sourceWordwith'. self cCode: 'opTable[4+1] = (int)bitInvertAndwith'. self cCode: 'opTable[5+1] = (int)destinationWordwith'. self cCode: 'opTable[6+1] = (int)bitXorwith'. self cCode: 'opTable[7+1] = (int)bitOrwith'. self cCode: 'opTable[8+1] = (int)bitInvertAndInvertwith'. self cCode: 'opTable[9+1] = (int)bitInvertXorwith'. self cCode: 'opTable[10+1] = (int)bitInvertDestinationwith'. self cCode: 'opTable[11+1] = (int)bitOrInvertwith'. self cCode: 'opTable[12+1] = (int)bitInvertSourcewith'. self cCode: 'opTable[13+1] = (int)bitInvertOrwith'. self cCode: 'opTable[14+1] = (int)bitInvertOrInvertwith'. self cCode: 'opTable[15+1] = (int)destinationWordwith'. self cCode: 'opTable[16+1] = (int)destinationWordwith'. self cCode: 'opTable[17+1] = (int)destinationWordwith'. self cCode: 'opTable[18+1] = (int)addWordwith'. self cCode: 'opTable[19+1] = (int)subWordwith'. self cCode: 'opTable[20+1] = (int)rgbAddwith'. self cCode: 'opTable[21+1] = (int)rgbSubwith'. self cCode: 'opTable[22+1] = (int)OLDrgbDiffwith'. self cCode: 'opTable[23+1] = (int)OLDtallyIntoMapwith'. self cCode: 'opTable[24+1] = (int)alphaBlendwith'. self cCode: 'opTable[25+1] = (int)pixPaintwith'. self cCode: 'opTable[26+1] = (int)pixMaskwith'. self cCode: 'opTable[27+1] = (int)rgbMaxwith'. self cCode: 'opTable[28+1] = (int)rgbMinwith'. self cCode: 'opTable[29+1] = (int)rgbMinInvertwith'. self cCode: 'opTable[30+1] = (int)alphaBlendConstwith'. self cCode: 'opTable[31+1] = (int)alphaPaintConstwith'. self cCode: 'opTable[32+1] = (int)rgbDiffwith'. self cCode: 'opTable[33+1] = (int)tallyIntoMapwith'. self cCode: 'opTable[34+1] = (int)alphaBlendScaledwith'. self cCode: 'opTable[35+1] = (int)alphaBlendScaledwith'. self cCode: 'opTable[36+1] = (int)alphaBlendScaledwith'. self cCode: 'opTable[37+1] = (int)rgbMulwith'.! ! !BitBltSimulation methodsFor: 'primitives' stamp: 'yo 2/14/2001 12:43'! primitiveDisplayString | kernDelta xTable glyphMap stopIndex startIndex sourceString bbObj maxGlyph ascii glyphIndex sourcePtr left | self export: true. self var: #sourcePtr type: 'unsigned char *'. interpreterProxy methodArgumentCount = 6 ifFalse:[^interpreterProxy primitiveFail]. kernDelta _ interpreterProxy stackIntegerValue: 0. xTable _ interpreterProxy stackObjectValue: 1. glyphMap _ interpreterProxy stackObjectValue: 2. ((interpreterProxy fetchClassOf: xTable) = interpreterProxy classArray and:[ (interpreterProxy fetchClassOf: glyphMap) = interpreterProxy classArray]) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: glyphMap) = 256 ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy failed ifTrue:[^nil]. maxGlyph _ (interpreterProxy slotSizeOf: xTable) - 2. stopIndex _ interpreterProxy stackIntegerValue: 3. startIndex _ interpreterProxy stackIntegerValue: 4. sourceString _ interpreterProxy stackObjectValue: 5. (interpreterProxy isBytes: sourceString) ifFalse:[^interpreterProxy primitiveFail]. (startIndex > 0 and:[stopIndex > 0 and:[ stopIndex <= (interpreterProxy byteSizeOf: sourceString)]]) ifFalse:[^interpreterProxy primitiveFail]. bbObj _ interpreterProxy stackObjectValue: 6. (self loadBitBltFrom: bbObj) ifFalse:[^interpreterProxy primitiveFail]. left _ destX. sourcePtr _ interpreterProxy firstIndexableField: sourceString. startIndex to: stopIndex do:[:charIndex| ascii _ interpreterProxy byteAt: sourcePtr + charIndex - 1. glyphIndex _ interpreterProxy fetchInteger: ascii ofObject: glyphMap. (glyphIndex < 0 or:[glyphIndex > maxGlyph]) ifTrue:[^interpreterProxy primitiveFail]. sourceX _ interpreterProxy fetchInteger: glyphIndex ofObject: xTable. width _ (interpreterProxy fetchInteger: glyphIndex+1 ofObject: xTable) - sourceX. interpreterProxy failed ifTrue:[^nil]. self clipRange. "Must clip here" (bbW > 0 and:[bbH > 0]) ifTrue: [self copyBits]. interpreterProxy failed ifTrue:[^nil]. destX _ destX + width + kernDelta. ]. affectedL _ left. self showDisplayBits. interpreterProxy pop: 6. "pop args, return rcvr"! ! !BitBltSimulation class methodsFor: 'initialization' stamp: 'hg 1/29/2001 17:02'! initializeRuleTable "BitBltSimulation initializeRuleTable" "**WARNING** You MUST change initBBOpTable if you change this" OpTable _ #( "0" clearWord:with: "1" bitAnd:with: "2" bitAndInvert:with: "3" sourceWord:with: "4" bitInvertAnd:with: "5" destinationWord:with: "6" bitXor:with: "7" bitOr:with: "8" bitInvertAndInvert:with: "9" bitInvertXor:with: "10" bitInvertDestination:with: "11" bitOrInvert:with: "12" bitInvertSource:with: "13" bitInvertOr:with: "14" bitInvertOrInvert:with: "15" destinationWord:with: "16" destinationWord:with: "unused - was old paint" "17" destinationWord:with: "unused - was old mask" "18" addWord:with: "19" subWord:with: "20" rgbAdd:with: "21" rgbSub:with: "22" OLDrgbDiff:with: "23" OLDtallyIntoMap:with: "24" alphaBlend:with: "25" pixPaint:with: "26" pixMask:with: "27" rgbMax:with: "28" rgbMin:with: "29" rgbMinInvert:with: "30" alphaBlendConst:with: "31" alphaPaintConst:with: "32" rgbDiff:with: "33" tallyIntoMap:with: "34" alphaBlendScaled:with: "35" alphaBlendScaled:with: "unused here - only used by FXBlt" "36" alphaBlendScaled:with: "unused here - only used by FXBlt" "37" rgbMul:with: ). OpTableSize _ OpTable size + 1. "0-origin indexing" ! ! !BitBltSimulation class methodsFor: 'translation' stamp: 'hg 2/2/2001 14:36'! declareCVarsIn: aCCodeGenerator aCCodeGenerator var: 'opTable' declareC: 'int opTable[' , OpTableSize printString , ']'. aCCodeGenerator var: 'maskTable' declareC:'int maskTable[33] = { 0, 1, 3, 0, 15, 31, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 65535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 }'. aCCodeGenerator var: 'ditherMatrix4x4' declareC:'const int ditherMatrix4x4[16] = { 0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5 }'. aCCodeGenerator var: 'ditherThresholds16' declareC:'const int ditherThresholds16[8] = { 0, 2, 4, 6, 8, 12, 14, 16 }'. aCCodeGenerator var: 'ditherValues16' declareC:'const int ditherValues16[32] = { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }'. aCCodeGenerator var: 'warpBitShiftTable' declareC:'int warpBitShiftTable[32]'.! ! !BitBltSimulator methodsFor: 'as yet unclassified' stamp: 'hg 2/2/2001 14:15'! initBBOpTable opTable _ OpTable. maskTable _ Array new: 32. #(1 2 4 5 8 16 32) do:[:i| maskTable at: i put: (1 << i)-1]. self initializeDitherTables. warpBitShiftTable _ CArrayAccessor on: (Array new: 32).! ! !BlockNode methodsFor: 'tiles' stamp: 'RAA 2/16/2001 09:08'! asMorphicSyntaxIn: parent ^parent blockNode: self arguments: arguments statements: statements! ! !Browser methodsFor: 'class list' stamp: 'nk 2/13/2001 13:26'! classListIndex: anInteger "Set anInteger to be the index of the current class selection." | className | classListIndex _ anInteger. self setClassOrganizer. messageCategoryListIndex _ 1. messageListIndex _ 0. self classCommentIndicated ifTrue: [] ifFalse: [editSelection _ anInteger = 0 ifTrue: [metaClassIndicated | (systemCategoryListIndex == 0) ifTrue: [#none] ifFalse: [#newClass]] ifFalse: [#editClass]]. contents _ nil. self selectedClass isNil ifFalse: [className _ self selectedClass name. (RecentClasses includes: className) ifTrue: [RecentClasses remove: className]. RecentClasses addFirst: className. RecentClasses size > 16 ifTrue: [RecentClasses removeLast]]. self changed: #classSelectionChanged. self changed: #classListIndex. "update my selection" self changed: #messageCategoryList. self changed: #messageList. self changed: #relabel. self contentsChanged! ! !Browser methodsFor: 'initialize-release' stamp: 'RAA 2/9/2001 16:36'! buildMorphicClassList | myClassList | (myClassList _ PluggableListMorph new) setProperty: #highlightSelector toValue: #highlightClassList:with:; on: self list: #classList selected: #classListIndex changeSelected: #classListIndex: menu: #classListMenu:shifted: keystroke: #classListKey:from:. myClassList borderWidth: 0. myClassList enableDragNDrop: Preferences browseWithDragNDrop. ^myClassList ! ! !Browser methodsFor: 'initialize-release' stamp: 'RAA 2/9/2001 16:37'! buildMorphicMessageCatList | myMessageCatList | (myMessageCatList _ PluggableMessageCategoryListMorph new) setProperty: #highlightSelector toValue: #highlightMessageCategoryList:with:; on: self list: #messageCategoryList selected: #messageCategoryListIndex changeSelected: #messageCategoryListIndex: menu: #messageCategoryMenu: keystroke: #arrowKey:from: getRawListSelector: #rawMessageCategoryList. myMessageCatList enableDragNDrop: Preferences browseWithDragNDrop. ^myMessageCatList ! ! !Browser methodsFor: 'initialize-release' stamp: 'RAA 2/9/2001 16:35'! buildMorphicMessageList | aListMorph | (aListMorph _ PluggableListMorph new) setProperty: #highlightSelector toValue: #highlightMessageList:with:; on: self list: #messageList selected: #messageListIndex changeSelected: #messageListIndex: menu: #messageListMenu:shifted: keystroke: #messageListKey:from:. aListMorph enableDragNDrop: Preferences browseWithDragNDrop. aListMorph menuTitleSelector: #messageListSelectorTitle. ^aListMorph ! ! !Browser methodsFor: 'initialize-release' stamp: 'RAA 2/9/2001 16:34'! buildMorphicSystemCatList | dragNDropFlag myCatList | dragNDropFlag _ Preferences browseWithDragNDrop. (myCatList _ PluggableListMorph new) setProperty: #highlightSelector toValue: #highlightSystemCategoryList:with:; on: self list: #systemCategoryList selected: #systemCategoryListIndex changeSelected: #systemCategoryListIndex: menu: #systemCategoryMenu: keystroke: #systemCatListKey:from:. myCatList enableDragNDrop: dragNDropFlag. ^myCatList ! ! !Browser methodsFor: 'initialize-release' stamp: 'nk 2/13/2001 13:25'! labelString ^self selectedClass ifNil: [ self defaultBrowserTitle ] ifNotNil: [ self defaultBrowserTitle, ': ', self selectedClass printString ]. ! ! !Browser methodsFor: 'initialize-release' stamp: 'sw 2/6/2001 03:34'! optionalButtonPairs "Answer a tuple (formerly pairs) defining buttons, in the format: button label selector to send help message" ^ #( ('senders' browseSendersOfMessages 'browse senders of...') ('implementors' browseMessages 'browse implementors of...') ('versions' browseVersions 'browse versions')), (Preferences decorateBrowserButtons ifTrue: [{#('inheritance' methodHierarchy 'browse method inheritance green: sends to super tan: has override(s) mauve: both of the above' )}] ifFalse: [{#('inheritance' methodHierarchy 'browse method inheritance')}]), #( ('hierarchy' classHierarchy 'browse class hierarchy') ('inst vars' browseInstVarRefs 'inst var refs...') ('class vars' browseClassVarRefs 'class var refs...'))! ! !Browser methodsFor: 'message list' stamp: 'di 2/5/2001 22:04'! validateMessageSource: selector | sourcesName | (self selectedClass compilerClass == Object compilerClass and: [(contents asString findString: selector keywords first ) ~= 1]) ifTrue: [sourcesName _ FileDirectory localNameFor: Smalltalk sourcesName. PopUpMenu notify: 'There may be a problem with your sources file!! The source code for every method should start with the method selector but this is not the case!! You may proceed with caution but it is recommended that you get a new source file. This can happen if you download the "' , sourcesName , '" file, or the ".changes" file you use, as TEXT. It must be transfered in BINARY mode, even if it looks like a text file, to preserve the CR line ends. Mac users: This may have been caused by Stuffit Expander. To prevent the files above to be converted to Mac line ends when they are expanded, do this: Start the program, then from Preferences... in the File menu, choose the Cross Platform panel, then select "Never" and press OK. Then expand the compressed archive again.'].! ! !Browser class methodsFor: 'instance creation' stamp: 'nk 2/13/2001 13:47'! fullOnClass: aClass selector: aSelector "Open a new full browser set to class." | brow classToUse | classToUse _ Preferences browseToolClass. brow _ classToUse new. brow setClass: aClass selector: aSelector. classToUse openBrowserView: (brow openEditString: nil) label: brow labelString! ! !CArrayAccessor methodsFor: 'comparing' stamp: 'yo 2/9/2001 11:23'! < other ^ (object == other object) and: [offset < other offset].! ! !CArrayAccessor methodsFor: 'comparing' stamp: 'yo 2/9/2001 11:24'! <= other ^ (object == other object) and: [offset <= other offset].! ! !CArrayAccessor methodsFor: 'comparing' stamp: 'yo 2/9/2001 11:24'! > other ^ (object == other object) and: [offset > other offset].! ! !CArrayAccessor methodsFor: 'comparing' stamp: 'yo 2/9/2001 11:24'! >= other ^ (object == other object) and: [offset >= other offset].! ! !CObjectAccessor methodsFor: 'accessing' stamp: 'yo 2/9/2001 11:23'! object ^ object! ! !CObjectAccessor methodsFor: 'accessing' stamp: 'yo 2/9/2001 11:23'! offset ^ offset ! ! !Celeste methodsFor: 'categories pane' stamp: 'ls 2/10/2001 10:25'! cacheTOC "Caches a version of the TOC" | tocStringColumns | self initializeTocLists. 'Processing ' , currentMessages size printString , ' messages.' displayProgressAt: Sensor cursorPoint from: 0 to: currentMessages size during: [:bar | 1 to: currentMessages size do: [:i | bar value: i. (self tocLists at: 1) add: i printString. "columns from the database are 5" tocStringColumns _ mailDB getTOCstringAsColumns: (currentMessages at: i). (self tocLists at: 2) add: ((tocStringColumns at: 5) ifTrue: ['@'] ifFalse: [' ']). (self tocLists at: 3) add: (tocStringColumns at: 1). (self tocLists at: 4) add: (tocStringColumns at: 2). (self tocLists at: 5) add: (tocStringColumns at: 4). (self tocLists at: 6) add: (tocStringColumns at: 3)]]. (currentMessages includes: currentMsgID) ifFalse: [currentMsgID _ nil]! ! !Celeste methodsFor: 'categories pane' stamp: 'ls 2/10/2001 10:32'! setCategory: newCategory "Change the currently selected category. We must also compute the table of contents and message list for the new category." | messageCount | currentCategory _ newCategory. newCategory isNil ifTrue: [currentMessages _ currentMsgID _ nil. self class includeStatusPane ifTrue: [status _ nil]] ifFalse: [currentMessages _ self filteredMessagesIn: newCategory. messageCount _ currentMessages size. messageCount > self maxMessagesToDisplay ifTrue: [self messages: self maxMessagesToDisplay from: messageCount. currentMessages _ currentMessages copyLast: self maxMessagesToDisplay] ifFalse: [self messages: messageCount from: messageCount]. self cacheTOC]. self changed: #category. self changed: #tocEntryList. self changed: #tocEntry. self changed: #messageText. self changed: #status! ! !Celeste methodsFor: 'table of contents pane' stamp: 'ls 2/10/2001 14:24'! autoFile "automatically pick a folder for the current message, and file the current message there" | folder | folder := self chooseFilterForCurrentMessage. folder ifNil: [ ^self]. lastCategory := folder. mailDB file: currentMsgID inCategory: folder.! ! !Celeste methodsFor: 'table of contents pane' stamp: 'ls 2/10/2001 14:24'! autoMove "automatically pick a folder for the current message, and move the message there" | folder | folder := self chooseFilterForCurrentMessage. folder ifNil: [ ^self]. lastCategory := folder. mailDB file: currentMsgID inCategory: folder. self removeMessage.! ! !Celeste methodsFor: 'table of contents pane' stamp: 'ls 2/10/2001 10:31'! nextMessage "Select the next message." | index | (currentCategory isNil | currentMsgID isNil) ifTrue: [^ self]. index _ currentMessages indexOf: currentMsgID. index < currentMessages size ifTrue: [self setTOCEntry: ((self tocLists at: 1) at: index + 1)] ifFalse: [self setTOCEntry: ((self tocLists at: 1) at: 1)]. ! ! !Celeste methodsFor: 'table of contents pane' stamp: 'ls 2/10/2001 10:31'! previousMessage "Select the previous message." | index | (currentCategory isNil | currentMsgID isNil) ifTrue: [^ self]. index _ currentMessages indexOf: currentMsgID. index > 1 ifTrue: [self setTOCEntry: ((self tocLists at: 1) at: index - 1)] ifFalse: [self setTOCEntry: ((self tocLists at: 1) at: currentMessages size)]. ! ! !Celeste methodsFor: 'table of contents pane' stamp: 'ls 2/10/2001 10:23'! removeAll "Remove all messages from the current category." mailDB removeAll: currentMessages fromCategory: currentCategory. currentMsgID _ nil. currentMessages _ #(). self initializeTocLists. self changed: #tocEntryList. self changed: #tocEntry. self changed: #messageText ! ! !Celeste methodsFor: 'table of contents pane' stamp: 'ls 2/10/2001 11:21'! removeMessage "Remove the current message from the current category." | currentMessageIndex | currentMsgID ifNil: [^ self]. mailDB remove: currentMsgID fromCategory: currentCategory. "remove the message from the listing" currentMessageIndex _ currentMessages indexOf: currentMsgID. currentMessages _ currentMessages copyWithout: currentMsgID. 2 to: self tocLists size do: [:index | (tocLists at: index) removeAt: currentMessageIndex]. tocLists first removeLast. "update the message index and message ID" currentMessages isEmpty ifTrue: [currentMsgID _ nil] ifFalse: [currentMsgID _ currentMessages at: (currentMessageIndex min: currentMessages size)]. self changed: #tocEntryList. self changed: #tocEntry. self changed: #messageText! ! !Celeste methodsFor: 'table of contents pane' stamp: 'ls 2/10/2001 10:26'! setTOCEntry: newTOCentry "Change the currently selected message. This is done by finding the message ID corresponding to the selected table of contents entry." | i | newTOCentry isNil ifTrue: [currentMsgID _ nil] ifFalse: [i _ (self tocLists at: 1) indexOf: newTOCentry ifAbsent: []. i isNil ifTrue: [currentMsgID _ nil] ifFalse: [currentMsgID _ currentMessages at: i]]. self changed: #tocEntry. Cursor read showWhile: [self changed: #messageText]! ! !Celeste methodsFor: 'filtering' stamp: 'ls 2/10/2001 14:26'! chooseFilterForCurrentMessage "automatically choose a filter to move the selected message. Returns nil if there isn't a message selected, or if there isn't exactly 1 matching filter" | matchingFilters | currentMsgID ifNil: [ ^nil ]. matchingFilters := self filtersFor: currentMsgID from: self filterNames. matchingFilters size = 1 ifTrue: [ ^matchingFilters anyOne ] ifFalse: [ ^nil ]! ! !Celeste methodsFor: 'filtering' stamp: 'ls 2/10/2001 10:16'! customFilterNamed: filterName ^CustomFiltersCompiled at: filterName! ! !Celeste methodsFor: 'filtering' stamp: 'ls 2/10/2001 14:22'! customFilterOn "Select or define and activate a custom filter." | filterName filterMenu | filterMenu := CustomMenu new. currentMsgID ifNotNil: [ (self filtersFor: currentMsgID from: self filterNames) do: [ :name | filterMenu add: name action: name ]. filterMenu addLine.]. filterMenu add: '(none)' action: #none. filterMenu add: '' action: #define. filterMenu add: '' action: #edit. filterMenu add: '' action: #delete. filterMenu addLine. self filterNames do: [ :name | filterMenu add: name action: name ]. filterName _ filterMenu startUpWithCaption: 'Select a filter:'. filterName ifNil: [ ^self ]. filterName = #none ifTrue: [^self customFilterOff ]. filterName = #delete ifTrue: [ ^self deleteFilter]. filterName = #edit ifTrue: [filterName _ self editFilter] ifFalse: [ filterName = #define ifTrue: [filterName _ self defineFilter] ]. filterName ifNil: [ ^self ]. filterName isEmpty ifTrue: [^self]. customFilterBlock _ CustomFiltersCompiled at: filterName. self updateTOC. self changed: #isCustomFilterOn.! ! !Celeste methodsFor: 'filtering' stamp: 'ls 2/10/2001 14:22'! deleteFilter | filterName | CustomFilters isEmpty ifTrue: [^'']. filterName _ (CustomMenu selections: self filterNames) startUpWithCaption: 'Filter to delete?'. filterName = nil ifTrue: [^'']. CustomFilters removeKey: filterName ifAbsent: []. CustomFiltersCompiled removeKey: filterName ifAbsent: [].! ! !Celeste methodsFor: 'filtering' stamp: 'ls 2/10/2001 14:22'! editFilter | filterName | CustomFilters isEmpty ifTrue: [^'']. filterName _ (CustomMenu selections: self filterNames) startUpWithCaption: 'Filter to edit?'. filterName = nil ifTrue: [^'']. ^self editFilterNamed: filterName filterExpr: (CustomFilters at: filterName)! ! !Celeste methodsFor: 'filtering' stamp: 'ls 2/10/2001 14:21'! editFilterNamed: filterName filterExpr: oldExpr | newDefinition | newDefinition _ FillInTheBlank request: 'Enter a filter definition where "m" is the message being testing. The expression can send "fromHas:", "toHas:", "ccHas:", "subjectHas:", "participantHas:", or "textHas:" to m to test for inclusion of a string--or one of an array of strings--in a field. It can also test m''s time and/or date and can combine several tests with logical operators. Examples: m fromHas: ''johnm'' -- messages from johnm m participantHas: ''johnm'' -- messages from, to, or cc-ing johnm m textHas: #(squeak smalltalk java) -- messages with any of these words m subjectHas: #(0 1 2 3 4 5 6 7 8 9) -- numbers in lists treated as strings NOTE: "textHas:" is very slow, since it must read the message from disk.' initialAnswer: oldExpr. newDefinition isEmpty ifTrue: [^'']. CustomFilters at: filterName put: newDefinition. CustomFiltersCompiled at: filterName put: (self class makeFilterFor: newDefinition). ^filterName! ! !Celeste methodsFor: 'filtering' stamp: 'ls 2/10/2001 14:18'! filterNames "return a sorted list of custom filter names" ^CustomFilters keys asSortedArray! ! !Celeste class methodsFor: 'filters' stamp: 'ls 2/10/2001 10:16'! compileAllCustomFilters "recompile all custom filters" CustomFiltersCompiled := Dictionary new. CustomFilters keysAndValuesDo: [ :filterName :filter | CustomFiltersCompiled at: filterName put: (self makeFilterFor: filter) ].! ! !Celeste class methodsFor: 'filters' stamp: 'ls 2/10/2001 10:15'! makeFilterFor: filterExpr "compile a given custom filter" ^Compiler evaluate: '[ :m | ', filterExpr, ']'. ! ! !CelesteComposition methodsFor: 'private' stamp: 'ls 2/10/2001 13:57'! breakLines: aString atWidth: width "break lines in the given string into shorter lines" | result start end atAttachment | result _ WriteStream on: (String new: (aString size * 50 // 49)). atAttachment _ false. aString asString linesDo: [ :line | (line beginsWith: '====') ifTrue: [ atAttachment _ true ]. atAttachment ifTrue: [ "at or after an attachment line; no more wrapping for the rest of the message" result nextPutAll: line. result cr ] ifFalse: [ (line beginsWith: '>') ifTrue: [ "it's quoted text; don't wrap it" result nextPutAll: line. result cr. ] ifFalse: [ "regular old line. Wrap it to multiple lines" start _ 1. "output one shorter line each time through this loop" [ start + width <= line size ] whileTrue: [ "find the end of the line" end _ start + width - 1. [end >= start and: [ (line at: (end+1)) isSeparator not ]] whileTrue: [ end _ end - 1 ]. end < start ifTrue: [ "a word spans the entire width!!" end _ start + width - 1 ]. "copy the line to the output" result nextPutAll: (line copyFrom: start to: end). result cr. "get ready for next iteration" start _ end+1. (line at: start) isSeparator ifTrue: [ start _ start + 1 ]. ]. "write out the final part of the line" result nextPutAll: (line copyFrom: start to: line size). result cr. ]. ]. ]. ^result contents! ! !CelesteComposition methodsFor: 'private' stamp: 'ls 2/10/2001 14:08'! breakLinesInMessage: message "reformat long lines in the specified message into shorter ones" message body mainType = 'text' ifTrue: [ "it's a single-part text message. reformat the text" | newBodyText | newBodyText := self breakLines: message bodyText atWidth: 72. message body: (MIMEDocument contentType: message body contentType content: newBodyText). ^self ]. message body isMultipart ifTrue: [ "multipart message; process the top-level parts. HACK: the parts are modified in place" message parts do: [ :part | part body mainType = 'text' ifTrue: [ | newBodyText | newBodyText := self breakLines: part bodyText atWidth: 72. part body: (MIMEDocument contentType: part body contentType content: newBodyText) ] ]. message regenerateBodyFromParts. ].! ! !CelesteComposition methodsFor: 'access' stamp: 'ls 2/10/2001 14:07'! submit | message | "submit the message" textEditor ifNotNil: [self hasUnacceptedEdits ifTrue: [textEditor accept]]. message := MailMessage from: messageText asString. self breakLinesInMessage: message. celeste queueMessageWithText: message text. morphicWindow ifNotNil: [morphicWindow delete]. mvcWindow ifNotNil: [mvcWindow controller close]! ! !CelesteComposition methodsFor: 'interface' stamp: 'ls 2/10/2001 13:29'! addAttachment | file fileResult fileName | textEditor ifNotNil: [self hasUnacceptedEdits ifTrue: [textEditor accept]]. (fileResult _ StandardFileMenu oldFile) ifNotNil: [fileName _ fileResult directory fullNameFor: fileResult name. file _ FileStream readOnlyFileNamed: fileName. file ifNotNil: [file binary. self messageText: ((MailMessage from: self messageText asString) addAttachmentFrom: file withName: fileResult name; text)]] ! ! !ChangeSet methodsFor: 'fileIn/Out' stamp: 'ls 2/10/2001 16:35'! mailOut "File out the receiver, to a file whose name is a function of the change-set name and either of the date & time or chosen to have a unique numeric tag, depending on the preference 'sequentialChangeSetRevertableFileNames'." | subjectPrefix slips message compressBuffer compressStream data compressedStream compressTarget | (Smalltalk includesKey: #Celeste) ifFalse: [^ self notify: 'no mail reader present']. subjectPrefix _ self chooseSubjectPrefixForEmail. self checkForConversionMethods. Cursor write showWhile: [ "prepare the message" message := MailMessage empty. message setField: 'from' toString: Celeste userName. message setField: 'to' toString: 'squeak@cs.uiuc.edu'. message setField: 'subject' toString: (subjectPrefix, name). message body: (MIMEDocument contentType: 'text/plain' content: (String streamContents: [ :str | str nextPutAll: 'from preamble:'; cr; cr. self fileOutPreambleOn: str ])). "Prepare the gzipped data" data _ data _ WriteStream on: String new. data header. self fileOutPreambleOn: data. self fileOutOn: data. self fileOutPostscriptOn: data. data trailer. data _ ReadStream on: data contents. compressBuffer _ ByteArray new: 1000. compressStream _ GZipWriteStream on: (compressTarget _ WriteStream on: (ByteArray new: 1000)). [data atEnd] whileFalse: [compressStream nextPutAll: (data nextInto: compressBuffer)]. compressStream close. compressedStream _ ReadStream on: compressTarget contents asString. message addAttachmentFrom: compressedStream withName: (name, '.cs.gz'). CelesteComposition openForCeleste: Celeste current initialText: message text. ]. Preferences suppressCheckForSlips ifTrue: [^ self]. slips _ self checkForSlips. (slips size > 0 and: [self confirm: 'Methods in this fileOut have halts or references to the Transcript or other ''slips'' in them. Would you like to browse them?']) ifTrue: [Smalltalk browseMessageList: slips name: 'Possible slips in ' , name]! ! !Character methodsFor: 'object fileIn' stamp: 'tk 2/16/2001 14:52'! objectForDataStream: refStrm "I am being collected for inclusion in a segment. Do not include Characters!! Let them be in outPointers." refStrm insideASegment ifFalse: ["Normal use" ^ self] ifTrue: ["recording objects to go into an ImageSegment" "remove it from references. Do not trace." refStrm references removeKey: self ifAbsent: []. ^ nil] ! ! !CharacterBlockScanner methodsFor: 'stop conditions' stamp: 'hmm 2/2/2001 15:27'! cr "Answer a CharacterBlock that specifies the current location of the mouse relative to a carriage return stop condition that has just been encountered. The ParagraphEditor convention is to denote selections by CharacterBlocks, sometimes including the carriage return (cursor is at the end) and sometimes not (cursor is in the middle of the text)." ((characterIndex ~= nil and: [characterIndex > text size]) or: [(line last = text size) and: [(destY + line lineHeight) < characterPoint y]]) ifTrue: ["When off end of string, give data for next character" destY _ destY + line lineHeight. lastCharacter _ nil. characterPoint _ nextLeftMargin @ destY. lastIndex _ lastIndex + 1. self lastCharacterExtentSetX: 0. ^ true]. lastCharacter _ CR. characterPoint _ destX @ destY. self lastCharacterExtentSetX: rightMargin - destX. ^true! ! !CharacterBlockScanner methodsFor: 'stop conditions' stamp: 'hmm 2/2/2001 14:59'! crossedX "Text display has wrapping. The scanner just found a character past the x location of the cursor. We know that the cursor is pointing at a character or before one." | leadingTab currentX | characterIndex == nil ifFalse: [ "If the last character of the last line is a space, and it crosses the right margin, then locating the character block after it is impossible without this hack." characterIndex > text size ifTrue: [ lastIndex _ characterIndex. characterPoint _ (nextLeftMargin ifNil: [leftMargin]) @ (destY + line lineHeight). ^true]]. characterPoint x <= (destX + (lastCharacterExtent x // 2)) ifTrue: [lastCharacter _ (text at: lastIndex). characterPoint _ destX @ destY. ^true]. lastIndex >= line last ifTrue: [lastCharacter _ (text at: line last). characterPoint _ destX @ destY. ^true]. "Pointing past middle of a character, return the next character." lastIndex _ lastIndex + 1. lastCharacter _ text at: lastIndex. currentX _ destX + lastCharacterExtent x + kern. self lastCharacterExtentSetX: (font widthOf: lastCharacter). characterPoint _ currentX @ destY. lastCharacter = Space ifFalse: [^ true]. "Yukky if next character is space or tab." textStyle alignment = Justified ifTrue: [self lastCharacterExtentSetX: (lastCharacterExtent x + (line justifiedPadFor: (spaceCount + 1))). ^ true]. true ifTrue: [^ true]. "NOTE: I find no value to the following code, and so have defeated it - DI" "See tabForDisplay for illumination on the following awfulness." leadingTab _ true. line first to: lastIndex - 1 do: [:index | (text at: index) ~= Tab ifTrue: [leadingTab _ false]]. (textStyle alignment ~= Justified or: [leadingTab]) ifTrue: [self lastCharacterExtentSetX: (textStyle nextTabXFrom: currentX leftMargin: leftMargin rightMargin: rightMargin) - currentX] ifFalse: [self lastCharacterExtentSetX: (((currentX + (textStyle tabWidth - (line justifiedTabDeltaFor: spaceCount))) - currentX) max: 0)]. ^ true! ! !CharacterBlockScanner methodsFor: 'private' stamp: 'hmm 2/1/2001 16:20'! buildCharacterBlockIn: para | lineIndex runLength lineStop done stopCondition | "handle nullText" (para numberOfLines = 0 or: [text size = 0]) ifTrue: [^ CharacterBlock new stringIndex: 1 "like being off end of string" text: para text topLeft: (para leftMarginForDisplayForLine: 1) @ para compositionRectangle top extent: 0 @ textStyle lineGrid]. "find the line" lineIndex _ para lineIndexOfTop: characterPoint y. destY _ para topAtLineIndex: lineIndex. line _ para lines at: lineIndex. rightMargin _ para rightMarginForDisplay. (lineIndex = para numberOfLines and: [(destY + line lineHeight) < characterPoint y]) ifTrue: ["if beyond lastLine, force search to last character" self characterPointSetX: rightMargin] ifFalse: [characterPoint y < (para compositionRectangle) top ifTrue: ["force search to first line" characterPoint _ (para compositionRectangle) topLeft]. characterPoint x > rightMargin ifTrue: [self characterPointSetX: rightMargin]]. destX _ (leftMargin _ para leftMarginForDisplayForLine: lineIndex). nextLeftMargin_ para leftMarginForDisplayForLine: lineIndex+1. lastIndex _ line first. self setStopConditions. "also sets font" runLength _ (text runLengthFor: line first). characterIndex == nil ifTrue: [lineStop _ line last "characterBlockAtPoint"] ifFalse: [lineStop _ characterIndex "characterBlockForIndex"]. (runStopIndex _ lastIndex + (runLength - 1)) > lineStop ifTrue: [runStopIndex _ lineStop]. lastCharacterExtent _ 0 @ line lineHeight. spaceCount _ 0. done _ false. self handleIndentation. [done] whileFalse: [stopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex in: text string rightX: characterPoint x stopConditions: stopConditions kern: kern. "see setStopConditions for stopping conditions for character block operations." self lastCharacterExtentSetX: (font widthOf: (text at: lastIndex)). (self perform: stopCondition) ifTrue: [characterIndex == nil ifTrue: ["characterBlockAtPoint" ^ CharacterBlock new stringIndex: lastIndex text: text topLeft: characterPoint + (font descentKern @ 0) extent: lastCharacterExtent] ifFalse: ["characterBlockForIndex" ^ CharacterBlock new stringIndex: lastIndex text: text topLeft: characterPoint + ((font descentKern) - kern @ 0) extent: lastCharacterExtent]]]! ! !CharacterBlockScanner methodsFor: 'scanning' stamp: 'hmm 2/2/2001 15:07'! indentationLevel: anInteger super indentationLevel: anInteger. nextLeftMargin _ leftMargin. indentationLevel timesRepeat: [ nextLeftMargin _ textStyle nextTabXFrom: nextLeftMargin leftMargin: leftMargin rightMargin: rightMargin]! ! !CharacterScanner methodsFor: 'scanning' stamp: 'hmm 7/15/2000 22:40'! handleIndentation self indentationLevel timesRepeat: [ self plainTab]! ! !CharacterScanner methodsFor: 'scanning' stamp: 'hmm 7/15/2000 22:41'! plainTab "This is the basic method of adjusting destX for a tab." destX _ (textStyle alignment == Justified and: [self leadingTab not]) ifTrue: "embedded tabs in justified text are weird" [destX + (textStyle tabWidth - (line justifiedTabDeltaFor: spaceCount)) max: destX] ifFalse: [textStyle nextTabXFrom: destX leftMargin: leftMargin rightMargin: rightMargin]! ! !CharacterScanner methodsFor: 'scanning' stamp: 'hmm 7/14/2000 16:07'! scanCharactersFrom: startIndex to: stopIndex in: sourceString rightX: rightX stopConditions: stops kern: kernDelta "Primitive. This is the inner loop of text display--but see scanCharactersFrom: to:rightX: which would get the string, stopConditions and displaying from the instance. March through source String from startIndex to stopIndex. If any character is flagged with a non-nil entry in stops, then return the corresponding value. Determine width of each character from xTable, indexed by map. If dextX would exceed rightX, then return stops at: 258. Advance destX by the width of the character. If stopIndex has been reached, then return stops at: 257. Optional. See Object documentation whatIsAPrimitive." | ascii nextDestX char | lastIndex _ startIndex. [lastIndex <= stopIndex] whileTrue: [char _ (sourceString at: lastIndex). ascii _ char asciiValue + 1. (stops at: ascii) == nil ifFalse: [^stops at: ascii]. "Note: The following is querying the font about the width since the primitive may have failed due to a non-trivial mapping of characters to glyphs or a non-existing xTable." nextDestX _ destX + (font widthOf: char). nextDestX > rightX ifTrue: [^stops at: CrossedX]. destX _ nextDestX + kernDelta. lastIndex _ lastIndex + 1]. lastIndex _ stopIndex. ^stops at: EndOfRun! ! !ChineseCheckers methodsFor: 'drag and drop' stamp: 'ajh 2/15/2001 21:11'! acceptDroppingMorph: aPiece event: evt | dropLoc | dropLoc _ self boardLocAt: evt cursorPoint. dropLoc = aPiece boardLoc ifTrue: "Null move" [^ aPiece rejectDropMorphEvent: evt]. (plannedMove _ (self allMovesFrom: aPiece boardLoc) detect: [:move | move last = dropLoc] ifNone: [nil]) ifNil: [^ aPiece rejectDropMorphEvent: evt. "Not a valid move"]. super acceptDroppingMorph: aPiece event: evt. movePhase _ 1. "Start the animation if any." ! ! !CipherPanel methodsFor: 'initialization' stamp: 'nk 2/16/2001 13:54'! encodedQuote: aString "World addMorph: CipherPanel new" | morph prev | aString isEmpty ifTrue: [ ^self ]. (letterMorphs == nil or: [self isClean]) ifFalse: [(self confirm: 'Are you sure you want to discard all typing?') ifFalse: [^ self]]. haveTypedHere _ false. quote _ aString asUppercase. prev _ nil. originalMorphs _ quote asArray collectWithIndex: [:c :i | WordGameLetterMorph new plain indexInQuote: i id1: nil; setLetter: (quote at: i)]. letterMorphs _ OrderedCollection new. decodingMorphs _ quote asArray collectWithIndex: [:c :i | (quote at: i) isLetter ifTrue: [morph _ WordGameLetterMorph new underlined indexInQuote: i id1: nil. morph on: #mouseDown send: #mouseDownEvent:letterMorph: to: self. morph on: #keyStroke send: #keyStrokeEvent:letterMorph: to: self. letterMorphs addLast: morph. morph predecessor: prev. prev ifNotNil: [prev successor: morph]. prev _ morph] ifFalse: [WordGameLetterMorph new plain indexInQuote: i id1: nil; setLetter: (quote at: i)]]. self color: originalMorphs first color. self extent: 500@500 ! ! !CipherPanel methodsFor: 'initialization' stamp: 'di 2/14/2001 13:50'! extent: newExtent "Lay out with word wrap, alternating bewteen decoded and encoded lines." "Currently not tolerant of narrow (less than a word) margins" | w h relLoc topLeft thisWord i m corner row firstWord | self removeAllMorphs. w _ originalMorphs first width - 1. h _ originalMorphs first height * 2 + 10. topLeft _ self position + self borderWidth + (0@10). thisWord _ OrderedCollection new. i _ 1. firstWord _ true. relLoc _ 0@0. corner _ topLeft. [i <= originalMorphs size] whileTrue: [m _ originalMorphs at: i. thisWord addLast: ((decodingMorphs at: i) position: topLeft + relLoc). thisWord addLast: (m position: topLeft + relLoc + (0@m height)). (m letter = Character space or: [i = originalMorphs size]) ifTrue: [self addAllMorphs: thisWord. corner _ corner max: thisWord last bounds bottomRight. thisWord reset. firstWord _ false]. relLoc _ relLoc + (w@0). (relLoc x + w) > newExtent x ifTrue: [firstWord ifTrue: ["No spaces -- force a line break" thisWord removeLast; removeLast. self addAllMorphs: thisWord. corner _ corner max: thisWord last bounds bottomRight] ifFalse: [i _ i - (thisWord size//2) + 1]. thisWord reset. firstWord _ true. relLoc _ 0@(relLoc y + h)] ifFalse: [i _ i + 1]]. row _ self buttonRow. row fullBounds. self addMorph: row. super extent: (corner - topLeft) + (self borderWidth * 2) + (0@row height+10). row align: row bounds bottomCenter with: self bounds bottomCenter - (0@2).! ! !CipherPanel methodsFor: 'menu' stamp: 'di 10/4/2000 10:55'! addMenuItemsTo: aMenu hand: aHandMorph aMenu add: 'show cipher help' target: self action: #showHelpWindow. aMenu add: 'show cipher hints' target: self action: #showHintsWindow. aMenu add: 'clear cipher typing' target: self action: #clearTyping. aMenu add: 'enter a new cipher' target: self action: #enterANewCipher. aMenu add: 'quote from Squeak' target: self action: #squeakCipher. ! ! !CipherPanel methodsFor: 'menu' stamp: 'di 10/4/2000 10:54'! buttonRow | row aButton | row _ AlignmentMorph newRow color: self color; hResizing: #shrinkWrap; vResizing: #shrinkWrap. aButton _ SimpleButtonMorph new target: self. aButton color: Color transparent; borderWidth: 1; borderColor: Color black. #('show help' 'show hints' 'clear typing' 'enter a new cipher' 'quote from Squeak') with: #(showHelpWindow showHintsWindow clearTyping enterANewCipher squeakCipher) do: [:label :selector | aButton _ aButton fullCopy. aButton actionSelector: selector. aButton label: label. row addMorphBack: aButton. row addTransparentSpacerOfSize: (3 @ 0)]. ^ row ! ! !CipherPanel methodsFor: 'menu' stamp: 'di 10/4/2000 11:00'! enterANewCipher self clearTyping; encodedQuote: (FillInTheBlank request: 'Type a cipher text to work on here below...')! ! !CipherPanel methodsFor: 'menu' stamp: 'di 10/4/2000 10:48'! squeakCipher self encodedQuote: (CipherPanel encode: (CipherPanel randomComment))! ! !CipherPanel class methodsFor: 'as yet unclassified' stamp: 'di 10/4/2000 10:42'! encode: aString "CipherPanel encode: 'Now is the time for all good men to come to the aid of their country.'" | dict repeat | dict _ Dictionary new. repeat _ true. [repeat] whileTrue: [repeat _ false. ($A to: $Z) with: ($A to: $Z) shuffled do: [:a :b | a = b ifTrue: [repeat _ true]. dict at: a put: b]]. ^ aString asUppercase collect: [:a | dict at: a ifAbsent: [a]]! ! !CipherPanel class methodsFor: 'as yet unclassified' stamp: 'di 10/4/2000 10:43'! randomComment "CipherPanel randomComment" "Generate cryptic puzzles from method comments in the system" | c s | s _ 'none'. [s = 'none'] whileTrue: [s _ ((c _ Smalltalk allClasses atRandom) selectors collect: [:sel | (c firstCommentAt: sel) asString]) detect: [:str | str size between: 100 and: 200] ifNone: ['none']]. ^ s! ! !CipherPanel class methodsFor: 'as yet unclassified' stamp: 'di 10/4/2000 10:45'! tedsHack "Generate cryptic puzzles from method comments in the system" (self newFromQuote: (self encode: (self randomComment))) openInWorld "CipherPanel tedsHack"! ! !ClassBuilder methodsFor: 'private' stamp: 'di 2/12/2001 22:06'! fixGlobalReferences "Fix all the references to globals which are now outdated. Care must be taken that we do not accidentally 'fix' dangerous stuff." | oldClasses newClasses condition any | classMap == nil ifTrue:[^self]. (self retryWithGC: [condition _ classMap anySatisfy: [:any0 | any _ any0. any0 _ nil. any notNil and:[any isObsolete]]. any_nil. condition] until:[:obsRef| obsRef = false]) ifFalse:[^self]. "GC cleaned up the remaining refs" "Collect the old and the new refs" oldClasses _ OrderedCollection new. newClasses _ OrderedCollection new. classMap keysAndValuesDo:[:new :old| old == nil ifFalse:[ newClasses add: new. oldClasses add: old]]. oldClasses isEmpty ifTrue:[^self]. "GC cleaned up the rest" "Now fix all the known dangerous pointers to old classes by creating copies of those still needed. Dangerous pointers should come only from obsolete subclasses (where the superclass must be preserved)." self fixObsoleteReferencesTo: oldClasses. "After this has been done fix the remaining references" progress == nil ifFalse:[progress value: 'Fixing references to globals']. "Forward all old refs to the new ones" (oldClasses asArray) elementsForwardIdentityTo: (newClasses asArray). "Done"! ! !ClassDescription methodsFor: 'initialize-release' stamp: 'di 2/12/2001 22:06'! updateInstancesFrom: oldClass "Recreate any existing instances of the argument, oldClass, as instances of the receiver, which is a newly changed class. Permute variables as necessary." "ar 7/15/1999: The updating below is possibly dangerous. If there are any contexts having an old instance as receiver it might crash the system if the new receiver in which the context is executed has a different layout. See bottom below for a simple example:" | oldInstances | Smalltalk garbageCollect. "ensure that allInstances is correct" oldInstances _ oldClass allInstances asArray. self updateInstances: oldInstances from: oldClass isMeta: self isMeta. "Now fix up instances in segments that are out on the disk." ImageSegment allSubInstancesDo: [:seg | seg segUpdateInstancesOf: oldClass toBe: self isMeta: self isMeta]. oldInstances _ nil. Smalltalk garbageCollect. "ensure that old instances are gone" " | crashingBlock class | class _ Object subclass: #CrashTestDummy instanceVariableNames: 'instVar' classVariableNames: '' poolDictionaries: '' category: 'Crash-Test'. class compile:'instVar: value instVar _ value'. class compile:'crashingBlock ^[instVar]'. crashingBlock _ (class new) instVar: 42; crashingBlock. Object subclass: #CrashTestDummy instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Crash-Test'. crashingBlock. crashingBlock value. " ! ! !ClassOrganizer methodsFor: 'accessing' stamp: 'JW 2/15/2001 07:40'! classComment globalComment ifNil: [^ '']. ^ globalComment text ifNil: ['']! ! !Clipboard methodsFor: 'accessing' stamp: 'RAA 2/6/2001 11:18'! clipboardText "Return the text currently in the clipboard. If the system clipboard is empty, or if it differs from the Smalltalk clipboard text, use the Smalltalk clipboard. This is done since (a) the Mac clipboard gives up on very large chunks of text and (b) since not all platforms support the notion of a clipboard." | s | s _ self primitiveClipboardText. (s isEmpty or: [s = contents asString]) ifTrue: [^ contents] ifFalse: [^ s asText]! ! !Clipboard methodsFor: 'accessing' stamp: 'RAA 2/6/2001 11:21'! clipboardText: text "Set text currently on the clipboard. Also export to OS" contents _ text. self noteRecentClipping: text asText. self primitiveClipboardText: text asString! ! !CodeLoader methodsFor: 'installing' stamp: 'ar 2/6/2001 19:11'! installSegment: reqEntry "Install the previously loaded segment" | contentStream contents trusted | contentStream _ reqEntry value contentStream. contentStream ifNil:[^self error:'No content to install: ', reqEntry key printString]. trusted _ SecurityManager default positionToSecureContentsOf: contentStream. trusted ifFalse:[(SecurityManager default enterRestrictedMode) ifFalse:[ (contentStream respondsTo: #close) ifTrue:[contentStream close]. ^self error:'Insecure content encountered: ', reqEntry key printString]]. contents _ contentStream upToEnd unzipped. (contentStream respondsTo: #close) ifTrue:[contentStream close]. ^(RWBinaryOrTextStream with: contents) reset fileInObjectAndCode install.! ! !CodeLoader methodsFor: 'installing' stamp: 'ar 2/6/2001 19:13'! installSourceFile: aStream "Install the previously loaded source file" | contents trusted | aStream ifNil:[^self error:'No content to install']. trusted _ SecurityManager default positionToSecureContentsOf: aStream. trusted ifFalse:[(SecurityManager default enterRestrictedMode) ifFalse:[ (aStream respondsTo: #close) ifTrue:[aStream close]. ^self error:'Insecure content encountered']]. contents _ aStream upToEnd unzipped. (aStream respondsTo: #close) ifTrue:[aStream close]. ^(RWBinaryOrTextStream with: contents) reset fileIn! ! !CodeLoader class methodsFor: 'utilities' stamp: 'ar 2/6/2001 19:22'! signFile: fileName renameAs: destFile key: privateKey dsa: dsa "Sign the given file using the private key." | in out | in _ FileStream readOnlyFileNamed: fileName. in binary. out _ FileStream newFileNamed: destFile. out binary. [in atEnd] whileFalse:[out nextPutAll: (in next: 4096)]. in close. out close. FileDirectory splitName: destFile to:[:path :file| SecurityManager default signFile: file directory: (FileDirectory on: path). ]. ! ! !CodeLoader class methodsFor: 'utilities' stamp: 'ar 2/6/2001 19:17'! verifySignedFileNamed: aFileName "CodeLoader verifySignedFileNamed: 'signed\dummy1.dsq' " | secured signedFileStream | signedFileStream _ FileStream fileNamed: aFileName. secured _ SecurityManager default positionToSecureContentsOf: signedFileStream. signedFileStream close. Transcript show: aFileName , ' verified: '; show: secured printString; cr. ! ! !CompositionScanner methodsFor: 'scanning' stamp: 'hmm 2/9/2001 11:55'! composeFrom: startIndex inRectangle: lineRectangle firstLine: firstLine leftSide: leftSide rightSide: rightSide "Answer an instance of TextLineInterval that represents the next line in the paragraph." | runLength done stopCondition | "Set up margins" leftMargin _ lineRectangle left. leftSide ifTrue: [leftMargin _ leftMargin + (firstLine ifTrue: [textStyle firstIndent] ifFalse: [textStyle restIndent])]. destX _ spaceX _ leftMargin. rightMargin _ lineRectangle right. rightSide ifTrue: [rightMargin _ rightMargin - textStyle rightIndent]. lastIndex _ startIndex. "scanning sets last index" destY _ lineRectangle top. lineHeight _ baseline _ 0. "Will be increased by setFont" self setStopConditions. "also sets font" runLength _ text runLengthFor: startIndex. runStopIndex _ (lastIndex _ startIndex) + (runLength - 1). line _ (TextLine start: lastIndex stop: 0 internalSpaces: 0 paddingWidth: 0) rectangle: lineRectangle. spaceCount _ 0. self handleIndentation. leftMargin _ destX. line leftMargin: leftMargin. done _ false. [done] whileFalse: [stopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex in: text string rightX: rightMargin stopConditions: stopConditions kern: kern. "See setStopConditions for stopping conditions for composing." (self perform: stopCondition) ifTrue: [^ line lineHeight: lineHeight + textStyle leading baseline: baseline + textStyle leading]]! ! !CompositionScanner methodsFor: 'scanning' stamp: 'hmm 7/20/2000 18:24'! composeLine: lineIndex fromCharacterIndex: startIndex inParagraph: aParagraph "Answer an instance of TextLineInterval that represents the next line in the paragraph." | runLength done stopCondition | destX _ spaceX _ leftMargin _ aParagraph leftMarginForCompositionForLine: lineIndex. destY _ 0. rightMargin _ aParagraph rightMarginForComposition. leftMargin >= rightMargin ifTrue: [self error: 'No room between margins to compose']. lastIndex _ startIndex. "scanning sets last index" lineHeight _ textStyle lineGrid. "may be increased by setFont:..." baseline _ textStyle baseline. self setStopConditions. "also sets font" self handleIndentation. runLength _ text runLengthFor: startIndex. runStopIndex _ (lastIndex _ startIndex) + (runLength - 1). line _ TextLineInterval start: lastIndex stop: 0 internalSpaces: 0 paddingWidth: 0. spaceCount _ 0. done _ false. [done] whileFalse: [stopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex in: text string rightX: rightMargin stopConditions: stopConditions kern: kern. "See setStopConditions for stopping conditions for composing." (self perform: stopCondition) ifTrue: [^line lineHeight: lineHeight + textStyle leading baseline: baseline + textStyle leading]]! ! !CompositionScanner methodsFor: 'stop conditions' stamp: 'ar 1/9/2000 13:59'! tab "Advance destination x according to tab settings in the paragraph's textStyle. Answer whether the character has crossed the right edge of the composition rectangle of the paragraph." destX _ textStyle nextTabXFrom: destX leftMargin: leftMargin rightMargin: rightMargin. destX > rightMargin ifTrue: [^self crossedX]. lastIndex _ lastIndex + 1. ^false ! ! !CompoundTileMorph methodsFor: 'miscellaneous' stamp: 'ar 2/6/2001 22:07'! recompileScript "Pertains only when the test is outside a script?!!" ! ! !CompoundTileMorph methodsFor: 'testing' stamp: 'ar 2/7/2001 17:57'! isTileEditor "Yes I am" ^true! ! !Debugger methodsFor: 'context stack menu' stamp: 'nk 2/6/2001 19:34'! where "Select the expression whose evaluation was interrupted." selectingPC _ true. self contextStackIndex: contextStackIndex oldContextWas: self selectedContext ! ! !DigitalSignatureAlgorithm methodsFor: 'initialization' stamp: 'ar 2/1/2001 20:18'! initRandomFromString: aString "Ask the user to type a long random string and use the result to seed the secure random number generator." | s k srcIndex | s _ aString. k _ LargePositiveInteger new: (s size min: 64). srcIndex _ 0. k digitLength to: 1 by: -1 do: [:i | k digitAt: i put: (s at: (srcIndex _ srcIndex + 1)) asciiValue]. k _ k + (Random new next * 16r7FFFFFFF) asInteger. "a few additional bits randomness" k highBit > 512 ifTrue: [k _ k bitShift: k highBit - 512]. self initRandom: k. ! ! !DisplayMedium methodsFor: 'displaying' stamp: 'hmm 9/16/2000 21:27'! deferUpdatesIn: aRectangle while: aBlock "DisplayScreen overrides with something more involved..." ^aBlock value! ! !DisplayScanner methodsFor: 'scanning' stamp: 'hmm 9/20/2000 12:54'! displayLines: linesInterval in: aParagraph clippedBy: visibleRectangle "The central display routine. 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)." | runLength done stopCondition leftInRun startIndex string lastPos | "leftInRun is the # of characters left to scan in the current run; when 0, it is time to call 'self setStopConditions'" leftInRun _ 0. self initializeFromParagraph: aParagraph clippedBy: visibleRectangle. ignoreColorChanges _ false. paragraph _ aParagraph. foregroundColor _ paragraphColor _ aParagraph foregroundColor. backgroundColor _ aParagraph backgroundColor. aParagraph backgroundColor isTransparent ifTrue: [fillBlt _ nil] ifFalse: [fillBlt _ bitBlt copy. "Blt to fill spaces, tabs, margins" fillBlt sourceForm: nil; sourceOrigin: 0@0. fillBlt fillColor: aParagraph backgroundColor]. rightMargin _ aParagraph rightMarginForDisplay. lineY _ aParagraph topAtLineIndex: linesInterval first. bitBlt destForm deferUpdatesIn: visibleRectangle while: [ linesInterval do: [:lineIndex | leftMargin _ aParagraph leftMarginForDisplayForLine: lineIndex. destX _ (runX _ leftMargin). line _ aParagraph lines at: lineIndex. lineHeight _ line lineHeight. fillBlt == nil ifFalse: [fillBlt destX: visibleRectangle left destY: lineY width: visibleRectangle width height: lineHeight; copyBits]. lastIndex _ line first. leftInRun <= 0 ifTrue: [self setStopConditions. "also sets the font" leftInRun _ text runLengthFor: line first]. destY _ lineY + line baseline - font ascent. "Should have happened in setFont" runLength _ leftInRun. runStopIndex _ lastIndex + (runLength - 1) min: line last. leftInRun _ leftInRun - (runStopIndex - lastIndex + 1). spaceCount _ 0. done _ false. string _ text string. self handleIndentation. [done] whileFalse:[ startIndex _ lastIndex. lastPos _ destX@destY. stopCondition _ self scanCharactersFrom: lastIndex to: runStopIndex in: string rightX: rightMargin stopConditions: stopConditions kern: kern. lastIndex >= startIndex ifTrue:[ font displayString: string on: bitBlt from: startIndex to: lastIndex at: lastPos kern: kern]. "see setStopConditions for stopping conditions for displaying." done _ self perform: stopCondition]. fillBlt == nil ifFalse: [fillBlt destX: destX destY: lineY width: visibleRectangle right-destX height: lineHeight; copyBits]. lineY _ lineY + lineHeight]]! ! !DisplayScanner methodsFor: 'private' stamp: 'hmm 9/16/2000 21:29'! initializeFromParagraph: aParagraph clippedBy: clippingRectangle super initializeFromParagraph: aParagraph clippedBy: clippingRectangle. bitBlt _ BitBlt current toForm: aParagraph destinationForm. bitBlt sourceX: 0; width: 0. "Init BitBlt so that the first call to a primitive will not fail" bitBlt combinationRule: Form paint. bitBlt colorMap: (Bitmap with: 0 "Assumes 1-bit deep fonts" with: (aParagraph foregroundColor pixelValueForDepth: bitBlt destForm depth)). bitBlt clipRect: clippingRectangle. ! ! !DisplayScanner methodsFor: 'private' stamp: 'hmm 9/16/2000 21:29'! setPort: aBitBlt "Install the BitBlt to use" bitBlt _ aBitBlt. bitBlt sourceX: 0; width: 0. "Init BitBlt so that the first call to a primitive will not fail" bitBlt sourceForm: nil. "Make sure font installation won't be confused" ! ! !DisplayScanner methodsFor: 'stop conditions' stamp: 'hmm 7/16/2000 08:23'! plainTab | oldX | oldX _ destX. super plainTab. fillBlt == nil ifFalse: [fillBlt destX: oldX destY: destY width: destX - oldX height: font height; copyBits]! ! !DisplayScanner methodsFor: 'stop conditions' stamp: 'hmm 7/16/2000 08:23'! tab self plainTab. lastIndex _ lastIndex + 1. ^ false! ! !DisplayScanner methodsFor: 'quick print' stamp: 'hmm 9/20/2000 11:44'! drawString: aString at: aPoint "Draw the given string." destX _ aPoint x asInteger. destY _ aPoint y asInteger. lastIndex _ 1. self scanCharactersFrom: 1 to: aString size in: aString rightX: bitBlt clipX + bitBlt clipWidth + font maxWidth stopConditions: stopConditions kern: kern. font displayString: aString on: bitBlt from: 1 to: lastIndex at: aPoint kern: kern.! ! !DisplayScanner methodsFor: 'quick print' stamp: 'hmm 2/1/2001 16:24'! stringWidth: aString "Answer the width of the given string." destX _ destY _ 0. aString ifNil: [^ 0]. lastIndex _ 1. "else the prim will fail" self scanCharactersFrom: 1 to: aString size in: aString rightX: 99999 "virtual infinity" stopConditions: stopConditions kern: kern. ^ destX " (1 to: 10) collect: [:i | QuickPrint new stringWidth: (String new: i withAll: $A)] "! ! !DisplayScreen methodsFor: 'other' stamp: 'hmm 6/18/2000 19:16'! deferUpdates: aBoolean | wasDeferred | "Set the deferUpdates flag in the virtual machine. When this flag is true, BitBlt operations on the Display are not automatically propagated to the screen. If this underlying platform does not support deferred updates, this primitive will fail. Answer whether updates were deferred before if the primitive succeeds, nil if it fails." wasDeferred _ DeferringUpdates == true. DeferringUpdates _ aBoolean. ^(self primitiveDeferUpdates: aBoolean) ifNotNil: [wasDeferred]! ! !DisplayScreen methodsFor: 'other' stamp: 'hmm 2/2/2001 10:14'! deferUpdatesIn: aRectangle while: aBlock | result | (self deferUpdates: true) ifTrue: [^aBlock value]. result _ aBlock value. self deferUpdates: false. self forceToScreen: aRectangle. ^result! ! !DisplayScreen methodsFor: 'other' stamp: 'ar 2/14/2001 00:01'! getCurrentMorphicWorld ^RequestCurrentWorldNotification signal ifNil: [ (self morphicWorldAt: Sensor peekPosition) ifNil: [ self getOuterMorphicWorld ]. ] ! ! !DisplayScreen methodsFor: 'other' stamp: 'hmm 6/18/2000 19:14'! primitiveDeferUpdates: aBoolean "Set the deferUpdates flag in the virtual machine. When this flag is true, BitBlt operations on the Display are not automatically propagated to the screen. If this underlying platform does not support deferred updates, this primitive will fail. Answer the receiver if the primitive succeeds, nil if it fails." ^ nil "answer nil if primitive fails" ! ! !DisplayScreen class methodsFor: 'snapshots' stamp: 'ar 2/5/2001 17:24'! actualScreenDepth ^ Display depth! ! This class defines the necessary primitives for dropping files from the OS onto Squeak. Implementation notes: The drop support is really a two phase process. The first thing the OS code needs to do is to signal an event of type EventTypeDragDropFiles to Squeak. This event needs to include the following information (see sq.h for the definition of sqDragDropFilesEvent): * dragType: DragEnter - dragging mouse entered Squeak window DragMove - dragging mouse moved within Squeak window DragLeave - dragging mouse left Squeak window DragDrop - dropped files onto Squeak window * numFiles: The number of files in the drop operation. * x, y, modifiers: Associated mouse state. When these events are received, the primitives implemented by this plugin come into play. The two primitives can be used to either receive a list of file names or to receive a list of (read-only) file handles. Because drag and drop operations are intended to work in a restricted (plugin) environment, certain security precautions need to be taken: * Access to the contents of the files (e.g., the file streams) must only be granted after a drop occured. Simply dragging the file over the Squeak window is not enough to grant access. * Access to the contents of the files after a drop is allowed to bypass the file sandbox and create a read-only file stream directly. * Access to the names of files can be granted even if the files are only dragged over Squeak (but not dropped). This is so that appropriate user feedback can be given. If somehow possible, the support code should track the location of the drag-and-drop operation and generate appropriate DragMove type events. While not important right now, it will allow us to integrate OS DnD operations with Morphic DnD operation in a seemless manner. ! !EToyGenericDialogMorph methodsFor: 'as yet unclassified' stamp: 'RAA 2/6/2001 14:10'! genericTextFieldNamed: aString | newField | newField _ ShowEmptyTextMorph new beAllFont: self myFont; extent: 300@20; contentsWrapped: ''. namedFields at: aString put: newField. ^newField ! ! !EToyVocabulary methodsFor: 'initialization' stamp: 'jla 2/4/2001 19:24'! initialize "Initialize the receiver (automatically called when instances are created via 'new')" | classes aMethodCategory selector selectors categorySymbols | super initialize. self vocabularyName: #eToy. self documentation: '"EToy" is a vocabulary that provides the equivalent of the 1997-2000 etoy prototype'. categorySymbols _ Set new. classes _ Smalltalk allImplementorsOf: #additionsToViewerCategories. classes do: [:anItem | MessageSet parse: anItem toClassAndSelector: [:aClass :aSelector | categorySymbols addAll: aClass soleInstance basicNew categoriesForViewer]]. categorySymbols asOrderedCollection do: [:aCategorySymbol | aMethodCategory _ ElementCategory new categoryName: aCategorySymbol.. classes _ (Smalltalk allImplementorsOf: #additionsToViewerCategories) collect: [:anItem | MessageSet parse: anItem toClassAndSelector: [:aMetaClass :aSelector | aMetaClass soleInstance]]. selectors _ Set new. classes do: [:aClass | (aClass additionsToViewerCategory: aCategorySymbol) do: [:anElement | anElement first == #command ifTrue: [selectors add: (selector _ anElement second). (methodInterfaces includesKey: selector) ifFalse: [methodInterfaces at: selector put: (MethodInterface new initializeFromEToyCommandSpec: anElement category: aCategorySymbol)]] ifFalse: "#slot format" [selectors add: (selector _ anElement seventh). "the getter" selectors add: (anElement at: 9) "the setter". (methodInterfaces includesKey: selector) ifFalse: [self addGetterAndSetterInterfacesFromOldSlotSpec: anElement]]]]. (selectors copyWithout: #unused) asSortedArray do: [:aSelector | aMethodCategory elementAt: aSelector put: (methodInterfaces at: aSelector)]. self addCategory: aMethodCategory]. #(scripts 'instance variables') do: [:sym | self addCategoryNamed: sym]. self setCategoryDocumentationStrings! ! !Encoder methodsFor: 'encoding' stamp: 'RAA 2/5/2001 10:44'! encodeVariable: name sourceRange: range ifUnknown: action | varNode | varNode _ scopeTable at: name ifAbsent: [(self lookupInPools: name ifFound: [:assoc | varNode _ self global: assoc name: name]) ifTrue: [varNode] ifFalse: [action value]]. range ifNotNil: [ name first isUppercase ifTrue: [globalSourceRanges addLast: { name. range. false }]. ]. (varNode isTemp and: [varNode scope < 0]) ifTrue: [ OutOfScopeNotification signal ifFalse: [ ^self notify: 'out of scope']. ]. ^ varNode! ! !EventSensor methodsFor: 'accessing' stamp: 'ar 2/7/2001 17:13'! flushEvents eventQueue ifNotNil:[eventQueue flush].! ! !EventSensor methodsFor: 'accessing' stamp: 'RAA 2/10/2001 23:16'! nextEventFromQueue "Return the next event from the receiver." eventQueue isEmpty ifTrue:[inputSemaphore signal]. EventPollFrequency _ 500. "since Squeak is taking the event, reset to normal delay" eventQueue isEmpty ifTrue:[^nil] ifFalse:[^eventQueue next]! ! !EventSensor methodsFor: 'accessing' stamp: 'ar 2/14/2001 00:03'! peekButtons inputSemaphore signal. ^mouseButtons! ! !EventSensor methodsFor: 'accessing' stamp: 'ar 2/8/2001 21:45'! peekMousePt ^mousePosition! ! !EventSensor methodsFor: 'accessing' stamp: 'ar 2/14/2001 00:01'! peekPosition inputSemaphore signal. "get latest state" ^mousePosition! ! !EventSensor methodsFor: 'private-I/O' stamp: 'RAA 2/10/2001 23:16'! ioProcess "Run the i/o process" | eventBuffer type | eventBuffer _ Array new: 8. [true] whileTrue:[ [self primGetNextEvent: eventBuffer. type _ eventBuffer at: 1. type = EventTypeNone] whileFalse:[self processEvent: eventBuffer]. inputSemaphore waitTimeoutMSecs: EventPollFrequency. ]. ! ! !EventSensor methodsFor: 'private' stamp: 'ar 12/5/2000 13:49'! primKbdNext inputSemaphore signal. eventQueue ifNotNil:[eventQueue flush]. keyboardBuffer isEmpty ifTrue:[^nil] ifFalse:[^keyboardBuffer next]! ! !EventSensor methodsFor: 'private' stamp: 'ar 12/5/2000 13:50'! primKbdPeek inputSemaphore signal. eventQueue ifNotNil:[eventQueue flush]. ^keyboardBuffer peek! ! !EventSensor methodsFor: 'private' stamp: 'ar 12/5/2000 13:50'! primMouseButtons inputSemaphore signal. eventQueue ifNotNil:[eventQueue flush]. ^mouseButtons! ! !EventSensor methodsFor: 'private' stamp: 'ar 12/5/2000 13:50'! primMousePt inputSemaphore signal. eventQueue ifNotNil:[eventQueue flush]. ^mousePosition! ! !EventSensor methodsFor: 'NOTES' stamp: 'RAA 2/10/2001 23:16'! higherPerformanceNotes " This is mostly a Mac issue, but may have some effect on other platforms. These changes do not take effect until you set the preference #higherPerformance to true. The impact of setting this pref to true may be higher performance for this Squeak image, but lower performance for other applications/processes that may be running concurrently. Experiment with your particular configuration/desires and decide for yourself. -- 10 Feb 2001 -- removed item #1 since other changes in event handling made it moot -- 1. In order to reduce the amount of time lost (perhaps 20 to 30% in some cases) to background applications on the Mac, change the strategy used to poll for UI events. Every time we poll the OS for UI events, increase the delay until the next check. Every time Squeak actually requests an event from EventSensor, reset the delay to its normal value (20 ms). This means that a long-running evaluation started in the UI process will receive less competition from background apps (and less overhead even if it is the only app), but normal UI-intensive operations will happen as they do now. What is lost by this change is some sensitivity to mouse events that occur while Squeak is busy over long periods. My thought is that if Squeak is so occupied for a period of seconds, these events are much less useful and perhaps even harmful. 2. Reduce the minimum morphic cycle time (MinCycleLapse) so that the frame rate (and, hence, running of #step methods) can proceed at greater than 50 frames per second. This can be quite beneficial to things like simulations that are run via #step. "! ! !EventSensor class methodsFor: 'class initialization' stamp: 'RAA 2/10/2001 23:15'! initialize "EventSensor initialize" self initializeEventSensorConstants. EventPollFrequency _ 500. "Note: The above is important. Most systems will not notify the VM about the occurance of events asynchronously. Therefore, we have to go check for ourselves every now and then."! ! !FFIPlugin class methodsFor: 'C support code' stamp: 'JMM 2/6/2001 10:55'! sqMacFFIPPCFile ^'/**************************************************************************** * PROJECT: Squeak foreign function interface * FILE: sqMacFFIPPC.c * CONTENT: Mac/PPC specific support for the foreign function interface * * AUTHOR: Andreas Raab (ar) * ADDRESS: Walt Disney Imagineering, Glendale, CA * EMAIL: Andreas.Raab@disney.com * RCSID: $Id$ * * NOTES: * *****************************************************************************/ #include "sq.h" #include "sqFFI.h" /* note: LONGLONG is usually declared by universal headers */ #ifndef LONGLONG #define LONGLONG long long #endif extern struct VirtualMachine *interpreterProxy; #define primitiveFail() interpreterProxy->primitiveFail(); #define GP_MAX_REGS 8 #define FP_MAX_REGS 13 /* Values passed in GPR3-GPR10 */ static int GPRegs[8]; /* Nr of GPRegs used so far */ static int gpRegCount = 0; /* Values passed in FPR1-FPR13 */ static double FPRegs[13]; /* Nr of FPRegs used so far */ static int fpRegCount = 0; /* Max stack size */ #define FFI_MAX_STACK 512 /* The stack used to assemble the arguments for a call */ static int ffiStack[FFI_MAX_STACK]; /* The stack pointer while filling the stack */ static int ffiStackIndex = 0; /* The area for temporarily allocated strings */ static char *ffiTempStrings[FFI_MAX_STACK]; /* The number of temporarily allocated strings */ static int ffiTempStringCount = 0; /* The return values for calls */ static int intReturnValue; static LONGLONG longReturnValue; static double floatReturnValue; static int *structReturnValue = NULL; /**************************************************************/ #define ARG_CHECK() if(gpRegCount >= GP_MAX_REGS && ffiStackIndex >= FFI_MAX_STACK) return primitiveFail(); #define ARG_PUSH(value) { \ ARG_CHECK(); \ if(gpRegCount < GP_MAX_REGS) GPRegs[gpRegCount++] = value; \ ffiStack[ffiStackIndex++] = value; \ } /*****************************************************************************/ /*****************************************************************************/ /* ffiInitialize: Announce that the VM is about to do an external function call. */ int ffiInitialize(void) { ffiStackIndex = 0; gpRegCount = 0; fpRegCount = 0; floatReturnValue = 0.0; return 1; } /* ffiSupportsCallingConvention: Return true if the support code supports the given calling convention. */ int ffiSupportsCallingConvention(int callType) { if(callType == FFICallTypeCDecl) return 1; if(callType == FFICallTypeApi) return 1; return 0; } int ffiAlloc(int byteSize) { return (int) malloc(byteSize); } int ffiFree(int ptr) { if(ptr) free((void*)ptr); return 1; } /*****************************************************************************/ /*****************************************************************************/ int ffiPushSignedChar(int value) { ARG_PUSH(value); return 1; } int ffiPushUnsignedChar(int value) { ARG_PUSH(value); return 1; } int ffiPushSignedByte(int value) { ARG_PUSH(value); return 1; } int ffiPushUnsignedByte(int value) { ARG_PUSH(value); return 1; } int ffiPushSignedShort(int value) { ARG_PUSH(value); return 1; } int ffiPushUnsignedShort(int value) { ARG_PUSH(value); return 1; } int ffiPushSignedInt(int value) { ARG_PUSH(value); return 1; } int ffiPushUnsignedInt(int value) { ARG_PUSH(value); return 1; } int ffiPushSignedLongLong(int low, int high) { ARG_PUSH(high); ARG_PUSH(low); return 1; } int ffiPushUnsignedLongLong(int low, int high) { ARG_PUSH(high); ARG_PUSH(low); return 1; } int ffiPushSingleFloat(double value) { float floatValue = (float) value; if(fpRegCount < FP_MAX_REGS) { /* Still space in FPRegs - so we use the more accurate double value */ FPRegs[fpRegCount++] = value; } /* Note: Even for args that are passed in FPRegs we pass the actual 32bit value in either GPRegs or stack frame for varargs calls. */ ARG_PUSH(*(int*)(&floatValue)); return 1; } int ffiPushDoubleFloat(double value) { if(fpRegCount < FP_MAX_REGS) { /* Still space in FPRegs */ FPRegs[fpRegCount++] = value; } /* Note: Even for args that are passed in FPRegs we pass the actual 64bit value in either GPRegs or stack frame for varargs calls. */ ARG_PUSH(((int*)(&value))[1]); ARG_PUSH(((int*)(&value))[0]); return 1; } int ffiPushStructureOfLength(int pointer, int *structSpec, int specSize) { int i, typeSpec; int *data = (int*) pointer; for(i = 0; i> FFIAtomicTypeShift; switch(atomicType) { case FFITypeUnsignedChar: case FFITypeUnsignedByte: ffiPushUnsignedByte(*(unsigned char*)data); break; case FFITypeSignedChar: case FFITypeSignedByte: ffiPushSignedByte(*(signed char*)data); break; case FFITypeUnsignedShort: ffiPushUnsignedShort(*(unsigned short*)data); break; case FFITypeSignedShort: ffiPushSignedShort(*(signed short*)data); break; case FFITypeUnsignedInt: ffiPushUnsignedInt(*(unsigned int*)data); break; case FFITypeSignedInt: ffiPushSignedInt(*(signed int*)data); break; case FFITypeUnsignedLongLong: ffiPushUnsignedLongLong( ((unsigned int*)data)[1], ((unsigned int*)data)[0]); break; case FFITypeSignedLongLong: ffiPushSignedLongLong( ((signed int*)data)[1], ((signed int*)data)[0]); break; case FFITypeSingleFloat: ffiPushSingleFloat( *(float*)data); break; case FFITypeDoubleFloat: { double fArg; ((int*)&fArg)[0] = ((int*)data)[0]; ((int*)&fArg)[1] = ((int*)data)[1]; ffiPushDoubleFloat(fArg); } break; default: return primitiveFail(); } data = (int*) ((int)data + (typeSpec & FFIStructSizeMask)); } } return 1; } int ffiPushPointer(int pointer) { ARG_PUSH(pointer); return 1; } int ffiPushStringOfLength(int srcIndex, int length) { char *ptr; ARG_CHECK(); /* fail before allocating */ ptr = (char*) malloc(length+1); if(!!ptr) return primitiveFail(); memcpy(ptr, (void*)srcIndex, length); ptr[length] = 0; ffiTempStrings[ffiTempStringCount++] = ptr; ARG_PUSH((int)ptr); return 1; } /*****************************************************************************/ /*****************************************************************************/ /* ffiCanReturn: Return true if the support code can return the given type. */ int ffiCanReturn(int *structSpec, int specSize) { int header = *structSpec; if(header & FFIFlagPointer) return 1; if(header & FFIFlagStructure) { /* structs are always returned as pointers to hidden structures */ int structSize = header & FFIStructSizeMask; structReturnValue = malloc(structSize); if(!!structReturnValue) return 0; ARG_PUSH((int)structReturnValue); } return 1; } /* ffiReturnFloatValue: Return the value from a previous ffi call with float return type. */ double ffiReturnFloatValue(void) { return floatReturnValue; } /* ffiLongLongResultLow: Return the low 32bit from the 64bit result of a call to an external function */ int ffiLongLongResultLow(void) { return ((int*) &longReturnValue)[1]; } /* ffiLongLongResultHigh: Return the high 32bit from the 64bit result of a call to an external function */ int ffiLongLongResultHigh(void) { return ((int*) &longReturnValue)[0]; } /* ffiStoreStructure: Store the structure result of a previous ffi call into the given address. */ int ffiStoreStructure(int address, int structSize) { if(structReturnValue) { memcpy((void*)address, (void*)structReturnValue, structSize); } else { memcpy((void*)address, (void*)&intReturnValue, structSize); } return 1; } /* ffiCleanup: Cleanup after a foreign function call has completed. The generic support code only frees the temporarily allocated strings. */ int ffiCleanup(void) { int i; for(i=0; ix, pt1->y, pt1->z, pt1->w); printf("pt2.x = %d\npt2.y = %d\npt2.z = %d\npt2.w = %d\n", pt2->x, pt2->y, pt2->z, pt2->w); result = (ffiTestPoint4*) malloc(sizeof(ffiTestPoint4)); result->x = pt1->x + pt2->x; result->y = pt1->y + pt2->y; result->z = pt1->z + pt2->z; result->w = pt1->w + pt2->w; return result; } /* test passing and returning longlongs */ EXPORT(LONGLONG) ffiTestLongLong(LONGLONG i1, LONGLONG i2) { return i1 + i2; } #endif /* NO_FFI_TEST */ '! ! !FXBltSimulation methodsFor: 'inner loop' stamp: 'ar 2/10/2001 00:21'! copyLoopPixels "This version of the inner loop maps source pixels and dest pixels one at a time. This is the most general (and slowest) version which must also keep track of source and dest paint mode by itself." | nPix srcShift dstShift destWord srcIndex dstIndex nLines sourceWord lastSrcPix sourcePix srcMask dstMask srcMapped lastDstPix destPix dstMapped resultMapped resultPix srcPaint dstPaint paintMode mergeFn | self inline: false. mergeFn _ opTable at: combinationRule+1. srcPaint _ srcKeyMode. dstPaint _ dstKeyMode. paintMode _ srcPaint | dstPaint. "Additional inits" srcMask _ maskTable at: sourceDepth. dstMask _ maskTable at: destDepth. sourceIndex _ srcIndex _ sourceBits + (sy * sourcePitch) + ((sx // sourcePPW) *4). dstIndex _ destIndex. "Precomputed shifts for pickSourcePixels" srcShift _ ((sx bitAnd: sourcePPW - 1) * sourceDepth). dstShift _ ((dx bitAnd: destPPW - 1) * destDepth). sourceMSB ifTrue:[srcShift _ 32 - sourceDepth - srcShift]. destMSB ifTrue:[dstShift _ 32 - destDepth - dstShift]. srcBitShift _ srcShift. dstBitShift _ dstShift. noSourceMap ifTrue:[pixelDepth _ sourceDepth] ifFalse:[pixelDepth _ 32]. destMask _ -1. nLines _ bbH. ["this is the vertical loop" sourceWord _ self srcLongAt: srcIndex. destWord _ self dstLongAt: dstIndex. "Prefetch first source pixel" lastSrcPix _ sourcePix _ sourceWord >> srcShift bitAnd: srcMask. srcMapped _ self mapSourcePixel: sourcePix. "Prefetch first dest pixel" lastDstPix _ destPix _ destWord >> dstShift bitAnd: dstMask. dstMapped _ self mapDestPixel: destPix. nPix _ bbW. ["this is the horizontal loop" (paintMode) ifTrue:[ ((srcPaint and:[sourcePix = sourceAlphaKey]) or:[dstPaint and:[destPix ~= destAlphaKey]]) ifTrue:[resultMapped _ dstMapped] ifFalse:[ resultMapped _ self merge: srcMapped with: dstMapped function: mergeFn]. ] ifFalse:[ resultMapped _ self merge: srcMapped with: dstMapped function: mergeFn. ]. (noColorMap and:[resultMapped = dstMapped]) ifFalse:[ resultPix _ self mapPixel: resultMapped. destWord _ destWord bitAnd: (dstMask << dstShift) bitInvert32. destWord _ destWord bitOr: (resultPix bitAnd: dstMask) << dstShift. ]. sourceMSB ifTrue:[ "Adjust source if at pixel boundary" (srcShift _ srcShift - sourceDepth) < 0 ifTrue: [srcShift _ srcShift + 32. sourceWord _ self srcLongAt: (srcIndex _ srcIndex + 4)]. ] ifFalse:[ "Adjust source if at pixel boundary" (srcShift _ srcShift + sourceDepth) > 31 ifTrue: [srcShift _ srcShift - 32. sourceWord _ self srcLongAt: (srcIndex _ srcIndex + 4)]. ]. destMSB ifTrue:[ "Adjust dest if at pixel boundary" (dstShift _ dstShift - destDepth) < 0 ifTrue: [dstShift _ dstShift + 32. self dstLongAt: dstIndex put: destWord. destWord _ self dstLongAt: (dstIndex _ dstIndex + 4)]. ] ifFalse:[ "Adjust dest if at pixel boundary" (dstShift _ dstShift + destDepth) > 31 ifTrue: [dstShift _ dstShift - 32. self dstLongAt: dstIndex put: destWord. destWord _ self dstLongAt: (dstIndex _ dstIndex + 4)]. ]. (nPix _ nPix - 1) = 0] whileFalse:[ "Fetch next source/dest pixel" sourcePix _ sourceWord >> srcShift bitAnd: srcMask. lastSrcPix = sourcePix ifFalse:[ srcMapped _ self mapSourcePixel: sourcePix. lastSrcPix _ sourcePix]. destPix _ destWord >> dstShift bitAnd: dstMask. lastDstPix = destPix ifFalse:[ dstMapped _ self mapDestPixel: destPix. lastDstPix _ destPix] ]. (nLines _ nLines - 1) = 0] whileFalse:[ "Store last destWord" self dstLongAt: dstIndex put: destWord. "Advance sourceIndex, destIndex" srcIndex _ sourceIndex _ sourceIndex + sourcePitch. dstIndex _ destIndex _ destIndex + destPitch. srcShift _ srcBitShift. dstShift _ dstBitShift. ]. dstIndex <= (destIndex + destPitch + 4) ifTrue:[ "Store final destWord but not beyound range" self dstLongAt: dstIndex put: destWord. ]. ! ! !FXBltSimulation class methodsFor: 'translation' stamp: 'hg 2/2/2001 14:36'! declareCVarsIn: aCCodeGenerator aCCodeGenerator var: 'colorMap' declareC:'int *colorMap'; var: 'cmShiftTable' declareC:'int *cmShiftTable'; var: 'cmMaskTable' declareC:'int *cmMaskTable'; var: 'sourceMap' declareC:'int *sourceMap'; var: 'smShiftTable' declareC:'int *smShiftTable'; var: 'smMaskTable' declareC:'int *smMaskTable'; var: 'destMap' declareC:'int *destMap'; var: 'dmShiftTable' declareC:'int *dmShiftTable'; var: 'dmMaskTable' declareC:'int *dmMaskTable'; var: 'warpQuad' declareC:'int warpQuad[8]'; var: 'tallyMap' declareC:'int *tallyMap'. aCCodeGenerator var: 'opTable' declareC: 'int opTable[' , OpTableSize printString , ']'. aCCodeGenerator var: 'maskTable' declareC:'int maskTable[33] = { 0, 1, 3, 0, 15, 31, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 65535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 }'. aCCodeGenerator var: 'ditherMatrix4x4' declareC:'const int ditherMatrix4x4[16] = { 0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5 }'. aCCodeGenerator var: 'ditherThresholds16' declareC:'const int ditherThresholds16[8] = { 0, 2, 4, 6, 8, 12, 14, 16 }'. aCCodeGenerator var: 'ditherValues16' declareC:'const int ditherValues16[32] = { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }'. aCCodeGenerator var: 'warpBitShiftTable' declareC:'int warpBitShiftTable[32]'.! ! !FXBltSimulator methodsFor: 'as yet unclassified' stamp: 'hg 2/2/2001 15:55'! initBBOpTable opTable _ OpTable. maskTable _ Array new: 32. #(1 2 4 5 8 16 32) do:[:i| maskTable at: i put: (1 << i)-1]. self initializeDitherTables. warpBitShiftTable _ CArrayAccessor on: (Array new: 32). cmCache _ CArrayAccessor on: (Array new: ColorCacheSize*2). warpQuad _ CArrayAccessor on: (Array new: 8).! ! !FileDirectory methodsFor: 'enumeration' stamp: 'ar 2/6/2001 15:48'! localName "Return the local name of this directory." ^FileDirectory localNameFor: pathName! ! !FileDirectory methodsFor: 'file directory' stamp: 'ar 2/6/2001 15:48'! assureExistance "Make sure the current directory exists. If necessary, create all parts inbetween" ^self containingDirectory assureExistanceOfPath: self localName! ! !FileDirectory methodsFor: 'file directory' stamp: 'ar 2/6/2001 15:50'! assureExistanceOfPath: localPath "Make sure the local directory exists. If necessary, create all parts inbetween" (self directoryNames includes: localPath) ifTrue:[^self]. "exists" "otherwise check parent first and then create local dir" self containingDirectory assureExistanceOfPath: self localName. self createDirectory: localPath.! ! !FileDirectory class methodsFor: 'name utilities' stamp: 'ar 2/12/2001 15:45'! startUp "Establish the platform-specific FileDirectory subclass. Do any platform-specific startup." self setDefaultDirectoryFrom: Smalltalk imageName. Preferences startInUntrustedDirectory ifTrue:[ self setDefaultDirectory: SecurityManager default untrustedUserDirectory. "Make sure we have a place to go to" DefaultDirectory assureExistance]. Smalltalk openSourceFiles. ! ! !FileDirectory class methodsFor: 'system start up' stamp: 'ar 2/12/2001 15:30'! openChanges: changesName forImage: imageName "Initialize the default directory to the image directory and open the sources and changes files, if possible. Look for the changes file in image directory. Look for the system sources (or an alias to it) first in the VM directory, then in the image directory. Open the changes and sources files and install them in SourceFiles." | changes fd | "look for the changes file or an alias to it in the image directory" fd _ FileDirectory on: (FileDirectory dirPathFor: imageName). (fd fileExists: changesName) ifTrue: [changes _ fd oldFileNamed: changesName]. changes ifNotNil:[^changes]. "look for the changes in the current directory" fd _ DefaultDirectory. (fd fileExists: changesName) ifTrue: [changes _ fd oldFileNamed: changesName]. changes ifNotNil:[^changes]. "look for read-only changes in the image directory" fd _ FileDirectory on: (FileDirectory dirPathFor: imageName). (fd fileExists: changesName) ifTrue: [changes _ fd readOnlyFileNamed: changesName]. changes ifNotNil:[^changes]. "look for read-only changes in the current directory" fd _ DefaultDirectory. (fd fileExists: changesName) ifTrue: [changes _ fd readOnlyFileNamed: changesName]. ^changes ! ! !FileDirectory class methodsFor: 'system start up' stamp: 'ar 2/12/2001 15:23'! openSources: sourcesName andChanges: changesName forImage: imageName "Initialize the default directory to the image directory and open the sources and changes files, if possible. Look for the changes file in image directory. Look for the system sources (or an alias to it) first in the VM directory, then in the image directory. Open the changes and sources files and install them in SourceFiles." "Note: SourcesName and imageName are full paths; changesName is a local name." | sources changes msg wmsg | msg _ 'Squeak cannot locate &fileRef. Please check that the file is named properly and is in the same directory as this image. Further explanation can found in the startup window, ''How Squeak Finds Source Code''.'. wmsg _ 'Squeak cannot write to &fileRef. Please check that you have write permission for this file. You won''t be able to save this image correctly until you fix this.'. sources _ self openSources: sourcesName forImage: imageName. changes _ self openChanges: changesName forImage: imageName. ((sources == nil or: [sources atEnd]) and: [Preferences valueOfFlag: #warnIfNoSourcesFile]) ifTrue: [PopUpMenu notify: (msg copyReplaceAll: '&fileRef' with: 'the sources file named ' , sourcesName). Smalltalk platformName = 'Mac OS' ifTrue: [PopUpMenu notify: 'Make sure the sources file is not an Alias.']]. (changes == nil and: [Preferences valueOfFlag: #warnIfNoChangesFile]) ifTrue: [PopUpMenu notify: (msg copyReplaceAll: '&fileRef' with: 'the changes file named ' , changesName)]. (Preferences valueOfFlag: #warnIfNoChangesFile) ifTrue: [ changes isReadOnly ifTrue:[ PopUpMenu notify: (wmsg copyReplaceAll: '&fileRef' with: 'the changes file named ' , changesName)]. ((changes next: 200) includesSubString: String crlf) ifTrue: [ PopUpMenu notify: 'The changes file named ' , changesName, ' has been injured by an unpacking utility. Crs were changed to CrLfs. Please set the preferences in your decompressing program to "do not convert text files" and unpack the system again.']]. SourceFiles _ Array with: sources with: changes! ! !FileDirectory class methodsFor: 'system start up' stamp: 'ar 2/12/2001 15:19'! openSources: fullSourcesName forImage: imageName "Initialize the default directory to the image directory and open the sources and changes files, if possible. Look for the changes file in image directory. Look for the system sources (or an alias to it) first in the VM directory, then in the image directory. Open the changes and sources files and install them in SourceFiles." | sources fd sourcesName | sourcesName _ FileDirectory localNameFor: fullSourcesName. "look for the sources file or an alias to it in the VM's directory" fd _ FileDirectory on: Smalltalk vmPath. (fd fileExists: sourcesName) ifTrue: [sources _ fd readOnlyFileNamed: sourcesName]. sources ifNotNil:[^sources]. "look for the sources file or an alias to it in the image directory" fd _ FileDirectory on: (FileDirectory dirPathFor: imageName). (fd fileExists: sourcesName) ifTrue: [sources _ fd readOnlyFileNamed: sourcesName]. sources ifNotNil:[^sources]. "look for the sources in the current directory" fd _ DefaultDirectory. (fd fileExists: sourcesName) ifTrue: [sources _ fd readOnlyFileNamed: sourcesName]. ^sources ! ! !FileDirectory class methodsFor: 'system start up' stamp: 'ar 2/12/2001 15:39'! setDefaultDirectory: directoryName "Initialize the default directory to the directory supplied. This method is called when the image starts up." | dirName | DirectoryClass _ self activeDirectoryClass. dirName _ directoryName. [dirName endsWith: self slash] whileTrue:[ dirName _ dirName copyFrom: 1 to: dirName size - self slash size. ]. DefaultDirectory _ self on: dirName.! ! !FileDirectoryWrapper methodsFor: 'as yet unclassified' stamp: 'ar 2/12/2001 16:20'! contents ^((model directoryNamesFor: item) sortBy: [ :a :b | a caseInsensitiveLessOrEqual: b]) collect: [ :n | FileDirectoryWrapper with: (item directoryNamed: n) name: n model: self ] ! ! !FileDirectoryWrapper methodsFor: 'as yet unclassified' stamp: 'ar 2/12/2001 16:22'! directoryNamesFor: anItem ^model directoryNamesFor: anItem! ! !FileList methodsFor: 'file list menu' stamp: 'sw 2/16/2001 16:22'! fileSelectedMenu: aMenu "Fill the menu with items appropriate for the selected file type, or for all file types if the shift key is down" | firstItems secondItems thirdItems n1 n2 n3 | firstItems _ self itemsForFileEnding: (Sensor leftShiftDown ifFalse: [self fileNameSuffix asLowercase] ifTrue: ['*']). secondItems _ self itemsForAnyFile. thirdItems _ self itemsForNoFile. n1 _ firstItems first size. n2 _ n1 + secondItems first size. n3 _ n2 + thirdItems first size. ^ aMenu labels: firstItems first , secondItems first , thirdItems first , #('more...') lines: firstItems second , (Array with: n1 with: n2) , (thirdItems second collect: [:n | n + n2]) , (Array with: n3) selections: firstItems third , secondItems third , thirdItems third , #(offerAllFileOptions)! ! !FileList2 methodsFor: 'as yet unclassified' stamp: 'ar 2/12/2001 16:20'! directoryNamesFor: item "item may be file directory or server directory" | entries | entries _ item directoryNames. dirSelectionBlock ifNotNil:[entries _ entries select: dirSelectionBlock]. ^entries! ! !FileList2 methodsFor: 'as yet unclassified' stamp: 'ar 2/12/2001 16:12'! initialDirectoryList | dir nameToShow dirList | dirList _ (FileDirectory on: '') directoryNames collect: [ :each | FileDirectoryWrapper with: (FileDirectory on: each) name: each model: self]. dirList isEmpty ifTrue:[ dirList _ Array with: (FileDirectoryWrapper with: FileDirectory default name: FileDirectory default localName model: self)]. dirList _ dirList,( ServerDirectory serverNames collect: [ :n | dir _ ServerDirectory serverNamed: n. nameToShow _ n. (dir directoryWrapperClass with: dir name: nameToShow model: self) balloonText: dir realUrl ] ). ^dirList! ! !FileList2 methodsFor: 'as yet unclassified' stamp: 'RAA 2/17/2001 12:25'! limitedSuperSwikiDirectoryList | dir nameToShow dirList | dirList _ OrderedCollection new. ServerDirectory serverNames do: [ :n | dir _ ServerDirectory serverNamed: n. (dir isKindOf: SuperSwikiServer) ifTrue: [ nameToShow _ n. dirList add: ((dir directoryWrapperClass with: dir name: nameToShow model: self) balloonText: dir realUrl) ]. ]. {Project current squeakletDirectory} do: [ :each | dirList add: (FileDirectoryWrapper with: each name: each localName model: self) ]. ^dirList! ! !FileList2 methodsFor: 'as yet unclassified' stamp: 'RAA 2/17/2001 12:48'! limitedSuperSwikiPublishDirectoryList | dir nameToShow dirList | dirList _ OrderedCollection new. ServerDirectory serverNames do: [ :n | dir _ ServerDirectory serverNamed: n. (dir isKindOf: SuperSwikiServer) ifTrue: [ nameToShow _ n. dirList add: ((dir directoryWrapperClass with: dir name: nameToShow model: self) balloonText: dir realUrl) ]. ]. ^dirList! ! !FileList2 methodsFor: 'as yet unclassified' stamp: 'RAA 2/17/2001 12:18'! morphicDirectoryTreePane ^self morphicDirectoryTreePaneFiltered: #initialDirectoryList ! ! !FileList2 methodsFor: 'as yet unclassified' stamp: 'RAA 2/17/2001 12:17'! morphicDirectoryTreePaneFiltered: aSymbol ^(SimpleHierarchicalListMorph on: self list: aSymbol selected: #getSelectedDirectory changeSelected: #setSelectedDirectoryTo: menu: nil keystroke: nil) autoDeselect: false ! ! !FileList2 class methodsFor: 'blue ui' stamp: 'RAA 2/17/2001 12:26'! morphicViewProjectLoader2InWorld: aWorld reallyLoad: aBoolean dirFilterType: aSymbol | window aFileList buttons treePane textColor1 fileListPane pane2a pane2b | window _ AlignmentMorphBob1 newColumn. window hResizing: #shrinkWrap; vResizing: #shrinkWrap. textColor1 _ Color r: 0.742 g: 0.839 b: 1.0. aFileList _ self new directory: FileDirectory default. aFileList optionalButtonSpecs: self specsForProjectLoader; fileSelectionBlock: self projectOnlySelectionBlock; "dirSelectionBlock: self hideSqueakletDirectoryBlock;" modalView: window. window setProperty: #FileList toValue: aFileList; wrapCentering: #center; cellPositioning: #topCenter; borderWidth: 4; borderColor: (Color r: 0.355 g: 0.516 b: 1.0); useRoundedCorners. buttons _ #('OK' 'Cancel') collect: [ :each | self blueButtonText: each textColor: textColor1 inWindow: window ]. (treePane _ aFileList morphicDirectoryTreePaneFiltered: aSymbol) extent: 250@300; retractable: false; borderWidth: 0. fileListPane _ aFileList morphicFileListPane extent: 350@300; retractable: false; borderWidth: 0. window addARow: { window fancyText: 'Load A Project' ofSize: 21 color: textColor1 }; addARowCentered: { buttons first. (Morph new extent: 30@5) color: Color transparent. buttons second }; addARow: { window fancyText: 'Please select a project' ofSize: 21 color: Color blue }; addARow: { (window inAColumn: {(pane2a _ window inARow: {window inAColumn: {treePane}}) useRoundedCorners; layoutInset: 6}) layoutInset: 10. (window inAColumn: {(pane2b _ window inARow: {window inAColumn: {fileListPane}}) useRoundedCorners; layoutInset: 6}) layoutInset: 10. }. window fullBounds. window fillWithRamp: self blueRamp1 oriented: 0.65. pane2a fillWithRamp: self blueRamp3 oriented: (0.7 @ 0.35). pane2b fillWithRamp: self blueRamp3 oriented: (0.7 @ 0.35). buttons do: [ :each | each fillWithRamp: self blueRamp2 oriented: (0.75 @ 0). ]. buttons first on: #mouseUp send: (aBoolean ifTrue: [#okHitForProjectLoader] ifFalse: [#okHit]) to: aFileList. buttons second on: #mouseUp send: #cancelHit to: aFileList. aFileList postOpen. window position: aWorld topLeft + (aWorld extent - window extent // 2). ^ window openInWorld: aWorld.! ! !FileList2 class methodsFor: 'blue ui' stamp: 'RAA 2/17/2001 13:03'! morphicViewProjectSaverFor: aProject " (FileList2 morphicViewProjectSaverFor: Project current) openInWorld " | window aFileList buttons treePane pane2 textColor1 option | textColor1 _ Color r: 0.742 g: 0.839 b: 1.0. aFileList _ self new directory: FileDirectory default. aFileList dirSelectionBlock: self hideSqueakletDirectoryBlock. window _ AlignmentMorphBob1 newColumn. window hResizing: #shrinkWrap; vResizing: #shrinkWrap. aFileList modalView: window. window setProperty: #FileList toValue: aFileList; wrapCentering: #center; cellPositioning: #topCenter; borderWidth: 4; borderColor: (Color r: 0.355 g: 0.516 b: 1.0); useRoundedCorners. buttons _ #( ('OK' okHit) ('Cancel' cancelHit) ) collect: [ :each | (self blueButtonText: each first textColor: textColor1 inWindow: window) on: #mouseUp send: each second to: aFileList ]. option _ aProject world valueOfProperty: #SuperSwikiPublishOptions ifAbsent: [#initialDirectoryList]. aProject world removeProperty: #SuperSwikiPublishOptions. (treePane _ aFileList morphicDirectoryTreePaneFiltered: option) extent: 350@300; retractable: false; borderWidth: 0. window addARowCentered: { window fancyText: 'Publish This Project' ofSize: 21 color: textColor1 }; addARowCentered: { buttons first. (Morph new extent: 30@5) color: Color transparent. buttons second }; addARowCentered: { (window inAColumn: {(ProjectViewMorph on: aProject) lock}) layoutInset: 4}; addARowCentered: { window fancyText: 'Please select a folder' ofSize: 21 color: Color blue }; addARow: { ( window inAColumn: { (pane2 _ window inARow: {window inAColumn: {treePane}}) useRoundedCorners; layoutInset: 6 } ) layoutInset: 10 }. window fullBounds. window fillWithRamp: self blueRamp1 oriented: 0.65. pane2 fillWithRamp: self blueRamp3 oriented: (0.7 @ 0.35). buttons do: [ :each | each fillWithRamp: self blueRamp2 oriented: (0.75 @ 0). ]. window setProperty: #morphicLayerNumber toValue: 11. aFileList postOpen. ^ window ! ! !FilePlugin methodsFor: 'file primitives' stamp: 'ar 2/5/2001 18:09'! primitiveFileDelete | namePointer nameIndex nameSize | self var: 'nameIndex' type: 'char *'. self export: true. namePointer _ interpreterProxy stackValue: 0. (interpreterProxy isBytes: namePointer) ifFalse:[^interpreterProxy primitiveFail]. nameIndex _ interpreterProxy firstIndexableField: namePointer. nameSize _ interpreterProxy byteSizeOf: namePointer. (self ioCanDeleteFile: nameIndex OfSize: nameSize) ifFalse:[^interpreterProxy primitiveFail]. self sqFileDeleteName: (self cCoerce: nameIndex to: 'int') Size: nameSize. interpreterProxy failed ifFalse:[interpreterProxy pop: 1. "pop name, leave rcvr on stack" ]. ! ! !FilePlugin methodsFor: 'file primitives' stamp: 'ar 2/6/2001 17:53'! primitiveFileFlush | file | self var: 'file' declareC: 'SQFile *file'. self export: true. file _ self fileValueOf: (interpreterProxy stackValue: 0). interpreterProxy failed ifFalse:[self sqFileFlush: file]. interpreterProxy failed ifFalse: [interpreterProxy pop: 1].! ! !FilePlugin methodsFor: 'file primitives' stamp: 'ar 2/5/2001 18:09'! primitiveFileOpen | writeFlag namePointer filePointer file nameIndex nameSize | self var: 'file' declareC: 'SQFile *file'. self var: 'nameIndex' type:'char *'. self export: true. writeFlag _ interpreterProxy booleanValueOf: (interpreterProxy stackValue: 0). namePointer _ interpreterProxy stackValue: 1. (interpreterProxy isBytes: namePointer) ifFalse:[^interpreterProxy primitiveFail]. filePointer _ interpreterProxy instantiateClass: (interpreterProxy classByteArray) indexableSize: self fileRecordSize. file _ self fileValueOf: filePointer. nameIndex _ interpreterProxy firstIndexableField: namePointer. nameSize _ interpreterProxy byteSizeOf: namePointer. (self ioCanOpenFile: nameIndex OfSize: nameSize Writable: writeFlag) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self cCode: 'sqFileOpen(file, (int)nameIndex, nameSize, writeFlag)'. ]. interpreterProxy failed ifFalse:[ interpreterProxy pop: 3. "rcvr, name, writeFlag" interpreterProxy push: filePointer. ].! ! !FilePlugin methodsFor: 'file primitives' stamp: 'ar 2/5/2001 18:10'! primitiveFileRename | oldNamePointer newNamePointer oldNameIndex oldNameSize newNameIndex newNameSize | self var: 'oldNameIndex' type: 'char *'. self var: 'newNameIndex' type: 'char *'. self export: true. newNamePointer _ interpreterProxy stackValue: 0. oldNamePointer _ interpreterProxy stackValue: 1. ((interpreterProxy isBytes: newNamePointer) and:[ (interpreterProxy isBytes: oldNamePointer)]) ifFalse:[^interpreterProxy primitiveFail]. newNameIndex _ interpreterProxy firstIndexableField: newNamePointer. newNameSize _ interpreterProxy byteSizeOf: newNamePointer. oldNameIndex _ interpreterProxy firstIndexableField: oldNamePointer. oldNameSize _ interpreterProxy byteSizeOf: oldNamePointer. (self ioCanRenameFile: oldNameIndex OfSize: oldNameSize) ifFalse:[^interpreterProxy primitiveFail]. self sqFileRenameOld: (self cCoerce: oldNameIndex to: 'int') Size: oldNameSize New: (self cCoerce: newNameIndex to: 'int') Size: newNameSize. interpreterProxy failed ifFalse:[ interpreterProxy pop: 2. "pop new and old names, leave rcvr on stack" ].! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar 2/6/2001 12:55'! primitiveDirectoryCreate | dirName dirNameIndex dirNameSize | self var: #dirNameIndex type: 'char *'. self export: true. dirName _ interpreterProxy stackValue: 0. (interpreterProxy isBytes: dirName) ifFalse:[^interpreterProxy primitiveFail]. dirNameIndex _ interpreterProxy firstIndexableField: dirName. dirNameSize _ interpreterProxy byteSizeOf: dirName. (self ioCanCreatePath: dirNameIndex OfSize: dirNameSize) ifFalse:[^interpreterProxy primitiveFail]. (self cCode: 'dir_Create((char *) dirNameIndex, dirNameSize)' inSmalltalk:[false]) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: 1. "pop dirName; leave rcvr on stack"! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar 2/5/2001 18:04'! primitiveDirectoryDelete | dirName dirNameIndex dirNameSize | self var: #dirNameIndex type: 'char *'. self export: true. dirName _ interpreterProxy stackValue: 0. (interpreterProxy isBytes: dirName) ifFalse:[^interpreterProxy primitiveFail]. dirNameIndex _ interpreterProxy firstIndexableField: dirName. dirNameSize _ interpreterProxy byteSizeOf: dirName. (self ioCanDeletePath: dirNameIndex OfSize: dirNameSize) ifFalse:[^interpreterProxy primitiveFail]. (self cCode: 'dir_Delete((char *) dirNameIndex, dirNameSize)' inSmalltalk:[false]) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: 1. "pop dirName; leave rcvr on stack"! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar 2/5/2001 18:14'! primitiveDirectoryGetMacTypeAndCreator | creatorString typeString fileName creatorStringIndex typeStringIndex fileNameIndex fileNameSize | self var: 'creatorStringIndex' type: 'char *'. self var: 'typeStringIndex' type: 'char *'. self var: 'fileNameIndex' type: 'char *'. self export: true. creatorString _ interpreterProxy stackValue: 0. typeString _ interpreterProxy stackValue: 1. fileName _ interpreterProxy stackValue: 2. ((interpreterProxy isBytes: creatorString) and: [(interpreterProxy byteSizeOf: creatorString) = 4]) ifFalse:[^interpreterProxy primitiveFail]. ((interpreterProxy isBytes: typeString) and: [(interpreterProxy byteSizeOf: typeString) = 4]) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isBytes: fileName) ifFalse:[^interpreterProxy primitiveFail]. creatorStringIndex _ interpreterProxy firstIndexableField: creatorString. typeStringIndex _ interpreterProxy firstIndexableField: typeString. fileNameIndex _ interpreterProxy firstIndexableField: fileName. fileNameSize _ interpreterProxy byteSizeOf: fileName. (self ioCanGetFileType: fileNameIndex OfSize: fileNameSize) ifFalse:[^interpreterProxy primitiveFail]. (self cCode: 'dir_GetMacFileTypeAndCreator( (char *) fileNameIndex, fileNameSize, (char *) typeStringIndex, (char *) creatorStringIndex)' inSmalltalk:[true]) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: 3. "pop filename, type, creator; leave rcvr on stack" ! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar 2/5/2001 18:07'! primitiveDirectoryLookup | index pathName pathNameIndex pathNameSize status entryName entryNameSize createDate modifiedDate dirFlag fileSize | self var: 'entryName' declareC: 'char entryName[256]'. self var: 'pathNameIndex' type: 'char *'. self export: true. index _ interpreterProxy stackIntegerValue: 0. pathName _ interpreterProxy stackValue: 1. (interpreterProxy isBytes: pathName) ifFalse:[^interpreterProxy primitiveFail]. pathNameIndex _ interpreterProxy firstIndexableField: pathName. pathNameSize _ interpreterProxy byteSizeOf: pathName. (self ioCanListPath: pathNameIndex OfSize: pathNameSize) ifTrue:[ status _ self cCode: 'dir_Lookup( (char *) pathNameIndex, pathNameSize, index, entryName, &entryNameSize, &createDate, &modifiedDate, &dirFlag, &fileSize)'. ] ifFalse:[ status _ DirNoMoreEntries. ]. interpreterProxy failed ifTrue:[^nil]. status = DirNoMoreEntries ifTrue: [ "no more entries; return nil" interpreterProxy pop: 3. "pop pathName, index, rcvr" interpreterProxy push: interpreterProxy nilObject. ^ nil ]. status = DirBadPath ifTrue: [ ^ interpreterProxy primitiveFail ]. "bad path" interpreterProxy pop: 3. "pop pathName, index, rcvr" interpreterProxy push: (self makeDirEntryName: entryName size: entryNameSize createDate: createDate modDate: modifiedDate isDir: dirFlag fileSize: fileSize).! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar 2/5/2001 18:08'! primitiveDirectorySetMacTypeAndCreator | creatorString typeString fileName creatorStringIndex typeStringIndex fileNameIndex fileNameSize | self var: 'creatorStringIndex' type: 'char *'. self var: 'typeStringIndex' type: 'char *'. self var: 'fileNameIndex' type: 'char *'. self export: true. creatorString _ interpreterProxy stackValue: 0. typeString _ interpreterProxy stackValue: 1. fileName _ interpreterProxy stackValue: 2. ((interpreterProxy isBytes: creatorString) and: [(interpreterProxy byteSizeOf: creatorString) = 4]) ifFalse:[^interpreterProxy primitiveFail]. ((interpreterProxy isBytes: typeString) and: [(interpreterProxy byteSizeOf: typeString) = 4]) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isBytes: fileName) ifFalse:[^interpreterProxy primitiveFail]. creatorStringIndex _ interpreterProxy firstIndexableField: creatorString. typeStringIndex _ interpreterProxy firstIndexableField: typeString. fileNameIndex _ interpreterProxy firstIndexableField: fileName. fileNameSize _ interpreterProxy byteSizeOf: fileName. (self ioCanSetFileType: fileNameIndex OfSize: fileNameSize) ifFalse:[^interpreterProxy primitiveFail]. (self cCode: 'dir_SetMacFileTypeAndCreator( (char *) fileNameIndex, fileNameSize, (char *) typeStringIndex, (char *) creatorStringIndex)' inSmalltalk:[true]) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: 3. "pop filename, type, creator; leave rcvr on stack" ! ! !FilePlugin methodsFor: 'security primitives' stamp: 'ar 2/6/2001 14:00'! primitiveDisableFileAccess self export: true. self ioDisableFileAccess. interpreterProxy failed ifFalse:[interpreterProxy pop: 1].! ! !FilePlugin methodsFor: 'security primitives' stamp: 'ar 2/6/2001 14:01'! primitiveHasFileAccess self export: true. interpreterProxy pop: 1. interpreterProxy pushBool: self ioHasFileAccess.! ! !FilePlugin class methodsFor: 'translation' stamp: 'ar 2/6/2001 17:54'! headerFile ^'/* File support definitions */ /* squeak file record; see sqFilePrims.c for details */ typedef struct { FILE *file; int sessionID; int writable; int fileSize; int lastOp; /* 0 = uncommitted, 1 = read, 2 = write */ } SQFile; /* file i/o */ int sqFileAtEnd(SQFile *f); int sqFileClose(SQFile *f); int sqFileDeleteNameSize(int sqFileNameIndex, int sqFileNameSize); int sqFileGetPosition(SQFile *f); int sqFileInit(void); int sqFileShutdown(void); int sqFileOpen(SQFile *f, int sqFileNameIndex, int sqFileNameSize, int writeFlag); int sqFileReadIntoAt(SQFile *f, int count, int byteArrayIndex, int startIndex); int sqFileRenameOldSizeNewSize(int oldNameIndex, int oldNameSize, int newNameIndex, int newNameSize); int sqFileSetPosition(SQFile *f, int position); int sqFileSize(SQFile *f); int sqFileValid(SQFile *f); int sqFileWriteFromAt(SQFile *f, int count, int byteArrayIndex, int startIndex); int sqFileFlush(SQFile *f); /* directories */ int dir_Create(char *pathString, int pathStringLength); int dir_Delete(char *pathString, int pathStringLength); int dir_Delimitor(void); int dir_Lookup(char *pathString, int pathStringLength, int index, /* outputs: */ char *name, int *nameLength, int *creationDate, int *modificationDate, int *isDirectory, int *sizeIfFile); int dir_PathToWorkingDir(char *pathName, int pathNameMax); int dir_SetMacFileTypeAndCreator(char *filename, int filenameSize, char *fType, char *fCreator); int dir_GetMacFileTypeAndCreator(char *filename, int filenameSize, char *fType, char *fCreator); /*** security traps ***/ /* directory access */ int ioCanCreatePathOfSize(char* dirNameIndex, int dirNameSize); int ioCanListPathOfSize(char* dirNameIndex, int dirNameSize); int ioCanDeletePathOfSize(char* dirNameIndex, int dirNameSize); /* file access */ int ioCanOpenFileOfSizeWritable(char* fileNameIndex, int fileNameSize, int writeFlag); int ioCanDeleteFileOfSize(char* fileNameIndex, int fileNameSize); int ioCanRenameFileOfSize(char* fileNameIndex, int fileNameSize); int ioCanGetFileTypeOfSize(char* fileNameIndex, int fileNameSize); int ioCanSetFileTypeOfSize(char* fileNameIndex, int fileNameSize); /* top level functions */ int ioDisableFileAccess(void); int ioHasFileAccess(void); #ifdef DISABLE_SECURITY #define ioCanCreatePathOfSize(name, size) 1 #define ioCanListPathOfSize(name, size) 1 #define ioCanDeletePathOfSize(name, size) 1 #define ioCanOpenFileOfSizeWritable(name, size, writeFlag) 1 #define ioCanDeleteFileOfSize(name, size) 1 #define ioCanRenameFileOfSize(name, size) 1 #define ioCanGetFileTypeOfSize(name, size) 1 #define ioCanSetFileTypeOfSize(name, size) 1 #define ioDisableFileAccess() 1 #define ioHasFileAccess() 1 #endif /* DISABLE_SECURITY */ '.! ! !FilePluginSimulator methodsFor: 'as yet unclassified' stamp: 'ar 2/6/2001 17:54'! sqFileFlush: file ^interpreterProxy sqFileFlush: file! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 19:23'! ioCanCreatePath: dirNameIndex OfSize: dirNameSize "Return true if we're allowed to create a directory with the given name" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:16'! ioCanDeleteFile: nameIndex OfSize: nameSize "Return true if we're allowed to delete the file with the given name" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:16'! ioCanDeletePath: dirNameIndex OfSize: dirNameSize "Return true if we're allowed to delete the directory with the given name" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:16'! ioCanGetFileType: fileNameIndex OfSize: fileNameSize "Return true if we're allowed to retrieve the (mac) file type of the given file." ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:17'! ioCanListPath: pathNameIndex OfSize: pathNameSize "Return true if we're allowed to list the contents of the given directory" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:17'! ioCanOpenFile: nameIndex OfSize: nameSize Writable: writeFlag "Return true if we're allowed to open the given file (possibly in write mode)" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:17'! ioCanRenameFile: oldNameIndex OfSize: oldNameSize "Return true if we're allowed to rename the given file" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:18'! ioCanSetFileType: fileNameIndex OfSize: fileNameSize "Return true if we're allowed to set the (mac) file type and creator on the given file" ^true! ! !FlapTab methodsFor: 'show & hide' stamp: 'sw 2/12/2001 16:49'! lastReferentThickness: anInteger "Set the last remembered referent thickness to the given integer" lastReferentThickness _ anInteger! ! !FlapTab methodsFor: 'show & hide' stamp: 'sw 2/12/2001 16:59'! openFully "Make an educated guess at how wide or tall we are to be, and open to that thickness" | thickness amt | thickness _ referent boundingBoxOfSubmorphs extent max: (100 @ 100). self applyThickness: (amt _ self orientation == #horizontal ifTrue: [thickness y] ifFalse: [thickness x]). self lastReferentThickness: amt. self showFlap! ! !FlapTab methodsFor: 'show & hide' stamp: 'sw 2/12/2001 17:04'! tabSelected "The user clicked on the tab. Show or hide the flap. Try to be a little smart about a click on a tab whose flap is open but only just barely." dragged == true ifTrue: [^ dragged _ false]. self flapShowing ifTrue: [self referentThickness < 23 "an attractive number" ifTrue: [self openFully] ifFalse: [self hideFlap]] ifFalse: [self showFlap]! ! !Form class methodsFor: 'mode constants' stamp: 'hg 1/29/2001 17:28'! rgbMul "Answer the integer denoting 'Multiply each color component, their values regarded as fractions of 1' rule." ^ 37! ! !Form class methodsFor: 'BMP file reading' stamp: 'ar 2/5/2001 00:02'! bmpColorsFrom: aBinaryStream count: colorCount depth: depth "Read colorCount BMP color map entries from the given binary stream. Answer an array of Colors." | maxLevel colors b g r | depth = 16 ifTrue:[^nil]. colorCount = 0 ifTrue: [ "this BMP file does not have a color map" "default monochrome color map" depth = 1 ifTrue: [^ Array with: Color white with: Color black]. "default gray-scale color map" maxLevel _ (2 raisedTo: depth) - 1. ^ (0 to: maxLevel) collect: [:level | Color gray: (level asFloat / maxLevel)]]. colors _ Array new: colorCount. 1 to: colorCount do: [:i | b _ aBinaryStream next. g _ aBinaryStream next. r _ aBinaryStream next. aBinaryStream skip: 1. colors at: i put: (Color r: r g: g b: b range: 255)]. ^ colors ! ! !Form class methodsFor: 'BMP file reading' stamp: 'ar 2/5/2001 00:15'! bmpPixelDataFrom: aBinaryStream width: w height: h depth: d colors: colors "Read uncompressed pixel data of depth d from the given BMP stream, where d is 1, 4, 8, or 16" | form bytesPerRow pixelData pixelLine startIndex cm word formBits | (colors == nil) ifTrue:[ form _ Form extent: w@h depth: d. ] ifFalse:[ form _ ColorForm extent: w@h depth: d. form colors: colors. ]. bytesPerRow _ (((d* w) + 31) // 32) * 4. pixelData _ ByteArray new: bytesPerRow * h. h to: 1 by: -1 do: [:y | pixelLine _ aBinaryStream next: bytesPerRow. startIndex _ ((y - 1) * bytesPerRow) + 1. pixelData replaceFrom: startIndex to: startIndex + bytesPerRow - 1 with: pixelLine startingAt: 1]. form bits copyFromByteArray: pixelData. d = 16 ifTrue:[ "swap red and blue components" cm _ Bitmap new: (1 << 15). word _ 0. 0 to: 31 do:[:r| 0 to: 31 do:[:g| 0 to: 31 do:[:b| cm at: (word _ word + 1) put: (b bitShift: 10) + (g bitShift: 5) + r]]]. cm at: 1 put: 1. formBits _ form bits. 1 to: formBits size do:[:i| word _ formBits at: i. word _ (cm at: (word bitAnd: 16r7FFF) + 1) + ((cm at: ((word bitShift: -16) bitAnd: 16r7FFF) +1) bitShift: 16). formBits at: i put: word. ]. ]. ^ form ! ! !Form class methodsFor: 'BMP file reading' stamp: 'ar 2/4/2001 21:54'! fromBMPFile: aBinaryStream "Read a BMP format image from the given binary stream." "Form fromBMPFile: (HTTPSocket httpGet: 'http://anHTTPServer/squeak/squeakers.bmp' accept: 'image/bmp')" | fType fSize reserved pixDataStart hdrSize w h planes d compressed colorCount colors colorForm | (aBinaryStream isMemberOf: String) ifTrue: [^ nil]. "a network error message" aBinaryStream binary. fType _ aBinaryStream nextLittleEndianNumber: 2. fSize _ aBinaryStream nextLittleEndianNumber: 4. reserved _ aBinaryStream nextLittleEndianNumber: 4. pixDataStart _ aBinaryStream nextLittleEndianNumber: 4. hdrSize _ aBinaryStream nextLittleEndianNumber: 4. w _ aBinaryStream nextLittleEndianNumber: 4. h _ aBinaryStream nextLittleEndianNumber: 4. planes _ aBinaryStream nextLittleEndianNumber: 2. d _ aBinaryStream nextLittleEndianNumber: 2. compressed _ aBinaryStream nextLittleEndianNumber: 4. aBinaryStream nextLittleEndianNumber: 4. "biSizeImage" aBinaryStream nextLittleEndianNumber: 4. "biXPelsPerMeter" aBinaryStream nextLittleEndianNumber: 4. "biYPelsPerMeter" colorCount _ aBinaryStream nextLittleEndianNumber: 4. aBinaryStream nextLittleEndianNumber: 4. "biClrImportant" ((fType = 19778) & (reserved = 0) & (planes = 1) & (hdrSize = 40) & (fSize <= aBinaryStream size)) ifFalse: [self error: 'Bad BMP file header']. compressed = 0 ifFalse: [self error: 'Can only read uncompressed BMP files']. d = 24 ifTrue: [ aBinaryStream position: pixDataStart. ^ self bmp24BitPixelDataFrom: aBinaryStream width: w height: h]. "read the color map" "Note: some programs (e.g. Photoshop 4.0) apparently do not set colorCount; assume that any data between the end of the header and the start of the pixel data is the color map" colorCount _ (pixDataStart - 54) // 4. colors _ self bmpColorsFrom: aBinaryStream count: colorCount depth: d. "read the pixel data" aBinaryStream position: pixDataStart. colorForm _ self bmpPixelDataFrom: aBinaryStream width: w height: h depth: d colors: colors. ^ colorForm ! ! !FormCanvas methodsFor: 'drawing-rectangles' stamp: 'RAA 2/6/2001 14:00'! infiniteFillRectangle: aRectangle fillStyle: aFillStyle | additionalOffset rInPortTerms clippedPort targetTopLeft clipOffset ex | "this is a bit of a kludge to get the form to be aligned where I *think* it should be. something better is needed, but not now" additionalOffset _ 0@0. ex _ aFillStyle form extent. rInPortTerms _ aRectangle translateBy: origin. clippedPort _ port clippedBy: rInPortTerms. targetTopLeft _ clippedPort clipRect topLeft truncateTo: ex. clipOffset _ rInPortTerms topLeft - targetTopLeft. additionalOffset _ (clipOffset \\ ex) - ex. ^aFillStyle displayOnPort: clippedPort offsetBy: additionalOffset ! ! !FormCanvas methodsFor: 'drawing-general' stamp: 'di 2/6/2001 14:03'! roundCornersOf: aMorph during: aBlock aMorph wantsRoundedCorners ifFalse:[^aBlock value]. (self seesNothingOutside: (CornerRounder rectWithinCornersOf: aMorph bounds)) ifTrue: ["Don't bother with corner logic if the region is inside them" ^ aBlock value]. CornerRounder roundCornersOf: aMorph on: self displayBlock: aBlock borderWidth: aMorph borderWidthForRounding corners: aMorph roundedCorners! ! !HTTPSocket class methodsFor: 'get the page' stamp: 'RAA 2/16/2001 18:26'! httpPostToSuperSwiki: url args: argsDict accept: mimeType request: requestString | serverName serverAddr s header length bare page list firstData aStream port specifiedServer type mimeBorder contentsData | Socket initializeNetwork. "parse url" bare _ (url asLowercase beginsWith: 'http://') ifTrue: [url copyFrom: 8 to: url size] ifFalse: [url]. serverName _ bare copyUpTo: $/. specifiedServer _ serverName. (serverName includes: $:) ifFalse: [ port _ self defaultPort ] ifTrue: [ port _ (serverName copyFrom: (serverName indexOf: $:) + 1 to: serverName size) asNumber. serverName _ serverName copyUpTo: $:. ]. page _ bare copyFrom: (bare indexOf: $/ ifAbsent: [^'error']) to: bare size. page size = 0 ifTrue: [page _ '/']. HTTPProxyServer ifNotNil: [ page _ 'http://', serverName, ':', port printString, page. "put back together" serverName _ HTTPProxyServer. port _ HTTPProxyPort]. mimeBorder _ '---------SuperSwiki',Time millisecondClockValue printString,'-----'. contentsData _ String streamContents: [ :strm | strm nextPutAll: mimeBorder, CrLf. argsDict associationsDo: [:assoc | assoc value do: [ :value | strm nextPutAll: 'Content-disposition: form-data; name="', assoc key, '"'; nextPutAll: CrLf; nextPutAll: CrLf; nextPutAll: value; nextPutAll: CrLf; nextPutAll: CrLf; nextPutAll: mimeBorder; nextPutAll: CrLf. ] ]. ]. "make the request" self retry: [serverAddr _ NetNameResolver addressForName: serverName timeout: 20. serverAddr ~~ nil] asking: 'Trouble resolving server name. Keep trying?' ifGiveUp: [^ 'Could not resolve the server named: ', serverName]. s _ HTTPSocket new. s connectTo: serverAddr port: port. s waitForConnectionUntil: self standardDeadline. s sendCommand: 'POST ', page, ' HTTP/1.1', CrLf, (mimeType ifNotNil: ['ACCEPT: ', mimeType, CrLf] ifNil: ['']), 'ACCEPT: text/html', CrLf, "Always accept plain text" HTTPBlabEmail, "may be empty" requestString, "extra user request. Authorization" 'User-Agent: Squeak 2.9', CrLf, 'Content-type: multipart/form-data; boundary=', mimeBorder, CrLf, 'Content-length: ', contentsData size printString, CrLf, 'Host: ', specifiedServer, CrLf. "blank line automatically added" s sendCommand: contentsData. list _ s getResponseUpTo: CrLf, CrLf. "list = header, CrLf, CrLf, beginningOfData" header _ list at: 1. firstData _ list at: 3. header isEmpty ifTrue: [ s destroy. ^'no response' ]. s header: header. length _ s getHeader: 'content-length'. length ifNotNil: [ length _ length asNumber ]. type _ s getHeader: 'content-type'. aStream _ s getRestOfBuffer: firstData totalLength: length. s responseCode = '401' ifTrue: [^ header, aStream contents]. s destroy. "Always OK to destroy!!" ^ MIMEDocument contentType: type content: aStream contents url: url! ! !HaloMorph methodsFor: 'private' stamp: 'di 2/15/2001 22:09'! doGrow: evt with: growHandle "Called while the mouse is down in the grow handle" | newExtent extentToUse | evt hand obtainHalo: self. newExtent _ (target pointFromWorld: (target griddedPoint: evt cursorPoint - positionOffset)) - target topLeft. evt shiftPressed ifTrue: [newExtent _ (newExtent x max: newExtent y) asPoint]. (newExtent x = 0 or: [newExtent y = 0]) ifTrue: [^ self]. target renderedMorph extent: (extentToUse _ newExtent). growHandle position: evt cursorPoint - (growHandle extent // 2). self layoutChanged. (self valueOfProperty: #commandInProgress) doIfNotNil: [:cmd | "Update the final extent" cmd redoTarget: target selector: #extent: argument: extentToUse] ! ! !HandMorph methodsFor: 'drawing' stamp: 'ar 2/11/2001 16:34'! fullDrawOn: aCanvas "A HandMorph has unusual drawing requirements: 1. the hand itself (i.e., the cursor) appears in front of its submorphs 2. morphs being held by the hand cast a shadow on the world/morphs below The illusion is that the hand plucks up morphs and carries them above the world." "Note: This version caches an image of the morphs being held by the hand for better performance. This cache is invalidated if one of those morphs changes." | disableCaching subBnds roundCorners rounded | self visible ifFalse:[^self]. disableCaching _ false. disableCaching ifTrue: [self nonCachingFullDrawOn: aCanvas. ^ self]. submorphs isEmpty ifTrue: [cacheCanvas _ nil. ^ self drawOn: aCanvas]. "just draw the hand itself" subBnds _ Rectangle merging: (submorphs collect: [:m | m fullBounds]). self updateCacheCanvas: aCanvas. (cacheCanvas == nil or: [cachedCanvasHasHoles and: [cacheCanvas depth = 1]]) ifTrue: ["could not use caching due to translucency; do full draw" self nonCachingFullDrawOn: aCanvas. ^ self]. "--> begin rounded corners hack <---" roundCorners _ (cachedCanvasHasHoles == false) and:[ submorphs size = 1 and:[submorphs first wantsRoundedCorners]]. roundCorners ifTrue:[ rounded _ submorphs first. aCanvas asShadowDrawingCanvas translateBy: self shadowOffset during:[:shadowCanvas| shadowCanvas roundCornersOf: rounded during:[ (subBnds areasOutside: (rounded boundsWithinCorners translateBy: self shadowOffset negated)) do: [:r | shadowCanvas fillRectangle: r color: Color black]]]. aCanvas roundCornersOf: rounded during:[ aCanvas drawImage: cacheCanvas form at: subBnds origin sourceRect: cacheCanvas form boundingBox]. ^self drawOn: aCanvas. "draw the hand itself in front of morphs"]. "--> end rounded corners hack <---" "draw the shadow" aCanvas asShadowDrawingCanvas translateBy: self shadowOffset during:[:shadowCanvas| cachedCanvasHasHoles ifTrue: ["Have to draw the real shadow of the form" shadowCanvas paintImage: cacheCanvas form at: subBnds origin] ifFalse: ["Much faster if only have to shade the edge of a solid rectangle" (subBnds areasOutside: (subBnds translateBy: self shadowOffset negated)) do: [:r | shadowCanvas fillRectangle: r color: Color black]]]. "draw morphs in front of the shadow using the cached Form" cachedCanvasHasHoles ifTrue: [aCanvas paintImage: cacheCanvas form at: subBnds origin] ifFalse: [aCanvas drawImage: cacheCanvas form at: subBnds origin sourceRect: cacheCanvas form boundingBox]. self drawOn: aCanvas. "draw the hand itself in front of morphs" ! ! !HandMorph methodsFor: 'drawing' stamp: 'ar 2/11/2001 16:35'! updateCacheCanvas: aCanvas "Update the cached image of the morphs being held by this hand." | subBnds rectList nPix | "Note: The following is an attempt to quickly get out if there's no change" subBnds _ Rectangle merging: (submorphs collect: [:m | m fullBounds]). rectList _ damageRecorder invalidRectsFullBounds: (0@0 extent: subBnds extent). (rectList isEmpty and:[cacheCanvas notNil and:[cacheCanvas extent = subBnds extent]]) ifTrue:[^self]. "Always check for real translucency -- can't be cached in a form" self allMorphsDo: [:m | m hasTranslucentColor ifTrue: [ cacheCanvas _ nil. cachedCanvasHasHoles _ true. ^ self]]. (cacheCanvas == nil or: [cacheCanvas extent ~= subBnds extent]) ifTrue: [ cacheCanvas _ (aCanvas allocateForm: subBnds extent) getCanvas. cacheCanvas translateBy: subBnds origin negated during:[:tempCanvas| self drawSubmorphsOn: tempCanvas]. self submorphsDo: [:m | (m areasRemainingToFill: subBnds) isEmpty ifTrue: [^ cachedCanvasHasHoles _ false]]. nPix _ cacheCanvas form tallyPixelValues at: 1. "--> begin rounded corners hack <---" (nPix = 48 and:[submorphs size = 1 and:[submorphs first wantsRoundedCorners]]) ifTrue:[cachedCanvasHasHoles _ false] ifFalse:[cachedCanvasHasHoles _ nPix > 0]. "--> end rounded corners hack <---" ^ self]. "incrementally update the cache canvas" rectList _ damageRecorder invalidRectsFullBounds: (0@0 extent: subBnds extent). damageRecorder reset. rectList do: [:r | cacheCanvas translateTo: subBnds origin negated clippingTo: r during:[:c| c fillColor: Color transparent. "clear to transparent" self drawSubmorphsOn: c]].! ! !HandMorph methodsFor: 'event handling' stamp: 'ar 2/9/2001 14:03'! processEvents "Process user input events from the local input devices." | evt evtBuf type hadAny | hadAny _ false. [(evtBuf _ Sensor nextEvent) == nil] whileFalse:[ evt _ nil. "for unknown event types" type _ evtBuf at: 1. (type = EventTypeMouse) ifTrue:[evt _ self generateMouseEvent: evtBuf]. (type = EventTypeKeyboard) ifTrue:[evt _ self generateKeyboardEvent: evtBuf]. (type = EventTypeDragDropFiles) ifTrue:[evt _ self generateDropFilesEvent: evtBuf]. "All other events are ignored" evt == nil ifFalse:[ "Finally, handle it" self handleEvent: evt. hadAny _ true. "For better user feedback, return immediately after a mouse event has been processed." evt isMouse ifTrue:[^self]. ]. ]. "note: if we come here we didn't have any mouse events" (mouseClickState notNil) ifTrue:[ "No mouse events during this cycle. Make sure click states time out accordingly" mouseClickState handleEvent: lastMouseEvent asMouseMove from: self]. hadAny ifFalse:[ "No pending events. Make sure z-order is up to date" self mouseOverHandler processMouseOver: lastMouseEvent. ].! ! !HandMorph methodsFor: 'grabbing/dropping' stamp: 'ar 2/6/2001 22:15'! grabMorph: aMorph from: formerOwner "Grab the given morph (i.e., add it to this hand and remove it from its current owner) without changing its position. This is used to pick up a morph under the hand's current position, versus attachMorph: which is used to pick up a morph that may not be near this hand." | grabbed offset targetPoint grabTransform fullTransform | self releaseMouseFocus. "Break focus" grabbed _ aMorph. "Compute the transform to apply to the grabbed morph" grabTransform _ formerOwner ifNil: [IdentityTransform new] ifNotNil: [formerOwner grabTransform]. "Compute the full transform for the grabbed morph" fullTransform _ formerOwner ifNil: [IdentityTransform new] ifNotNil: [formerOwner transformFrom: owner]. "targetPoint is point in aMorphs reference frame" targetPoint _ fullTransform globalPointToLocal: self position. "but current position will be determined by grabTransform, so compute offset" offset _ targetPoint - (grabTransform globalPointToLocal: self position). "apply the transform that should be used after grabbing" grabbed _ grabbed transformedBy: grabTransform. grabbed == aMorph ifFalse: [grabbed setProperty: #addedFlexAtGrab toValue: true]. "offset target to compensate for differences in transforms" grabbed position: grabbed position - offset asIntegerPoint. "And compute distance from hand's position" targetOffset _ grabbed position - self position. self addMorphBack: grabbed. grabbed justGrabbedFrom: formerOwner.! ! !HandMorph methodsFor: 'halo handling' stamp: 'RAA 2/13/2001 17:24'! removeHaloFromClick: anEvent on: aMorph | halo | halo _ self halo ifNil:[^self]. (halo target hasOwner: self) ifTrue:[^self]. (halo staysUpWhenMouseIsDownIn: aMorph) ifFalse:[ halo delete. self removeProperty: #halo. ].! ! !ImageSegment methodsFor: 'fileIn/Out' stamp: 'RAA 2/13/2001 21:10'! comeFullyUpOnReload: smartRefStream "fix up the objects in the segment that changed size. An object in the segment is the wrong size for the modern version of the class. Construct a fake class that is the old size. Replace the modern class with the old one in outPointers. Load the segment. Traverse the instances, making new instances by copying fields, and running conversion messages. Keep the new instances. Bulk forward become the old to the new. Let go of the fake objects and classes. After the install (below), arrayOfRoots is filled in. Globalize new classes. Caller may want to do some special install on certain objects in arrayOfRoots. May want to write the segment out to disk in its new form." | mapFakeClassesToReal ccFixups receiverClasses rootsToUnhiberhate myProject | self flag: #bobconv. RecentlyRenamedClasses _ nil. "in case old data hanging around" mapFakeClassesToReal _ smartRefStream reshapedClassesIn: outPointers. "Dictionary of just the ones that change shape. Substitute them in outPointers." ccFixups _ self remapCompactClasses: mapFakeClassesToReal refStrm: smartRefStream. ccFixups ifFalse: [^ self error: 'A class in the file is not compatible']. endMarker _ segment nextObject. "for enumeration of objects" endMarker == 0 ifTrue: [endMarker _ 'End' clone]. arrayOfRoots _ self loadSegmentFrom: segment outPointers: outPointers. "Can't use install. Not ready for rehashSets" mapFakeClassesToReal isEmpty ifFalse: [ self reshapeClasses: mapFakeClassesToReal refStream: smartRefStream ]. receiverClasses _ self restoreEndianness. "rehash sets" smartRefStream checkFatalReshape: receiverClasses. "Classes in this segment." arrayOfRoots do: [:importedObject | importedObject class class == Metaclass ifTrue: [self declare: importedObject]]. arrayOfRoots do: [:importedObject | (importedObject isKindOf: Project) ifTrue: [ myProject _ importedObject. importedObject ensureChangeSetNameUnique. Project addingProject: importedObject. importedObject restoreReferences. ScriptEditorMorph writingUniversalTiles: (importedObject world valueOfProperty: #universalTiles)]]. rootsToUnhiberhate _ arrayOfRoots select: [:importedObject | importedObject respondsTo: #unhibernate "ScriptEditors and ViewerFlapTabs" ]. myProject ifNotNil: [ myProject world setProperty: #thingsToUnhibernate toValue: rootsToUnhiberhate ]. mapFakeClassesToReal isEmpty ifFalse: [ mapFakeClassesToReal keys do: [:aFake | aFake indexIfCompact > 0 ifTrue: [aFake becomeUncompact]. aFake removeFromSystemUnlogged]. SystemOrganization removeEmptyCategories]. "^ self"! ! !InfiniteForm methodsFor: 'displaying' stamp: 'RAA 2/6/2001 14:02'! displayOnPort: aPort at: offset | targetBox patternBox savedMap top left | self flag: #bob. "this *may* not get called at the moment. I have been trying to figure out the right way for this to work and am using #displayOnPort:offsetBy: as my current offering - Bob" (patternForm isKindOf: Form) ifFalse: [ "patternForm is a Pattern or Color; just use it as a mask for BitBlt" ^ aPort fill: aPort clipRect fillColor: patternForm rule: Form over]. "do it iteratively" targetBox _ aPort clipRect. patternBox _ patternForm boundingBox. savedMap _ aPort colorMap. aPort sourceForm: patternForm; fillColor: nil; combinationRule: Form paint; sourceRect: (0@0 extent: patternBox extent); colorMap: (patternForm colormapIfNeededForDepth: aPort destForm depth). top _ (targetBox top truncateTo: patternBox height) "- (offset y \\ patternBox height)". left _ (targetBox left truncateTo: patternBox width) "- (offset x \\ patternBox width)". left to: (targetBox right - 1) by: patternBox width do: [:x | top to: (targetBox bottom - 1) by: patternBox height do: [:y | aPort destOrigin: x@y; copyBits]]. aPort colorMap: savedMap. ! ! !InfiniteForm methodsFor: 'displaying' stamp: 'RAA 2/6/2001 14:03'! displayOnPort: aPort offsetBy: offset | targetBox patternBox savedMap top left | "this version tries to get the form aligned where the user wants it and not just aligned with the cliprect" (patternForm isKindOf: Form) ifFalse: [ "patternForm is a Pattern or Color; just use it as a mask for BitBlt" ^ aPort fill: aPort clipRect fillColor: patternForm rule: Form over]. "do it iteratively" targetBox _ aPort clipRect. patternBox _ patternForm boundingBox. savedMap _ aPort colorMap. aPort sourceForm: patternForm; fillColor: nil; combinationRule: Form paint; sourceRect: (0@0 extent: patternBox extent); colorMap: (patternForm colormapIfNeededForDepth: aPort destForm depth). top _ (targetBox top truncateTo: patternBox height) + offset y. left _ (targetBox left truncateTo: patternBox width) + offset x. left to: (targetBox right - 1) by: patternBox width do: [:x | top to: (targetBox bottom - 1) by: patternBox height do: [:y | aPort destOrigin: x@y; copyBits]]. aPort colorMap: savedMap. ! ! !InputSensor methodsFor: 'mouse' stamp: 'ar 2/14/2001 00:02'! peekButtons ^self primMouseButtons! ! !InputSensor methodsFor: 'mouse' stamp: 'ar 2/8/2001 21:45'! peekMousePt ^self primMousePt! ! !InputSensor methodsFor: 'cursor' stamp: 'ar 2/14/2001 00:00'! peekPosition ^self cursorPoint! ! !InternalThreadNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 2/4/2001 16:12'! acceptSortedContentsFrom: aHolder "Update my page list from the given page sorter." | nameOfThisProject cachedData proj | threadName isEmpty ifTrue: [threadName _ 'I need a name']. threadName _ FillInTheBlank request: 'Name this thread.' initialAnswer: threadName. threadName isEmptyOrNil ifTrue: [^self]. listOfPages _ OrderedCollection new. aHolder submorphs doWithIndex: [:m :i | (nameOfThisProject _ m valueOfProperty: #nameOfThisProject) ifNotNil: [ cachedData _ {nameOfThisProject}. proj _ Project named: nameOfThisProject. (proj isNil or: [proj thumbnail isNil]) ifFalse: [ cachedData _ cachedData, {proj thumbnail scaledToSize: self myThumbnailSize}. ]. listOfPages add: cachedData. ]. ]. self class know: listOfPages as: threadName. self removeAllMorphs; addButtons. self world ifNil: [ self openInWorld; positionAppropriately. ]. ! ! !InternalThreadNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 2/4/2001 16:08'! addButtons | marginPt i sz data images pageNumber f m b1 b2 dot arrowWidth arrowCenter vertices arrowHeight nameMorph | self changeNoLayout. self hResizing: #rigid. self vResizing: #rigid. marginPt _ 4@4. i _ self currentIndex. sz _ self myThumbnailSize. arrowWidth _ 14. arrowHeight _ 17. data _ { {i - 1. 'Previous:'. #previousPage. #rightCenter. arrowWidth negated. 'Prev'}. {i + 1. 'Next:'. #nextPage. #leftCenter. arrowWidth. 'Next'} }. images _ data collect: [ :tuple | pageNumber _ tuple first. (pageNumber between: 1 and: listOfPages size) ifTrue: [ f _ self makeThumbnailForPageNumber: pageNumber scaledToSize: sz default: tuple sixth. f _ f deepCopy. "we're going to mess it up" arrowCenter _ f boundingBox perform: tuple fourth. vertices _ { arrowCenter - (0@arrowHeight). arrowCenter + (0@arrowHeight). arrowCenter + (tuple fifth @ 0). }. f getCanvas drawPolygon: vertices color: Color orange borderWidth: 0 borderColor: Color transparent. m _ ImageMorph new image: f. m setBalloonText: tuple second,' ',(listOfPages at: pageNumber) first. m addMouseUpActionWith: ( MessageSend receiver: self selector: tuple third ). ] ifFalse: [ f _ (Form extent: sz depth: 16) fillColor: Color lightGray. m _ ImageMorph new image: f. ]. m ]. b1 _ images first. b2 _ images second. dot _ EllipseMorph new extent: 16@16; color: Color orange lighter; borderWidth: 0. self addMorph: (b1 position: self position + marginPt). self addMorph: (b2 position: b1 topRight + (marginPt x @ 0)). self extent: (b1 bottomRight max: b2 bottomRight) - self position + marginPt. self addMorph: dot. dot align: dot center with: b1 bounds rightCenter + ((marginPt x @ 0) // 2). dot setBalloonText: threadName,' more commands'. dot on: #mouseDown send: #moreCommands to: self. self fullBounds. self addMorph: (nameMorph _ SquishedNameMorph new). nameMorph target: self getSelector: #threadName setSelector: nil; color: Color transparent; width: self width; height: 15; align: nameMorph bottomLeft with: self bottomLeft. ! ! !InternalThreadNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 2/4/2001 11:41'! editThisThread | sorter | sorter _ ProjectSorterMorph new. sorter navigator: self listOfPages: listOfPages. self currentWorld addMorphFront: sorter. sorter align: sorter center with: self currentWorld center. self delete. ! ! !InternalThreadNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 2/4/2001 09:57'! insertNewProject | newProj me | [newProj _ Project newMorphicOn: nil.] on: ProjectViewOpenNotification do: [ :ex | ex resume: false]. EToyProjectDetailsMorph getFullInfoFor: newProj ifValid: [ me _ CurrentProjectRefactoring currentProjectName. listOfPages withIndexDo: [ :each :index | each first = me ifTrue: [ listOfPages add: {newProj name} afterIndex: index. ^self switchToThread: threadName ]. ]. listOfPages add: {newProj name} afterIndex: listOfPages size. ^self switchToThread: threadName ] expandedFormat: false. ! ! !InternalThreadNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 2/4/2001 09:38'! makeThumbnailForPageNumber: pageNumber scaledToSize: sz default: aString | cachedData proj tn label | cachedData _ listOfPages at: pageNumber. proj _ Project named: cachedData first. (proj isNil or: [proj thumbnail isNil]) ifTrue: [ cachedData size >= 2 ifTrue: [^cachedData second]. tn _ Form extent: sz depth: 8. tn fillColor: Color veryLightGray. label _ (StringMorph contents: aString) imageForm. label displayOn: tn at: tn center - (label extent // 2) rule: Form paint. ^tn ]. tn _ proj thumbnail scaledToSize: sz. cachedData size < 2 ifTrue: [ cachedData _ cachedData,#(0). listOfPages at: pageNumber put: cachedData. ]. cachedData at: 2 put: tn. ^tn ! ! !InternalThreadNavigationMorph methodsFor: 'as yet unclassified' stamp: 'RAA 2/4/2001 16:16'! myThumbnailSize ^52@39! ! !Interpreter methodsFor: 'float primitives' stamp: 'yo 2/1/2001 23:49'! primitiveExponent "Exponent part of this float." | rcvr frac pwr | self var: #rcvr declareC: 'double rcvr'. self var: #frac declareC: 'double frac'. rcvr _ self popFloat. successFlag ifTrue: [ "rcvr = frac * 2^pwr, where frac is in [0.5..1.0)" self cCode: 'frac = frexp(rcvr, &pwr)' inSmalltalk: [pwr _ rcvr exponent]. self pushInteger: pwr - 1] ifFalse: [self unPop: 1].! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'ar 2/5/2001 17:24'! primitiveScreenDepth "Return a SmallInteger indicating the current depth of the OS screen" | depth | self export: true. depth _ self ioScreenDepth. (self failed or:[depth <= 0]) ifTrue:[^self primitiveFail]. self pop: 1. self pushInteger: depth.! ! !Interpreter methodsFor: 'other primitives' stamp: 'ar 2/5/2001 18:31'! primitiveImageName "When called with a single string argument, record the string as the current image file name. When called with zero arguments, return a string containing the current image file name." | s sz | argumentCount = 1 ifTrue: [ self ioCanRenameImage ifFalse:[^self primitiveFail]. s _ self stackTop. self assertClassOf: s is: (self splObj: ClassString). successFlag ifTrue: [ sz _ self stSizeOf: s. self imageNamePut: (s + BaseHeaderSize) Length: sz. self pop: 1. "pop s, leave rcvr on stack" ]. ] ifFalse: [ sz _ self imageNameSize. s _ self instantiateClass: (self splObj: ClassString) indexableSize: sz. self imageNameGet: (s + BaseHeaderSize) Length: sz. self pop: 1. "rcvr" self push: s. ]. ! ! !Interpreter methodsFor: 'other primitives' stamp: 'yo 2/7/2001 10:49'! primitiveObsoleteIndexedPrimitive "Primitive. Invoke an obsolete indexed primitive." | pluginName functionName functionAddress | self var: #pluginName declareC:'char *pluginName'. self var: #functionName declareC:'char *functionName'. functionAddress _ self cCoerce: ((obsoleteIndexedPrimitiveTable at: primitiveIndex) at: 2) to: 'int'. functionAddress = nil ifFalse:[^self cCode: '((int (*) (void))functionAddress)()' inSmalltalk:[self callExternalPrimitive: functionAddress]]. pluginName _ (obsoleteIndexedPrimitiveTable at: primitiveIndex) at: 0. functionName _ (obsoleteIndexedPrimitiveTable at: primitiveIndex) at: 1. (pluginName = nil and:[functionName = nil]) ifTrue:[^self primitiveFail]. functionAddress _ self ioLoadFunction: functionName From: pluginName. functionAddress = 0 ifFalse:["Cache for future use" (obsoleteIndexedPrimitiveTable at: primitiveIndex) at: 2 put: (self cCoerce: functionAddress to: 'char*'). ^self cCode: '((int (*) (void))functionAddress)()' inSmalltalk:[self callExternalPrimitive: functionAddress]]. ^self primitiveFail! ! !Interpreter methodsFor: 'other primitives' stamp: 'yo 2/1/2001 23:50'! primitiveVMParameter "Behaviour depends on argument count: 0 args: return an Array of VM parameter values; 1 arg: return the indicated VM parameter; 2 args: set the VM indicated parameter. VM parameters are numbered as follows: 1 end of old-space (0-based, read-only) 2 end of young-space (read-only) 3 end of memory (read-only) 4 allocationCount (read-only) 5 allocations between GCs (read-write) 6 survivor count tenuring threshold (read-write) 7 full GCs since startup (read-only) 8 total milliseconds in full GCs since startup (read-only) 9 incremental GCs since startup (read-only) 10 total milliseconds in incremental GCs since startup (read-only) 11 tenures of surving objects since startup (read-only) 12-20 specific to the translating VM 21 root table size (read-only) 22 root table overflows since startup (read-only) 23 bytes of extra memory to reserve for VM buffers, plugins, etc. Note: Thanks to Ian Piumarta for this primitive." | mem paramsArraySize result arg index | mem _ self cCoerce: memory to: 'int'. self cCode: '' inSmalltalk: [mem _ 0]. argumentCount = 0 ifTrue: [ paramsArraySize _ 23. result _ self instantiateClass: (self splObj: ClassArray) indexableSize: paramsArraySize. 0 to: paramsArraySize - 1 do: [:i | self storeWord: i ofObject: result withValue: (self integerObjectOf: 0)]. self storeWord: 0 ofObject: result withValue: (self integerObjectOf: youngStart - mem). self storeWord: 1 ofObject: result withValue: (self integerObjectOf: freeBlock - mem). self storeWord: 2 ofObject: result withValue: (self integerObjectOf: endOfMemory - mem). self storeWord: 3 ofObject: result withValue: (self integerObjectOf: allocationCount). self storeWord: 4 ofObject: result withValue: (self integerObjectOf: allocationsBetweenGCs). self storeWord: 5 ofObject: result withValue: (self integerObjectOf: tenuringThreshold). self storeWord: 6 ofObject: result withValue: (self integerObjectOf: statFullGCs). self storeWord: 7 ofObject: result withValue: (self integerObjectOf: statFullGCMSecs). self storeWord: 8 ofObject: result withValue: (self integerObjectOf: statIncrGCs). self storeWord: 9 ofObject: result withValue: (self integerObjectOf: statIncrGCMSecs). self storeWord: 10 ofObject: result withValue: (self integerObjectOf: statTenures). self storeWord: 20 ofObject: result withValue: (self integerObjectOf: rootTableCount). self storeWord: 21 ofObject: result withValue: (self integerObjectOf: statRootTableOverflows). self storeWord: 22 ofObject: result withValue: (self integerObjectOf: extraVMMemory). self pop: 1 thenPush: result. ^nil]. arg _ self stackTop. (self isIntegerObject: arg) ifFalse: [^self primitiveFail]. arg _ self integerValueOf: arg. argumentCount = 1 ifTrue: [ "read VM parameter" (arg < 1 or: [arg > 23]) ifTrue: [^self primitiveFail]. arg = 1 ifTrue: [result _ youngStart - mem]. arg = 2 ifTrue: [result _ freeBlock - mem]. arg = 3 ifTrue: [result _ endOfMemory - mem]. arg = 4 ifTrue: [result _ allocationCount]. arg = 5 ifTrue: [result _ allocationsBetweenGCs]. arg = 6 ifTrue: [result _ tenuringThreshold]. arg = 7 ifTrue: [result _ statFullGCs]. arg = 8 ifTrue: [result _ statFullGCMSecs]. arg = 9 ifTrue: [result _ statIncrGCs]. arg = 10 ifTrue: [result _ statIncrGCMSecs]. arg = 11 ifTrue: [result _ statTenures]. ((arg >= 12) and: [arg <= 20]) ifTrue: [result _ 0]. arg = 21 ifTrue: [result _ rootTableCount]. arg = 22 ifTrue: [result _ statRootTableOverflows]. arg = 23 ifTrue: [result _ extraVMMemory]. self pop: 2 thenPush: (self integerObjectOf: result). ^nil]. "write a VM parameter" argumentCount = 2 ifFalse: [^self primitiveFail]. index _ self stackValue: 1. (self isIntegerObject: index) ifFalse: [^self primitiveFail]. index _ self integerValueOf: index. index <= 0 ifTrue: [^self primitiveFail]. successFlag _ false. index = 5 ifTrue: [ result _ allocationsBetweenGCs. allocationsBetweenGCs _ arg. successFlag _ true]. index = 6 ifTrue: [ result _ tenuringThreshold. tenuringThreshold _ arg. successFlag _ true]. index = 23 ifTrue: [ result _ extraVMMemory. extraVMMemory _ arg. successFlag _ true]. successFlag ifTrue: [ self pop: 3 thenPush: (self integerObjectOf: result). "return old value" ^ nil]. self primitiveFail. "attempting to write a read-only parameter" ! ! !Interpreter methodsFor: 'debug support' stamp: 'di 2/15/2001 22:33'! okayFields: oop "If this is a pointers object, check that its fields are all okay oops." | i fieldOop c | (oop = nil or: [oop = 0]) ifTrue: [ ^true ]. (self isIntegerObject: oop) ifTrue: [ ^true ]. self okayOop: oop. self oopHasOkayClass: oop. (self isPointers: oop) ifFalse: [ ^true ]. c _ self fetchClassOf: oop. (c = (self splObj: ClassMethodContext) or: [c = (self splObj: ClassBlockContext)]) ifTrue: [i _ CtxtTempFrameStart + (self fetchStackPointerOf: oop) - 1] ifFalse: [i _ (self lengthOf: oop) - 1]. [i >= 0] whileTrue: [ fieldOop _ self fetchPointer: i ofObject: oop. (self isIntegerObject: fieldOop) ifFalse: [ self okayOop: fieldOop. self oopHasOkayClass: fieldOop. ]. i _ i - 1. ].! ! !Interpreter methodsFor: 'image save/restore' stamp: 'ar 2/5/2001 19:21'! writeImageFileIO: imageBytes | headerStart headerSize f bytesWritten | self var: #f declareC: 'sqImageFile f'. self ioCanWriteImage ifFalse:[^self primitiveFail]. "local constants" headerStart _ 0. headerSize _ 64. "header size in bytes; do not change!!" f _ self cCode: 'sqImageFileOpen(imageName, "wb")'. f = nil ifTrue: [ "could not open the image file for writing" self success: false. ^ nil]. headerStart _ self cCode: 'sqImageFileStartLocation(f,imageName,headerSize+imageBytes)'. self cCode: '/* Note: on Unix systems one could put an exec command here, padded to 512 bytes */'. "position file to start of header" self sqImageFile: f Seek: headerStart. self putLong: (self imageFormatVersion) toFile: f. self putLong: headerSize toFile: f. self putLong: imageBytes toFile: f. self putLong: (self startOfMemory) toFile: f. self putLong: specialObjectsOop toFile: f. self putLong: lastHash toFile: f. self putLong: (self ioScreenSize) toFile: f. self putLong: fullScreenFlag toFile: f. self putLong: extraVMMemory toFile: f. 1 to: 7 do: [:i | self putLong: 0 toFile: f]. "fill remaining header words with zeros" successFlag ifFalse: [ "file write or seek failure" self cCode: 'sqImageFileClose(f)'. ^ nil]. "position file after the header" self sqImageFile: f Seek: headerStart + headerSize. "write the image data" bytesWritten _ self cCode: 'sqImageFileWrite(memory, sizeof(unsigned char), imageBytes, f)'. self success: bytesWritten = imageBytes. self cCode: 'sqImageFileClose(f)'. ! ! !Interpreter class methodsFor: 'translation' stamp: 'ar 2/5/2001 22:18'! translate: fileName doInlining: inlineFlag forBrowserPlugin: pluginFlag "Note: The pluginFlag is meaningless on Windows and Unix. On these platforms Squeak runs as it's own process and doesn't need any special attention from the VMs point of view. Meaning that NONE of the required additional functions will be supported. In other words, the pluginFlag is not needed and not supported." "Translate the Smalltalk description of the virtual machine into C. If inlineFlag is true, small method bodies are inlined to reduce procedure call overhead. On the PPC, this results in a factor of three speedup with only 30% increase in code size. If pluginFlag is true, generate code for an interpreter that runs as a browser plugin (Netscape or IE)." | doInlining cg exports | doInlining _ inlineFlag. pluginFlag ifTrue: [doInlining _ true]. "must inline when generating browser plugin" Interpreter initialize. ObjectMemory initialize. GenerateBrowserPlugin _ pluginFlag. cg _ CCodeGenerator new initialize. cg addClass: Interpreter. cg addClass: ObjectMemory. Interpreter declareCVarsIn: cg. ObjectMemory declareCVarsIn: cg. "Get all the named prims from the VM. Note: the format of exports is: pluginName -> Array of: primitiveName. so we can generate a nice table from it." exports _ Array with: '' -> cg exportedPrimitiveNames asArray. cg storeCodeOnFile: fileName doInlining: doInlining. "Add our plugins" { "Graphics" "Note: BitBltSimulation should go first, because three of it's entries might be looked up quite often (due to refs from InterpreterProxy). This will go away at some point but for now it's a good idea to have those entries early in the table." BitBltSimulation. BalloonEnginePlugin. SurfacePlugin. "To support OS surfaces through FXBlt" "I/O subsystems" FilePlugin. SocketPlugin. MIDIPlugin. SerialPlugin. JoystickTabletPlugin. AsynchFilePlugin. "Sound" SoundPlugin. SoundGenerationPlugin. ADPCMCodecPlugin. KlattSynthesizerPlugin. SoundCodecPlugin. "Numerics" LargeIntegersPlugin. FFTPlugin. FloatArrayPlugin. Matrix2x3Plugin. "Compression" DeflatePlugin. "Others" B3DEnginePlugin. DSAPlugin. DropPlugin. MiscPrimitivePlugin. SecurityPlugin. "Note: Optionally, you can translate the following as builtins. As of Squeak 2.7 they are not builtins by default: FFIPlugin. " } do:[:plugin| cg _ plugin translate: plugin moduleName, '.c' doInlining: doInlining locally: true. exports _ exports copyWith: (plugin moduleName -> cg exportedPrimitiveNames asArray). ]. self storeExports: exports on: 'sqNamedPrims.h'.! ! !InterpreterSimulator methodsFor: 'initialization' stamp: 'yo 2/7/2001 10:47'! initialize "Initialize the InterpreterSimulator when running the interpreter inside Smalltalk. The primary responsibility of this method is to allocate Smalltalk Arrays for variables that will be declared as statically-allocated global arrays in the translated code." "initialize class variables" ObjectMemory initialize. Interpreter initialize. methodCache _ Array new: MethodCacheSize. atCache _ Array new: AtCacheTotalSize. rootTable _ Array new: RootTableSize. remapBuffer _ Array new: RemapBufferSize. semaphoresUseBufferA _ true. semaphoresToSignalA _ Array new: SemaphoresToSignalSize. semaphoresToSignalB _ Array new: SemaphoresToSignalSize. externalPrimitiveTable _ CArrayAccessor on: (Array new: MaxExternalPrimitiveTableSize). obsoleteNamedPrimitiveTable _ CArrayAccessor on: self class obsoleteNamedPrimitiveTable. obsoleteIndexedPrimitiveTable _ CArrayAccessor on: (self class obsoleteIndexedPrimitiveTable collect:[:spec| CArrayAccessor on: (spec ifNil:[Array new: 3] ifNotNil:[Array with: spec first with: spec second with: nil])]). pluginList _ #(). mappedPluginEntries _ #(). "initialize InterpreterSimulator variables used for debugging" byteCount _ 0. sendCount _ 0. traceOn _ true. myBitBlt _ BitBltSimulator new setInterpreter: self. displayForm _ nil. "displayForm is created in response to primitiveBeDisplay" filesOpen _ OrderedCollection new. ! ! !InterpreterSimulator methodsFor: 'initialization' stamp: 'yo 2/7/2001 10:53'! openOn: fileName extraMemory: extraBytes "InterpreterSimulator new openOn: 'clone.im' extraMemory: 100000" | f version headerSize count oldBaseAddr bytesToShift swapBytes | "open image file and read the header" f _ FileStream readOnlyFileNamed: fileName. imageName _ f fullName. f binary. version _ self nextLongFrom: f. "current version: 16r1966 (=6502)" (self readableFormat: version) ifTrue: [swapBytes _ false] ifFalse: [(version _ self byteSwapped: version) = self imageFormatVersion ifTrue: [swapBytes _ true] ifFalse: [self error: 'incomaptible image format']]. headerSize _ self nextLongFrom: f swap: swapBytes. endOfMemory _ self nextLongFrom: f swap: swapBytes. "first unused location in heap" oldBaseAddr _ self nextLongFrom: f swap: swapBytes. "object memory base address of image" specialObjectsOop _ self nextLongFrom: f swap: swapBytes. lastHash _ self nextLongFrom: f swap: swapBytes. "Should be loaded from, and saved to the image header" savedWindowSize _ self nextLongFrom: f swap: swapBytes. lastHash = 0 ifTrue: [lastHash _ 999]. savedWindowSize _ self nextLongFrom: f swap: swapBytes. fullScreenFlag _ self nextLongFrom: f swap: swapBytes. extraVMMemory _ self nextLongFrom: f swap: swapBytes. "allocate interpreter memory" memoryLimit _ endOfMemory + extraBytes. "read in the image in bulk, then swap the bytes if necessary" f position: headerSize. memory _ Bitmap new: memoryLimit // 4. count _ f readInto: memory startingAt: 1 count: endOfMemory // 4. count ~= (endOfMemory // 4) ifTrue: [self halt]. f close. swapBytes ifTrue: [Utilities informUser: 'Swapping bytes of foreign image...' during: [self reverseBytesInImage]]. self initialize. bytesToShift _ 0 - oldBaseAddr. "adjust pointers for zero base address" endOfMemory _ endOfMemory. Utilities informUser: 'Relocating object pointers...' during: [self initializeInterpreter: bytesToShift]. ! ! !InterpreterSimulator methodsFor: 'I/O primitives' stamp: 'yo 2/14/2001 14:17'! ioGetNextEvent: evtBuf self primitiveFail. ! ! !InterpreterSimulator methodsFor: 'I/O primitives' stamp: 'ar 2/5/2001 17:24'! ioScreenDepth ^DisplayScreen actualScreenDepth.! ! !InterpreterSimulator methodsFor: 'I/O primitives' stamp: 'yo 2/14/2001 14:17'! ioSetInputSemaphore: index self primitiveFail! ! !InterpreterSimulator methodsFor: 'file primitives' stamp: 'yo 2/14/2001 12:04'! primitiveFileOpen | namePointer writeFlag fileName f | writeFlag _ self booleanValueOf: self stackTop. namePointer _ self stackValue: 1. self success: (self isBytes: namePointer). successFlag ifTrue: [fileName _ self stringOf: namePointer. filesOpen addLast: (writeFlag ifTrue: [f _ FileStream fileNamed: fileName. f ifNil: [^ self primitiveFail] ifNotNil: [f binary]] ifFalse: [(StandardFileStream isAFileNamed: fileName) ifTrue: [f _ (FileStream readOnlyFileNamed: fileName). f ifNil:[^self primitiveFail] ifNotNil:[f binary]] ifFalse: [^ self primitiveFail]]). self pop: 3. "rcvr, name, write" self pushInteger: filesOpen size]! ! !InterpreterSimulator methodsFor: 'file primitives' stamp: 'ar 2/6/2001 17:54'! sqFileFlush: file ^ file flush! ! !InterpreterSimulator methodsFor: 'plugin support' stamp: 'yo 2/14/2001 11:15'! classNameOf: aClass Is: className "Check if aClass' name is className" | name | (self lengthOf: aClass) <= 6 ifTrue:[^false]. "Not a class but maybe behavior" name _ self fetchPointer: 6 ofObject: aClass. (self isBytes: name) ifFalse:[^false]. ^ className = (self stringOf: name). ! ! !InterpreterSimulator methodsFor: 'security' stamp: 'ar 2/5/2001 18:33'! ioCanRenameImage ^true! ! !InterpreterSimulator methodsFor: 'security' stamp: 'ar 2/5/2001 20:42'! ioCanWriteImage ^true! ! !InterpreterSupportCode class methodsFor: 'source file exporting' stamp: 'JMM 2/12/2001 16:28'! compareWithFilesInFolder: folderName "InterpreterSupportCode compareWithFilesInFolder: 'Tosh:Desktop Folder:Squeak VM Project'" | dir | dir _ FileDirectory on: folderName. (dir readOnlyFileNamed: 'projectArchive.sit') binary contentsOfEntireFile = InterpreterSupportCode macArchiveBinaryFile asByteArray ifFalse: [self inform: 'File projectArchive.sit differs from the version stored in this image.']. (dir readOnlyFileNamed: 'readme') contentsOfEntireFile = InterpreterSupportCode readmeFile ifFalse: [self inform: 'File readme differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sq.h') contentsOfEntireFile = InterpreterSupportCode squeakHeaderFile ifFalse: [self inform: 'File sq.h differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqConfig.h') contentsOfEntireFile = InterpreterSupportCode squeakConfigFile ifFalse: [self inform: 'File sqConfig.h differs from the version stored in this image.']. (dir readOnlyFileNamed: 'platform.exports') contentsOfEntireFile = InterpreterSupportCode squeakPlatformExportsFile ifFalse: [self inform: 'File platform.exports differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqPlatformSpecific.h') contentsOfEntireFile = InterpreterSupportCode squeakPlatSpecFile ifFalse: [self inform: 'File sqPlatformSpecific.h differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqFilePrims.c') contentsOfEntireFile = InterpreterSupportCode squeakFilePrimsFile ifFalse: [self inform: 'File sqFilePrims.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacAsyncFilePrims.c') contentsOfEntireFile = InterpreterSupportCode macAsyncFilePrimsFile ifFalse: [self inform: 'File sqMacAsyncFilePrims.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacNSPlugin.c') contentsOfEntireFile = InterpreterSupportCode macBrowserPluginFile ifFalse: [self inform: 'File sqMacNSPlugin.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacDirectory.c') contentsOfEntireFile = InterpreterSupportCode macDirectoryFile ifFalse: [self inform: 'File sqMacDirectory.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacDragDrop.c') contentsOfEntireFile = InterpreterSupportCode macDragDropFile ifFalse: [self inform: 'File sqMacDragDrop.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacJoystickAndTablet.c') contentsOfEntireFile = InterpreterSupportCode macJoystickAndTabletFile ifFalse: [self inform: 'File sqMacJoystickAndTablet.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacMinimal.c') contentsOfEntireFile = InterpreterSupportCode macMinimal ifFalse: [self inform: 'File sqMacMinimal.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacNetwork.c') contentsOfEntireFile = InterpreterSupportCode macNetworkFile ifFalse: [self inform: 'File sqMacNetwork.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacSerialAndMIDIPort.c') contentsOfEntireFile = InterpreterSupportCode macSerialAndMIDIPortFile ifFalse: [self inform: 'File sqMacSerialAndMIDIPort.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacSecurity.c') contentsOfEntireFile = InterpreterSupportCode macSecurityFile ifFalse: [self inform: 'File sqMacSecurity.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacSound.c') contentsOfEntireFile = InterpreterSupportCode macSoundFile ifFalse: [self inform: 'File sqMacSound.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqMacWindow.c') contentsOfEntireFile = InterpreterSupportCode macWindowFile ifFalse: [self inform: 'File sqMacWindow.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqNamedPrims.c') contentsOfEntireFile = InterpreterSupportCode squeakNamedPrimsFile ifFalse: [self inform: 'File sqNamedPrims.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqVirtualMachine.h') contentsOfEntireFile = InterpreterSupportCode squeakVirtualMachineHeaderFile ifFalse: [self inform: 'File sqVirtualMachine.h differs from the version stored in this image.']. (dir readOnlyFileNamed: 'sqVirtualMachine.c') contentsOfEntireFile = InterpreterSupportCode squeakVirtualMachineFile ifFalse: [self inform: 'File sqVirtualMachine.c differs from the version stored in this image.']. (dir readOnlyFileNamed: 'MacTCP.h') contentsOfEntireFile = InterpreterSupportCode macTCPFile ifFalse: [self inform: 'File MacTCP.h differs from the version stored in this image.']. (dir readOnlyFileNamed: 'AddressXlation.h') contentsOfEntireFile = InterpreterSupportCode macAddressXlationFile ifFalse: [self inform: 'File AddressXlation.h differs from the version stored in this image.']. (dir readOnlyFileNamed: 'dnr.c') contentsOfEntireFile = InterpreterSupportCode macDNRFile ifFalse: [self inform: 'File dnr.c differs from the version stored in this image.']. ! ! !InterpreterSupportCode class methodsFor: 'source file exporting' stamp: 'JMM 2/12/2001 16:27'! writeMacSourceFiles "Store into this image's folder the C sources files required to support the interpreter on the Macintosh. It also generates the code for the sound synthesis primitives. However, because generating code for the interpreter itself takes several minutes, that is not done automatically by this method. To generate the interpreter code, use the method 'translate:doInlining:' in Interpreter class." "InterpreterSupportCode writeMacSourceFiles" self writeSupportFiles. FFIPlugin writeSupportFiles. self storeString: self macAsyncFilePrimsFile onFileNamed: 'sqMacAsyncFilePrims.c'. self storeString: self macBrowserPluginFile onFileNamed: 'sqMacNSPlugin.c'. self storeString: self macDirectoryFile onFileNamed: 'sqMacDirectory.c'. self storeString: self macJoystickAndTabletFile onFileNamed: 'sqMacJoystickAndTablet.c'. self storeString: self macMinimal onFileNamed: 'sqMacMinimal.c'. self storeString: self macNetworkFile onFileNamed: 'sqMacNetwork.c'. self storeString: self macDragDropFile onFileNamed: 'sqMacDragDrop.c'. self storeString: self macSecurityFile onFileNamed: 'sqMacSecurity.c'. self storeString: self macSerialAndMIDIPortFile onFileNamed: 'sqMacSerialAndMIDIPort.c'. self storeString: self macSoundFile onFileNamed: 'sqMacSound.c'. self storeString: self macWindowFile onFileNamed: 'sqMacWindow.c'. self storeString: self macTCPFile onFileNamed: 'MacTCP.h'. self storeString: self macAddressXlationFile onFileNamed: 'AddressXlation.h'. self storeString: self macDNRFile onFileNamed: 'dnr.c'. self storeStuffitArchive: self macArchiveBinaryFile onFileNamed: 'projectArchive.sit'. ! ! !InterpreterSupportCode class methodsFor: 'source file exporting' stamp: 'ar 2/6/2001 14:07'! writeSupportFiles "Store into this image's folder the C sources files required to support the interpreter on all platforms. This method also generates the code for the sound synthesis and other primitives translated from Smalltalk to C. However, because generating code for the interpreter itself takes several minutes, that is not done automatically by this method. To generate that code, use the method 'translate:doInlining:' in Interpreter class." "InterpreterSupportCode writeSupportFiles" self storeString: self readmeFile onFileNamed: 'readme'. self storeString: self squeakHeaderFile onFileNamed: 'sq.h'. self storeString: self squeakConfigFile onFileNamed: 'sqConfig.h'. self storeString: self squeakPlatformExportsFile onFileNamed: 'platform.exports'. self storeString: self squeakPlatSpecFile onFileNamed: 'sqPlatformSpecific.h'. self storeString: self squeakVirtualMachineHeaderFile onFileNamed: 'sqVirtualMachine.h'. self storeString: self squeakVirtualMachineFile onFileNamed: 'sqVirtualMachine.c'. self storeString: self squeakNamedPrimsFile onFileNamed:'sqNamedPrims.c'. self storeString: self squeakFilePrimsFile onFileNamed: 'sqFilePrims.c'.! ! !InterpreterSupportCode class methodsFor: 'source files' stamp: 'JMM 2/16/2001 22:04'! macArchiveBinaryFile "Answer the binary contents of a StuffIt archive file containing the CodeWarrier project files for the virtual machine. You will need to use a StuffIt unpacking utility such as StuffIt Expander to unpack the file. The result will be a folder containing the project files." "To create the text for this method evaulate: | in out | in _ (FileStream oldFileNamed: 'projectArchive.sit') binary. out _ WriteStream on: (String new: 100000). out nextPutAll: '#('. [in atEnd] whileFalse: [out nextPutAll: in next printString; space]. out skip: -1. out nextPutAll: ')'. in close. Clipboard clipboardText: out contents asText and then do paste into this method." ^ #(83 116 117 102 102 73 116 32 40 99 41 49 57 57 55 45 49 57 57 56 32 65 108 97 100 100 105 110 32 83 121 115 116 101 109 115 44 32 73 110 99 46 44 32 104 116 116 112 58 47 47 119 119 119 46 97 108 97 100 100 105 110 115 121 115 46 99 111 109 47 83 116 117 102 102 73 116 47 13 10 26 0 5 16 0 0 109 144 0 0 0 114 0 10 0 0 0 114 220 92 0 43 0 5 1 96 1 255 0 0 0 0 0 0 165 165 165 165 1 0 0 62 0 16 181 144 51 21 182 158 25 127 0 0 0 0 0 0 11 3 0 0 0 0 0 14 47 50 0 0 37 20 0 0 9 183 0 0 0 0 15 0 109 121 77 97 99 72 101 97 100 101 114 115 46 99 0 1 249 212 84 69 88 84 67 87 73 69 1 0 1 128 1 1 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 1 154 0 0 0 106 0 0 0 0 15 0 66 193 212 138 116 88 41 37 231 118 79 249 86 183 220 130 201 119 237 194 11 107 95 101 129 233 78 237 233 41 2 10 134 65 190 14 57 147 88 117 246 30 129 230 100 86 124 160 181 213 228 113 176 242 110 15 116 236 78 49 113 111 82 137 215 100 243 164 56 26 150 173 165 69 200 187 255 179 112 28 55 170 135 33 198 200 235 206 99 142 62 109 255 116 149 57 0 236 41 186 92 188 174 38 174 192 66 193 212 132 70 70 86 227 229 250 240 216 108 46 2 127 7 118 93 193 98 100 220 19 200 129 89 135 89 82 22 238 49 159 133 108 171 14 212 223 34 215 77 208 114 160 164 237 185 214 129 65 199 201 45 211 163 103 203 58 2 85 140 45 151 178 152 115 9 199 215 95 96 151 105 218 21 183 124 139 66 246 165 122 233 239 249 49 33 230 241 98 152 155 66 5 97 56 210 80 40 74 50 161 38 49 191 246 13 248 37 22 30 82 47 247 193 20 8 253 47 112 160 72 112 53 215 204 3 97 248 96 8 243 221 18 149 108 14 129 125 171 25 125 64 92 146 29 121 208 175 185 114 183 252 116 88 47 20 203 91 54 195 197 212 254 215 49 246 175 214 179 20 62 218 106 240 184 65 250 38 189 140 67 51 74 95 30 3 237 219 189 131 26 139 234 59 182 38 237 228 223 81 228 70 109 151 93 182 102 227 203 12 157 152 107 15 98 148 171 41 204 102 172 62 195 233 155 129 52 241 31 197 124 118 99 45 58 83 248 22 215 210 251 42 253 224 32 223 130 124 29 99 117 213 224 39 13 123 115 248 26 221 26 239 139 238 20 111 20 56 127 75 111 87 227 74 59 31 173 85 118 51 26 21 56 145 199 107 6 134 163 54 13 38 143 9 8 177 101 138 176 126 236 42 83 222 165 174 137 128 18 108 62 172 104 206 82 31 153 2 182 57 73 14 84 208 156 251 177 59 232 160 12 252 203 218 179 103 69 40 108 127 129 76 239 43 241 84 12 202 12 118 247 134 247 28 5 26 17 8 152 197 86 37 168 231 169 178 114 72 86 108 222 32 244 59 133 232 143 193 13 133 147 126 127 149 24 121 2 38 68 52 152 209 111 150 184 27 137 253 238 123 197 0 118 134 239 237 36 138 92 9 194 243 159 213 60 212 20 229 59 28 20 233 18 161 31 106 165 1 110 83 216 106 180 249 207 9 174 17 94 185 168 244 3 4 168 140 63 65 99 190 250 119 64 70 17 171 160 166 169 104 159 33 175 236 14 164 90 174 65 175 124 152 30 15 87 146 118 109 236 131 130 220 219 214 112 125 170 137 231 54 250 21 145 43 231 188 66 60 145 144 78 191 182 237 122 40 55 70 174 38 200 113 225 103 84 13 29 121 130 211 114 223 222 52 197 13 242 137 125 59 249 152 208 14 117 204 232 95 173 10 254 158 64 113 32 71 211 118 10 37 152 22 6 193 1 255 147 16 255 96 95 2 197 244 163 41 80 165 64 231 82 177 26 111 196 195 16 244 124 241 119 42 72 98 152 240 138 13 187 140 50 8 203 25 228 139 176 231 43 188 185 2 244 190 171 127 194 95 139 23 204 75 146 60 62 27 80 38 93 38 145 109 19 117 6 190 225 110 85 211 48 214 67 194 48 118 230 103 121 110 231 193 135 164 195 102 232 253 49 148 47 128 195 236 125 10 219 186 74 154 99 167 196 60 86 195 220 106 181 140 85 69 75 218 24 134 11 31 42 184 151 115 226 63 107 52 127 87 90 27 209 125 49 244 52 72 106 47 168 194 221 133 102 80 172 93 30 180 148 98 219 250 1 131 80 231 16 175 251 155 120 51 58 133 74 44 194 98 69 220 203 116 191 232 6 60 149 104 160 232 101 60 176 56 85 193 184 154 196 187 176 181 220 6 241 108 26 22 183 125 180 240 179 101 192 98 125 237 3 89 114 235 91 209 164 113 1 58 129 69 227 29 19 29 199 223 52 106 86 210 28 98 88 130 229 148 120 16 129 14 17 4 222 44 49 251 34 155 53 1 122 248 192 61 173 28 105 15 199 20 82 30 53 37 81 146 117 100 246 78 108 152 234 93 106 164 44 100 57 126 9 134 155 27 184 21 148 185 94 106 50 113 228 79 94 34 151 21 160 54 33 4 249 230 134 176 70 241 249 85 152 252 212 193 251 181 238 242 57 219 252 62 154 74 65 219 88 115 39 77 236 5 188 230 126 109 127 233 91 10 224 186 224 60 237 252 238 150 54 161 201 94 8 244 145 47 44 217 137 239 234 201 42 8 178 49 89 199 176 56 165 31 101 19 109 234 101 137 162 10 229 183 144 68 242 150 52 133 117 88 173 140 84 230 109 53 133 118 31 127 28 54 7 230 85 169 251 254 192 6 169 172 189 140 22 174 91 19 91 125 223 162 84 237 230 213 183 153 250 131 177 111 6 84 183 247 13 76 39 186 31 198 85 4 65 32 19 1 99 145 201 225 227 243 17 214 185 26 33 101 205 44 160 34 195 147 137 18 207 88 193 239 159 19 49 180 186 110 34 91 81 126 47 101 10 118 12 117 42 111 147 156 94 195 157 204 248 229 229 155 103 232 66 107 220 242 138 252 243 151 217 136 131 173 212 193 219 166 253 173 88 80 220 63 46 109 88 232 90 249 96 67 199 255 136 27 154 43 84 216 241 187 178 227 175 65 114 73 13 15 98 255 39 134 162 119 232 163 16 23 93 129 62 166 157 15 154 27 26 22 115 8 168 226 84 233 64 121 6 75 60 59 127 229 225 29 214 193 226 73 79 102 74 60 56 130 137 229 133 2 50 59 52 230 115 36 203 162 101 18 167 216 183 101 153 45 171 24 125 246 212 22 150 51 149 179 153 191 89 161 218 135 97 19 194 50 34 223 113 101 103 136 83 76 55 48 36 80 56 226 27 48 120 156 42 19 32 20 17 57 39 33 219 123 249 192 127 10 182 75 171 92 189 220 14 220 60 159 227 228 14 241 235 112 90 20 251 157 160 3 36 236 95 173 58 230 127 69 243 123 75 97 113 205 83 246 125 11 125 96 36 176 106 177 61 42 181 20 175 94 167 143 126 251 254 160 166 65 77 62 9 249 97 143 85 228 244 116 212 36 139 27 39 2 205 126 120 142 16 221 171 238 9 71 136 127 183 207 62 15 86 53 15 2 102 101 179 61 141 49 213 40 141 163 67 190 184 255 243 129 31 131 167 254 204 179 48 58 103 182 95 167 251 52 47 18 107 18 137 227 164 93 85 188 234 111 109 2 84 181 250 201 87 56 179 139 122 116 9 72 150 26 201 3 16 131 116 158 40 94 162 107 116 254 167 70 163 135 76 238 186 199 185 34 229 206 216 82 176 11 88 86 57 139 30 2 208 123 57 141 221 171 211 186 142 118 126 139 154 109 57 79 1 35 167 40 44 39 213 242 211 220 168 159 200 169 179 212 88 68 78 200 147 37 40 78 169 30 98 229 242 15 101 5 179 4 239 182 164 66 15 21 205 242 169 118 60 166 24 139 110 88 102 100 95 76 164 156 185 94 78 122 188 84 74 244 3 153 155 54 89 214 52 181 186 49 248 74 61 63 130 1 251 48 92 241 131 25 214 90 146 245 111 208 0 200 130 56 240 165 169 148 206 222 128 170 66 144 165 235 199 35 41 172 79 16 73 84 79 60 126 86 20 84 57 189 173 108 83 108 81 41 110 196 34 198 64 130 167 53 95 252 127 145 160 17 25 107 30 200 4 122 235 171 27 245 83 163 114 251 243 83 92 90 202 225 71 136 233 48 236 166 227 153 9 44 86 152 46 157 33 106 211 38 217 131 189 158 77 118 186 137 83 106 231 38 183 90 52 35 137 96 149 252 106 81 140 59 206 123 111 194 70 128 243 110 236 189 248 13 44 218 175 155 189 61 117 24 11 169 190 120 244 49 97 84 33 238 113 123 121 234 200 117 143 213 164 67 118 136 81 156 181 97 170 195 15 90 84 197 162 128 180 123 146 157 140 166 23 62 191 219 207 52 11 47 102 15 132 239 222 55 33 195 105 219 7 235 139 152 116 60 25 96 195 178 61 14 158 181 173 197 130 3 51 243 102 76 103 143 10 245 92 220 236 141 223 116 227 66 7 57 153 114 238 10 230 232 176 12 175 132 255 205 252 18 152 205 169 191 124 59 188 115 70 80 37 198 61 238 169 19 8 73 36 110 103 133 105 74 11 15 219 222 225 80 37 208 46 80 225 212 115 148 86 235 203 83 7 141 117 136 142 4 23 62 124 10 94 45 49 81 53 68 172 40 141 44 61 248 53 189 171 93 232 151 125 187 242 44 48 78 122 14 155 71 149 26 249 110 4 137 252 232 107 95 133 111 248 39 32 216 250 139 71 199 65 188 109 185 222 173 38 154 41 26 203 164 65 78 224 92 171 208 90 72 55 177 173 76 81 231 243 216 204 118 128 229 102 224 120 76 223 0 232 167 190 139 96 143 251 23 60 117 73 185 52 25 41 30 92 16 109 65 55 254 254 173 95 201 191 193 56 212 8 23 212 173 150 167 92 25 22 96 99 170 165 164 40 36 195 183 62 219 4 67 46 22 63 222 5 189 85 231 135 117 193 81 183 28 185 150 204 45 138 16 29 249 195 34 17 152 49 55 161 150 67 67 238 114 100 72 91 0 22 231 161 15 143 49 222 113 6 12 169 143 119 228 135 153 170 60 177 165 119 120 180 81 178 118 192 182 42 171 188 123 62 224 76 89 178 221 232 21 1 32 55 48 174 83 32 204 196 152 115 160 94 162 76 36 234 130 46 208 158 156 130 16 2 200 63 214 12 68 238 216 11 69 230 210 144 197 49 0 137 72 242 7 201 79 14 15 92 223 226 57 137 113 156 96 94 22 62 239 156 25 246 159 72 150 236 47 148 93 81 82 160 65 193 218 226 5 173 68 149 131 185 38 21 54 28 45 163 133 100 249 71 53 193 81 236 219 46 36 117 122 241 67 70 160 158 137 200 28 140 228 117 216 92 197 139 107 45 76 132 225 120 25 241 135 183 155 93 124 61 178 162 153 124 169 222 88 143 122 87 102 247 47 37 141 255 232 110 183 43 235 205 24 115 77 112 204 130 226 183 244 107 237 88 133 215 112 156 91 244 40 149 126 211 18 61 248 243 242 234 1 67 155 205 165 46 241 183 45 57 192 220 209 108 240 103 75 84 225 56 241 98 50 22 74 38 110 229 178 174 113 149 105 219 99 204 9 187 142 57 11 80 19 222 31 78 163 164 81 225 238 93 139 39 45 77 116 191 122 147 93 63 47 1 43 54 59 33 120 183 197 115 221 125 55 140 107 197 207 252 168 189 93 204 160 15 6 92 87 21 69 13 171 60 68 240 229 169 136 185 10 16 114 157 62 4 62 98 10 25 57 208 210 238 206 221 244 23 46 24 203 6 182 53 192 196 161 244 15 113 51 114 84 111 207 79 49 240 83 61 153 132 114 177 48 194 95 237 67 44 187 237 135 159 159 33 223 31 214 108 74 197 120 50 91 204 64 45 244 193 54 170 53 199 41 10 70 220 145 68 218 10 32 158 205 48 186 18 120 100 158 47 3 157 62 91 7 54 31 217 83 233 226 95 125 28 51 6 123 194 39 147 63 52 100 201 220 96 226 242 131 85 96 214 22 71 194 69 5 99 37 88 48 22 245 153 70 245 85 38 116 133 224 61 191 197 143 169 70 94 167 89 162 114 248 119 73 40 186 97 52 83 229 239 50 37 67 25 0 165 165 165 165 1 0 0 64 0 16 181 144 51 13 182 158 25 127 0 0 0 114 0 0 13 78 0 0 0 0 0 16 118 69 0 0 3 20 0 0 1 114 0 0 0 0 15 0 109 121 77 97 99 72 101 97 100 101 114 115 46 112 99 104 0 1 88 136 84 69 88 84 67 87 73 69 1 0 0 192 2 1 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 1 154 0 0 0 103 0 0 0 0 15 0 66 193 212 165 47 158 101 143 90 111 232 62 137 252 56 69 246 56 222 197 11 110 186 70 46 68 245 227 157 58 176 118 108 255 85 62 40 178 85 18 69 169 203 40 18 219 49 207 252 15 57 78 136 238 192 137 69 135 101 84 46 156 13 5 175 9 5 162 245 172 207 165 169 206 88 73 211 171 164 174 112 63 71 184 31 221 37 166 79 5 131 15 114 244 238 207 216 239 17 227 177 67 160 66 193 212 154 175 240 32 110 231 176 220 75 122 67 45 140 218 152 26 188 19 16 70 46 100 12 102 162 171 207 147 232 46 129 230 224 142 44 70 162 102 82 16 65 169 232 58 197 1 226 230 247 241 20 175 215 67 32 203 217 208 134 187 150 162 63 110 169 185 56 142 225 246 180 33 114 124 5 37 84 212 128 30 164 229 208 216 224 187 2 126 209 51 142 7 56 139 220 232 168 56 210 119 197 236 95 113 121 147 62 5 16 6 102 148 120 76 237 88 4 46 152 207 227 190 58 105 25 63 228 30 242 145 30 205 193 119 28 65 161 6 85 113 254 35 25 218 241 155 57 46 34 101 87 219 177 175 90 37 23 192 16 110 135 14 201 90 113 155 204 60 215 16 232 111 135 218 123 36 119 224 93 163 67 233 232 62 127 241 177 118 93 131 253 225 94 147 211 226 106 223 56 140 40 243 210 212 240 205 25 69 158 223 23 7 45 121 161 103 21 93 76 191 131 11 37 220 95 159 108 53 71 237 228 38 192 96 36 234 168 14 101 68 218 187 125 239 67 136 208 224 145 202 41 73 44 92 125 93 164 127 252 148 199 42 76 2 0 50 102 61 155 95 144 49 242 226 212 139 39 169 250 165 133 244 188 11 198 113 244 133 255 208 95 234 165 90 112 27 52 250 90 78 166 0 202 127 35 59 223 131 14 154 81 218 181 53 29 254 103 48 33 191 225 6 186 233 121 161 97 169 147 218 120 247 111 39 193 212 57 27 102 129 167 141 48 58 146 236 83 180 135 36 193 196 77 181 97 218 24 94 119 88 225 88 61 107 38 42 0 165 165 165 165 1 0 0 70 0 16 181 144 51 13 182 158 25 125 0 0 11 3 0 0 15 252 0 0 0 0 0 22 20 235 0 0 3 180 0 0 1 205 0 0 0 0 15 0 109 121 77 97 99 72 101 97 100 101 114 115 67 97 114 98 111 110 46 112 99 104 0 1 219 219 84 69 88 84 67 87 73 69 1 0 0 16 0 16 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 1 154 0 0 0 105 0 0 0 0 15 0 66 193 212 165 47 158 104 163 81 45 121 217 33 168 151 12 136 51 216 133 159 78 214 216 43 6 93 88 173 49 224 16 210 176 244 190 46 112 249 208 12 31 155 208 114 175 160 237 166 80 129 149 37 165 111 12 49 64 250 168 169 159 82 99 244 238 46 66 203 196 69 63 252 89 175 97 38 187 103 169 162 122 93 198 238 248 174 171 90 231 91 24 116 109 194 102 235 220 101 188 198 239 167 48 0 66 193 212 247 142 41 244 252 170 32 131 125 120 226 219 34 155 40 95 65 156 245 152 111 218 35 102 116 216 131 145 17 84 107 97 158 240 249 195 150 60 120 140 104 228 134 193 204 31 57 215 166 99 44 206 176 32 16 144 208 6 248 187 61 109 226 227 51 211 25 218 191 40 12 114 22 28 230 0 112 11 172 202 32 219 160 175 46 72 139 187 24 169 29 138 113 109 138 194 65 131 26 203 70 229 19 88 5 218 129 23 174 244 179 27 110 213 99 88 249 52 149 107 131 128 11 191 219 77 60 140 147 221 41 5 154 71 244 111 11 122 216 102 224 199 124 224 181 243 197 90 177 66 36 17 3 41 236 155 135 117 157 197 125 86 112 49 216 189 27 139 184 235 236 11 77 248 224 96 79 164 194 90 103 41 162 119 82 173 71 116 83 120 63 237 133 59 95 243 179 182 38 66 89 112 120 57 175 247 2 86 164 221 215 242 66 72 241 206 94 82 185 213 183 84 158 243 111 184 131 123 154 113 69 129 63 216 193 18 183 237 229 86 226 139 223 239 210 173 153 53 67 49 7 198 215 211 213 85 237 110 87 144 203 47 169 210 32 17 124 119 167 84 218 32 64 80 64 213 139 46 73 67 237 85 242 129 68 80 18 116 121 38 21 132 110 38 88 152 155 85 234 152 132 14 186 223 127 213 177 161 118 126 164 93 140 86 9 39 140 158 128 15 121 128 22 82 198 32 125 160 105 176 229 213 67 60 105 93 166 53 20 133 196 110 63 239 200 252 182 252 210 104 194 171 61 38 193 140 109 223 92 105 43 228 169 222 61 252 104 255 66 238 34 62 131 239 211 193 88 118 48 247 65 45 181 8 92 165 55 106 219 2 60 38 114 62 64 145 43 151 179 227 59 232 214 164 43 226 209 187 193 230 212 51 34 107 155 72 0 26 242 4 241 9 64 80 182 179 217 254 181 123 67 245 13 80 221 209 230 9 60 229 105 10 138 253 27 231 68 155 196 137 233 97 229 82 175 213 222 96 165 165 165 165 1 0 0 61 0 0 172 94 103 33 181 100 42 6 0 0 13 78 0 0 28 169 0 0 0 0 0 13 171 241 0 0 7 218 0 0 2 139 0 0 0 0 15 0 77 121 80 108 117 103 105 110 46 112 114 111 106 0 1 46 58 77 77 80 82 67 87 73 69 1 0 3 64 1 1 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 43 27 0 0 9 179 0 0 0 0 15 0 66 193 212 194 19 180 140 109 220 205 78 57 63 90 66 84 57 156 71 10 240 179 194 234 180 76 49 136 61 86 193 33 87 165 51 39 174 141 114 32 57 229 43 22 87 128 72 84 38 117 129 4 182 215 234 186 97 240 130 6 7 168 37 149 122 3 125 3 195 87 185 151 254 22 251 249 238 210 167 130 219 121 155 186 134 229 95 75 152 58 93 250 123 38 106 43 222 218 75 149 20 150 219 56 44 81 228 23 54 251 165 214 237 251 0 192 205 43 113 64 228 181 201 133 51 84 209 66 37 59 176 144 234 4 186 142 81 128 228 2 55 216 158 134 41 177 194 7 95 252 212 255 73 83 237 231 200 33 245 234 99 190 79 33 76 97 115 253 35 55 46 42 13 118 116 73 161 215 249 23 162 74 26 161 34 208 52 177 148 31 2 225 128 147 212 218 175 235 77 215 179 45 41 42 83 138 73 222 20 4 247 49 227 152 237 224 96 210 249 218 162 93 24 168 187 8 67 87 106 36 240 23 14 253 32 32 233 250 182 103 110 104 23 208 218 230 121 74 225 57 124 53 128 60 111 91 170 168 211 245 68 13 214 181 216 230 12 119 31 218 154 171 103 239 30 230 22 188 226 29 238 162 224 59 253 70 31 56 103 224 36 245 159 238 139 104 201 201 132 39 227 128 0 62 234 60 136 63 255 195 11 172 202 17 37 216 84 146 63 219 54 56 151 166 38 241 106 221 197 103 27 237 182 165 6 183 114 101 218 141 240 64 148 45 222 37 21 103 254 127 46 56 173 37 215 210 155 156 143 214 184 249 118 238 209 196 193 63 132 149 152 85 92 181 13 27 221 176 225 145 152 79 7 62 97 181 120 39 91 165 74 115 184 46 199 3 192 153 218 145 229 140 225 48 115 235 24 105 61 157 168 6 39 4 200 157 182 175 112 130 106 48 11 175 17 0 192 51 97 61 92 231 192 128 4 202 158 82 84 178 6 244 58 194 143 198 197 84 245 194 178 69 38 193 153 99 228 73 197 137 51 95 234 74 220 141 111 161 135 191 121 33 201 254 51 7 28 164 179 195 57 17 73 210 193 161 123 149 11 73 41 75 25 196 86 100 212 137 148 255 191 61 249 212 167 243 124 178 252 243 230 210 105 103 137 88 244 8 170 166 127 33 239 33 76 177 46 165 94 119 60 57 69 82 53 93 97 113 18 211 180 59 221 195 107 202 4 125 117 172 218 169 252 32 46 1 54 41 228 135 201 89 109 105 202 112 20 196 166 41 173 208 173 27 148 202 143 245 25 142 72 111 18 240 135 44 9 113 199 4 252 36 142 207 253 43 184 119 116 86 138 249 177 138 141 63 33 191 93 190 139 209 129 212 216 83 151 194 200 24 252 41 196 242 80 71 41 30 226 43 28 209 35 219 218 177 65 128 188 55 183 237 64 231 242 161 168 189 135 114 61 217 9 64 19 4 196 99 134 88 34 235 184 97 44 234 25 195 176 83 127 209 207 190 234 196 243 14 19 177 134 74 190 120 202 207 65 100 1 59 62 46 48 80 135 3 9 73 242 18 57 109 183 245 222 178 216 183 84 76 56 208 27 8 158 248 66 214 155 165 188 137 94 194 111 156 211 2 200 53 127 166 203 170 79 164 98 8 33 169 242 184 152 189 171 140 226 112 193 38 34 179 149 178 39 37 88 11 56 158 240 172 153 69 71 107 203 187 140 154 176 235 8 151 194 172 241 194 59 173 162 204 166 181 114 97 224 92 71 116 144 235 121 221 159 124 218 189 170 239 83 135 28 243 178 223 131 227 17 146 169 220 93 31 64 246 60 114 194 162 48 94 192 255 37 210 128 223 90 148 255 167 134 204 96 230 126 180 73 114 139 161 17 171 76 130 56 199 160 130 180 229 165 79 185 10 128 134 241 79 80 147 118 89 165 116 61 94 67 177 61 154 226 10 230 26 219 235 251 35 12 194 40 38 35 252 251 191 11 198 3 254 127 229 204 232 61 105 255 53 135 108 128 24 78 193 229 23 109 141 167 141 113 72 6 184 7 83 149 143 141 161 13 193 130 105 121 159 72 83 255 218 246 207 168 2 188 251 220 106 202 121 24 137 85 236 151 184 191 38 29 12 123 142 42 244 196 40 124 66 26 203 78 220 166 73 142 150 63 166 17 119 99 243 166 176 210 220 215 118 253 59 143 35 122 222 50 58 29 51 211 19 174 220 236 227 198 71 227 70 156 97 25 76 78 210 252 109 98 200 134 0 148 114 221 154 66 23 196 248 37 253 225 184 18 33 116 236 252 67 236 135 114 205 157 120 160 155 132 133 60 83 40 206 205 65 122 27 3 244 137 119 158 91 42 59 189 57 230 202 3 71 214 181 17 91 237 71 219 25 87 69 187 54 79 222 40 229 9 229 71 160 174 72 187 107 25 142 156 159 128 201 103 230 130 228 230 37 21 220 76 245 164 173 70 236 120 248 32 0 235 8 226 156 150 195 159 49 115 251 27 199 242 115 185 77 140 190 205 244 7 223 191 94 162 200 1 170 101 82 196 36 62 145 104 149 184 123 177 153 15 220 14 50 253 40 5 192 198 227 129 195 234 3 23 1 199 104 182 67 51 17 31 177 252 147 96 76 24 221 202 12 236 136 115 123 75 165 115 55 2 242 194 9 252 13 250 160 95 132 217 253 162 222 168 205 117 26 224 163 41 136 164 32 42 40 60 7 24 87 230 249 31 58 236 150 135 184 249 22 205 31 97 180 112 137 182 250 89 4 221 38 113 74 247 168 206 215 112 54 174 17 124 134 22 229 141 40 117 220 60 36 142 159 28 196 12 79 250 234 136 200 220 192 151 253 59 63 143 176 44 197 118 7 251 9 88 225 69 165 197 229 146 92 13 230 142 60 188 7 204 81 241 42 116 68 128 100 171 169 163 137 188 9 17 212 4 231 195 226 170 216 196 24 94 172 65 211 52 75 97 206 167 143 24 61 168 230 229 31 239 42 70 74 67 179 96 52 199 96 80 117 42 122 92 36 146 138 21 213 65 96 75 175 232 31 107 43 33 91 231 154 123 5 24 28 139 122 138 127 91 147 185 79 21 150 196 39 242 145 196 148 195 22 235 187 30 46 175 109 249 30 33 44 231 138 19 255 207 171 119 184 201 171 190 52 6 187 143 13 176 206 38 141 52 54 14 234 19 13 72 228 115 134 239 231 78 161 68 240 39 189 238 92 137 134 220 92 228 98 165 0 223 127 16 233 228 150 150 183 157 213 170 18 108 187 193 244 40 94 214 27 214 103 133 11 23 106 140 153 150 249 216 192 173 245 226 15 71 223 152 10 15 241 34 209 142 177 116 19 237 153 115 235 149 33 51 8 136 185 42 26 124 13 143 64 6 191 151 249 2 34 136 141 198 23 227 78 45 51 175 180 143 131 177 93 122 47 116 190 243 99 42 32 159 106 87 251 223 159 179 37 63 143 200 173 119 171 27 79 79 149 2 209 224 156 255 224 213 5 208 114 14 166 128 135 141 222 107 146 148 60 212 87 95 249 62 108 29 151 193 171 48 111 202 218 27 135 180 253 254 184 223 129 63 91 60 123 221 98 165 199 70 36 4 155 209 197 95 213 90 27 172 67 75 182 52 134 225 138 50 128 100 245 153 1 73 95 228 92 254 186 19 225 208 85 38 151 24 215 131 149 191 230 74 57 107 248 227 229 111 209 108 16 211 152 104 163 251 128 215 147 85 150 15 43 134 83 159 42 239 54 28 40 73 52 207 84 129 239 98 214 179 21 102 137 178 110 247 152 202 120 33 245 91 121 128 234 177 58 4 101 109 183 205 222 157 164 79 7 109 210 19 253 233 66 110 212 180 156 55 124 37 83 157 36 52 71 108 27 185 118 84 11 222 1 186 180 176 54 75 2 134 10 200 41 247 243 115 198 166 236 142 190 189 239 126 125 106 88 219 213 89 86 112 164 28 237 40 73 163 214 41 167 51 226 144 185 109 128 31 24 46 11 81 151 124 82 134 29 127 35 25 190 38 212 98 223 126 203 32 60 74 103 251 72 156 19 78 206 72 239 13 5 249 184 234 54 28 128 245 0 249 90 69 3 123 98 160 210 186 41 73 17 3 28 112 129 216 217 199 108 97 59 3 225 73 152 69 217 146 229 62 27 45 119 23 226 20 9 145 94 46 115 121 134 233 179 133 155 94 199 108 100 28 131 175 206 140 90 173 14 18 76 19 202 83 159 22 214 223 144 183 119 149 129 120 70 181 99 68 133 35 149 192 17 182 40 216 129 186 185 222 109 72 135 219 119 115 196 249 44 150 83 58 212 26 210 154 53 109 49 36 39 146 188 84 202 107 117 165 30 161 103 160 138 30 154 85 67 10 214 221 117 225 102 176 143 120 211 187 176 196 245 60 28 179 165 154 167 22 55 97 242 45 252 235 170 218 20 43 72 243 201 54 123 101 20 33 48 168 180 233 60 232 203 7 66 56 124 146 214 112 254 140 37 96 243 38 179 116 69 25 227 129 70 166 160 195 95 119 149 251 212 214 138 62 183 247 149 85 11 116 61 189 17 187 149 100 21 248 121 103 245 72 14 36 248 191 128 103 91 132 118 39 131 121 52 247 206 93 47 82 113 11 31 148 91 121 169 110 211 31 34 248 177 165 90 108 123 99 171 35 104 32 238 176 63 65 30 99 58 169 225 58 211 237 4 229 142 123 59 108 223 136 197 220 218 91 179 0 121 93 76 67 65 204 151 161 33 65 74 212 79 82 70 71 34 30 120 110 193 0 36 170 193 44 45 143 228 131 205 150 244 160 150 106 22 65 152 121 20 125 25 104 52 133 104 165 184 88 121 83 121 93 99 250 114 15 118 56 143 178 96 88 189 162 5 211 244 73 153 40 207 205 71 138 167 60 186 201 213 118 68 181 199 75 78 195 34 132 17 127 183 98 72 65 22 255 140 196 232 205 157 2 110 42 175 37 4 30 101 25 242 48 107 25 105 159 30 213 210 157 118 121 51 157 187 180 131 3 44 5 185 15 215 79 162 2 26 65 168 188 175 126 122 46 117 97 63 225 223 18 22 211 203 44 218 82 158 29 119 110 57 91 14 143 66 109 2 240 56 94 247 35 47 101 146 49 98 29 193 204 226 150 16 203 189 11 251 203 208 29 186 250 218 53 107 74 41 140 45 140 4 31 27 113 69 36 188 128 46 81 132 34 77 101 50 169 28 156 133 164 129 253 215 241 194 174 172 194 42 220 190 205 227 223 125 42 185 109 222 61 100 144 193 147 66 193 232 72 220 164 225 179 24 189 206 106 11 94 84 43 63 244 25 229 114 152 79 232 252 147 54 43 138 6 104 248 81 78 162 136 226 36 206 113 106 248 66 115 193 28 216 164 130 112 222 54 251 213 143 169 214 127 195 37 79 48 191 31 239 222 47 54 197 188 194 74 4 90 50 70 38 100 59 49 223 218 178 37 231 49 12 152 217 227 91 99 20 154 159 152 122 106 149 86 103 187 70 156 1 251 186 172 207 166 67 51 147 24 159 0 66 193 212 209 173 202 54 121 186 247 106 241 139 248 136 144 151 199 247 80 188 144 101 75 21 223 57 158 220 219 236 232 23 100 202 212 173 34 206 147 90 245 218 205 94 143 37 178 123 245 10 207 222 177 255 205 243 59 2 92 205 14 246 210 227 42 114 60 115 43 247 225 110 54 179 180 171 8 226 94 227 206 84 12 108 245 165 220 186 62 202 190 198 31 48 221 104 253 145 8 22 239 235 157 224 89 115 154 66 225 233 26 132 65 101 103 113 198 133 195 218 235 163 15 66 48 130 138 254 104 191 21 132 73 188 3 18 49 233 212 33 173 203 85 255 167 237 129 60 173 232 204 54 14 112 18 11 20 121 253 133 205 30 128 169 42 1 114 138 184 35 247 111 197 232 255 8 125 197 39 27 123 188 217 183 113 101 115 55 200 76 41 136 182 194 36 115 226 46 180 223 15 180 184 199 127 207 175 183 18 108 253 224 68 225 189 230 145 197 113 58 99 64 169 236 231 55 89 138 194 172 139 126 15 235 114 7 190 146 185 206 38 26 160 116 201 4 85 157 75 151 138 219 4 150 5 192 67 120 123 231 151 29 125 34 237 37 125 175 14 219 63 40 148 37 198 227 142 220 5 165 190 80 20 226 226 188 106 110 189 68 213 83 144 111 161 33 212 140 77 52 244 117 247 254 247 134 221 112 95 223 125 162 95 247 113 127 148 138 20 251 103 234 125 73 19 94 81 44 249 114 11 173 196 15 63 229 13 115 251 195 11 98 206 183 202 33 193 89 219 11 110 155 116 53 252 253 48 32 153 170 120 19 185 239 38 248 134 53 99 79 234 178 251 112 68 87 151 119 91 159 228 132 234 207 90 233 251 86 23 140 87 198 204 228 239 33 97 205 23 105 57 191 169 94 234 175 182 54 157 209 165 39 1 23 153 99 4 83 250 118 150 110 225 141 205 108 23 85 157 117 151 134 213 237 178 162 80 51 220 165 2 220 8 167 35 52 225 141 195 156 254 21 76 95 231 237 249 231 199 223 249 56 16 105 49 246 179 86 86 199 222 103 162 50 165 41 77 133 132 4 246 90 221 161 237 175 20 1 224 5 208 134 151 85 245 81 241 166 113 128 176 170 18 208 148 167 107 165 84 201 247 77 110 178 243 212 76 28 185 151 25 3 254 91 135 233 7 181 194 191 189 100 178 100 20 92 126 239 85 113 127 203 20 251 252 161 1 63 35 197 97 30 51 62 136 236 104 162 216 84 86 49 130 181 92 215 169 183 20 181 106 88 75 233 118 139 43 234 2 58 27 15 194 152 140 103 217 39 100 170 4 96 201 205 75 153 189 203 211 117 177 25 176 204 93 16 68 7 53 84 183 210 189 91 68 187 188 136 34 168 145 152 249 26 42 26 225 31 239 15 249 137 120 247 29 172 107 103 137 180 207 217 121 27 149 32 90 137 141 176 165 165 165 165 1 0 0 64 0 0 172 94 103 33 181 100 23 240 0 0 15 252 0 0 40 248 0 0 0 0 0 16 180 253 0 0 7 90 0 0 2 148 0 0 0 0 15 0 77 121 80 108 117 103 105 110 54 56 75 46 112 114 111 106 0 1 162 139 77 77 80 82 67 87 73 69 1 0 3 128 0 129 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 37 135 0 0 9 73 0 0 0 0 15 0 66 193 212 169 9 210 149 55 104 18 166 123 198 254 115 231 189 56 26 63 233 107 89 215 26 41 64 39 168 254 239 247 106 245 213 179 37 162 85 150 47 25 75 142 73 147 42 103 39 18 89 87 185 158 183 144 191 121 197 58 247 237 47 168 4 250 221 80 196 140 250 2 153 82 24 7 101 152 165 56 154 236 133 124 32 161 65 134 202 240 234 38 74 220 207 29 183 187 78 143 128 78 228 25 224 83 50 226 241 200 15 193 111 178 15 246 78 206 228 147 246 197 203 10 10 242 105 41 4 66 205 9 1 225 252 22 138 140 209 6 181 240 179 154 27 24 6 94 118 33 215 71 251 65 6 46 194 156 224 245 152 248 245 163 117 106 184 81 55 44 43 63 12 15 131 173 177 63 58 108 90 116 237 57 130 18 45 207 39 168 184 124 14 234 151 77 158 24 238 174 149 45 154 30 127 131 200 231 47 199 96 208 217 78 147 104 4 219 175 174 33 142 236 210 130 219 100 211 116 254 15 231 119 8 95 0 178 98 122 210 142 229 104 67 70 12 175 141 92 58 110 110 125 213 36 115 84 117 144 245 75 148 181 55 130 172 219 99 192 169 188 102 174 245 3 98 201 249 187 198 155 60 173 205 234 41 227 58 211 109 39 124 98 234 206 156 15 73 86 25 233 109 125 254 184 178 214 178 133 136 246 117 48 173 55 248 26 8 190 78 97 200 67 23 26 223 148 9 135 229 250 93 43 221 207 238 48 11 146 126 167 202 57 129 122 208 16 68 11 171 85 193 55 197 75 206 6 101 225 159 104 37 53 24 149 113 98 108 118 35 180 159 124 25 241 188 82 51 147 186 228 19 144 214 103 241 33 199 95 1 89 148 121 49 217 177 30 75 206 83 68 131 49 235 210 72 87 124 132 117 54 28 248 36 131 82 144 238 147 41 18 75 146 21 97 35 176 24 27 156 45 171 65 232 213 217 183 86 97 199 127 122 105 229 192 146 21 171 163 104 83 164 85 85 159 97 16 133 250 117 123 35 109 109 221 183 95 120 25 237 167 23 213 43 6 178 186 44 154 201 162 86 26 136 87 11 90 163 230 224 102 104 162 19 246 228 233 218 91 12 199 141 183 74 205 224 12 153 150 177 85 0 41 202 28 63 57 160 34 129 152 15 10 240 140 213 45 91 151 230 63 252 32 81 62 58 251 113 147 52 74 212 214 30 114 32 135 185 204 7 224 181 26 172 91 169 81 65 140 201 52 185 195 170 193 233 103 214 112 109 65 219 94 83 253 182 167 152 47 211 90 104 203 34 241 216 55 162 73 128 24 254 18 243 43 51 199 224 93 181 216 4 195 100 21 1 142 111 89 99 181 120 228 69 89 150 166 67 160 133 83 74 25 120 228 202 151 213 197 238 169 7 25 75 215 132 139 13 128 148 42 185 174 244 128 76 188 161 166 164 16 51 147 115 251 235 205 105 232 86 142 76 237 244 167 29 43 177 248 156 194 246 97 15 7 255 213 141 41 156 105 175 207 13 3 192 68 119 2 85 97 230 126 53 40 79 97 45 221 168 205 66 34 36 28 180 173 22 22 180 51 194 56 193 255 243 75 101 57 141 155 154 6 150 42 8 180 204 128 177 95 60 122 220 131 125 225 225 49 227 224 60 187 72 148 80 225 109 173 250 161 103 80 190 248 119 106 225 182 172 156 189 14 39 39 172 51 134 119 87 74 119 174 13 184 80 179 206 211 203 197 4 98 108 88 244 9 167 90 0 179 111 74 175 93 37 151 71 255 226 242 57 3 70 223 10 238 143 109 72 108 218 5 38 140 97 70 133 196 185 229 124 137 190 203 76 81 53 60 4 82 244 201 125 216 66 13 237 218 214 208 120 143 242 251 23 135 220 72 32 82 237 68 189 70 62 224 254 70 62 224 229 134 119 188 130 31 152 255 212 226 149 189 221 60 223 148 73 202 157 18 249 54 56 126 101 207 255 58 91 68 133 67 118 98 230 235 242 45 38 75 183 17 235 204 212 204 222 45 249 140 101 163 86 59 125 195 111 43 228 127 205 120 199 85 241 203 115 36 38 114 138 200 134 12 65 52 23 170 58 186 89 15 23 144 208 141 125 252 131 154 213 103 133 164 20 24 181 20 212 220 255 114 55 158 205 47 147 146 107 120 61 236 170 84 104 212 61 32 201 252 208 92 120 214 182 30 6 28 5 1 22 67 109 244 114 222 27 168 58 178 108 199 187 12 57 225 72 255 253 245 130 250 31 222 250 246 10 101 46 52 182 55 251 253 245 81 49 245 105 93 45 82 221 74 249 125 1 22 82 12 24 109 64 86 153 199 117 92 85 16 118 131 199 159 35 198 115 25 194 53 204 76 60 91 61 99 94 137 235 45 223 47 205 83 53 161 9 165 132 157 86 145 51 163 200 190 148 205 153 118 167 140 3 86 133 127 81 179 26 56 173 105 221 157 174 25 29 252 191 134 231 205 247 66 63 40 168 20 174 40 253 99 88 50 93 57 46 77 42 38 230 44 152 237 96 246 158 174 127 80 223 21 171 208 218 64 83 60 6 39 178 161 246 16 149 28 35 238 182 210 44 48 166 87 16 17 60 128 20 135 242 84 199 79 197 192 216 159 45 88 172 97 28 155 254 95 247 229 19 84 119 64 208 127 23 119 239 50 27 133 55 86 37 222 63 40 63 237 92 219 43 139 185 171 144 78 174 41 45 134 33 179 81 222 241 244 47 230 107 206 53 93 206 223 25 220 198 187 145 188 22 208 189 21 158 201 29 156 207 162 236 106 151 65 58 250 220 39 200 228 244 143 101 56 32 72 194 32 92 161 170 95 226 91 247 74 68 91 243 111 13 53 30 159 155 43 194 142 72 76 100 240 231 155 202 2 170 87 103 101 137 13 158 138 204 152 21 128 163 227 158 239 113 74 203 205 138 28 253 172 176 47 237 128 246 167 129 252 181 12 189 44 9 25 249 55 100 198 20 247 11 221 58 43 244 154 235 66 177 195 182 215 227 81 34 233 12 208 171 215 60 228 237 247 68 237 254 101 72 11 189 214 132 0 237 192 83 247 146 44 29 115 128 161 61 99 89 134 224 142 199 58 193 76 75 167 233 190 242 240 211 62 140 149 132 19 231 30 187 11 119 216 16 130 123 220 109 76 105 8 8 51 177 93 127 176 168 236 224 185 239 147 241 252 89 235 117 89 232 240 134 105 5 97 209 251 211 122 163 130 146 101 27 0 163 26 227 99 143 189 100 252 184 92 204 15 249 41 66 137 162 186 236 108 107 110 37 6 27 122 43 43 183 9 177 188 52 107 174 190 52 142 8 234 72 246 140 207 86 16 62 58 111 246 174 164 206 167 225 25 226 156 194 36 44 43 216 74 52 246 175 115 93 50 77 141 193 52 62 121 123 202 32 231 159 172 154 127 94 71 139 59 99 60 95 93 5 219 230 131 152 119 71 166 108 172 186 159 236 122 151 241 89 190 225 248 70 6 59 222 41 63 1 165 51 242 86 140 13 190 182 4 62 76 202 29 142 235 136 247 213 221 89 87 129 198 64 125 243 139 125 99 248 77 77 161 154 149 206 132 228 19 219 21 20 117 100 106 17 25 129 82 47 223 238 149 91 209 180 62 152 199 225 74 120 88 182 193 105 50 55 18 249 249 177 21 79 110 42 239 129 88 200 29 133 34 98 15 45 175 191 221 140 248 216 149 245 89 166 178 80 182 78 190 69 50 222 205 239 161 190 224 7 58 209 212 252 3 217 253 195 183 64 52 49 155 161 91 219 253 14 98 134 170 152 67 190 151 34 0 244 30 29 40 140 166 74 48 227 156 179 126 37 235 250 104 255 27 136 65 183 130 244 43 240 35 123 226 134 15 235 124 3 209 133 214 35 208 2 203 15 238 71 79 163 249 77 38 232 160 127 174 99 90 151 104 248 47 21 102 40 10 75 7 38 213 12 191 187 208 175 51 104 120 67 247 117 94 241 128 200 6 166 210 115 55 169 169 217 14 21 75 98 182 140 181 241 103 66 242 210 58 92 215 100 223 168 223 224 23 185 68 213 123 36 81 24 49 168 209 69 245 79 245 26 172 28 132 233 201 18 122 188 2 206 212 185 33 163 205 123 122 253 31 107 244 225 171 154 126 238 192 76 97 3 130 6 136 89 106 53 55 117 226 25 20 196 35 147 112 210 205 162 106 50 158 32 159 46 222 213 182 51 197 240 80 51 244 161 110 150 205 10 210 29 211 191 134 8 62 165 173 11 212 161 149 21 59 192 148 10 206 136 162 153 70 254 239 231 184 38 59 63 15 77 159 36 158 37 220 110 219 185 101 189 130 102 113 59 89 8 251 111 16 111 199 206 9 183 37 71 67 15 254 146 122 128 22 246 172 83 255 83 89 0 246 254 92 199 238 49 177 50 56 60 7 47 70 50 98 209 93 12 210 64 75 186 162 82 59 16 42 28 252 150 217 13 179 131 109 44 168 155 109 124 107 172 34 39 56 93 136 156 226 51 195 139 240 86 22 205 163 244 246 122 13 115 134 172 202 203 8 83 178 251 160 6 219 89 67 181 18 209 214 63 231 59 24 227 158 23 7 240 58 71 177 7 113 158 183 64 244 85 7 107 227 60 68 82 254 89 181 121 244 154 127 239 164 100 253 201 24 40 247 95 2 117 74 39 105 8 93 65 60 200 39 164 174 113 104 28 234 29 2 248 240 139 89 240 62 145 199 95 144 239 95 112 133 161 248 7 69 77 160 179 10 214 118 130 47 36 196 113 185 107 12 184 128 166 184 156 240 64 39 22 137 148 42 166 209 186 106 148 29 222 181 182 12 140 98 107 232 202 192 126 214 67 12 90 3 7 248 95 36 76 59 188 66 63 98 47 55 72 103 196 189 55 155 89 36 43 7 171 26 228 14 129 26 180 143 57 83 243 131 55 10 86 141 23 182 84 53 42 118 71 72 221 140 17 103 43 14 243 168 38 236 161 104 222 196 131 99 100 2 95 182 238 89 158 129 168 152 135 33 197 190 201 123 56 211 17 219 71 63 164 17 28 210 229 135 70 215 21 37 111 40 118 238 71 231 185 92 225 238 138 15 196 191 125 76 175 41 229 73 155 45 56 91 234 166 249 104 4 179 127 38 179 30 101 157 148 54 199 109 249 21 239 65 56 118 173 182 77 172 225 67 185 168 180 146 85 179 50 125 131 216 129 42 197 47 124 221 171 199 98 155 4 245 181 64 165 225 148 159 88 65 126 225 27 188 72 65 126 66 80 88 14 250 23 35 36 212 224 92 173 32 66 193 212 120 244 150 156 45 75 143 253 186 160 103 148 110 138 210 209 163 125 11 126 208 172 225 255 129 97 133 7 117 173 34 14 198 74 241 119 114 179 69 78 241 172 212 89 124 91 120 8 205 235 82 98 142 194 32 245 179 201 44 162 110 214 68 254 158 4 147 19 254 191 118 156 232 12 254 184 209 40 217 121 173 182 158 0 168 203 19 227 183 248 42 166 119 134 20 184 72 174 2 197 58 133 29 213 233 74 101 1 85 71 25 150 55 32 225 207 234 168 1 132 48 188 104 84 53 145 212 222 88 12 164 128 218 29 207 78 77 249 16 88 28 232 164 142 192 159 5 8 135 38 217 75 132 1 169 131 180 254 194 85 160 186 146 180 24 82 91 133 163 169 12 134 152 70 138 133 74 186 173 245 88 137 116 233 235 3 118 28 107 126 133 54 54 53 235 170 9 149 65 194 190 72 136 43 247 87 106 245 14 28 216 174 131 61 75 2 32 48 18 90 42 185 42 139 107 94 143 236 239 204 214 131 5 194 198 84 239 253 129 60 182 156 134 15 194 224 152 87 64 148 238 6 49 222 188 124 178 199 34 127 212 174 139 147 19 174 19 177 25 35 173 239 20 162 133 142 35 21 226 49 117 215 117 82 150 137 206 32 224 106 132 88 229 130 225 121 252 199 118 93 193 14 161 171 76 13 36 30 78 89 226 51 243 117 178 220 71 194 253 155 147 117 169 112 214 170 151 80 176 47 113 137 200 71 128 223 66 205 149 141 14 174 254 215 224 212 209 129 71 42 114 80 117 179 6 107 207 86 126 92 5 186 201 125 182 1 242 50 66 210 232 200 192 245 137 242 31 142 235 147 161 97 3 161 124 80 122 86 211 86 19 222 78 188 48 94 226 5 28 139 115 71 189 71 214 76 63 3 208 118 242 103 42 218 166 31 193 172 90 1 221 207 45 41 132 69 109 253 53 20 18 46 39 129 112 108 97 15 218 100 16 0 87 235 39 246 68 156 112 218 135 240 49 235 29 171 113 255 41 197 77 237 159 181 64 19 122 215 56 164 218 187 2 68 137 251 240 202 132 181 223 81 212 100 47 233 101 78 16 141 85 48 151 108 6 121 86 47 13 210 187 225 178 157 228 22 177 139 131 77 189 136 67 214 106 21 35 156 24 206 241 20 160 172 42 105 163 82 42 95 198 28 128 214 182 183 18 226 9 84 238 73 67 7 6 79 149 143 81 6 165 26 204 217 230 127 245 25 64 156 2 31 40 230 31 152 83 16 27 19 48 88 183 13 234 44 214 230 142 115 130 245 184 253 244 91 188 169 175 129 42 172 27 94 36 204 250 103 164 187 225 237 171 117 127 191 201 200 10 17 53 9 251 134 12 155 134 192 93 150 96 13 18 25 200 160 243 9 207 137 253 198 235 76 86 159 204 94 141 69 7 244 119 142 65 54 80 199 204 199 217 168 184 53 128 33 0 165 165 165 165 1 0 0 59 0 16 181 174 127 194 181 175 1 132 0 0 28 169 0 0 43 74 0 0 0 0 0 11 142 68 0 0 2 170 0 0 1 124 0 0 0 0 15 0 83 113 117 101 97 107 65 112 112 46 114 0 1 36 38 84 69 88 84 67 87 73 69 1 0 3 192 0 1 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 1 154 0 0 0 105 0 0 0 0 15 0 66 193 212 165 47 158 101 198 187 5 232 62 137 252 56 69 246 56 206 7 115 110 186 70 46 70 112 68 98 27 12 96 93 177 126 138 205 129 15 225 200 70 141 184 144 238 51 187 21 2 100 253 33 237 17 99 201 74 232 168 36 57 93 93 223 103 146 181 14 19 20 203 255 77 196 6 172 46 213 244 253 180 118 156 135 21 216 169 140 101 119 170 86 133 3 176 82 146 129 56 164 43 198 114 16 66 193 212 157 170 210 35 52 27 93 136 197 106 52 54 31 166 122 205 231 32 32 112 160 40 138 126 3 77 99 4 251 242 199 125 87 169 103 99 226 123 60 70 128 113 18 28 85 6 189 121 109 31 26 249 161 83 169 157 62 74 239 8 51 45 186 94 58 49 252 46 209 169 153 202 106 248 205 178 15 4 139 59 160 209 168 125 168 73 48 103 120 110 199 109 171 159 179 239 33 94 118 136 247 133 234 179 177 46 218 151 77 116 44 159 93 94 44 99 70 93 125 137 53 84 131 32 59 239 13 28 34 65 92 91 104 119 79 119 174 134 219 228 67 30 37 182 200 207 220 0 237 187 20 146 233 200 152 182 39 167 14 242 53 180 240 195 154 154 94 91 182 52 134 249 136 119 67 194 147 228 97 60 211 48 22 65 190 202 99 103 114 208 10 131 161 3 87 31 64 250 4 254 133 169 217 77 183 225 106 142 240 240 180 146 248 39 192 170 88 102 69 95 13 89 148 174 206 78 162 131 133 161 167 150 32 158 248 178 173 101 227 217 102 143 206 171 62 75 41 237 239 9 58 126 14 226 107 122 250 208 40 209 10 252 105 101 26 155 10 18 126 136 104 210 186 8 64 134 82 245 212 110 151 241 61 69 16 181 128 165 251 123 137 63 121 161 161 183 56 176 164 4 136 161 23 48 88 225 129 48 129 37 151 67 233 215 152 90 89 82 27 227 240 224 102 238 138 80 14 201 181 17 19 136 193 127 207 108 171 212 101 238 237 175 10 248 251 8 248 107 203 87 203 119 235 140 103 161 208 168 170 55 199 88 185 214 52 170 233 214 179 94 170 196 230 181 174 40 0 165 165 165 165 1 0 0 68 0 0 181 174 119 219 181 183 37 82 0 0 40 248 0 0 43 246 0 0 0 0 0 20 128 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 113 117 101 97 107 67 97 114 98 111 110 65 112 112 46 114 115 114 99 0 1 224 122 114 115 114 99 82 83 69 68 1 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 1 56 0 0 0 54 0 0 0 0 15 0 66 193 212 120 70 64 63 99 16 59 255 97 202 132 145 70 204 255 242 147 131 117 178 216 188 111 47 148 73 157 252 231 185 213 153 225 248 22 106 46 220 74 229 99 130 75 44 98 229 175 219 67 79 64 165 165 165 165 1 0 0 62 0 0 181 174 119 219 182 174 202 51 0 0 43 74 0 0 57 141 0 0 0 0 0 14 248 37 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 113 117 101 97 107 65 112 112 46 114 115 114 99 0 1 174 60 114 115 114 99 82 83 69 68 1 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 40 111 0 0 13 39 0 0 0 0 15 0 66 193 213 19 32 207 221 161 198 69 165 49 49 163 44 68 182 220 208 98 3 104 90 104 50 121 149 179 221 229 227 218 24 177 155 55 76 59 170 223 31 186 42 107 230 227 232 78 210 112 78 144 78 101 153 20 100 21 113 34 86 121 4 82 215 232 227 236 158 8 177 190 230 223 83 84 237 148 7 170 219 251 49 107 209 121 95 19 142 221 245 229 208 93 102 171 66 93 51 91 15 192 115 41 146 47 38 44 128 149 206 19 73 214 243 63 134 185 162 63 190 209 118 46 232 38 160 233 103 92 179 67 170 147 238 96 5 178 108 31 198 142 27 71 0 252 18 157 84 217 115 240 55 138 8 134 100 181 201 91 154 43 221 56 198 203 54 203 223 246 78 211 75 62 202 147 101 108 145 98 255 87 81 19 116 84 105 20 53 35 186 106 250 114 137 91 30 167 101 76 166 46 241 174 167 210 92 15 66 47 106 89 111 95 216 169 157 97 204 203 175 67 131 100 228 115 101 202 102 201 85 197 128 102 224 152 248 208 22 182 13 65 185 43 236 146 8 103 164 68 199 167 90 161 44 115 100 75 148 212 133 205 185 240 91 254 62 54 53 239 150 84 98 211 70 114 120 183 103 103 115 93 178 126 224 111 251 255 187 2 190 193 166 28 139 27 108 150 55 252 38 95 40 204 61 107 86 49 0 195 169 32 120 204 107 253 57 197 232 114 108 33 166 115 221 202 25 154 147 237 211 246 212 49 74 55 186 91 190 105 219 116 226 226 36 175 193 108 174 164 118 229 107 74 31 1 243 123 184 154 227 118 219 112 165 164 185 116 70 7 186 27 160 3 238 43 56 239 52 158 217 130 219 45 109 54 78 222 17 74 25 52 114 1 227 42 217 72 253 223 216 56 77 220 203 181 240 246 160 86 241 58 137 154 1 231 100 197 96 17 176 142 199 47 194 252 250 110 162 91 79 145 135 5 163 208 132 42 60 79 75 147 68 55 152 119 214 213 47 14 150 27 193 38 43 165 127 127 75 132 242 209 231 232 89 126 66 156 28 75 227 86 88 207 237 205 174 175 87 163 66 170 84 73 46 254 137 242 54 115 196 174 218 202 97 38 219 195 93 60 181 174 167 59 231 121 249 72 52 73 75 49 207 153 183 36 92 152 67 144 242 41 95 120 53 6 194 187 37 81 183 108 61 251 97 133 131 117 112 185 189 62 47 242 76 213 173 190 134 5 232 230 42 251 141 208 92 172 43 245 73 101 64 52 209 174 19 130 208 81 142 251 177 162 137 173 180 116 194 47 225 254 183 79 149 232 26 99 207 157 241 164 100 3 186 7 25 232 127 100 208 251 155 101 111 175 18 151 221 250 195 184 196 181 223 15 54 248 124 35 187 40 151 41 162 220 124 117 110 240 242 156 16 128 130 181 96 83 246 199 168 56 206 43 80 29 245 175 249 35 121 248 210 115 72 76 23 244 205 19 44 64 136 208 49 43 150 23 231 121 254 6 231 177 35 162 187 223 239 42 173 134 19 0 89 208 123 54 205 224 15 205 97 164 189 131 196 241 126 185 8 93 180 37 22 54 115 85 228 67 22 121 189 141 18 110 1 205 209 142 54 99 120 183 30 64 50 129 77 78 2 108 20 222 78 4 196 116 123 27 208 185 42 199 162 209 56 42 240 245 155 178 100 14 196 7 90 223 49 48 79 61 11 90 253 199 86 80 19 205 111 23 176 155 168 173 95 195 147 132 14 44 241 9 253 193 84 44 17 35 235 138 211 59 120 166 225 221 214 151 115 215 190 143 100 85 97 131 201 229 20 29 6 177 48 253 73 42 243 168 86 179 189 136 135 245 28 120 11 125 43 166 135 159 177 12 91 121 192 204 111 227 246 110 126 20 113 118 230 21 222 213 193 151 95 119 19 64 195 190 11 255 236 12 53 217 217 164 245 66 15 169 197 234 18 160 163 213 203 198 254 2 168 126 135 240 211 150 94 17 120 8 230 236 30 214 12 54 138 83 68 206 177 106 247 90 231 78 229 141 54 66 178 53 181 39 13 67 163 90 118 85 238 106 13 34 247 121 208 97 216 135 178 131 164 60 128 39 207 5 45 30 199 202 211 97 254 73 193 243 155 54 76 45 121 160 182 126 140 113 2 65 248 17 85 31 25 236 44 38 214 132 73 75 83 62 179 21 33 158 252 11 206 36 230 207 236 81 224 140 196 197 246 50 241 165 35 75 106 207 58 3 172 187 78 242 229 110 193 138 71 36 103 230 54 218 187 141 183 95 200 100 78 202 203 196 63 162 46 134 184 71 157 59 151 181 120 241 241 166 173 125 218 222 67 3 56 86 180 135 209 65 46 217 36 118 162 15 131 233 0 150 122 247 228 219 147 251 75 116 57 114 145 32 221 14 127 211 8 89 128 49 218 182 44 125 14 162 144 101 36 100 103 27 61 93 100 118 151 153 231 153 236 104 245 153 21 173 185 70 90 220 219 66 109 96 242 235 80 212 196 109 167 151 243 83 221 180 155 122 218 166 191 107 15 36 201 123 1 212 157 98 164 105 93 73 241 244 43 2 239 247 167 159 236 223 105 79 67 147 194 117 75 219 109 243 197 157 128 58 253 11 160 194 232 136 9 127 62 58 185 146 230 71 38 161 142 235 225 251 51 18 206 250 66 163 161 34 160 147 109 207 14 170 252 222 162 124 132 139 20 28 97 180 112 0 144 62 117 118 177 199 231 5 68 201 122 252 235 77 175 203 131 88 117 176 140 114 97 74 4 217 241 184 41 254 39 165 101 134 215 124 16 64 168 145 213 83 212 125 51 229 219 212 246 166 251 105 150 176 97 253 37 98 188 174 169 112 138 151 120 93 98 2 174 18 73 208 121 65 129 7 121 50 168 56 106 226 162 117 246 232 112 26 105 133 169 49 57 78 44 144 238 238 111 70 45 16 245 193 185 20 238 75 242 230 177 89 253 10 160 126 246 119 90 247 154 243 79 125 170 174 45 41 57 237 169 182 17 176 49 32 199 54 145 169 163 119 196 156 170 59 214 179 150 90 80 122 51 110 227 203 250 15 200 0 199 253 135 1 26 210 220 211 224 29 63 201 148 180 149 137 50 192 140 89 93 177 178 201 214 181 181 205 237 185 39 229 87 187 146 107 1 126 57 29 24 15 210 184 50 46 103 7 254 73 65 83 142 2 42 47 26 120 3 2 181 53 121 3 59 73 63 52 118 204 213 14 161 85 127 74 111 85 189 190 136 234 197 105 224 147 43 252 91 63 191 106 169 2 187 219 161 122 210 145 110 155 53 165 245 56 107 201 8 21 24 135 140 117 79 142 157 158 243 229 177 53 129 115 200 64 113 172 165 163 114 39 190 159 181 139 43 151 228 202 167 106 31 232 34 241 141 224 19 110 80 242 75 1 168 216 114 161 72 142 6 210 129 8 253 30 134 0 132 170 150 196 243 94 142 178 77 131 154 74 222 86 171 21 162 224 14 12 92 175 166 8 103 120 231 96 121 159 254 243 8 58 97 47 104 236 245 123 97 69 65 194 201 142 238 214 51 59 133 59 61 216 63 237 71 228 47 18 80 71 180 196 255 202 109 101 6 132 2 230 189 39 1 232 7 243 166 170 151 181 151 24 2 162 123 101 149 5 193 126 159 0 107 235 124 0 81 197 203 251 245 20 197 40 68 26 101 95 142 221 53 148 101 28 69 243 32 1 140 190 24 42 180 77 21 229 116 163 137 38 88 175 194 187 33 232 13 94 61 2 201 2 117 150 35 221 25 251 67 172 42 99 161 98 18 127 255 7 190 23 54 89 71 17 239 126 130 160 92 150 91 176 55 26 96 17 144 211 130 143 205 52 11 39 209 73 102 80 153 211 52 13 113 200 32 246 78 123 245 86 140 157 235 132 215 86 102 46 65 124 127 181 190 237 140 86 34 254 155 226 210 2 243 100 155 74 24 207 95 27 36 135 58 47 42 162 157 222 182 131 228 123 216 96 17 255 148 219 176 53 35 187 216 247 188 0 33 123 213 195 111 164 59 82 31 235 13 165 226 90 82 187 84 149 58 232 84 191 19 65 144 139 42 224 243 159 71 17 95 34 236 46 181 186 19 253 201 220 70 25 183 172 26 251 197 44 205 214 154 55 124 21 185 97 245 216 198 87 6 47 218 209 245 112 46 22 245 12 186 119 158 4 243 85 70 158 250 160 224 122 226 142 185 13 102 82 121 117 93 204 176 110 220 150 206 132 3 157 23 70 8 30 92 39 57 240 92 4 111 228 32 138 158 79 152 204 43 123 75 106 220 126 3 115 197 39 209 250 64 235 65 137 148 74 249 89 39 46 175 81 110 238 228 202 180 65 110 182 49 93 33 150 40 124 133 254 49 191 138 24 5 198 183 93 109 143 40 122 228 245 91 205 152 194 6 147 95 191 104 142 112 178 65 95 153 202 197 164 192 89 199 230 224 120 132 124 188 110 248 47 204 178 204 194 9 247 101 4 5 66 94 228 240 146 166 89 88 104 244 48 112 21 13 170 58 132 254 42 32 253 196 30 160 184 95 32 52 185 66 33 77 25 6 239 225 205 66 151 155 36 157 150 37 145 49 232 172 97 169 19 169 164 180 245 222 209 172 188 53 36 55 136 231 28 35 168 16 17 188 192 249 213 30 192 142 119 8 205 175 189 22 154 38 111 163 181 73 209 31 198 93 97 156 188 48 37 198 24 148 193 126 201 7 36 198 125 11 33 149 91 144 17 228 69 76 157 220 3 156 14 0 81 140 208 78 68 18 32 12 99 193 90 202 197 253 207 50 192 160 206 68 106 31 137 133 68 90 25 230 88 128 244 164 119 94 31 103 19 24 85 110 216 115 58 31 247 91 224 206 251 182 24 41 102 12 75 92 171 164 61 83 4 23 189 228 149 47 222 167 114 166 232 172 235 220 6 90 84 125 43 176 237 139 3 75 250 147 201 21 165 86 185 167 253 83 250 223 76 202 72 129 224 204 105 109 167 141 116 159 178 238 125 174 216 32 103 184 62 30 193 129 200 168 216 77 14 240 25 167 11 135 147 132 253 147 163 230 81 55 101 169 251 167 64 58 0 117 232 124 230 12 231 7 107 170 216 77 154 99 146 141 43 30 208 151 213 160 45 92 104 19 173 47 39 92 50 82 136 211 29 15 239 22 211 186 249 135 31 115 152 126 108 88 190 151 161 55 18 53 125 81 253 44 223 173 192 0 161 218 62 174 8 1 76 122 7 151 154 165 214 33 223 88 7 33 123 159 235 236 159 138 129 144 207 133 34 248 111 102 4 110 51 122 82 23 96 101 68 110 146 19 27 14 13 255 211 145 37 67 180 117 157 162 67 39 122 105 251 112 157 224 127 86 244 92 183 189 72 102 128 9 146 92 28 247 181 210 206 18 96 101 51 198 77 13 123 209 234 106 160 180 174 129 86 19 67 175 25 205 73 234 156 132 12 64 247 135 37 244 29 156 196 123 179 70 126 12 91 137 147 8 212 47 248 167 50 221 101 22 19 186 106 251 100 198 184 253 75 32 232 95 40 75 87 195 21 154 186 68 81 227 234 19 174 173 74 87 146 87 146 167 20 153 127 162 128 26 103 98 127 92 99 61 85 8 194 46 124 93 203 129 50 192 212 66 151 189 180 42 109 122 69 55 81 253 94 8 197 6 43 181 98 26 63 81 4 101 222 255 203 17 13 225 6 247 132 146 242 152 129 95 80 196 251 153 254 93 120 121 9 150 121 197 137 129 252 84 73 36 226 38 31 154 195 62 253 142 128 31 253 105 222 94 26 100 125 88 17 158 18 182 128 179 153 187 113 241 103 236 34 61 210 93 49 62 127 157 3 38 57 17 41 73 11 248 215 197 118 246 204 208 26 11 171 159 111 37 200 49 185 95 185 161 68 75 99 226 61 111 65 42 233 41 158 183 66 138 96 236 114 220 43 148 133 251 182 237 171 168 11 49 5 79 249 112 23 91 102 60 125 106 99 204 44 37 251 17 7 192 7 93 107 42 118 214 101 21 32 193 164 159 26 229 131 76 91 63 40 22 105 215 185 255 34 161 218 14 254 35 221 48 242 64 3 226 102 118 118 64 201 157 91 57 84 246 232 80 55 16 205 103 205 159 182 179 87 5 157 15 136 192 114 165 233 140 132 146 11 153 234 193 51 184 136 16 88 83 252 76 217 58 235 134 122 194 166 165 168 215 65 197 191 135 254 138 183 78 231 196 240 233 207 54 25 190 162 140 8 150 132 57 202 29 63 111 102 103 74 174 155 24 217 142 72 240 189 94 13 159 61 172 54 43 3 223 179 152 173 134 111 198 192 109 213 223 220 102 193 109 211 24 122 68 213 25 79 13 200 136 155 233 162 128 238 61 57 20 112 113 7 142 173 139 113 103 249 158 45 177 157 167 34 251 43 5 14 253 253 14 40 124 119 129 108 173 217 13 17 94 63 81 61 169 191 38 236 189 245 152 155 229 82 196 22 91 154 60 182 2 221 132 185 173 47 252 217 68 111 6 231 238 249 161 177 236 40 200 62 84 129 46 98 132 50 245 133 141 112 75 238 106 53 52 147 89 160 165 64 244 220 112 205 219 46 164 187 123 206 235 74 178 117 194 171 96 25 57 172 128 18 30 200 118 12 16 177 222 25 33 118 181 59 94 92 137 169 244 134 147 26 115 56 6 63 14 191 228 164 68 122 146 143 39 233 122 118 112 96 145 193 81 52 99 156 41 213 247 8 153 220 172 40 201 71 192 251 112 209 233 235 18 255 15 82 62 39 2 26 78 192 101 49 25 172 55 118 64 109 70 212 120 223 248 24 94 27 219 213 93 182 155 230 84 43 224 41 0 31 102 21 23 123 17 252 33 23 247 132 220 28 230 14 155 233 47 45 86 246 11 124 131 80 99 159 89 71 207 251 148 215 47 210 217 154 60 180 91 135 250 99 88 115 227 208 105 5 33 49 213 236 79 165 151 134 179 134 26 16 217 195 205 66 229 185 203 70 244 228 190 152 11 199 48 37 213 248 60 154 85 54 143 241 185 194 134 204 137 238 26 251 152 90 183 37 158 10 135 87 149 245 65 35 70 35 55 7 143 101 77 78 213 183 252 60 22 201 145 52 145 153 78 239 133 242 130 11 145 87 255 239 53 230 244 27 8 91 13 26 226 185 139 28 133 224 164 143 150 11 21 8 202 116 136 76 245 168 103 97 60 147 77 134 216 19 42 152 141 64 86 124 216 48 178 74 70 63 52 66 154 152 156 85 9 21 163 69 168 181 49 135 48 231 133 72 58 120 18 165 11 247 188 9 100 55 67 132 239 127 70 219 37 68 207 107 82 232 193 99 96 112 105 171 125 108 32 236 192 135 160 27 124 232 160 51 188 250 135 114 65 159 8 242 136 1 251 232 176 54 141 59 87 149 232 245 68 214 179 141 138 18 215 255 121 254 123 251 69 16 81 99 46 222 201 38 137 146 58 178 15 112 12 133 20 229 237 184 197 172 220 131 0 165 165 165 165 1 0 0 68 0 0 180 207 51 128 182 174 202 65 0 0 43 246 0 0 59 143 0 0 0 0 0 20 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 113 117 101 97 107 73 110 66 114 111 119 115 101 114 46 114 115 114 99 0 1 62 107 114 115 114 99 82 83 69 68 1 0 4 0 0 129 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 0 0 1 255 0 0 1 140 0 0 0 0 15 0 66 193 213 15 229 191 253 198 175 177 189 18 34 107 98 168 73 19 2 254 167 237 104 233 24 99 195 182 120 233 103 215 50 61 227 104 183 96 45 151 154 255 135 43 239 227 32 62 31 86 24 157 103 20 248 100 127 150 140 240 49 199 72 82 125 155 224 31 238 35 24 180 90 120 184 187 141 164 53 50 237 118 117 17 212 147 70 168 83 219 190 144 88 100 254 9 225 48 129 169 244 40 52 95 17 148 215 81 199 12 135 215 28 126 152 6 1 207 207 249 186 208 168 221 51 239 139 49 18 207 25 253 249 92 20 247 203 154 204 198 254 253 88 78 39 19 147 55 27 199 55 155 227 106 182 30 201 2 164 102 117 45 118 124 65 142 162 141 91 87 174 234 2 228 70 129 20 35 94 154 191 34 130 12 176 102 10 5 186 154 32 23 235 255 134 203 57 224 128 100 168 90 62 49 3 226 17 127 232 153 35 119 43 136 108 118 253 229 168 181 111 9 154 77 83 72 211 18 25 121 150 57 23 59 118 81 94 96 184 27 87 208 199 188 96 232 171 193 97 214 193 110 2 15 38 131 58 139 155 88 242 234 237 27 45 239 235 135 31 237 132 193 52 7 22 40 194 93 6 131 60 141 99 131 166 162 225 120 10 175 47 169 19 10 182 63 202 189 149 39 89 211 19 9 101 98 231 20 223 200 114 179 35 20 239 87 149 0 153 233 167 247 113 247 111 161 219 14 241 106 70 129 114 208 38 145 194 236 225 233 137 29 117 13 136 118 141 61 113 129 32 72 6 116 28 26 52 27 122 112 83 161 121 163 140 134 91 88 94 229 239 184 131 165 35 0 119 117 59 49 172 168 234 203 40 15 77 132 220 115 217 216 67 240 93 176 165 165 165 165 1 0 0 62 0 16 182 179 83 229 182 179 83 229 0 0 57 141 0 0 0 0 0 0 0 0 0 14 72 205 0 12 209 180 0 0 49 159 0 0 0 0 15 0 83 113 117 101 97 107 80 114 111 53 46 120 109 108 0 0 99 190 84 69 88 84 67 87 73 69 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 66 193 212 227 255 127 127 12 60 103 118 108 165 221 169 237 116 200 1 124 16 229 32 96 32 163 69 255 112 3 193 121 185 58 62 226 6 174 29 169 109 184 180 113 234 154 249 45 113 252 62 214 111 165 117 213 183 210 53 125 163 61 30 29 197 158 16 207 8 94 220 119 42 180 207 30 134 153 180 41 155 97 187 245 178 17 87 25 90 169 43 173 172 242 223 39 160 217 60 217 83 81 212 17 124 100 228 120 101 3 10 213 218 133 100 100 125 24 226 48 138 52 85 56 153 8 147 122 163 59 83 109 145 48 6 142 117 226 219 88 241 204 5 171 75 9 198 2 136 121 63 187 115 96 88 156 217 1 242 173 112 70 112 214 101 254 211 22 224 81 45 20 255 187 132 36 132 133 78 3 3 189 15 138 207 249 57 74 170 168 111 135 58 75 134 99 146 205 24 139 115 208 88 209 172 238 126 111 243 27 119 179 42 74 88 228 140 233 181 239 42 29 123 158 111 95 158 133 184 147 208 181 93 254 213 225 222 199 170 0 111 201 85 86 67 153 76 198 22 226 108 102 134 111 196 88 58 2 43 17 225 206 191 69 104 28 201 21 219 48 70 2 246 161 71 12 70 57 172 160 240 124 188 93 238 65 228 251 37 84 86 24 176 35 107 39 118 16 129 239 45 180 186 87 246 215 94 74 237 108 2 66 74 37 60 12 168 186 28 133 139 43 56 225 47 210 157 231 238 153 160 206 70 71 109 159 51 117 158 189 196 105 12 20 239 215 53 220 114 200 94 7 10 129 46 6 30 169 115 64 116 5 119 1 107 180 123 84 70 103 12 110 231 140 15 248 217 50 68 144 177 126 151 86 165 53 240 128 17 34 120 208 74 247 153 176 71 128 166 213 187 181 174 64 96 96 71 45 175 45 234 228 16 228 33 106 153 208 251 75 79 238 237 118 66 175 198 140 56 60 48 38 101 43 145 181 221 241 51 212 123 236 30 102 168 149 96 200 28 164 57 105 254 240 9 207 125 177 99 69 0 110 132 143 23 149 95 56 52 44 166 36 113 164 13 175 208 100 67 126 42 86 1 11 187 86 146 106 221 3 124 148 202 214 123 112 254 170 153 161 157 251 120 46 79 191 126 30 169 60 220 174 148 64 157 31 188 184 27 166 113 147 147 140 65 2 50 73 40 5 202 126 30 92 250 118 140 204 58 220 208 118 178 220 73 38 102 58 237 192 213 94 218 186 48 66 125 213 19 213 53 12 253 113 243 183 94 242 6 253 238 113 124 108 215 132 85 1 6 125 91 189 26 150 91 26 146 243 77 238 18 39 220 39 0 10 209 62 31 193 196 16 198 112 45 232 223 130 23 241 187 111 118 93 76 100 30 164 60 45 202 213 109 79 77 214 240 192 137 141 252 46 15 121 147 153 205 47 16 209 14 200 154 95 106 164 59 109 61 169 213 83 199 99 241 75 32 120 166 191 118 132 41 30 237 16 29 17 47 36 37 252 202 250 137 110 46 158 102 202 10 137 71 66 178 216 227 39 199 141 196 239 49 51 107 132 60 212 52 202 59 77 218 184 156 99 128 203 213 209 154 184 111 55 168 155 28 251 25 119 130 20 163 22 153 201 234 113 11 210 86 51 80 206 214 195 124 246 42 43 226 109 35 111 156 103 109 110 114 227 15 0 52 169 20 63 28 39 101 102 96 26 81 144 64 111 154 58 221 93 32 79 206 13 189 248 73 41 182 21 237 246 9 105 84 166 250 254 107 57 65 51 104 172 182 36 26 178 25 51 105 16 21 118 181 43 184 114 254 245 250 47 196 116 237 175 192 245 244 122 0 216 169 168 219 157 224 255 36 151 221 189 212 195 142 139 147 66 177 4 171 68 79 207 12 143 30 109 42 44 158 127 90 69 171 104 57 217 148 219 22 222 58 252 64 74 74 54 98 30 172 175 137 13 54 147 195 167 8 180 53 97 235 83 209 224 194 106 7 71 144 34 196 123 253 236 181 168 157 81 65 132 46 134 252 25 32 102 237 141 52 1 46 186 148 70 67 207 245 38 75 248 83 95 29 188 166 33 246 255 70 162 254 228 107 60 174 130 73 202 110 114 148 209 226 105 73 10 207 187 43 109 106 240 46 105 183 81 160 140 39 67 227 191 134 144 76 11 13 68 76 22 250 234 46 47 40 255 127 96 15 80 6 27 45 208 244 148 56 118 156 232 153 129 41 191 149 110 93 112 209 203 49 217 145 183 179 80 186 98 248 196 114 60 140 167 209 216 119 199 205 158 194 43 171 72 179 25 245 11 46 160 65 20 203 143 42 16 144 202 67 200 94 140 207 17 60 116 200 70 46 138 146 134 86 119 132 87 97 87 173 16 156 167 69 243 97 215 101 8 245 113 195 13 195 83 176 27 141 164 17 121 85 159 126 235 184 33 151 245 110 99 154 144 48 19 157 72 245 70 98 98 226 137 47 105 129 199 14 64 83 96 183 40 175 169 102 66 89 246 137 65 193 61 251 223 198 206 221 24 183 245 27 130 63 73 153 80 181 230 66 200 32 43 102 119 101 104 238 155 71 165 33 39 84 27 26 68 149 18 30 228 208 88 191 96 245 11 174 155 124 142 222 181 188 63 229 196 119 196 194 108 219 205 224 90 184 111 26 28 252 185 51 244 74 147 155 109 15 122 36 32 211 228 17 226 21 228 141 197 172 15 54 104 118 74 124 194 157 137 219 157 244 129 69 167 209 206 96 72 160 209 232 42 75 20 238 87 169 148 217 122 193 133 149 199 71 73 159 92 143 16 100 23 192 129 154 190 98 41 49 25 72 101 202 234 49 22 132 189 172 134 7 164 157 249 63 140 28 38 223 110 172 165 174 26 169 160 65 2 102 143 243 222 241 72 63 146 225 235 200 21 122 185 116 101 18 140 228 164 59 44 170 127 211 95 73 231 134 83 222 67 62 132 191 104 250 162 253 16 212 56 150 142 117 34 243 36 192 126 121 174 106 81 240 49 50 53 128 135 250 136 253 126 159 0 214 79 181 186 38 180 68 241 66 76 209 85 143 204 218 183 169 172 183 33 216 21 93 57 154 244 121 215 80 194 107 9 247 89 212 189 25 98 195 31 15 48 182 179 43 186 228 179 148 186 214 184 69 4 120 184 254 133 67 152 201 122 161 188 172 42 201 228 137 141 209 30 75 240 231 186 220 89 21 241 117 130 137 254 61 170 105 150 70 212 57 65 111 222 211 159 208 137 96 17 173 4 99 172 124 37 236 115 199 3 78 38 21 54 118 203 59 37 249 78 138 205 229 168 173 178 27 206 219 68 159 127 39 236 69 174 216 75 35 196 147 41 253 46 149 193 123 163 35 154 153 196 130 115 234 215 194 180 147 129 214 208 196 133 24 120 74 43 145 43 126 65 249 131 179 198 12 14 5 88 184 212 65 0 31 21 134 147 196 206 253 40 227 210 251 83 250 246 158 144 93 84 159 117 228 99 232 78 22 213 33 32 46 55 171 135 6 52 173 81 1 185 107 162 159 48 199 144 206 62 156 87 112 47 22 231 173 115 141 153 5 79 184 130 249 81 22 136 228 194 145 32 155 94 213 147 129 35 194 24 193 68 231 171 162 117 189 11 102 185 79 207 52 112 102 138 9 98 219 93 61 7 185 222 65 117 122 151 128 47 224 209 207 156 38 1 174 54 51 66 158 89 152 6 120 98 212 101 140 246 206 128 154 195 113 29 241 4 192 64 20 191 147 66 218 12 138 95 250 78 231 198 162 194 94 236 69 196 129 9 150 160 38 105 232 159 42 41 237 86 61 62 213 186 228 184 146 52 177 121 165 1 3 78 17 213 156 34 120 188 60 231 126 13 255 243 43 28 242 138 200 76 199 11 80 40 82 213 172 14 181 228 32 144 50 3 146 107 164 60 36 139 29 79 51 150 188 24 23 51 140 216 80 144 145 57 90 30 182 143 61 174 62 160 24 169 234 133 193 232 115 2 200 236 192 114 50 73 150 113 245 166 35 136 117 150 97 219 188 16 226 91 213 227 36 40 191 145 242 241 127 34 176 81 227 13 149 96 255 82 75 27 9 156 112 33 35 155 53 185 85 236 254 24 151 143 122 86 21 252 100 32 11 63 194 202 209 61 108 81 82 74 59 48 237 72 48 176 214 26 201 108 79 142 167 234 94 31 101 205 133 116 156 216 221 181 90 141 157 141 37 186 122 219 148 32 212 107 54 100 243 246 7 6 29 66 122 146 85 96 31 19 168 49 142 123 182 79 170 11 222 56 207 45 10 171 89 137 36 33 151 78 20 100 158 6 102 130 6 65 104 72 13 139 114 8 71 149 224 123 142 119 168 248 99 63 82 228 153 204 216 52 0 41 216 164 9 109 78 109 62 89 47 163 184 96 131 68 209 196 255 36 96 158 141 123 107 11 231 77 110 48 9 123 134 32 137 221 124 43 217 17 200 102 240 40 204 247 223 161 214 100 234 242 140 19 23 19 22 124 106 129 109 137 145 80 163 178 137 75 127 201 118 192 55 41 70 54 170 177 25 58 107 131 227 128 238 73 34 127 212 221 23 20 35 148 112 153 156 195 126 209 148 43 111 154 155 224 104 155 66 127 135 8 117 159 141 76 16 40 11 171 60 164 202 116 6 22 164 54 169 199 138 196 122 92 15 131 41 99 233 119 170 243 55 122 18 29 47 94 11 48 108 209 77 178 179 190 145 238 81 46 243 121 15 243 179 76 119 180 48 54 230 25 203 50 1 120 16 104 205 134 215 9 161 243 72 223 165 120 162 254 159 83 20 72 117 39 208 221 173 253 30 169 133 75 182 10 199 5 208 205 121 60 220 184 17 135 194 137 242 159 134 112 182 70 35 238 63 184 99 85 48 72 57 252 25 74 163 216 239 37 237 179 86 223 64 213 167 231 118 197 64 139 205 145 208 212 50 82 215 145 245 90 115 153 212 145 81 207 34 192 73 209 231 119 135 38 191 12 82 115 77 175 255 29 7 142 209 4 22 13 152 151 203 193 141 209 64 230 186 202 118 167 42 240 46 15 135 30 83 200 74 88 145 216 147 220 115 4 158 168 194 198 12 61 147 27 58 79 197 110 79 143 26 38 46 65 193 157 142 90 47 24 65 99 5 82 220 133 81 219 252 68 116 176 91 175 151 179 168 176 240 78 88 252 135 125 82 83 201 43 157 82 224 146 116 236 94 189 156 164 157 214 77 40 97 99 175 181 36 91 88 57 250 55 190 213 71 148 249 96 74 111 231 99 152 198 121 83 73 131 158 39 49 83 100 221 170 208 197 80 63 160 111 131 182 3 251 24 119 53 99 224 133 62 94 245 14 252 163 59 174 63 192 29 45 88 144 253 103 174 223 245 4 116 213 100 224 219 219 57 197 109 58 12 36 132 122 214 155 120 138 84 24 171 98 18 28 176 156 191 92 146 215 115 229 150 219 145 64 115 208 255 206 193 255 19 111 23 106 169 246 187 59 209 87 101 229 142 167 172 159 198 130 118 25 156 167 96 2 25 144 169 145 121 21 38 209 117 94 207 1 143 91 144 190 62 136 45 255 126 10 153 95 42 149 24 78 121 125 155 156 72 70 252 194 169 87 21 189 14 63 220 3 238 248 103 94 80 203 245 41 117 151 73 46 124 206 25 142 128 184 124 212 107 150 233 147 82 31 102 98 165 75 163 8 187 80 212 59 95 173 162 240 169 203 225 246 82 8 214 248 206 225 141 97 204 96 231 74 127 114 19 250 115 237 199 86 80 85 246 148 142 98 73 90 114 66 236 74 159 204 77 174 62 167 70 45 82 12 70 142 79 130 206 184 79 123 153 83 113 58 147 100 253 122 246 199 55 19 186 59 231 15 6 163 100 6 92 205 71 17 68 16 253 252 192 79 116 122 53 181 7 112 237 6 160 96 157 54 51 173 189 1 142 64 196 96 127 31 109 123 97 248 217 197 158 142 69 63 137 13 57 189 117 58 26 33 53 16 12 146 173 242 235 87 129 176 221 36 171 56 221 237 112 253 150 161 7 118 140 255 240 56 118 9 167 151 129 62 42 236 104 200 123 4 71 34 112 9 66 181 236 244 229 8 34 86 180 240 194 224 239 121 175 176 20 237 203 179 161 188 254 219 52 83 134 136 160 234 157 135 33 6 68 31 0 144 10 128 150 9 0 109 39 229 167 195 27 153 177 227 107 36 11 216 208 216 152 65 133 249 151 179 98 175 10 19 163 115 194 56 208 217 102 110 140 255 240 208 167 44 42 6 19 219 215 205 135 157 12 227 161 118 128 39 191 249 137 213 204 98 96 46 24 24 14 213 253 91 127 139 71 127 216 104 148 112 120 235 247 46 236 104 228 120 120 130 102 143 99 144 163 180 130 112 51 51 219 158 7 170 106 37 162 20 82 197 66 124 161 153 56 140 20 115 182 26 16 81 20 116 34 99 197 235 77 222 106 192 22 170 150 0 35 21 90 71 82 129 190 192 239 211 70 129 223 3 25 114 102 98 129 190 251 221 156 80 21 127 185 167 67 129 64 102 104 137 188 115 38 236 179 128 84 54 220 59 118 114 252 201 99 190 10 190 5 62 250 235 0 91 78 25 179 190 198 241 37 125 248 61 153 35 164 159 36 206 178 41 28 107 77 223 64 74 147 92 174 196 50 104 55 22 225 179 142 77 198 202 44 78 238 236 240 224 12 88 17 106 242 251 67 85 116 96 109 214 54 105 68 77 255 170 203 30 184 232 46 102 69 241 133 80 113 191 163 242 212 147 43 161 6 168 162 185 227 43 84 185 12 115 198 156 205 58 239 97 103 208 250 36 202 52 41 250 117 11 116 193 81 114 138 138 107 86 31 215 118 203 19 171 131 147 41 13 27 114 177 66 169 57 126 11 253 30 44 231 62 217 140 87 39 12 224 117 214 104 177 178 54 190 158 190 99 132 186 175 210 93 131 151 70 4 48 44 146 139 53 154 74 1 112 49 199 227 126 253 172 9 239 210 138 163 98 250 86 38 174 239 0 205 188 145 46 98 216 168 98 211 163 92 153 132 142 54 93 224 140 20 242 67 94 57 145 124 23 143 112 187 97 46 139 61 156 66 95 152 28 80 201 64 219 140 154 243 86 209 181 203 43 249 165 240 112 47 223 6 180 115 69 204 26 109 228 186 221 28 24 141 200 79 221 108 225 180 130 244 86 240 41 69 182 166 163 159 46 200 98 36 178 219 238 217 169 38 89 68 152 44 113 195 160 149 90 59 77 227 215 113 132 65 185 201 229 105 3 89 89 175 195 238 134 109 40 115 231 94 93 4 163 15 140 143 141 89 234 101 32 167 177 218 31 61 57 232 81 82 170 55 105 40 115 109 64 21 223 150 160 16 117 243 52 19 12 23 83 111 195 102 92 38 211 113 188 88 67 53 55 157 209 114 144 231 213 190 237 26 32 120 198 49 150 178 189 86 106 13 134 203 90 93 33 150 221 204 250 203 25 5 128 169 58 214 227 32 70 74 168 200 7 28 90 249 134 47 193 87 250 206 41 171 80 107 129 146 208 61 215 57 250 10 18 81 48 220 113 228 52 38 248 14 156 172 175 206 172 159 63 184 58 221 13 174 225 145 152 138 137 23 124 207 187 62 71 241 66 48 31 2 134 108 126 153 152 150 181 211 89 99 32 182 242 51 129 4 219 96 112 194 89 108 239 25 148 91 51 245 27 93 62 104 201 51 5 183 50 213 238 247 29 69 30 176 175 160 72 100 123 225 29 137 90 209 245 46 192 87 141 240 52 178 164 177 176 121 4 239 135 224 18 94 20 29 40 70 111 69 33 30 52 180 117 45 182 117 149 188 92 71 155 67 95 39 14 200 124 223 171 185 189 12 118 250 161 88 89 175 0 140 196 82 76 23 115 57 221 235 128 153 112 244 209 4 35 72 72 98 56 100 68 147 175 55 178 144 168 16 117 127 155 123 6 113 77 172 44 71 55 99 150 92 214 33 120 232 246 212 83 190 93 111 81 118 118 119 231 147 16 236 150 125 166 70 161 78 241 63 61 53 57 89 253 91 133 154 194 48 11 52 110 144 181 127 11 192 253 196 242 160 100 99 82 17 191 121 160 252 70 78 87 232 109 30 84 95 236 177 41 76 125 233 240 124 24 11 152 15 69 248 102 159 45 23 109 52 233 211 61 141 189 241 227 112 198 133 155 138 93 25 79 49 64 228 16 19 106 211 22 10 219 84 166 253 128 109 99 20 7 67 231 133 50 27 166 123 218 178 244 185 41 127 31 160 208 190 96 127 75 178 14 235 241 191 148 230 191 118 181 205 65 199 184 174 204 17 67 58 170 104 232 30 54 23 184 181 94 106 7 139 26 163 86 243 168 223 124 220 125 23 234 44 143 190 62 111 49 231 173 151 153 203 172 27 22 120 136 165 140 141 34 122 212 227 5 167 219 132 38 39 128 25 218 205 48 32 24 230 157 249 102 203 139 185 54 234 193 224 3 31 109 204 182 249 161 181 190 246 168 103 34 74 253 60 95 60 44 75 249 4 11 191 90 207 210 84 128 30 117 246 144 74 121 63 172 80 58 254 242 19 6 201 252 104 182 111 14 19 119 163 233 23 71 115 133 226 94 221 180 177 198 254 76 61 55 109 119 18 115 156 217 1 135 164 229 186 16 131 53 174 21 83 123 8 183 104 140 89 88 23 234 127 56 45 49 97 109 7 54 97 248 139 156 135 56 176 8 15 235 185 3 109 60 88 190 18 71 110 241 216 247 123 216 170 150 8 94 128 32 143 240 193 146 199 204 9 109 68 17 129 83 9 221 7 126 236 57 200 205 204 231 28 84 48 219 161 200 189 129 164 169 5 113 118 239 200 25 76 198 168 171 59 161 178 140 104 205 230 236 237 254 241 20 22 146 106 21 97 67 146 139 221 114 232 231 179 6 168 110 2 125 57 72 7 223 47 147 181 179 188 63 225 63 89 213 24 115 108 181 160 76 74 226 57 154 175 118 164 169 131 225 228 176 70 200 212 248 150 176 251 39 70 250 144 93 51 185 132 214 191 181 189 202 129 139 29 13 200 140 120 177 18 68 246 153 75 102 144 29 159 208 19 30 83 127 107 74 164 231 98 5 57 71 154 75 82 195 248 191 222 144 244 21 144 154 128 220 204 137 207 176 243 191 198 74 48 75 205 166 205 111 149 223 107 82 181 25 30 135 118 204 56 40 86 54 234 196 65 253 158 181 170 44 161 200 235 253 94 136 159 144 70 190 101 171 14 107 81 175 45 74 27 248 130 1 218 237 139 128 187 96 213 128 109 0 38 25 85 103 142 192 198 26 47 248 111 240 246 245 239 12 60 53 79 156 30 225 18 241 168 96 100 84 208 207 52 59 55 47 34 147 205 87 31 96 109 83 147 185 219 252 248 250 32 192 54 146 172 81 93 80 195 191 211 112 94 226 137 253 17 254 235 63 171 170 170 26 232 68 76 180 35 212 202 191 109 35 205 173 71 223 37 247 235 33 102 68 236 143 99 182 173 164 252 123 4 56 217 162 2 121 252 175 27 144 211 178 29 210 68 120 230 72 132 253 34 227 248 116 118 62 175 168 220 198 175 103 191 210 147 208 11 148 10 241 20 22 230 60 104 137 55 216 69 205 236 81 126 30 6 226 110 199 102 20 74 18 60 169 181 121 210 98 179 112 174 134 54 4 206 191 240 231 73 180 175 42 224 159 99 34 101 99 67 59 190 190 49 69 101 40 3 243 46 48 190 0 58 193 51 26 162 31 193 122 31 233 96 17 190 63 230 38 208 150 250 116 237 200 145 246 232 66 187 254 255 70 252 30 119 70 51 77 210 55 202 246 176 186 180 176 242 183 155 122 116 95 115 153 107 90 246 56 125 128 234 127 159 183 50 18 121 66 111 31 133 130 210 110 250 128 254 43 4 211 55 42 154 94 201 63 175 45 146 142 51 190 177 31 112 213 124 156 140 212 68 87 130 239 200 170 150 12 121 41 18 157 27 246 24 174 19 127 122 23 3 115 83 123 208 214 70 74 74 25 53 184 120 40 3 107 88 244 251 212 167 174 94 217 50 226 81 49 72 31 106 105 41 160 24 38 6 73 155 11 37 217 67 126 46 245 89 85 12 144 69 50 37 206 110 159 229 132 218 27 57 170 124 167 55 221 15 104 4 212 20 86 85 4 81 90 191 19 73 187 93 244 232 90 72 49 137 59 188 208 179 183 207 44 172 227 27 243 194 141 141 166 6 201 207 62 245 215 228 228 188 111 67 35 65 32 67 62 77 38 22 79 25 73 99 36 83 254 89 129 201 203 31 6 235 28 224 80 127 71 131 47 120 70 15 1 178 22 69 243 67 33 27 85 189 13 80 11 159 223 20 134 9 100 218 171 46 41 12 231 27 211 245 129 167 109 62 7 15 229 215 54 241 63 201 193 58 66 230 66 33 150 156 30 214 255 36 33 128 247 125 226 251 162 28 4 251 28 167 34 55 123 245 120 43 167 163 168 211 157 163 241 207 179 246 105 5 65 74 109 38 14 28 206 232 136 71 105 133 2 191 222 67 140 227 161 155 119 210 92 115 252 188 184 248 209 35 54 158 189 197 189 2 241 140 144 167 99 234 139 178 109 89 202 84 80 68 61 96 36 251 51 182 43 16 110 218 102 36 249 230 236 17 186 24 50 234 239 116 233 109 15 90 120 69 70 253 63 160 90 210 74 57 37 245 101 33 85 8 66 244 22 10 223 210 159 193 70 92 235 127 48 254 127 62 64 192 29 149 178 138 89 14 89 57 103 238 130 38 32 252 161 158 6 58 189 88 248 255 89 157 45 208 211 88 168 255 68 74 106 77 113 137 233 136 29 139 102 94 54 73 27 225 227 109 58 192 220 73 85 178 199 149 12 120 78 147 70 140 143 72 88 120 240 47 106 229 4 104 180 96 187 192 1 29 39 35 5 10 15 157 150 242 230 124 229 74 121 240 235 108 6 137 126 152 131 22 119 59 218 8 234 167 96 81 218 191 151 133 142 80 37 123 231 225 49 199 67 37 127 228 212 174 237 40 65 81 238 61 246 204 176 225 153 162 127 67 12 97 121 133 200 6 247 102 25 90 197 203 72 202 41 107 236 52 160 57 147 238 62 62 22 117 216 181 190 174 72 124 21 245 179 42 91 111 238 217 126 207 22 123 144 206 85 228 238 238 158 8 114 42 18 152 136 150 107 158 203 141 200 185 212 128 230 178 189 2 135 234 56 101 250 181 131 42 76 31 144 107 190 125 6 87 177 244 20 154 182 107 230 143 136 19 135 167 150 40 1 77 237 149 230 219 229 60 211 63 4 88 173 204 244 9 30 227 180 232 235 111 109 59 45 216 0 115 251 64 34 252 252 63 149 83 228 226 13 122 24 67 85 162 81 51 204 164 212 181 211 214 250 114 193 160 5 210 87 134 6 165 246 235 30 27 193 234 36 68 43 217 221 148 16 1 192 157 225 177 178 7 225 162 72 139 134 104 94 161 38 222 233 18 186 201 62 0 111 176 104 185 153 251 242 57 9 102 175 64 173 33 201 230 109 229 38 176 142 151 133 139 97 150 173 225 63 110 148 250 200 25 31 160 89 130 200 97 140 63 196 227 244 222 154 53 117 253 187 55 222 255 139 131 166 121 148 243 65 224 75 120 219 26 105 20 182 198 138 151 89 132 234 89 33 154 25 38 42 161 154 97 44 79 46 132 48 101 176 153 233 16 35 78 92 70 247 134 60 133 190 148 16 121 86 175 86 115 240 139 40 98 44 49 7 153 167 113 168 175 24 23 124 5 138 186 13 206 33 54 191 234 204 54 190 141 233 249 66 148 193 76 136 132 104 145 222 211 66 179 55 155 15 44 195 163 242 60 16 2 67 224 67 82 48 125 91 125 203 238 255 53 130 248 214 29 8 235 51 12 213 253 229 19 102 74 119 109 19 31 115 59 56 47 83 196 221 146 5 154 205 31 209 107 71 36 21 253 93 226 205 37 206 119 239 124 107 213 134 192 102 169 225 151 87 16 251 220 44 215 241 203 138 64 21 97 122 237 160 68 81 211 168 81 174 150 148 163 143 181 249 252 124 225 77 200 16 59 168 209 114 107 170 183 87 86 121 29 12 8 11 51 65 89 22 8 153 68 75 59 79 217 250 111 38 126 100 61 51 189 172 168 121 172 209 171 82 208 25 27 83 46 143 215 43 48 152 119 133 27 144 190 4 176 37 11 5 8 126 0 82 227 33 78 45 162 29 23 184 229 56 52 59 39 84 251 5 92 139 40 99 17 149 8 85 140 66 159 219 220 232 29 250 90 117 118 187 32 221 176 243 68 7 13 6 222 9 37 173 29 31 80 172 122 24 247 28 86 196 238 244 86 55 157 202 29 246 213 115 245 190 26 227 239 107 39 27 197 39 46 67 112 213 121 104 252 6 37 76 65 109 244 64 106 200 119 22 13 15 233 252 64 209 43 103 26 124 156 58 161 184 12 209 87 250 253 121 81 208 72 79 108 122 254 218 64 69 206 127 10 115 125 141 162 114 90 65 223 59 9 168 185 33 49 245 78 233 124 15 29 142 236 194 228 35 253 108 84 19 129 114 193 104 110 84 71 242 157 231 242 140 212 85 189 149 208 37 29 175 201 139 220 150 149 7 102 167 173 184 98 106 202 229 228 104 51 40 245 156 129 21 94 140 37 242 122 160 34 147 31 152 198 145 241 69 145 113 138 227 199 182 199 35 4 31 186 52 222 170 15 204 151 88 80 228 33 42 196 39 50 79 148 145 15 35 145 84 22 194 60 31 34 4 40 251 155 64 32 65 175 164 155 24 186 232 164 95 96 106 170 64 79 42 102 17 86 166 27 44 185 248 52 174 3 225 89 7 154 157 238 170 170 79 134 189 12 115 24 199 117 70 132 79 5 183 70 146 178 99 145 164 202 231 108 164 206 138 144 64 182 210 148 51 172 29 170 134 138 114 27 28 53 244 173 13 105 6 230 8 236 56 178 103 103 203 131 243 249 11 189 26 94 125 138 226 223 94 218 72 42 147 186 82 146 159 90 18 238 115 80 239 239 113 214 253 2 124 151 129 0 170 145 60 180 78 113 213 124 63 24 94 215 210 45 3 27 231 120 200 120 67 218 235 111 119 250 28 24 205 84 8 191 23 178 43 137 72 178 96 237 23 30 108 82 163 48 57 55 137 58 120 168 48 114 91 54 63 95 189 16 128 123 72 114 95 72 243 111 26 29 214 220 133 165 38 214 82 117 129 62 119 161 102 128 184 183 214 1 40 93 96 60 128 221 90 53 16 200 137 189 248 27 26 251 16 121 1 135 18 200 94 167 162 226 30 87 207 53 189 157 133 141 156 43 247 123 1 252 201 5 70 46 191 66 222 54 27 241 183 124 140 198 86 198 232 216 5 127 7 164 199 217 112 168 206 159 81 147 149 181 97 128 204 32 146 190 80 58 78 158 150 17 244 30 64 136 56 255 197 138 234 169 18 202 200 190 220 38 165 17 124 202 230 186 98 65 54 33 15 44 59 187 90 205 113 128 22 70 161 224 191 252 202 46 246 183 48 247 177 154 62 107 53 114 168 88 206 19 74 187 137 102 73 247 47 178 195 93 33 89 71 52 120 9 92 178 213 225 116 107 96 135 0 42 223 42 38 68 213 126 34 249 152 156 161 182 101 65 149 111 101 171 151 136 153 184 210 163 150 225 229 163 142 218 105 114 230 76 241 173 14 145 227 238 96 83 127 255 59 82 25 46 70 223 223 6 90 48 6 120 157 217 20 70 92 127 29 8 146 182 237 184 125 200 191 187 196 7 238 189 116 142 194 176 87 152 25 211 11 238 79 0 20 191 225 80 144 72 12 188 184 46 15 75 25 106 155 245 177 178 233 27 202 174 1 246 114 66 188 42 191 64 194 90 38 82 115 36 136 50 227 87 223 251 176 184 140 171 15 152 253 227 121 109 226 105 26 28 40 230 33 115 226 71 160 39 59 122 105 203 106 250 54 130 118 112 35 233 84 77 206 239 75 164 176 93 25 144 33 85 241 151 251 77 27 160 162 239 3 18 49 31 151 75 134 240 66 151 96 189 29 43 164 210 164 175 20 251 137 218 193 33 204 108 39 41 69 36 215 74 251 45 235 106 13 139 46 223 5 40 223 112 59 13 194 40 158 12 71 216 42 70 206 70 120 227 15 201 216 199 243 214 123 215 140 117 90 207 139 32 151 213 233 53 96 224 152 244 11 135 36 24 93 110 22 189 244 170 218 140 212 135 9 251 210 149 177 56 140 157 252 94 54 210 219 252 178 202 178 182 89 221 122 31 207 134 188 177 186 225 219 119 41 38 8 227 151 28 91 27 50 47 193 221 218 74 23 151 34 97 9 82 179 180 173 179 196 226 172 246 162 77 151 173 140 25 15 110 105 248 13 66 192 226 184 227 251 208 58 66 176 136 47 148 131 227 31 247 85 143 124 254 213 175 91 223 157 114 13 49 223 187 241 7 42 193 110 110 64 200 40 81 21 189 172 69 117 43 42 237 25 102 158 206 89 2 200 80 12 168 191 38 102 163 177 180 74 140 67 98 191 250 244 183 71 105 216 140 160 11 138 9 74 24 196 180 187 125 133 15 255 133 222 32 179 143 113 151 243 55 16 218 185 156 15 38 33 206 68 192 222 149 45 179 255 97 68 189 70 79 120 159 33 247 208 214 248 36 212 202 7 161 251 95 78 211 135 79 187 130 0 239 114 162 142 242 106 209 42 169 249 9 209 183 186 180 82 157 7 79 203 254 243 32 255 23 31 96 121 214 173 133 42 209 213 196 109 224 180 178 165 53 28 177 122 205 8 52 213 135 149 3 43 214 160 170 67 97 188 13 230 249 78 151 140 183 240 204 103 129 61 127 97 66 193 92 161 185 149 124 189 65 71 101 117 187 255 111 181 204 243 91 8 77 247 110 57 203 1 202 10 68 41 60 227 255 104 227 175 91 190 107 188 34 233 188 55 225 80 55 77 229 176 200 235 91 185 27 115 229 122 8 131 28 224 85 184 55 32 178 105 208 246 190 165 205 138 0 108 92 45 78 101 229 247 109 183 160 37 254 180 236 54 228 32 19 40 41 219 146 117 15 58 11 2 113 153 0 97 154 173 92 130 75 152 100 185 49 88 180 224 88 117 90 5 72 162 49 31 77 215 122 57 194 207 229 192 29 138 61 123 226 97 184 84 177 243 157 42 66 252 53 36 33 201 106 177 235 123 197 54 224 31 44 74 250 78 36 218 122 45 80 221 215 208 78 184 43 238 202 14 202 195 213 183 118 59 52 115 116 109 9 14 254 227 168 35 105 23 12 82 163 37 212 98 82 72 18 85 234 55 80 150 3 112 79 94 176 41 76 208 235 239 104 244 148 180 190 206 185 14 198 164 245 170 119 43 105 128 242 91 223 35 180 47 16 224 40 121 111 214 79 244 178 38 196 99 189 238 23 46 197 209 43 156 233 137 103 140 159 88 193 113 123 37 162 153 254 2 73 101 113 64 68 37 109 176 125 117 80 230 233 167 191 250 125 96 137 25 1 201 222 167 7 206 1 130 119 239 108 154 216 88 41 3 111 173 156 15 51 2 128 192 161 96 131 95 230 222 248 110 82 127 154 225 19 193 105 208 67 205 75 178 119 106 198 219 183 174 75 55 2 235 211 92 178 142 228 100 161 17 182 164 190 193 179 30 143 255 241 80 117 142 214 196 38 70 242 196 65 220 47 237 165 202 138 152 91 116 93 79 209 129 180 104 219 29 36 184 226 44 73 99 63 144 215 154 157 40 8 136 236 132 209 150 254 3 7 119 228 13 161 171 105 187 101 250 162 75 185 195 189 5 142 254 6 215 145 165 25 28 140 184 10 45 132 27 101 134 217 202 176 170 152 107 122 84 133 143 116 84 152 101 17 229 161 229 230 150 12 40 181 209 8 86 93 3 128 151 224 152 116 73 92 163 126 158 163 107 234 85 142 251 181 118 94 164 51 168 215 204 10 114 180 149 225 198 75 34 187 178 8 128 58 34 19 56 185 97 213 1 197 193 206 254 168 165 242 245 53 183 238 126 90 208 245 61 9 131 219 160 212 3 1 42 125 52 5 194 248 44 91 238 122 172 172 132 131 145 31 182 23 158 47 219 243 141 171 44 223 211 220 103 196 114 136 63 126 234 115 26 184 149 92 92 87 222 215 28 214 224 205 79 161 178 228 252 61 167 1 144 125 190 37 164 249 233 64 122 191 51 30 220 194 31 27 66 228 241 137 166 142 220 102 93 131 205 57 212 90 3 122 70 164 125 147 237 126 54 30 111 23 248 183 49 234 41 39 171 182 5 207 30 123 57 212 241 0 102 123 58 90 143 150 206 96 83 97 143 189 221 122 244 116 123 192 19 202 64 61 144 152 134 94 32 52 120 97 83 173 216 238 50 220 102 38 128 207 248 12 255 10 230 181 12 234 250 170 181 239 62 143 146 53 177 237 75 36 22 121 187 209 247 49 179 101 61 18 169 122 255 124 144 184 206 44 19 124 73 239 14 130 103 209 81 86 243 225 6 174 31 116 165 42 79 198 91 67 0 198 134 55 181 118 85 145 249 12 227 178 228 173 243 148 102 205 39 179 201 27 197 224 52 13 136 28 59 143 157 86 93 188 237 172 112 72 239 73 209 31 132 6 111 161 52 22 116 2 167 85 254 251 236 38 186 248 161 188 222 213 218 178 99 176 52 232 205 249 36 56 220 36 2 126 86 147 166 236 68 236 88 167 42 219 152 195 133 40 83 155 246 173 245 78 20 220 38 177 85 234 178 110 238 47 233 0 2 100 205 39 187 143 126 143 131 213 181 150 8 114 81 91 30 192 56 158 242 168 19 50 185 197 196 117 0 37 142 18 22 232 182 55 238 62 249 30 156 222 77 246 179 146 121 71 175 77 253 205 111 101 171 133 24 151 180 84 198 73 107 151 238 102 182 12 82 235 99 171 7 128 121 190 182 109 134 100 230 193 94 111 3 203 105 15 87 159 218 192 99 80 235 127 250 191 50 40 189 190 108 35 25 51 20 229 65 53 245 50 59 211 26 33 110 213 171 147 51 247 226 245 161 226 125 243 244 229 206 201 85 92 54 44 62 249 7 53 178 172 72 232 133 229 165 228 147 4 44 128 142 202 7 105 63 199 176 129 217 86 198 159 102 78 209 140 98 120 91 79 112 219 163 139 65 215 83 55 16 168 30 116 68 24 22 193 213 91 163 230 18 140 230 26 71 196 35 220 8 187 209 38 82 245 59 221 176 130 210 178 8 28 83 119 218 82 146 85 133 58 244 26 57 90 78 46 218 80 54 244 93 92 215 49 92 116 209 216 104 146 206 81 195 30 55 172 251 104 0 0 132 134 221 47 81 163 131 174 20 106 87 179 129 70 49 211 95 19 143 82 6 251 169 25 110 42 144 213 144 238 206 140 178 22 135 172 45 11 218 82 38 177 12 16 53 14 253 113 226 74 220 126 19 66 248 164 75 24 82 201 20 148 154 187 9 241 181 163 101 76 136 225 55 104 42 110 142 80 151 6 232 237 242 252 76 14 190 70 160 156 247 253 127 241 23 48 90 101 216 244 75 138 49 2 65 119 39 220 234 187 52 124 29 255 85 216 205 252 53 230 100 35 90 162 116 27 145 61 158 16 91 241 209 24 169 187 188 169 188 30 123 111 39 122 1 206 241 200 171 175 156 248 184 135 102 29 32 221 135 25 157 218 203 72 154 242 140 202 130 0 145 228 151 148 1 205 192 241 240 157 97 54 26 72 197 252 194 73 52 165 48 109 22 3 212 65 63 249 6 23 49 201 190 109 80 66 19 55 252 227 160 48 57 228 153 100 153 64 146 110 130 74 190 112 103 64 180 33 212 95 217 112 69 21 24 208 230 178 76 5 136 219 181 50 126 172 150 65 228 107 120 177 27 137 38 227 152 110 58 152 31 221 177 136 141 29 255 159 67 127 143 43 169 92 103 52 163 26 32 148 87 127 240 241 44 123 160 250 192 93 8 145 87 92 23 164 101 15 138 232 223 241 10 42 28 103 23 204 251 156 79 44 101 240 177 59 41 146 40 213 62 165 40 6 37 73 225 90 174 121 93 234 44 168 40 239 176 29 103 208 141 89 127 130 58 254 72 147 9 160 13 101 70 1 88 173 106 5 46 168 151 76 234 18 51 184 121 1 118 247 185 185 245 120 227 115 38 134 194 117 247 80 124 233 159 228 169 37 221 202 136 171 55 167 63 22 84 165 245 231 74 237 40 243 181 11 178 97 29 125 249 95 252 150 224 136 234 92 48 199 209 245 49 199 13 78 43 132 99 106 187 143 131 161 136 151 236 40 176 136 219 58 114 7 57 52 131 18 76 140 91 176 203 76 16 146 137 55 184 5 220 235 128 211 194 174 57 106 22 150 82 37 184 195 19 161 94 109 96 217 239 127 209 204 23 217 118 210 58 170 82 252 68 51 110 12 243 14 211 140 77 55 151 78 111 248 207 59 42 174 175 234 48 3 38 102 49 21 51 45 248 67 118 211 205 144 91 52 206 129 63 194 55 195 167 109 122 6 41 222 247 134 47 215 36 40 212 235 64 167 95 27 113 27 27 162 60 1 227 253 16 45 154 15 191 155 81 131 218 245 46 215 128 38 180 9 218 79 158 175 180 169 67 179 120 69 18 70 206 98 120 160 213 5 131 198 155 73 94 5 128 92 140 137 243 23 32 178 29 208 103 23 13 175 217 225 94 197 53 36 101 33 179 8 101 144 152 173 71 42 99 25 227 53 106 174 215 136 56 4 21 4 152 236 249 255 61 250 6 37 58 116 246 230 116 67 100 206 231 189 254 222 57 193 129 4 5 56 176 88 76 184 105 193 104 255 73 46 183 34 16 36 91 206 2 138 87 236 162 173 134 23 199 124 60 176 84 91 96 88 247 228 85 2 149 184 77 194 164 219 166 240 203 174 105 0 188 183 41 37 131 160 210 39 247 201 54 90 55 221 174 133 74 219 192 208 206 22 185 55 240 10 43 64 40 129 198 47 123 244 10 249 14 101 87 23 119 106 248 156 197 116 161 83 6 195 52 85 232 159 191 116 183 150 42 81 44 60 240 31 217 108 232 26 244 65 242 204 202 176 169 115 165 78 52 174 106 31 110 73 133 216 51 209 66 83 81 189 202 197 210 77 219 174 117 243 176 239 90 78 159 219 210 64 190 121 31 172 218 113 92 195 51 4 80 39 51 143 38 61 37 19 184 194 255 60 224 176 68 97 220 139 153 110 12 109 95 192 240 179 49 147 32 152 217 104 136 10 24 119 160 189 25 93 254 45 90 56 232 207 121 213 72 128 187 195 128 224 239 185 98 83 251 164 32 84 218 102 146 92 58 92 83 203 66 1 143 130 5 89 187 178 149 92 208 184 228 27 103 186 100 71 59 16 146 72 28 251 28 230 144 112 46 249 95 86 134 192 59 6 144 228 58 194 237 221 234 168 254 156 111 224 44 242 81 219 57 220 234 174 110 48 95 130 149 179 161 62 55 141 224 91 85 109 81 67 38 138 195 37 185 172 230 133 8 217 90 196 197 59 173 67 27 198 26 250 73 178 128 18 183 101 57 36 224 4 170 67 141 155 136 57 27 59 160 20 212 75 7 65 194 143 139 180 40 212 19 64 246 1 93 66 233 128 56 181 171 163 177 106 177 32 178 45 96 234 158 235 78 250 35 227 160 227 8 218 120 188 200 46 235 79 132 35 80 93 169 29 66 78 104 119 9 183 217 112 211 128 53 38 245 116 226 137 28 165 39 139 38 254 40 229 209 50 116 109 71 18 28 71 207 184 5 125 51 138 110 150 238 45 91 168 85 16 90 135 52 200 174 33 233 126 99 180 178 205 163 24 232 254 152 8 153 138 39 253 49 173 62 60 124 175 74 134 118 82 15 135 108 221 208 64 48 231 47 42 109 79 159 9 131 227 79 142 73 78 23 3 100 86 183 67 100 247 146 25 217 205 36 219 19 229 226 250 175 32 135 118 177 162 95 114 99 26 0 160 228 154 183 247 21 178 231 71 228 179 251 153 85 82 176 240 129 97 221 154 192 230 225 160 196 186 84 101 141 47 38 17 217 250 166 74 225 32 219 37 203 74 155 129 47 232 189 205 150 27 23 108 62 169 194 118 32 199 130 141 123 197 123 136 185 223 63 50 77 58 205 255 5 70 118 23 207 165 228 111 31 198 18 69 197 40 7 214 159 126 235 189 172 125 65 62 133 33 127 199 166 105 89 102 58 114 154 141 167 239 11 236 67 174 47 195 160 253 180 233 7 255 13 18 26 8 161 6 109 220 169 182 121 45 77 7 109 101 44 229 236 103 55 82 151 244 175 219 110 89 116 55 163 9 223 251 251 158 205 48 208 109 143 245 101 51 125 150 27 55 113 86 102 112 85 135 255 90 193 232 227 118 167 118 186 161 133 190 87 5 130 9 58 184 211 21 43 174 3 211 119 132 251 184 75 245 225 201 140 49 217 54 129 5 128 215 38 66 158 96 1 68 45 137 61 43 34 194 161 63 112 207 11 8 154 45 195 118 138 217 0 188 163 7 244 233 27 197 160 161 162 13 47 145 99 213 35 242 49 198 2 25 218 102 215 119 18 233 46 159 210 172 240 173 210 14 242 138 114 141 63 102 227 74 0 110 207 238 2 107 176 32 164 169 240 245 193 166 77 156 30 3 220 121 165 213 149 5 200 129 34 185 167 1 13 124 72 57 12 216 113 186 147 212 24 27 254 56 220 52 201 39 58 201 83 194 72 198 173 192 95 173 245 167 178 182 33 224 105 11 238 2 122 242 210 237 69 217 70 73 151 28 102 213 143 237 169 170 172 29 13 66 183 220 1 157 251 179 14 35 186 212 37 238 161 49 34 235 175 235 24 10 230 150 187 33 92 250 182 255 14 246 214 117 189 167 135 172 107 181 189 217 190 112 130 221 162 199 195 1 12 210 7 159 224 167 182 88 195 187 94 130 80 246 67 133 65 199 28 214 60 98 107 178 233 8 116 93 227 25 212 53 38 10 215 70 250 195 33 208 101 128 124 183 4 194 241 24 10 173 100 162 37 100 96 217 145 88 20 153 31 132 103 187 91 10 7 94 220 51 180 86 130 128 20 17 193 28 172 35 29 81 207 113 128 75 70 117 215 199 192 62 49 143 189 108 52 244 164 188 54 66 150 240 186 66 53 50 108 103 109 182 153 9 187 173 101 204 101 147 107 245 125 54 63 50 65 77 225 222 79 240 54 34 100 41 146 25 85 165 33 39 89 47 231 51 28 218 36 65 70 183 155 219 113 113 17 160 109 94 36 237 112 22 103 170 80 83 80 176 148 125 122 175 237 221 90 114 140 10 243 130 232 43 165 38 69 96 122 209 223 52 144 47 80 135 176 125 124 253 236 194 144 184 143 1 226 162 201 233 43 166 96 24 237 107 129 232 86 63 69 164 86 206 109 247 107 156 74 140 93 7 63 74 219 90 60 88 246 33 96 42 182 185 211 104 167 227 219 53 35 225 13 7 88 1 218 53 106 44 232 49 216 215 43 192 111 59 156 165 34 127 41 21 207 172 127 54 139 111 22 4 132 192 65 87 45 63 223 217 46 64 89 22 242 117 231 219 93 185 67 200 227 90 243 94 15 121 199 128 246 173 71 96 164 198 100 238 34 29 155 186 70 24 139 3 107 162 114 11 158 46 188 182 50 245 203 78 87 26 97 95 240 64 53 28 177 40 223 13 132 174 67 220 139 218 108 186 153 54 15 124 73 169 89 233 171 103 95 243 185 234 89 16 75 93 37 140 112 183 210 31 155 145 102 4 192 7 62 44 188 25 125 44 130 3 177 193 139 210 205 119 138 105 141 183 215 42 79 232 19 253 219 168 145 93 25 151 63 161 62 185 250 37 242 246 131 214 123 74 73 93 92 6 103 160 182 23 194 230 139 215 176 142 231 1 34 54 221 62 217 61 99 10 151 224 131 228 52 167 30 10 40 126 124 252 10 133 198 141 128 139 221 240 88 167 183 105 114 217 21 27 104 117 87 63 111 205 118 174 53 132 241 19 5 71 245 40 237 71 42 96 85 72 213 47 76 233 83 84 39 229 73 158 253 63 105 96 35 119 101 26 8 164 59 162 154 45 230 158 170 203 98 158 243 172 89 218 237 6 207 135 205 216 48 25 248 163 163 187 221 170 202 116 19 50 151 229 124 89 82 143 119 30 161 3 222 127 44 66 140 236 141 12 79 77 191 9 56 50 27 253 115 197 57 99 231 238 16 135 243 15 146 33 15 144 171 72 228 10 128 9 75 212 81 201 227 70 43 248 208 26 188 67 90 29 197 84 14 237 101 3 87 231 140 152 83 74 30 184 61 197 188 63 185 34 103 113 109 169 112 51 179 16 182 176 127 216 44 118 214 128 78 176 4 133 105 55 57 17 72 134 112 220 146 241 221 156 152 244 163 6 218 113 66 179 73 69 86 38 221 53 199 161 155 130 188 8 109 37 122 5 61 251 122 115 64 244 245 8 212 177 67 235 123 3 86 20 94 156 66 22 127 86 25 131 199 125 226 117 61 46 234 123 46 110 212 123 68 55 205 14 14 253 247 49 127 226 102 2 0 145 50 210 242 176 33 243 113 185 240 235 140 252 231 116 84 198 99 118 121 117 108 26 223 133 196 186 81 234 230 0 58 137 80 199 136 128 136 231 251 215 209 144 55 181 136 88 114 115 188 81 57 10 112 69 89 173 159 78 12 31 31 117 184 50 181 37 147 130 23 233 138 84 77 42 153 13 82 106 232 68 181 136 26 131 206 13 77 126 92 29 43 96 131 39 104 44 112 100 111 165 55 61 104 198 92 205 147 73 106 62 133 122 18 155 79 153 39 207 116 126 170 138 9 120 25 167 233 114 18 180 237 8 238 215 233 18 203 78 133 38 9 213 215 254 29 15 193 65 182 58 209 205 61 82 191 47 117 119 44 8 160 143 14 71 43 213 76 26 17 3 58 15 59 106 28 78 68 90 158 105 218 214 244 204 96 94 10 191 56 138 171 236 8 183 248 222 67 33 249 132 156 92 252 134 51 192 45 105 157 183 130 104 159 55 184 117 171 212 65 83 42 207 41 92 173 109 98 80 57 54 93 132 61 25 40 104 247 170 223 97 182 182 26 125 125 238 144 181 26 59 60 139 147 64 165 38 83 17 75 177 158 217 124 56 178 198 223 21 183 86 237 13 190 16 209 177 224 6 59 230 121 141 146 81 104 175 235 49 11 32 235 54 25 117 104 187 231 30 129 21 45 140 9 30 170 7 188 49 21 182 237 36 67 72 197 184 188 25 104 24 84 155 250 39 240 2 46 14 32 193 62 75 217 37 131 203 164 61 34 193 20 104 181 112 103 153 248 32 241 82 120 101 89 234 171 39 70 211 75 193 28 11 7 155 229 255 133 39 171 50 35 65 232 65 137 147 61 179 179 33 150 209 123 224 69 120 206 130 160 17 75 131 115 52 68 18 197 188 68 133 239 248 143 136 186 176 101 196 6 2 28 122 199 29 220 70 91 168 136 46 103 148 127 103 172 89 16 239 219 173 139 41 145 95 129 43 166 162 194 43 206 170 82 45 154 42 203 106 119 150 112 239 182 21 181 254 73 222 122 96 187 239 58 33 14 22 107 149 46 16 5 94 56 227 104 52 132 109 182 251 173 186 206 229 187 73 16 221 15 139 77 0 147 145 243 52 243 11 207 245 195 139 63 238 154 138 205 86 19 128 176 136 202 102 179 195 58 6 204 227 242 219 102 82 146 230 39 138 157 100 154 190 82 195 117 108 33 206 132 245 184 244 189 242 56 225 162 133 44 184 179 49 80 53 70 113 125 198 119 75 128 105 207 175 198 9 86 123 197 210 200 87 189 152 228 135 13 49 1 253 28 26 79 28 189 123 159 2 11 130 217 134 38 216 210 196 0 128 159 37 32 108 54 56 198 192 240 42 124 59 206 42 9 98 151 42 69 189 242 21 251 89 159 122 214 76 154 218 204 27 81 115 216 208 65 188 103 178 243 23 230 44 166 7 2 134 233 46 205 195 202 121 12 106 173 125 209 137 6 248 171 216 210 142 77 47 231 61 228 52 213 17 238 235 158 125 55 10 184 168 251 87 33 93 147 41 58 20 218 44 214 155 108 20 226 240 171 31 123 201 230 140 175 170 135 176 112 175 188 11 144 53 84 29 188 235 206 24 114 102 177 33 115 154 238 104 21 79 99 223 171 51 202 35 4 190 151 156 195 158 26 224 13 165 194 124 81 171 97 103 15 111 94 43 218 205 150 238 54 205 213 73 140 245 91 83 222 9 214 45 15 154 115 106 234 157 139 145 76 250 155 146 27 200 141 252 96 54 187 198 27 41 198 126 130 154 100 127 23 12 217 180 57 218 131 68 95 252 87 2 210 217 138 198 168 167 178 9 229 129 103 213 93 184 79 223 77 214 6 104 188 187 106 64 215 16 200 156 63 141 217 52 173 229 110 160 118 220 164 198 56 245 36 33 187 122 62 92 8 107 244 11 193 99 117 2 74 195 253 159 245 199 18 78 19 1 126 156 53 233 58 250 80 212 243 154 78 139 236 72 230 0 218 50 218 23 79 136 55 6 112 161 42 236 73 178 238 108 62 145 104 240 2 4 211 43 232 210 122 43 65 111 34 67 143 206 48 222 144 232 129 60 243 204 103 98 252 2 115 242 107 80 34 2 91 116 166 21 119 96 165 76 208 252 105 186 10 122 68 158 148 118 162 65 57 142 140 212 36 74 185 157 155 0 80 21 252 174 222 212 247 42 156 212 32 230 248 173 212 74 74 27 199 158 188 215 177 174 46 107 15 174 166 242 136 165 100 157 60 120 251 175 204 57 229 138 25 190 147 121 164 6 220 32 112 60 68 177 206 21 47 7 115 246 79 212 176 171 90 135 220 5 41 147 32 135 113 255 41 18 197 183 16 2 16 81 185 136 83 192 235 247 216 1 173 31 8 22 163 221 156 37 227 87 24 28 77 69 215 117 132 158 74 214 141 28 135 167 205 124 102 4 137 48 65 126 119 120 126 222 31 89 146 75 51 193 106 231 30 196 146 206 195 6 58 164 141 58 168 202 42 8 230 238 64 245 132 11 30 62 239 41 60 106 198 233 217 109 208 119 179 54 82 1 191 52 254 211 188 158 198 10 48 246 47 217 37 75 183 96 142 243 198 228 180 147 3 137 189 183 120 254 144 193 225 114 239 139 169 227 89 195 58 49 98 151 136 186 181 227 105 113 108 83 35 40 9 199 157 19 107 112 32 190 158 22 142 107 234 230 29 213 249 37 86 56 196 182 153 241 34 209 145 73 37 228 139 66 154 194 56 9 175 158 68 226 60 85 227 27 227 147 189 247 91 109 144 97 45 18 118 192 251 67 25 95 201 181 101 0 194 168 125 6 190 235 127 125 5 137 151 56 29 222 29 238 110 220 76 24 169 234 191 218 215 160 236 220 38 58 241 79 103 201 248 206 105 170 177 30 113 197 36 148 246 36 221 134 110 189 203 211 68 43 17 158 176 52 67 243 15 130 255 101 178 61 138 200 46 119 135 139 115 59 10 216 96 145 177 171 154 243 47 218 51 12 237 6 227 225 94 174 182 48 170 70 44 80 166 206 239 164 128 67 245 71 52 96 164 194 222 249 56 28 15 163 34 158 235 128 58 253 12 213 100 214 161 171 69 160 214 142 85 19 90 56 121 86 93 0 148 149 132 166 65 113 130 96 244 0 103 6 20 36 54 250 147 145 239 40 158 131 252 148 83 165 87 30 33 30 127 231 206 72 233 63 241 81 227 58 122 169 111 206 147 62 35 26 149 45 178 40 18 182 4 113 69 202 45 42 9 202 181 138 230 220 25 151 15 35 20 171 213 242 49 32 248 94 32 47 206 122 126 78 92 189 108 10 255 237 251 4 105 17 158 89 110 182 205 202 111 51 105 89 233 3 126 117 8 39 143 43 251 190 136 14 61 86 11 104 218 30 108 60 55 248 69 184 133 204 28 16 241 11 11 24 79 179 170 61 123 143 168 172 172 112 68 221 18 198 3 137 42 37 30 84 187 58 152 236 213 198 142 150 53 234 95 45 57 175 22 143 215 76 138 179 108 61 98 19 243 119 171 228 111 17 80 148 65 126 54 126 43 1 9 181 66 211 108 4 175 231 200 112 231 216 192 146 82 172 103 106 219 97 127 53 175 5 154 236 151 121 220 125 54 10 157 212 178 47 183 61 234 54 105 49 0 180 27 91 213 189 9 222 69 53 167 116 43 124 247 71 85 25 226 55 128 34 26 154 54 106 218 24 204 221 109 27 140 102 29 102 244 112 113 134 137 110 249 17 53 240 161 196 10 150 226 27 218 152 246 117 69 253 142 44 163 168 69 199 248 155 24 1 168 41 176 107 145 83 181 79 208 106 129 147 187 134 254 11 84 175 165 37 86 81 118 75 213 227 116 90 44 149 222 29 237 80 230 130 195 14 220 213 214 11 88 73 183 70 188 74 131 254 226 161 142 85 92 121 246 83 225 3 95 248 154 179 190 212 44 64 226 16 208 33 52 20 133 247 61 72 217 59 32 69 201 37 237 81 185 123 209 254 252 196 98 169 14 229 78 37 95 153 241 153 135 173 69 211 235 135 18 6 176 57 140 131 223 231 30 107 33 202 179 132 224 155 208 17 52 94 120 2 50 45 21 197 142 194 176 177 67 248 162 133 181 64 141 79 81 191 105 182 181 7 123 5 44 69 129 201 41 164 228 172 60 158 126 123 189 176 115 149 193 48 23 38 102 37 98 11 155 176 127 48 37 110 21 90 113 10 137 251 237 45 158 167 166 252 165 248 96 170 131 132 126 148 30 208 211 4 77 114 219 255 171 54 83 234 7 76 85 117 233 182 159 35 215 80 80 184 91 237 103 139 37 157 14 78 77 78 25 136 105 239 253 209 26 152 25 22 145 97 118 177 242 75 32 32 110 134 187 203 222 65 219 212 134 203 126 37 224 13 241 124 92 223 148 230 57 89 251 141 223 20 36 59 18 158 123 85 148 11 14 245 146 11 24 206 51 253 240 56 151 213 145 51 249 125 227 149 242 151 84 96 25 9 249 27 86 227 39 240 185 179 63 54 169 147 242 239 131 63 7 35 122 158 56 41 92 49 28 194 169 173 133 63 190 223 165 152 141 66 111 112 251 170 166 84 160 115 246 54 217 103 39 194 122 150 1 218 57 39 17 156 181 127 16 219 45 72 55 51 175 206 98 232 232 6 129 100 168 2 78 72 5 44 127 58 73 2 115 89 77 234 18 52 70 78 172 101 92 243 146 154 98 228 230 25 77 66 187 192 23 228 52 37 207 63 69 121 95 241 212 131 125 124 251 114 160 61 10 169 228 83 133 158 54 116 166 127 50 164 115 176 37 116 50 37 207 114 177 244 158 221 175 129 8 189 2 164 131 112 214 119 6 208 253 145 141 222 158 53 56 88 107 99 180 255 251 163 45 189 73 83 10 229 68 101 87 38 153 5 109 70 130 97 239 98 175 74 140 249 117 0 224 13 87 162 170 32 92 250 198 41 12 64 4 177 8 87 164 211 196 255 244 46 145 30 232 84 195 128 24 227 163 240 204 215 135 209 165 150 65 94 184 203 234 7 151 4 223 70 104 87 109 163 91 238 79 87 218 178 112 13 231 242 173 110 62 6 47 238 67 251 239 205 86 40 68 58 198 18 183 222 119 90 214 68 221 32 61 212 57 175 90 202 104 141 110 93 22 159 167 78 224 218 98 140 91 70 157 43 12 167 253 165 86 237 167 51 0 193 93 34 3 143 249 141 217 190 145 88 29 83 92 163 215 82 124 225 13 45 32 139 119 102 58 137 5 176 246 123 212 182 13 36 64 129 140 46 205 219 210 181 27 21 5 73 158 166 139 236 158 252 192 77 56 187 57 72 6 194 243 215 152 211 235 158 150 15 12 212 44 176 179 139 18 229 88 246 38 186 192 201 158 219 49 96 14 227 252 44 113 114 120 215 240 139 46 155 14 148 191 209 165 157 226 9 147 88 175 255 50 226 232 252 221 107 160 94 207 39 92 151 173 121 167 30 165 33 174 135 40 86 80 1 171 182 218 165 101 186 131 172 209 1 196 109 22 125 2 50 85 153 100 237 177 128 135 188 43 29 64 117 134 255 149 142 233 118 249 23 64 182 75 18 41 51 97 212 118 220 55 152 98 53 31 180 212 126 236 236 245 58 187 169 113 12 10 110 67 45 36 58 107 66 155 63 81 152 187 124 111 19 127 0)! ! !InterpreterSupportCode class methodsFor: 'source files' stamp: 'JMM 2/12/2001 21:59'! macAsyncFilePrimsFile ^ '/* Adjustments for pluginized VM * * Note: The Mac support files have not yet been fully converted to * pluginization. For the time being, it is assumed that they are linked * with the VM. When conversion is complete, they will no longer import * "sq.h" and they will access all VM functions and variables through * the interpreterProxy mechanism. */ #include "sq.h" #include "AsynchFilePlugin.h" #include #if !!TARGET_API_MAC_CARBON #define DisposeIOCompletionUPP(userUPP) DisposeRoutineDescriptor(userUPP) #endif /* initialize/shutdown */ int asyncFileInit() { return true; } int asyncFileShutdown() {} /* End of adjustments for pluginized VM */ /* Experimental support for asynchronous file reading and writing. When a read or write operation is initiated, control is returned to Squeak immediately. A semaphore is signaled when the operation completes, at which time the client can find out how many bytes were actually read or written and copy the results of the read operation from the file buffer into a Squeak buffer. Only one operation may be in progress on a given file at a given time, but operations on different files may be done in parallel. The semaphore is signalled once for each transfer operation that is successfully started, even if that operation later fails. Write operations always write their entire buffer if they succeed, but read operations may transfer less than their buffer size if they are started less than a buffer''s size from the end of the file. The state of a file is kept in the following structure, which is stored directly in a Squeak ByteArray object: typedef struct { int sessionID; AsyncFileState *state; } AsyncFile; The session ID is used to detect stale files--files that were open when the image was saved. The state pointer of such files is meaningless. Async file handles use the same session ID as ordinary file handles. Note: These primitives are experimental!! They need not be implemented on every platform, and they may be withdrawn or replaced in a future release. */ #include #include #include /* Async file handle (defined in header file): */ typedef struct { ParamBlockRec pb; /* must be first */ long refNum; int writable; int semaIndex; int status; int bytesTransferred; int bufferSize; char *bufferPtr; } AsyncFileState; /*** Status Values ***/ #define IDLE 0 #define LAST_OP_FAILED 1 #define BUSY 2 /*** Imported Variables ***/ extern int successFlag; extern int thisSession; /*** Local Vaiables ***/ IOCompletionUPP asyncFileCompletionProc = nil; /*** Exported Functions ***/ int asyncFileClose(AsyncFile *f); int asyncFileOpen(AsyncFile *f, int fileNamePtr, int fileNameSize, int writeFlag, int semaIndex); int asyncFileRecordSize(); int asyncFileReadResult(AsyncFile *f, int bufferPtr, int bufferSize); int asyncFileReadStart(AsyncFile *f, int fPosition, int count); int asyncFileWriteResult(AsyncFile *f); int asyncFileWriteStart(AsyncFile *f, int fPosition, int bufferPtr, int bufferSize); /*** Local Functions ***/ int asyncFileAllocateBuffer(AsyncFileState *state, int byteCount); pascal void asyncFileCompletionRoutine(AsyncFileState *state); int asyncFileInitPB(AsyncFileState *state, int fPosition); int asyncFileValid(AsyncFile *f); int asyncFileAllocateBuffer(AsyncFileState *state, int byteCount) { /* Allocate a new buffer of the given size if necessary. If the current buffer is already allocated and of the desired size, do nothing. */ if ((state->bufferPtr !!= nil) && (state->bufferSize == byteCount)) { return; /* buffer is already allocated and of the desired size */ } /* free old buffer, if any */ if (state->bufferPtr !!= nil) { DisposePtr(state->bufferPtr); state->bufferSize = 0; state->bufferPtr = nil; } /* allocate new buffer */ state->bufferPtr = NewPtr(byteCount); if (state->bufferPtr == nil) { state->bufferSize = 0; return success(false); /* could not allocate a buffer of size count */ } state->bufferSize = byteCount; } pascal void asyncFileCompletionRoutine(AsyncFileState *state) { /* Called when an I/O request completes. Decides what to do based on the given state. Note that the first part of the state record is the I/O parameter block. */ OSErr err; err = state->pb.ioParam.ioResult; if ((err !!= noErr) && (err !!= eofErr)) { /* Note: eofErr indicates that fewer than the count bytes were transfered when reading because the end-of-file was encountered first; it isn''t a real error. */ state->status = LAST_OP_FAILED; state->bytesTransferred = 0; signalSemaphoreWithIndex(state->semaIndex); return; } state->bytesTransferred = state->pb.ioParam.ioActCount; state->status = IDLE; signalSemaphoreWithIndex(state->semaIndex); } int asyncFileInitPB(AsyncFileState *state, int fPosition) { memset(&state->pb, 0, sizeof(ParamBlockRec)); state->pb.ioParam.ioCompletion = asyncFileCompletionProc; state->pb.ioParam.ioRefNum = state->refNum; state->pb.ioParam.ioBuffer = state->bufferPtr; state->pb.ioParam.ioReqCount = state->bufferSize; state->pb.ioParam.ioPosMode = fsFromStart; state->pb.ioParam.ioPosOffset = (fPosition < 0) ? 0 : fPosition; state->status = BUSY; state->bytesTransferred = 0; } int asyncFileValid(AsyncFile *f) { return ( (f !!= NULL) && (f->sessionID == thisSession) && (f->state !!= NULL) && (((AsyncFileState *) f->state)->refNum !!= 0)); } /*** Exported Functions ***/ int asyncFileClose(AsyncFile *f) { /* Close the given asynchronous file. */ AsyncFileState *state; short int volRefNum; OSErr err; if (!!asyncFileValid(f)) return; /* already closed */ state = f->state; err = GetVRefNum(state->refNum, &volRefNum); success(err == noErr); err = FSClose(state->refNum); success(err == noErr); if (successFlag) err = FlushVol(NULL, volRefNum); success(err == noErr); if (asyncFileCompletionProc !!= nil) DisposeIOCompletionUPP(asyncFileCompletionProc); asyncFileCompletionProc = nil; if (state->bufferPtr !!= nil) DisposePtr(state->bufferPtr); DisposePtr((void *) f->state); f->state = nil; f->sessionID = 0; } int asyncFileOpen(AsyncFile *f, int fileNamePtr, int fileNameSize, int writeFlag, int semaIndex) { /* Opens the given file using the supplied AsyncFile structure to record its state. Fails with no side effects if f is already open. Files are always opened in binary mode. */ int i; Str255 cFileName; short int fileRefNum; AsyncFileState *state; OSErr err; /* don''t open an already open file */ if (asyncFileValid(f)) return success(false); /* build complete routine descriptor, if necessary */ if (asyncFileCompletionProc == nil) { #if TARGET_API_MAC_CARBON asyncFileCompletionProc = NewIOCompletionUPP((pascal void (*) (union ParamBlockRec *) )asyncFileCompletionRoutine); #else asyncFileCompletionProc = NewIOCompletionProc((pascal void (*) (union ParamBlockRec *) )asyncFileCompletionRoutine); #endif } /* copy the file name into a null-terminated C string */ if (fileNameSize > 255) return success(false); sqFilenameFromString(cFileName, fileNamePtr, fileNameSize); CopyCStringToPascal((const char *)cFileName,cFileName); f->sessionID = 0; if (writeFlag) { /* first try to open an existing file read/write: */ err = HOpenDF(0,0,cFileName, fsRdWrPerm, &fileRefNum); if (err !!= noErr) { /* file does not exist; must create it. */ err = HCreate(0, 0, cFileName,''R*ch'',''TEXT''); if (err !!= noErr) return success(false); err = HOpenDF(0,0,cFileName,fsRdWrPerm, &fileRefNum); if (err !!= noErr) return success(false); } } else { /* open the file read-only */ err = HOpenDF(0,0,cFileName, fsRdPerm, &fileRefNum); if (err !!= noErr) return success(false); } f->state = (AsyncFileState *) NewPtr(sizeof(AsyncFileState)); /* allocate state record */ if (f->state == nil) { FSClose(fileRefNum); return success(false); } f->sessionID = thisSession; state = (AsyncFileState *) f->state; state->refNum = fileRefNum; state->writable = writeFlag; state->semaIndex = semaIndex; state->status = IDLE; state->bytesTransferred = 0; state->bufferSize = 0; state->bufferPtr = nil; } int asyncFileReadResult(AsyncFile *f, int bufferPtr, int bufferSize) { /* Copy up to bufferSize bytes from the buffer of the last read operation into the given Squeak buffer, and return the number of bytes copied. Negative values indicate: -1 -- busy; the last operation has not finished yet -2 -- error; the last operation failed Note that a read operation may read fewer bytes than requested if, for example, there are fewer than the requested number of bytes between the starting file position of the read operation and the end-of-file. */ AsyncFileState *state; int bytesRead; if (!!asyncFileValid(f)) return success(false); state = f->state; if (state->status == BUSY) return -1; if (state->status == LAST_OP_FAILED) return -2; /* copy the file buffer into the squeak buffer */ bytesRead = (bufferSize < state->bytesTransferred) ? bufferSize : state->bytesTransferred; memcpy((char *) bufferPtr, state->bufferPtr, bytesRead); return bytesRead; } int asyncFileReadStart(AsyncFile *f, int fPosition, int count) { /* Start an asynchronous operation to read count bytes from the given file starting at the given file position. The file''s semaphore will be signalled when the operation is complete. The client may then use asyncFileReadResult() to find out if the operation succeeded and to get the data that was read. */ AsyncFileState *state; OSErr err; if (!!asyncFileValid(f)) return success(false); state = f->state; if (state->status == BUSY) return success(false); /* operation in progress */ /* allocate a new buffer if necessary */ asyncFileAllocateBuffer(state, count); if (state->bufferPtr == nil) return success(false); /* could not allocate buffer */ asyncFileInitPB(state, fPosition); err = PBReadAsync(&state->pb); if (err !!= noErr) { state->status = IDLE; return success(false); } } int asyncFileRecordSize() { return sizeof(AsyncFile); } int asyncFileWriteResult(AsyncFile *f) { /* Return the number of bytes copied by the last write operation. Negative values indicate: -1 -- busy; the last operation has not finished yet -2 -- error; the last operation failed */ AsyncFileState *state; if (!!asyncFileValid(f)) return success(false); state = f->state; if (state->status == BUSY) return -1; if (state->status == LAST_OP_FAILED) return -2; return state->bytesTransferred; } int asyncFileWriteStart(AsyncFile *f, int fPosition, int bufferPtr, int bufferSize) { /* Start an asynchronous operation to write bufferSize bytes to the given file starting at the given file position. The file''s semaphore will be signalled when the operation is complete. The client may then use asyncFileWriteResult() to find out if the operation succeeded and how many bytes were actually written. */ AsyncFileState *state; OSErr err; if (!!asyncFileValid(f)) return success(false); state = f->state; if (state->status == BUSY) return success(false); /* operation in progress */ if (!!state->writable) return success(false); /* allocate a new buffer if necessary */ asyncFileAllocateBuffer(state, bufferSize); if (state->bufferPtr == nil) return success(false); /* could not allocate buffer */ /* copy the squeak buffer into the file buffer */ memcpy(state->bufferPtr, (char *) bufferPtr, bufferSize); asyncFileInitPB(state, fPosition); err = PBWriteAsync(&state->pb); if (err !!= noErr) { state->status = IDLE; return success(false); } } '! ! !InterpreterSupportCode class methodsFor: 'source files' stamp: 'JMM 2/16/2001 21:47'! macBrowserPluginFile ^ '/********** Notes on Browser Plugin VM ************ How it Works: The browser plugin VM allows Squeak to be run as a plug-in under version 4.0 and later of either Netscape Navigator or Internet Explorer. To use it, you must translate a version of interp.c with the browser plugin hooks. Note for fullscreen support NPP_HandleEvent does not return control, it consumes events from waitnextevent. When fullscreen mode is turn off then control is returned to the browser. Relationship of this file to sqMacWindow.c: One can think of this file as specializing and extending sqMacWindow.c for running within a browser. Certain methods in sqMacWindow.c are replaced by functions defined here. The originals are removed from sqMacWindow.c by defining the PLUGIN flag in that file when compiling. Here is a list of the functions overridden: ioExit() ioScreenSize() ioSetFullScreen() sqAllocateMemory() In addition, ioProcessEvents() becomes a noop and main() is completely omitted when sqMacWindow.c is compiled for use in the browser plugin VM. Thing busted 2000 July 26th squeak quit restart has issues with change file open June/July 2000 johnmci@smalltalkconsulting.com Reviewed code readded comments, added FullScreen Support fixed issues with Carbon, general code cleaning. Sept 27th 2000 johnmci@smalltalkconsulting.com added logic to have more flexibility in memory size. Fix issue with volume ID, don''t use 0 Fix issue were IE lies about the frame size as it figures out the frame size in real time durning rendering Added check for file: in URL logic to disallow Fixed problem in NPP_URLNotify, must call notify complete logic Ensure NP_memFree is called for plugin arguments Add logic for URLPosting Feb 8th 2001 johnmci@smalltalkconsulting.com Rewrote to use Apple multithreaded library and ported Squeak VM 3.0 **********/ #include "sq.h" #include "FilePlugin.h" #include "npapi.h" #include #include #include #include #include #include #include #include #include #include #include #if TARGET_API_MAC_CARBON #define EnableMenuItemCarbon(m1,v1) EnableMenuItem(m1,v1); #define DisableMenuItemCarbon(m1,v1) DisableMenuItem(m1,v1); #else #define EnableMenuItemCarbon(m1,v1) EnableItem(m1,v1); #define DisableMenuItemCarbon(m1,v1) DisableItem(m1,v1); inline Rect *GetPortBounds(CGrafPtr w,Rect *r) { *r = w->portRect; return &w->portRect;} inline Rect *GetRegionBounds(RgnHandle region, Rect * bounds) { *bounds = (*region)->rgnBBox; return &(*region)->rgnBBox;} inline RgnHandle GetPortClipRegion(CGrafPtr port,RgnHandle clipRgn) {MacCopyRgn (port->clipRgn,clipRgn); return clipRgn;} inline BitMap *GetQDGlobalsScreenBits(BitMap *bm){*bm = qd.screenBits; return &qd.screenBits; } inline BitMap * GetPortBitMapForCopyBits (CGrafPtr w) { return &((GrafPtr)w)->portBits;} inline pascal long InvalWindowRect(WindowRef window, const Rect * bounds) {InvalRect (bounds);} #endif /********** Compilation Options: * * ENABLE_URL_FETCH * Define this to compile primitives to fetch URL''s via the browser. * * Warning: Fetching file URL''s through the URL fetch mechanism allows * potentially untrusted code to read files outside of the Squeak * file system "sandbox", a serious breach of privacy. * There are few uses for use for the browser URL fetch * mechanism, since you can always fetch URL''s from remote servers * using Squeak''s own HTTPSocket. * **********/ #define ENABLE_URL_FETCH #define IMAGE_NAME "SqueakPlugin.image" #define VMPATH_SIZE 300 /*** Exported Primitives ***/ #ifdef ENABLE_URL_FETCH #pragma export on int primitivePluginBrowserReady(void); int primitivePluginDestroyRequest(void); int primitivePluginRequestFileHandle(void); int primitivePluginRequestState(void); int primitivePluginRequestURL(void); int primitivePluginRequestURLStream(void); int primitivePluginPostURL(void); #pragma export off #endif /* Constants */ #define MAX_STRING_LENGTH 255 #define MAX_ARG_STRING_LENGTH 100 #define STATUS_BAD_HANDLE -1 #define STATUS_IDLE 0 #define STATUS_IN_PROGRESS 1 #define STATUS_FAILED 2 #define STATUS_SUCCEEDED 3 #define STARTINGsqueakHeapMBytes 20*1024*1024 /*** Imported Variables ***/ extern int interruptKeycode; extern unsigned char *memory; extern WindowPtr stWindow; extern int fullScreenFlag; extern int successFlag; extern char documentName[]; /* full path to document file */ extern char imageName[]; /* full path to image file */ extern char shortImageName[]; /* just the image file name */ extern char vmPath[]; /* full path to interpreter''s directory */ extern struct VirtualMachine *interpreterProxy; extern int thisSession; /* from sqFilePrims.c: */ /*** Local Variables ***/ int exitRequested = false; Rect gSavePortPortRect; RgnHandle gSavePortClipRgn; CGrafPtr gOldPort = nil; int needsUpdate = false; NPWindow* netscapeWindow = nil; Str255 notificationMsg = ""; NMRec notifyRec; int pluginArgCount = 0; char *pluginArgName[MAX_ARG_STRING_LENGTH]; char *pluginArgValue[MAX_ARG_STRING_LENGTH]; Boolean ignoreFirstEvent=false; int squeakHeapMBytes = STARTINGsqueakHeapMBytes; /* default heap size, override via the "memory" EMBED tag */ char squeakPluginImageName[] = IMAGE_NAME; NPP thisInstance = nil; WindowPtr gAFullscreenWindow = nil; char rememberMemoryString[128]=""; extern Boolean gAllowAccessToFilePlease; #define URL_REQUEST_COUNT 100 typedef struct { int id; /* used to associate a request with its outcome */ int status; int semaIndex; char fileName[MAX_STRING_LENGTH + 1]; char *buffer; } URLRequestRecord; URLRequestRecord urlRequests[URL_REQUEST_COUNT]; int nextRequestID = 1; /*** Functions Imported from sqMacWindow ***/ int recordKeystroke(EventRecord *theEvent); int recordModifierButtons(EventRecord *theEvent); int recordMouseDown(EventRecord *theEvent); void ioSetFullScreenRestore(); int PrefixPathWith(char *pathName, int pathNameSize, int pathNameMax, char *prefix); int PathToWorkingDir(char *pathName, int pathNameMax, short volumeNumber,long directoryID); extern int dropInit(void); /*** From VM ***/ int checkImageVersionFromstartingAt(sqImageFile f, int imageOffset); int getLongFromFileswap(sqImageFile f, int swapFlag); extern int inputSemaphoreIndex; int recordMouseEvent(EventRecord *theEvent, int theButtonState); int MouseModifierState(EventRecord *theEvent); typedef int (*eventMessageHook)(EventRecord* event); extern eventMessageHook postMessageHook; int recordKeyboardEvent(EventRecord *theEvent, int keyType); extern Boolean gThreadManager; OSErr createNewThread(); extern PixMapHandle stPixMap; extern ThreadID gSqueakThread; GDHandle getDominateDevice( WindowPtr theWindow,Rect *windRect); int ioInitSecurity(void); /*** Local Functions ***/ int CaseInsensitiveMatch(char *s1, char *s2); void EndDraw(void); void ExitCleanup(void); int FindIdleURLRequest(void); int InitFilePaths(void); void InitURLRequestTable(void); int IsPrefixedBy(char *s, char *prefix); void OpenFileReadOnly(SQFile *f, char *fileName); void ReadSqueakImage(void); void StartDraw(void); int StringToInteger(char *s); void URLRequestCompleted(int notifyData, const char* fileName); int URLRequestCreate(char *url, char *target, int semaIndex); void URLRequestDestroy(int requestHandle); void URLRequestFailed(int notifyData, int reason); char * URLRequestFileName(int requestHandle); int URLRequestStatus(int requestHandle); int parseMemorySize(int baseSize, char *src); int AbortIfFileURL(char *url); int URLPostCreate(char *url, char *buffer, char * window,int semaIndex); /*** Initialize/Shutdown ***/ /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_Initialize: * Provides global initialization for a plug-in, and returns an error value. * * This function is called once when a plug-in is loaded, before the first instance * is created. Allocate any memory or resources shared by all * instances of your plug-in at this time. After the last instance has been deleted, * NPP_Shutdown will be called, where you can release any memory or * resources allocated by NPP_Initialize. +++++++++++++++++++++++++++++++++++++++++++++++++*/ NPError NPP_Initialize(void) { exitRequested = false; needsUpdate = false; netscapeWindow = nil; pluginArgCount = 0; thisInstance = nil; InitURLRequestTable(); return NPERR_NO_ERROR; } /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_GetJavaClass: * New in Netscape Navigator 3.0. * * NPP_GetJavaClass is called during initialization to ask your plugin * what its associated Java class is. If you don''t have one, just return * NULL. +++++++++++++++++++++++++++++++++++++++++++++++++*/ jref NPP_GetJavaClass(void) { return (jref) NULL; } /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_Shutdown: * Provides global deinitialization for a plug-in. * * This function is called once after the last instance of your plug-in is destroyed. * Use this function to release any memory or resources shared across all * instances of your plug-in. +++++++++++++++++++++++++++++++++++++++++++++++++*/ void NPP_Shutdown(void) { ExitCleanup(); } /*** Instance Create/Destroy ***/ /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_New: * Creates a new instance of a plug-in and returns an error value. * * NPP_New creates a new instance of your plug-in with MIME type specified * by pluginType. The parameter mode is NP_EMBED if the instance was created * by an EMBED tag, or NP_FULL if the instance was created by a separate file. * You can allocate any instance-specific private data in instance->pdata at this * time. The NPP pointer is valid until the instance is destroyed. +++++++++++++++++++++++++++++++++++++++++++++++++*/ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved) { int i; long threadGestaltInfo; OSErr err; /* only one Squeak instance can be active at a time */ if (thisInstance !!= nil) return NPERR_GENERIC_ERROR; for (i = 0; i < MAX_ARG_STRING_LENGTH; i++) { pluginArgName[i] = pluginArgValue[i] = ""; } /* record plugin arguments */ pluginArgCount = argc; for (i = 0; (i < argc) && (i < MAX_ARG_STRING_LENGTH); i++) { pluginArgName[i] = (char *) NPN_MemAlloc(strlen(argn[i]) + 1); strcpy(pluginArgName[i], argn[i]); pluginArgValue[i] = (char *) NPN_MemAlloc(strlen(argv[i]) + 1); strcpy(pluginArgValue[i], argv[i]); if (CaseInsensitiveMatch(pluginArgName[i], "memory")) { strcpy(rememberMemoryString,pluginArgValue[i]); } } memory = nil; ReadSqueakImage(); if (!!memory) return NPERR_GENERIC_ERROR; thisInstance = instance; gSavePortClipRgn = NewRgn(); if ((Gestalt( gestaltThreadMgrAttr, &threadGestaltInfo) == noErr) && threadGestaltInfo & (1<pdata. If the instance being deleted is the last instance created * by your plug-in, NPP_Shutdown will subsequently be called, where you can * delete any data allocated in NPP_Initialize to be shared by all your plug-in''s * instances. Note that you should not perform any graphics operations in * NPP_Destroy as the instance''s window is no longer guaranteed to be valid. +++++++++++++++++++++++++++++++++++++++++++++++++*/ NPError NPP_Destroy(NPP instance, NPSavedData** save) { long i; ExitCleanup(); if (pluginArgCount !!= 0) { for(i=0;iwindow are NULL, the plug-in must not perform any additional * graphics operations on the window and should free any resources associated * with the window. +++++++++++++++++++++++++++++++++++++++++++++++++*/ NPError NPP_SetWindow(NPP instance, NPWindow* window) { NP_Port* port; if (window == NULL) return NPERR_NO_ERROR; if (window->window == NULL) return NPERR_NO_ERROR; netscapeWindow = window; port = (NP_Port *) netscapeWindow->window; stWindow = (WindowPtr) port->port; needsUpdate = true; dropInit(); return NPERR_NO_ERROR; } /*** Streaming ***/ /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_NewStream: * Notifies an instance of a new data stream and returns an error value. * * NPP_NewStream notifies the instance denoted by instance of the creation of * a new stream specifed by stream. The NPStream* pointer is valid until the * stream is destroyed. The MIME type of the stream is provided by the * parameter type. +++++++++++++++++++++++++++++++++++++++++++++++++*/ NPError NPP_NewStream( NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype) { /* Call to load the initial URL and to handle explicit URL fetch requests. */ *stype = NP_ASFILEONLY; /* ask Netscape to cache file and call NPP_StreamAsFile */ return NPERR_NO_ERROR; } /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_DestroyStream: * Indicates the closure and deletion of a stream, and returns an error value. * * The NPP_DestroyStream function is called when the stream identified by * stream for the plug-in instance denoted by instance will be destroyed. You * should delete any private data allocated in stream->pdata at this time. +++++++++++++++++++++++++++++++++++++++++++++++++*/ NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) { return NPERR_NO_ERROR; } /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_StreamAsFile: * Provides a local file name for the data from a stream. * * NPP_StreamAsFile provides the instance with a full path to a local file, * identified by fname, for the stream specified by stream. NPP_StreamAsFile is * called as a result of the plug-in requesting mode NP_ASFILEONLY or * NP_ASFILE in a previous call to NPP_NewStream. If an error occurs while * retrieving the data or writing the file, fname may be NULL. +++++++++++++++++++++++++++++++++++++++++++++++++*/ void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname) { if (fname !!= null) URLRequestCompleted((int) stream->notifyData, fname); else URLRequestFailed((int) stream->notifyData, 1); } /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_WriteReady: * Returns the maximum number of bytes that an instance is prepared to accept * from the stream. * * NPP_WriteReady determines the maximum number of bytes that the * instance will consume from the stream in a subsequent call NPP_Write. This * function allows Netscape to only send as much data to the instance as the * instance is capable of handling at a time, allowing more efficient use of * resources within both Netscape and the plug-in. +++++++++++++++++++++++++++++++++++++++++++++++++*/ int32 NPP_WriteReady(NPP instance, NPStream *stream) { /* not used, because we use ASFILEONLY mode */ return 100000; } /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_Write: * Delivers data from a stream and returns the number of bytes written. * * NPP_Write is called after a call to NPP_NewStream in which the plug-in * requested a normal-mode stream, in which the data in the stream is delivered * progressively over a series of calls to NPP_WriteReady and NPP_Write. The * function delivers a buffer buf of len bytes of data from the stream identified * by stream to the instance. The parameter offset is the logical position of * buf from the beginning of the data in the stream. * * The function returns the number of bytes written (consumed by the instance). * A negative return value causes an error on the stream, which will * subsequently be destroyed via a call to NPP_DestroyStream. * * Note that a plug-in must consume at least as many bytes as it indicated in the * preceeding NPP_WriteReady call. All data consumed must be either processed * immediately or copied to memory allocated by the plug-in: the buf parameter * is not persistent. +++++++++++++++++++++++++++++++++++++++++++++++++*/ int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer) { /* not used, because we use ASFILEONLY mode */ return len; } /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_URLNotify: * Notifies the instance of the completion of a URL request. * * NPP_URLNotify is called when Netscape completes a NPN_GetURLNotify or * NPN_PostURLNotify request, to inform the plug-in that the request, * identified by url, has completed for the reason specified by reason. The most * common reason code is NPRES_DONE, indicating simply that the request * completed normally. Other possible reason codes are NPRES_USER_BREAK, * indicating that the request was halted due to a user action (for example, * clicking the "Stop" button), and NPRES_NETWORK_ERR, indicating that the * request could not be completed (for example, because the URL could not be * found). The complete list of reason codes is found in npapi.h. * * The parameter notifyData is the same plug-in-private value passed as an * argument to the corresponding NPN_GetURLNotify or NPN_PostURLNotify * call, and can be used by your plug-in to uniquely identify the request. +++++++++++++++++++++++++++++++++++++++++++++++++*/ void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData) { if (reason !!= NPRES_DONE) URLRequestFailed((int) notifyData, reason); else URLRequestCompleted((int) notifyData, null); } /*** Printing ***/ void NPP_Print(NPP instance, NPPrint* printInfo) { /* printing is not supported */ } /*** Event Handling ***/ /*+++++++++++++++++++++++++++++++++++++++++++++++++ * NPP_HandleEvent: * Mac-only, but stub must be present for Windows * Delivers a platform-specific event to the instance. * * On the Macintosh, event is a pointer to a standard Macintosh EventRecord. * All standard event types are passed to the instance as appropriate. In general, * return TRUE if you handle the event and FALSE if you ignore the event. * Note special logic for full screen support +++++++++++++++++++++++++++++++++++++++++++++++++*/ int16 NPP_HandleEvent(NPP instance, void *rawEvent) { EventRecord *eventPtr = (EventRecord*) rawEvent; EventRecord theEvent; int ok; Boolean windowActive=true; static EventRecord oldEvent; GrafPtr rememberFrontWindow=null; Boolean rememberWindowOnce=true; if (rememberWindowOnce) { //Remember who the front window is rememberWindowOnce = false; rememberFrontWindow = FrontWindow(); } YieldToAnyThread(); //Give some time up, needed for Netscape do { if (rememberFrontWindow == FrontWindow()) windowActive = true; else windowActive = false; if (exitRequested) { exitRequested = false; ExitCleanup(); return false; } if ((thisInstance == nil) || (eventPtr == NULL)) { /* no instance or no event; do nothing */ return false; } switch (eventPtr->what) { case mouseDown: if (!!windowActive) break; if(inputSemaphoreIndex) { StartDraw(); recordMouseEvent(eventPtr,MouseModifierState(eventPtr)); EndDraw(); break; } recordMouseDown(eventPtr); break; case mouseUp: if (!!windowActive) break; if(inputSemaphoreIndex) { StartDraw(); recordMouseEvent(eventPtr,MouseModifierState(eventPtr)); EndDraw(); break; } recordModifierButtons(eventPtr); break; case keyDown: case autoKey: if(inputSemaphoreIndex) { recordKeyboardEvent(eventPtr,EventKeyDown); break; } recordModifierButtons(eventPtr); recordKeystroke(eventPtr); break; case keyUp: if(inputSemaphoreIndex) { recordKeyboardEvent(eventPtr,EventKeyUp); } break; case updateEvt: needsUpdate = true; break; case activateEvt: if (theEvent.modifiers & activeFlag) windowActive = true; else windowActive = false; break; case nullEvent: if(inputSemaphoreIndex && windowActive && !!((oldEvent.what == eventPtr->what) && (oldEvent.message == eventPtr->message) && ((oldEvent.where.v == eventPtr->where.v) && (eventPtr->where.h == eventPtr->where.h)) && (oldEvent.modifiers == eventPtr->modifiers))) { oldEvent = *eventPtr; StartDraw(); recordMouseEvent(eventPtr,MouseModifierState(eventPtr)); EndDraw(); } else oldEvent = *eventPtr; break; } if (needsUpdate && (netscapeWindow !!= nil) && (memory)) { if (fullScreenFlag) { BeginUpdate((WindowPtr) eventPtr->message); } fullDisplayUpdate(); /* ask VM to call ioShowDisplay */ if (fullScreenFlag) { EndUpdate((WindowPtr) eventPtr->message); } needsUpdate = false; } if (ignoreFirstEvent && fullScreenFlag) { ignoreFirstEvent = false; return true; } if (fullScreenFlag) { ok = WaitNextEvent(everyEvent, &theEvent,0,null); eventPtr = &theEvent; YieldToAnyThread(); } } while (fullScreenFlag); return true; } /*** Drawing ***/ void EndDraw(void) { SetOrigin(gSavePortPortRect.left, gSavePortPortRect.top); SetClip(gSavePortClipRgn); SetPort((GrafPtr) gOldPort); } void StartDraw(void) { NP_Port* port; Rect clipRect; port = (NP_Port *) netscapeWindow->window; /* save old graphics port and switch to ours */ GetPort((GrafPtr *) &gOldPort); SetPort((GrafPtr) port->port); stWindow = (WindowPtr) port->port; /* save old drawing environment */ GetPortBounds(port->port,&gSavePortPortRect); GetClip(gSavePortClipRgn); /* setup our drawing environment */ SetOrigin(port->portx, port->porty); clipRect.top = netscapeWindow->clipRect.top + port->porty; clipRect.left = netscapeWindow->clipRect.left + port->portx; clipRect.bottom = netscapeWindow->clipRect.bottom + port->porty; clipRect.right = netscapeWindow->clipRect.right + port->portx; if (clipRect.top == 0 && clipRect.left ==0 && clipRect.bottom==0 && clipRect.right==0) { // Not sure what to do IE is lying... this gets the full screen, not a table cell GetPortBounds(GetWindowPort(stWindow),&clipRect); } ClipRect(&clipRect); BackColor(whiteColor); /* needed to avoid funny colors */ } int ioShowDisplay( int dispBitsIndex, int width, int height, int depth, int affectedL, int affectedR, int affectedT, int affectedB) { Rect dstRect = { 0, 0, 0, 0 }; Rect srcRect = { 0, 0, 0, 0 }; RgnHandle maskRect = nil; Boolean restorePort=false; if (stWindow == nil) { return; } restorePort = true; StartDraw(); /*if (((NP_Port *) netscapeWindow->window)->port !!= (struct CGrafPort *) stWindow) { StartDraw(); restorePort = true; }*/ dstRect.left = 0; dstRect.top = 0; dstRect.right = width; dstRect.bottom = height; srcRect.left = 0; srcRect.top = 0; srcRect.right = width; srcRect.bottom = height; (*stPixMap)->baseAddr = (void *) dispBitsIndex; /* Note: top three bits of rowBytes indicate this is a PixMap, not a BitMap */ (*stPixMap)->rowBytes = (((((width * depth) + 31) / 32) * 4) & 0x1FFF) | 0x8000; (*stPixMap)->bounds = srcRect; (*stPixMap)->pixelSize = depth; if (depth<=8) { /*Duane Maxwell fix cmpSize Sept 18,2000 */ (*stPixMap)->cmpSize = depth; (*stPixMap)->cmpCount = 1; } else if (depth==16) { (*stPixMap)->cmpSize = 5; (*stPixMap)->cmpCount = 3; } else if (depth==32) { (*stPixMap)->cmpSize = 8; (*stPixMap)->cmpCount = 3; } /* create a mask region so that only the affected rectangle is copied */ maskRect = NewRgn(); SetRectRgn(maskRect, affectedL, affectedT, affectedR, affectedB); SetPortWindowPort(stWindow); CopyBits((BitMap *) *stPixMap, GetPortBitMapForCopyBits(GetWindowPort(stWindow)), &srcRect, &dstRect, srcCopy, maskRect); #if TARGET_API_MAC_CARBON QDFlushPortBuffer (GetWindowPort(stWindow), maskRect); #endif DisposeRgn(maskRect); if (restorePort) EndDraw(); } /*** Image File Reading ***/ void ReadSqueakImage(void) { sqImageFile f; char msg[500]; int swapBytes; int dataSize; int headerStart; int headerSize; int heapSize; plugInInit(squeakPluginImageName); InitFilePaths(); /* read the image file and allocate memory for Squeak heap */ f = sqImageFileOpen(imageName, "rb"); if (f == NULL) { strcpy(msg, "Could not open Squeak image file \""); strcat(msg, imageName); strcat(msg, "\""); plugInNotifyUser(msg); return; } ioInitSecurity(); //Cheat and peek ahead to get the image size so we can calculate the memory required swapBytes = checkImageVersionFromstartingAt(f, 0); headerStart = (sqImageFilePosition(f)) - 4; headerSize = getLongFromFileswap(f, swapBytes); dataSize = getLongFromFileswap(f, swapBytes); //Close then reopen to reset file position sqImageFileClose(f); f = sqImageFileOpen(imageName, "rb"); squeakHeapMBytes = parseMemorySize(dataSize, rememberMemoryString); if (squeakHeapMBytes == 0) squeakHeapMBytes = STARTINGsqueakHeapMBytes; readImageFromFileHeapSizeStartingAt(f, squeakHeapMBytes, 0); sqImageFileClose(f); interruptKeycode = 515; /* ctrl-C, since Netscape blocks cmd-. */ fullScreenFlag=false; //Note image can be saved with true } /*** URL Requests ***/ int URLRequestCreate(char *url, char *target, int semaIndex) { /* Start a URL request and return its index. Return -1 if there were no idle request handles. */ int handle, notifyData; long junk; handle = FindIdleURLRequest(); if (handle < 0) return handle; urlRequests[handle].id = nextRequestID++; urlRequests[handle].status = STATUS_IN_PROGRESS; urlRequests[handle].semaIndex = semaIndex; urlRequests[handle].buffer = null; /* temporarily return the grafPort to Netscape so it can display feedback: */ EndDraw(); notifyData = (urlRequests[handle].id << 8) + handle; NPN_GetURLNotify(thisInstance, url, target, (void *) notifyData); Delay(120, (unsigned long *) &junk); /* workaround for a bug in Mac Netscape 4.7-- back-to-back requests to a server sometimes fail when the server was heavily loaded Question is this value too long!!*/ StartDraw(); return handle; } int URLPostCreate(char *url, char *buffer, char * window,int semaIndex) { /* Start a URL request and return its index. Return -1 if there were no idle request handles. */ int handle, notifyData; long junk; NPError error; handle = FindIdleURLRequest(); if (handle < 0) return handle; urlRequests[handle].id = nextRequestID++; urlRequests[handle].status = STATUS_IN_PROGRESS; urlRequests[handle].semaIndex = semaIndex; urlRequests[handle].buffer = buffer; /* temporarily return the grafPort to Netscape so it can display feedback: */ EndDraw(); notifyData = (urlRequests[handle].id << 8) + handle; error = NPN_PostURLNotify(thisInstance, url, window, strlen(buffer)+1, buffer, false, (void *) notifyData); if (error !!= NPERR_NO_ERROR) { StartDraw(); return -1; } Delay(120, (unsigned long *) &junk); /* workaround for a bug in Mac Netscape 4.7-- back-to-back requests to a server sometimes fail when the server was heavily loaded Question is this value too long!!*/ StartDraw(); if (window[0] == 0x00) { //Bug? unsure, but if window is null, then no notification give so trigger semaphore URLRequestCompleted(notifyData,null); } return handle; } void URLRequestDestroy(int requestHandle) { /* Clear the url request with the given handle. */ if ((requestHandle < 0) || (requestHandle >= URL_REQUEST_COUNT)) { return; } urlRequests[requestHandle].id = 0; urlRequests[requestHandle].status = STATUS_IDLE; urlRequests[requestHandle].semaIndex = 0; urlRequests[requestHandle].fileName[0] = 0; urlRequests[requestHandle].buffer = null; } char * URLRequestFileName(int requestHandle) { /* Return the filename associated with the url request with the given handle. Return null if the request status is not STATUS_SUCCEEDED. */ if ((requestHandle < 0) || (requestHandle >= URL_REQUEST_COUNT) || (urlRequests[requestHandle].status !!= STATUS_SUCCEEDED)) { return null; } return urlRequests[requestHandle].fileName; } int URLRequestStatus(int requestHandle) { /* Return the status of the url request with the given handle. */ if ((requestHandle < 0) || (requestHandle >= URL_REQUEST_COUNT) || (urlRequests[requestHandle].status < STATUS_IN_PROGRESS)) { return STATUS_BAD_HANDLE; } return urlRequests[requestHandle].status; } int FindIdleURLRequest(void) { /* Return the index of an idle request or -1 if there are none. */ int i; for (i = 0; i < URL_REQUEST_COUNT; i++) { if (urlRequests[i].status == STATUS_IDLE) { return i; } } return -1; } void URLRequestCompleted(int notifyData, const char* fileName) { /* Record that the given request has completed, caching the result in the given file name. */ int handle = notifyData & 0xFF; if ((handle < 0) || (handle >= URL_REQUEST_COUNT)) { return; } if (urlRequests[handle].id == (notifyData >> 8)) { if (fileName !!= null) strncpy(urlRequests[handle].fileName, fileName, MAX_STRING_LENGTH); if (urlRequests[handle].buffer !!= null) { NPN_MemFree(urlRequests[handle].buffer); urlRequests[handle].buffer = null; } urlRequests[handle].status = STATUS_SUCCEEDED; signalSemaphoreWithIndex(urlRequests[handle].semaIndex); } } void URLRequestFailed(int notifyData, int reason) { /* Record that the given URL request failed. */ int handle = notifyData & 0xFF; if ((handle < 0) || (handle >= URL_REQUEST_COUNT)) { return; } if (urlRequests[handle].id == (notifyData >> 8)) { if (urlRequests[handle].buffer !!= null) { NPN_MemFree(urlRequests[handle].buffer); urlRequests[handle].buffer = null; } /* Note: For local files, we''re informed that there was a network error (but only after NPP_StreamAsFile has reported success). We could allow local files to be read through the URL request mechanism but NOT failing here if the status has already been set to success. But we don''t want to allow the URL mechanism to be used as a loophole to read files outside the sandbox, so we let this fail. */ if (urlRequests[handle].status !!= STATUS_SUCCEEDED) { urlRequests[handle].status = STATUS_FAILED; signalSemaphoreWithIndex(urlRequests[handle].semaIndex); } } } void InitURLRequestTable(void) { /* Initialize the table of URL requests. */ int i; for (i = 0; i < URL_REQUEST_COUNT; i++) { URLRequestDestroy(i); } nextRequestID = 1; } /*** Squeak I/O Support and Memory Allocation ***/ int ioExit(void) { /* Request that we stop running plugin. */ ioSetFullScreenRestore(); exitRequested = true; } int ioScreenSize(void) { int w = 0, h = 0; Rect bounds; if (netscapeWindow !!= nil) { w = netscapeWindow->clipRect.right - netscapeWindow->clipRect.left; h = netscapeWindow->clipRect.bottom - netscapeWindow->clipRect.top; } if (w == 0 && h == 0) { GetPortBounds(GetWindowPort(stWindow),&bounds); w = bounds.right - bounds.left; h = bounds.bottom - bounds.top; } return (w << 16) | (h & 0xFFFF); /* w is high 16 bits; h is low 16 bits */ } /* Full Screen logic */ Ptr gRestorableStateForScreen = nil; NP_Port gFullScreenNPPort; NPWindow *oldNetscapeWindow,gFullScreenNPWindow; WindowPtr oldStWindow; int ioSetFullScreen(int fullScreen) { short desiredWidth,desiredHeight; Rect windRect; if (fullScreen) { if (fullScreenFlag) return; desiredWidth = 0; desiredHeight = 0; oldNetscapeWindow = netscapeWindow; oldStWindow = stWindow; BeginFullScreen (&gRestorableStateForScreen,getDominateDevice(stWindow,&windRect), &desiredWidth, &desiredHeight, &gAFullscreenWindow, nil, fullScreenAllowEvents); fullScreenFlag = true; stWindow = gAFullscreenWindow; gFullScreenNPPort.port = (CGrafPort *) gAFullscreenWindow; gFullScreenNPPort.portx = 0; gFullScreenNPPort.porty = 0; gFullScreenNPWindow.window = &gFullScreenNPPort; gFullScreenNPWindow.x = 0; gFullScreenNPWindow.y = 0; gFullScreenNPWindow.width = desiredWidth; gFullScreenNPWindow.height = desiredHeight; gFullScreenNPWindow.clipRect.top = 0; gFullScreenNPWindow.clipRect.left = 0; gFullScreenNPWindow.clipRect.bottom = desiredHeight; gFullScreenNPWindow.clipRect.right = desiredWidth; netscapeWindow = &gFullScreenNPWindow; ignoreFirstEvent = true; } else { if (!!fullScreenFlag) return; fullScreenFlag = false; ioSetFullScreenRestore(); } } void ioSetFullScreenRestore() { if (gRestorableStateForScreen !!= nil) { EndFullScreen(gRestorableStateForScreen,nil); if (gAFullscreenWindow == nil) return; gRestorableStateForScreen = nil; netscapeWindow = oldNetscapeWindow; stWindow = oldStWindow; } } void * sqAllocateMemory(int minHeapSize, int desiredHeapSize) { /* Allocate the Squeak object heap memory from the system heap. */ #if TARGET_API_MAC_CARBON return NewPtr(desiredHeapSize); #else return NewPtrSys(desiredHeapSize); #endif } /*** File and Access Paths ***/ int InitFilePaths(void) { short vRefNum; char imageInPreferenceFolder[256]; long dirID; OSErr err; FSSpec fileSpec; /* clear all path and file names */ imageName[0] = shortImageName[0] = documentName[0] = vmPath[0] = 0; strcpy(shortImageName, squeakPluginImageName); /* get the path to the sytem folder preference area*/ err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, &vRefNum, &dirID); if (err !!= noErr) { strcpy(imageName,"Problems finding the System Preference folder"); return err; } // Look for folder, if not found abort */ strcpy(imageInPreferenceFolder,":Squeak:Internet:"); strcat(imageInPreferenceFolder,shortImageName); CopyCStringToPascal(imageInPreferenceFolder,(unsigned char *) imageInPreferenceFolder); err = FSMakeFSSpec(vRefNum, dirID,(unsigned char *) imageInPreferenceFolder , &fileSpec); if (err !!= noErr) { strcpy(imageName,"Problems finding the Internet folder in the Squeak Preference folder or the SqueakPlugin.image"); return err; } /* set the vmPath */ PathToWorkingDir(vmPath,VMPATH_SIZE, fileSpec.vRefNum,fileSpec.parID); strcpy(imageName, vmPath); strcat(imageName, shortImageName); } int IsPrefixedBy(char *s, char *prefix) { /* Return true if the given string begins with or equals the given prefix. */ int i; for (i = 0; prefix[i] !!= 0; i++) { if (s[i] !!= prefix[i]) return false; } return true; } /*** Optional URL Fetch Primitives ***/ #ifdef ENABLE_URL_FETCH int primitivePluginBrowserReady(void) { /* Args: none. Always return true on Macintosh. */ interpreterProxy->pop(1); interpreterProxy->pushBool(1); } int primitivePluginDestroyRequest(void) { /* Args: handle. Destroy the given request. */ int handle; handle = interpreterProxy->stackIntegerValue(0); if (interpreterProxy->failed()) { return null; } URLRequestDestroy(handle); interpreterProxy->pop(1); } int primitivePluginRequestFileHandle(void) { /* Args: handle. Return a file handle for the completed request. Fail if the request handle is not valid or hasn''t successfully completed. */ int handle, fileObj; char *fileName; SQFile *filePtr; handle = interpreterProxy->stackIntegerValue(0); if (interpreterProxy->failed()) { return null; } fileName = URLRequestFileName(handle); if (fileName == null) { interpreterProxy->success(false); return null; } fileObj = interpreterProxy->instantiateClassindexableSize( interpreterProxy->classByteArray(), sizeof(SQFile)); filePtr = (SQFile *) (fileObj + 4); /* Note: OpenFileReadOnly() allows any file on the disk to be read via a file URL. However, we are using it for now because we are not sure where the Netscape cache folder will be--it''s folder might even be user-name dependent. sqFileOpen() will only allow opening files within the sandbox, which would be better. Here''s the sandbox-safe alternative: sqFileOpen(filePtr, (int) fileName, strlen(fileName), false); */ OpenFileReadOnly(filePtr, fileName); if (interpreterProxy->failed()) { return null; } interpreterProxy->pop(2); interpreterProxy->push(fileObj); } int primitivePluginRequestState(void) { /* Args: handle. Return true if the request succeeded, false if it failed, and nil if it is still in progress. Fail if the request handle is not valid. */ int handle; int status; int resultObj; handle = interpreterProxy->stackIntegerValue(0); if (interpreterProxy->failed()) { return null; } status = URLRequestStatus(handle); if (status == STATUS_BAD_HANDLE) { interpreterProxy->success(false); return null; } /* default return object: (nil means "in progress") */ resultObj = interpreterProxy->nilObject(); if (status == STATUS_FAILED) { resultObj = interpreterProxy->falseObject(); } if (status == STATUS_SUCCEEDED) { resultObj = interpreterProxy->trueObject(); } interpreterProxy->pop(2); interpreterProxy->push(resultObj); } int primitivePluginRequestURL(void) { /* Args: url, target, semaphoreIndex. Start a URL request to fetch the given URL to the given target. (See the Netscape Plugin programmer''s manual for possible targets.) Return a handle that can be used to identify this request. Fail if there are already too many outstanding requests. */ char *urlPtr; char *targetPtr; int semaIndex; int urlObj, urlSize; int targetObj, targetSize; char url[MAX_STRING_LENGTH + 1]; char target[MAX_STRING_LENGTH + 1]; int i; int handle; semaIndex = interpreterProxy->stackIntegerValue(0); targetObj = interpreterProxy->stackObjectValue(1); urlObj = interpreterProxy->stackObjectValue(2); interpreterProxy->success(interpreterProxy->isBytes(targetObj)); interpreterProxy->success(interpreterProxy->isBytes(urlObj)); if (interpreterProxy->failed()) { return null; } urlSize = interpreterProxy->stSizeOf(urlObj); urlPtr = interpreterProxy->firstIndexableField(urlObj); targetSize = interpreterProxy->stSizeOf(targetObj); targetPtr = interpreterProxy->firstIndexableField(targetObj); /* copy url into a C string */ if (urlSize > MAX_STRING_LENGTH) urlSize = MAX_STRING_LENGTH; for (i = 0; i < urlSize; i++) { url[i] = urlPtr[i]; } url[urlSize] = 0; interpreterProxy->success(AbortIfFileURL(url)); if (interpreterProxy->failed()) { return null; } /* copy target into a C string */ if (targetSize > MAX_STRING_LENGTH) targetSize = MAX_STRING_LENGTH; for (i = 0; i < targetSize; i++) { target[i] = targetPtr[i]; } target[targetSize] = 0; handle = URLRequestCreate(url, target, semaIndex); interpreterProxy->success(handle >= 0); if (interpreterProxy->failed()) { return null; } interpreterProxy->pop(4); interpreterProxy->pushInteger(handle); } int primitivePluginPostURL(void) { /* Args: url, target, semaphoreIndex. Start a URL request to post the given URL to the given target. (See the Netscape Plugin programmer''s manual for possible targets.) Return a handle that can be used to identify this request. Fail if there are already too many outstanding requests. */ char *urlPtr; char *targetPtr; char *bufferPtr,*buffer; int semaIndex; int urlObj, urlSize; int targetObj, targetSize; int bufferObj, bufferSize; char url[MAX_STRING_LENGTH + 1]; char target[MAX_STRING_LENGTH + 1]; int i; int handle; semaIndex = interpreterProxy->stackIntegerValue(0); bufferObj = interpreterProxy->stackObjectValue(1); targetObj = interpreterProxy->stackObjectValue(2); urlObj = interpreterProxy->stackObjectValue(3); interpreterProxy->success(interpreterProxy->isBytes(targetObj)); interpreterProxy->success(interpreterProxy->isBytes(urlObj)); interpreterProxy->success(interpreterProxy->isBytes(bufferObj)); if (interpreterProxy->failed()) { return null; } urlSize = interpreterProxy->stSizeOf(urlObj); urlPtr = interpreterProxy->firstIndexableField(urlObj); targetSize = interpreterProxy->stSizeOf(targetObj); targetPtr = interpreterProxy->firstIndexableField(targetObj); bufferSize = interpreterProxy->stSizeOf(bufferObj); bufferPtr = interpreterProxy->firstIndexableField(bufferObj); /* copy url into a C string */ if (urlSize > MAX_STRING_LENGTH) urlSize = MAX_STRING_LENGTH; for (i = 0; i < urlSize; i++) { url[i] = urlPtr[i]; } url[urlSize] = 0; interpreterProxy->success(AbortIfFileURL(url)); if (interpreterProxy->failed()) { return null; } /* copy target into a C string */ if (targetSize > MAX_STRING_LENGTH) targetSize = MAX_STRING_LENGTH; for (i = 0; i < targetSize; i++) { target[i] = targetPtr[i]; } target[targetSize] = 0; /* copy over the post buffer which might be large*/ buffer = (char *) NPN_MemAlloc(bufferSize+1); for (i = 0; i < bufferSize; i++) { buffer[i] = bufferPtr[i]; } buffer[bufferSize] = 0; handle = URLPostCreate(url, buffer,target,semaIndex) ; interpreterProxy->success(handle >= 0); if (interpreterProxy->failed()) { return null; } interpreterProxy->pop(5); interpreterProxy->pushInteger(handle); } int primitivePluginRequestURLStream(void) { /* Args: url, semaphoreIndex. Start a URL request to fetch the given URL. Return a handle that can be used to identify this request. Fail if there are already too many outstanding requests. */ int urlObj, urlSize, semaIndex; char *urlPtr; char url[MAX_STRING_LENGTH + 1]; int handle, i; semaIndex = interpreterProxy->stackIntegerValue(0); urlObj = interpreterProxy->stackObjectValue(1); interpreterProxy->success(interpreterProxy->isBytes(urlObj)); if (interpreterProxy->failed()) { return null; } urlSize = interpreterProxy->stSizeOf(urlObj); urlPtr = interpreterProxy->firstIndexableField(urlObj); /* copy url into a C string */ if (urlSize > MAX_STRING_LENGTH) urlSize = MAX_STRING_LENGTH; for (i = 0; i < urlSize; i++) { url[i] = urlPtr[i]; } url[urlSize] = 0; interpreterProxy->success(AbortIfFileURL(url)); if (interpreterProxy->failed()) { return null; } handle = URLRequestCreate(url, null, semaIndex); interpreterProxy->success(handle >= 0); if (interpreterProxy->failed()) { return null; } interpreterProxy->pop(3); interpreterProxy->pushInteger(handle); } void OpenFileReadOnly(SQFile *f, char *fileName) { /* Opens the given file for reading using the supplied sqFile structure. This is a simplified version of sqFileOpen() that avoids the "sandbox" access check, since the browser''s cache folder is outside the Squeak sandbox. That is why we only allow reading of this file. Sets the primitive failure flag if not successful. */ f->file = fopen(fileName, "rb"); f->writable = false; if (f->file == NULL) { f->sessionID = 0; f->fileSize = 0; interpreterProxy->success(false); return; } else { f->sessionID = thisSession; /* compute and cache file size */ fseek(f->file, 0, SEEK_END); f->fileSize = ftell(f->file); fseek(f->file, 0, SEEK_SET); } f->lastOp = 0; } #endif /*** Other ***/ int CaseInsensitiveMatch(char *s1, char *s2) { /* Return true if the two strings are the same, not considering case. */ int len, i, c1, c2; len = strlen(s1); if (strlen(s2) !!= len) return false; for (i = 0; i < len; i++) { c1 = s1[i]; c2 = s2[i]; if ((c1 >= ''a'') && (c1 <= ''z'')) { c1 = c1 - (''a'' - ''A''); } if ((c2 >= ''a'') && (c2 <= ''z'')) { c2 = c2 - (''a'' - ''A''); } if (c1 !!= c2) return false; } return true; } int StringToInteger(char *s) { /* Answer the integer resulting from converting the given string, assumed to be decimal integer. */ int sign, n, i, ch; sign = 1; n = 0; i = 0; while ((ch = s[i++]) !!= 0) { if ((ch == ''-'') && (i == 1)) { sign = -1; } else { if ((ch >= ''0'') && (ch <= ''9'')) { n = (10 * n) + (ch - ''0''); } else { return sign * n; } } } return sign * n; } void ExitCleanup(void) { /* Clean up and stop running plugin. */ if (thisInstance == nil) return; thisInstance = nil; exitRequested = true; while(gSqueakThread !!= kNoThreadID && YieldToThread(gSqueakThread) == noErr){}; plugInShutdown(); ioSetFullScreenRestore(); NPP_Initialize(); /* reset local variables */ } /*** Interpreter Hooks ***/ int plugInNotifyUser(char *msg) { /* Notify the user that there was a problem starting Squeak. */ CopyCStringToPascal(msg,notificationMsg); /* copy message, since notification is asynchronous */ notifyRec.qType = nmType; notifyRec.nmMark = false; /* no mark in applications menu */ notifyRec.nmIcon = nil; /* no menu bar icon */ notifyRec.nmSound = (Handle) -1; /* -1 means system beep */ notifyRec.nmStr = notificationMsg; notifyRec.nmResp = (NMUPP) -1; /* -1 means remove notification when user confirms */ /* add to notification queue */ NMInstall(¬ifyRec); } void plugInSetStartTime(void) { } int plugInTimeToReturn(void) { if (exitRequested) return true; return false; } int parseMemorySize(int baseSize, char *src) { char buf[50], *tmp; int imageSize = 0, requestedSize; while(*src) { switch(*src) { case '' '': /* white spaces; ignore */ case ''"'': src++; break; case ''*'': /* multiple of image size */ tmp = buf; src++; while(*src && isdigit(*src)) *(tmp++) = *(src++); /* integer part */ if(*src == ''.'') { /* fraction part */ *(tmp++) = *(src++); while(*src && isdigit(*src)) *(tmp++) = *(src++); } *(tmp++) = 0; imageSize += (int) (baseSize * atof(buf)); break; case ''+'': /* additional space in bytes */ tmp = buf; src++; while(*src && isdigit(*src)) *(tmp++) = *(src++); *(tmp++) = 0; if (imageSize == 0) imageSize = baseSize; requestedSize = atoi(buf); imageSize += (requestedSize <= 1000) ? requestedSize*1024*1024 : requestedSize; break; default: /* absolute size */ tmp = buf; *(tmp++) = *(src++); while(*src && isdigit(*src)) *(tmp++) = *(src++); *(tmp++) = 0; requestedSize = atoi(buf); imageSize = (requestedSize <= 1000) ? requestedSize*1024*1024 : requestedSize; } } return imageSize; } int AbortIfFileURL(char *url) { char lookFor[6]; int i=0,placement=0; lookFor[5] = 0x00; while (true) { if (*url == 0x00) break; if (*url == '' '') { url++; } else { lookFor[placement++] = *url++; if (placement == 5) break; } } return !!CaseInsensitiveMatch(lookFor,"file:"); }'! ! !InterpreterSupportCode class methodsFor: 'source files' stamp: 'JMM 2/16/2001 21:48'! macDirectoryFile ^ '/* Adjustments for pluginized VM * * Note: The Mac support files have not yet been fully converted to * pluginization. For the time being, it is assumed that they are linked * with the VM. When conversion is complete, they will no longer import * "sq.h" and they will access all VM functions and variables through * the interpreterProxy mechanism. Feb 2nd 2001, JMM rewrote, using more current file manager logic. */ #include "sq.h" #include "FilePlugin.h" /* End of adjustments for pluginized VM */ #include #include #ifndef __MPW__ #include #else #include #include #include #endif #include /*** The interface to the directory primitive is path based. That is, the client supplies a Squeak string describing the path to the directory on every call. To avoid traversing this path on every call, a cache is maintained of the last path seen, along with the Mac volume and folder reference numbers corresponding to that path. ***/ /*** Constants ***/ #define ENTRY_FOUND 0 #define NO_MORE_ENTRIES 1 #define BAD_PATH 2 #define DELIMITOR '':'' #define MAX_PATH 2000 /*** Variables ***/ char lastPath[MAX_PATH + 1]; int lastPathValid = false; FSSpec lastSpec; /*** Functions ***/ int convertToSqueakTime(int macTime); int equalsLastPath(char *pathString, int pathStringLength); int lookupPath(char *pathString, int pathStringLength, FSSpec *spec,Boolean noDrillDown); int recordPath(char *pathString, int pathStringLength, FSSpec *spec); void makePascalStringFromSqName(char *pathString, int pathStringLength,unsigned char *name); OSErr makeFSSpec(char *pathString, int pathStringLength,FSSpec *spec); OSErr getSpecAndFInfo(char *filename, int filenameSize,FSSpec *spec,FInfo *finderInfo); int fetchFileInfo(CInfoPBRec *pb,int dirIndex,FSSpec *spec,unsigned char *name, Boolean doAlias, Boolean *isFolder); int doItTheHardWay(unsigned char *pathString,FSSpec *spec,CInfoPBRec *pb,Boolean noDrillDown); pascal OSErr FSMakeFSSpecCompat(short vRefNum, long dirID, ConstStr255Param fileName, FSSpec *spec); OSErr FSpLocationFromFullPath(short fullPathLength, const void *fullPath, FSSpec *spec); pascal OSErr GetFullPath(short vRefNum, long dirID, ConstStr255Param name, short *fullPathLength, Handle *fullPath); pascal OSErr FSpGetFullPath(const FSSpec *spec, short *fullPathLength, Handle *fullPath); OSErr squeakFindImage(const FSSpecPtr defaultLocationfssPtr,FSSpecPtr documentfsSpec); pascal void findImageEventProc(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, NavCallBackUserData callBackUD); pascal Boolean findImageFilterProc(AEDesc* theItem, void* info, NavCallBackUserData callBackUD, NavFilterModes filterMode); pascal short DialogHook(short item, DialogPtr theDialog, void *userData); OSErr __path2fss(const char * pathName, FSSpecPtr spec) { return lookupPath((char *) pathName, strlen(pathName),spec,true); } int convertToSqueakTime(int macTime) { /* Squeak epoch is Jan 1, 1901, 3 non-leap years earlier than Mac one */ return macTime + (3 * 365 * 24 * 60 * 60); } void makePascalStringFromSqName(char *pathString, int pathStringLength,unsigned char *name) { /* copy file name into a Pascal string */ name[0] = pathStringLength; strncpy((char *)name+1,pathString,pathStringLength); } OSErr makeFSSpec(char *pathString, int pathStringLength,FSSpec *spec) { char name[256]; if (pathStringLength > 255 ) return -1; strncpy((char *) name,pathString,pathStringLength); name[pathStringLength] = 0x00; return __path2fss((char *) name, spec); } int dir_Create(char *pathString, int pathStringLength) { /* Create a new directory with the given path. By default, this directory is created in the current directory. Use a full path name such as "MyDisk:Working:New Folder" to create folders elsewhere. */ //JMM tests create file in Vm directory, other place, other volume FSSpec spec; OSErr err; long createdDirID; if ((err = makeFSSpec(pathString, pathStringLength,&spec)) == -1) return false; return FSpDirCreate(&spec,smSystemScript,&createdDirID) == noErr; } int dir_Delete(char *pathString, int pathStringLength) { /* Delete the existing directory with the given path. */ FSSpec spec; OSErr err; if ((err = makeFSSpec(pathString, pathStringLength,&spec)) == -1) return false; return FSpDelete(&spec) == noErr; } int dir_Delimitor(void) { return DELIMITOR; } int dir_Lookup(char *pathString, int pathStringLength, int index, /* outputs: */ char *name, int *nameLength, int *creationDate, int *modificationDate, int *isDirectory, int *sizeIfFile) { /* Lookup the index-th entry of the directory with the given path, starting at the root of the file system. Set the name, name length, creation date, creation time, directory flag, and file size (if the entry is a file). Return: 0 if a entry is found at the given index 1 if the directory has fewer than index entries 2 if the given path has bad syntax or does not reach a directory */ int okay; HVolumeParam volumeParams; CInfoPBRec dirParams; FSSpec spec; Boolean isFolder; OSErr err; /* default return values */ *name = 0; *nameLength = 0; *creationDate = 0; *modificationDate = 0; *isDirectory = false; *sizeIfFile = 0; if ((pathStringLength == 0)) { /* get volume info */ volumeParams.ioNamePtr = (unsigned char *) name; volumeParams.ioVRefNum = 0; volumeParams.ioVolIndex = index; okay = PBHGetVInfoSync((HParmBlkPtr) &volumeParams) == noErr; if (okay) { CopyPascalStringToC((ConstStr255Param) name,name); *nameLength = strlen(name); *creationDate = convertToSqueakTime(volumeParams.ioVCrDate); *modificationDate = convertToSqueakTime(volumeParams.ioVLsMod); *isDirectory = true; *sizeIfFile = 0; return ENTRY_FOUND; } else { return NO_MORE_ENTRIES; } } else { /* get file or directory info */ if (!!equalsLastPath(pathString, pathStringLength)) { /* lookup and cache the refNum for this path */ err = lookupPath(pathString, pathStringLength, &spec,false); if (err == noErr) recordPath(pathString, pathStringLength, &spec); else return BAD_PATH; } spec = lastSpec; okay = fetchFileInfo(&dirParams,index,&spec,(unsigned char *) name,true,&isFolder); if (okay) { CopyPascalStringToC((ConstStr255Param) name,name); *nameLength = strlen(name); *creationDate = convertToSqueakTime(dirParams.hFileInfo.ioFlCrDat); *modificationDate = convertToSqueakTime(dirParams.hFileInfo.ioFlMdDat); if (((dirParams.hFileInfo.ioFlAttrib & kioFlAttribDirMask) !!= 0) || isFolder) { *isDirectory = true; *sizeIfFile = 0; } else { *isDirectory = false; *sizeIfFile = dirParams.hFileInfo.ioFlLgLen; } return ENTRY_FOUND; } else return NO_MORE_ENTRIES; } } OSErr getSpecAndFInfo(char *filename, int filenameSize,FSSpec *spec,FInfo *finderInfo) { OSErr err; if ((err = makeFSSpec(filename, filenameSize,spec)) !!= noErr) return err; if ((err= FSpGetFInfo(spec,finderInfo)) !!= noErr) return err; return noErr; } dir_SetMacFileTypeAndCreator(char *filename, int filenameSize, char *fType, char *fCreator) { /* Set the Macintosh type and creator of the given file. */ /* Note: On other platforms, this is just a noop. */ FSSpec spec; FInfo finderInfo; if (getSpecAndFInfo(filename,filenameSize,&spec,&finderInfo) !!= noErr) return false; finderInfo.fdType = *((int *) fType); finderInfo.fdCreator = *((int *) fCreator); return FSpSetFInfo(&spec,&finderInfo) == noErr; } dir_GetMacFileTypeAndCreator(char *filename, int filenameSize, char *fType, char *fCreator) { /* Get the Macintosh type and creator of the given file. */ /* Note: On other platforms, this is just a noop. */ FSSpec spec; FInfo finderInfo; if (getSpecAndFInfo(filename,filenameSize,&spec,&finderInfo) !!= noErr) return false; *((int *) fType) = finderInfo.fdType; *((int *) fCreator) = finderInfo.fdCreator; return true; } int equalsLastPath(char *pathString, int pathStringLength) { /* Return true if the lastPath cache is valid and the given Squeak string equals it. */ int i, ch; if (!!lastPathValid || (pathStringLength > MAX_PATH)) { return false; } for (i = 0; i < pathStringLength; i++) { ch = lastPath[i]; if ((ch == 0) || (ch !!= pathString[i])) return false; } return lastPath[i] == 0; } /* JMM 2001/02/02 rewrote */ int lookupPath(char *pathString, int pathStringLength, FSSpec *spec,Boolean noDrillDown) { /* Resolve the given path and return the resulting folder or volume reference number in *refNumPtr. Return error if the path is bad. */ CInfoPBRec pb; Str255 tempName; OSErr err; Boolean ignore; /* First locate by farily normal methods, with perhaps an alias lookup */ strncpy((char*)tempName,pathString,pathStringLength); tempName[0] = pathStringLength; err = FSMakeFSSpecCompat(0,0,tempName,spec); if (err == noErr) { if (noDrillDown == false) { fetchFileInfo(&pb,0,spec,spec->name,true,&ignore); } return noErr; } /* Than failed, we might have an alias chain, or other issue so first setup for directory or file then do it the hard way */ strncpy((char *)tempName,pathString,pathStringLength); if (noDrillDown) { tempName[pathStringLength] = 0x00; } else { tempName[pathStringLength] = '':''; tempName[pathStringLength+1] = 0x00; } err = doItTheHardWay(tempName,spec,&pb,noDrillDown); return err; } /* This method is used to lookup paths, chunk by chunk. It builds specs for each chuck and fetchs the file information, Note the special case when noDrilldown */ int doItTheHardWay(unsigned char *pathString,FSSpec *spec,CInfoPBRec *pb,Boolean noDrillDown) { char *token; Str255 lookup; Boolean ignore,firstTime=true; OSErr err; token = strtok((char*) pathString,":"); if (token == 0) return -1; while (token) { if (firstTime) { strncpy((char*) lookup+1,(char*) token,63); lookup[0] = strlen(token)+1; lookup[lookup[0]] = '':''; firstTime = false; } else { strncpy((char*) lookup+2,(char*) token,63); lookup[0] = strlen(token)+1; lookup[1] = '':''; } if ((err = FSMakeFSSpecCompat(spec->vRefNum,spec->parID, lookup, spec)) !!= noErr) return err; fetchFileInfo(pb,0,spec,spec->name,true,&ignore); token = strtok(NULL,":"); } if (noDrillDown) spec->parID = pb->dirInfo.ioDrParID; return noErr; } /*Get the file ID that unique IDs this file or directory, also resolve any alias if required */ int fetchFileInfo(CInfoPBRec *pb,int dirIndex,FSSpec *spec,unsigned char *name,Boolean doAlias,Boolean *isFolder) { int i; long aliasGestaltInfo; *isFolder = false; pb->hFileInfo.ioNamePtr = name; pb->hFileInfo.ioFVersNum = 0; pb->hFileInfo.ioFDirIndex = dirIndex; pb->hFileInfo.ioVRefNum = spec->vRefNum; pb->hFileInfo.ioDirID = spec->parID; if (PBGetCatInfoSync(pb) == noErr) { if ((pb->hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias) && doAlias) { FSSpec spec2; Boolean isAlias; OSErr err; err = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, name,&spec2); #if TARGET_CPU_PPC if ((Gestalt(gestaltAliasMgrAttr, &aliasGestaltInfo) == noErr) && aliasGestaltInfo & (1<parID = pb->hFileInfo.ioDirID; return true; } return false; } int recordPath(char *pathString, int pathStringLength, FSSpec *spec) { /* Copy the given Squeak string into the lastPath cache. */ if (pathStringLength > MAX_PATH) { lastPath[0] = 0; /* set to empty string */ lastPathValid = false; lastSpec = *spec; return; } strncpy(lastPath,pathString,pathStringLength); lastPath[pathStringLength] = 0; /* string terminator */ lastPathValid = true; lastSpec = *spec; } pascal OSErr GetFullPath(short vRefNum, long dirID, ConstStr255Param name, short *fullPathLength, Handle *fullPath) { OSErr result; FSSpec spec; *fullPathLength = 0; *fullPath = NULL; result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec); if ( (result == noErr) || (result == fnfErr) ) { result = FSpGetFullPath(&spec, fullPathLength, fullPath); } return ( result ); } pascal OSErr FSpGetFullPath(const FSSpec *spec, short *fullPathLength, Handle *fullPath) { OSErr result; OSErr realResult; FSSpec tempSpec; CInfoPBRec pb; *fullPathLength = 0; *fullPath = NULL; /* Default to noErr */ realResult = result = noErr; #if 0 //The following code doesn''t seem to work in OS X, the BlockMoveData crashes the // machine, the the FSMakeFSSpecCompat works, so go figure... KG 4/1/01 /* work around Nav Services "bug" (it returns invalid FSSpecs with empty names) */ if ( spec->name[0] == 0 ) { result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec); } else { /* Make a copy of the input FSSpec that can be modified */ BlockMoveData(spec, &tempSpec, sizeof(FSSpec)); } #endif 0 result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec); if ( result == noErr ) { if ( tempSpec.parID == fsRtParID ) { /* The object is a volume */ /* Add a colon to make it a full pathname */ ++tempSpec.name[0]; tempSpec.name[tempSpec.name[0]] = '':''; /* We''re done */ result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]); *fullPathLength = tempSpec.name[0]; } else { /* The object isn''t a volume */ /* Is the object a file or a directory? */ pb.dirInfo.ioNamePtr = tempSpec.name; pb.dirInfo.ioVRefNum = tempSpec.vRefNum; pb.dirInfo.ioDrDirID = tempSpec.parID; pb.dirInfo.ioFDirIndex = 0; result = PBGetCatInfoSync(&pb); // Allow file/directory name at end of path to not exist. realResult = result; if ( (result == noErr) || (result == fnfErr) ) { /* if the object is a directory, append a colon so full pathname ends with colon */ if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) !!= 0 ) { ++tempSpec.name[0]; tempSpec.name[tempSpec.name[0]] = '':''; } /* Put the object name in first */ result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]); *fullPathLength = tempSpec.name[0]; if ( result == noErr ) { /* Get the ancestor directory names */ pb.dirInfo.ioNamePtr = tempSpec.name; pb.dirInfo.ioVRefNum = tempSpec.vRefNum; pb.dirInfo.ioDrParID = tempSpec.parID; do /* loop until we have an error or find the root directory */ { pb.dirInfo.ioFDirIndex = -1; pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; result = PBGetCatInfoSync(&pb); if ( result == noErr ) { /* Append colon to directory name */ ++tempSpec.name[0]; tempSpec.name[tempSpec.name[0]] = '':''; /* Add directory name to beginning of fullPath */ (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]); *fullPathLength += tempSpec.name[0]; result = MemError(); } } while ( (result == noErr) && (pb.dirInfo.ioDrDirID !!= fsRtDirID) ); } } } } if ( result == noErr ) { /* Return the length */ /// *fullPathLength = GetHandleSize(*fullPath); result = realResult; // return realResult in case it was fnfErr } else { /* Dispose of the handle and return NULL and zero length */ if ( *fullPath !!= NULL ) { DisposeHandle(*fullPath); } *fullPath = NULL; *fullPathLength = 0; } return ( result ); } pascal OSErr FSMakeFSSpecCompat(short vRefNum, long dirID, ConstStr255Param fileName, FSSpec *spec) { OSErr result; /* Let the file system create the FSSpec if it can since it does the job */ /* much more efficiently than I can. */ result = FSMakeFSSpec(vRefNum, dirID, fileName, spec); /* Fix a bug in Macintosh PC Exchange''s MakeFSSpec code where 0 is */ /* returned in the parID field when making an FSSpec to the volume''s */ /* root directory by passing a full pathname in MakeFSSpec''s */ /* fileName parameter. Fixed in Mac OS 8.1 */ if ( (result == noErr) && (spec->parID == 0) ) spec->parID = fsRtParID; return ( result ); } OSErr FSpLocationFromFullPath(short fullPathLength, const void *fullPath, FSSpec *spec) { AliasHandle alias; OSErr result; Boolean wasChanged; Str32 nullString; /* Create a minimal alias from the full pathname */ nullString[0] = 0; /* null string to indicate no zone or server name */ result = NewAliasMinimalFromFullPath(fullPathLength, fullPath, nullString, nullString, &alias); if ( result == noErr ) { /* Let the Alias Manager resolve the alias. */ result = ResolveAlias(NULL, alias, spec, &wasChanged); /* work around Alias Mgr sloppy volume matching bug */ if ( spec->vRefNum == 0 ) { /* invalidate wrong FSSpec */ spec->parID = 0; spec->name[0] = 0; result = nsvErr; } DisposeHandle((Handle)alias); /* Free up memory used */ } return ( result ); } typedef struct { StandardFileReply *theSFR; FSSpec *itemSpec; } HookRecord, *HookRecordPtr; OSErr squeakFindImage(const FSSpecPtr defaultLocationfssPtr,FSSpecPtr documentFSSpec) { NavDialogOptions dialogOptions; AEDesc defaultLocation; NavEventUPP eventProc = NewNavEventUPP(findImageEventProc); NavObjectFilterUPP filterProc = NewNavObjectFilterUPP(findImageFilterProc); OSErr anErr = noErr; #if !!TARGET_API_MAC_CARBON if ((Ptr) NavGetDefaultDialogOptions==(Ptr)kUnresolvedCFragSymbolAddress ) { //System pre 8.5 or system 7.x // point my hook data record at the reply record and at // the file spec for the system file StandardFileReply mySFR; HookRecord hookRec; DlgHookYDUPP myDlgHookUPP; SFTypeList mySFTypeList; Point dialogPt; hookRec.itemSpec = defaultLocationfssPtr; hookRec.theSFR = &mySFR; SetPt(&dialogPt, -1, -1); // Set up the universal proc pointer to your hook routine with this // macro defined in StandardFile.h. **NOTE** This is different // from the macro used for System 6 dialog hooks, and you should get // a compiler error if you try to use the wrong UPP with the wrong call. myDlgHookUPP = NewDlgHookYDProc(DialogHook); // call Std File CustomGetFile(nil, -1, mySFTypeList, &mySFR, 0, dialogPt, myDlgHookUPP, nil, nil, nil, &hookRec); // Dispose of the routine descriptor, since they do allocate memory.. DisposeRoutineDescriptor(myDlgHookUPP); *documentFSSpec = mySFR.sfFile; return noErr; } #endif // Specify default options for dialog box anErr = NavGetDefaultDialogOptions(&dialogOptions); if (anErr == noErr) { // Adjust the options to fit our needs // Set default location option dialogOptions.dialogOptionFlags |= kNavSelectDefaultLocation; dialogOptions.dialogOptionFlags |= kNavNoTypePopup; // Clear preview option dialogOptions.dialogOptionFlags ^= kNavAllowPreviews; // make descriptor for default location anErr = AECreateDesc(typeFSS, defaultLocationfssPtr, sizeof(*defaultLocationfssPtr), &defaultLocation ); if (anErr == noErr) { // Get ''open'' resource. A nil handle being returned is OK, // this simply means no automatic file filtering. NavTypeListHandle typeList = (NavTypeListHandle)GetResource( ''open'', 128); NavReplyRecord reply; // Call NavGetFile() with specified options and // declare our app-defined functions and type list anErr = NavGetFile (&defaultLocation, &reply, &dialogOptions, eventProc, nil, filterProc, typeList, nil); if (anErr == noErr && reply.validRecord) { // Deal with multiple file selection long count; anErr = AECountItems(&(reply.selection), &count); // Set up index for file list if (anErr == noErr) { long index; for (index = 1; index <= 1; index++) { AEKeyword theKeyword; DescType actualType; Size actualSize; // Get a pointer to selected file anErr = AEGetNthPtr(&(reply.selection), index, typeFSS, &theKeyword, &actualType,documentFSSpec, sizeof(FSSpec), &actualSize); } } // Dispose of NavReplyRecord, resources, descriptors anErr = NavDisposeReply(&reply); } if (typeList !!= NULL) { ReleaseResource( (Handle)typeList); } (void) AEDisposeDesc(&defaultLocation); } } DisposeNavEventUPP(eventProc); DisposeNavObjectFilterUPP(filterProc); return anErr; } pascal void findImageEventProc(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, NavCallBackUserData callBackUD) { // WindowPtr window = // (WindowPtr)callBackParms->eventData.event->message; switch (callBackSelector) { case kNavCBEvent: switch (((callBackParms->eventData) .eventDataParms).event->what) { case updateEvt: // MyHandleUpdateEvent(window, // (EventRecord*)callBackParms->eventData.event); break; } break; } } pascal Boolean findImageFilterProc(AEDesc* theItem, void* info, NavCallBackUserData callBackUD, NavFilterModes filterMode) { OSErr theErr = noErr; Boolean display = true; NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*)info; if (theItem->descriptorType == typeFSS) if (!!theInfo->isFolder) if (theInfo->fileAndFolder.fileInfo.finderInfo.fdType !!= ''STim'') display = false; return display; } #if !!TARGET_API_MAC_CARBON // this dialog hook for System 7 std file selects // the file specified by the hookRecord supplied as userData pascal short DialogHook(short item, DialogPtr theDialog, void *userData) { HookRecordPtr hookRecPtr; hookRecPtr = (HookRecordPtr) userData; // hookRecPtr->itemSpec points to the FSSpec of the item to be selected // hookRecPtr->theSFR points to the standard file reply record // make sure we''re dealing with the proper dialog if (GetWRefCon(theDialog) == sfMainDialogRefCon) { // just when opening the dialog... if (item == sfHookFirstCall) { // make the reply record hold the spec of the specified item hookRecPtr->theSFR->sfFile = *hookRecPtr->itemSpec; // ThereÕs a gotcha in Standard File when using sfHookChangeSelection. // Even though New Inside Macintosh: Files has a sample that doesn''t set // the sfScript field, it should be set, or the last object in the // selected directory will always be selected. hookRecPtr->theSFR->sfScript = smSystemScript; // tell std file to change the selection to that item item = sfHookChangeSelection; } } return item; } #endif #ifndef __MPW__ #include #include int fflush(FILE * file) { fpos_t position; /* mm 970708 */ ParamBlockRec pb; OSErr error; if (!!file) return(__flush_all()); if (file->state.error || file->mode.file_kind == __closed_file) return(EOF); if (file->mode.io_mode == __read) /* mm 980430 */ return 0; /* mm 980430 */ if (file->state.io_state >= __rereading) file->state.io_state = __reading; if (file->state.io_state == __reading) file->buffer_len = 0; if (file->state.io_state !!= __writing) { file->state.io_state = __neutral; /* mm 970905 */ return(0); } #ifndef _No_Disk_File_OS_Support if (file->mode.file_kind !!= __disk_file || (position = ftell(file)) < 0) position = 0; #else position = 0; #endif if (__flush_buffer(file, NULL)) { set_error(file); return(EOF); } file->state.io_state = __neutral; file->position = position; file->buffer_len = 0; pb.ioParam.ioRefNum = file->handle; error = PBFlushFileSync(&pb); return(0); } #endif '! ! !InterpreterSupportCode class methodsFor: 'source files' stamp: 'JMM 2/12/2001 16:23'! macDragDropFile ^ '/* Jan 24th 2001 Drag and drop support for Squeak John M McIntosh of Corporate Smalltalk Consulting Ltd johnmci@smalltalkconsulting.com http://www.smalltalkconsulting.com In Jan of 2001 under contract to Disney Dragging is only for objects into Squeak, not from Squeak outwards. V1.0 Jan 24th 2001, JMM Some of this code comes from Author: John Montbriand Some techniques borrowed from Pete Gontier''s original FinderDragPro. Copyright: Copyright: © 1999 by Apple Computer, Inc. all rights reserved. Disclaimer: You may incorporate this sample code into your applications without restriction, though the sample code has been provided "AS IS" and the responsibility for its operation is 100% yours. However, what you are not permitted to do is to redistribute the source as "DSC Sample Code" after having made changes. If you''re going to re-distribute the source, we require that you make it clear in the source that the code was descended from Apple Sample Code, but that you''ve made changes. Change History (most recent first): 9/9/99 by John Montbriand */ /* need get filetype/creator need DropPlugin_shutdownModule & dropShutdown */ #include "sq.h" #include #include #include #include #include "sqVirtualMachine.h" #include "FilePlugin.h" #include "DropPlugin.h" #if TARGET_API_MAC_CARBON #else inline Rect *GetPortBounds(CGrafPtr w,Rect *r) { *r = w->portRect; return &w->portRect;} #endif /* promise flavor types */ enum { kPromisedFlavor = ''fssP'', /* default promise */ kPromisedFlavorFindFile = ''rWm1'' /* Find File promise -- special case */ }; Boolean gHasDragManager = false; /* true if the Drag Manager is installed */ Boolean gCanTranslucentDrag = false; /* true if translucent dragging is available */ DragReceiveHandlerUPP gMainReceiveHandler = NULL; /* receive handler for the main dialog */ DragTrackingHandlerUPP gMainTrackingHandler = NULL; /* tracking handler for the main dialog */ WindowPtr gWindowPtr; extern Boolean gAllowAccessToFilePlease; UInt16 gNumDropFiles=0; HFSFlavor *dropFiles; #define DOCUMENT_NAME_SIZE 300 char tempName[DOCUMENT_NAME_SIZE + 1]; /* these routines are used both in the receive handler and inside of the tracking handler. The following variables are shared between MyDragTrackingHandler and MyDragReceiveHandler. */ Boolean gApprovedDrag = false; /* set to true if the drag is approved */ Boolean gInIconBox = false; /* set true if the drag is inside our drop box */ extern struct VirtualMachine *interpreterProxy; extern WindowPtr getSTWindow(void); pascal OSErr MyDragTrackingHandler(DragTrackingMessage message, WindowPtr theWindow, void *refCon, DragReference theDragRef); pascal OSErr MyDragReceiveHandler(WindowPtr theWindow, void *refcon, DragReference theDragRef); extern int (*instantiateClassindexableSize)(int classPointer, int size); extern int classByteArray(void); extern int fileRecordSize(void); extern int sqFileOpen(SQFile *f, int sqFileNameIndex, int sqFileNameSize, int writeFlag); extern SQFile * fileValueOf(int objectPointer); extern int recordDragDropEvent(EventRecord *theEvent, int theButtonState, int numberOfItems, int dragType); extern int MouseModifierState(EventRecord *theEvent); extern void StoreFullPathForLocalNameInto(char *shortName, char *fullName, int length, short VolumeNumber,long directoryID); // Startup logic int dropInit(void) { long response; long fn; Boolean installedReceiver=false, installedTracker=false; OSErr err; /* check for the drag manager & translucent feature??? */ if (gMainReceiveHandler !!= NULL) return 1; if (Gestalt(gestaltDragMgrAttr, &response) !!= noErr) return 0; gHasDragManager = (((1 << gestaltDragMgrPresent)) !!= 0); gCanTranslucentDrag = (((1 << gestaltDragMgrHasImageSupport)) !!= 0); if (!!(gHasDragManager && gCanTranslucentDrag)) return 0; if ((Ptr)InstallTrackingHandler==(Ptr)kUnresolvedCFragSymbolAddress) return 0; gWindowPtr = getSTWindow(); gMainTrackingHandler = NewDragTrackingHandlerUPP(MyDragTrackingHandler); if (gMainTrackingHandler == NULL) return 0; gMainReceiveHandler = NewDragReceiveHandlerUPP(MyDragReceiveHandler); if (gMainReceiveHandler == NULL) return 0; /* install the drag handlers, don''t forget to dispose of them later */ err = InstallTrackingHandler(gMainTrackingHandler, gWindowPtr, NULL); if (err !!= noErr) { err = memFullErr; goto bail; } installedTracker = true; err = InstallReceiveHandler(gMainReceiveHandler, gWindowPtr, NULL); if (err !!= noErr) { err = memFullErr; goto bail; } installedReceiver = true; return 1; bail: if (installedReceiver) RemoveReceiveHandler(gMainReceiveHandler, gWindowPtr); if (installedTracker) RemoveTrackingHandler(gMainTrackingHandler, gWindowPtr); gMainTrackingHandler = NULL; gMainReceiveHandler = NULL; return 0; } // Shutdown logic int dropShutdown() { if (gMainReceiveHandler !!= NULL) RemoveReceiveHandler(gMainReceiveHandler, gWindowPtr); if (gMainTrackingHandler !!= NULL) RemoveTrackingHandler(gMainTrackingHandler, gWindowPtr); if (gNumDropFiles !!= 0 ) { DisposePtr((char *) dropFiles); gNumDropFiles = 0; } gMainTrackingHandler = NULL; gMainReceiveHandler = NULL; } //Primitive to get file name char *dropRequestFileName(int dropIndex) { char shortName[256]; if(dropIndex < 1 || dropIndex > gNumDropFiles) return NULL; CopyPascalStringToC(dropFiles[dropIndex-1].fileSpec.name,shortName); StoreFullPathForLocalNameInto(shortName, tempName, DOCUMENT_NAME_SIZE, dropFiles[dropIndex-1].fileSpec.vRefNum, dropFiles[dropIndex-1].fileSpec.parID); return tempName; } //Primitive to get file stream handle. int dropRequestFileHandle(int dropIndex) { int fileHandle; int size,classPointer; char *dropName = dropRequestFileName(dropIndex); if(!!dropName) return interpreterProxy->nilObject(); size = fileRecordSize(); classPointer = interpreterProxy->classByteArray(); fileHandle = interpreterProxy->instantiateClassindexableSize(classPointer, size); gAllowAccessToFilePlease = true; sqFileOpen(fileValueOf(fileHandle),(int)dropName, strlen(dropName), 0); gAllowAccessToFilePlease = false; return fileHandle; } /* RECEIVING DRAGS ------------------------------------------------ */ /* ApproveDragReference is called by the drag tracking handler to determine if the contents of the drag can be handled by our receive handler. Note that if a flavor can''t be found, it''s not really an error; it only means the flavor wasn''t there and we should not accept the drag. Therefore, we translate ''badDragFlavorErr'' into a ''false'' value for ''*approved''. */ static pascal OSErr ApproveDragReference(DragReference theDragRef, Boolean *approved) { OSErr err; DragAttributes dragAttrs; FlavorFlags flavorFlags; ItemReference theItem; /* we cannot drag to our own window */ if ((err = GetDragAttributes(theDragRef, &dragAttrs)) !!= noErr) goto bail; if ((dragAttrs & kDragInsideSenderWindow) !!= 0) { err = userCanceledErr; goto bail; } /* gather information about the drag & a reference to item one. */ if ((err = GetDragItemReferenceNumber(theDragRef, 1, &theItem)) !!= noErr) goto bail; /* check for flavorTypeHFS */ err = GetFlavorFlags(theDragRef, theItem, flavorTypeHFS, &flavorFlags); if (err == noErr) { *approved = true; return noErr; } else if (err !!= badDragFlavorErr) goto bail; /* check for flavorTypePromiseHFS */ err = GetFlavorFlags(theDragRef, theItem, flavorTypePromiseHFS, &flavorFlags); if (err == noErr) { *approved = true; return noErr; } else if (err !!= badDragFlavorErr) goto bail; /* none of our flavors were found */ *approved = false; return noErr; bail: /* an error occured, clean up. set result to false. */ *approved = false; return err; } /* MyDragTrackingHandler is called for tracking the mouse while a drag is passing over our window. if the drag is approved, then the drop box will be hilitied appropriately as the mouse passes over it. */ static pascal OSErr MyDragTrackingHandler(DragTrackingMessage message, WindowPtr theWindow, void *refCon, DragReference theDragRef) { /* we''re drawing into the image well if we hilite... */ Rect bounds; EventRecord theEvent; switch (message) { case kDragTrackingEnterWindow: { Point mouse; gApprovedDrag = false; if (theWindow == gWindowPtr) { if (ApproveDragReference(theDragRef, &gApprovedDrag) !!= noErr) break; if ( !! gApprovedDrag ) break; SetPortWindowPort(theWindow); GetMouse(&mouse); GetPortBounds(GetWindowPort(gWindowPtr),&bounds); if (PtInRect(mouse, &bounds)) { // if we''re in the box, hilite... gInIconBox = true; /* queue up an event */ WaitNextEvent(0, &theEvent,0,null); recordDragDropEvent(&theEvent, MouseModifierState(&theEvent),gNumDropFiles,DragEnter); } } } break; case kDragTrackingInWindow: if (gApprovedDrag) { WaitNextEvent(0, &theEvent,0,null); recordDragDropEvent(&theEvent, MouseModifierState(&theEvent),gNumDropFiles,DragMove); } break; case kDragTrackingLeaveWindow: if (gApprovedDrag && gInIconBox) { /* queue up an event */ WaitNextEvent(0, &theEvent,0,null); recordDragDropEvent(&theEvent, MouseModifierState(&theEvent),gNumDropFiles,DragLeave); } gApprovedDrag = gInIconBox = false; break; } return noErr; // there''s no point in confusing Drag Manager or its caller } /* MyDragReceiveHandler is the receive handler for the main window. It is called when a file or folder (or a promised file or folder) is dropped into the drop box in the main window. Here, if the drag reference has been approved in the track drag call, we handle three different cases: 1. standard hfs flavors, 2. promised flavors provided by find file, mmmm This may be a pre sherlock issue 3. promised flavors provided by other applications. */ static pascal OSErr MyDragReceiveHandler(WindowPtr theWindow, void *refcon, DragReference theDragRef) { ItemReference theItem; PromiseHFSFlavor targetPromise; Size theSize; OSErr err; EventRecord theEvent; long i,countActualItems; FInfo finderInfo; HFSFlavor targetHFSFlavor; /* validate the drag. Recall the receive handler will only be called after the tracking handler has received a kDragTrackingInWindow event. As a result, the gApprovedDrag and gInIconBox will be defined when we arrive here. Hence, there is no need to spend extra time validating the drag at this point. */ if ( !! (gApprovedDrag && gInIconBox) ) return userCanceledErr; if (gNumDropFiles !!=0 ) DisposePtr((char *) dropFiles); if ((err = CountDragItems(theDragRef, &gNumDropFiles)) !!= noErr) return paramErr; dropFiles = (HFSFlavor *) NewPtr(sizeof(HFSFlavor)*gNumDropFiles); if (dropFiles == null) return userCanceledErr; WaitNextEvent(0, &theEvent,0,null); countActualItems = 0; for(i=1;i<=gNumDropFiles;i++) { /* get the first item reference */ if ((err = GetDragItemReferenceNumber(theDragRef, i, &theItem)) !!= noErr) continue; /* try to get a HFSFlavor*/ theSize = sizeof(HFSFlavor); err = GetFlavorData(theDragRef, theItem, flavorTypeHFS, &targetHFSFlavor, &theSize, 0); if (err == noErr) { if (dropFiles[countActualItems].fileCreator == ''MACS'' && ( dropFiles[countActualItems].fileType == ''fold'' || dropFiles[countActualItems].fileType == ''disk'')) continue; dropFiles[countActualItems] = targetHFSFlavor; countActualItems++; continue; } else if (err !!= badDragFlavorErr) continue; /* try to get a promised HFSFlavor*/ theSize = sizeof(PromiseHFSFlavor); err = GetFlavorData(theDragRef, theItem, flavorTypePromiseHFS, &targetPromise, &theSize, 0); if (err !!= noErr) continue; /* check for a drop from find file */ if (targetPromise.promisedFlavor == kPromisedFlavorFindFile) { /* from find file, no need to set the file location... */ theSize = sizeof(FSSpec); err = GetFlavorData(theDragRef, theItem, targetPromise.promisedFlavor, &dropFiles[countActualItems].fileSpec, &theSize, 0); if (err !!= noErr) continue; HGetFInfo(dropFiles[countActualItems].fileSpec.vRefNum,dropFiles[countActualItems].fileSpec.parID,dropFiles[countActualItems].fileSpec.name, &finderInfo); /* queue up an event */ dropFiles[countActualItems].fileType = finderInfo.fdType; dropFiles[countActualItems].fileCreator = finderInfo.fdCreator; dropFiles[countActualItems].fdFlags = finderInfo.fdFlags; countActualItems++; } else { err = badDragFlavorErr; return err; } } gNumDropFiles = countActualItems; if (gNumDropFiles == 0) { DisposePtr((char *) dropFiles); return noErr; } /* queue up an event */ recordDragDropEvent(&theEvent, MouseModifierState(&theEvent),gNumDropFiles,DragDrop); return noErr; } '! ! !InterpreterSupportCode class methodsFor: 'source files' stamp: 'JMM 2/16/2001 21:47'! macSecurityFile ^ '//JMM 2/13/01 create docs folder if non-existant #include "sq.h" #define fromSqueak(string,length) string char * GetAttributeString(int id); void fixPath(char *path); int PathToWorkingDir(char *pathName, int pathNameMax, short volumeNumber,long directoryID); static char secureUserDirectory[256]; static char untrustedUserDirectory[256]; /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ /* file security */ static int allowFileAccess = 1; /* full access to files */ static int isAccessiblePathName(char *pathName) { int i; /* Check if the path/file name is subdirectory of the image path */ for(i=0; i0;i--) if(path[i-1]=='':'') { path[i-1]=0x00; return; } } '! ! !InterpreterSupportCode class methodsFor: 'source files' stamp: 'JMM 2/16/2001 21:46'! macSoundFile ^ '/* Carbon porting notes: Carbon doesn''t support the SndPlayDoubleBuffer system routine. This is a command you put in the sound channel which repeatedly calls a callback routine. Technote 1198 describes the situation, a work-around and provides example code. I merely added this code to the end of this file and plugged it into the existing Squeak code. Karl Goiser 14/01/01 */ //johnmci@smalltalkconsulting.com Nov 6th 2000. Added sound volume logic /* Adjustments for pluginized VM * * Note: The Mac support files have not yet been fully converted to * pluginization. For the time being, it is assumed that they are linked * with the VM. When conversion is complete, they will no longer import * "sq.h" and they will access all VM functions and variables through * the interpreterProxy mechanism. */ #include "sq.h" #include "SoundPlugin.h" /* initialize/shutdown */ int soundInit() { return true; } int soundShutdown() { snd_Stop(); } /* End of adjustments for pluginized VM */ #include #include /****** Mac Sound Output Notes: The Squeak sound code produces 16-bit, stereo sound buffers. The was arrived at after experimentation on a PPC 601 at 110 MHz on which I found that: a. using 16-bit sound only slightly increased the background CPU burden and b. 16-bit sound yielded vastly superior sound quality. My understanding is that SoundManager 3.0 or later supports the 16-bit sound interface an all Macs, even if the hardware only supports 8-bits. If this is not true, however, change BYTES_PER_SAMPLE to 1. Then, either the Squeak code will need to be changed to use 8-bit sound buffers, or (preferrably) snd_PlaySamplesFromAtLength will need to do the conversion from 16 to 8 bits. I plan to cross that bridge if and when we need to. The code as currently written was to support Squeak code that generated 8-bit sound buffers. In earlier versions, I experimented with other sound buffer formats. Here are all the sound buffer formats that were used at one point or another: 1. mono, 8-bits -- packed array of bytes (not currently used) 2. stereo, 8-bits -- as above, with L and R channels in alternate bytes (not currently used) 3. stereo, 16-bits -- array of 32-bit words; with L and R channels in high and low half-words Note: 8-bit samples are encoded with 0x80 as the center (zero) value Note: 16-bit samples are encoded as standard, signed integers (i.e., 2''s-complement) Note: When the sound drive is operating in "mono", the two stereo channels are mixed together. This feature was added in January, 1998. -- John Maloney, July 28, 1996 -- edited: John Maloney, January 5, 1998 Mac Sound Input Notes: Squeak sound input is currently defined to provide a single (mono) stream of signed 16-bit samples for all platforms. Platforms that only support 8-bit sound input should convert samples to signed 16 bit values, leaving the low order bits zero. Since the available sampling rates differ from platform to platform, the client may not get the requested sampling rate; however, the call snd_GetRecordingSampleRate returns the sampling rate. On many platforms, simultaneous record and playback is permitted only if the input and output sampling rates are the same. -- John Maloney, Aug 22, 1997 ******/ #define BYTES_PER_SAMPLE 2 /*** double-buffer state record ***/ typedef struct { int open; int stereo; int frameCount; int sampleRate; int lastFlipTime; int playSemaIndex; int bufSizeInBytes; int bufState0; int bufState1; int done; } PlayStateRec; /*** possible buffer states ***/ #define BUF_EMPTY 0 #define BUF_FULL 1 #define BUF_PLAYING 2 /*** record buffer state record ***/ /* Note: RECORD_BUFFER_SIZE should be a multiple of 4096 bytes to avoid clicking. (The clicking was observed on a Mac 8100; the behavior of other Macs could differ.) Note: G3 Series Powerbook requires minimum of 4 * 4096 buffer size for stereo. */ #define RECORD_BUFFER_SIZE (4096 * 2) typedef struct { SPB paramBlock; int stereo; int bytesPerSample; int recordSemaIndex; int readIndex; /* index of the next sample to read */ char samples[RECORD_BUFFER_SIZE]; } RecordBufferRec, *RecordBuffer; /*** sound output variables ***/ SndChannelPtr chan; PlayStateRec bufState = {false, false, 0, 0, 0, 0, 0, 0, 0, true}; SndDoubleBufferHeader dblBufHeader; /*** sound input variables ***/ RecordBufferRec recordBuffer1, recordBuffer2; int recordingInProgress; long soundInputRefNum; /*** local functions ***/ pascal void DoubleBack(SndChannelPtr chan, SndDoubleBufferPtr buf); int FillBufferWithSilence(SndDoubleBufferPtr buf); pascal void FlipRecordBuffers(SPBPtr pb); int MixInSamples(int count, char *srcBufPtr, int srcStartIndex, char *dstBufPtr, int dstStartIndex); OSErr CarbonSndPlayDoubleBuffer (SndChannelPtr chan, SndDoubleBufferHeaderPtr theParams); pascal void DoubleBack(SndChannelPtr chan, SndDoubleBufferPtr buf) { /* Switch buffers (at interrupt time). The given buffer just finished playing. */ PlayStateRec *state; chan; /* reference argument to avoid compiler warnings */ state = (PlayStateRec *) buf->dbUserInfo[0]; if (buf->dbUserInfo[1] == 0) { state->bufState0 = BUF_EMPTY; state->bufState1 = BUF_PLAYING; } else { state->bufState0 = BUF_PLAYING; state->bufState1 = BUF_EMPTY; } buf->dbNumFrames = state->frameCount; buf->dbFlags = buf->dbFlags | dbBufferReady; if (state->done) { buf->dbFlags = buf->dbFlags | dbLastBuffer; } else { signalSemaphoreWithIndex(state->playSemaIndex); } state->lastFlipTime = ioMicroMSecs(); FillBufferWithSilence(buf); /* avoids ugly stutter if not filled in time */ } int FillBufferWithSilence(SndDoubleBufferPtr buf) { unsigned int *sample, *lastSample; sample = (unsigned int *) &buf->dbSoundData[0]; lastSample = (unsigned int *) &buf->dbSoundData[bufState.bufSizeInBytes]; /* word-fill buffer with silence */ if (BYTES_PER_SAMPLE == 1) { while (sample < lastSample) { *sample++ = 0x80808080; /* Note: 0x80 is zero value for 8-bit samples */ } } else { while (sample < lastSample) { *sample++ = 0; } } } pascal void FlipRecordBuffers(SPBPtr pb) { /* called at interrupt time to exchange the active and inactive record buffers */ RecordBuffer thisBuffer = (RecordBuffer) pb; RecordBuffer nextBuffer = (RecordBuffer) pb->userLong; if (pb->error == 0) { /* restart recording using the other buffer */ SPBRecord(&nextBuffer->paramBlock, true); /* reset the read pointer for the buffer that has just been filled */ thisBuffer->readIndex = 0; signalSemaphoreWithIndex(nextBuffer->recordSemaIndex); } } /*** exported sound output functions ***/ int snd_AvailableSpace(void) { if (!!bufState.open) return -1; if ((bufState.bufState0 == BUF_EMPTY) || (bufState.bufState1 == BUF_EMPTY)) { return bufState.bufSizeInBytes; } return 0; } int snd_PlaySamplesFromAtLength(int frameCount, int arrayIndex, int startIndex) { SndDoubleBufferPtr buf; int framesWritten; if (!!bufState.open) return -1; if (bufState.bufState0 == BUF_EMPTY) { buf = dblBufHeader.dbhBufferPtr[0]; bufState.bufState0 = BUF_FULL; } else { if (bufState.bufState1 == BUF_EMPTY) { buf = dblBufHeader.dbhBufferPtr[1]; bufState.bufState1 = BUF_FULL; } else { return 0; /* neither buffer is available */ } } if (bufState.frameCount < frameCount) { framesWritten = bufState.frameCount; } else { framesWritten = frameCount; } if (BYTES_PER_SAMPLE == 1) { /* 8-bit samples */ unsigned char *src, *dst, *end; src = (unsigned char *) (arrayIndex + startIndex); end = (unsigned char *) src + (framesWritten * (bufState.stereo ? 2 : 1)); dst = (unsigned char *) &buf->dbSoundData[0]; while (src < end) { *dst++ = *src++; } } else { /* 16-bit samples */ short int *src, *dst, *end; src = (short int *) (arrayIndex + (startIndex * 4)); end = (short int *) (arrayIndex + ((startIndex + framesWritten) * 4)); dst = (short int *) &buf->dbSoundData[0]; if (bufState.stereo) { /* stereo */ while (src < end) { *dst++ = *src++; } } else { /* mono */ /* if mono, average the left and right channels of the source */ while (src < end) { *dst++ = (*src++ + *src++) / 2; } } } return framesWritten; } int MixInSamples(int count, char *srcBufPtr, int srcStartIndex, char *dstBufPtr, int dstStartIndex) { int sample; if (BYTES_PER_SAMPLE == 1) { /* 8-bit samples */ unsigned char *src, *dst, *end; src = (unsigned char *) srcBufPtr + srcStartIndex; end = (unsigned char *) srcBufPtr + (count * (bufState.stereo ? 2 : 1)); dst = (unsigned char *) dstBufPtr + dstStartIndex; while (src < end) { sample = *dst + (*src++ - 128); if (sample > 255) sample = 255; if (sample < 0) sample = 0; *dst++ = sample; } } else { /* 16-bit samples */ short int *src, *dst, *end; src = (short int *) (srcBufPtr + (srcStartIndex * 4)); end = (short int *) (srcBufPtr + ((srcStartIndex + count) * 4)); if (bufState.stereo) { /* stereo */ dst = (short int *) (dstBufPtr + (dstStartIndex * 4)); while (src < end) { sample = *dst + *src++; if (sample > 32767) sample = 32767; if (sample < -32767) sample = -32767; *dst++ = sample; } } else { /* mono */ /* if mono, average the left and right channels of the source */ dst = (short int *) (dstBufPtr + (dstStartIndex * 2)); while (src < end) { sample = *dst + ((*src++ + *src++) / 2); if (sample > 32767) sample = 32767; if (sample < -32767) sample = -32767; *dst++ = sample; } } } } int snd_InsertSamplesFromLeadTime(int frameCount, int srcBufPtr, int samplesOfLeadTime) { SndDoubleBufferPtr bufPlaying, otherBuf; int samplesInserted, startSample, count; if (!!bufState.open) return -1; if (bufState.bufState0 == BUF_PLAYING) { bufPlaying = dblBufHeader.dbhBufferPtr[0]; otherBuf = dblBufHeader.dbhBufferPtr[1]; } else { bufPlaying = dblBufHeader.dbhBufferPtr[1]; otherBuf = dblBufHeader.dbhBufferPtr[0]; } samplesInserted = 0; /* mix as many samples as can fit into the remainder of the currently playing buffer */ startSample = ((bufState.sampleRate * (ioMicroMSecs() - bufState.lastFlipTime)) / 1000) + samplesOfLeadTime; if (startSample < bufState.frameCount) { count = bufState.frameCount - startSample; if (count > frameCount) count = frameCount; MixInSamples(count, (char *) srcBufPtr, 0, (char *) &bufPlaying->dbSoundData[0], startSample); samplesInserted = count; } /* mix remaining samples into the inactive buffer */ count = bufState.frameCount; if (count > (frameCount - samplesInserted)) { count = frameCount - samplesInserted; } MixInSamples(count, (char *) srcBufPtr, samplesInserted, (char *) &otherBuf->dbSoundData[0], 0); return samplesInserted + count; } int snd_PlaySilence(void) { if (!!bufState.open) return -1; if (bufState.bufState0 == BUF_EMPTY) { FillBufferWithSilence(dblBufHeader.dbhBufferPtr[0]); bufState.bufState0 = BUF_FULL; } else { if (bufState.bufState1 == BUF_EMPTY) { FillBufferWithSilence(dblBufHeader.dbhBufferPtr[1]); bufState.bufState1 = BUF_FULL; } else { return 0; /* neither buffer is available */ } } return bufState.bufSizeInBytes; } int snd_Start(int frameCount, int samplesPerSec, int stereo, int semaIndex) { OSErr err; SndDoubleBufferPtr buffer; int bytesPerFrame, bufferBytes, i; bytesPerFrame = stereo ? 2 * BYTES_PER_SAMPLE : BYTES_PER_SAMPLE; bufferBytes = ((frameCount * bytesPerFrame) / 8) * 8; /* Note: Must round bufferBytes down to an 8-byte boundary to avoid clicking!!!!!! */ if (bufState.open) { /* still open from last time; clean up before continuing */ snd_Stop(); } bufState.open = false; /* set to true if successful */ bufState.stereo = stereo; bufState.frameCount = bufferBytes / bytesPerFrame; bufState.sampleRate = samplesPerSec; bufState.lastFlipTime = ioMicroMSecs(); bufState.playSemaIndex = semaIndex; bufState.bufSizeInBytes = bufferBytes; bufState.bufState0 = BUF_EMPTY; bufState.bufState1 = BUF_EMPTY; bufState.done = false; dblBufHeader.dbhNumChannels = stereo ? 2 : 1; dblBufHeader.dbhSampleSize = BYTES_PER_SAMPLE * 8; dblBufHeader.dbhCompressionID = 0; dblBufHeader.dbhPacketSize = 0; dblBufHeader.dbhSampleRate = samplesPerSec << 16; /* convert to fixed point */ #if TARGET_API_MAC_CARBON dblBufHeader.dbhDoubleBack = nil; #else dblBufHeader.dbhDoubleBack = NewSndDoubleBackProc(DoubleBack); #endif chan = NULL; err = SndNewChannel(&chan, sampledSynth, 0, NULL); if (err !!= noErr) return false; /* could not open sound channel */ for (i = 0; i < 2; i++) { buffer = (SndDoubleBufferPtr) NewPtrClear(sizeof(SndDoubleBuffer) + bufState.bufSizeInBytes); if (buffer == NULL) { /* could not allocate memory for a buffer; clean up and abort */ SndDisposeChannel(chan, true); #if !!TARGET_API_MAC_CARBON DisposeRoutineDescriptor(dblBufHeader.dbhDoubleBack); #endif if (i == 1) { /* free the first buffer */ DisposePtr((char *) dblBufHeader.dbhBufferPtr[1]); dblBufHeader.dbhBufferPtr[1] = NULL; } return false; } buffer->dbNumFrames = bufState.frameCount; buffer->dbFlags = dbBufferReady; buffer->dbUserInfo[0] = (long) &bufState; buffer->dbUserInfo[1] = i; FillBufferWithSilence(buffer); dblBufHeader.dbhBufferPtr[i] = buffer; } #if TARGET_API_MAC_CARBON err = CarbonSndPlayDoubleBuffer(chan, &dblBufHeader); #else err = SndPlayDoubleBuffer(chan, &dblBufHeader); #endif if (err !!= noErr) return false; /* could not play double buffer */ bufState.open = true; return true; } int snd_Stop(void) { OSErr err; SndDoubleBufferPtr buffer; SCStatus status; long i, junk; if (!!bufState.open) return; bufState.open = false; bufState.done = true; while (true) { err = SndChannelStatus(chan, sizeof(status), &status); if (err !!= noErr) break; /* could not get channel status */ if (!!status.scChannelBusy) break; Delay(1, (void *) &junk); } SndDisposeChannel(chan, true); #if !!TARGET_API_MAC_CARBON DisposeRoutineDescriptor(dblBufHeader.dbhDoubleBack); #endif for (i = 0; i < 2; i++) { buffer = dblBufHeader.dbhBufferPtr[i]; if (buffer !!= NULL) { DisposePtr((char *) buffer); } dblBufHeader.dbhBufferPtr[i] = NULL; } bufState.open = false; } /*** exported sound input functions ***/ int snd_SetRecordLevel(int level) { /* set the recording level to a value between 0 (minimum gain) and 1000. */ Fixed inputGainArg; int err; if (!!recordingInProgress || (level < 0) || (level > 1000)) { success(false); return; /* noop if not recording */ } inputGainArg = ((500 + level) << 16) / 1000; /* gain is Fixed between 0.5 and 1.5 */ err = SPBSetDeviceInfo(soundInputRefNum, siInputGain, &inputGainArg); /* don''t fail on error; hardware may not support setting the gain */ } int snd_StartRecording(int desiredSamplesPerSec, int stereo, int semaIndex) { /* turn on sound recording, trying to use a sampling rate close to the one specified. semaIndex is the index in the exportedObject array of a semaphore to be signalled when input data is available. */ Str255 deviceName = ""; short automaticGainControlArg; Fixed inputGainArg; long compressionTypeArg; short continuousArg; short sampleSizeArg; short channelCountArg; UnsignedFixed sampleRateArg; int err; err = SPBOpenDevice(deviceName, siWritePermission, &soundInputRefNum); if (err !!= noErr) { success(false); return; } /* try to initialize some optional parameters, but don''t fail if we can''t */ automaticGainControlArg = false; SPBSetDeviceInfo(soundInputRefNum, siAGCOnOff, &automaticGainControlArg); inputGainArg = 1 << 16; /* 1.0 in Fixed */ SPBSetDeviceInfo(soundInputRefNum, siInputGain, &inputGainArg); compressionTypeArg = ''NONE''; SPBSetDeviceInfo(soundInputRefNum, siCompressionType, &compressionTypeArg); continuousArg = true; err = SPBSetDeviceInfo(soundInputRefNum, siContinuous, &continuousArg); if (err !!= noErr) { success(false); SPBCloseDevice(soundInputRefNum); return; } sampleSizeArg = 16; err = SPBSetDeviceInfo(soundInputRefNum, siSampleSize, &sampleSizeArg); if (err !!= noErr) { /* use 8-bit samples */ sampleSizeArg = 8; err = SPBSetDeviceInfo(soundInputRefNum, siSampleSize, &sampleSizeArg); if (err !!= noErr) { success(false); SPBCloseDevice(soundInputRefNum); return; } } channelCountArg = stereo ? 2 : 1; err = SPBSetDeviceInfo(soundInputRefNum, siNumberChannels, &channelCountArg); if (err !!= noErr) { success(false); SPBCloseDevice(soundInputRefNum); return; } /* try to set the client''s desired sample rate */ sampleRateArg = desiredSamplesPerSec << 16; err = SPBSetDeviceInfo(soundInputRefNum, siSampleRate, &sampleRateArg); if (err !!= noErr) { /* if client''s rate fails, try the nearest common sampling rates in {11025, 22050, 44100} */ if (desiredSamplesPerSec <= 16538) { sampleRateArg = 11025 << 16; } else { if (desiredSamplesPerSec <= 33075) { sampleRateArg = 22050 << 16; } else { sampleRateArg = 44100 << 16; } } /* even if following fails, recording can go on at the default sample rate */ SPBSetDeviceInfo(soundInputRefNum, siSampleRate, &sampleRateArg); } recordBuffer1.paramBlock.inRefNum = soundInputRefNum; recordBuffer1.paramBlock.count = RECORD_BUFFER_SIZE; recordBuffer1.paramBlock.milliseconds = 0; recordBuffer1.paramBlock.bufferLength = RECORD_BUFFER_SIZE; recordBuffer1.paramBlock.bufferPtr = recordBuffer1.samples; #if TARGET_API_MAC_CARBON recordBuffer1.paramBlock.completionRoutine = NewSICompletionUPP(FlipRecordBuffers); #else recordBuffer1.paramBlock.completionRoutine = NewSICompletionProc(FlipRecordBuffers); #endif recordBuffer1.paramBlock.interruptRoutine = nil; recordBuffer1.paramBlock.userLong = (long) &recordBuffer2; /* pointer to other buffer */ recordBuffer1.paramBlock.error = noErr; recordBuffer1.paramBlock.unused1 = 0; recordBuffer1.stereo = stereo; recordBuffer1.bytesPerSample = sampleSizeArg == 8 ? 1 : 2; recordBuffer1.recordSemaIndex = semaIndex; recordBuffer1.readIndex = RECORD_BUFFER_SIZE; recordBuffer2.paramBlock.inRefNum = soundInputRefNum; recordBuffer2.paramBlock.count = RECORD_BUFFER_SIZE; recordBuffer2.paramBlock.milliseconds = 0; recordBuffer2.paramBlock.bufferLength = RECORD_BUFFER_SIZE; recordBuffer2.paramBlock.bufferPtr = recordBuffer2.samples; #if TARGET_API_MAC_CARBON recordBuffer2.paramBlock.completionRoutine = NewSICompletionUPP(FlipRecordBuffers); #else recordBuffer2.paramBlock.completionRoutine = NewSICompletionProc(FlipRecordBuffers); #endif recordBuffer2.paramBlock.interruptRoutine = nil; recordBuffer2.paramBlock.userLong = (long) &recordBuffer1; /* pointer to other buffer */ recordBuffer2.paramBlock.error = noErr; recordBuffer2.paramBlock.unused1 = 0; recordBuffer2.stereo = stereo; recordBuffer2.bytesPerSample = sampleSizeArg == 8 ? 1 : 2; recordBuffer2.recordSemaIndex = semaIndex; recordBuffer2.readIndex = RECORD_BUFFER_SIZE; err = SPBRecord(&recordBuffer1.paramBlock, true); if (err !!= noErr) { success(false); SPBCloseDevice(soundInputRefNum); return; } recordingInProgress = true; } int snd_StopRecording(void) { /* turn off sound recording */ int err; if (!!recordingInProgress) return; /* noop if not recording */ err = SPBStopRecording(soundInputRefNum); if (err !!= noErr) success(false); SPBCloseDevice(soundInputRefNum); #if TARGET_API_MAC_CARBON DisposeSICompletionUPP(recordBuffer1.paramBlock.completionRoutine); #else DisposeRoutineDescriptor(recordBuffer1.paramBlock.completionRoutine); #endif recordBuffer1.paramBlock.completionRoutine = nil; #if TARGET_API_MAC_CARBON DisposeSICompletionUPP(recordBuffer2.paramBlock.completionRoutine); #else DisposeRoutineDescriptor(recordBuffer2.paramBlock.completionRoutine); #endif recordBuffer2.paramBlock.completionRoutine = nil; recordBuffer1.recordSemaIndex = 0; recordBuffer2.recordSemaIndex = 0; recordingInProgress = false; } double snd_GetRecordingSampleRate(void) { /* return the actual recording rate; fail if not currently recording */ UnsignedFixed sampleRateArg; int err; if (!!recordingInProgress) { success(false); return 0.0; } err = SPBGetDeviceInfo(soundInputRefNum, siSampleRate, &sampleRateArg); if (err !!= noErr) { success(false); return 0.0; } return (double) ((sampleRateArg >> 16) & 0xFFFF) + ((double) (sampleRateArg & 0xFFFF) / 65536.0); } int snd_RecordSamplesIntoAtLength(int buf, int startSliceIndex, int bufferSizeInBytes) { /* if data is available, copy as many sample slices as possible into the given buffer starting at the given slice index. do not write past the end of the buffer, which is buf + bufferSizeInBytes. return the number of slices (not bytes) copied. a slice is one 16-bit sample in mono or two 16-bit samples in stereo. */ int bytesPerSlice = (recordBuffer1.stereo ? 4 : 2); char *nextBuf = (char *) buf + (startSliceIndex * bytesPerSlice); char *bufEnd = (char *) buf + bufferSizeInBytes; char *src, *srcEnd; RecordBuffer recBuf = nil; int bytesCopied; if (!!recordingInProgress) { success(false); return 0; } /* select the buffer with unread samples, if any */ recBuf = nil; if (recordBuffer1.readIndex < RECORD_BUFFER_SIZE) recBuf = &recordBuffer1; if (recordBuffer2.readIndex < RECORD_BUFFER_SIZE) recBuf = &recordBuffer2; if (recBuf == nil) return 0; /* no samples available */ /* copy samples into the client''s buffer */ src = &recBuf->samples[0] + recBuf->readIndex; srcEnd = &recBuf->samples[RECORD_BUFFER_SIZE]; if (recBuf->bytesPerSample == 1) { while ((src < srcEnd) && (nextBuf < bufEnd)) { /* convert 8-bit sample to 16-bit sample */ *nextBuf++ = (*src++) - 128; /* convert from [0-255] to [-128-127] */ *nextBuf++ = 0; /* low-order byte is zero */ } } else { while ((src < srcEnd) && (nextBuf < bufEnd)) { *nextBuf++ = *src++; } } recBuf->readIndex = src - &recBuf->samples[0]; /* update read index */ /* return the number of slices copied */ bytesCopied = (int) nextBuf - (buf + (startSliceIndex * bytesPerSlice)); return bytesCopied / bytesPerSlice; } //Nov 6th 2000 void snd_Volume(double *left, double *right) { double temp; SndCommand cmd; long results; OSErr err; *left = 1.0; *right = 1.0; cmd.cmd = getVolumeCmd; cmd.param1 = 0; cmd.param2 = (long) &results; err = -1; if (chan !!= null) err = SndDoImmediate(chan,&cmd); if (err !!= noErr) { err = GetDefaultOutputVolume(&results); } if (err !!= noErr) return; temp = (results & 0xFFFF); *left = temp/256.0; temp = (results >> 16); *right = temp/256.0; } void snd_SetVolume(double left, double right) { unsigned long tempLeft,tempRight; SndCommand cmd; OSErr err; tempLeft = left*256.0 + 0.5; tempLeft = tempLeft & 0xFFFF; tempRight = right*256.0 + 0.5; tempRight= tempRight & 0xFFFF; cmd.cmd = volumeCmd; cmd.param1 = 0; cmd.param2 = (tempRight << 16) | tempLeft; err = -1; if (chan !!= null) err= SndDoImmediate(chan,&cmd); if (err !!= noErr) { err = SetDefaultOutputVolume(cmd.param2); } } /* File: CarbonSndPlayDB.c Description:Routines demonstrating how to create a function that works much like the original SndPlayDoubleBuffer but is Carbon compatible (which SndPlayDoubleBuffer isn''t). Author: MC Copyright: © Copyright 1999-2000 Apple Computer, Inc. All rights reserved. Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Change History (most recent first): */ /* Requirements for using this shim code: 1) The sound channel''s queue must be empty before you call CarbonSndPlayDoubleBuffer 2) You cannot call MySndDoImmediate until CarbonSndPlayDoubleBuffer returns. Be careful about calling MySndDoImmediate at interrupt time with a quietCmd. */ /* Some code is commented out becuase knowing who calls it and how allows shortcuts Karl Goiser 14/01/01 */ #if TARGET_API_MAC_CARBON #undef UNNECESSARY_FOR_SQUEAK #if UNNECESSARY_FOR_SQUEAK static pascal void CarbonSndPlayDoubleBufferCleanUpProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd); #endif static pascal void CarbonSndPlayDoubleBufferCallBackProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd); static void InsertSndDoCommand (SndChannelPtr chan, SndCommand * theCmd); static pascal void NMResponseProc (NMRecPtr nmReqPtr); #define kBufSize 2048 // Structs struct PerChanInfo { QElemPtr qLink; /* next queue entry */ short qType; /* queue type = 0 */ short stopping; #if DEBUG OSType magic; #endif SndCallBackUPP usersCallBack; SndDoubleBufferHeaderPtr theParams; CmpSoundHeader soundHeader; }; typedef struct PerChanInfo PerChanInfo; typedef struct PerChanInfo * PerChanInfoPtr; // Globals Boolean gNMRecBusy; NMRecPtr gNMRecPtr; QHdrPtr gFreeList; Ptr gSilenceTwos; Ptr gSilenceOnes; static SndCallBackUPP gCarbonSndPlayDoubleBufferCallBackUPP = nil; static SndCallBackUPP gCarbonSndPlayDoubleBufferCleanUpUPP = nil; #if UNNECESSARY_FOR_SQUEAK // Remember this routine could be called at interrupt time, so don''t allocate or deallocate memory. OSErr MySndDoImmediate (SndChannelPtr chan, SndCommand * cmd) { PerChanInfoPtr perChanInfoPtr; // Is this being called on one of the sound channels we are manipulating? // If so, we need to pull our callback out of the way so that the user''s commands run if (gCarbonSndPlayDoubleBufferCallBackUPP == chan->callBack) { if (quietCmd == cmd->cmd || flushCmd == cmd->cmd) { // We know that our callBackCmd is the first item in the queue if this is our channel perChanInfoPtr = (PerChanInfoPtr)(chan->queue[chan->qHead].param2); #if DEBUG if (perChanInfoPtr->magic !!= ''SANE'') DebugStr("\pBAD in MySndDoImmediate"); #endif perChanInfoPtr->stopping = true; Enqueue ((QElemPtr)perChanInfoPtr, gFreeList); if (!! OTAtomicSetBit (&gNMRecBusy, 0)) { NMInstall (gNMRecPtr); } chan->callBack = perChanInfoPtr->usersCallBack; } } return (SndDoImmediate (chan, cmd)); } #endif UNNECESSARY_FOR_SQUEAK // This must be called at task time. OSErr CarbonSndPlayDoubleBuffer (SndChannelPtr chan, SndDoubleBufferHeaderPtr theParams) { OSErr err; CompressionInfo compInfo; PerChanInfoPtr perChanInfoPtr; SndCommand playCmd; SndCommand callBack; if (nil == chan) return badChannel; if (nil == theParams) return paramErr; if (nil == gFreeList) { // This can''t ever be disposed since we don''t know when we might need to use it (at interrupt time) gFreeList = (QHdrPtr)NewPtrClear (sizeof (QHdr)); err = MemError (); if (noErr !!= err) goto exit; } if (nil == gSilenceOnes) { short i; // This can''t ever be disposed since we don''t know when we might need to use it (at interrupt time) gSilenceOnes = NewPtr (kBufSize); err = MemError (); if (noErr !!= err) goto exit; for (i = 0; i < kBufSize; i++) *gSilenceOnes++ = (char)0x80; } if (nil == gSilenceTwos) { // This can''t ever be disposed since we don''t know when we might need to use it (at interrupt time) gSilenceTwos = NewPtrClear (kBufSize); err = MemError (); if (noErr !!= err) goto exit; } if (nil == gNMRecPtr) { // This can''t ever be disposed since we don''t know when we might need to use it (at interrupt time) gNMRecPtr = (NMRecPtr)NewPtr (sizeof (NMRec)); err = MemError (); if (noErr !!= err) goto exit; // Set up our NMProc info that will dispose of most (but not all) of our memory gNMRecPtr->qLink = nil; gNMRecPtr->qType = 8; gNMRecPtr->nmFlags = 0; gNMRecPtr->nmPrivate = 0; gNMRecPtr->nmReserved = 0; gNMRecPtr->nmMark = nil; gNMRecPtr->nmIcon = nil; gNMRecPtr->nmSound = nil; gNMRecPtr->nmStr = nil; gNMRecPtr->nmResp = NewNMUPP (NMResponseProc); gNMRecPtr->nmRefCon = 0; } perChanInfoPtr = (PerChanInfoPtr)NewPtr (sizeof (PerChanInfo)); err = MemError (); if (noErr !!= err) goto exit; // Init basic per channel information perChanInfoPtr->qLink = nil; perChanInfoPtr->qType = 0; // not used perChanInfoPtr->stopping = 0; #if DEBUG perChanInfoPtr->magic = ''SANE''; #endif perChanInfoPtr->theParams = theParams; // Have to remember the user''s callback function from the sound because // we are going to overwrite it with our own callback function. perChanInfoPtr->usersCallBack = chan->callBack; // Set up the sound header for the bufferCmd that will be used to play // the buffers passed in by the SndPlayDoubleBuffer call. perChanInfoPtr->soundHeader.samplePtr = (Ptr)(theParams->dbhBufferPtr[0]->dbSoundData); perChanInfoPtr->soundHeader.numChannels = theParams->dbhNumChannels; perChanInfoPtr->soundHeader.sampleRate = theParams->dbhSampleRate; perChanInfoPtr->soundHeader.loopStart = 0; perChanInfoPtr->soundHeader.loopEnd = 0; perChanInfoPtr->soundHeader.encode = cmpSH; perChanInfoPtr->soundHeader.baseFrequency = kMiddleC; perChanInfoPtr->soundHeader.numFrames = (unsigned long)theParams->dbhBufferPtr[0]->dbNumFrames; // perChanInfoPtr->soundHeader.AIFFSampleRate = 0; // unused perChanInfoPtr->soundHeader.markerChunk = nil; perChanInfoPtr->soundHeader.futureUse2 = nil; perChanInfoPtr->soundHeader.stateVars = nil; perChanInfoPtr->soundHeader.leftOverSamples = nil; perChanInfoPtr->soundHeader.compressionID = theParams->dbhCompressionID; perChanInfoPtr->soundHeader.packetSize = (unsigned short)theParams->dbhPacketSize; perChanInfoPtr->soundHeader.snthID = 0; perChanInfoPtr->soundHeader.sampleSize = (unsigned short)theParams->dbhSampleSize; perChanInfoPtr->soundHeader.sampleArea[0] = 0; // Is the sound compressed? If so, we need to treat theParams as a SndDoubleBufferHeader2Ptr. if (0 !!= theParams->dbhCompressionID) { // Sound is compressed err = GetCompressionInfo (theParams->dbhCompressionID, ((SndDoubleBufferHeader2Ptr)theParams)->dbhFormat, theParams->dbhNumChannels, theParams->dbhSampleSize, &compInfo); if (noErr !!= err) goto exitDispose; perChanInfoPtr->soundHeader.format = compInfo.format; } else { // Sound is not compressed perChanInfoPtr->soundHeader.format = kSoundNotCompressed; } playCmd.cmd = bufferCmd; playCmd.param1 = 0; // unused playCmd.param2 = (long)&perChanInfoPtr->soundHeader; callBack.cmd = callBackCmd; callBack.param1 = 0; // which buffer to fill, 0 buffer, 1, 0, ... callBack.param2 = (long)perChanInfoPtr; // Install our callback function pointer straight into the sound channel structure if (nil == gCarbonSndPlayDoubleBufferCallBackUPP) { gCarbonSndPlayDoubleBufferCallBackUPP = NewSndCallBackUPP(CarbonSndPlayDoubleBufferCallBackProc); } chan->callBack = gCarbonSndPlayDoubleBufferCallBackUPP; #if UNNECESSARY_FOR_SQUEAK if (gCarbonSndPlayDoubleBufferCleanUpUPP == nil) { gCarbonSndPlayDoubleBufferCleanUpUPP = NewSndCallBackProc (CarbonSndPlayDoubleBufferCleanUpProc); } #endif err = SndDoCommand (chan, &playCmd, true); if (noErr !!= err) goto exitDispose; err = SndDoCommand (chan, &callBack, true); if (noErr !!= err) goto exitDispose; exit: return err; exitDispose: if (nil !!= perChanInfoPtr) DisposePtr ((Ptr)perChanInfoPtr); goto exit; } #if UNNECESSARY_FOR_SQUEAK static pascal void CarbonSndPlayDoubleBufferCleanUpProc( SndChannelPtr theChannel, SndCommand * theCallBackCmd) { PerChanInfoPtr perChanInfoPtr; perChanInfoPtr = (PerChanInfoPtr)(theCallBackCmd->param2); #if DEBUG if (perChanInfoPtr->magic !!= ''SANE'') DebugStr("\pBAD in CarbonSndPlayDoubleBufferCleanUpProc"); #endif // Put our per channel data on the free queue so we can clean up later Enqueue ((QElemPtr)perChanInfoPtr, gFreeList); // Have to install our Notification Manager routine so that we can clean up the gFreeList if (!! OTAtomicSetBit (&gNMRecBusy, 0)) { NMInstall (gNMRecPtr); } // Have to put the user''s callback proc back so they get called when the next buffer finishes theChannel->callBack = perChanInfoPtr->usersCallBack; } #endif static pascal void CarbonSndPlayDoubleBufferCallBackProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd) { SndDoubleBufferHeaderPtr theParams; SndDoubleBufferPtr emptyBuf; SndDoubleBufferPtr nextBuf; PerChanInfoPtr perChanInfoPtr; SndCommand playCmd; perChanInfoPtr = (PerChanInfoPtr)(theCallBackCmd->param2); #if DEBUG if (perChanInfoPtr->magic !!= ''SANE'') DebugStr("\pBAD in CarbonSndPlayDoubleBufferCallBackProc"); #endif if (true == perChanInfoPtr->stopping) goto exit; theParams = perChanInfoPtr->theParams; // The buffer that just played and needs to be filled emptyBuf = theParams->dbhBufferPtr[theCallBackCmd->param1]; // Clear the ready flag emptyBuf->dbFlags ^= dbBufferReady; // This is the buffer to play now nextBuf = theParams->dbhBufferPtr[!!theCallBackCmd->param1]; // Check to see if it is ready, or if we have to wait a bit if (nextBuf->dbFlags & dbBufferReady) { perChanInfoPtr->soundHeader.numFrames = (unsigned long)nextBuf->dbNumFrames; perChanInfoPtr->soundHeader.samplePtr = (Ptr)(nextBuf->dbSoundData); // Flip the bit telling us which buffer is next theCallBackCmd->param1 = !!theCallBackCmd->param1; // If this isn''t the last buffer, call the user''s fill routine if (!!(nextBuf->dbFlags & dbLastBuffer)) { // Declare a function pointer to the user''s double back proc void (*doubleBackProc)(SndChannel*, SndDoubleBuffer*); // Call user''s double back proc doubleBackProc = (void*)DoubleBack; (*doubleBackProc) (theChannel, emptyBuf); } else { // Call our clean up proc when the last buffer finishes theChannel->callBack = gCarbonSndPlayDoubleBufferCleanUpUPP; } } else { // We have to wait for the buffer to become ready. // The real SndPlayDoubleBuffer would play a short bit of silence waiting for // the user to read the audio from disk, so that''s what we do here. #if DEBUG DebugStr ("\p buffer is not ready!!"); #endif // Play a short section of silence so that we can check the ready flag again if (theParams->dbhSampleSize == 8) { perChanInfoPtr->soundHeader.numFrames = (UInt32)(kBufSize / theParams->dbhNumChannels); perChanInfoPtr->soundHeader.samplePtr = gSilenceOnes; } else { perChanInfoPtr->soundHeader.numFrames = (UInt32)(kBufSize / (theParams->dbhNumChannels * (theParams->dbhSampleSize / 8))); perChanInfoPtr->soundHeader.samplePtr = gSilenceTwos; } } // Insert our callback command InsertSndDoCommand (theChannel, theCallBackCmd); // Play the next buffer playCmd.cmd = bufferCmd; playCmd.param1 = 0; playCmd.param2 = (long)&(perChanInfoPtr->soundHeader); InsertSndDoCommand (theChannel, &playCmd); exit: return; } static void InsertSndDoCommand (SndChannelPtr chan, SndCommand * newCmd) { if (-1 == chan->qHead) { chan->qHead = chan->qTail; } if (1 <= chan->qHead) { chan->qHead--; } else { chan->qHead = chan->qTail; } chan->queue[chan->qHead] = *newCmd; } static pascal void NMResponseProc (NMRecPtr nmReqPtr) { PerChanInfoPtr perChanInfoPtr; OSErr err; NMRemove (nmReqPtr); gNMRecBusy = false; do { perChanInfoPtr = (PerChanInfoPtr)gFreeList->qHead; if (nil !!= perChanInfoPtr) { err = Dequeue ((QElemPtr)perChanInfoPtr, gFreeList); if (noErr == err) { DisposePtr ((Ptr)perChanInfoPtr); } } } while (nil !!= perChanInfoPtr && noErr == err); } #endif'! ! !InterpreterSupportCode class methodsFor: 'source files' stamp: 'JMM 2/16/2001 21:46'! macWindowFile ^ '#include "sq.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __MPW__ #include #endif #include #include #ifndef __MPW__ #include #endif #include #include #include #include #include /*** Compilation Options: * * define PLUGIN to compile code for Netscape or IE Plug-in * define MAKE_PROFILE to compile code for profiling * ***/ //#define PLUGIN //#define MAKE_PROFILE //#define IHAVENOHEAD //Aug 7th 2000,JMM Added logic for interrupt driven dispatching //Sept 1st 2000, JMM fix problem with modifier information being passed back incorrectly. //Sept 1st 2000, JMM use floating point for time versus 64bit math (faster!!) //Sept 1st 2000, JMM watch mouse movement foreground only, ignore when squeak in background. //Sept 18th 2000, JMM fix to cmpSize //Sept 19th 2000, JMM Sept 1st fix to keyboard modifier info broke cmd shift //Sept 27 2000, JMM fix to documentPath //Nov 13 2000, JMM logic to read/write image from VM. //Nov 22 2000, JMM Bob Arning found a bug with the duplicate mouse event logic (we were altering the event then recording the altered value) //Nov 30 2000, JMM Use Open Transport clock versus upTime, solves some issues for jitter and it''s faster //Dec 5th 2000, JMM poll 60 times a second... do event polling via checkForInterrupts and drive semaphore //Dec 6th 2000, JMM added logic to interface with power manger (1997 was there but dropped..., back again for ibooks) //Jan 14th 2001, KG Did some carbon porting. //Feb 2nd 2001, JMM V3.0 added zoom window support, full path support //Feb 2nd 2001, JMM V3.04 do an open window dialog at startup time if no image file //Feb 14th 2001, JMM V3.06 don''t cache image read/writes #if TARGET_API_MAC_CARBON #define EnableMenuItemCarbon(m1,v1) EnableMenuItem(m1,v1); #define DisableMenuItemCarbon(m1,v1) DisableMenuItem(m1,v1); #else #ifndef NewAEEventHandlerUPP #define NewAEEventHandlerUPP NewAEEventHandlerProc #endif #define EnableMenuItemCarbon(m1,v1) EnableItem(m1,v1); #define DisableMenuItemCarbon(m1,v1) DisableItem(m1,v1); inline Rect *GetPortBounds(CGrafPtr w,Rect *r) { *r = w->portRect; return &w->portRect;} inline Rect *GetRegionBounds(RgnHandle region, Rect * bounds) { *bounds = (*region)->rgnBBox; return &(*region)->rgnBBox;} inline BitMap *GetQDGlobalsScreenBits(BitMap *bm){*bm = qd.screenBits; return &qd.screenBits; } inline BitMap * GetPortBitMapForCopyBits (CGrafPtr w) { return &((GrafPtr)w)->portBits;} inline pascal long InvalWindowRect(WindowRef window, const Rect * bounds) {InvalRect (bounds);} #endif /*** Enumerations ***/ enum { appleID = 1, fileID, editID }; enum { quitItem = 1 }; /* The following prototype is missing from the CW11 header files: */ pascal void ExitToShell(void); /*** Variables -- Imported from Browser Plugin Module ***/ #ifdef PLUGIN extern int pluginArgCount; extern char *pluginArgName[100]; extern char *pluginArgValue[100]; #endif /*** Variables -- Imported from Virtual Machine ***/ extern int fullScreenFlag; extern int interruptCheckCounter; extern int interruptKeycode; extern int interruptPending; /* set to true by recordKeystroke if interrupt key is pressed */ extern unsigned char *memory; extern int savedWindowSize; /* set from header when image file is loaded */ /*** Variables -- image and path names ***/ #define IMAGE_NAME_SIZE 300 char imageName[IMAGE_NAME_SIZE + 1]; /* full path to image file */ #define SHORTIMAGE_NAME_SIZE 100 char shortImageName[SHORTIMAGE_NAME_SIZE + 1]; /* just the image file name */ #define DOCUMENT_NAME_SIZE 300 char documentName[DOCUMENT_NAME_SIZE + 1]; /* full path to document file */ #define VMPATH_SIZE 300 char vmPath[VMPATH_SIZE + 1]; /* full path to interpreter''s directory */ /*** Variables -- Mac Related ***/ MenuHandle appleMenu = nil; MenuHandle editMenu = nil; int menuBarHeight = 20; RgnHandle menuBarRegion = nil; /* if non-nil, then menu bar has been hidden */ MenuHandle fileMenu = nil; CTabHandle stColorTable = nil; PixMapHandle stPixMap = nil; WindowPtr stWindow = nil; OTTimeStamp timeStart; Boolean gTapPowerManager=false; Boolean gDisablePowerManager=false; const long gDisableIdleTickCount=60*10; long gDisableIdleTickLimit=0; Boolean gThreadManager=false; ThreadID gSqueakThread = kNoThreadID; ThreadEntryUPP gSqueakThreadUPP; Boolean gAllowAccessToFilePlease=false; #ifdef __MPW__ QDGlobals qd; #endif /*** Variables -- Event Recording ***/ #define MAX_EVENT_BUFFER 1024 int inputSemaphoreIndex = 0;/* if non-zero the event semaphore index */ sqInputEvent eventBuffer[MAX_EVENT_BUFFER]; int eventBufferGet = 0; int eventBufferPut = 0; /* declaration of the event message hook */ typedef int (*eventMessageHook)(EventRecord* event); eventMessageHook messageHook = NULL; eventMessageHook postMessageHook = NULL; #define KEYBUF_SIZE 64 int keyBuf[KEYBUF_SIZE]; /* circular buffer */ int keyBufGet = 0; /* index of next item of keyBuf to read */ int keyBufPut = 0; /* index of next item of keyBuf to write */ int keyBufOverflows = 0; /* number of characters dropped */ int buttonState = 0; /* mouse button and modifier state when mouse button went down or 0 if not pressed */ int cachedButtonState = 0; /* buffered mouse button and modifier state for last mouse click even if button has since gone up; this cache is kept until the next time ioGetButtonState() is called to avoid missing short clicks */ Point savedMousePosition; /* mouse position when window is inactive */ int windowActive = true; /* true if the Squeak window is the active window */ /* This table maps the 5 Macintosh modifier key bits to 4 Squeak modifier bits. (The Mac shift and caps lock keys are both mapped to the single Squeak shift bit). Mac bits: