Hmm, timer is messed up.
Offline
yes. That's my fault for trying the new prettydate system.
anyway, the commenting system has never had any direct input variables in it for database connection:
mysql_query("INSERT INTO comments (username, comment, time, ip, epoch, commentName, smilies, status)
VALUES ('$username', '$comment', '$time', '$ip', '$epoch', '$commentName', '$smilies', '$commentType')");so there must be some other problem...
EDIT: I've changed the database table type from MyISAM to innoDB, as recommended by an online guide. See if it helps...
Last edited by sparks (2012-01-30 17:52:38)
Offline
cocolover76 wrote:
I think I may be able to help develop this. (I have said that on a million topics.)
I have an idea:
PHP reads databases like this:blocklib_scratch
motion
picurl(string) | id(varchar) | whomade(string) | desc(string)
imageshack blah | 12345678 | cocolover76 | blah blah blehAnd so on, and so on.
And prints it like this:(image with url picurl) By (whomade)
(desc)EDIT: Way, WAY outposted. I ...will delete this.
What do you mean? I know what MySQL databases look like and how to read/write them. The problem isn't that it isn't writing all the time, its that it sometimes reads and sometimes does not. This means there is either something I am doing wrong with my PHP coding that no one else can spot either, or that there is some sort of connection problem between the site and the database.
cocolover76 wrote:
Way, WAY outposted. I ...will delete this.
Oh. I got really confused then, you deleted that as I was replying and then it was gone!
Last edited by sparks (2012-01-30 16:59:49)
Offline
It doesn't load slowly for me.
Offline
I wouldnt mind managing the mysql database, keeping it in shape.
Offline
Zeusking19 wrote:
I wouldnt mind managing the mysql database, keeping it in shape.
![]()
Thanks for the offer, but I think the idea is the database keeps itself from getting messy
Librarians accept or reject new blocks, the database stores them
Offline
Oh well. If you guys need html help i am free.
Offline
the site says Squawkers13 is an invalid creator name!
Offline
Hey! Do you need any help at all with php or mysql or html, css, or javascript? I'm really good at php primarely, but I know how to communicate to mysql with php
Offline
Squawkers13 wrote:
the site says Squawkers13 is an invalid creator name!
Squawkers13, does it allow you to be on the site without having to be a developer? If so, you could register if there is a way to get the sign-up page.
Offline
http://scratch.mit.edu/forums/viewtopic … 5#p1141075
HELP!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Offline
You might need to change the block library a little.
I made a patch which let's you import, export, and create blocks.
This is the patch:
'From MIT Squeak 0.9.4 (June 1, 2003) [No updates present.] on 17 March 2012 at 1:51:00 pm'!
ScriptableScratchMorph subclass: #CustomBlockSpecsDictionary
instanceVariableNames: ''
classVariableNames: 'CustomBlockSpecs NewestBlock '
poolDictionaries: ''
category: 'Scratch-Objects'!
DialogBoxMorph subclass: #CustomBlockSpecsEditor
instanceVariableNames: 'scratchFrame newCustomBlockSpecs '
classVariableNames: ''
poolDictionaries: ''
category: 'Scratch-UI-Dialogs'!
DialogBoxMorph subclass: #CreateBlockDialog
instanceVariableNames: 'blockName helpButtonMorph blockSelectorMorph receiver blockArgsMorph blockTypeMorph editorMorph blockInserterMorph blockSectionMorph blockSelector '
classVariableNames: ''
poolDictionaries: ''
category: 'Scratch-UI-Dialogs'!
DialogBoxMorph subclass: #ScrollingStringDialog
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Scratch-UI-Dialogs'!
!CustomBlockSpecsDictionary commentStamp: '<historical>' prior: 0!
Written By Dreamod.
When you import a block the block spec is stored as a method under 'custom block specs' like this:
forward: t1
^ ('motion' ('move %n steps' #- #forward: 10))
These can be deleted at any point in the browser but are useful to recover data. The block specs are stored into the class variable 'CustomBlockSpecs'
Selecting 'Delete All Custom Blocks' from the blocks menu will only replace 'CustomBlockSpecs' with this:
#('obsolete' 'motion' #- 'control' #- 'looks' #- 'sensing' #- 'sound' #- 'operators' #- 'pen' #- 'variables' 'lists' 'obsolete' )
All block writing is stored in CommandBlockMorph!
!CustomBlockSpecsDictionary class methodsFor: 'accessing'!
customBlockSpecs
CustomBlockSpecs ifNil: [self updateCustomBlocks].
^ CustomBlockSpecs! !
!CustomBlockSpecsDictionary class methodsFor: 'accessing'!
newestBlock
^ NewestBlock! !
!CustomBlockSpecsDictionary class methodsFor: 'initialization'!
removeCustomBlocks
| t1 t2 t3 t4 |
CustomBlockSpecs _ nil.
ScriptableScratchMorph new makeFile: 'temporaryFile.cs'.
ScriptableScratchMorph new clearFile: 'temporaryFile.cs'.
ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''initialization''!!
getNewestBlock
^ #(''obsolete'')!! !!' toFile: 'temporaryFile.cs'.
t3 _ (FileDirectory forFileName: 'temporaryFile.cs')
oldFileNamed: 'temporaryFile.cs'.
t4 _ t3 contentsOfEntireFile.
(ReadWriteStream
on: t4
from: 1
to: t4 size) fileIn.
CustomBlockSpecsDictionary updateCustomBlocks.
ScriptableScratchMorph new deleteFile: 'temporaryFile.cs'! !
!CustomBlockSpecsDictionary class methodsFor: 'accessing'!
updateBlocks
CustomBlockSpecs _ self editBlocks! !
!CustomBlockSpecsDictionary class methodsFor: 'accessing'!
getNewestBlock
^ #('obsolete' )! !
!CustomBlockSpecsDictionary class methodsFor: 'custom block specs'!
editBlocks
^ #('obsolete' 'motion' #- 'control' #- 'looks' #- 'sensing' #- 'sound' #- 'operators' #- 'pen' #- 'variables' 'lists' 'obsolete')! !
!CommandBlockMorph methodsFor: 'export block'!
createBlock
| t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 |
t13 _ CreateBlockDialog new editBlockNamed: '' reciever: '';
getUserResponse.
t13 = #cancelled ifTrue: [^ self].
t1 _ t13 at: 2.
t3 _ t13 at: 4.
t5 _ t13 at: 1.
t6 _ StringDialog ask: 'comment?'.
t6 = #cancelled | t6 = '' ifTrue: [^ self].
(t6 findString: '!!')
> 0
ifTrue:
[
[DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!'''.
t6 _ StringDialog ask: 'comment?'.
t6 = #cancelled ifTrue: [^ self].
nil].
(t6 findString: '!!')
> 0 ifTrue: [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!''' asUTF8].
t6 _ StringDialog ask: 'comment?'.
t6 = #cancelled ifTrue: [^ self].
(t6 findString: '!!')
> 0 ifTrue: [^ self]].
t11 _ t6.
(t6 findString: 'moreCodes')
> 0
ifTrue:
[(t6 findString: ':')
> 0 ifTrue: [t14 _ (ScriptableScratchMorph new
letters: (t6 findString: ':')
+ 2
through: (t6 findString: ':')
+ 2
of: t6) asNumberNoError].
(t6 findString: ';')
> 0 ifTrue: [t11 _ ScriptableScratchMorph new
letters: (t6 findString: ';')
+ 1
through: t6 size
of: t6]].
t4 _ ScratchFileChooserDialog
chooseNewFileDefaultBlocks: t1
title: 'Export Block As ' , t5
type: '.block'.
t4 = #cancelled ifTrue: [^ self].
t2 _ t13 at: 3.
(t4 asLowercase endsWith: '.block')
ifFalse: [t4 _ t4 , '.block'].
ScriptableScratchMorph new makeFile: t4.
ScriptableScratchMorph new clearFile: t4.
ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!!
' toFile: t4.
t10 _ (t13 at: 5) lines at: 1.
ScriptableScratchMorph new writeText: t10 toFile: t4.
ScriptableScratchMorph new writeText: ' ^ #(''' , t5 , ''' ' , '(''' , t1 , '''' , ' #' , t2 , ' #' , t3 , '))' toFile: t4.
ScriptableScratchMorph new writeText: '
' , '"' , t11 , '" !! !!
' toFile: t4.
t2 = 's' | t2 = 'c'
ifTrue:
[t8 _ 'ScratchProcess'.
t9 _ '''private-special forms''']
ifFalse:
[t8 _ 'ScriptableScratchMorph'.
t9 _ '''' , t5 , ' ops'''].
ScriptableScratchMorph new writeText: '!!' , t8 , ' methodsFor:' , '' , t9 , '' , '!!' toFile: t4.
t7 _ t13 at: 5.
ScriptableScratchMorph new writeText: t7 , '!! !!' toFile: t4.
ScriptableScratchMorph new writeText: '
!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!!' toFile: t4.
ScriptableScratchMorph new writeText: '
getNewestBlock' toFile: t4.
t10 _ self getNewTitleWithOutVariables: t13.
ScriptableScratchMorph new writeText: '
^ self ' , t10 toFile: t4.
ScriptableScratchMorph new writeText: '!! !!' toFile: t4.
t14 ifNil: [t14 _ 1].
t14
timesRepeat: [(t6 findString: 'moreCodes')
> 0
ifTrue:
[(t6 findString: 'moreCodes:')
> 0 ifTrue: [t12 _ ScriptableScratchMorph new
letters: (ScriptableScratchMorph new index: ':' of: t11)
+ 1
through: (ScriptableScratchMorph new index: ':' of: t6)
+ 1
of: t6].
ScriptableScratchMorph new writeText: (self moreCustomCodes: t12)
toFile: t4]].
t3 _ (FileDirectory forFileName: t4)
oldFileNamed: t4.
t4 _ t3 contentsOfEntireFile.
(ReadWriteStream
on: t4
from: 1
to: t4 size) fileIn.
CustomBlockSpecsDictionary updateCustomBlocks! !
!CommandBlockMorph methodsFor: 'export block'!
exportBlock
| t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 |
t1 _ self commandSpec.
t3 _ self selector.
t5 _ self getCategoryForSelector: t3.
t6 _ StringDialog ask: 'comment?'.
t6 = #cancelled ifTrue: [^ self].
(t6 findString: '!!')
> 0
ifTrue:
[DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!'''.
t6 _ StringDialog ask: 'comment?'.
t6 = #cancelled ifTrue: [^ self].
(t6 findString: '!!')
> 0 ifTrue: [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!''' asUTF8].
t6 _ StringDialog ask: 'comment?'.
t6 = #cancelled ifTrue: [^ self].
(t6 findString: '!!')
> 0 ifTrue: [^ self]].
t11 _ t6.
(t6 findString: 'moreCodes')
> 0
ifTrue:
[(t6 findString: ':')
> 0 ifTrue: [t13 _ (ScriptableScratchMorph new
letters: (t6 findString: ':')
+ 2
through: (t6 findString: ':')
+ 2
of: t6) asNumberNoError].
(t6 findString: ';')
> 0
ifTrue: [t11 _ ScriptableScratchMorph new
letters: (t6 findString: ';')
+ 1
through: t6 size
of: t6]
ifFalse: [t11 _ 'no comment available']].
t4 _ ScratchFileChooserDialog
chooseNewFileDefaultBlocks: t1
title: 'Export Block As ' , t5
type: '.block'.
t4 = #cancelled ifTrue: [^ self].
(self isKindOf: CommandBlockMorph)
ifTrue: [t2 _ '-'].
(self isKindOf: ReporterBlockMorph)
ifTrue:
[self isReporter ifTrue: [t2 _ 'r'].
self isBooleanReporter ifTrue: [t2 _ 'b']].
(self isKindOf: CBlockMorph)
| (self isKindOf: IfElseBlockMorph) ifTrue: [t2 _ 'c'].
(self isKindOf: SetterBlockMorph)
| (self isKindOf: VariableBlockMorph) | (self isKindOf: ListContentsBlockMorph) | (self isKindOf: HatBlockMorph) ifTrue: [^ self beep].
self isTimed ifTrue: [t2 _ 't'].
self isSpecialForm & (self isKindOf: CBlockMorph) not & (self isKindOf: IfElseBlockMorph) not ifTrue: [t2 _ 's'].
(t4 asLowercase endsWith: '.block')
ifFalse: [t4 _ t4 , '.block'].
ScriptableScratchMorph new makeFile: t4.
ScriptableScratchMorph new clearFile: t4.
ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!!
' toFile: t4.
t10 _ self getNewTitleWithVariables.
ScriptableScratchMorph new writeText: t10 toFile: t4.
ScriptableScratchMorph new writeText: ' ^ #(''' , t5 , ''' ' , '(''' , t1 , '''' , ' #' , t2 , ' #' , t3 , '))' toFile: t4.
ScriptableScratchMorph new writeText: '
' , '"' , t11 , '" !! !!
' toFile: t4.
self isSpecialForm | (self isKindOf: CBlockMorph)
ifTrue:
[t8 _ 'ScratchProcess'.
t9 _ '''private-special forms''']
ifFalse:
[t8 _ 'ScriptableScratchMorph'.
t9 _ '''' , t5 , ' ops'''].
ScriptableScratchMorph new writeText: '!!' , t8 , ' methodsFor:' , '' , t9 , '' , '!!' toFile: t4.
t7 _ self getCode.
ScriptableScratchMorph new writeText: t7 , '!! !!' toFile: t4.
ScriptableScratchMorph new writeText: '
!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!!' toFile: t4.
ScriptableScratchMorph new writeText: '
getNewestBlock' toFile: t4.
t10 _ self getNewTitleWithOutVariables.
ScriptableScratchMorph new writeText: '
^ self ' , t10 toFile: t4.
ScriptableScratchMorph new writeText: '!! !!' toFile: t4.
t13 ifNil: [t13 _ 1].
t13
timesRepeat: [(t6 findString: 'moreCodes')
> 0
ifTrue:
[(t6 findString: 'moreCodes:')
> 0 ifTrue: [t12 _ ScriptableScratchMorph new
letters: (ScriptableScratchMorph new index: ':' of: t11)
+ 1
through: (ScriptableScratchMorph new index: ':' of: t6)
+ 1
of: t6].
ScriptableScratchMorph new writeText: (self moreCodes: t12)
toFile: t4]]! !
!CommandBlockMorph methodsFor: 'export block'!
getCategoryForSelector: t1
| t2 t3 t4 t5 t6 |
t2 _ ScriptableScratchMorph selectors asString.
(t2 findString: t1 asString)
> 0
ifTrue: [t2 _ ScriptableScratchMorph]
ifFalse: [t2 _ nil].
t2
ifNil:
[t2 _ ScratchSpriteMorph selectors asString.
(t2 findString: t1 asString)
> 0
ifTrue: [t2 _ ScratchSpriteMorph]
ifFalse: [t2 _ nil]].
t2
ifNil:
[t2 _ ScratchStageMorph selectors asString.
(t2 findString: t1 asString)
> 0
ifTrue: [t2 _ ScratchStageMorph]
ifFalse: [t2 _ ScriptableScratchMorph]].
t2 ifNil: [t2 _ ScriptableScratchMorph].
t6 _ t1 asString.
t3 _ ScriptableScratchMorph blockSpecCategories.
t5 _ 1.
t3 size
timesRepeat:
[t4 _ (t2 blockSpecsForCategory: (t3 at: t5)) asString.
(t4 findString: t6 asString)
> 0 ifTrue: [^ (t3 at: t5) asString].
t5 _ t5 + 1.
t5 > t3 size ifTrue: [^ 'motion'].
nil].
DialogBoxMorph inform: t4! !
!CommandBlockMorph methodsFor: 'export block'!
getCode
| t1 t2 |
t1 _ self selector.
t2 _ ScriptableScratchMorph selectors asString.
(t2 findString: t1 asString)
> 0 ifTrue: [^ (ScriptableScratchMorph sourceCodeAt: t1) asString].
t2 _ ScratchSpriteMorph selectors asString.
(t2 findString: t1 asString)
> 0 ifTrue: [^ (ScratchSpriteMorph sourceCodeAt: t1) asString].
t2 _ ScratchStageMorph selectors asString.
(t2 findString: t1 asString)
> 0 ifTrue: [^ (ScratchStageMorph sourceCodeAt: t1) asString].
t2 _ ScratchProcess selectors asString.
(t2 findString: t1 asString)
> 0 ifTrue: [^ (ScratchProcess sourceCodeAt: t1) asString]! !
!CommandBlockMorph methodsFor: 'export block'!
getNewTitleWithOutVariables
| t1 |
t1 _ self selector.
^ t1 asString copyReplaceAll: ':' with: ': '' '! !
!CommandBlockMorph methodsFor: 'export block'!
getNewTitleWithOutVariables: t1
| t2 |
t2 _ t1 at: 4.
(t2 findString: ' ')
> 0 ifFalse: [t2 _ t2 , ' '].
t2 _ ScriptableScratchMorph new
letters: 1
through: (t2 findString: ' ')
of: t2.
^ t2 asString copyReplaceAll: ':' with: ': '' '' '! !
!CommandBlockMorph methodsFor: 'export block'!
getNewTitleWithVariables
| t1 t2 t3 t4 t5 |
t1 _ 1.
t2 _ ''.
t3 _ 1.
t4 _ self selector.
t5 _ self argMorphs size asNumber.
self isTimed ifTrue: [t5 _ t5 + 2].
(t4 findString: ':')
> 0
ifTrue: [t5
timesRepeat:
[t2 _ t2 , (ScriptableScratchMorph new
letters: t1
through: (ScriptableScratchMorph new
indexOf: ':'
startingAt: t1
in: t4)
of: t4) , ' t' , t3 asString , ' '.
t1 _ (ScriptableScratchMorph new
indexOf: ':'
startingAt: t1
in: t4)
+ 1.
t3 _ t3 + 1]]
ifFalse: [t2 _ t4].
^ t2! !
!CommandBlockMorph methodsFor: 'export block'!
moreCodes: t1
| t2 t3 t4 t5 t6 t7 t8 t9 t10 |
t2 _ StringDialog ask: 'Enter Class And Selector
' , ' (' , 'ex: ScratchFrameMorph new saveScratchProject' , ') ' initialAnswer: 'ScratchFrameMorph new saveScratchProject'.
(t2 findString: 'moreCodes')
> 0
ifTrue: [(t2 findString: ';')
> 0 ifTrue: [t2 _ ScriptableScratchMorph new
letters: (t2 findString: ';')
+ 1
through: t2 size
of: t2]].
t3 _ ScriptableScratchMorph new
letters: 1
through: (t2 findString: ' ')
- 1
of: t2.
t4 _ t2 findString: 'new'.
t4 > 0
ifTrue: [t4 _ ' ']
ifFalse: [t4 _ ' class '].
t5 _ t2 findString: ' '.
t4 = ' ' ifTrue: [t5 _ t5 + 5].
t6 _ 'thing' asString.
t6 _ ScriptableScratchMorph new
letters: t5
through: t2 size
of: t2.
t7 _ t3 asString , t4 asString , 'sourceCodeAt: ' , '#' , t6 asString.
ScriptableScratchMorph new makeFile: 'temporaryFile.cs'.
ScriptableScratchMorph new clearFile: 'temporaryFile.cs'.
ScriptableScratchMorph new writeText: '!!CommandBlockMorph methodsFor: ''export block''!!
writeMoreCodes
^ ' , t7 toFile: 'temporaryFile.cs'.
t9 _ (FileDirectory forFileName: 'temporaryFile.cs')
oldFileNamed: 'temporaryFile.cs'.
t10 _ t9 contentsOfEntireFile.
(ReadWriteStream
on: t10
from: 1
to: t10 size) fileIn.
ScriptableScratchMorph new deleteFile: 'temporaryFile.cs'.
t8 _ self writeMoreCodes asString.
^ '
!!' , t3 , t4 , 'methodsFor: ''as yet unclassified''!!
' , t8 , '!! !!'! !
!CommandBlockMorph methodsFor: 'export block'!
moreCustomCodes: t1
| t2 t3 t4 t5 t6 t7 t8 t9 t10 |
t2 _ StringDialog ask: 'Enter Class And Selector
' , ' (' , 'ex: ScratchFrameMorph new saveScratchProject' , ') ' initialAnswer: 'ScratchFrameMorph new saveScratchProject'.
(t2 findString: 'moreCodes')
> 0
ifTrue: [(t2 findString: ';')
> 0 ifTrue: [t2 _ ScriptableScratchMorph new
letters: (t2 findString: ';')
+ 1
through: t2 size
of: t2]].
t3 _ ScriptableScratchMorph new
letters: 1
through: (t2 findString: ' ')
- 1
of: t2.
t4 _ t2 findString: 'new'.
t4 > 0
ifTrue: [t4 _ ' ']
ifFalse: [t4 _ ' class '].
t5 _ t2 findString: ' '.
t4 = ' ' ifTrue: [t5 _ t5 + 5].
t6 _ 'thing' asString.
t6 _ ScriptableScratchMorph new
letters: t5
through: t2 size
of: t2.
t8 _ CreateBlockDialog new moreCodes; getUserResponse2.
^ '
!!' , t3 , t4 , 'methodsFor: ''as yet unclassified''!!
' , t8 , '!! !!'! !
!CommandBlockMorph methodsFor: 'private'!
rightButtonMenu
| t1 t2 t3 t4 |
t1 _ CustomMenu new.
t1 add: 'help' action: #presentHelpScreen.
t1 add: 'export block' action: #exportBlock.
(owner isKindOf: ScratchBlockPaletteMorph)
ifFalse:
[t1 addLine.
(#(#+ #- #* #/ #\\ ) includes: selector)
ifTrue: [#(#+ #- #* #/ #mod ) with: #(#+ #- #* #/ #\\ ) do: [:t5 :t6 | t1 add: t5 action: t6]].
(#(#< #= #> ) includes: selector)
ifTrue: [#(#< #= #> ) do: [:t6 | t1 add: t6 action: t6]].
(#(#& #| ) includes: selector)
ifTrue: [#(#and #or ) with: #(#& #| ) do: [:t5 :t6 | t1 add: t5 action: t6]].
t1 addLine.
t1 add: 'duplicate' action: #duplicate.
(self owner isKindOf: BlockMorph)
ifFalse: [t1 add: 'delete' action: #delete]].
t2 _ self ownerThatIsA: ScratchFrameMorph.
(t2 notNil and: [#(#sensor: #sensorPressed: ) includes: selector])
ifTrue:
[t1 addLine.
t1 add: 'show ScratchBoard watcher' action: #showSensorBoard.
t2 workPane scratchServer ifNil: [t1 add: 'enable remote sensor connections' action: #enableRemoteSensors]
ifNotNil: [t1 add: 'disable remote sensor connections' action: #exitScratchSession]].
DebugMenu
ifTrue:
[t1 addLine.
t1 add: 'show tuples' action: #showTuples].
(t3 _ t1 localize; startUp) ifNil: [^ self].
(#(#presentHelpScreen #duplicate #delete ) includes: t3)
ifTrue: [^ self perform: t3].
t3 = #showSensorBoard
ifTrue:
[t2 showSensorBoard.
^ self].
t3 = #enableRemoteSensors
ifTrue:
[t2 enableRemoteSensors.
^ self].
t3 = #exitScratchSession
ifTrue:
[t2 exitScratchSession.
^ self].
t3 = #exportBlock ifTrue: [^ self exportBlock].
t3 = #showTuples ifTrue: [^ self showTuples].
t4 _ '%n ' , t3 , ' %n'.
'\\' = t3 ifTrue: [t4 _ ScratchTranslator translationFor: '%n mod %n'].
'&' = t3 ifTrue: [t4 _ ScratchTranslator translationFor: '%b and %b'].
'|' = t3 ifTrue: [t4 _ ScratchTranslator translationFor: '%b or %b'].
self commandSpec: t4.
self selector: t3! !
!CreateBlockDialog methodsFor: 'initialization'!
initialize
super initialize.
self
withButtonsForYes: false
no: false
okay: true
cancel: false! !
!CreateBlockDialog methodsFor: 'other'!
blockSection
^ blockSectionMorph evaluate! !
!CreateBlockDialog methodsFor: 'other'!
blockSpec
^ blockArgsMorph contents! !
!CreateBlockDialog methodsFor: 'other'!
blockType
^ blockTypeMorph contents! !
!CreateBlockDialog methodsFor: 'other'!
editBlockNamed: t1 reciever: t2
| t3 |
editorMorph _ ScrollingStringMorph new borderWidth: 0;
contents: '';
font: self class monoSpacedFont;
backForm: (ScratchFrameMorph skinAt: #stringFieldFrame);
width: 300.
blockArgsMorph _ StringFieldMorph new useStringFieldFrame; width: 250.
blockSelectorMorph _ StringFieldMorph new useStringFieldFrame; width: 250.
blockTypeMorph _ StringFieldMorph new useStringFieldFrame; width: 35.
blockSectionMorph _ StringFieldMorph new useStringFieldFrame; width: 100.
helpButtonMorph _ (self buttonLabel: ('Help' , ScratchTranslator ellipsesSuffix) localized action: #presentHelpMenu)
width: 300.
t3 _ AlignmentMorph new width: 300;
color: Color transparent;
centering: #center.
t3 addMorph: blockSectionMorph;
addMorph: blockTypeMorph;
addMorph: blockArgsMorph.
self title: 'Create A Block'.
mainColumn addMorphBack: t3.
mainColumn addMorphBack: blockSelectorMorph.
mainColumn addMorphBack: editorMorph.
mainColumn addMorphBack: helpButtonMorph.
mainColumn addMorphBack: buttonRow.
editorMorph contents: (ScratchSpriteMorph sourceCodeAt: #forward:) asString.
blockArgsMorph contents: 'move %n steps' asString.
blockTypeMorph contents: '-' asString.
blockSectionMorph contents: 'motion'.
blockSelectorMorph contents: 'forward: 10'.
bottomSpacer delete.
bottomSpacer _ nil.
tabFields add: editorMorph.
tabFields add: helpButtonMorph.
tabFields add: blockArgsMorph.
tabFields add: blockTypeMorph! !
!CreateBlockDialog methodsFor: 'other'!
getUserResponse
| t1 t2 |
self openInWorld.
self centerOnScreen.
t1 _ self world.
tabFields size > 0 ifTrue: [t1 activeHand newKeyboardFocus: (tabFields at: 4)].
done _ false.
[done]
whileFalse: [t1 doOneCycle].
t2 _ Array
with: blockSectionMorph contents
with: blockArgsMorph contents
with: blockTypeMorph contents
with: blockSelectorMorph contents
with: self value.
^ t2! !
!CreateBlockDialog methodsFor: 'other'!
getUserResponse2
| t1 t2 |
self openInWorld.
self centerOnScreen.
t1 _ self world.
tabFields size > 0 ifTrue: [t1 activeHand newKeyboardFocus: (tabFields at: 1)].
done _ false.
[done]
whileFalse: [t1 doOneCycle].
^ self value! !
!CreateBlockDialog methodsFor: 'other'!
moreCodes
| t1 |
editorMorph _ ScrollingStringMorph new borderWidth: 0;
contents: '';
font: self class monoSpacedFont;
backForm: (ScratchFrameMorph skinAt: #stringFieldFrame);
width: 300.
t1 _ AlignmentMorph new width: 300;
color: Color transparent;
centering: #center.
self title: 'Create A Block'.
mainColumn addMorphBack: t1.
mainColumn addMorphBack: editorMorph.
mainColumn addMorphBack: buttonRow.
editorMorph contents: 'message selector and argument names
"comment stating purpose of message"
| temporary variable names |
statements' asString.
bottomSpacer delete.
bottomSpacer _ nil.
tabFields add: editorMorph! !
!CreateBlockDialog methodsFor: 'other'!
presentHelpMenu
| t1 t2 |
t1 _ CustomMenu new.
t1 add: 'arguments' action: #arguments.
t1 add: 'type' action: #type.
t1 add: 'name' action: #name.
t1 add: 'selector' action: #selector.
t1 add: 'code' action: #code.
t2 _ t1 localize; startUp.
t2 = #arguments ifTrue: [^ ScrollingStringDialog new text: 'Arguments are spaces where you can enter text, numbers, colors, booleans etc. They are encoded using ''%'' and a letter, ex. %s = string, %m = morph list (sprite list).
Different Scratch Mods have different arguments. Here is your list of arguments. It can be found at Scratch-Blocks>>CommandBlockMorph>>private>>uncoloredArgMorphFor:
' , (CommandBlockMorph sourceCodeAt: #uncoloredArgMorphFor:) asString , '
for information visit: ' title: 'Help - About Arguments';
getUserResponse].
t2 = #type ifTrue: [^ ScrollingStringDialog new text: 'This determines the shape of your block.
Explanation of flags:
- no flags
b boolean reporter
c c-shaped block containing a sequence of commands (always special form)
r reporter
s special form command with its own evaluation rule
t timed command, like wait or glide
E message event hat
K key event hat
M mouse-click event hat
S start event hat
W when <condition> hat (obsolete).
Some modifications like panther and BYOB have even more block kinds.
' title: 'Help - Block Types';
getUserResponse].
t2 = #name ifTrue: [^ ScrollingStringDialog new text: 'The title of the block is the text that shows up on the block' title: 'Help - Title';
getUserResponse].
t2 = #selector ifTrue: [ScrollingStringDialog new text: 'The selector should be the same as the title of the code. However, instead of typing ''do: t1 ThisCode: t2 On: t3'' (example) you type ''do:ThisCode:On:''
Why do I need to type the selector?
this is important because the blockspecs builder builds the blockspec from 4 things.
>> the category (''motion''...
>> the title (''move %n steps''...
>> the type #-
>> and the selector: forward:)
You cannot type the full blockspec because the block exporter needs all the data seperately.' title: 'Help - Selector';
getUserResponse].
t2 = #code ifTrue: [^ ScrollingStringDialog new text: 'The code (or method) is what make the block work. First you type the title and then you type the variables, like this: | t1 t2 t3 |
Then you type your statements (actions)' title: 'Help - Code';
getUserResponse]! !
!CreateBlockDialog class methodsFor: 'instance creation'!
monoSpacedFont
^ ScratchFrameMorph getFont: #ProjectNotes! !
!CreateBlockDialog methodsFor: 'other'!
value
^ editorMorph contents! !
!CustomBlockSpecsEditor class methodsFor: 'initialization'!
editNotesFor: aScratchFrameMorph
^ self new
createNotesDialogFor: aScratchFrameMorph;
extent: 350@450.! !
!CustomBlockSpecsEditor methodsFor: 'initialization'!
newCustomBlockSpecs
^ newCustomBlockSpecs contents! !
!CustomBlockSpecsEditor methodsFor: 'initialization'!
createNotesDialogFor: t1
| t2 |
t2 _ ScratchFrameMorph getFont: #ProjectNotes.
newCustomBlockSpecs _ ScrollingStringMorph new borderWidth: 0;
contents: '';
font: t2;
backForm: (ScratchFrameMorph skinAt: #stringFieldFrame);
width: 500.
self title: 'Edit Custom Blockspecs'.
mainColumn addMorphBack: newCustomBlockSpecs.
mainColumn addMorphBack: buttonRow.
scratchFrame _ t1.
newCustomBlockSpecs contents: CustomBlockSpecsDictionary customBlockSpecs asString.
bottomSpacer delete.
bottomSpacer _ nil.
tabFields add: newCustomBlockSpecs! !
!CustomBlockSpecsEditor methodsFor: 'initialization'!
initialize
super initialize.
self
withButtonsForYes: false
no: false
okay: true
cancel: true! !
!CustomBlockSpecsEditor methodsFor: 'other'!
getUserResponse
| t1 t2 t3 t4 |
self openInWorld.
self centerOnScreen.
t1 _ self world.
t1 activeHand newKeyboardFocus: newCustomBlockSpecs.
done _ false.
[done]
whileFalse: [t1 doOneCycle].
response = #cancelled ifTrue: [^ #cancelled].
t2 _ 'temporaryFile.cs'.
ScriptableScratchMorph new makeFile: t2.
ScriptableScratchMorph new clearFile: t2.
ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!!
editBlocks
^ #' toFile: t2.
ScriptableScratchMorph new writeText: newCustomBlockSpecs contents toFile: 'temporaryFile.cs'.
ScriptableScratchMorph new writeText: '!! !!' toFile: t2.
t3 _ (FileDirectory forFileName: t2)
oldFileNamed: t2.
t4 _ t3 contentsOfEntireFile.
(ReadWriteStream
on: t4
from: 1
to: t4 size) fileIn.
^ CustomBlockSpecsDictionary updateBlocks! !
!ScrollingStringDialog methodsFor: 'initialization'!
text: t1 title: t2
| t3 |
t3 _ ScrollingStringMorph new borderWidth: 0;
contents: t1;
font: (ScratchFrameMorph getFont: #ProjectNotes);
isEditable: false;
backForm: (ScratchFrameMorph skinAt: #stringFieldFrame);
width: 500.
self title: t2.
mainColumn addMorphBack: t3.
buttonRow addMorphBack: (self buttonLabel: 'OK' action: #yes).
mainColumn addMorphBack: buttonRow.
bottomSpacer delete.
bottomSpacer _ nil! !
!ScratchFrameMorph methodsFor: 'menu/button actions'!
createBlock
CommandBlockMorph new createBlock! !
!ScratchFrameMorph methodsFor: 'menu/button actions'!
deleteAllBlocks
CustomBlockSpecsDictionary removeCustomBlocks! !
!ScratchFrameMorph methodsFor: 'menu/button actions'!
editCustomBlockSpecs
^ (CustomBlockSpecsEditor editNotesFor: self) getUserResponse! !
!ScratchFrameMorph methodsFor: 'menu/button actions'!
createMenuPanel
| t1 t2 |
menuPanel _ AlignmentMorph new color: Color transparent;
centering: #center;
inset: 0;
height: 0.
self addShortcutButtonsTo: menuPanel.
t1 _ #((#File #fileMenu:) (#Edit #editMenu:) (#Blocks #blocksMenu:) (#Help #helpMenu:) ).
t1 do:
[:t3 |
t2 _ ScratchMenuTitleMorph new contents: (t3 at: 1) localized;
target: self selector: (t3 at: 2).
menuPanel addMorphBack: t2.
#helpMenu: = (t3 at: 2) ifFalse: [menuPanel addMorphBack: (Morph new color: Color transparent;
extent: 12 @ 5)]].
topPane addMorph: menuPanel! !
!ScratchFrameMorph methodsFor: 'menu/button actions'!
blocksMenu: t1
| t2 |
t2 _ CustomMenu new.
t2 add: 'Edit Custom Block Specs' action: #editCustomBlockSpecs.
t2 add: 'Delete All Custom Blocks' action: #deleteAllBlocks.
t2 addLine.
t2 add: 'Import Block' action: #addBlock.
t2 add: 'Create Block' action: #createBlock.
t2 invokeOn: self at: t1 bottomLeft + (0 @ 10)! !
!ScratchFrameMorph methodsFor: 'menu/button actions'!
addBlock
| t1 t2 t3 t4 |
t1 _ ScratchFileChooserDialog new createBlockFileChooserFor: self;
type: #block.
t2 _ t1 getUserResponse.
t2 = #cancelled ifTrue: [^ self].
t3 _ (FileDirectory forFileName: t2)
oldFileNamed: t2.
t4 _ t3 contentsOfEntireFile.
(ReadWriteStream
on: t4
from: 1
to: t4 size) fileIn.
CustomBlockSpecsDictionary updateCustomBlocks! !
!ScratchFileChooserDialog methodsFor: 'initialization'!
createFileChooserLayoutBlock: t1
list _ ScratchFilePicker new.
self removeAllMorphs.
bottomSpacer delete.
bottomSpacer _ nil.
mainColumn addMorphBack: list.
self title: 'Open'.
t1
ifTrue:
[self title: 'Save As'.
newFileTitle _ StringMorph new contents: 'New Filename:' localized , ' ';
color: (Color gray: 0.3);
font: (ScratchFrameMorph getFont: #FileChooserNewFileTitle).
newFileName _ StringFieldMorph new font: (ScratchFrameMorph getFont: #FileChooserNewFilename);
color: (Color
r: 211 / 255
g: 214 / 255
b: 216 / 255);
width: 180.
newTitleBin addMorphBack: newFileTitle;
addMorphBack: (Morph new extent: 5 @ 5;
color: Color transparent);
addMorphBack: (Morph new extent: 5 @ 5;
color: Color transparent);
addMorphBack: newFileName;
addMorphBack: (AlignmentMorph newSpacer: Color transparent).
ScratchTranslator isRTL ifTrue: [newTitleBin submorphs reversed do:
[:t2 |
t2 delete.
newTitleBin addMorphBack: t2]]].
mainColumn addMorphBack: newTitleBin;
addMorphBack: newTitleBin;
addMorphBack: buttonRow.
self addMorphBack: shortcutColumn;
addMorphBack: mainColumn;
addMorphBack: fileInfoColumn! !
!ScratchFileChooserDialog methodsFor: 'initialization'!
createBlockFileChooserFor: t1
scratchFrame _ nil.
readingScratchFile _ true.
list _ ScratchFilePicker new extensions: #(#block ).
self removeAllMorphs.
bottomSpacer delete.
bottomSpacer _ nil.
mainColumn addMorphBack: list.
self title: 'Import Block'.
list scratchInfoClient: nil.
mainColumn addMorphBack: (Morph new extent: 5 @ 9;
color: Color transparent);
addMorphBack: newTitleBin.
fileInfoColumn addMorphBack: buttonRow.
self addMorphBack: shortcutColumn;
addMorphBack: mainColumn;
addMorphBack: fileInfoColumn! !
!CustomBlockSpecsDictionary class methodsFor: 'initialization'!
updateCustomBlocks
CustomBlockSpecs ifNil: [CustomBlockSpecs _ #('obsolete' 'motion' #- 'control' #- 'looks' #- 'sensing' #- 'sound' #- 'operators' #- 'pen' #- 'variables' 'lists' )].
NewestBlock _ self getNewestBlock.
CustomBlockSpecs _ CustomBlockSpecs , NewestBlock! !
!ScriptableScratchMorph methodsFor: 'file ops'!
clearFile: t1
| t2 t3 t4 |
t4 _ 'credit to panther'.
t3 _ FileDirectory forFileName: t1.
t3 deleteFileNamed: t1.
t2 _ FileStream newFileNamed: t1.
t2 close! !
!ScriptableScratchMorph methodsFor: 'file ops'!
deleteFile: t1
| t2 t3 |
t2 _ FileDirectory forFileName: t1.
t3 _ FileDirectory localNameFor: t1.
t2 deleteFileNamed: t3 ifAbsent: []! !
!ScriptableScratchMorph methodsFor: 'file ops'!
makeFile: t1
| t2 t3 t4 t5 t6 t7 t8 t9 t10 |
t10 _ 'credit to panther'.
t2 _ t1.
t9 _ t1.
t6 _ 'I exist'.
t3 _ self readFile: t9.
self writeText: t6 toFile: t9.
t5 _ self readFile: t9.
t7 _ self stringLength: t6.
t8 _ self stringLength: t5.
t7 _ t8 - t7.
t7 _ t7 + 1.
t7 _ self
letters: t7
through: t8
of: t5.
t7 = t6
ifTrue:
[t4 _ true.
self clearFile: t9.
t3 = '' ifFalse: [self writeText: t3 toFile: t9]]
ifFalse: [t4 _ false].
t4 = false ifTrue: [FileStream newFileNamed: t2]! !
!ScriptableScratchMorph methodsFor: 'file ops'!
readFile: t1
| t2 t3 t4 |
t4 _ 'credit to panther'.
(FileDirectory default fileExists: t1)
ifFalse: [^ ''].
t2 _ (FileStream readOnlyFileNamed: t1) binary.
t2 ifNil: [^ ''].
t3 _ t2 contentsOfEntireFile asString.
t2 close.
^ t3! !
!ScriptableScratchMorph methodsFor: 'file ops'!
writeText: t1 toFile: t2
| t3 t4 |
t4 _ 'credit to panther'.
(FileDirectory default fileExists: t2)
ifFalse: [^ self].
t3 _ (FileStream fileNamed: t2) binary.
t3 ifNil: [^ self].
t3 setToEnd.
t3 nextPutAll: t1.
t3 close! !
!ScriptableScratchMorph methodsFor: 'string ops'!
letters: t1 through: t2 of: t3
^ t3 asString copyFrom: (t1 max: 1)
to: (t2 min: t3 size)! !
!ScriptableScratchMorph methodsFor: 'string ops'!
indexOf: t1 startingAt: t2 in: t3
^ t3 asString findString: t1 startingAt: t2! !
!ScriptableScratchMorph methodsFor: 'string ops'!
index: t1 of: t2
^ t2 findString: t1! !
!ScriptableScratchMorph class methodsFor: 'block specs'!
blockSpecs
"Answer a collection of block specifications for the blocks that are common to all objects. Block specificatons (Arrays) are interspersed with category names (Strings). A block specification is an Array of the form: (<block spec string> <block type> <selector> [optional initial argument values]).
Explanation of flags:
- no flags
b boolean reporter
c c-shaped block containing a sequence of commands (always special form)
r reporter
s special form command with its own evaluation rule
t timed command, like wait or glide
E message event hat
K key event hat
M mouse-click event hat
S start event hat
W when <condition> hat (obsolete)"
| blocks |
blocks _ #(
'control'
('when %m clicked' S -)
('when %k key pressed' K -)
('when %m clicked' M -)
-
('wait %n secs' t wait:elapsed:from: 1)
-
('forever' c doForever)
('repeat %n' c doRepeat 10)
-
('broadcast %e' - broadcast:)
('broadcast %e and wait' s doBroadcastAndWait)
('when I receive %e' E -)
-
('forever if %b' c doForeverIf)
('if %b' c doIf)
('if %b' c doIfElse)
('wait until %b' s doWaitUntil)
('repeat until %b' c doUntil)
-
('stop script' s doReturn)
('stop all' - stopAll)
'operators'
('%n + %n' r + - -)
('%n - %n' r - - -)
('%n * %n' r * - -)
('%n / %n' r / - -)
-
('pick random %n to %n' r randomFrom:to: 1 10)
-
('%s < %s' b < '' '')
('%s = %s' b = '' '')
('%s > %s' b > '' '')
-
('%b and %b' b &)
('%b or %b' b |)
('not %b' b not)
-
('join %s %s' r concatenate:with: 'hello ' 'world')
('letter %n of %s' r letter:of: 1 'world')
('length of %s' r stringLength: 'world')
-
('%n mod %n' r \\ - -)
('round %n' r rounded -)
-
('%f of %n' r computeFunction:of: 'sqrt' 10)
'sound'
('play sound %S' - playSound:)
('play sound %S until done' s doPlaySoundAndWait)
('stop all sounds' - stopAllSounds)
-
('play drum %D for %n beats' t drum:duration:elapsed:from: 48 0.2)
('rest for %n beats' t rest:elapsed:from: 0.2)
-
('play note %N for %n beats' t noteOn:duration:elapsed:from: 60 0.5)
('set instrument to %I' - midiInstrument: 1)
-
('change volume by %n' - changeVolumeBy: -10)
('set volume to %n%' - setVolumeTo: 100)
('volume' r volume)
-
('change tempo by %n' - changeTempoBy: 20)
('set tempo to %n bpm' - setTempoTo: 60)
('tempo' r tempo)
'motor'
('motor on for %n secs' t motorOnFor:elapsed:from: 1)
('motor on' - allMotorsOn)
('motor off' - allMotorsOff)
('motor power %n' - startMotorPower: 100)
('motor direction %W' - setMotorDirection: 'this way')
'variables'
('show variable %v' - showVariable:)
('hide variable %v' - hideVariable:)
'list'
('add %s to %L' - append:toList: 'thing')
-
('delete %y of %L' - deleteLine:ofList: 1)
('insert %s at %i of %L' - insert:at:ofList: 'thing' 1)
('replace item %i of %L with %s' - setLine:ofList:to: 1 'list' 'thing')
-
('item %i of %L' r getLine:ofList: 1)
('length of %L' r lineCountOfList:)
('%L contains %s' b list:contains: 'list' 'thing')
).
^ blocks, self obsoleteBlockSpecs , CustomBlockSpecsDictionary customBlockSpecs
! !
!ScratchFileChooserDialog class methodsFor: 'instance creation'!
chooseNewFileDefaultBlocks: t1 title: t2 type: t3
| t4 |
ScratchFileChooserDialog deleteDuplicates.
t4 _ self new createFileChooserLayoutBlock: true;
type: t3;
defaultName: t1;
title: t2;
listExtent: 400 @ 280.
^ t4 getUserResponseForNewFile! !Please consider making a little spot for downloadable blocks. (I can make the files)
Offline
Okay, so here's the thing.
I am just finishing off my last piece of coursework right now (taking a tea break). I already have a huge list of things to do over my holiday, but thankfully most of them are fun! I will be doing a block library update at some point, but in question of the block library site, I think what I'm going to do is start again, clear it all (apart from the API) and just build up again from scratch, especially the PHP in an attempt to eliminate the SQL problems the site has been experiencing.
Offline
sparks wrote:
Okay, so here's the thing.
I am just finishing off my last piece of coursework right now (taking a tea break). I already have a huge list of things to do over my holiday, but thankfully most of them are fun! I will be doing a block library update at some point, but in question of the block library site, I think what I'm going to do is start again, clear it all (apart from the API) and just build up again from scratch, especially the PHP in an attempt to eliminate the SQL problems the site has been experiencing.
i'm on school holiday now so, if you want, i can help you sort out some errors...
Offline
TRocket wrote:
sparks wrote:
Okay, so here's the thing.
I am just finishing off my last piece of coursework right now (taking a tea break). I already have a huge list of things to do over my holiday, but thankfully most of them are fun! I will be doing a block library update at some point, but in question of the block library site, I think what I'm going to do is start again, clear it all (apart from the API) and just build up again from scratch, especially the PHP in an attempt to eliminate the SQL problems the site has been experiencing.i'm on school holiday now so, if you want, i can help you sort out some errors...
Cool. I'm on holiday as of tomorrow, though I have plans for the rest of this week. I have pasted most all of the PHP code on the site above. The thing is that currently SQL connections are only SOMETIMES made. Not never, and not always. If you can work out why that would be awesome!
Offline
Maybe you could test connecting to a different database (I have one we could test with)
Offline
sparks wrote:
Okay, so here's the thing.
I am just finishing off my last piece of coursework right now (taking a tea break). I already have a huge list of things to do over my holiday, but thankfully most of them are fun! I will be doing a block library update at some point, but in question of the block library site, I think what I'm going to do is start again, clear it all (apart from the API) and just build up again from scratch, especially the PHP in an attempt to eliminate the SQL problems the site has been experiencing.
Sounds good to me; after all the inactivity as of late, starting over sounds like a good idea.
Offline
sparks wrote:
TRocket wrote:
sparks wrote:
Okay, so here's the thing.
I am just finishing off my last piece of coursework right now (taking a tea break). I already have a huge list of things to do over my holiday, but thankfully most of them are fun! I will be doing a block library update at some point, but in question of the block library site, I think what I'm going to do is start again, clear it all (apart from the API) and just build up again from scratch, especially the PHP in an attempt to eliminate the SQL problems the site has been experiencing.i'm on school holiday now so, if you want, i can help you sort out some errors...
Cool. I'm on holiday as of tomorrow, though I have plans for the rest of this week. I have pasted most all of the PHP code on the site above. The thing is that currently SQL connections are only SOMETIMES made. Not never, and not always. If you can work out why that would be awesome!
what error do you get when it doesn't connect?
can you access the mysql log files? if so is there an error recorded in there when it can't connect?
Offline
TRocket wrote:
sparks wrote:
TRocket wrote:
i'm on school holiday now so, if you want, i can help you sort out some errors...Cool. I'm on holiday as of tomorrow, though I have plans for the rest of this week. I have pasted most all of the PHP code on the site above. The thing is that currently SQL connections are only SOMETIMES made. Not never, and not always. If you can work out why that would be awesome!
what error do you get when it doesn't connect?
can you access the mysql log files? if so is there an error recorded in there when it can't connect?
There is no error. It acts as if it has successfully connected:
"Congratulations, your block has been submitted!" means nothing cos it might not have. I can't remember whether I actually added an ordie(mysql_error) in there...
Offline
Does anyone want to design a favicon? I've made a quick one, but it doesn't looks great:
http://blocks.scratchr.org/favicon.ico
You may like to use this tool.
Offline